@helpway/react 0.15.2 → 0.16.0

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../widget-core/src/client.ts","../../widget-core/src/visitor-id.ts","../../types/src/realtime-events.ts","../../types/src/doc-nav-icons.ts","../../widget-core/src/ws.ts","../../widget-core/src/store.ts","../../widget-core/src/api.ts","../../widget-core/src/theme.ts","../../widget-core/src/events.ts","../../widget-core/src/i18n.ts","../../widget-core/src/utils.ts","../src/provider.tsx","../src/themed/default-widget.tsx","../src/hooks/use-announcements.ts","../src/hooks/use-composer.ts","../src/hooks/use-conversations.ts","../src/hooks/use-header-identity.ts","../src/hooks/use-i18n.ts","../src/hooks/use-presence.ts","../src/hooks/use-timeline.ts","../src/hooks/use-unread.ts","../src/hooks/use-widget.ts","../src/themed/composer.tsx","../src/themed/icons.tsx","../src/themed/debug-overlay.tsx","../src/shell/docked-bar.tsx","../src/themed/content/content-tab-view.tsx","../src/hooks/use-content-tab.ts","../src/themed/content/simple-markdown.tsx","../src/themed/content/content-detail-view.tsx","../src/themed/content/content-list-view.tsx","../src/themed/content/grouped-content-tab-view.tsx","../src/hooks/use-grouped-content-tab.ts","../src/themed/content/tab-icon.tsx","../src/themed/announcement-previews.tsx","../src/themed/strip-markdown.ts","../src/themed/message-bubble.tsx","../src/themed/message-list.tsx","../src/themed/message-preview.tsx","#style-inject:#style-inject","../src/themed/styles.css","../src/helpway-widget.tsx","../src/hooks/use-realtime.ts"],"sourcesContent":["import { createTRPCClient, httpBatchLink } from \"@trpc/client\";\nimport { getOrCreateVisitorId } from \"./visitor-id\";\n\n// The real AppRouter lives in apps/api/src/trpc/ but importing it pulls in CF Worker\n// source files. We type the client as `any` here — real type safety is in the\n// Zustand store (widget-react). The tRPC link config is the same at runtime.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type WidgetClient = any;\n\n/**\n * Create a tRPC vanilla client for widget API calls.\n *\n * Visitor identity uses a dual strategy:\n * 1. X-Visitor-Id header (localStorage-based) — always works, even cross-origin\n * 2. hw_visitor cookie (server-set) — additional persistence layer\n *\n * This ensures visitor identity survives 3rd-party cookie blocking\n * (Safari ITP, Firefox ETP, Chrome Privacy Sandbox).\n */\nexport function createWidgetClient(config: {\n\tapiUrl: string;\n\tapiKey: string;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n}): any {\n\treturn createTRPCClient({\n\t\tlinks: [\n\t\t\thttpBatchLink({\n\t\t\t\turl: `${config.apiUrl}/trpc`,\n\t\t\t\theaders() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t\"X-Public-Key\": config.apiKey,\n\t\t\t\t\t\t\"X-Visitor-Id\": getOrCreateVisitorId(config.apiKey),\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tfetch(url, options) {\n\t\t\t\t\t// credentials: \"include\" sends cookies cross-origin (when not blocked)\n\t\t\t\t\treturn globalThis.fetch(url, { ...options, credentials: \"include\" });\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t});\n}\n","/**\n * Per-site visitor identity storage (localStorage).\n *\n * Matches Intercom's `intercom-id-[app_id]` pattern — each publicKey gets\n * its own localStorage slot so a single browser visiting multiple Helpway\n * workspaces never bleeds identities across them.\n *\n * Storage key: `helpway:visitor:<publicKey-suffix>` (last 16 chars of the key,\n * which is always random — see `generatePublicKey` in apps/api/src/lib/id.ts).\n */\n\nconst PREFIX = \"helpway:visitor\";\nconst LEGACY_KEY = \"helpway:visitor-id\";\n\nfunction keyFor(publicKey: string): string {\n\t// Last 16 chars of publicKey — enough uniqueness (2^80 collision space for nanoid alphabet)\n\t// and keeps localStorage key short. Stable for a given site.\n\tconst suffix = publicKey.slice(-16);\n\treturn `${PREFIX}:${suffix}`;\n}\n\nfunction generateId(): string {\n\tconst ts = Date.now().toString(36);\n\tconst rand = Math.random().toString(36).slice(2, 10);\n\treturn `${ts}${rand}`;\n}\n\n/**\n * Get or create a persistent visitor ID scoped to `publicKey`.\n * Returns a stable per-site ID across page loads.\n */\nexport function getOrCreateVisitorId(publicKey: string): string {\n\ttry {\n\t\tconst storageKey = keyFor(publicKey);\n\t\tconst existing = localStorage.getItem(storageKey);\n\t\tif (existing) return existing;\n\n\t\t// One-time migration: if a legacy global key exists AND no per-site key\n\t\t// is set yet, seed this site with it. Keeps returning visitors identified\n\t\t// on their FIRST post-upgrade site load. Subsequent sites get fresh IDs.\n\t\tconst legacy = localStorage.getItem(LEGACY_KEY);\n\t\tif (legacy) {\n\t\t\tlocalStorage.setItem(storageKey, legacy);\n\t\t\tlocalStorage.removeItem(LEGACY_KEY);\n\t\t\treturn legacy;\n\t\t}\n\n\t\tconst id = generateId();\n\t\tlocalStorage.setItem(storageKey, id);\n\t\treturn id;\n\t} catch {\n\t\t// localStorage unavailable (SSR, private mode, quota exceeded)\n\t\treturn generateId();\n\t}\n}\n\n/** Sync the server-assigned canonical visitor ID back into localStorage. */\nexport function syncVisitorId(publicKey: string, serverVisitorId: string): void {\n\ttry {\n\t\tlocalStorage.setItem(keyFor(publicKey), serverVisitorId);\n\t} catch {\n\t\t// ignore\n\t}\n}\n\n/** Clear the visitor ID for a specific site (used by playground \"simulate anonymous\"). */\nexport function clearVisitorId(publicKey: string): void {\n\ttry {\n\t\tlocalStorage.removeItem(keyFor(publicKey));\n\t} catch {\n\t\t// ignore\n\t}\n}\n","import type { Conversation } from \"./conversation\";\nimport type { TimelineItem } from \"./timeline-item\";\n\n// ── Event type constants ─────────────────────────────────\n\nexport const WsEventType = {\n\tConnectionEstablished: \"connectionEstablished\",\n\tConversationCreated: \"conversationCreated\",\n\tConversationUpdated: \"conversationUpdated\",\n\tTimelineItemCreated: \"timelineItemCreated\",\n\tTimelineItemUpdated: \"timelineItemUpdated\",\n\tTimelineItemDeleted: \"timelineItemDeleted\",\n\tConversationSeen: \"conversationSeen\",\n\tConversationTyping: \"conversationTyping\",\n\tAiProcessingProgress: \"aiProcessingProgress\",\n\tAiProcessingCompleted: \"aiProcessingCompleted\",\n\tAiStreamChunk: \"aiStreamChunk\",\n\tVisitorPresenceChanged: \"visitorPresenceChanged\",\n\tMemberUpdated: \"memberUpdated\",\n\tWorkspaceUnreadCounts: \"workspaceUnreadCounts\",\n} as const;\n\n// ── Union of all realtime events ──────────────────────────\n\nexport type RealtimeEvent =\n\t| ConnectionEstablishedEvent\n\t| ConversationCreatedEvent\n\t| ConversationUpdatedEvent\n\t| TimelineItemCreatedEvent\n\t| TimelineItemUpdatedEvent\n\t| TimelineItemDeletedEvent\n\t| ConversationSeenEvent\n\t| ConversationTypingEvent\n\t| AiProcessingProgressEvent\n\t| AiProcessingCompletedEvent\n\t| AiStreamChunkEvent\n\t| VisitorPresenceChangedEvent\n\t| MemberUpdatedEvent\n\t| WorkspaceUnreadCountsEvent;\n\n// ── Connection ────────────────────────────────────────────\n\nexport interface ConnectionEstablishedEvent {\n\ttype: \"connectionEstablished\";\n\tconnectionId: string;\n}\n\n// ── Conversation lifecycle ────────────────────────────────\n\nexport interface ConversationCreatedEvent {\n\ttype: \"conversationCreated\";\n\tconversation: Conversation;\n}\n\nexport interface ConversationUpdatedEvent {\n\ttype: \"conversationUpdated\";\n\tconversationId: string;\n\tupdates: Partial<Conversation>;\n}\n\n// ── Timeline items ────────────────────────────────────────\n\nexport interface TimelineItemCreatedEvent {\n\ttype: \"timelineItemCreated\";\n\tconversationId: string;\n\titem: TimelineItem;\n}\n\nexport interface TimelineItemUpdatedEvent {\n\ttype: \"timelineItemUpdated\";\n\tconversationId: string;\n\titem: TimelineItem;\n}\n\nexport interface TimelineItemDeletedEvent {\n\ttype: \"timelineItemDeleted\";\n\tconversationId: string;\n\titemId: string;\n}\n\n// ── Presence / read receipts ──────────────────────────────\n\nexport interface ConversationSeenEvent {\n\ttype: \"conversationSeen\";\n\tconversationId: string;\n\tuserId?: string;\n\tvisitorId?: string;\n\tlastSeenAt: string;\n}\n\nexport interface ConversationTypingEvent {\n\ttype: \"conversationTyping\";\n\tconversationId: string;\n\tuserId?: string;\n\tvisitorId?: string;\n\tisTyping: boolean;\n}\n\n// ── AI processing indicators ──────────────────────────────\n\nexport interface AiProcessingProgressEvent {\n\ttype: \"aiProcessingProgress\";\n\tconversationId: string;\n\tphase: \"thinking\" | \"searching\" | \"responding\";\n}\n\nexport interface AiProcessingCompletedEvent {\n\ttype: \"aiProcessingCompleted\";\n\tconversationId: string;\n\tstatus: \"success\" | \"error\" | \"skipped\";\n}\n\nexport interface AiStreamChunkEvent {\n\ttype: \"aiStreamChunk\";\n\tconversationId: string;\n\t/** Incremental text delta — widget appends to the streaming bubble. */\n\tdelta: string;\n\t/** True when this is the final chunk — widget should finalize the bubble. */\n\tdone: boolean;\n}\n\n// ── Visitor presence ─────────────────────────────────────\n\nexport interface VisitorPresenceChangedEvent {\n\ttype: \"visitorPresenceChanged\";\n\tvisitorId: string;\n\tstatus: \"online\" | \"offline\";\n}\n\n// ── Organization team ────────────────────────────────────\n\nexport interface MemberUpdatedEvent {\n\ttype: \"memberUpdated\";\n\taction: \"added\" | \"removed\" | \"roleChanged\";\n\tmemberId: string;\n}\n\n// ── Workspace meta events ───────────────────────────────\n\nexport interface WorkspaceUnreadCountsEvent {\n\ttype: \"workspaceUnreadCounts\";\n\tcounts: Record<string, number>;\n}\n\n// ── Event type guard helper ───────────────────────────────\n\nexport function isRealtimeEvent(data: unknown): data is RealtimeEvent {\n\treturn (\n\t\ttypeof data === \"object\" &&\n\t\tdata !== null &&\n\t\t\"type\" in data &&\n\t\ttypeof (data as RealtimeEvent).type === \"string\"\n\t);\n}\n","/**\n * Single source of truth for the docs/help-center sidebar nav icon allowlist.\n *\n * Shared so the content portal (dashboard) and the public content-site never\n * drift: the portal lists/validates these names, the content-site renders them.\n * Stored as structured primitives (not raw SVG markup) so consumers render real\n * SVG elements — no `dangerouslySetInnerHTML`, no XSS surface, no React in this\n * (types) package. Each consumer wraps these in its own `<svg viewBox=\"0 0 24\n * 24\" stroke=\"currentColor\" stroke-width=\"1.75\">`.\n *\n * Authors may still set a raw `<svg>` string instead of a name (rendered by the\n * content-site through an <img> data-URI); this allowlist is the curated set.\n */\n\nexport type DocNavIconShape =\n\t| { t: \"path\"; d: string }\n\t| { t: \"polyline\"; points: string }\n\t| { t: \"polygon\"; points: string }\n\t| { t: \"circle\"; cx: number; cy: number; r: number }\n\t| { t: \"rect\"; x: number; y: number; width: number; height: number; rx?: number }\n\t| { t: \"line\"; x1: number; y1: number; x2: number; y2: number };\n\nexport interface DocNavIcon {\n\t/** Stable key authors type (lowercase). */\n\tname: string;\n\t/** Human label for a picker. */\n\tlabel: string;\n\tshapes: DocNavIconShape[];\n}\n\nexport const DOC_NAV_ICONS: DocNavIcon[] = [\n\t{\n\t\tname: \"globe\",\n\t\tlabel: \"Globe\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 12, cy: 12, r: 10 },\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"code\",\n\t\tlabel: \"Code\",\n\t\tshapes: [\n\t\t\t{ t: \"polyline\", points: \"16 18 22 12 16 6\" },\n\t\t\t{ t: \"polyline\", points: \"8 6 2 12 8 18\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"book\",\n\t\tlabel: \"Book\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M4 19.5A2.5 2.5 0 0 1 6.5 17H20\" },\n\t\t\t{ t: \"path\", d: \"M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"rocket\",\n\t\tlabel: \"Rocket\",\n\t\tshapes: [\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"terminal\",\n\t\tlabel: \"Terminal\",\n\t\tshapes: [\n\t\t\t{ t: \"polyline\", points: \"4 17 10 11 4 5\" },\n\t\t\t{ t: \"line\", x1: 12, y1: 19, x2: 20, y2: 19 },\n\t\t],\n\t},\n\t{\n\t\tname: \"smartphone\",\n\t\tlabel: \"Smartphone\",\n\t\tshapes: [\n\t\t\t{ t: \"rect\", x: 5, y: 2, width: 14, height: 20, rx: 2 },\n\t\t\t{ t: \"line\", x1: 12, y1: 18, x2: 12.01, y2: 18 },\n\t\t],\n\t},\n\t{\n\t\tname: \"server\",\n\t\tlabel: \"Server\",\n\t\tshapes: [\n\t\t\t{ t: \"rect\", x: 2, y: 2, width: 20, height: 8, rx: 2 },\n\t\t\t{ t: \"rect\", x: 2, y: 14, width: 20, height: 8, rx: 2 },\n\t\t\t{ t: \"line\", x1: 6, y1: 6, x2: 6.01, y2: 6 },\n\t\t\t{ t: \"line\", x1: 6, y1: 18, x2: 6.01, y2: 18 },\n\t\t],\n\t},\n\t{\n\t\tname: \"key\",\n\t\tlabel: \"Key\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 7.5, cy: 15.5, r: 5.5 },\n\t\t\t{ t: \"path\", d: \"m21 2-9.6 9.6M16 6l4 4\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"puzzle\",\n\t\tlabel: \"Puzzle\",\n\t\tshapes: [\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M19.439 7.85c-.049.322.059.648.289.878l1.568 1.568c.47.47.706 1.087.706 1.704s-.235 1.233-.706 1.704l-1.611 1.611a.98.98 0 0 1-.837.276c-.47-.07-.802-.48-.968-.925a2.501 2.501 0 1 0-3.214 3.214c.446.166.855.497.925.968a.979.979 0 0 1-.276.837l-1.61 1.61a2.404 2.404 0 0 1-1.704.706 2.402 2.402 0 0 1-1.704-.706l-1.568-1.568a1.026 1.026 0 0 0-.877-.29c-.493.074-.84.504-1.02.968a2.5 2.5 0 1 1-3.237-3.237c.464-.18.894-.527.967-1.02a1.026 1.026 0 0 0-.289-.877l-1.568-1.568A2.402 2.402 0 0 1 1.998 12c0-.617.236-1.234.706-1.704L4.28 8.687c.24-.24.581-.353.925-.29.493.074.84.504 1.02.968a2.5 2.5 0 1 0 3.237-3.237c-.464-.18-.894-.527-.967-1.02a1.026 1.026 0 0 1 .289-.877l1.568-1.568A2.402 2.402 0 0 1 12 1.998c.617 0 1.234.236 1.704.706l1.568 1.568c.23.23.556.338.877.29.493-.074.84-.504 1.02-.968a2.5 2.5 0 1 1 3.237 3.237c-.18.464-.527.894-1.02.968z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"file\",\n\t\tlabel: \"File\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" },\n\t\t\t{ t: \"polyline\", points: \"14 2 14 8 20 8\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"settings\",\n\t\tlabel: \"Settings\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 12, cy: 12, r: 3 },\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"zap\",\n\t\tlabel: \"Zap\",\n\t\tshapes: [{ t: \"polygon\", points: \"13 2 3 14 12 14 11 22 21 10 12 10 13 2\" }],\n\t},\n\t{\n\t\tname: \"layers\",\n\t\tlabel: \"Layers\",\n\t\tshapes: [\n\t\t\t{ t: \"polygon\", points: \"12 2 2 7 12 12 22 7 12 2\" },\n\t\t\t{ t: \"polyline\", points: \"2 17 12 22 22 17\" },\n\t\t\t{ t: \"polyline\", points: \"2 12 12 17 22 12\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"plug\",\n\t\tlabel: \"Plug\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M12 22v-5\" },\n\t\t\t{ t: \"path\", d: \"M9 8V2M15 8V2\" },\n\t\t\t{ t: \"path\", d: \"M18 8v5a6 6 0 0 1-12 0V8z\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"message\",\n\t\tlabel: \"Message\",\n\t\tshapes: [{ t: \"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\t},\n\t{\n\t\tname: \"inbox\",\n\t\tlabel: \"Inbox\",\n\t\tshapes: [\n\t\t\t{ t: \"polyline\", points: \"22 12 16 12 14 15 10 15 8 12 2 12\" },\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"users\",\n\t\tlabel: \"Users\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\" },\n\t\t\t{ t: \"circle\", cx: 9, cy: 7, r: 4 },\n\t\t\t{ t: \"path\", d: \"M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"mail\",\n\t\tlabel: \"Mail\",\n\t\tshapes: [\n\t\t\t{ t: \"rect\", x: 2, y: 4, width: 20, height: 16, rx: 2 },\n\t\t\t{ t: \"path\", d: \"m22 7-10 5L2 7\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"credit-card\",\n\t\tlabel: \"Credit card\",\n\t\tshapes: [\n\t\t\t{ t: \"rect\", x: 1, y: 4, width: 22, height: 16, rx: 2 },\n\t\t\t{ t: \"line\", x1: 1, y1: 10, x2: 23, y2: 10 },\n\t\t],\n\t},\n\t{\n\t\tname: \"sparkles\",\n\t\tlabel: \"Sparkles\",\n\t\tshapes: [\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"m12 3-1.9 5.8a2 2 0 0 1-1.3 1.3L3 12l5.8 1.9a2 2 0 0 1 1.3 1.3L12 21l1.9-5.8a2 2 0 0 1 1.3-1.3L21 12l-5.8-1.9a2 2 0 0 1-1.3-1.3z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"bell\",\n\t\tlabel: \"Bell\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9\" },\n\t\t\t{ t: \"path\", d: \"M10.3 21a1.94 1.94 0 0 0 3.4 0\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"search\",\n\t\tlabel: \"Search\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 11, cy: 11, r: 8 },\n\t\t\t{ t: \"path\", d: \"m21 21-4.3-4.3\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"wrench\",\n\t\tlabel: \"Wrench\",\n\t\tshapes: [\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"shield\",\n\t\tlabel: \"Shield\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\" },\n\t\t\t{ t: \"path\", d: \"m9 12 2 2 4-4\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"lifebuoy\",\n\t\tlabel: \"Life buoy\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 12, cy: 12, r: 10 },\n\t\t\t{ t: \"circle\", cx: 12, cy: 12, r: 4 },\n\t\t\t{ t: \"line\", x1: 4.93, y1: 4.93, x2: 9.17, y2: 9.17 },\n\t\t\t{ t: \"line\", x1: 14.83, y1: 14.83, x2: 19.07, y2: 19.07 },\n\t\t\t{ t: \"line\", x1: 14.83, y1: 9.17, x2: 19.07, y2: 4.93 },\n\t\t\t{ t: \"line\", x1: 4.93, y1: 19.07, x2: 9.17, y2: 14.83 },\n\t\t],\n\t},\n\t{\n\t\tname: \"chart\",\n\t\tlabel: \"Chart\",\n\t\tshapes: [\n\t\t\t{ t: \"line\", x1: 12, y1: 20, x2: 12, y2: 10 },\n\t\t\t{ t: \"line\", x1: 18, y1: 20, x2: 18, y2: 4 },\n\t\t\t{ t: \"line\", x1: 6, y1: 20, x2: 6, y2: 16 },\n\t\t],\n\t},\n\t{\n\t\tname: \"share\",\n\t\tlabel: \"Share\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 18, cy: 5, r: 3 },\n\t\t\t{ t: \"circle\", cx: 6, cy: 12, r: 3 },\n\t\t\t{ t: \"circle\", cx: 18, cy: 19, r: 3 },\n\t\t\t{ t: \"line\", x1: 8.59, y1: 13.51, x2: 15.42, y2: 17.49 },\n\t\t\t{ t: \"line\", x1: 15.41, y1: 6.51, x2: 8.59, y2: 10.49 },\n\t\t],\n\t},\n];\n\n/** Lowercase name set for O(1) validation. */\nexport const DOC_NAV_ICON_NAMES: string[] = DOC_NAV_ICONS.map((i) => i.name);\n\nconst DOC_NAV_ICON_MAP: Record<string, DocNavIcon> = Object.fromEntries(\n\tDOC_NAV_ICONS.map((i) => [i.name, i]),\n);\n\n/**\n * Lucide names the imported docs corpus uses, mapped to the nearest icon we ship.\n *\n * The MDX cards were authored against fumadocs, which passes icon names straight to\n * lucide — so a card can ask for `FileCode` or `WifiOff`, which this allowlist has\n * never heard of. Unresolved, they showed as nothing at best: `Box` is three\n * characters, so it fell through to the emoji branch and the word \"Box\" rendered on\n * the card where its icon belonged.\n *\n * These are deliberate approximations, not a lucide port: the goal is a card that\n * looks intentional, and every entry here is a name that actually appears in the\n * corpus. Add to it when a new name shows up rather than widening the emoji branch.\n */\nconst DOC_NAV_ICON_ALIASES: Record<string, string> = {\n\tfilecode: \"file\",\n\tbookopen: \"book\",\n\tdatabase: \"server\",\n\tbot: \"message\",\n\troute: \"share\",\n\trepeat: \"share\",\n\twifioff: \"plug\",\n\thook: \"plug\",\n\tbox: \"puzzle\",\n\tshoppingcart: \"credit-card\",\n\ttype: \"code\",\n\tcalendar: \"bell\",\n\tpause: \"settings\",\n\tflaskconical: \"wrench\",\n};\n\n/** Resolve a named icon (case-insensitive). Returns undefined for unknown names. */\nexport function getDocNavIcon(name: string): DocNavIcon | undefined {\n\tconst key = name.trim().toLowerCase();\n\treturn DOC_NAV_ICON_MAP[key] ?? DOC_NAV_ICON_MAP[DOC_NAV_ICON_ALIASES[key] ?? \"\"];\n}\n","import { type RealtimeEvent, isRealtimeEvent } from \"@helpway/types\";\n\nexport type EventHandler = (event: RealtimeEvent) => void;\n\ninterface WebSocketManagerConfig {\n\tapiUrl: string;\n\tvisitorId: string;\n\twebsiteId: string;\n\t/** Public API key — appended as ?key= on the WS upgrade URL so the server\n\t * can authenticate the widget without relying on custom headers (which the\n\t * browser's native WebSocket API does not support). */\n\tapiKey: string;\n}\n\n/**\n * WebSocket connection manager for ChatRoom Durable Object.\n * Handles connect, disconnect, auto-reconnect with exponential backoff,\n * ping/pong keep-alive, and event dispatching.\n *\n * Ping gating — visibility-aware:\n * Ping doubles as a presence heartbeat on the server (refreshes KV\n * presence key with a 150s TTL). When the tab is hidden we pause the\n * ping so a forgotten background tab naturally drops offline within\n * ~2.5 minutes. The socket itself stays open; only the heartbeat stops.\n */\nexport class WebSocketManager {\n\tprivate ws: WebSocket | null = null;\n\tprivate handlers = new Set<EventHandler>();\n\tprivate config: WebSocketManagerConfig;\n\tprivate reconnectAttempts = 0;\n\tprivate maxReconnectAttempts = 10;\n\tprivate reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate pingTimer: ReturnType<typeof setInterval> | null = null;\n\tprivate isDestroyed = false;\n\tprivate visibilityHandler: (() => void) | null = null;\n\n\tconstructor(config: WebSocketManagerConfig) {\n\t\tthis.config = config;\n\t\tthis.setupVisibilityListener();\n\t}\n\n\tprivate setupVisibilityListener(): void {\n\t\tif (typeof document === \"undefined\") return;\n\t\tthis.visibilityHandler = () => {\n\t\t\tif (document.visibilityState === \"hidden\") {\n\t\t\t\t// Tab backgrounded — stop heartbeat so KV TTL drops user offline.\n\t\t\t\tthis.stopPing();\n\t\t\t} else if (this.ws?.readyState === WebSocket.OPEN) {\n\t\t\t\t// Tab visible again — resume heartbeat immediately to restore presence.\n\t\t\t\tthis.startPing();\n\t\t\t\tthis.send({ type: \"ping\" });\n\t\t\t}\n\t\t};\n\t\tdocument.addEventListener(\"visibilitychange\", this.visibilityHandler);\n\t}\n\n\t/** Update connection parameters (call before connect) */\n\tconfigure(params: Partial<WebSocketManagerConfig>): void {\n\t\tObject.assign(this.config, params);\n\t}\n\n\t/** Connect to the ChatRoom Durable Object WebSocket */\n\tconnect(): void {\n\t\tif (this.ws?.readyState === WebSocket.OPEN) return;\n\t\t// Reset destroyed flag — allows reconnect after React StrictMode remount\n\t\tthis.isDestroyed = false;\n\n\t\tconst protocol = this.config.apiUrl.startsWith(\"https\") ? \"wss\" : \"ws\";\n\t\tconst base = this.config.apiUrl.replace(/^https?/, protocol);\n\t\tconst params = new URLSearchParams({\n\t\t\ttype: \"visitor\",\n\t\t\tid: this.config.visitorId,\n\t\t\twebsiteId: this.config.websiteId,\n\t\t\tkey: this.config.apiKey,\n\t\t});\n\n\t\tconst ws = new WebSocket(`${base}/ws?${params}`);\n\n\t\tws.onopen = () => {\n\t\t\tthis.reconnectAttempts = 0;\n\t\t\t// Only start heartbeat if the tab is visible — the visibility\n\t\t\t// listener resumes it automatically when the user returns.\n\t\t\tif (typeof document === \"undefined\" || document.visibilityState === \"visible\") {\n\t\t\t\tthis.startPing();\n\t\t\t}\n\t\t};\n\n\t\tws.onmessage = (event) => {\n\t\t\ttry {\n\t\t\t\tconst data = JSON.parse(event.data as string);\n\t\t\t\tif (data.type === \"pong\") return;\n\t\t\t\tif (isRealtimeEvent(data)) {\n\t\t\t\t\tfor (const handler of this.handlers) {\n\t\t\t\t\t\thandler(data);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Malformed message — ignore\n\t\t\t}\n\t\t};\n\n\t\tws.onclose = () => {\n\t\t\tthis.stopPing();\n\t\t\tthis.ws = null;\n\t\t\tif (!this.isDestroyed) {\n\t\t\t\tthis.scheduleReconnect();\n\t\t\t}\n\t\t};\n\n\t\tws.onerror = () => {\n\t\t\t// onclose will fire after onerror\n\t\t};\n\n\t\tthis.ws = ws;\n\t}\n\n\t/** Disconnect and stop reconnecting */\n\tdisconnect(): void {\n\t\tthis.isDestroyed = true;\n\t\tthis.stopPing();\n\t\tif (this.reconnectTimer) {\n\t\t\tclearTimeout(this.reconnectTimer);\n\t\t\tthis.reconnectTimer = null;\n\t\t}\n\t\tif (this.visibilityHandler && typeof document !== \"undefined\") {\n\t\t\tdocument.removeEventListener(\"visibilitychange\", this.visibilityHandler);\n\t\t\tthis.visibilityHandler = null;\n\t\t}\n\t\tif (this.ws) {\n\t\t\tthis.ws.close(1000, \"Client disconnect\");\n\t\t\tthis.ws = null;\n\t\t}\n\t}\n\n\t/** Send a JSON message through the WebSocket */\n\tsend(data: Record<string, unknown>): void {\n\t\tif (this.ws?.readyState === WebSocket.OPEN) {\n\t\t\tthis.ws.send(JSON.stringify(data));\n\t\t}\n\t}\n\n\t/** Send typing indicator */\n\tsendTyping(conversationId: string, isTyping: boolean): void {\n\t\tthis.send({ type: \"typing\", conversationId, isTyping });\n\t}\n\n\t/** Subscribe to realtime events */\n\tonEvent(handler: EventHandler): () => void {\n\t\tthis.handlers.add(handler);\n\t\treturn () => {\n\t\t\tthis.handlers.delete(handler);\n\t\t};\n\t}\n\n\t/** Check if connected */\n\tget isConnected(): boolean {\n\t\treturn this.ws?.readyState === WebSocket.OPEN;\n\t}\n\n\t// ── Private ──────────────────────────────────────────\n\n\tprivate scheduleReconnect(): void {\n\t\tif (this.reconnectAttempts >= this.maxReconnectAttempts) return;\n\n\t\tconst delay = Math.min(1000 * 2 ** this.reconnectAttempts, 30000);\n\t\tthis.reconnectAttempts++;\n\n\t\tthis.reconnectTimer = setTimeout(() => {\n\t\t\tthis.connect();\n\t\t}, delay);\n\t}\n\n\tprivate startPing(): void {\n\t\tthis.stopPing();\n\t\tthis.pingTimer = setInterval(() => {\n\t\t\tthis.send({ type: \"ping\" });\n\t\t}, 25000);\n\t}\n\n\tprivate stopPing(): void {\n\t\tif (this.pingTimer) {\n\t\t\tclearInterval(this.pingTimer);\n\t\t\tthis.pingTimer = null;\n\t\t}\n\t}\n}\n","import { WsEventType } from \"@helpway/types\";\nimport type { PublicVisitor, RealtimeEvent, TimelineItem } from \"@helpway/types\";\nimport { createStore } from \"zustand/vanilla\";\n\n// ── Agent Config (from bootstrap) ────────────────────────\n\nexport interface WidgetContentTab {\n\tid: string;\n\tlabel: string;\n\ticon: string;\n\tmodelSlug: string;\n\tdisplay?: {\n\t\tsubtitleField?: string;\n\t\tbadgeField?: string;\n\t\timageField?: string;\n\t\tdateField?: string;\n\t};\n\ttabType?: \"flat\" | \"grouped\";\n\titemsModelSlug?: string;\n\tgroupField?: string;\n\t/** Marks this tab as the \"What's New\" / announcements source.\n\t * Only one tab should have this flag — the first match wins. */\n\tisAnnouncements?: boolean;\n}\n\nexport interface AgentConfig {\n\tid: string;\n\tname: string;\n\tavatarUrl: string | null;\n\tavatarPreset: string | null;\n\twelcomeMessage: string | null;\n\tsubtitleText: string | null;\n\tbrandColor: string;\n\twidgetPosition: \"bottom-right\" | \"bottom-left\";\n\tlauncherStyle: \"icon\" | \"bubble\" | \"help\";\n\t/** Custom image rendered inside the launcher bubble. NULL → fall back\n\t * to the chat-header chain (avatarUrl → avatarPreset → website logo). */\n\tlauncherIconUrl: string | null;\n\tbubbleStyle: \"rounded\" | \"square\" | \"pill\";\n\t/** Show/hide Messages tab in widget footer */\n\tshowMessagesTab: boolean;\n\t/** Require visitor to provide email before starting a conversation */\n\trequireVisitorEmail: boolean;\n\t/** Dynamic content tabs from Better i18n Content CMS integration */\n\tcontentTabs: WidgetContentTab[];\n}\n\n// ── Content Cache ──────────────────────────────────────────\n\nexport interface ContentCacheEntry {\n\tdata: unknown;\n\tts: number;\n}\n\nexport const CONTENT_CACHE_TTL = 5 * 60 * 1000; // 5 minutes\n\n// ── State Shape ──────────────────────────────────────────\n\nexport interface WidgetState {\n\t// Connection\n\tisReady: boolean;\n\tisConnecting: boolean;\n\n\t// Identity\n\tvisitor: PublicVisitor | null;\n\twebsite: { id: string; name: string; domain: string | null; logoUrl: string | null } | null;\n\n\t// Agent config (from bootstrap)\n\tagentConfig: AgentConfig | null;\n\n\t// Conversations\n\tconversations: ConversationSummary[];\n\tactiveConversationId: string | null;\n\n\t// Messages per conversation\n\tmessages: Map<string, TimelineItem[]>;\n\n\t// Presence\n\ttypingUsers: Map<string, boolean>; // conversationId → someone is typing\n\taiProcessing: Map<string, boolean>; // conversationId → AI is processing\n\tstreamingText: Map<string, string>; // conversationId → accumulated streamed text\n\n\t// UI state\n\tisOpen: boolean;\n\tisDismissed: boolean;\n\tview: \"home\" | \"conversation\" | \"new\";\n\n\t// Incoming message preview (shown when widget is closed)\n\tincomingPreview: {\n\t\ttext: string;\n\t\tconversationId: string;\n\t\ttimestamp: number;\n\t\t/** Who sent it. A human reply used to surface under the AI's name\n\t\t * because the card only ever read agentConfig — the event carries\n\t\t * userName/userImage, they were simply dropped here. Null for the AI,\n\t\t * which is the case the agent name is actually right for. */\n\t\tsenderName?: string | null;\n\t\tsenderImage?: string | null;\n\t\tmessages?: Array<{ text: string }>;\n\t\tquickReplies?: {\n\t\t\tstepId: string;\n\t\t\tprompt: string | null;\n\t\t\toptions: Array<{ id: string; label: string }>;\n\t\t};\n\t} | null;\n\n\t// Announcement previews (shown when widget is closed and unseen content exists)\n\t// Multiple previews stack when several isAnnouncements tabs have new content.\n\tannouncementPreviews: Array<{\n\t\ttitle: string;\n\t\tbody: string | null;\n\t\tslug: string;\n\t\ttabId: string;\n\t\tbadge: string | null;\n\t}>;\n\n\t// Number of unseen announcement entries (drives launcher dot + tab badge)\n\tunseenAnnouncementCount: number;\n\n\t// Pre-filled text for new conversation (set via global API)\n\tnewConversationPrefill: string | null;\n\n\t// Pending content-detail open intent — when set, DefaultWidget\n\t// navigates to the matching content tab + entry detail on the next\n\t// render and clears it. Used so consumers rendering anchored\n\t// announcement previews (or any external trigger) can deep-link a\n\t// visitor straight into a specific entry instead of dropping them\n\t// on the home surface. The launcher's onOpen does this internally;\n\t// this field makes the same navigation reachable from outside\n\t// DefaultWidget's local state.\n\tpendingContentDetail: { slug: string; tabId: string } | null;\n\n\t// Content cache (survives tab switches — keyed by request params)\n\tcontentCache: Map<string, ContentCacheEntry>;\n}\n\nexport interface ConversationSummary {\n\tid: string;\n\ttitle: string | null;\n\tstatus: string;\n\tlastMessageText: string | null;\n\tlastMessageAt: string | null;\n\tlastMessageSenderType: string | null;\n\tlastMessageSenderName: string | null;\n\tlastMessageSenderImage: string | null;\n\t/** Display-only fields for the assigned support user. NULL when no\n\t * human is assigned (AI agent is handling). UserId is intentionally\n\t * not exposed — only what the chat header needs to render. */\n\tassigneeName: string | null;\n\tassigneeImage: string | null;\n\tunreadCount: number;\n}\n\n// ── Actions ──────────────────────────────────────────────\n\nexport interface WidgetActions {\n\t// Lifecycle\n\tsetReady(\n\t\tvisitor: WidgetState[\"visitor\"],\n\t\twebsite: WidgetState[\"website\"],\n\t\tagentConfig?: AgentConfig | null,\n\t): void;\n\tsetConnecting(connecting: boolean): void;\n\n\t// Conversations\n\tsetConversations(conversations: ConversationSummary[]): void;\n\taddConversation(conversation: ConversationSummary): void;\n\tsetActiveConversation(id: string | null): void;\n\n\t// Messages\n\tsetMessages(conversationId: string, items: TimelineItem[]): void;\n\taddMessage(conversationId: string, item: TimelineItem): void;\n\t/**\n\t * Replace a message by ID (used by optimistic send — swaps\n\t * temp `optimistic-*` id for the server-confirmed item).\n\t */\n\treplaceMessage(conversationId: string, oldId: string, item: TimelineItem): void;\n\t/** Remove a message by ID (used for optimistic rollback on send failure) */\n\tremoveMessage(conversationId: string, id: string): void;\n\t/**\n\t * Move an optimistic conversation to its server-assigned ID.\n\t * Copies messages + updates activeConversationId + conversations list.\n\t */\n\tremapConversationId(oldId: string, newId: string): void;\n\n\t// Presence\n\tsetTyping(conversationId: string, isTyping: boolean): void;\n\tsetAiProcessing(conversationId: string, processing: boolean): void;\n\tappendStreamChunk(conversationId: string, delta: string, done: boolean): void;\n\t/** Drop a finished stream once its real message is on screen. See appendStreamChunk. */\n\tclearStream(conversationId: string): void;\n\n\t// Identity\n\tupdateVisitorContact(contact: { id: string; name: string | null; email: string | null }): void;\n\n\t// Unread\n\tclearUnread(conversationId: string): void;\n\n\t// UI\n\tsetOpen(open: boolean): void;\n\tsetDismissed(dismissed: boolean): void;\n\tsetView(view: WidgetState[\"view\"]): void;\n\tsetNewConversationPrefill(text: string | null): void;\n\t/** Schedule a deep-link into a specific content entry's detail\n\t * view. DefaultWidget consumes it on the next render — call\n\t * `setOpen(true)` alongside to reveal the panel. Pass `null` to\n\t * clear (DefaultWidget does this automatically once it\n\t * navigates). */\n\tsetPendingContentDetail(value: { slug: string; tabId: string } | null): void;\n\tdismissPreview(): void;\n\n\t// Announcements\n\tsetAnnouncementPreview(preview: WidgetState[\"announcementPreviews\"][number]): void;\n\tdismissAnnouncementPreview(slug?: string): void;\n\tsetUnseenAnnouncementCount(count: number): void;\n\n\t// Content cache\n\tsetContentCache(key: string, data: unknown): void;\n\n\t// Realtime\n\thandleRealtimeEvent(event: RealtimeEvent): void;\n}\n\nexport type WidgetStore = WidgetState & WidgetActions;\n\n// ── Store Factory ────────────────────────────────────────\n\n// Proactive incoming-message previews must survive a page reload —\n// otherwise an agent/AI ping vanishes the moment the visitor refreshes\n// (it lived only in the in-memory store). Persist the single\n// `incomingPreview` field to localStorage; the existing clear paths\n// (setOpen-when-open, dismissPreview) flow through the subscription\n// below, so closing or replying still wipes it. Per-browser only\n// (localStorage) — not cross-device, fine for a transient affordance.\nconst PREVIEW_STORAGE_KEY = \"helpway:incoming-preview\";\n\n/**\n * React key for the bubble that carries an AI answer, streamed or final.\n *\n * The streamed copy and the persisted message are two different objects but one\n * thing on screen, so they have to occupy the same slot in the same keyed list or\n * React tears the first down to build the second. MessageList renders the stream\n * under this key; addMessage hands the arriving item the same one.\n */\nexport function streamingKeyFor(conversationId: string): string {\n\treturn `streaming-${conversationId}`;\n}\n\nfunction loadPersistedPreview(): WidgetStore[\"incomingPreview\"] {\n\tif (typeof window === \"undefined\") return null;\n\ttry {\n\t\tconst raw = window.localStorage.getItem(PREVIEW_STORAGE_KEY);\n\t\treturn raw ? (JSON.parse(raw) as WidgetStore[\"incomingPreview\"]) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction persistPreview(preview: WidgetStore[\"incomingPreview\"]): void {\n\tif (typeof window === \"undefined\") return;\n\ttry {\n\t\tif (preview) {\n\t\t\twindow.localStorage.setItem(PREVIEW_STORAGE_KEY, JSON.stringify(preview));\n\t\t} else {\n\t\t\twindow.localStorage.removeItem(PREVIEW_STORAGE_KEY);\n\t\t}\n\t} catch {\n\t\t// quota / privacy-mode / SSR — non-fatal, preview just won't persist\n\t}\n}\n\n/**\n * The escalation/join event carries its payload as JSON in the item's text:\n * `{action:\"joined\", name, image}` when a specific person took the thread. The\n * unassigned case is a plain sentence (\"Connecting you with a team member…\"), and\n * that is not a handoff to anyone in particular — so only the JSON shape counts.\n */\nfunction parseJoinEvent(text: string): { name: string | null; image: string | null } | null {\n\tif (!text.startsWith(\"{\")) return null;\n\ttry {\n\t\tconst parsed = JSON.parse(text) as {\n\t\t\taction?: string;\n\t\t\tname?: string | null;\n\t\t\timage?: string | null;\n\t\t};\n\t\tif (parsed.action !== \"joined\") return null;\n\t\treturn { name: parsed.name ?? null, image: parsed.image ?? null };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Who, if anyone, has taken this thread — read off the timeline rather than waited\n * for as a separate signal.\n *\n * The obvious place for this was the realtime reducer, and it does not work there:\n * the join event reaches the widget through the timeline refetch that follows the\n * AI's turn, not through a `timelineItemCreated` frame, so a reducer branch never\n * fires. Both paths end in the message list, so the message list is where the\n * handoff is learned. Last join wins — reassignment is a later join.\n */\nfunction latestAssignee(\n\titems: readonly { type?: string | null; text?: string | null }[],\n): { name: string | null; image: string | null } | null {\n\tfor (let i = items.length - 1; i >= 0; i--) {\n\t\tconst item = items[i];\n\t\tif (item?.type !== \"event\" || !item.text) continue;\n\t\tconst joined = parseJoinEvent(item.text);\n\t\tif (joined) return joined;\n\t}\n\treturn null;\n}\n\nexport function createWidgetStore() {\n\tconst store = createStore<WidgetStore>((set, get) => ({\n\t\t// Initial state\n\t\tisReady: false,\n\t\tisConnecting: true,\n\t\tvisitor: null,\n\t\twebsite: null,\n\t\tagentConfig: null,\n\t\tconversations: [],\n\t\tactiveConversationId: null,\n\t\tmessages: new Map(),\n\t\ttypingUsers: new Map(),\n\t\taiProcessing: new Map(),\n\t\tstreamingText: new Map(),\n\t\tisOpen: false,\n\t\tisDismissed: false,\n\t\tview: \"home\",\n\t\tincomingPreview: loadPersistedPreview(),\n\t\tannouncementPreviews: [],\n\t\tunseenAnnouncementCount: 0,\n\t\tnewConversationPrefill: null,\n\t\tpendingContentDetail: null,\n\t\tcontentCache: new Map(),\n\n\t\t// ── Lifecycle ────────────────────────────────────\n\n\t\tsetReady(visitor, website, agentConfig) {\n\t\t\tset({\n\t\t\t\tisReady: true,\n\t\t\t\tisConnecting: false,\n\t\t\t\tvisitor,\n\t\t\t\twebsite,\n\t\t\t\tagentConfig: agentConfig ?? null,\n\t\t\t});\n\t\t},\n\n\t\tsetConnecting(connecting) {\n\t\t\tset({ isConnecting: connecting });\n\t\t},\n\n\t\t// ── Conversations ────────────────────────────────\n\n\t\tsetConversations(conversations) {\n\t\t\tset({ conversations });\n\t\t},\n\n\t\taddConversation(conversation) {\n\t\t\tset((state) => ({\n\t\t\t\tconversations: [conversation, ...state.conversations],\n\t\t\t}));\n\t\t},\n\n\t\tsetActiveConversation(id) {\n\t\t\tset({ activeConversationId: id, view: id ? \"conversation\" : \"home\" });\n\t\t},\n\n\t\t// ── Messages ─────────────────────────────────────\n\n\t\tsetMessages(conversationId, items) {\n\t\t\tconst joined = latestAssignee(items);\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.messages);\n\t\t\t\tnext.set(conversationId, items);\n\t\t\t\treturn {\n\t\t\t\t\tmessages: next,\n\t\t\t\t\t/* Hydrating a thread that already contains a handoff means the header\n\t\t\t\t\t should open as that person, not as the AI who answered before them. */\n\t\t\t\t\t...(joined\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tconversations: state.conversations.map((c) =>\n\t\t\t\t\t\t\t\t\tc.id === conversationId\n\t\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t\t...c,\n\t\t\t\t\t\t\t\t\t\t\t\tassigneeName: joined.name ?? c.assigneeName,\n\t\t\t\t\t\t\t\t\t\t\t\tassigneeImage: joined.image ?? c.assigneeImage,\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t: c,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\n\t\taddMessage(conversationId, item) {\n\t\t\tconst joined = item.type === \"event\" && item.text ? parseJoinEvent(item.text) : null;\n\t\t\tif (joined) {\n\t\t\t\tset((state) => ({\n\t\t\t\t\tconversations: state.conversations.map((c) =>\n\t\t\t\t\t\tc.id === conversationId\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t...c,\n\t\t\t\t\t\t\t\t\tassigneeName: joined.name ?? c.assigneeName,\n\t\t\t\t\t\t\t\t\tassigneeImage: joined.image ?? c.assigneeImage,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: c,\n\t\t\t\t\t),\n\t\t\t\t}));\n\t\t\t}\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.messages);\n\t\t\t\tconst existing = next.get(conversationId) ?? [];\n\t\t\t\t// Deduplicate by ID — WS echoes may arrive twice (once from broadcast,\n\t\t\t\t// once from the mutation response path).\n\t\t\t\tif (existing.some((m) => m.id === item.id)) return state;\n\t\t\t\t/* The visitor's own message, echoed back under its server id while the\n\t\t\t\t optimistic copy is still on screen. Appending it and letting\n\t\t\t\t replaceMessage drop the optimistic one later costs a REMOUNT: the\n\t\t\t\t node the visitor is looking at is destroyed and a new one takes its\n\t\t\t\t place ~180ms after, so the appear animation runs a second time and\n\t\t\t\t the bubble visibly flashes. Swapping in place keeps _stableKey, so\n\t\t\t\t React reuses the same DOM node and nothing replays. */\n\t\t\t\t/* Same remount cost as the echo case below, on the AI's side. The streamed\n\t\t\t\t bubble is rendered as the last entry of the same keyed list this item\n\t\t\t\t is about to join (see MessageList), so handing the arriving item the\n\t\t\t\t stream's key lets React reuse that DOM node instead of destroying it\n\t\t\t\t and mounting a replacement — which is the \"it renders again when the\n\t\t\t\t stream finishes\" that survived making the state swap atomic. State\n\t\t\t\t continuity stopped the blank frame; key continuity stops the repaint. */\n\t\t\t\tconst streamKey = streamingKeyFor(conversationId);\n\t\t\t\tif (!item.visitorId && item.aiAgentId && state.streamingText.has(conversationId)) {\n\t\t\t\t\tnext.set(conversationId, [\n\t\t\t\t\t\t...existing,\n\t\t\t\t\t\t{ ...item, _stableKey: streamKey } as TimelineItem,\n\t\t\t\t\t]);\n\t\t\t\t\treturn { messages: next };\n\t\t\t\t}\n\t\t\t\tconst echoIndex = item.visitorId\n\t\t\t\t\t? existing.findIndex(\n\t\t\t\t\t\t\t(m) => !!m.visitorId && m.text === item.text && m.id.startsWith(\"optimistic-\"),\n\t\t\t\t\t\t)\n\t\t\t\t\t: -1;\n\t\t\t\tif (echoIndex >= 0) {\n\t\t\t\t\tconst optimistic = existing[echoIndex] as TimelineItem & { _stableKey?: string };\n\t\t\t\t\tconst merged = [...existing];\n\t\t\t\t\tmerged[echoIndex] = {\n\t\t\t\t\t\t...item,\n\t\t\t\t\t\t_stableKey: optimistic._stableKey ?? optimistic.id,\n\t\t\t\t\t} as TimelineItem;\n\t\t\t\t\tnext.set(conversationId, merged);\n\t\t\t\t\treturn { messages: next };\n\t\t\t\t}\n\t\t\t\t// Agent welcome messages are always the opener of a conversation.\n\t\t\t\t// If the first existing item is a visitor message, prepend the welcome\n\t\t\t\t// so the greeting stays above — don't rely on createdAt (client clock\n\t\t\t\t// vs server clock drift can flip the order).\n\t\t\t\tconst isAgentWelcome = !!item.aiAgentId && !item.visitorId;\n\t\t\t\tconst firstIsVisitor = existing[0]?.visitorId != null;\n\t\t\t\tif (isAgentWelcome && firstIsVisitor) {\n\t\t\t\t\tnext.set(conversationId, [item, ...existing]);\n\t\t\t\t\treturn { messages: next };\n\t\t\t\t}\n\t\t\t\t// General case: insert chronologically. Sort only when the newcomer\n\t\t\t\t// is older than the current tail (rare — WS reorders).\n\t\t\t\tconst last = existing[existing.length - 1];\n\t\t\t\tconst isOutOfOrder = last && item.createdAt < last.createdAt;\n\t\t\t\tconst merged = [...existing, item];\n\t\t\t\tif (isOutOfOrder) {\n\t\t\t\t\tmerged.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n\t\t\t\t}\n\t\t\t\tnext.set(conversationId, merged);\n\t\t\t\treturn { messages: next };\n\t\t\t});\n\t\t},\n\n\t\treplaceMessage(conversationId, oldId, item) {\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.messages);\n\t\t\t\tconst existing = next.get(conversationId) ?? [];\n\t\t\t\t// Race with WS echo: if the real item already landed, just drop the optimistic\n\t\t\t\tif (existing.some((m) => m.id === item.id && m.id !== oldId)) {\n\t\t\t\t\tnext.set(\n\t\t\t\t\t\tconversationId,\n\t\t\t\t\t\texisting.filter((m) => m.id !== oldId),\n\t\t\t\t\t);\n\t\t\t\t\treturn { messages: next };\n\t\t\t\t}\n\t\t\t\t// Preserve the optimistic ID as _stableKey so the React key\n\t\t\t\t// stays constant across the optimistic → real ID swap.\n\t\t\t\tnext.set(\n\t\t\t\t\tconversationId,\n\t\t\t\t\texisting.map((m) =>\n\t\t\t\t\t\tm.id === oldId\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t...item,\n\t\t\t\t\t\t\t\t\t_stableKey: (m as unknown as { _stableKey?: string })._stableKey ?? oldId,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: m,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\treturn { messages: next };\n\t\t\t});\n\t\t},\n\n\t\tremoveMessage(conversationId, id) {\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.messages);\n\t\t\t\tconst existing = next.get(conversationId);\n\t\t\t\tif (!existing) return state;\n\t\t\t\tnext.set(\n\t\t\t\t\tconversationId,\n\t\t\t\t\texisting.filter((m) => m.id !== id),\n\t\t\t\t);\n\t\t\t\treturn { messages: next };\n\t\t\t});\n\t\t},\n\n\t\tremapConversationId(oldId, newId) {\n\t\t\tset((state) => {\n\t\t\t\t// Merge messages from tempId + newId — WS echo may have inserted\n\t\t\t\t// items under the real id BEFORE the createConversation mutation\n\t\t\t\t// resolved. Dedupe by id so we don't lose the WS-delivered items.\n\t\t\t\tconst nextMessages = new Map(state.messages);\n\t\t\t\tconst tempItems = nextMessages.get(oldId) ?? [];\n\t\t\t\tconst existingItems = nextMessages.get(newId) ?? [];\n\t\t\t\tconst tempRewritten = tempItems.map((m) => ({ ...m, conversationId: newId }));\n\t\t\t\tconst isAgentMsg = (m: TimelineItem) => !!m.aiAgentId && !m.visitorId && !m.userId;\n\t\t\t\t// Prefer the seed welcome that came in via the temp conversation.\n\t\t\t\t// Keeping its DOM node stable is the whole point of openNewConversation\n\t\t\t\t// seeding; if we let the server-welcome (different id, same text)\n\t\t\t\t// take its slot, React unmounts the seed bubble and the animation\n\t\t\t\t// replays — exactly the \"git-gel\" the seed exists to prevent.\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\tconst merged: TimelineItem[] = [];\n\t\t\t\tlet keptAgentWelcome = false;\n\t\t\t\tfor (const m of tempRewritten) {\n\t\t\t\t\tif (seen.has(m.id)) continue;\n\t\t\t\t\tseen.add(m.id);\n\t\t\t\t\tmerged.push(m);\n\t\t\t\t\tif (isAgentMsg(m) && merged.length === 1) keptAgentWelcome = true;\n\t\t\t\t}\n\t\t\t\t// The server's welcome echo is the agent item that predates the\n\t\t\t\t// visitor's first server item (the API stamps it visitorTs - 1ms).\n\t\t\t\t// WS delivery is ordered, so if a genuine AI reply made it into\n\t\t\t\t// existingItems, the visitor item did too — when no visitor item\n\t\t\t\t// is present, the only agent item that can have arrived is the\n\t\t\t\t// welcome. Graft its identity onto the seed bubble (same DOM node\n\t\t\t\t// via _stableKey, real ULID for future dedup) instead of dropping\n\t\t\t\t// it; later agent items are genuine AI replies and MUST be kept.\n\t\t\t\tconst serverVisitorTs = existingItems.find((x) => x.visitorId)?.createdAt;\n\t\t\t\t/* The visitor's own message needs the same graft the welcome gets.\n\t\t\t\t It was sent optimistically under the temp conversation with a\n\t\t\t\t client id, and the server echoes it back under a real ULID — two\n\t\t\t\t different ids, so the id-only dedupe above keeps both and the\n\t\t\t\t visitor watches their own bubble render twice. Matched on text and\n\t\t\t\t claimed once, so sending the same words twice still shows twice. */\n\t\t\t\tconst isVisitorMsg = (m: TimelineItem) => !!m.visitorId && !m.aiAgentId && !m.userId;\n\t\t\t\tconst pendingVisitor = new Map<string, number>();\n\t\t\t\tmerged.forEach((m, i) => {\n\t\t\t\t\tif (isVisitorMsg(m) && typeof m.text === \"string\" && !pendingVisitor.has(m.text)) {\n\t\t\t\t\t\tpendingVisitor.set(m.text, i);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tlet graftedWelcome = false;\n\t\t\t\tfor (const m of existingItems) {\n\t\t\t\t\tif (seen.has(m.id)) continue;\n\t\t\t\t\tif (isVisitorMsg(m) && typeof m.text === \"string\" && pendingVisitor.has(m.text)) {\n\t\t\t\t\t\tconst idx = pendingVisitor.get(m.text) as number;\n\t\t\t\t\t\tpendingVisitor.delete(m.text);\n\t\t\t\t\t\tconst optimistic = merged[idx];\n\t\t\t\t\t\tmerged[idx] = {\n\t\t\t\t\t\t\t...m,\n\t\t\t\t\t\t\t_stableKey: optimistic\n\t\t\t\t\t\t\t\t? ((optimistic as unknown as { _stableKey?: string })._stableKey ?? optimistic.id)\n\t\t\t\t\t\t\t\t: m.id,\n\t\t\t\t\t\t} as TimelineItem;\n\t\t\t\t\t\tseen.add(m.id);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst isWelcomeEcho =\n\t\t\t\t\t\tisAgentMsg(m) &&\n\t\t\t\t\t\tkeptAgentWelcome &&\n\t\t\t\t\t\t!graftedWelcome &&\n\t\t\t\t\t\t(!serverVisitorTs || m.createdAt <= serverVisitorTs);\n\t\t\t\t\tif (isWelcomeEcho) {\n\t\t\t\t\t\tconst seed = merged[0];\n\t\t\t\t\t\tmerged[0] = {\n\t\t\t\t\t\t\t...m,\n\t\t\t\t\t\t\t_stableKey: seed\n\t\t\t\t\t\t\t\t? ((seed as unknown as { _stableKey?: string })._stableKey ?? seed.id)\n\t\t\t\t\t\t\t\t: m.id,\n\t\t\t\t\t\t} as TimelineItem;\n\t\t\t\t\t\tseen.add(m.id);\n\t\t\t\t\t\tgraftedWelcome = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tseen.add(m.id);\n\t\t\t\t\tmerged.push(m);\n\t\t\t\t}\n\t\t\t\tnextMessages.delete(oldId);\n\t\t\t\tnextMessages.set(newId, merged);\n\n\t\t\t\t// Dedupe conversation list — WS conversationCreated may have\n\t\t\t\t// prepended newId already; in that case drop the temp entry.\n\t\t\t\tconst hasNewId = state.conversations.some((c) => c.id === newId);\n\t\t\t\tconst conversations = hasNewId\n\t\t\t\t\t? state.conversations.filter((c) => c.id !== oldId)\n\t\t\t\t\t: state.conversations.map((c) => (c.id === oldId ? { ...c, id: newId } : c));\n\n\t\t\t\t/* Every map keyed by conversationId has to move, not just `messages`.\n\t\t\t\t This dropped three of them, and the visible cost was on the very\n\t\t\t\t first message of a thread: the composer marks aiProcessing under the\n\t\t\t\t TEMP id, createConversation resolves, activeConversationId becomes\n\t\t\t\t the real id — and the panel starts reading aiProcessing.get(realId),\n\t\t\t\t which nothing had written. So the dots appeared, vanished at the\n\t\t\t\t remap, and came back a second or two later when the server's own\n\t\t\t\t aiProcessingProgress finally arrived under the real id. Two loading\n\t\t\t\t phases for one reply, with a hole between them.\n\n\t\t\t\t Renaming a conversation means renaming it everywhere it is keyed;\n\t\t\t\t doing it per-map by hand is how the next map added here inherits the\n\t\t\t\t same bug, so this moves whatever is present under `oldId`. */\n\t\t\t\tconst moveKey = <V,>(m: Map<string, V>): Map<string, V> => {\n\t\t\t\t\tif (!m.has(oldId)) return m;\n\t\t\t\t\tconst next = new Map(m);\n\t\t\t\t\tconst carried = next.get(oldId) as V;\n\t\t\t\t\tnext.delete(oldId);\n\t\t\t\t\t// A value already under newId came from the server and is newer.\n\t\t\t\t\tif (!next.has(newId)) next.set(newId, carried);\n\t\t\t\t\treturn next;\n\t\t\t\t};\n\n\t\t\t\treturn {\n\t\t\t\t\tmessages: nextMessages,\n\t\t\t\t\tconversations,\n\t\t\t\t\ttypingUsers: moveKey(state.typingUsers),\n\t\t\t\t\taiProcessing: moveKey(state.aiProcessing),\n\t\t\t\t\tstreamingText: moveKey(state.streamingText),\n\t\t\t\t\tactiveConversationId:\n\t\t\t\t\t\tstate.activeConversationId === oldId ? newId : state.activeConversationId,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\n\t\t// ── Presence ─────────────────────────────────────\n\n\t\tsetTyping(conversationId, isTyping) {\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.typingUsers);\n\t\t\t\tnext.set(conversationId, isTyping);\n\t\t\t\treturn { typingUsers: next };\n\t\t\t});\n\t\t},\n\n\t\tsetAiProcessing(conversationId, processing) {\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.aiProcessing);\n\t\t\t\tnext.set(conversationId, processing);\n\t\t\t\treturn { aiProcessing: next };\n\t\t\t});\n\t\t},\n\n\t\t/**\n\t\t * `done` no longer clears the text, and that is the whole point.\n\t\t *\n\t\t * The final chunk and the real message are two separate WebSocket frames.\n\t\t * Deleting on `done` removed the streamed bubble in the first frame and the\n\t\t * persisted message only arrived in the second — so at the end of every\n\t\t * answer the text vanished and then came back, which is what a reader sees\n\t\t * as the message flickering just as it finishes. React batching cannot help:\n\t\t * two frames are two ticks.\n\t\t *\n\t\t * So a finished stream stays on screen and is retired by whoever proves it is\n\t\t * no longer needed — `timelineItemCreated` for that conversation, or\n\t\t * `aiProcessingCompleted` as a backstop. The server awaits those in that\n\t\t * order (pipeline.ts emits the item, then completion), so the swap happens in\n\t\t * the same tick as the real bubble mounting: one commit, no empty frame.\n\t\t */\n\t\tappendStreamChunk(conversationId, delta, done) {\n\t\t\t/* `done` changes nothing about the delta. The API chunks by four words and\n\t\t\t flags the LAST chunk done (ai/tools.ts), so that frame carries real text —\n\t\t\t skipping it dropped the closing words, and the bubble then had to repaint\n\t\t\t when the persisted message arrived with them. Which is the flicker,\n\t\t\t moved: not a blank frame any more, a rewrite of the final line. `done`\n\t\t\t only means \"no more is coming\"; retiring the text is the job of the\n\t\t\t message that replaces it. */\n\t\t\tvoid done;\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.streamingText);\n\t\t\t\tconst prev = next.get(conversationId) ?? \"\";\n\t\t\t\tnext.set(conversationId, prev + delta);\n\t\t\t\treturn { streamingText: next };\n\t\t\t});\n\t\t},\n\n\t\tclearStream(conversationId) {\n\t\t\tset((state) => {\n\t\t\t\tif (!state.streamingText.has(conversationId)) return {};\n\t\t\t\tconst next = new Map(state.streamingText);\n\t\t\t\tnext.delete(conversationId);\n\t\t\t\treturn { streamingText: next };\n\t\t\t});\n\t\t},\n\n\t\t// ── Identity ─────────────────────────────────────\n\n\t\tupdateVisitorContact(contact) {\n\t\t\tset((state) => ({\n\t\t\t\tvisitor: state.visitor ? { ...state.visitor, contact } : state.visitor,\n\t\t\t}));\n\t\t},\n\n\t\t// ── Unread ───────────────────────────────────────\n\n\t\tclearUnread(conversationId) {\n\t\t\tset((s) => ({\n\t\t\t\tconversations: s.conversations.map((c) =>\n\t\t\t\t\tc.id === conversationId ? { ...c, unreadCount: 0 } : c,\n\t\t\t\t),\n\t\t\t}));\n\t\t},\n\n\t\t// ── UI ───────────────────────────────────────────\n\n\t\tsetOpen(open) {\n\t\t\tset((s) => ({\n\t\t\t\tisOpen: open,\n\t\t\t\tincomingPreview: open ? null : s.incomingPreview,\n\t\t\t\tannouncementPreviews: open ? [] : s.announcementPreviews,\n\t\t\t}));\n\t\t},\n\n\t\tsetPendingContentDetail(value) {\n\t\t\tset({ pendingContentDetail: value });\n\t\t},\n\n\t\tsetDismissed(dismissed) {\n\t\t\tset({ isDismissed: dismissed });\n\t\t},\n\n\t\tsetView(view) {\n\t\t\tset({ view });\n\t\t},\n\n\t\tsetNewConversationPrefill(text) {\n\t\t\tset({ newConversationPrefill: text });\n\t\t},\n\n\t\tdismissPreview() {\n\t\t\tset({ incomingPreview: null });\n\t\t},\n\n\t\t// ── Announcements ────────────────────────────────\n\n\t\tsetAnnouncementPreview(preview) {\n\t\t\tset((s) => ({\n\t\t\t\tannouncementPreviews: [\n\t\t\t\t\t...s.announcementPreviews.filter((p) => p.tabId !== preview.tabId),\n\t\t\t\t\tpreview,\n\t\t\t\t],\n\t\t\t}));\n\t\t},\n\n\t\tdismissAnnouncementPreview(slug) {\n\t\t\tif (slug) {\n\t\t\t\tset((s) => ({\n\t\t\t\t\tannouncementPreviews: s.announcementPreviews.filter((p) => p.slug !== slug),\n\t\t\t\t}));\n\t\t\t} else {\n\t\t\t\tset({ announcementPreviews: [] });\n\t\t\t}\n\t\t},\n\n\t\tsetUnseenAnnouncementCount(count) {\n\t\t\tset({ unseenAnnouncementCount: count });\n\t\t},\n\n\t\t// ── Content Cache ────────────────────────────────\n\n\t\tsetContentCache(key, data) {\n\t\t\tget().contentCache.set(key, { data, ts: Date.now() });\n\t\t},\n\n\t\t// ── Realtime Event Handler ───────────────────────\n\n\t\thandleRealtimeEvent(event) {\n\t\t\tconst state = get();\n\n\t\t\tswitch (event.type) {\n\t\t\t\tcase WsEventType.TimelineItemCreated: {\n\t\t\t\t\t// Only add public messages (widget shouldn't see private notes)\n\t\t\t\t\tif (event.item.visibility === \"public\") {\n\t\t\t\t\t\t// When the widget seeded a local welcome bubble (openNewConversation)\n\t\t\t\t\t\t// the server's createConversation path ALSO emits its own welcome\n\t\t\t\t\t\t// timeline item. The echo usually lands AFTER the optimistic visitor\n\t\t\t\t\t\t// message is already in the list, so we can't gate on list length.\n\t\t\t\t\t\t// The reliable discriminator is the timestamp: the API stamps the\n\t\t\t\t\t\t// welcome 1ms BEFORE the visitor's first message, while a genuine\n\t\t\t\t\t\t// AI reply is always stamped after it — and by the time the seed\n\t\t\t\t\t\t// exists under the server conversation id, the visitor item has\n\t\t\t\t\t\t// already been swapped to its server-stamped twin, so both sides\n\t\t\t\t\t\t// of the comparison come from the server clock (drift-safe).\n\t\t\t\t\t\tconst isAgentAuthored =\n\t\t\t\t\t\t\t!!event.item.aiAgentId && !event.item.visitorId && !event.item.userId;\n\t\t\t\t\t\tconst existing = state.messages.get(event.conversationId);\n\t\t\t\t\t\tconst seedId = existing?.[0]?.id;\n\t\t\t\t\t\tconst hasSeedWelcome = typeof seedId === \"string\" && seedId.startsWith(\"seed-welcome-\");\n\t\t\t\t\t\tif (isAgentAuthored && hasSeedWelcome) {\n\t\t\t\t\t\t\tconst firstVisitorTs = existing?.find((m) => m.visitorId)?.createdAt;\n\t\t\t\t\t\t\tconst isWelcomeEcho = !firstVisitorTs || event.item.createdAt <= firstVisitorTs;\n\t\t\t\t\t\t\tif (isWelcomeEcho) {\n\t\t\t\t\t\t\t\t// Adopt the server identity onto the seed bubble instead of\n\t\t\t\t\t\t\t\t// dropping the event — replaceMessage keeps the seed id as\n\t\t\t\t\t\t\t\t// _stableKey (no remount/flash) and future hydrations dedupe\n\t\t\t\t\t\t\t\t// against the real ULID instead of the synthetic seed id.\n\t\t\t\t\t\t\t\tstate.replaceMessage(event.conversationId, seedId, event.item);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstate.addMessage(event.conversationId, event.item);\n\t\t\t\t\t}\n\t\t\t\t\t// Clear typing/processing indicators as soon as the AI message arrives\n\t\t\t\t\t// (don't wait for aiProcessingCompleted which comes later after auto-title etc.)\n\t\t\t\t\tif (event.item.aiAgentId) {\n\t\t\t\t\t\tstate.setAiProcessing(event.conversationId, false);\n\t\t\t\t\t\tstate.setTyping(event.conversationId, false);\n\t\t\t\t\t\t/* Retire the streamed copy here, in the same tick that mounts the\n\t\t\t\t\t\t real one. Same tick means one React commit, so the reader never\n\t\t\t\t\t\t sees the frame where neither exists. */\n\t\t\t\t\t\tstate.clearStream(event.conversationId);\n\t\t\t\t\t}\n\t\t\t\t\t// Update conversation preview + unread count\n\t\t\t\t\tif (event.item.type === \"message\" && event.item.text) {\n\t\t\t\t\t\tconst isIncoming = !event.item.visitorId; // team or AI message\n\t\t\t\t\t\tconst currentState = get();\n\t\t\t\t\t\tconst isViewingThis =\n\t\t\t\t\t\t\tcurrentState.isOpen && currentState.activeConversationId === event.conversationId;\n\n\t\t\t\t\t\tset((s) => ({\n\t\t\t\t\t\t\tconversations: s.conversations.map((c) =>\n\t\t\t\t\t\t\t\tc.id === event.conversationId\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t...c,\n\t\t\t\t\t\t\t\t\t\t\tlastMessageText: event.item.text,\n\t\t\t\t\t\t\t\t\t\t\tlastMessageAt: event.item.createdAt,\n\t\t\t\t\t\t\t\t\t\t\t// Increment unread if incoming and not actively viewing\n\t\t\t\t\t\t\t\t\t\t\t...(isIncoming && !isViewingThis ? { unreadCount: c.unreadCount + 1 } : {}),\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: c,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t// Show preview bubble if widget is closed and message is incoming\n\t\t\t\t\t\t\t...(isIncoming && !currentState.isOpen\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tincomingPreview: {\n\t\t\t\t\t\t\t\t\t\t\ttext: event.item.text ?? \"\",\n\t\t\t\t\t\t\t\t\t\t\tconversationId: event.conversationId,\n\t\t\t\t\t\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t\t\t\t\t\t\tsenderName:\n\t\t\t\t\t\t\t\t\t\t\t\t(event.item as { userName?: string | null }).userName ?? null,\n\t\t\t\t\t\t\t\t\t\t\tsenderImage:\n\t\t\t\t\t\t\t\t\t\t\t\t(event.item as { userImage?: string | null }).userImage ?? null,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t}));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.ConversationUpdated: {\n\t\t\t\t\tset((s) => ({\n\t\t\t\t\t\tconversations: s.conversations.map((c) =>\n\t\t\t\t\t\t\tc.id === event.conversationId ? { ...c, ...event.updates } : c,\n\t\t\t\t\t\t),\n\t\t\t\t\t}));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.ConversationTyping: {\n\t\t\t\t\t// Only show typing for non-visitor (team/AI typing)\n\t\t\t\t\tif (!event.visitorId) {\n\t\t\t\t\t\tstate.setTyping(event.conversationId, event.isTyping);\n\t\t\t\t\t\t// Auto-clear after 5 seconds\n\t\t\t\t\t\tif (event.isTyping) {\n\t\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\t\tstate.setTyping(event.conversationId, false);\n\t\t\t\t\t\t\t}, 5000);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.AiProcessingProgress: {\n\t\t\t\t\t// Track AI processing separately for distinct UI indicator\n\t\t\t\t\tstate.setAiProcessing(event.conversationId, true);\n\t\t\t\t\tstate.setTyping(event.conversationId, true);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.AiProcessingCompleted: {\n\t\t\t\t\tstate.setAiProcessing(event.conversationId, false);\n\t\t\t\t\tstate.setTyping(event.conversationId, false);\n\t\t\t\t\t/* Backstop: the server emits this after timelineItemCreated, so by now\n\t\t\t\t\t a finished stream has normally already been retired. If that frame\n\t\t\t\t\t was dropped, this is what stops the streamed text lingering as a\n\t\t\t\t\t ghost bubble forever. */\n\t\t\t\t\tstate.clearStream(event.conversationId);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.AiStreamChunk: {\n\t\t\t\t\tstate.setAiProcessing(event.conversationId, false);\n\t\t\t\t\tstate.setTyping(event.conversationId, false);\n\t\t\t\t\tstate.appendStreamChunk(event.conversationId, event.delta, event.done);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.ConversationCreated: {\n\t\t\t\t\t// Race-safe insert: WS may arrive before OR after the HTTP\n\t\t\t\t\t// createConversation response. If after, remapConversationId\n\t\t\t\t\t// already renamed tempId → realId, so the entry exists.\n\t\t\t\t\t// If before, we prepend here; the later remap call hits the\n\t\t\t\t\t// `hasNewId=true` branch and drops the temp entry.\n\t\t\t\t\tconst conv = event.conversation as unknown as {\n\t\t\t\t\t\tid: string;\n\t\t\t\t\t\ttitle: string | null;\n\t\t\t\t\t\tstatus: string;\n\t\t\t\t\t\tlastMessageText?: string | null;\n\t\t\t\t\t\tlastMessageAt?: string | null;\n\t\t\t\t\t\tlastMessageSenderType?: string | null;\n\t\t\t\t\t};\n\t\t\t\t\tconst alreadyPresent = state.conversations.some((c) => c.id === conv.id);\n\t\t\t\t\tif (alreadyPresent) break;\n\t\t\t\t\tstate.addConversation({\n\t\t\t\t\t\tid: conv.id,\n\t\t\t\t\t\ttitle: conv.title,\n\t\t\t\t\t\tstatus: conv.status,\n\t\t\t\t\t\tlastMessageText: conv.lastMessageText ?? null,\n\t\t\t\t\t\tlastMessageAt: conv.lastMessageAt ?? null,\n\t\t\t\t\t\tlastMessageSenderType: conv.lastMessageSenderType ?? null,\n\t\t\t\t\t\tlastMessageSenderName: null,\n\t\t\t\t\t\tlastMessageSenderImage: null,\n\t\t\t\t\t\tassigneeName: null,\n\t\t\t\t\t\tassigneeImage: null,\n\t\t\t\t\t\tunreadCount: 0,\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t},\n\t}));\n\n\t// Single source of persistence for the proactive preview: every\n\t// transition (WS set, setOpen-clears, dismissPreview) passes through\n\t// here, so we don't have to touch each call site.\n\tif (typeof window !== \"undefined\") {\n\t\tlet last = store.getState().incomingPreview;\n\t\tstore.subscribe((s) => {\n\t\t\tif (s.incomingPreview !== last) {\n\t\t\t\tlast = s.incomingPreview;\n\t\t\t\tpersistPreview(s.incomingPreview);\n\t\t\t}\n\t\t});\n\t}\n\n\treturn store;\n}\n","import type { StoreApi } from \"zustand/vanilla\";\nimport type { Listener, WidgetEventEmitter, WidgetEventName, WidgetEvents } from \"./events\";\nimport type { WidgetStore } from \"./store\";\nimport { clearVisitorId } from \"./visitor-id\";\n\n/**\n * The programmatic widget API — all the methods consumers can call\n * once the widget is mounted. Returned by `createHelpwayAPI()`.\n *\n * The global `window.Helpway` is the *callable* wrapper around this\n * (see `HelpwayAPI` and `installCallable`).\n */\nexport interface HelpwayMethods {\n\t/** Open the widget panel */\n\topen(): void;\n\t/** Close the widget panel */\n\tclose(): void;\n\t/** Toggle the widget panel open/closed */\n\ttoggle(): void;\n\t/** Dismiss the widget entirely (launcher + panel). Use for page-specific hiding. */\n\tdismiss(): void;\n\t/** Show the widget again after dismiss */\n\tshow(): void;\n\t/** Full reset: clear session, cookies, visitor identity */\n\tshutdown(): void;\n\t/** Identify the visitor (link to contact) */\n\tidentify(data: {\n\t\texternalId: string;\n\t\temail?: string;\n\t\tname?: string;\n\t\timage?: string;\n\t\tmetadata?: Record<string, unknown>;\n\t}): Promise<void>;\n\t/** Open a new conversation, optionally pre-filling the message */\n\tnewConversation(prefill?: string): void;\n\t/** Open a specific conversation by ID */\n\topenConversation(id: string): void;\n\t/** Get the current unread count */\n\treadonly unreadCount: number;\n\t/** Whether the widget panel is currently open */\n\treadonly isOpen: boolean;\n\t/** Subscribe to widget events */\n\ton<K extends WidgetEventName>(event: K, fn: Listener<WidgetEvents[K]>): void;\n\t/** Unsubscribe from widget events */\n\toff<K extends WidgetEventName>(event: K, fn: Listener<WidgetEvents[K]>): void;\n}\n\n/**\n * The global `window.Helpway` shape: callable (Intercom-style snippet API)\n * AND object (typed methods). Build one of these from a `HelpwayMethods`\n * via `installCallable()`.\n */\nexport interface HelpwayAPI extends HelpwayMethods {\n\t(command: string, ...args: unknown[]): unknown;\n}\n\n/**\n * Install a callable wrapper around any methods object onto `window.Helpway`,\n * draining any calls that the snippet stub queued before the widget mounted.\n * Returns the callable so callers can compare identities on cleanup.\n *\n * Generic in `T` so both the rich `HelpwayMethods` (from widget-react) and\n * the slimmer script-tag API (from widget-embed) can use the same plumbing.\n */\nexport function installCallable<T extends object>(\n\tmethods: T,\n): T & ((command: string, ...args: unknown[]) => unknown) {\n\tconst dispatch = (command: string, ...args: unknown[]): unknown => {\n\t\tconst fn = (methods as unknown as Record<string, unknown>)[command];\n\t\tif (typeof fn === \"function\") {\n\t\t\treturn (fn as (...a: unknown[]) => unknown)(...args);\n\t\t}\n\t\tconsole.warn(`[Helpway] Unknown command: ${command}`);\n\t\treturn undefined;\n\t};\n\tconst callable = Object.assign(dispatch, methods);\n\tconst previous = window.Helpway as { q?: unknown[][] } | undefined;\n\twindow.Helpway = callable as unknown as HelpwayAPI;\n\tconst queue = previous?.q;\n\tif (queue?.length) {\n\t\tfor (const entry of queue) {\n\t\t\ttry {\n\t\t\t\tdispatch(...(entry as [string, ...unknown[]]));\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Helpway] queued call failed:\", err);\n\t\t\t}\n\t\t}\n\t}\n\treturn callable;\n}\n\nexport function createHelpwayAPI(deps: {\n\tstore: StoreApi<WidgetStore>;\n\temitter: WidgetEventEmitter;\n\tidentify: (data: {\n\t\texternalId: string;\n\t\temail?: string;\n\t\tname?: string;\n\t\timage?: string;\n\t\tmetadata?: Record<string, unknown>;\n\t}) => Promise<void>;\n\tapiKey: string;\n}): HelpwayMethods {\n\tconst { store, emitter, identify, apiKey } = deps;\n\n\treturn {\n\t\topen() {\n\t\t\tstore.getState().setOpen(true);\n\t\t\tstore.getState().setDismissed(false);\n\t\t},\n\n\t\tclose() {\n\t\t\tstore.getState().setOpen(false);\n\t\t},\n\n\t\ttoggle() {\n\t\t\tconst s = store.getState();\n\t\t\tif (s.isDismissed) {\n\t\t\t\ts.setDismissed(false);\n\t\t\t\ts.setOpen(true);\n\t\t\t\temitter.emit(\"show\");\n\t\t\t} else {\n\t\t\t\ts.setOpen(!s.isOpen);\n\t\t\t}\n\t\t},\n\n\t\tdismiss() {\n\t\t\tstore.getState().setOpen(false);\n\t\t\tstore.getState().setDismissed(true);\n\t\t\temitter.emit(\"dismiss\");\n\t\t},\n\n\t\tshow() {\n\t\t\tstore.getState().setDismissed(false);\n\t\t\temitter.emit(\"show\");\n\t\t},\n\n\t\tshutdown() {\n\t\t\tstore.getState().setOpen(false);\n\t\t\tstore.getState().setDismissed(false);\n\t\t\tclearVisitorId(apiKey);\n\t\t\tif (typeof document !== \"undefined\") {\n\t\t\t\tdocument.cookie = \"hw_visitor=; Path=/; Max-Age=0\";\n\t\t\t}\n\t\t},\n\n\t\tidentify,\n\n\t\tnewConversation(prefill?: string) {\n\t\t\tconst s = store.getState();\n\t\t\ts.setDismissed(false);\n\t\t\ts.setOpen(true);\n\t\t\ts.setNewConversationPrefill(prefill ?? \"\");\n\t\t},\n\n\t\topenConversation(id: string) {\n\t\t\tconst s = store.getState();\n\t\t\ts.setDismissed(false);\n\t\t\ts.setActiveConversation(id);\n\t\t\ts.setOpen(true);\n\t\t},\n\n\t\tget unreadCount() {\n\t\t\treturn store.getState().conversations.reduce((sum, c) => sum + c.unreadCount, 0);\n\t\t},\n\n\t\tget isOpen() {\n\t\t\treturn store.getState().isOpen;\n\t\t},\n\n\t\ton(event, fn) {\n\t\t\temitter.on(event, fn);\n\t\t},\n\n\t\toff(event, fn) {\n\t\t\temitter.off(event, fn);\n\t\t},\n\t};\n}\n","/**\n * Widget theming — typed surface over the CSS custom properties baked\n * into the default themed widget. Consumers pass a `WidgetTheme` object;\n * `applyTheme` writes the values onto the host element so the cascade\n * picks them up inside the Shadow DOM.\n *\n * Common cases (color, position, radius) get their own first-class\n * fields. Anything else can still be set via `cssVariables` — it's a\n * raw passthrough for custom var names we don't model yet.\n *\n * **Note for SDK consumers:** prefer dashboard-driven theming when you\n * can — changes go live without a redeploy. This API is for runtime-\n * resolved values (multi-tenant, dark/light sync with the host app).\n *\n * @see https://helpway.ai/docs/customization for the full reference,\n * the dashboard config UI, and the multi-tenant example.\n */\n\nexport type WidgetPosition = \"bottom-right\" | \"bottom-left\";\n\n/**\n * Where the widget lives on the page. The conversation UI is identical\n * across all of these — only the shell moves, so this is one prop rather\n * than six components.\n *\n * - `bubble` launcher bottom-right, panel above it (the default)\n * - `docked` composer bar pinned to the foot of the page; the bar IS\n * the composer, so the panel above it renders without one\n * - `spotlight` centred over a scrim, opened by a shortcut\n * - `sidebar` docked full-height rail that pushes page content\n * - `page` the widget is the whole route (e.g. /help)\n * - `mobile` full-height sheet; a placement, not a breakpoint\n */\nexport type WidgetPlacement =\n\t| \"bubble\"\n\t| \"docked\"\n\t| \"spotlight\"\n\t| \"sidebar\"\n\t| \"page\"\n\t| \"mobile\";\n\n/**\n * A way in offered before the visitor has said anything. A bare string is\n * the question; the object form adds the short category label that makes a\n * list of three scannable instead of three sentences to read.\n */\nexport type DockSuggestion = string | { label: string; question: string };\n\nexport interface WidgetTheme {\n\t/** Launcher background + accent color. Hover variant is auto-derived. */\n\tprimaryColor?: string;\n\t/** Text/icon color rendered ON TOP of `primaryColor`. Defaults to white. */\n\tonPrimaryColor?: string;\n\t/** Visitor (outgoing) message bubble background. Defaults to `primaryColor`. */\n\tbubbleColor?: string;\n\t/** Visitor message bubble text color. Defaults to `onPrimaryColor`. */\n\tbubbleTextColor?: string;\n\t/** Widget panel background color. */\n\tbackgroundColor?: string;\n\t/** Widget panel text color. */\n\ttextColor?: string;\n\t/** Border color used inside the panel. */\n\tborderColor?: string;\n\t/** Corner radius for the panel + cards (any valid CSS length). */\n\tradius?: string;\n\t/** Font family stack for everything inside the widget. */\n\tfontFamily?: string;\n\t/** Launcher + panel placement. Defaults to \"bottom-right\". */\n\tposition?: WidgetPosition;\n\t/**\n\t * Which appearance the widget takes.\n\t *\n\t * `\"system\"` follows the VISITOR'S OS, which is the historical default\n\t * and is usually wrong: an embedded support widget lives inside someone\n\t * else's page, and a light page in a dark-OS browser gets a dark widget\n\t * stapled to it. Pass `\"light\"` or `\"dark\"` to match the host page.\n\t * @default \"system\"\n\t */\n\tcolorScheme?: \"light\" | \"dark\" | \"system\";\n\t/**\n\t * Which shell the widget renders in. Defaults to \"bubble\".\n\t * See {@link WidgetPlacement}.\n\t */\n\tplacement?: WidgetPlacement;\n\t/**\n\t * Drop to the `mobile` sheet automatically below `mobileBreakpoint`.\n\t * Defaults to true — a 400px panel on a 390px screen is not a panel.\n\t */\n\tautoMobile?: boolean;\n\t/** Width under which `autoMobile` takes over, in px. Defaults to 480. */\n\tmobileBreakpoint?: number;\n\t/**\n\t * Escape hatch: any CSS custom property not modeled above. Keys must\n\t * start with `--`. Wins over the typed fields above when both set.\n\t */\n\tcssVariables?: Record<`--${string}`, string>;\n}\n\n/** Validate a hex like `#aabbcc`. We're conservative on purpose. */\nfunction isValidHex(color: string): boolean {\n\treturn /^#[0-9a-fA-F]{6}$/.test(color);\n}\n\n/**\n * Lighten a #rrggbb hex by a fixed amount (used as the hover variant\n * of `primaryColor`). Non-hex inputs return unchanged so callers can\n * pass `oklch(...)`, `hsl(...)`, etc. and bring their own hover.\n */\nfunction lighten(hex: string): string {\n\tif (!isValidHex(hex)) return hex;\n\tconst r = Math.min(255, Number.parseInt(hex.slice(1, 3), 16) + 30);\n\tconst g = Math.min(255, Number.parseInt(hex.slice(3, 5), 16) + 30);\n\tconst b = Math.min(255, Number.parseInt(hex.slice(5, 7), 16) + 30);\n\tconst hex2 = (n: number) => n.toString(16).padStart(2, \"0\");\n\treturn `#${hex2(r)}${hex2(g)}${hex2(b)}`;\n}\n\n/** Map a single typed field onto its CSS variable(s). */\nfunction setVar(host: HTMLElement, name: string, value: string | undefined) {\n\tif (value == null || value === \"\") return;\n\thost.style.setProperty(name, value);\n}\n\n/**\n * Write a `WidgetTheme` onto the host element. Safe to call multiple\n * times — every call is incremental, only the keys you provide are\n * touched. Pass `undefined` for a field to leave the existing value alone;\n * call `clearTheme()` if you want to reset.\n */\nexport function applyTheme(host: HTMLElement, theme: WidgetTheme | undefined) {\n\tif (!host || !theme) return;\n\n\tif (theme.primaryColor) {\n\t\tsetVar(host, \"--hw-primary\", theme.primaryColor);\n\t\tsetVar(host, \"--hw-primary-hover\", lighten(theme.primaryColor));\n\t\tsetVar(host, \"--hw-brand\", theme.primaryColor);\n\t}\n\tsetVar(host, \"--hw-on-brand\", theme.onPrimaryColor);\n\tsetVar(host, \"--hw-visitor-bubble-bg\", theme.bubbleColor ?? theme.primaryColor);\n\tsetVar(host, \"--hw-visitor-bubble-text\", theme.bubbleTextColor ?? theme.onPrimaryColor);\n\tsetVar(host, \"--hw-bg\", theme.backgroundColor);\n\tsetVar(host, \"--hw-text\", theme.textColor);\n\tsetVar(host, \"--hw-border\", theme.borderColor);\n\tsetVar(host, \"--hw-radius\", theme.radius);\n\tsetVar(host, \"--hw-font\", theme.fontFamily);\n\n\tif (theme.position === \"bottom-left\") {\n\t\tsetVar(host, \"--hw-position-right\", \"auto\");\n\t\tsetVar(host, \"--hw-position-left\", \"20px\");\n\t\tsetVar(host, \"--hw-window-right\", \"auto\");\n\t\tsetVar(host, \"--hw-window-left\", \"0\");\n\t} else if (theme.position === \"bottom-right\") {\n\t\thost.style.removeProperty(\"--hw-position-right\");\n\t\thost.style.removeProperty(\"--hw-position-left\");\n\t\thost.style.removeProperty(\"--hw-window-right\");\n\t\thost.style.removeProperty(\"--hw-window-left\");\n\t}\n\n\t// The shell reads placement off the host as a data attribute rather\n\t// than a CSS variable — CSS variables cannot drive selectors, and every\n\t// shell rule is a selector (`[data-hw-placement=\"docked\"] .hw-panel`).\n\tif (theme.placement) host.dataset.hwPlacement = theme.placement;\n\n\t// The dark-token blocks are all guarded with\n\t// `.hw-widget:not([data-theme=\"light\"])`, so writing this attribute is\n\t// what actually pins the appearance. \"system\" leaves it unset and the\n\t// prefers-color-scheme media query decides.\n\tif (theme.colorScheme === \"light\" || theme.colorScheme === \"dark\") {\n\t\thost.dataset.theme = theme.colorScheme;\n\t} else if (theme.colorScheme === \"system\") {\n\t\tdelete host.dataset.theme;\n\t}\n\n\tif (theme.cssVariables) {\n\t\tfor (const [key, value] of Object.entries(theme.cssVariables)) {\n\t\t\tif (key.startsWith(\"--\")) host.style.setProperty(key, value);\n\t\t}\n\t}\n}\n\n/**\n * Resolve the placement actually in effect, folding in the automatic\n * mobile drop. Kept out of `applyTheme` so the React layer can call it on\n * every resize without re-writing the whole token set.\n */\nexport function resolvePlacement(\n\ttheme: WidgetTheme | undefined,\n\tviewportWidth: number,\n): WidgetPlacement {\n\tconst requested = theme?.placement ?? \"bubble\";\n\tif (requested === \"mobile\") return \"mobile\";\n\tconst auto = theme?.autoMobile ?? true;\n\tconst breakpoint = theme?.mobileBreakpoint ?? 480;\n\t// `page` owns its whole route, so it stays a page on a phone — it is\n\t// already full-bleed and has no launcher to get in the way.\n\tif (auto && requested !== \"page\" && viewportWidth < breakpoint) return \"mobile\";\n\treturn requested;\n}\n","export type Listener<T = unknown> = (data: T) => void;\n\nexport interface WidgetEvents {\n\topen: undefined;\n\tclose: undefined;\n\tdismiss: undefined;\n\tshow: undefined;\n\tunreadChange: number;\n\tmessageReceived: { conversationId: string; text: string; senderName: string | null };\n\tready: undefined;\n}\n\nexport type WidgetEventName = keyof WidgetEvents;\n\nexport class WidgetEventEmitter {\n\tprivate listeners = new Map<string, Set<Listener>>();\n\n\ton<K extends WidgetEventName>(event: K, fn: Listener<WidgetEvents[K]>): void {\n\t\tif (!this.listeners.has(event)) this.listeners.set(event, new Set());\n\t\tthis.listeners.get(event)!.add(fn as Listener);\n\t}\n\n\toff<K extends WidgetEventName>(event: K, fn: Listener<WidgetEvents[K]>): void {\n\t\tthis.listeners.get(event)?.delete(fn as Listener);\n\t}\n\n\temit<K extends WidgetEventName>(\n\t\tevent: K,\n\t\t...args: WidgetEvents[K] extends undefined ? [] : [WidgetEvents[K]]\n\t): void {\n\t\tconst data = args[0];\n\t\tthis.listeners.get(event)?.forEach((fn) => {\n\t\t\ttry {\n\t\t\t\tfn(data);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[Helpway] Event handler error (${event}):`, err);\n\t\t\t}\n\t\t});\n\t}\n\n\tremoveAll(): void {\n\t\tthis.listeners.clear();\n\t}\n}\n","/**\n * Widget i18n — lightweight, zero-dependency translation system.\n *\n * Architecture:\n * - English strings bundled as fallback (zero-latency, always works)\n * - Other locales fetched from Better i18n CDN at runtime\n * - Locale detection: data-locale > identify metadata > navigator.language > \"en\"\n * - Simple key-value lookup with t(\"widget.key\") syntax\n *\n * CDN URL: https://cdn.better-i18n.com/helpway/widget/{locale}/translations.json\n */\n\n// ── Bundled English fallback strings ────────────────────────\n\nconst en: Record<string, string> = {\n\t// Navigation & tabs\n\t\"widget.home\": \"Home\",\n\t\"widget.messages\": \"Messages\",\n\t\"widget.help\": \"Help\",\n\n\t// Home screen\n\t\"widget.send_us_message\": \"Send us a message\",\n\t\"widget.reply_time\": \"We typically reply in a few minutes\",\n\t\"widget.recent_conversations\": \"Recent conversations\",\n\t\"widget.see_all\": \"See all conversations\",\n\t\"widget.whats_new\": \"What's New\",\n\t\"widget.view_all\": \"View all\",\n\n\t// Messages tab\n\t\"widget.no_messages\": \"No messages yet\",\n\t\"widget.no_messages_desc\": \"Start a conversation to get help\",\n\t\"widget.start_conversation\": \"Start a conversation\",\n\t\"widget.no_preview\": \"No messages yet\",\n\n\t// Conversation\n\t\"widget.new_conversation\": \"New conversation\",\n\t\"widget.talk_to_human\": \"Talk to a human\",\n\t\"widget.talk_to_human_message\": \"I'd like to talk to a human, please.\",\n\t\"widget.aria_options\": \"Conversation options\",\n\t\"widget.resolved_text\": \"This conversation has been resolved\",\n\t\"widget.send_followup\": \"Send a follow-up\",\n\t\"widget.start_a_conversation\": \"Start a conversation\",\n\n\t// Composer\n\t\"widget.placeholder\": \"Send a message...\",\n\t\"widget.placeholder_new\": \"How can we help?\",\n\t\"widget.drop_files\": \"Drop files here\",\n\n\t// CSAT\n\t\"widget.csat_label\": \"How was your experience?\",\n\t\"widget.csat_thanks\": \"Thanks for your feedback!\",\n\n\t// Inline email collection (after AI reply)\n\t\"widget.email_title\": \"Don't miss our reply\",\n\t\"widget.email_subtitle\": \"We'll email you when we respond\",\n\t\"widget.email_placeholder\": \"you@email.com\",\n\t\"widget.email_continue\": \"Send\",\n\t\"widget.email_saved\": \"You'll be notified by email\",\n\t\"widget.email_dismiss\": \"No thanks\",\n\n\t// Errors\n\t\"widget.error_title\": \"Something went wrong\",\n\t\"widget.error_desc\": \"Failed to load. Please try again.\",\n\t\"widget.retry\": \"Retry\",\n\t\"widget.reconnecting\": \"Reconnecting...\",\n\t\"widget.send_error\": \"Message not sent\",\n\n\t// Date separators (today is implicit — never rendered)\n\t\"widget.yesterday\": \"Yesterday\",\n\n\t// Sender labels\n\t\"widget.helpway_ai\": \"Helpway AI\",\n\t\"widget.support\": \"Support\",\n\n\t// Events\n\t\"widget.joined\": \"joined the conversation\",\n\t\"widget.left\": \"left the conversation\",\n\n\t// Content/search\n\t\"widget.content\": \"Content\",\n\t\"widget.search\": \"Search...\",\n\t\"widget.no_results\": \"No results found\",\n\t\"widget.try_different\": \"Try a different search term\",\n\t\"widget.nothing_yet\": \"Nothing here yet\",\n\t\"widget.check_back\": \"Check back later for updates\",\n\t\"widget.load_more\": \"Load more\",\n\t\"widget.loading\": \"Loading...\",\n\n\t// Copy\n\t\"widget.copy\": \"Copy message\",\n\t\"widget.copied\": \"Copied\",\n\n\t// File upload\n\t\"widget.file_too_large\": \"File too large (max 10 MB)\",\n\t\"widget.click_to_open\": \"Click to open\",\n\t\"widget.caption_required\": \"Add a message to send with your attachment\",\n\n\t// Accessibility\n\t\"widget.aria_chat\": \"Support chat\",\n\t\"widget.aria_close\": \"Close\",\n\t\"widget.aria_back\": \"Back\",\n\t\"widget.aria_send\": \"Send message\",\n\t\"widget.aria_open_image\": \"Open image\",\n\t\"widget.aria_attach\": \"Attach file\",\n\t\"widget.aria_dictate\": \"Dictate message\",\n\t\"widget.aria_input\": \"Message input\",\n\t\"widget.aria_remove\": \"Remove\",\n\t\"widget.aria_dismiss\": \"Dismiss\",\n\t\"widget.aria_open\": \"Open support\",\n\t\"widget.aria_close_support\": \"Close support\",\n\t\"widget.aria_good\": \"Good\",\n\t\"widget.aria_bad\": \"Bad\",\n\t\"widget.aria_messages\": \"Messages\",\n\n\t// Time (relative)\n\t\"widget.time_now\": \"now\",\n\t\"widget.time_yesterday\": \"Yesterday\",\n\n\t// Powered by\n\t\"widget.powered_by\": \"Powered by\",\n\n\t// Hero / home screen\n\t/* One line, not two. The second line was \"How can we help?\" — the exact string\n\t the composer's own placeholder shows, two inches below it. The input is what\n\t asks the question; the greeting only has to say hello. */\n\t\"widget.welcome_message\": \"Hi there 👋\",\n\t\"widget.subtitle_text\": \"Usually replies in minutes\",\n};\n\n// ── State ───────────────────────────────────────────────────\n\nlet currentLocale = \"en\";\nlet translations: Record<string, string> = {};\nlet isLoaded = false;\nlet revision = 0; // Incremented on every translation change — React hook watches this\nconst listeners: Array<() => void> = [];\n\n// ── Public API ──────────────────────────────────────────────\n\n/**\n * Translate a key. Falls back to English bundled string, then to the key itself.\n *\n * Supports simple interpolation: t(\"widget.key\", { name: \"John\" })\n * Template: \"Hello {{name}}\" → \"Hello John\"\n */\nexport function t(key: string, params?: Record<string, string | number>): string {\n\tconst value = translations[key] ?? en[key] ?? key;\n\n\tif (!params) return value;\n\n\treturn value.replace(/\\{\\{(\\w+)\\}\\}/g, (_, k: string) => {\n\t\treturn params[k]?.toString() ?? `{{${k}}}`;\n\t});\n}\n\n/** Get the current locale code */\nexport function getLocale(): string {\n\treturn currentLocale;\n}\n\n/** Get current revision number — changes when translations are loaded/updated */\nexport function getI18nRevision(): number {\n\treturn revision;\n}\n\n/** Check if translations have been loaded */\nexport function isI18nReady(): boolean {\n\treturn isLoaded;\n}\n\n/** Subscribe to locale/translation changes. Returns unsubscribe fn. */\nexport function onLocaleChange(fn: () => void): () => void {\n\tlisteners.push(fn);\n\treturn () => {\n\t\tconst idx = listeners.indexOf(fn);\n\t\tif (idx >= 0) listeners.splice(idx, 1);\n\t};\n}\n\n// ── Initialization ──────────────────────────────────────────\n\n/**\n * Detect locale from available signals and fetch translations.\n *\n * Priority:\n * 1. Explicit `locale` param (from data-locale attribute)\n * 2. navigator.language (browser preference)\n * 3. \"en\" fallback\n */\nexport async function initI18n(options?: { locale?: string; cdnBase?: string }): Promise<void> {\n\tif (options?.cdnBase) {\n\t\tcdnBase = options.cdnBase;\n\t}\n\n\tconst detected =\n\t\toptions?.locale ?? (typeof navigator !== \"undefined\" ? navigator.language : \"en\");\n\n\t// Normalize: \"fr-FR\" → \"fr\", \"pt-BR\" → \"pt-BR\" (keep regional if meaningful)\n\tcurrentLocale = normalizeLocale(detected);\n\n\t// English is bundled — no fetch needed\n\tif (currentLocale === \"en\") {\n\t\tisLoaded = true;\n\t\tnotify();\n\t\treturn;\n\t}\n\n\t// Fetch from CDN\n\ttry {\n\t\tconst data = await fetchTranslations(currentLocale);\n\t\tif (data) {\n\t\t\t// Only pick widget.* keys from the full namespace bundle\n\t\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\ttranslations[`widget.${key}`] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch (err) {\n\t\tconsole.warn(`[Helpway] Failed to fetch ${currentLocale} translations, using English`, err);\n\t}\n\n\tisLoaded = true;\n\tnotify();\n}\n\n/**\n * Update locale at runtime (e.g., after identify() provides metadata.locale).\n * Re-fetches translations if locale changed.\n */\nexport async function setLocale(locale: string): Promise<void> {\n\tconst normalized = normalizeLocale(locale);\n\tif (normalized === currentLocale) return;\n\n\tcurrentLocale = normalized;\n\ttranslations = {}; // Clear old translations\n\n\tif (normalized === \"en\") {\n\t\tnotify();\n\t\treturn;\n\t}\n\n\ttry {\n\t\tconst data = await fetchTranslations(normalized);\n\t\tif (data) {\n\t\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\ttranslations[`widget.${key}`] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Silent fallback to English\n\t}\n\n\tnotify();\n}\n\n// ── Internals ───────────────────────────────────────────────\n\nlet cdnBase = \"https://cdn.better-i18n.com/helpway/widget\";\n\nasync function fetchTranslations(locale: string): Promise<Record<string, string> | null> {\n\t// All namespaces live in a single translations.json — widget keys nested under \"widget\" key\n\tconst url = `${cdnBase}/${locale}/translations.json`;\n\n\tlet res = await fetch(url);\n\tif (!res.ok && locale.includes(\"-\")) {\n\t\t// Try base locale: \"pt-BR\" → \"pt\"\n\t\tconst base = locale.split(\"-\")[0];\n\t\tres = await fetch(`${cdnBase}/${base}/translations.json`);\n\t}\n\tif (!res.ok) return null;\n\n\tconst data: Record<string, unknown> = await res.json();\n\t// CDN structure is nested: { \"widget\": { \"home\": \"Ana Sayfa\", ... }, \"sidebar\": {...} }\n\tconst widgetNs = data.widget;\n\tif (widgetNs && typeof widgetNs === \"object\" && !Array.isArray(widgetNs)) {\n\t\tconst result: Record<string, string> = {};\n\t\tfor (const [k, v] of Object.entries(widgetNs)) {\n\t\t\tif (typeof v === \"string\") result[k] = v;\n\t\t}\n\t\treturn result;\n\t}\n\treturn null;\n}\n\nfunction normalizeLocale(input: string): string {\n\t// Keep regional variants that are commonly distinct: pt-BR, zh-CN, zh-TW\n\tconst regional = [\"pt-br\", \"zh-cn\", \"zh-tw\", \"zh-hk\"];\n\tconst lower = input.toLowerCase().replace(\"_\", \"-\");\n\n\tfor (const r of regional) {\n\t\tif (lower.startsWith(r)) return r;\n\t}\n\n\t// Otherwise just use base: \"fr-FR\" → \"fr\"\n\treturn lower.split(\"-\")[0] ?? \"en\";\n}\n\nfunction notify(): void {\n\trevision++;\n\tfor (const fn of listeners) {\n\t\ttry {\n\t\t\tfn();\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t}\n}\n","import { t, getLocale } from \"./i18n\";\n\n/**\n * Format a date as relative time string.\n * Uses i18n for \"now\" and \"Yesterday\". Locale-aware date formatting.\n */\nexport function formatRelativeTime(date: string | Date): string {\n\tconst now = Date.now();\n\tconst then = typeof date === \"string\" ? new Date(date).getTime() : date.getTime();\n\tconst diffMs = now - then;\n\tconst diffMin = Math.floor(diffMs / 60000);\n\tconst diffHour = Math.floor(diffMs / 3600000);\n\tconst diffDay = Math.floor(diffMs / 86400000);\n\n\tif (diffMin < 1) return t(\"widget.time_now\");\n\tif (diffMin < 60) return `${diffMin}m`;\n\tif (diffHour < 24) return `${diffHour}h`;\n\tif (diffDay === 1) return t(\"widget.time_yesterday\");\n\tif (diffDay < 7) return `${diffDay}d`;\n\n\tconst d = typeof date === \"string\" ? new Date(date) : date;\n\treturn d.toLocaleDateString(getLocale(), { month: \"short\", day: \"numeric\" });\n}\n\n/**\n * Format time for message bubbles (HH:MM).\n */\nexport function formatTime(date: string | Date): string {\n\tconst d = typeof date === \"string\" ? new Date(date) : date;\n\treturn d.toLocaleTimeString(undefined, { hour: \"2-digit\", minute: \"2-digit\" });\n}\n\n/**\n * Resolve a label that may be a translation key (\"widget.*\") or plain text.\n * When the key resolves to itself (missing), falls back to a humanized form\n * so the UI never leaks raw \"widget.changelog\" strings to the visitor.\n */\nexport function resolveLabel(label: string): string {\n\tif (!label.startsWith(\"widget.\")) return label;\n\tconst resolved = t(label);\n\tif (resolved === label) {\n\t\treturn label\n\t\t\t.replace(\"widget.\", \"\")\n\t\t\t.replace(/_/g, \" \")\n\t\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n\t}\n\treturn resolved;\n}\n\n/**\n * Get initials from a name or email.\n */\nexport function getInitials(value: string): string {\n\tif (!value) return \"?\";\n\n\t// Email: take first letter\n\tif (value.includes(\"@\")) return (value[0] ?? \"?\").toUpperCase();\n\n\t// Name: take first letter of first two words\n\tconst parts = value.trim().split(/\\s+/);\n\tif (parts.length >= 2) {\n\t\treturn ((parts[0]?.[0] ?? \"\") + (parts[1]?.[0] ?? \"\")).toUpperCase();\n\t}\n\treturn (parts[0]?.[0] ?? \"?\").toUpperCase();\n}\n","\"use client\";\n\nimport {\n\tWebSocketManager,\n\tWidgetEventEmitter,\n\ttype HelpwayMethods,\n\ttype WidgetClient,\n\ttype WidgetStore,\n\ttype WidgetTheme,\n\tapplyTheme,\n\tcreateHelpwayAPI,\n\tcreateWidgetClient,\n\tcreateWidgetStore,\n\tinitI18n,\n\tinstallCallable,\n\tsetLocale,\n\tsyncVisitorId,\n} from \"@helpway/widget-core\";\nimport {\n\ttype ReactNode,\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { type StoreApi, useStore } from \"zustand\";\n\n// ── Context ──────────────────────────────────────────────\n\nexport interface IdentifyData {\n\texternalId: string;\n\temail?: string;\n\tname?: string;\n\timage?: string;\n\tmetadata?: Record<string, unknown>;\n}\n\ninterface WidgetContextValue {\n\tclient: WidgetClient;\n\tstore: StoreApi<WidgetStore>;\n\tws: WebSocketManager;\n\tidentify: (data: IdentifyData) => Promise<void>;\n\tapi: HelpwayMethods;\n\temitter: WidgetEventEmitter;\n\thasBootstrapError: boolean;\n\twsDisconnected: boolean;\n\tretryBootstrap: () => void;\n}\n\nconst WidgetContext = createContext<WidgetContextValue | null>(null);\n\nexport function useWidgetContext(): WidgetContextValue {\n\tconst ctx = useContext(WidgetContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useWidgetContext must be used within <SupportProvider>\");\n\t}\n\treturn ctx;\n}\n\n/** Use a slice of the widget store with auto re-render */\nexport function useWidgetStore<T>(selector: (state: WidgetStore) => T): T {\n\tconst { store } = useWidgetContext();\n\treturn useStore(store, selector);\n}\n\n/** Hook to identify the current visitor (link to customer contact) */\nexport function useIdentify() {\n\tconst { identify } = useWidgetContext();\n\treturn identify;\n}\n\n/** Raw tRPC client — used by interactive components that need to call\n * mutations not exposed via the public HelpwayMethods (e.g. workflow\n * quick-reply taps). The client is `any`-typed by design (see\n * packages/widget-core/src/client.ts) so callers must spell mutation\n * paths explicitly. */\nexport function useWidgetClient(): WidgetClient {\n\tconst { client } = useWidgetContext();\n\treturn client;\n}\n\n// ── Provider ─────────────────────────────────────────────\n\ninterface SupportProviderProps {\n\tapiKey: string;\n\tapiUrl?: string;\n\tlocale?: string;\n\tinitialConversationId?: string;\n\tdeepLinkToken?: string;\n\tonReady?: (api: HelpwayMethods) => void;\n\tcustomLauncherSelector?: string;\n\tonOpen?: () => void;\n\tonClose?: () => void;\n\tonUnreadChange?: (count: number) => void;\n\t/**\n\t * Developer-side theme override. Most consumers should configure\n\t * appearance in the Helpway dashboard (see\n\t * https://helpway.ai/docs/customization) so changes apply without\n\t * a redeploy. Use this prop only when you need the widget to inherit\n\t * a host-app theme that the dashboard can't see (e.g. a tenant-\n\t * specific brand color resolved at runtime). Values here are written\n\t * as CSS custom properties on the widget host and override the\n\t * dashboard config for this mount only.\n\t */\n\ttheme?: WidgetTheme;\n\tchildren: ReactNode;\n}\n\n/**\n * Root provider for the Helpway widget.\n * Creates tRPC client, WebSocket connection, and state store.\n *\n * Visitor identity is managed via server-side cookies (hw_visitor).\n * No localStorage or client-side ID management needed.\n */\nexport function SupportProvider({\n\tapiKey,\n\tapiUrl,\n\tlocale,\n\tinitialConversationId,\n\tdeepLinkToken,\n\tonReady,\n\tcustomLauncherSelector,\n\tonOpen,\n\tonClose,\n\tonUnreadChange,\n\ttheme,\n\tchildren,\n}: SupportProviderProps) {\n\tconst initRef = useRef<{\n\t\tclient: WidgetClient;\n\t\tstore: StoreApi<WidgetStore>;\n\t\tws: WebSocketManager;\n\t\tidentify: (data: IdentifyData) => Promise<void>;\n\t\tapi: HelpwayMethods;\n\t\temitter: WidgetEventEmitter;\n\t} | null>(null);\n\tconst [hasBootstrapError, setHasBootstrapError] = useState(false);\n\tconst [wsDisconnected, setWsDisconnected] = useState(false);\n\tconst [bootstrapAttempt, setBootstrapAttempt] = useState(0);\n\n\tif (!initRef.current) {\n\t\tconst resolvedApiUrl = apiUrl ?? inferApiUrl();\n\n\t\tconst client = createWidgetClient({\n\t\t\tapiUrl: resolvedApiUrl,\n\t\t\tapiKey,\n\t\t});\n\n\t\tconst store = createWidgetStore();\n\t\tconst emitter = new WidgetEventEmitter();\n\n\t\tconst ws = new WebSocketManager({\n\t\t\tapiUrl: resolvedApiUrl,\n\t\t\tvisitorId: \"\",\n\t\t\twebsiteId: \"\",\n\t\t\tapiKey,\n\t\t});\n\n\t\tconst identify = async (data: IdentifyData) => {\n\t\t\ttry {\n\t\t\t\tconst result = await client.widget.identify.mutate(data);\n\t\t\t\tif (result.contact) {\n\t\t\t\t\tstore.getState().updateVisitorContact({\n\t\t\t\t\t\tid: result.contact.id,\n\t\t\t\t\t\tname: result.contact.name ?? null,\n\t\t\t\t\t\temail: result.contact.email ?? null,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst metaLocale = data.metadata?.locale;\n\t\t\t\tif (typeof metaLocale === \"string\" && metaLocale.length > 0) {\n\t\t\t\t\tsetLocale(metaLocale);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Helpway] identify failed:\", err);\n\t\t\t}\n\t\t};\n\n\t\tconst api = createHelpwayAPI({ store, emitter, identify, apiKey });\n\n\t\t// Lazy init, once. react-doctor flags this as a ref mutated during\n\t\t// render and it is wrong to \"fix\": the values are consumed on this\n\t\t// same render two lines down, so moving the assignment into an\n\t\t// effect leaves client/store undefined on first paint. This is the\n\t\t// shape React's own docs sanction for expensive one-time setup.\n\t\tinitRef.current = { client, store, ws, identify, api, emitter };\n\t}\n\n\tconst { client, store, ws, identify, api, emitter } = initRef.current;\n\n\tconst retryBootstrap = useCallback(() => {\n\t\tsetHasBootstrapError(false);\n\t\tsetBootstrapAttempt((n) => n + 1);\n\t}, []);\n\n\t// Bootstrap on mount (re-runs on retry)\n\tuseEffect(() => {\n\t\tlet cancelled = false;\n\n\t\tasync function bootstrap() {\n\t\t\ttry {\n\t\t\t\tconst data = await client.widget.bootstrap.query();\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\t// Initialize i18n BEFORE setReady to avoid flash of English text.\n\t\t\t\t// Priority: explicit `locale` prop → server-side detection\n\t\t\t\t// (Accept-Language + CF-IPCountry) → widget-core bundled default.\n\t\t\t\tconst resolvedLocale =\n\t\t\t\t\tlocale ?? (data as { detectedLocale?: string | null }).detectedLocale ?? undefined;\n\t\t\t\tawait initI18n({\n\t\t\t\t\tlocale: resolvedLocale,\n\t\t\t\t\tcdnBase: (data.agentConfig as { i18nCdnBase?: string } | null)?.i18nCdnBase ?? undefined,\n\t\t\t\t});\n\n\t\t\t\tstore.getState().setReady(data.visitor, data.website, data.agentConfig);\n\t\t\t\tsetHasBootstrapError(false);\n\n\t\t\t\t// Sync server-assigned visitor ID to localStorage\n\t\t\t\t// Ensures client uses canonical ID on subsequent page loads\n\t\t\t\tif (data.visitor?.id) {\n\t\t\t\t\tsyncVisitorId(apiKey, data.visitor.id);\n\t\t\t\t}\n\n\t\t\t\tconst convData = await client.widget.listConversations.query();\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\tconst mapConversation = (c: {\n\t\t\t\t\tid: string;\n\t\t\t\t\ttitle: string | null;\n\t\t\t\t\tstatus: string;\n\t\t\t\t\tlastMessageText: string | null;\n\t\t\t\t\tlastMessageAt: string | null;\n\t\t\t\t\tlastMessageSenderType: string | null;\n\t\t\t\t\tlastMessageSenderName: string | null;\n\t\t\t\t\tlastMessageSenderImage: string | null;\n\t\t\t\t}) => ({\n\t\t\t\t\tid: c.id,\n\t\t\t\t\ttitle: c.title,\n\t\t\t\t\tstatus: c.status,\n\t\t\t\t\tlastMessageText: c.lastMessageText,\n\t\t\t\t\tlastMessageAt: c.lastMessageAt,\n\t\t\t\t\tlastMessageSenderType: c.lastMessageSenderType,\n\t\t\t\t\tlastMessageSenderName: c.lastMessageSenderName,\n\t\t\t\t\tlastMessageSenderImage: c.lastMessageSenderImage,\n\t\t\t\t\tunreadCount: 0,\n\t\t\t\t});\n\n\t\t\t\tstore.getState().setConversations(\n\t\t\t\t\tconvData.conversations.map(mapConversation),\n\t\t\t\t);\n\n\t\t\t\t// Connect WebSocket BEFORE the proactive check so the visitor-channel\n\t\t\t\t// subscription is live by the time the workflow orchestrator emits\n\t\t\t\t// timelineItemCreated. Without this, the greeting message is broadcast\n\t\t\t\t// to a not-yet-subscribed client and the launcher preview bubble never\n\t\t\t\t// appears (only the unread badge increments via REST).\n\t\t\t\tif (data.website?.id && data.visitor?.id) {\n\t\t\t\t\tws.configure({ websiteId: data.website.id, visitorId: data.visitor.id });\n\t\t\t\t\tws.connect();\n\t\t\t\t}\n\n\t\t\t\tif (convData.conversations.length === 0 && !initialConversationId) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst proactive = await client.widget.proactiveCheck.mutate();\n\t\t\t\t\t\tif (cancelled || !proactive.triggered) {\n\t\t\t\t\t\t\t// nothing to do\n\t\t\t\t\t\t} else if (proactive.ephemeral) {\n\t\t\t\t\t\t\t// Render the greeting + (optional) quick replies entirely\n\t\t\t\t\t\t\t// client-side. No server-side conversation exists yet — we\n\t\t\t\t\t\t\t// materialize on the visitor's first reply.\n\t\t\t\t\t\t\thandleEphemeralProactive(store, proactive.ephemeral);\n\t\t\t\t\t\t} else if (proactive.conversationId) {\n\t\t\t\t\t\t\t// Fallback path for complex workflows that needed the\n\t\t\t\t\t\t\t// orchestrator up-front (delays, AI agent before any\n\t\t\t\t\t\t\t// visitor input, etc).\n\t\t\t\t\t\t\tconst nowIso = new Date().toISOString();\n\t\t\t\t\t\t\tstore.getState().addConversation({\n\t\t\t\t\t\t\t\tid: proactive.conversationId,\n\t\t\t\t\t\t\t\ttitle: null,\n\t\t\t\t\t\t\t\tstatus: \"open\",\n\t\t\t\t\t\t\t\tlastMessageText: proactive.lastMessageText ?? null,\n\t\t\t\t\t\t\t\tlastMessageAt: proactive.lastMessageAt ?? nowIso,\n\t\t\t\t\t\t\t\tlastMessageSenderType: proactive.lastMessageSenderType ?? null,\n\t\t\t\t\t\t\t\tlastMessageSenderName: null,\n\t\t\t\t\t\t\t\tlastMessageSenderImage: null,\n\t\t\t\t\t\t\t\tassigneeName: null,\n\t\t\t\t\t\t\t\tassigneeImage: null,\n\t\t\t\t\t\t\t\tunreadCount: 1,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (proactive.lastMessageText && !store.getState().isOpen) {\n\t\t\t\t\t\t\t\tstore.setState({\n\t\t\t\t\t\t\t\t\tincomingPreview: {\n\t\t\t\t\t\t\t\t\t\ttext: proactive.lastMessageText,\n\t\t\t\t\t\t\t\t\t\tconversationId: proactive.conversationId,\n\t\t\t\t\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// proactive check is best-effort\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\t\tclient.widget.updatePage\n\t\t\t\t\t\t.mutate({\n\t\t\t\t\t\t\turl: window.location.href,\n\t\t\t\t\t\t\ttitle: document.title || window.location.pathname,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => {});\n\t\t\t\t}\n\n\t\t\t\tif (initialConversationId && !cancelled) {\n\t\t\t\t\tif (deepLinkToken) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst redeemed = await client.widget.redeemDeepLink.mutate({ token: deepLinkToken });\n\t\t\t\t\t\t\tif (!cancelled && redeemed?.visitorId && redeemed.visitorId !== data.visitor?.id) {\n\t\t\t\t\t\t\t\tsyncVisitorId(apiKey, redeemed.visitorId);\n\t\t\t\t\t\t\t\tconst freshData = await client.widget.bootstrap.query();\n\t\t\t\t\t\t\t\tif (!cancelled) {\n\t\t\t\t\t\t\t\t\tstore.getState().setReady(freshData.visitor, freshData.website, freshData.agentConfig);\n\t\t\t\t\t\t\t\t\tconst freshConvs = await client.widget.listConversations.query();\n\t\t\t\t\t\t\t\t\tif (!cancelled) {\n\t\t\t\t\t\t\t\t\t\tstore.getState().setConversations(\n\t\t\t\t\t\t\t\t\t\t\tfreshConvs.conversations.map(mapConversation),\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Token invalid/expired — still open widget but without identity restoration\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!cancelled) {\n\t\t\t\t\t\tstore.getState().setActiveConversation(initialConversationId);\n\t\t\t\t\t\tstore.getState().setOpen(true);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\temitter.emit(\"ready\");\n\t\t\t\tonReady?.(initRef.current!.api);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Helpway] Bootstrap failed:\", err);\n\t\t\t\tif (!cancelled) {\n\t\t\t\t\tstore.getState().setConnecting(false);\n\t\t\t\t\tsetHasBootstrapError(true);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbootstrap();\n\n\t\t// SPA route tracking — patches pushState/replaceState + listens for\n\t\t// popstate so updatePage fires whenever the visitor navigates without\n\t\t// a full reload. Server stores last 20 page views in visitor.pageHistory\n\t\t// for support agent context.\n\t\tlet pageDebounce: ReturnType<typeof setTimeout> | null = null;\n\t\tconst reportPage = () => {\n\t\t\tif (typeof window === \"undefined\") return;\n\t\t\tif (pageDebounce) clearTimeout(pageDebounce);\n\t\t\tpageDebounce = setTimeout(() => {\n\t\t\t\tclient.widget.updatePage\n\t\t\t\t\t.mutate({\n\t\t\t\t\t\turl: window.location.href,\n\t\t\t\t\t\ttitle: document.title || window.location.pathname,\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {});\n\t\t\t}, 250);\n\t\t};\n\n\t\tconst origPush = window.history.pushState.bind(window.history);\n\t\tconst origReplace = window.history.replaceState.bind(window.history);\n\t\twindow.history.pushState = function patchedPush(...args) {\n\t\t\torigPush(...args);\n\t\t\treportPage();\n\t\t};\n\t\twindow.history.replaceState = function patchedReplace(...args) {\n\t\t\torigReplace(...args);\n\t\t\treportPage();\n\t\t};\n\t\twindow.addEventListener(\"popstate\", reportPage);\n\n\t\t// Debounced markSeen — coalesces rapid events (AI may stream multiple\n\t\t// messages, plus the typing/processing events fire too).\n\t\tlet markSeenTimer: ReturnType<typeof setTimeout> | null = null;\n\t\tconst scheduleMarkSeen = (conversationId: string) => {\n\t\t\tif (markSeenTimer) clearTimeout(markSeenTimer);\n\t\t\tmarkSeenTimer = setTimeout(() => {\n\t\t\t\tclient.widget.markSeen.mutate({ conversationId }).catch(() => {});\n\t\t\t\tstore.getState().clearUnread(conversationId);\n\t\t\t}, 400);\n\t\t};\n\n\t\tconst unsub = ws.onEvent((event) => {\n\t\t\tstore.getState().handleRealtimeEvent(event);\n\n\t\t\tif (event.type === \"timelineItemCreated\") {\n\t\t\t\tconst item = event.item;\n\t\t\t\tconst isPublicIncoming = item?.visibility === \"public\" && !item.visitorId;\n\n\t\t\t\t// Emit messageReceived for public incoming messages\n\t\t\t\tif (isPublicIncoming && item?.text) {\n\t\t\t\t\temitter.emit(\"messageReceived\", {\n\t\t\t\t\t\tconversationId: event.conversationId,\n\t\t\t\t\t\ttext: item.text,\n\t\t\t\t\t\tsenderName: \"aiAgentId\" in item && item.aiAgentId ? \"AI\" : null,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (!isPublicIncoming) return;\n\t\t\t\tconst s = store.getState();\n\t\t\t\tconst isViewing = s.isOpen && s.activeConversationId === event.conversationId;\n\t\t\t\tif (isViewing) scheduleMarkSeen(event.conversationId);\n\t\t\t}\n\t\t});\n\n\t\t/* Monitor WebSocket connection state.\n\n\t\t A reconnect that heals in well under a second is not worth telling anyone\n\t\t about, and the old shape reported it anyway: a bare 3s poll of isConnected\n\t\t could catch a 400ms blip and then hold \"Reconnecting…\" on screen for the\n\t\t rest of its interval. That is how a self-healing state became a visible\n\t\t alarm — the socket was already back before the banner had finished\n\t\t animating in.\n\n\t\t Down has to persist to be reported; recovery is reported at once. The\n\t\t asymmetry is deliberate: being slow to announce trouble costs nothing,\n\t\t being slow to withdraw the claim is the bug. */\n\t\tconst DOWN_GRACE_MS = 2000;\n\t\tlet downSince: number | null = null;\n\t\tconst wsCheck = setInterval(() => {\n\t\t\tif (ws.isConnected) {\n\t\t\t\tdownSince = null;\n\t\t\t\tsetWsDisconnected(false);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (downSince === null) downSince = Date.now();\n\t\t\tsetWsDisconnected(Date.now() - downSince >= DOWN_GRACE_MS);\n\t\t}, 1000);\n\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t\tunsub();\n\t\t\tclearInterval(wsCheck);\n\t\t\tif (markSeenTimer) clearTimeout(markSeenTimer);\n\t\t\tif (pageDebounce) clearTimeout(pageDebounce);\n\t\t\twindow.history.pushState = origPush;\n\t\t\twindow.history.replaceState = origReplace;\n\t\t\twindow.removeEventListener(\"popstate\", reportPage);\n\t\t\tws.disconnect();\n\t\t};\n\t}, [client, store, ws, bootstrapAttempt]);\n\n\t// Re-initialize translations when locale prop changes after bootstrap\n\tuseEffect(() => {\n\t\tif (locale != null) {\n\t\t\tsetLocale(locale);\n\t\t}\n\t}, [locale]);\n\n\t// Wire up event callbacks: emit open/close events\n\tuseEffect(() => {\n\t\tconst unsub = store.subscribe((state, prev) => {\n\t\t\tif (state.isOpen && !prev.isOpen) {\n\t\t\t\temitter.emit(\"open\");\n\t\t\t\tonOpen?.();\n\t\t\t}\n\t\t\tif (!state.isOpen && prev.isOpen) {\n\t\t\t\temitter.emit(\"close\");\n\t\t\t\tonClose?.();\n\t\t\t}\n\t\t\tconst prevUnread = prev.conversations.reduce((s, c) => s + c.unreadCount, 0);\n\t\t\tconst nextUnread = state.conversations.reduce((s, c) => s + c.unreadCount, 0);\n\t\t\tif (nextUnread !== prevUnread) {\n\t\t\t\temitter.emit(\"unreadChange\", nextUnread);\n\t\t\t\tonUnreadChange?.(nextUnread);\n\t\t\t}\n\t\t});\n\t\treturn unsub;\n\t}, [store, emitter, onOpen, onClose, onUnreadChange]);\n\n\t// Custom launcher selector: attach click handler with MutationObserver fallback for SPAs\n\tuseEffect(() => {\n\t\tif (!customLauncherSelector) return;\n\t\tconst handler = (e: Event) => {\n\t\t\te.preventDefault();\n\t\t\tapi.toggle();\n\t\t};\n\n\t\tconst attach = () => {\n\t\t\tconst el = document.querySelector(customLauncherSelector);\n\t\t\tif (el) {\n\t\t\t\tel.addEventListener(\"click\", handler);\n\t\t\t\treturn el;\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\n\t\tlet el = attach();\n\t\tlet observer: MutationObserver | null = null;\n\n\t\tif (!el) {\n\t\t\tobserver = new MutationObserver(() => {\n\t\t\t\tel = attach();\n\t\t\t\tif (el) observer?.disconnect();\n\t\t\t});\n\t\t\tobserver.observe(document.body, { childList: true, subtree: true });\n\t\t}\n\n\t\treturn () => {\n\t\t\tel?.removeEventListener(\"click\", handler);\n\t\t\tobserver?.disconnect();\n\t\t};\n\t}, [customLauncherSelector, api]);\n\n\t// Sync window.Helpway with the current api instance on mount,\n\t// restore on unmount. Must live in an effect (not the init block)\n\t// so React StrictMode's double mount/unmount cycle doesn't leave\n\t// the global undefined: the effect re-runs on each mount and\n\t// re-installs the callable, while the init block only fires once\n\t// because initRef.current is preserved across remounts.\n\t//\n\t// IMPORTANT: window.Helpway is exposed as a CALLABLE function (Intercom-style)\n\t// so that `Helpway(\"identify\", payload)` works alongside `Helpway.identify(payload)`.\n\t// Earlier versions assigned the raw `api` object here, which clobbered the\n\t// callable installed by the widget-embed loader and made the documented\n\t// `Helpway(\"cmd\", ...)` form throw \"is not a function\" downstream.\n\t// Apply developer-side theme overrides. We target the host that the\n\t// widget script created (#helpway-widget) when running under the\n\t// embed loader; otherwise fall back to documentElement so the CSS\n\t// vars cascade into a Light-DOM React mount. See:\n\t// https://helpway.ai/docs/customization\n\tuseEffect(() => {\n\t\tif (!theme || typeof document === \"undefined\") return;\n\t\tconst target =\n\t\t\t(document.getElementById(\"helpway-widget\") as HTMLElement | null) ??\n\t\t\tdocument.documentElement;\n\t\tapplyTheme(target, theme);\n\t}, [theme]);\n\n\tuseEffect(() => {\n\t\tif (typeof window === \"undefined\") return;\n\t\tconst callable = installCallable(api);\n\t\treturn () => {\n\t\t\tif (window.Helpway === callable) {\n\t\t\t\twindow.Helpway = undefined;\n\t\t\t}\n\t\t\temitter.removeAll();\n\t\t};\n\t}, [api, emitter]);\n\n\tconst ctxValue: WidgetContextValue = {\n\t\tclient,\n\t\tstore,\n\t\tws,\n\t\tidentify,\n\t\tapi,\n\t\temitter,\n\t\thasBootstrapError,\n\t\twsDisconnected,\n\t\tretryBootstrap,\n\t};\n\n\treturn <WidgetContext.Provider value={ctxValue}>{children}</WidgetContext.Provider>;\n}\n\n// ── Helpers ──────────────────────────────────────────────\n\n/**\n * Resolve the API origin when the consumer doesn't pass `apiUrl` explicitly.\n *\n * Order of precedence:\n * 1. CDN script-tag origin — when the widget loads via\n * `<script src=\"https://cdn.helpway.ai/widget.js\" data-key=\"...\">` we\n * derive the origin from the script's URL so the bootstrap call hits\n * the API that owns the public key.\n * 2. Production default — `https://api.helpway.ai`. Matches the JSDoc\n * contract on the `apiUrl` prop.\n *\n * Earlier versions fell back to `window.location.origin` after the script\n * lookup, which broke any framework integration without the script tag\n * (Next App Router, Vite SPA, etc.) — bootstrap hit the consumer's own\n * server and 404'd. The `https://api.helpway.ai` fallback removes that\n * footgun.\n */\n/**\n * Synthetic conversation id prefix used for ephemeral proactive workflows.\n * The send-message flow checks for this prefix and routes to\n * `materializeFromProactive` instead of `sendMessage`/`createConversation`,\n * which is the moment we actually persist the conversation.\n */\nexport const EPHEMERAL_CONV_PREFIX = \"eph-\";\n\ninterface EphemeralProactivePayload {\n\tworkflowId: string;\n\tpathId: string;\n\tmessages: Array<{ stepId: string; text: string; sender: \"ai\" }>;\n\tquickReplies?: {\n\t\tstepId: string;\n\t\tprompt: string;\n\t\toptions: Array<{ id: string; label: string; goToPathId: string }>;\n\t};\n}\n\nfunction handleEphemeralProactive(\n\tstore: StoreApi<WidgetStore>,\n\tpayload: EphemeralProactivePayload,\n) {\n\tconst synthId = `${EPHEMERAL_CONV_PREFIX}${payload.workflowId}`;\n\tconst now = Date.now();\n\tconst lastMessage = payload.messages[payload.messages.length - 1];\n\tconst previewText = lastMessage?.text ?? \"\";\n\n\t// Inject the greeting (and quick replies) as if they came from the\n\t// server. Stagger timestamps so order is preserved if the visitor\n\t// scrolls through them later.\n\tconst items = payload.messages.map((m, i) => ({\n\t\tid: `${synthId}-msg-${m.stepId}`,\n\t\tconversationId: synthId,\n\t\ttype: \"message\" as const,\n\t\ttext: m.text,\n\t\tvisibility: \"public\" as const,\n\t\tuserId: null,\n\t\tvisitorId: null,\n\t\taiAgentId: null,\n\t\tcreatedAt: new Date(now - (payload.messages.length - i) * 100).toISOString(),\n\t\teditedAt: null,\n\t\tdeletedAt: null,\n\t}));\n\n\tif (payload.quickReplies) {\n\t\tconst qrFallback =\n\t\t\tpayload.quickReplies.prompt ||\n\t\t\tpayload.quickReplies.options.map((o) => `• ${o.label}`).join(\"\\n\");\n\t\titems.push({\n\t\t\tid: `${synthId}-qr-${payload.quickReplies.stepId}`,\n\t\t\tconversationId: synthId,\n\t\t\ttype: \"message\",\n\t\t\ttext: qrFallback,\n\t\t\tvisibility: \"public\",\n\t\t\tuserId: null,\n\t\t\tvisitorId: null,\n\t\t\taiAgentId: null,\n\t\t\tcreatedAt: new Date(now).toISOString(),\n\t\t\teditedAt: null,\n\t\t\tdeletedAt: null,\n\t\t\tmetadata: {\n\t\t\t\tkind: \"quick_replies\" as const,\n\t\t\t\tprompt: payload.quickReplies.prompt ?? null,\n\t\t\t\toptions: payload.quickReplies.options.map((o) => ({ id: o.id, label: o.label })),\n\t\t\t\tstepId: payload.quickReplies.stepId,\n\t\t\t},\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: metadata is widely typed\n\t\t} as any);\n\t}\n\n\tconst s = store.getState();\n\ts.addConversation({\n\t\tid: synthId,\n\t\ttitle: null,\n\t\tstatus: \"open\",\n\t\tlastMessageText: previewText,\n\t\tlastMessageAt: new Date(now).toISOString(),\n\t\tlastMessageSenderType: \"ai\",\n\t\tlastMessageSenderName: null,\n\t\tlastMessageSenderImage: null,\n\t\tassigneeName: null,\n\t\tassigneeImage: null,\n\t\tunreadCount: items.length,\n\t});\n\t// biome-ignore lint/suspicious/noExplicitAny: synthetic items match TimelineItem shape\n\ts.setMessages(synthId, items as any);\n\n\tif (!s.isOpen && previewText) {\n\t\tstore.setState({\n\t\t\tincomingPreview: {\n\t\t\t\ttext: previewText,\n\t\t\t\tconversationId: synthId,\n\t\t\t\ttimestamp: now,\n\t\t\t\tmessages: payload.messages.map((m) => ({ text: m.text })),\n\t\t\t\t...(payload.quickReplies\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tquickReplies: {\n\t\t\t\t\t\t\t\tstepId: payload.quickReplies.stepId,\n\t\t\t\t\t\t\t\tprompt: payload.quickReplies.prompt ?? null,\n\t\t\t\t\t\t\t\toptions: payload.quickReplies.options.map((o) => ({\n\t\t\t\t\t\t\t\t\tid: o.id,\n\t\t\t\t\t\t\t\t\tlabel: o.label,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t});\n\t}\n}\n\nfunction inferApiUrl(): string {\n\tif (typeof document !== \"undefined\") {\n\t\tconst script = document.querySelector(\"script[data-key][src]\");\n\t\tif (script) {\n\t\t\tconst src = script.getAttribute(\"src\");\n\t\t\tif (src) {\n\t\t\t\ttry {\n\t\t\t\t\tconst url = new URL(src);\n\t\t\t\t\treturn `${url.protocol}//${url.host}`;\n\t\t\t\t} catch {\n\t\t\t\t\t// Fall through to the production default.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn \"https://api.helpway.ai\";\n}\n","\"use client\";\n\nimport { formatRelativeTime, t } from \"@helpway/widget-core\";\nimport type {\n\tConversationSummary,\n\tDockSuggestion,\n\tWidgetContentTab,\n\tWidgetPlacement,\n} from \"@helpway/widget-core\";\nimport type { TimelineItem } from \"@helpway/types\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\n/** Resolve a label that might be a translation key (widget.*) or raw text */\nfunction resolveLabel(label: string): string {\n\tif (!label.startsWith(\"widget.\")) return label;\n\tconst resolved = t(label);\n\t// If t() returned the key itself (no translation found), humanize it\n\tif (resolved === label)\n\t\treturn label\n\t\t\t.replace(\"widget.\", \"\")\n\t\t\t.replace(/_/g, \" \")\n\t\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n\treturn resolved;\n}\n\nimport { useAnnouncements } from \"../hooks/use-announcements\";\nimport type { UnseenAnnouncementEntry } from \"../hooks/use-announcements\";\nimport { useComposer } from \"../hooks/use-composer\";\nimport { useConversations } from \"../hooks/use-conversations\";\nimport { useHeaderIdentity } from \"../hooks/use-header-identity\";\nimport { useI18n } from \"../hooks/use-i18n\";\nimport { usePresence } from \"../hooks/use-presence\";\nimport { useTimeline } from \"../hooks/use-timeline\";\nimport { useUnread } from \"../hooks/use-unread\";\nimport { useWidget } from \"../hooks/use-widget\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\nimport { Composer } from \"./composer\";\nimport { WidgetDebugOverlay } from \"./debug-overlay\";\nimport { DockedBar } from \"../shell/docked-bar\";\nimport { ChevronRightIcon, DotsIcon, NewChatIcon } from \"./icons\";\nimport { ContentTabView } from \"./content/content-tab-view\";\nimport { ContentTabIconComponent } from \"./content/tab-icon\";\nimport { HomeIcon, MessagesIcon, SendIcon, XIcon } from \"./icons\";\nimport { AnnouncementPreviews } from \"./announcement-previews\";\nimport { MessageBubble } from \"./message-bubble\";\nimport { MessageList } from \"./message-list\";\nimport { MessagePreview } from \"./message-preview\";\nimport { stripMarkdown } from \"./strip-markdown\";\n\nimport type { SubView, Tab } from \"./default-widget/types\";\n\nconst EMPTY_CONTENT_TABS: WidgetContentTab[] = [];\n\n/**\n * Factory-default admin strings. If the admin never customized these\n * values, the widget falls back to t() so visitors see their locale's\n * translation from the CDN bundle instead of frozen English.\n *\n * Keep in sync with packages/api seed defaults + widget-core/src/i18n.ts.\n */\n/* Sentinel, not display copy — it must keep matching the string the API seeds\n into the DB, or the untouched-default check below fails and every non-English\n visitor gets frozen English. The greeting that actually renders is\n t(\"widget.welcome_message\"), which is now one line; don't \"sync\" this to it. */\nconst DEFAULT_EN_WELCOME = \"Hi there 👋\\nHow can we help?\";\nconst DEFAULT_EN_SUBTITLE = \"Usually replies in minutes\";\n\n/**\n * Helpway brand mark — octagonal outer with stylized \"W\" inside. Used as\n * the widget's own fallback avatar when the customer hasn't configured a\n * custom avatar/preset and the host site didn't set a logo either. Keeps\n * unconfigured widgets looking intentional rather than generic.\n */\nfunction HelpwayMark({ className }: { className?: string }) {\n\treturn (\n\t\t<svg\n\t\t\tclassName={className}\n\t\t\twidth=\"100%\"\n\t\t\theight=\"100%\"\n\t\t\tviewBox=\"0 0 42 42\"\n\t\t\tfill=\"none\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<path\n\t\t\t\td=\"M28.7 0H12.8L0 12.8V28.7L12.8 41.5H28.7L41.5 28.7V12.8L28.7 0ZM15 28.9L6.80002 20.7L15 12.5C18.1 9.4 23.2 9.4 26.3 12.5L34.5 20.7L26.3 28.9C23.2 32 18.2 32 15 28.9Z\"\n\t\t\t\tfill=\"currentColor\"\n\t\t\t/>\n\t\t</svg>\n\t);\n}\n\n/**\n * WidgetLogo — chat-header avatar. Renders WHO is talking to the\n * visitor right now. Resolution chain:\n * 1. Active conversation's assigned support user (assigneeName +\n * assigneeImage from the widget API). When a human takes over a\n * conversation the visitor sees that human, not the AI agent.\n * 2. Agent uploaded image (agentConfig.avatarUrl)\n * 3. Agent icon preset (avatarPreset + brandColor)\n * 4. Website logo (website.logoUrl)\n * 5. Helpway brand mark (octagonal) as the true last-resort fallback\n *\n * The `forceAgent` escape hatch skips the assignee lookup — used by\n * surfaces that mean \"the agent\" specifically (welcome card, conversation\n * list rows where we want the persistent brand, etc.) rather than \"the\n * person currently helping you\".\n */\nexport function WidgetLogo({\n\tclassName,\n\tforceAgent = false,\n}: {\n\tclassName?: string;\n\tforceAgent?: boolean;\n}) {\n\tconst agentConfig = useWidgetStore((s) => s.agentConfig);\n\tconst logoUrl = useWidgetStore((s) => s.website?.logoUrl);\n\tconst activeId = useWidgetStore((s) => s.activeConversationId);\n\tconst assignee = useWidgetStore((s) => {\n\t\tif (forceAgent || !s.activeConversationId) return null;\n\t\tconst c = s.conversations.find((c) => c.id === s.activeConversationId);\n\t\treturn c?.assigneeName || c?.assigneeImage ? c : null;\n\t});\n\n\t// In the launcher bubble (forceAgent=true), uploaded images are\n\t// treated as brand logos — `contain` + padding so SVG/PNG marks\n\t// don't get cropped by the rounded bubble. In the chat-header\n\t// context, face-photo avatars keep `cover` behavior.\n\tconst logoClass = forceAgent ? \"hw-agent-img--logo\" : \"\";\n\n\t// Assigned human takes priority over the AI agent default — but only\n\t// when we actually have an active conversation we're rendering for.\n\tif (!forceAgent && activeId && assignee?.assigneeImage) {\n\t\treturn (\n\t\t\t<img\n\t\t\t\tsrc={assignee.assigneeImage}\n\t\t\t\talt={assignee.assigneeName ?? \"\"}\n\t\t\t\tclassName={`hw-agent-img ${className ?? \"\"}`}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// Agent uploaded image\n\tif (agentConfig?.avatarUrl) {\n\t\treturn <img src={agentConfig.avatarUrl} alt=\"\" className={`hw-agent-img ${logoClass} ${className ?? \"\"}`} />;\n\t}\n\n\t// Agent icon preset — use the same CSS variable as the welcome hero\n\t// so both surfaces stay color-synced. `--hw-primary` is fed by either\n\t// the inline style on `.hw-widget` (from agentConfig.brandColor) or\n\t// a `theme` prop override; reading the literal `agentConfig.brandColor`\n\t// here used to drift apart from the hero whenever the prop won.\n\tif (agentConfig?.avatarPreset) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={`hw-agent-icon ${className ?? \"\"}`}\n\t\t\t\tstyle={{\n\t\t\t\t\tbackgroundColor: \"var(--hw-primary)\",\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\tjustifyContent: \"center\",\n\t\t\t\t\tborderRadius: 8,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<AgentPresetIcon presetId={agentConfig.avatarPreset} />\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// Website logo — always a brand mark, never a face avatar. Apply\n\t// --logo class regardless of context so it stays uncropped in both\n\t// launcher bubble and chat-header circles.\n\tif (logoUrl) {\n\t\treturn <img src={logoUrl} alt=\"\" className={`hw-agent-img hw-agent-img--logo ${className ?? \"\"}`} />;\n\t}\n\n\treturn <HelpwayMark className={className} />;\n}\n\n/**\n * LauncherIcon — what the visitor sees on the always-visible bubble\n * BEFORE opening the widget. Brand-stable, doesn't change per\n * conversation. Resolution chain:\n * 1. Custom launcher icon (agentConfig.launcherIconUrl) — admin upload\n * 2. Agent avatar (avatarUrl) — same image as the chat header default\n * 3. Agent icon preset\n * 4. Website logo\n * 5. Helpway brand mark\n */\nfunction LauncherIcon({ className }: { className?: string }) {\n\tconst agentConfig = useWidgetStore((s) => s.agentConfig);\n\tconst [imgLoaded, setImgLoaded] = useState(false);\n\tconst imgSrc = agentConfig?.launcherIconUrl ?? null;\n\n\tuseEffect(() => {\n\t\tif (!imgSrc) return;\n\t\tsetImgLoaded(false);\n\t\tconst img = new Image();\n\t\timg.src = imgSrc;\n\t\tif (img.complete) { setImgLoaded(true); return; }\n\t\timg.onload = () => setImgLoaded(true);\n\t\timg.onerror = () => setImgLoaded(true);\n\t}, [imgSrc]);\n\n\tif (imgSrc) {\n\t\treturn (\n\t\t\t<img\n\t\t\t\tsrc={imgSrc}\n\t\t\t\talt=\"\"\n\t\t\t\tclassName={`hw-agent-img hw-agent-img--logo ${className ?? \"\"}`}\n\t\t\t\tstyle={{ opacity: imgLoaded ? 1 : 0, transition: \"opacity 0.15s ease\" }}\n\t\t\t/>\n\t\t);\n\t}\n\treturn <WidgetLogo className={className} forceAgent />;\n}\n\n/**\n * Exact SVG paths extracted from @central-icons-react at build time.\n * Pixel-perfect match with the dashboard picker. Using static trusted\n * strings (NOT user input) rendered via innerHTML — safe because content\n * is hardcoded SVG from our own icon library, never from external sources.\n */\nconst PRESET_SVG: Record<string, string> = {\n\t// Helpway brand mark — octagonal chamfer with stylized \"W\" inside.\n\t// First entry so it's the default preset for new orgs.\n\thelpway:\n\t\t'<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M16.4 0H7.31L0 7.31V16.4L7.31 23.71H16.4L23.71 16.4V7.31L16.4 0ZM8.57 16.51L3.89 11.83L8.57 7.14C10.34 5.37 13.26 5.37 15.03 7.14L19.71 11.83L15.03 16.51C13.26 18.29 10.4 18.29 8.57 16.51Z\" fill=\"white\"/>',\n\tatom: '<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M9.67904 3.29155C10.7467 1.56948 13.2537 1.56948 14.3214 3.29155L15.1308 4.59707C15.2462 4.7833 15.3634 4.9684 15.4823 5.15233C15.7005 5.1305 15.9185 5.10662 16.1363 5.08068L17.6626 4.89893C19.6747 4.65934 21.2396 6.61723 20.5571 8.52637L20.0401 9.97255C19.9664 10.1786 19.8947 10.3854 19.825 10.5927C19.9779 10.7493 20.1323 10.9045 20.2882 11.0583L21.3821 12.1371C22.8256 13.5609 22.2668 16.0039 20.3491 16.6605L18.895 17.1584C18.6876 17.2294 18.4809 17.3023 18.275 17.3772C18.2478 17.5943 18.2226 17.8117 18.1995 18.0294L18.0372 19.5565C17.823 21.572 15.5635 22.6577 13.8546 21.5695L12.5584 20.7442C12.3734 20.6264 12.1873 20.5103 12.0002 20.3961C11.8131 20.5103 11.627 20.6264 11.442 20.7442L10.1458 21.5695C8.4369 22.6577 6.17739 21.572 5.96321 19.5565L5.80094 18.0294C5.7778 17.8117 5.75263 17.5943 5.72541 17.3772C5.51949 17.3023 5.31282 17.2294 5.10542 17.1584L3.65133 16.6605C1.7336 16.0039 1.17475 13.5609 2.61829 12.1371L3.71216 11.0583C3.86807 10.9045 4.0225 10.7493 4.17541 10.5927C4.10567 10.3854 4.03395 10.1786 3.96028 9.97255L3.44329 8.52637C2.7608 6.61723 4.32567 4.65934 6.33777 4.89893L7.86408 5.08068C8.08191 5.10662 8.29993 5.1305 8.5181 5.15233C8.63698 4.9684 8.75417 4.7833 8.86963 4.59707L9.67904 3.29155ZM7.61407 6.4827L6.16966 6.31071C5.20357 6.19567 4.45578 7.13505 4.78207 8.04778L5.2716 9.41715C6.10452 8.48167 6.88648 7.5021 7.61407 6.4827ZM5.78854 10.961C7.04552 9.61105 8.19784 8.16742 9.23549 6.64268C11.076 6.78287 12.9244 6.78287 14.7649 6.64268C15.8026 8.16743 16.9549 9.61105 18.2119 10.961C17.6657 12.722 17.2545 14.522 16.9818 16.3454C15.2628 17.0169 13.5974 17.8181 12.0002 18.7422C10.403 17.8181 8.73761 17.0169 7.01863 16.3454C6.74592 14.522 6.3347 12.722 5.78854 10.961ZM4.65269 12.1275L3.61666 13.1494C2.92581 13.8308 3.19234 15.0006 4.11188 15.3154L5.48873 15.7868C5.27593 14.553 4.99684 13.3315 4.65269 12.1275ZM7.22343 17.9611L7.377 19.4062C7.47946 20.3704 8.56185 20.8926 9.38218 20.3703L10.6083 19.5895C9.51004 18.9865 8.38012 18.4429 7.22343 17.9611ZM13.3921 19.5895L14.6182 20.3703C15.4385 20.8926 16.5209 20.3704 16.6234 19.4062L16.777 17.9611C15.6203 18.4429 14.4903 18.9865 13.3921 19.5895ZM18.5117 15.7868L19.8885 15.3154C20.8081 15.0006 21.0746 13.8308 20.3837 13.1494L19.3477 12.1275C19.0035 13.3315 18.7245 14.553 18.5117 15.7868ZM18.7288 9.41715L19.2183 8.04778C19.5446 7.13505 18.7968 6.19567 17.8307 6.31071L16.3863 6.4827C17.1139 7.5021 17.8959 8.48167 18.7288 9.41715ZM13.8786 5.2756C12.6272 5.3429 11.3731 5.3429 10.1218 5.2756L10.8874 4.04072C11.3991 3.21542 12.6013 3.21542 13.113 4.04072L13.8786 5.2756Z\" fill=\"white\"/>',\n\tbrain:\n\t\t'<path d=\"M15 10C13.3431 10 12 8.65685 12 7\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9 14C10.6569 14 12 15.3431 12 17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 3.53516L12 20.2422\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M21 14.5C21 15.9633 20.102 17.2168 18.8271 17.7396C18.2888 19.6221 16.5553 21 14.5 21C13.5749 21 12.7151 20.7209 12 20.2422C11.285 20.7209 10.4251 21 9.5 21C7.44468 21 5.71119 19.6221 5.17291 17.7396C3.89797 17.2168 3 15.9633 3 14.5C3 13.5207 3.40223 12.6353 4.05051 12C3.40223 11.3647 3 10.4793 3 9.5C3 7.69511 4.36618 6.20931 6.12085 6.0203C6.55779 4.28478 8.12886 3 10 3C10.7286 3 11.4117 3.19479 12 3.53513C12.5883 3.19479 13.2714 3 14 3C15.8711 3 17.4422 4.28478 17.8792 6.0203C19.6338 6.20931 21 7.69511 21 9.5C21 10.4793 20.5978 11.3647 19.9495 12C20.5978 12.6353 21 13.5207 21 14.5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\trobot:\n\t\t'<path d=\"M12 4H7C5.89543 4 5 4.89543 5 6V11C5 12.1046 5.89543 13 7 13H17C18.1046 13 19 12.1046 19 11V6C19 4.89543 18.1046 4 17 4H12ZM12 4V2M6 15L4 17M6 15C6 18.3137 8.68629 21 12 21C15.3137 21 18 18.3137 18 15M6 15V13M18 15L20 17M18 15V13M9 8V9M15 8V9\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tsparkle:\n\t\t'<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M21 12.5C14.75 12.5 12 15.4028 12 22C12 15.4028 9.25 12.5 3 12.5C9.25 12.5 12 9.59722 12 3C12 9.59722 14.75 12.5 21 12.5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linejoin=\"round\"/>',\n\tbolt: '<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M13.1981 20.0571C11.7326 20.0571 10.2936 19.5252 9.46756 18.3817L9.1762 19.7304L3.79688 22.5824L4.3776 19.7304L8.2951 2H13.0916L11.7059 8.24953C12.8251 7.02621 13.8643 6.57412 15.1967 6.57412C18.0746 6.57412 19.9931 8.46227 19.9931 11.9194C19.9931 15.483 17.7815 20.0571 13.1981 20.0571ZM15.0368 12.9301C15.0368 14.5788 13.8643 15.8287 12.3455 15.8287C11.4927 15.8287 10.72 15.5096 10.2137 14.9511L10.9598 11.6802C11.5194 11.1216 12.1589 10.8025 12.905 10.8025C14.0509 10.8025 15.0368 11.6536 15.0368 12.9301Z\" fill=\"white\"/>',\n\tagent:\n\t\t'<path d=\"M12 8.5V12M12 12H8C6.89543 12 6 12.8954 6 14V15.5M12 12H16C17.1046 12 18 12.8954 18 14V15.5\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><circle cx=\"12\" cy=\"6\" r=\"2.5\" stroke=\"white\" stroke-width=\"2\"/><circle cx=\"6\" cy=\"18\" r=\"2.5\" stroke=\"white\" stroke-width=\"2\"/><circle cx=\"18\" cy=\"18\" r=\"2.5\" stroke=\"white\" stroke-width=\"2\"/>',\n\tbubble:\n\t\t'<path d=\"M4.00195 6.00003C4.00195 4.89546 4.89738 4.00003 6.00195 4.00002L18.0019 4C19.1065 4 20.002 4.89543 20.002 6V16.0358C20.002 17.1403 19.1065 18.0358 18.002 18.0358L15.3757 18.0358C15.1427 18.0358 14.9171 18.1171 14.7377 18.2657L11.9977 20.5358L9.29398 18.2694C9.11393 18.1185 8.8865 18.0358 8.65157 18.0358H6.00195C4.89738 18.0358 4.00195 17.1403 4.00195 16.0358V6.00003Z\" fill=\"white\"/><path d=\"M13.2395 9.43518L12.5426 7.62334C12.4561 7.39842 12.24 7.25 11.999 7.25C11.758 7.25 11.5419 7.39842 11.4554 7.62334L10.7586 9.43518C10.657 9.69927 10.4483 9.90797 10.1842 10.0095L8.37236 10.7064C8.14744 10.7929 7.99902 11.009 7.99902 11.25C7.99902 11.491 8.14744 11.7071 8.37236 11.7936L10.1842 12.4905C10.4483 12.592 10.657 12.8007 10.7586 13.0648L11.4554 14.8767C11.5419 15.1016 11.758 15.25 11.999 15.25C12.24 15.25 12.4561 15.1016 12.5426 14.8767L13.2395 13.0648C13.3411 12.8007 13.5498 12.592 13.8138 12.4905L15.6257 11.7936C15.8506 11.7071 15.999 11.491 15.999 11.25C15.999 11.009 15.8506 10.7929 15.6257 10.7064L13.8138 10.0095C13.5498 9.90797 13.3411 9.69927 13.2395 9.43518Z\" fill=\"white\"/>',\n\tlightbulb:\n\t\t'<path d=\"M10 21H14M15.6076 15C17.6404 13.7751 19 11.5463 19 9C19 5.13401 15.866 2 12 2C8.13401 2 5 5.13401 5 9C5 11.5463 6.35958 13.7751 8.39241 15M15.6076 15C15.4111 15.1184 15.2084 15.2274 15 15.3264V17C15 17.5523 14.5523 18 14 18H10C9.44772 18 9 17.5523 9 17V15.3264C8.7916 15.2274 8.58886 15.1184 8.39241 15M15.6076 15H8.39241\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\twand: '<path d=\"M11.3908 12.6089L4 19.9996\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M18.3943 5.2792C18.5999 5.1944 18.8056 5.40008 18.7208 5.60565L17.1697 9.36581C17.1339 9.45248 17.1497 9.55186 17.2105 9.62323L19.8476 12.72C19.9918 12.8894 19.8597 13.1485 19.638 13.1314L15.5826 12.8182C15.4891 12.811 15.3994 12.8566 15.3503 12.9365L13.22 16.4015C13.1035 16.591 12.8163 16.5455 12.764 16.3293L11.8087 12.3756C11.7867 12.2844 11.7156 12.2133 11.6244 12.1913L7.67069 11.236C7.45453 11.1837 7.40903 10.8964 7.59847 10.78L11.0635 8.64965C11.1434 8.60055 11.189 8.51089 11.1818 8.41743L10.8686 4.36198C10.8515 4.14027 11.1106 4.00822 11.2799 4.15239L14.3768 6.78952C14.4481 6.8503 14.5475 6.86604 14.6342 6.83029L18.3943 5.2792Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tchip: '<path d=\"M8 5.5V4M12 5.5V4M16 5.5V4M8 20V18.5M12 20V18.5M16 20V18.5M8.75 15H15.25C15.6642 15 16 14.6642 16 14.25V9.75C16 9.33579 15.6642 9 15.25 9H8.75C8.33579 9 8 9.33579 8 9.75V14.25C8 14.6642 8.33579 15 8.75 15ZM6 20H18C19.1046 20 20 19.1046 20 18V6C20 4.89543 19.1046 4 18 4H6C4.89543 4 4 4.89543 4 6V18C4 19.1046 4.89543 20 6 20Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tcode: '<path d=\"M10 9.5L8.20711 11.2929C7.81658 11.6834 7.81658 12.3166 8.20711 12.7071L10 14.5M14 9.5L15.7929 11.2929C16.1834 11.6834 16.1834 12.3166 15.7929 12.7071L14 14.5M6 20H18C19.1046 20 20 19.1046 20 18V6C20 4.89543 19.1046 4 18 4H6C4.89543 4 4 4.89543 4 6V18C4 19.1046 4.89543 20 6 20Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tlightning:\n\t\t'<path d=\"M4.11593 12.2764L8.61593 3.27639C8.70063 3.107 8.87376 3 9.06315 3H17.121C17.5097 3 17.7497 3.42399 17.5498 3.75725L15.4585 7.24275C15.2585 7.57601 15.4986 8 15.8872 8H20.6909C21.1505 8 21.3666 8.56776 21.0235 8.87338L7.38117 21.0236C7.00034 21.3628 6.41568 20.981 6.57301 20.4959L8.79194 13.6543C8.8967 13.3312 8.6559 13 8.31633 13H4.56314C4.19145 13 3.94971 12.6088 4.11593 12.2764Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tvibe: '<path d=\"M18.9847 2.4329C18.9568 2.18651 18.7485 2.00025 18.5005 2C18.2525 1.99975 18.0438 2.18557 18.0154 2.43191C17.838 3.96993 16.9699 4.83801 15.4319 5.01541C15.1856 5.04382 14.9997 5.25253 15 5.5005C15.0003 5.74847 15.1865 5.9568 15.4329 5.9847C16.9491 6.15645 17.8774 7.01617 18.0141 8.55536C18.0365 8.80725 18.2477 9.00028 18.5005 9C18.7534 8.99971 18.9642 8.80621 18.986 8.55426C19.1173 7.03683 20.0368 6.11734 21.5543 5.98599C21.8062 5.96418 21.9997 5.75344 22 5.50055C22.0003 5.24766 21.8073 5.03648 21.5554 5.01411C20.0162 4.87738 19.1564 3.94911 18.9847 2.4329Z\" fill=\"white\"/><path d=\"M2 20C2 16.6863 4.68629 14 8 14H8.5\" fill=\"white\"/><path d=\"M11 20L12.6892 14.0879C12.8732 13.444 13.4617 13 14.1315 13H20.5417C21.2725 13 21.8001 13.6995 21.5994 14.4022L20.2072 19.2747C20.0846 19.704 19.6922 20 19.2457 20H11ZM11 20H7\" fill=\"white\"/><circle cx=\"8.75\" cy=\"7.5\" r=\"3.5\" stroke=\"white\" stroke-width=\"2\"/>',\n\tnetwork:\n\t\t'<path d=\"M12 6.8501L16 7.2501M17.75 10.0001L16.55 14.0001M13.5 14.3572L12 12.0001L10.4091 9.5001M6.25 14.0001L7.45 10.0001M8 16.7501L12 17.1501\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><circle cx=\"18.5\" cy=\"7.5\" r=\"2.5\" stroke=\"white\" stroke-width=\"2\"/><circle cx=\"5.5\" cy=\"16.5\" r=\"2.5\" stroke=\"white\" stroke-width=\"2\"/><circle cx=\"8.5\" cy=\"6.5\" r=\"3.5\" stroke=\"white\" stroke-width=\"2\"/><circle cx=\"15.5\" cy=\"17.5\" r=\"3.5\" stroke=\"white\" stroke-width=\"2\"/>',\n\tconsole:\n\t\t'<path d=\"M7.5 8L9.25 9.75L7.5 11.5M12 11.5H14M6 20H18C19.1046 20 20 19.1046 20 18V6C20 4.89543 19.1046 4 18 4H6C4.89543 4 4 4.89543 4 6V18C4 19.1046 4.89543 20 6 20Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tprompt:\n\t\t'<path d=\"M6 5H5C3.89543 5 3 5.89543 3 7V8\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M18 5H19C20.1046 5 21 5.89543 21 7V8\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M21 16V17C21 18.1046 20.1046 19 19 19H18\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M6 19H5C3.89543 19 3 18.1046 3 17V16\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M8 10H16\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M8 14H14\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tglobe:\n\t\t'<path d=\"M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M21 12H3\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 21C10.067 21 8.5 16.9706 8.5 12C8.5 7.02944 10.067 3 12 3C13.933 3 15.5 7.02944 15.5 12C15.5 16.9706 13.933 21 12 21Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\ttarget:\n\t\t'<path d=\"M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M17 12C17 14.7614 14.7614 17 12 17C9.23858 17 7 14.7614 7 12C7 9.23858 9.23858 7 12 7C14.7614 7 17 9.23858 17 12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M13 12C13 12.5523 12.5523 13 12 13C11.4477 13 11 12.5523 11 12C11 11.4477 11.4477 11 12 11C12.5523 11 13 11.4477 13 12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tdiamond:\n\t\t'<path d=\"M8.28256 4C7.77978 4 7.29545 4.18937 6.926 4.53039L2.53016 8.58809C1.69548 9.35857 1.66929 10.6687 2.47251 11.4719L10.5864 19.5858C11.3674 20.3668 12.6338 20.3668 13.4148 19.5858L21.5287 11.4719C22.3319 10.6687 22.3057 9.35857 21.471 8.58809L17.0752 4.53039C16.7057 4.18937 16.2214 4 15.7186 4H8.28256Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9.5 8L7.5 10L9.5 12\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tstar: '<path d=\"M11.5288 2.29524C11.7179 1.90159 12.2821 1.90159 12.4712 2.29524L14.9458 7.44648C15.0219 7.60491 15.1735 7.71434 15.3487 7.73728L21.0456 8.4832C21.4809 8.5402 21.6552 9.07312 21.3368 9.37342L17.1693 13.303C17.0412 13.4238 16.9832 13.6009 17.0154 13.7735L18.0616 19.3857C18.1416 19.8146 17.6852 20.144 17.2993 19.9359L12.249 17.2133C12.0937 17.1296 11.9063 17.1296 11.751 17.2133L6.70073 19.9359C6.3148 20.144 5.85841 19.8146 5.93837 19.3857L6.98459 13.7735C7.01677 13.6009 6.95885 13.4238 6.83068 13.303L2.66324 9.37342C2.34476 9.07312 2.51909 8.5402 2.95444 8.4832L8.65127 7.73728C8.82648 7.71434 8.97811 7.60491 9.05422 7.44648L11.5288 2.29524Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\theart:\n\t\t'<path d=\"M21 10C21 15.75 12.75 20 12 20C11.25 20 3 15.75 3 10C3 6 5.5 4 8 4C10.5 4 12 5.5 12 5.5C12 5.5 13.5 4 16 4C18.5 4 21 6 21 10Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tshield:\n\t\t'<path d=\"M20 7.17737C20 6.32338 19.4578 5.56361 18.6502 5.286L12.6502 3.2235C12.2288 3.07866 11.7712 3.07866 11.3498 3.22349L5.34984 5.286C4.54224 5.56361 4 6.32338 4 7.17737V11.9123C4 16.8848 8 19 12 21.1579C16 19 20 16.8848 20 11.9123V7.17737Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\trocket:\n\t\t'<path d=\"M3 21H5C6.10457 21 7 20.1046 7 19C7 17.8954 6.10457 17 5 17C3.89543 17 3 17.8954 3 19V21Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M7.00098 13H4.76717C3.98987 13 3.50976 12.152 3.90968 11.4855L5.41837 8.97101C5.77982 8.3686 6.43083 8 7.13336 8H11.251C13.7671 5.25513 16.4925 3.3474 20.0017 3.04278C20.5519 2.99502 21.006 3.44906 20.9582 3.99927C20.6536 7.50845 18.7459 10.2339 16.001 12.75V16.8676C16.001 17.5701 15.6324 18.2212 15.03 18.5826L12.5155 20.0913C11.849 20.4912 11.001 20.0111 11.001 19.2338V17L7.00098 13Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M7 13L11.25 8\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M16 12.75L11 17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tcrown:\n\t\t'<path d=\"M4.16831 17.4079L2 7L8 10L12 4L16 10L22 7L19.8317 17.4079C19.6385 18.3353 18.8211 19 17.8737 19H6.12628C5.17892 19 4.36153 18.3353 4.16831 17.4079Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\ttrophy:\n\t\t'<path d=\"M12.0039 17V14\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M18 5H19C20.1046 5 21 5.89543 21 7C21 8.65685 19.6569 10 18 10\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M6 5C6 3.89543 6.89543 3 8 3H16C17.1046 3 18 3.89543 18 5V8C18 11.3137 15.3137 14 12 14C8.68629 14 6 11.3137 6 8V5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M7 19C7 17.8954 7.89543 17 9 17H15C16.1046 17 17 17.8954 17 19C17 20.1046 16.1046 21 15 21H9C7.89543 21 7 20.1046 7 19Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M6 5H5C3.89543 5 3 5.89543 3 7C3 8.65685 4.34315 10 6 10\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tcompass:\n\t\t'<path d=\"M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M14.6558 8.73023L10.5513 9.84965C10.2097 9.94281 9.94281 10.2097 9.84965 10.5513L8.73023 14.6558C8.62843 15.0291 8.97092 15.3716 9.34417 15.2698L13.4487 14.1504C13.7903 14.0572 14.0572 13.7903 14.1504 13.4487L15.2698 9.34417C15.3716 8.97092 15.0291 8.62843 14.6558 8.73023Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tfire: '<path d=\"M19.5 13.8122C19.5 23.3907 4.5 23.4012 4.5 13.8122C4.5 6.61352 12 2.5 12 2.5C12 2.5 19.5 6.61352 19.5 13.8122Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M15.5 17.4061C15.5 22.1954 8.5 22.2006 8.5 17.4061C8.5 13.8068 12 11.75 12 11.75C12 11.75 15.5 13.8068 15.5 17.4061Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tkey: '<path d=\"M20.8002 9.8753L20.0194 10.5L20.0194 10.5L20.8002 9.8753ZM22.0002 11.3753L21.2194 12V12L22.0002 11.3753ZM22.0002 12.6247L21.2194 12V12L22.0002 12.6247ZM20.8002 14.1247L20.0194 13.5L20.0194 13.5L20.8002 14.1247ZM18 14.5L17.5528 15.3944C17.6916 15.4639 17.8448 15.5 18 15.5V14.5ZM16 13.5L16.4472 12.6056C16.1657 12.4648 15.8343 12.4648 15.5528 12.6056L16 13.5ZM14 14.5V15.5C14.1552 15.5 14.3084 15.4639 14.4472 15.3944L14 14.5ZM11.0141 9.01843L11.8165 8.42152L11.8165 8.42152L11.0141 9.01843ZM11.0141 14.9816L10.2118 14.3847V14.3847L11.0141 14.9816ZM6.5 12C6.5 11.7239 6.72386 11.5 7 11.5V13.5C7.82843 13.5 8.5 12.8284 8.5 12H6.5ZM7 11.5C7.27614 11.5 7.5 11.7239 7.5 12H5.5C5.5 12.8284 6.17157 13.5 7 13.5V11.5ZM7.5 12C7.5 12.2761 7.27614 12.5 7 12.5V10.5C6.17157 10.5 5.5 11.1716 5.5 12H7.5ZM7 12.5C6.72386 12.5 6.5 12.2761 6.5 12H8.5C8.5 11.1716 7.82843 10.5 7 10.5V12.5ZM6.5 13H7.5V11H6.5V13ZM7 16C4.79086 16 3 14.2091 3 12H1C1 15.3137 3.68629 18 7 18V16ZM3 12C3 9.79086 4.79086 8 7 8V6C3.68629 6 1 8.68629 1 12H3ZM20.0194 10.5L21.2194 12L22.7811 10.7506L21.5811 9.25061L20.0194 10.5ZM21.2194 12L20.0194 13.5L21.5811 14.7494L22.7811 13.2494L21.2194 12ZM20.0194 13.5H18V15.5H20.0194V13.5ZM18.4472 13.6056L16.4472 12.6056L15.5528 14.3944L17.5528 15.3944L18.4472 13.6056ZM15.5528 12.6056L13.5528 13.6056L14.4472 15.3944L16.4472 14.3944L15.5528 12.6056ZM11.9079 10.5H20.0194V8.5H11.9079V10.5ZM7 8C8.31459 8 9.48107 8.63311 10.2118 9.61533L11.8165 8.42152C10.7246 6.9539 8.97356 6 7 6V8ZM14 13.5H11.9079V15.5H14V13.5ZM10.2118 14.3847C9.48107 15.3669 8.31459 16 7 16V18C8.97356 18 10.7246 17.0461 11.8165 15.5785L10.2118 14.3847ZM11.9079 13.5C11.1751 13.5 10.5749 13.8967 10.2118 14.3847L11.8165 15.5785C11.8445 15.5408 11.8734 15.5183 11.8929 15.5074C11.9106 15.4976 11.9148 15.5 11.9079 15.5V13.5ZM20.0194 13.5L20.0194 13.5V15.5C20.6269 15.5 21.2016 15.2238 21.5811 14.7494L20.0194 13.5ZM11.9079 8.5C11.9148 8.5 11.9106 8.50239 11.8929 8.49258C11.8734 8.48172 11.8445 8.45923 11.8165 8.42152L10.2118 9.61533C10.5749 10.1033 11.1751 10.5 11.9079 10.5V8.5ZM21.2194 12V12L22.7811 13.2494C23.3655 12.519 23.3655 11.481 22.7811 10.7506L21.2194 12ZM21.5811 9.25061C21.2016 8.77618 20.6269 8.5 20.0194 8.5V10.5L20.0194 10.5L21.5811 9.25061Z\" fill=\"white\"/>',\n\tlock: '<path d=\"M5 12C5 10.8954 5.89543 10 7 10H17C18.1046 10 19 10.8954 19 12V19C19 20.1046 18.1046 21 17 21H7C5.89543 21 5 20.1046 5 19V12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M16 9.5V7C16 4.79086 14.2091 3 12 3C9.79086 3 8 4.79086 8 7V9.5\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 14V17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tbookmark:\n\t\t'<path d=\"M19 19.9948V5C19 3.89543 18.1046 3 17 3H7C5.89543 3 5 3.89543 5 5V19.9948C5 20.8047 5.91243 21.2787 6.57503 20.813L10.8499 17.8083C11.54 17.3233 12.46 17.3233 13.1501 17.8083L17.425 20.813C18.0876 21.2787 19 20.8047 19 19.9948Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tstore:\n\t\t'<path d=\"M4 10V18C4 19.1046 4.89543 20 6 20H18C19.1046 20 20 19.1046 20 18V10\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M14.4996 4H9.49956L9.2133 8.00762C9.0978 9.62461 10.3785 11 11.9996 11C13.6207 11 14.9013 9.62461 14.7858 8.00763L14.4996 4Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9.50047 4H5.73506C4.73976 4 3.89592 4.73186 3.75516 5.71716L3.4699 7.71396C3.22214 9.44831 4.56792 11 6.31987 11C7.83025 11 9.08385 9.83276 9.19146 8.32621L9.50047 4Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M18.2654 4H14.5L14.809 8.32621C14.9166 9.83276 16.1702 11 17.6806 11C19.4326 11 20.7783 9.44831 20.5306 7.71396L20.2453 5.71716C20.1046 4.73186 19.2607 4 18.2654 4Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tbag: '<path d=\"M15.0001 8C15.0001 9.65685 13.6569 11 12.0001 11C10.3432 11 9.00008 9.65685 9.00008 8M4.88288 5.87524L4.13288 17.8752C4.06092 19.0266 4.97534 20 6.12899 20H17.8712C19.0248 20 19.9392 19.0266 19.8673 17.8752L19.1173 5.87524C19.0514 4.82117 18.1773 4 17.1212 4H6.87899C5.82286 4 4.94876 4.82117 4.88288 5.87524Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\t\"credit-card\":\n\t\t'<path d=\"M3 10V17C3 18.1046 3.89543 19 5 19H19C20.1046 19 21 18.1046 21 17V10M3 10V7C3 5.89543 3.89543 5 5 5H19C20.1046 5 21 5.89518 21 6.99975V10M3 10H21\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\treceipt:\n\t\t'<path d=\"M9 8H15M9 12H11M19 21V5C19 3.89543 18.1046 3 17 3H7C5.89543 3 5 3.89543 5 5V21L7.33333 19L9.66667 21L12 19L14.3333 21L16.6667 19L19 21Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tbank: '<path d=\"M11.1056 2.94723L3.68328 6.65838C3.26452 6.86776 3 7.29576 3 7.76395C3 8.44661 3.55341 9.00002 4.23607 9.00002H19.7639C20.4466 9.00002 21 8.44661 21 7.76395C21 7.29576 20.7355 6.86776 20.3167 6.65838L12.8944 2.94723C12.3314 2.6657 11.6686 2.6657 11.1056 2.94723Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M19.6126 20H4.38749C3.70493 20 3.22296 19.3313 3.4388 18.6838L3.54421 18.3675C3.81644 17.5509 4.58072 17 5.44158 17H18.5585C19.4194 17 20.1837 17.5509 20.4559 18.3675L20.5613 18.6838C20.7772 19.3313 20.2952 20 19.6126 20Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M19 9V17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M15 17V9\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5 9V17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9 17V9\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\twallet:\n\t\t'<path d=\"M3 8V7C3 5.89543 3.89543 5 5 5H19C20.1046 5 21 5.89543 21 7V8M3 8H21M3 8V11M21 8V11M21 11V17C21 18.1046 20.1046 19 19 19H5C3.89543 19 3 18.1046 3 17V11M21 11H15C15 12.1046 14.1046 13 13 13H11C9.89543 13 9 12.1046 9 11H3\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tpackage:\n\t\t'<path d=\"M9 4V7.5C9 8.32843 9.67157 9 10.5 9H13.5C14.3284 9 15 8.32843 15 7.5V4M14 16H16M4 6V18C4 19.1046 4.89543 20 6 20H18C19.1046 20 20 19.1046 20 18V6C20 4.89543 19.1046 4 18 4H6C4.89543 4 4 4.89543 4 6Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\ttruck:\n\t\t'<path d=\"M10 16.5C10 17.8807 8.88071 19 7.5 19C6.11929 19 5 17.8807 5 16.5C5 15.1193 6.11929 14 7.5 14C8.88071 14 10 15.1193 10 16.5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M19 16.5C19 17.8807 17.8807 19 16.5 19C15.1193 19 14 17.8807 14 16.5C14 15.1193 15.1193 14 16.5 14C17.8807 14 19 15.1193 19 16.5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M10 16H14\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9 14V7H6.07037C5.40166 7 4.7772 7.3342 4.40627 7.8906L3.3359 9.49615C3.11688 9.82469 3 10.2107 3 10.6056V14.2857C3 15.2325 3.76751 16 4.71429 16\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9 9V7C9 5.89543 9.89543 5 11 5H19C20.1046 5 21 5.89543 21 7V14C21 15.1046 20.1046 16 19 16\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tmegaphone:\n\t\t'<path d=\"M17.9961 14.0001C19.6529 14.0001 20.9961 12.657 20.9961 11.0001C20.9961 9.34325 19.6529 8.0001 17.9961 8.0001M12.8254 18.0001C12.4136 19.1653 11.3023 20.0001 9.99609 20.0001C8.33924 20.0001 6.99609 18.657 6.99609 17.0001V15.5001M6.99829 6.5001V15.5001M17.9961 5.73752V16.2627C17.9961 17.617 16.6784 18.5797 15.3882 18.1681L4.38819 14.6585C3.55899 14.394 2.99609 13.6235 2.99609 12.7532V9.24704C2.99609 8.37667 3.55899 7.60622 4.38819 7.34167L15.3882 3.83215C16.6784 3.42051 17.9961 4.38325 17.9961 5.73752Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\temail:\n\t\t'<path d=\"M20.782 6.09202L19.891 6.54601L19.891 6.54601L20.782 6.09202ZM19.908 5.21799L20.362 4.32698V4.32698L19.908 5.21799ZM4.09202 5.21799L3.63803 4.32698L3.63803 4.32698L4.09202 5.21799ZM3.21799 6.09202L2.32698 5.63803L2.32698 5.63803L3.21799 6.09202ZM3.21799 17.908L4.10899 17.454L4.10899 17.454L3.21799 17.908ZM4.09202 18.782L4.54601 17.891H4.54601L4.09202 18.782ZM19.908 18.782L20.362 19.673V19.673L19.908 18.782ZM20.782 17.908L19.891 17.454L19.891 17.454L20.782 17.908ZM21 8.2H20V15.8H21H22V8.2H21ZM21 8.2H22C22 7.65645 22.0008 7.18864 21.9694 6.80497C21.9371 6.40963 21.8658 6.01641 21.673 5.63803L20.782 6.09202L19.891 6.54601C19.9162 6.59545 19.9539 6.69617 19.9761 6.96784C19.9992 7.25117 20 7.62345 20 8.2H21ZM20.782 6.09202L21.673 5.63803C21.3854 5.07354 20.9265 4.6146 20.362 4.32698L19.908 5.21799L19.454 6.10899C19.6422 6.20487 19.7951 6.35785 19.891 6.54601L20.782 6.09202ZM17.8 5V6C18.3766 6 18.7488 6.00078 19.0322 6.02393C19.3038 6.04612 19.4045 6.0838 19.454 6.10899L19.908 5.21799L20.362 4.32698C19.9836 4.13419 19.5904 4.06287 19.195 4.03057C18.8114 3.99922 18.3436 4 17.8 4V5ZM6.2 5V6H17.8V5V4H6.2V5ZM6.2 5V4C5.65645 4 5.18864 3.99922 4.80497 4.03057C4.40963 4.06287 4.01641 4.13419 3.63803 4.32698L4.09202 5.21799L4.54601 6.10899C4.59545 6.0838 4.69617 6.04612 4.96784 6.02393C5.25117 6.00078 5.62345 6 6.2 6V5ZM3.21799 6.09202L4.10899 6.54601C4.20487 6.35785 4.35785 6.20487 4.54601 6.10899L4.09202 5.21799L3.63803 4.32698C3.07354 4.6146 2.6146 5.07354 2.32698 5.63803L3.21799 6.09202ZM3 8.2H4C4 7.62345 4.00078 7.25117 4.02393 6.96784C4.04612 6.69617 4.0838 6.59545 4.10899 6.54601L3.21799 6.09202L2.32698 5.63803C2.13419 6.01641 2.06287 6.40963 2.03057 6.80497C1.99922 7.18864 2 7.65645 2 8.2H3ZM3 15.8H4V8.2H3H2V15.8H3ZM3 15.8H2C2 16.3435 1.99922 16.8114 2.03057 17.195C2.06287 17.5904 2.13419 17.9836 2.32698 18.362L3.21799 17.908L4.10899 17.454C4.0838 17.4045 4.04612 17.3038 4.02393 17.0322C4.00078 16.7488 4 16.3765 4 15.8H3ZM4.09202 18.782L4.54601 17.891C4.35785 17.7951 4.20487 17.6421 4.10899 17.454L3.21799 17.908L2.32698 18.362C2.6146 18.9265 3.07354 19.3854 3.63803 19.673L4.09202 18.782ZM6.2 19V18C5.62345 18 5.25117 17.9992 4.96784 17.9761C4.69617 17.9539 4.59545 17.9162 4.54601 17.891L4.09202 18.782L3.63803 19.673C4.01641 19.8658 4.40963 19.9371 4.80497 19.9694C5.18864 20.0008 5.65645 20 6.2 20V19ZM17.8 19V18H6.2V19V20H17.8V19ZM17.8 19V20C18.3436 20 18.8114 20.0008 19.195 19.9694C19.5904 19.9371 19.9836 19.8658 20.362 19.673L19.908 18.782L19.454 17.891C19.4045 17.9162 19.3038 17.9539 19.0322 17.9761C18.7488 17.9992 18.3766 18 17.8 18V19ZM20.782 17.908L19.891 17.454C19.7951 17.6421 19.6422 17.7951 19.454 17.891L19.908 18.782L20.362 19.673C20.9265 19.3854 21.3854 18.9265 21.673 18.362L20.782 17.908ZM21 15.8H20C20 16.3765 19.9992 16.7488 19.9761 17.0322C19.9539 17.3038 19.9162 17.4045 19.891 17.454L20.782 17.908L21.673 18.362C21.8658 17.9836 21.9371 17.5904 21.9694 17.195C22.0008 16.8114 22 16.3435 22 15.8H21Z\" fill=\"white\"/><path d=\"M21 5.63635L13.2665 11.9638C12.5297 12.5666 11.4703 12.5666 10.7335 11.9638L3 5.63635\" fill=\"white\"/>',\n\tbell: '<path d=\"M4.69376 9.44981C5.15435 5.76511 8.28661 3 12 3C15.7134 3 18.8456 5.76511 19.3062 9.44981L19.969 14.7519C20.1182 15.9456 19.1874 17 17.9844 17H6.01555C4.81256 17 3.88178 15.9456 4.031 14.7519L4.69376 9.44981Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M16 17C16 19.2091 14.2091 21 12 21C9.79086 21 8 19.2091 8 17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tpeople:\n\t\t'<path d=\"M15.5 6.5C15.5 8.433 13.933 10 12 10C10.067 10 8.5 8.433 8.5 6.5C8.5 4.567 10.067 3 12 3C13.933 3 15.5 4.567 15.5 6.5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12.0011 13C8.60997 13 6.03711 15.0143 4.9836 17.8629C4.5748 18.9682 5.51944 20 6.69796 20H17.3043C18.4828 20 19.4274 18.9682 19.0186 17.8629C17.9651 15.0143 15.3923 13 12.0011 13Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tsupport:\n\t\t'<path d=\"M6 10H4.5C3.67157 10 3 10.6716 3 11.5V15C3 15.8284 3.67157 16.5 4.5 16.5H6V10Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M20 10H18.5V16.5H20C20.8284 16.5 21.5 15.8284 21.5 15V11.5C21.5 10.6716 20.8284 10 20 10Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M19.5 10V9.75C19.5 6.02208 16.2541 3 12.25 3C8.24594 3 5 6.02208 5 9.75V10\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 19V19.5C12 20.3284 12.6716 21 13.5 21H15.25C17.7353 21 19.75 18.9853 19.75 16.5\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\thandshake:\n\t\t'<path d=\"M11.8305 5.68856C9.57907 3.43715 5.92881 3.43715 3.6774 5.68856C1.57785 7.78811 1.40103 11.1544 3.42019 13.3313C5.71921 15.8101 8.14783 18.1408 10.7345 20.3519C11.4619 20.9737 12.5313 20.9737 13.2587 20.3519C15.8453 18.1408 18.2739 15.8101 20.573 13.3313C22.5921 11.1544 22.4153 7.78811 20.3158 5.68856C18.0644 3.43715 14.4141 3.43715 12.1627 5.68856L8.8146 9.03664C8.22881 9.62243 8.22881 10.5722 8.8146 11.158C9.98617 12.3295 11.8857 12.3295 13.0572 11.158L13.7643 10.4509C14.1549 10.0603 14.788 10.0603 15.1786 10.4509L18.7141 13.9864\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tpill: '<path d=\"M17.4541 10.0962C18.6109 8.31497 18.4083 5.90826 16.8462 4.34619C15.0513 2.55127 12.1411 2.55127 10.3462 4.34619L4.34619 10.3462C2.55127 12.1411 2.55127 15.0513 4.34619 16.8462C5.90826 18.4083 8.31497 18.6109 10.0962 17.4541\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M7.5 7.5L11 11\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M16.5 20.5L14.5 10.5\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><circle cx=\"15.5\" cy=\"15.5\" r=\"5.5\" stroke=\"white\" stroke-width=\"2\"/>',\n\t\"heart-beat\":\n\t\t'<path d=\"M16 12H14.5L13 14L10.5 10L9.25 12H8M12 5.76835C18.1619 -0.481837 28.7252 11.1257 12 20.5C-4.72523 11.1257 5.83803 -0.481838 12 5.76835Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tbook: '<path d=\"M9 6C8.44772 6 8 6.44772 8 7C8 7.55228 8.44772 8 9 8V6ZM15 8C15.5523 8 16 7.55228 16 7C16 6.44772 15.5523 6 15 6V8ZM9 10C8.44772 10 8 10.4477 8 11C8 11.5523 8.44772 12 9 12V10ZM12 12C12.5523 12 13 11.5523 13 11C13 10.4477 12.5523 10 12 10V12ZM7 4H17V2H7V4ZM18 5V19H20V5H18ZM17 20H7V22H17V20ZM6 19V5H4V19H6ZM7 20C6.44771 20 6 19.5523 6 19H4C4 20.6569 5.34315 22 7 22V20ZM18 19C18 19.5523 17.5523 20 17 20V22C18.6569 22 20 20.6569 20 19H18ZM17 4C17.5523 4 18 4.44772 18 5H20C20 3.34315 18.6569 2 17 2V4ZM7 2C5.34315 2 4 3.34315 4 5H6C6 4.44772 6.44772 4 7 4V2ZM18 12V15H20V12H18ZM17 16H7V18H17V16ZM7 22H10V20H7V22ZM7 16C5.34315 16 4 17.3431 4 19H6C6 18.4477 6.44772 18 7 18V16ZM18 15C18 15.5523 17.5523 16 17 16V18C18.6569 18 20 16.6569 20 15H18ZM9 8H15V6H9V8ZM9 12H12V10H9V12Z\" fill=\"white\"/>',\n\tgraduate:\n\t\t'<path d=\"M23 9L12 14L1 9L12 4L23 9ZM23 9V16M5 11V15.3025C5 16.0398 5.40565 16.7173 6.05556 17.0655L11.0556 19.744C11.6455 20.0601 12.3545 20.0601 12.9444 19.744L17.9444 17.0655C18.5944 16.7173 19 16.0398 19 15.3025V11\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n};\n\n/**\n * Renders preset icon SVG — uses trusted static SVG content extracted from\n * @central-icons-react at build time. Content is hardcoded (not user input),\n * so innerHTML usage is safe from XSS.\n */\nfunction AgentPresetIcon({ presetId }: { presetId: string }) {\n\tconst svgContent = PRESET_SVG[presetId] ?? PRESET_SVG.sparkle;\n\treturn (\n\t\t// biome-ignore lint: trusted static SVG content from our icon library\n\t\t<svg\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tstyle={{ width: \"55%\", height: \"55%\" }}\n\t\t\tdangerouslySetInnerHTML={{ __html: svgContent ?? \"\" }}\n\t\t/>\n\t);\n}\n\n/**\n * What the header's dismiss control does depends on the shell.\n *\n * In the bubble shell the panel goes away and the launcher is all that is left, so\n * an × is the truth. Docked, the bar stays on the page and keeps the thread one\n * keystroke away — nothing is closed, the conversation folds back into the bar.\n * A chevron says that; an × promises a disappearance that does not happen.\n */\nfunction CloseGlyph({ docked }: { docked: boolean }) {\n\tif (!docked) return <XIcon size={20} />;\n\treturn (\n\t\t<svg\n\t\t\twidth=\"20\"\n\t\t\theight=\"20\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<path d=\"M6 9.5 12 15.5 18 9.5\" />\n\t\t</svg>\n\t);\n}\n\n/**\n * Unified support widget — Intercom-style with tab navigation.\n * Two tabs: Home + Messages. Sub-views: conversation + new conversation.\n */\nexport function DefaultWidget({\n\thideLauncher = false,\n\tplacement = \"bubble\",\n\tcolorScheme,\n\tdockSuggestions,\n}: {\n\thideLauncher?: boolean;\n\tplacement?: WidgetPlacement;\n\t/**\n\t * Pin the appearance instead of following the visitor's OS. An embedded\n\t * widget lives in someone else's page; matching that page beats matching\n\t * the machine it is being read on.\n\t */\n\tcolorScheme?: \"light\" | \"dark\" | \"system\";\n\t/**\n\t * Ways in offered above the docked bar before the visitor types.\n\t * A prop for now — this belongs on AgentConfig once the API returns\n\t * per-workspace (and eventually per-page) suggestions.\n\t */\n\tdockSuggestions?: readonly DockSuggestion[];\n} = {}) {\n\tconst { isReady, website, agentConfig } = useWidget();\n\tuseI18n();\n\tconst { client, store, hasBootstrapError, wsDisconnected, retryBootstrap } = useWidgetContext();\n\tconst { conversations, create, isCreating, setActiveConversation } = useConversations();\n\tconst activeId = useWidgetStore((s) => s.activeConversationId);\n\tconst isDismissed = useWidgetStore((s) => s.isDismissed);\n\tconst { totalUnread } = useUnread();\n\n\tconst contentTabs = useWidgetStore((s) => s.agentConfig?.contentTabs) ?? EMPTY_CONTENT_TABS;\n\tconst { announcementTabs, markEntrySeen, getUnseenEntries } = useAnnouncements();\n\tconst unseenAnnouncementCount = useWidgetStore((s) => s.unseenAnnouncementCount);\n\n\tconst visitorContact = useWidgetStore((s) => s.visitor?.contact);\n\n\t// DEV: email prompt debug\n\tif (process.env.NODE_ENV !== \"production\") {\n\t\tconsole.debug(\"[Widget]\", {\n\t\t\treqEmail: agentConfig?.requireVisitorEmail,\n\t\t\tcontact: visitorContact?.email ?? null,\n\t\t\tactiveId,\n\t\t});\n\t}\n\n\tconst storeIsOpen = useWidgetStore((s) => s.isOpen);\n\tconst [isClosing, setIsClosing] = useState(false);\n\tconst isOpen = storeIsOpen || isClosing;\n\tconst [activeTab, setActiveTab] = useState<Tab>(\"home\");\n\tconst [subView, setSubView] = useState<SubView>(null);\n\tconst [newText, setNewText] = useState(\"\");\n\tconst [contentDetailSlug, setContentDetailSlug] = useState<string | null>(null);\n\tconst [contentCategoryName, setContentCategoryName] = useState<string | null>(null);\n\n\t// Sync API-driven navigation: when store.activeConversationId changes externally\n\t// (via window.Helpway.openConversation), drive the local subView to match.\n\tconst prevActiveIdRef = useRef(activeId);\n\tuseEffect(() => {\n\t\tif (activeId && activeId !== prevActiveIdRef.current && subView !== \"conversation\") {\n\t\t\tsetSubView(\"conversation\");\n\t\t}\n\t\tprevActiveIdRef.current = activeId;\n\t}, [activeId, subView]);\n\n\t// Consume newConversationPrefill from global API (window.Helpway.newConversation)\n\tconst prefill = useWidgetStore((s) => s.newConversationPrefill);\n\tuseEffect(() => {\n\t\tif (prefill !== null) {\n\t\t\tif (prefill.length > 0) setNewText(prefill);\n\t\t\tsetSubView(\"new\");\n\t\t\tsetActiveTab(\"home\");\n\t\t\tstore.getState().setNewConversationPrefill(null);\n\t\t}\n\t}, [prefill, store]);\n\n\tconst closeTimerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n\t// Resolve welcome/subtitle here (used both by openNewConversation seed\n\t// and by the header). Hoisted above openNewConversation so the callback\n\t// captures a defined binding instead of hitting the TDZ at closure time.\n\tconst welcomeMsgRaw = agentConfig?.welcomeMessage;\n\tconst welcomeIsFactoryDefault =\n\t\t!welcomeMsgRaw || welcomeMsgRaw === DEFAULT_EN_WELCOME;\n\tconst welcomeMessage = welcomeMsgRaw?.startsWith(\"widget.\")\n\t\t? t(welcomeMsgRaw)\n\t\t: welcomeIsFactoryDefault\n\t\t\t? t(\"widget.welcome_message\")\n\t\t\t: welcomeMsgRaw;\n\n\tconst openConversation = useCallback(\n\t\t(id: string) => {\n\t\t\tsetActiveConversation(id);\n\t\t\tsetSubView(\"conversation\");\n\t\t},\n\t\t[setActiveConversation],\n\t);\n\n\tconst openNewConversation = useCallback(() => {\n\t\t// Seed a temp conversation + a stable welcome bubble and drop the user\n\t\t// straight into \"conversation\" view. This keeps the welcome bubble\n\t\t// mounted in the SAME React subtree across the first-send transition\n\t\t// (previously: \"new\" view → \"conversation\" view = unmount + remount =\n\t\t// CSS `hw-msg-appear` animation replays = the \"git-gel\" flash).\n\t\t//\n\t\t// useComposer notices the temp id and routes through createConversation\n\t\t// when the visitor sends their first message.\n\t\tconst agentId = agentConfig?.id;\n\t\tif (!agentId) {\n\t\t\t// No agent config yet — skip the seed and let the server decide.\n\t\t\t// The user can still compose; submit will call createConversation.\n\t\t\tsetSubView(\"new\");\n\t\t\treturn;\n\t\t}\n\t\tconst tempId = `temp-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n\t\tconst seedWelcome: TimelineItem = {\n\t\t\tid: `seed-welcome-${tempId}`,\n\t\t\tconversationId: tempId,\n\t\t\torganizationId: \"\",\n\t\t\ttype: \"message\",\n\t\t\tvisibility: \"public\",\n\t\t\ttext: welcomeMessage,\n\t\t\tparts: null,\n\t\t\tuserId: null,\n\t\t\tvisitorId: null,\n\t\t\taiAgentId: agentId,\n\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\teditedAt: null,\n\t\t\tdeletedAt: null,\n\t\t};\n\t\tstore.getState().setMessages(tempId, [seedWelcome]);\n\t\tsetActiveConversation(tempId);\n\t\tsetSubView(\"conversation\");\n\t}, [agentConfig?.id, store, setActiveConversation, welcomeMessage]);\n\n\t// Open straight into a conversation — never onto a home screen.\n\t// First-timers get the seeded welcome + a focused composer; returning\n\t// visitors resume their most recent thread. Every screen between the\n\t// launcher and the composer is a place people drop out, so there isn't\n\t// one: the tab bar only exists once you navigate back to a list.\n\t// Ref-guarded so this fires once per open, and never fights a caller\n\t// that already routed us somewhere (openConversation / prefill).\n\tconst didAutoOpenRef = useRef(false);\n\tuseEffect(() => {\n\t\tif (!isOpen) {\n\t\t\tdidAutoOpenRef.current = false;\n\t\t\treturn;\n\t\t}\n\t\tif (didAutoOpenRef.current || !isReady) return;\n\t\tdidAutoOpenRef.current = true;\n\t\tif (subView !== null) return;\n\t\tconst mostRecent = conversations[0];\n\t\tif (mostRecent) openConversation(mostRecent.id);\n\t\telse openNewConversation();\n\t}, [\n\t\tisOpen,\n\t\tisReady,\n\t\tsubView,\n\t\tconversations,\n\t\topenConversation,\n\t\topenNewConversation,\n\t]);\n\n\t// ── Docked shell ───────────────────────────────────────────────────\n\t// In `placement=\"docked\"` the bar IS the composer, so it needs its own\n\t// composer state — the panel's is hidden. Sending from a cold start\n\t// has to open a conversation first, and useComposer binds its\n\t// conversation id at call time, so the text waits in a ref for one\n\t// render rather than being sent against a stale id.\n\tconst dockComposer = useComposer(activeId);\n\tconst dockRef = useRef(dockComposer);\n\t// Synced after commit, never during render — the ref is only read from\n\t// callbacks and timeouts, which all run after this effect.\n\tuseEffect(() => {\n\t\tdockRef.current = dockComposer;\n\t});\n\tconst pendingDockText = useRef<string | null>(null);\n\n\t/* Folding the panel away leaves the conversation intact — activeConversationId\n\t and the thread both survive — so pressing the bar again should put the\n\t visitor back in it. Guarded on an existing real conversation: on a docs page\n\t a press that opens an empty panel over the article is noise, and sending is\n\t already the thing that opens one from cold. */\n\tconst reopenFromDock = useCallback(() => {\n\t\tconst state = store.getState();\n\t\tif (state.isOpen) return;\n\t\tconst resumable = state.conversations.some((conv) => !conv.id.startsWith(\"temp-\"));\n\t\tif (!resumable) return;\n\t\tstate.setOpen(true);\n\t}, [store]);\n\n\tconst submitFromDock = useCallback(\n\t\t(override?: string) => {\n\t\t\tconst text = (override ?? dockRef.current.text).trim();\n\t\t\t/* An attachment with no caption still has to reach the composer. This guard\n\t\t\t used to be `if (!text) return`, which swallowed the press: the composer's\n\t\t\t caption policy — the thing that produces a visible \"add a message\" error —\n\t\t\t never ran, so a visitor who picked a file and pressed send got a dead\n\t\t\t button and no reason. Empty text is now the composer's call to refuse,\n\t\t\t which it does out loud. */\n\t\t\tconst stagedAttachment = dockRef.current.attachments.some((a) => a.part !== null);\n\t\t\tif (!text && !stagedAttachment) return;\n\t\t\t// The docked shell has no launcher, so sending is the only thing\n\t\t\t// that can reveal the panel — without this the conversation is\n\t\t\t// created and answered while nothing is on screen. Read off the\n\t\t\t// store rather than the hook: the hook binding is declared\n\t\t\t// further down this component.\n\t\t\tstore.getState().setOpen(true);\n\t\t\tif (activeId) {\n\t\t\t\tdockRef.current.setText(\"\");\n\t\t\t\tvoid dockRef.current.submit({ text, conversationId: activeId });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Cold start: openNewConversation seeds the temp conversation through\n\t\t\t// the zustand store, which is synchronous — the id is readable on the\n\t\t\t// next line, before any render. Handing it to submit is what makes a\n\t\t\t// suggestion pill actually send. The previous version staged the text\n\t\t\t// in a ref and fired a 0ms timer, and when the pill lost that race the\n\t\t\t// panel opened onto an empty composer with the question dropped.\n\t\t\topenNewConversation();\n\t\t\tconst seededId = store.getState().activeConversationId;\n\t\t\tdockRef.current.setText(\"\");\n\t\t\tif (!seededId) {\n\t\t\t\t// No agent config yet, so openNewConversation could only route to\n\t\t\t\t// the \"new\" view — the text waits until an id exists.\n\t\t\t\tpendingDockText.current = text;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvoid dockRef.current.submit({ text, conversationId: seededId });\n\t\t},\n\t\t[activeId, openNewConversation, store],\n\t);\n\n\tuseEffect(() => {\n\t\tif (!activeId || pendingDockText.current == null) return;\n\t\tconst text = pendingDockText.current;\n\t\tpendingDockText.current = null;\n\t\tvoid dockRef.current.submit({ text, conversationId: activeId });\n\t}, [activeId]);\n\n\t// Conversation options. The header's only affordance was a close\n\t// button, so expanding the panel or starting over had no home.\n\tconst [menuOpen, setMenuOpen] = useState(false);\n\tuseEffect(() => {\n\t\tif (!menuOpen) return;\n\t\tconst close = () => setMenuOpen(false);\n\t\tconst onKey = (event: KeyboardEvent) => {\n\t\t\tif (event.key === \"Escape\") setMenuOpen(false);\n\t\t};\n\t\tdocument.addEventListener(\"click\", close);\n\t\tdocument.addEventListener(\"keydown\", onKey);\n\t\treturn () => {\n\t\t\tdocument.removeEventListener(\"click\", close);\n\t\t\tdocument.removeEventListener(\"keydown\", onKey);\n\t\t};\n\t}, [menuOpen]);\n\n\tconst goBack = useCallback(() => {\n\t\tif (subView === \"content-detail\") {\n\t\t\t// If inside a grouped tab, go back to category items, not all the way to categories\n\t\t\tconst tabId = activeTab.startsWith(\"content:\") ? activeTab.slice(8) : null;\n\t\t\tconst activeContentTab = tabId ? contentTabs.find((t) => t.id === tabId) : null;\n\t\t\tif (activeContentTab?.tabType === \"grouped\" && contentCategoryName) {\n\t\t\t\tsetSubView(\"content-category\");\n\t\t\t\tsetContentDetailSlug(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetSubView(null);\n\t\t\tsetContentDetailSlug(null);\n\t\t\treturn;\n\t\t}\n\t\tif (subView === \"content-category\") {\n\t\t\tsetSubView(null);\n\t\t\tsetContentCategoryName(null);\n\t\t\treturn;\n\t\t}\n\t\t// Race-immune mark-seen: when leaving a conversation, the visitor has\n\t\t// effectively \"seen\" everything currently in it — including any AI reply\n\t\t// that may have arrived via WS milliseconds before they tapped back.\n\t\t// Without this, the WS event arriving AFTER setActiveConversation(null)\n\t\t// finds isViewing=false and increments unreadCount.\n\t\t// Skip temp-* IDs (server doesn't know about them yet).\n\t\tconst leavingId = store.getState().activeConversationId;\n\t\tif (leavingId && !leavingId.startsWith(\"temp-\")) {\n\t\t\tstore.getState().clearUnread(leavingId);\n\t\t\tclient.widget.markSeen.mutate({ conversationId: leavingId }).catch(() => {});\n\t\t}\n\t\tsetActiveConversation(null);\n\t\tsetSubView(null);\n\t}, [setActiveConversation, subView, activeTab, contentTabs, contentCategoryName, client, store]);\n\n\tconst switchTab = useCallback(\n\t\t(tab: Tab) => {\n\t\t\t// Save current tab state\n\t\t\ttabStateRef.current[activeTab] = { subView, activeId };\n\t\t\t// Restore target tab state (if any)\n\t\t\tconst saved = tabStateRef.current[tab];\n\t\t\tsetActiveTab(tab);\n\t\t\tsetSubView(saved?.subView ?? null);\n\t\t\tif (saved?.activeId != null) {\n\t\t\t\tsetActiveConversation(saved.activeId);\n\t\t\t} else if (!saved) {\n\t\t\t\tsetActiveConversation(null);\n\t\t\t}\n\t\t},\n\t\t[activeTab, subView, activeId, setActiveConversation],\n\t);\n\n\t// Consume pendingContentDetail — set by anchored consumers (or any\n\t// external trigger) that want to deep-link the visitor into a\n\t// specific content entry's detail view instead of dropping them on\n\t// the home surface. Mirrors what the launcher's announcement onOpen\n\t// does internally: mark the entry seen, switch to the right content\n\t// tab, open its detail, then clear the pending state. Sits after\n\t// `switchTab` so the dep array can reference the stable useCallback.\n\tconst pendingContentDetail = useWidgetStore((s) => s.pendingContentDetail);\n\tuseEffect(() => {\n\t\tif (!pendingContentDetail) return;\n\t\tconst { slug, tabId } = pendingContentDetail;\n\t\tmarkEntrySeen(slug);\n\t\tswitchTab(`content:${tabId}`);\n\t\tsetContentDetailSlug(slug);\n\t\tsetSubView(\"content-detail\");\n\t\tstore.getState().setPendingContentDetail(null);\n\t}, [pendingContentDetail, markEntrySeen, switchTab, store]);\n\n\tconst setStoreOpen = useWidgetStore((s) => s.setOpen);\n\n\tconst handleBubbleClick = useCallback(() => {\n\t\tif (storeIsOpen) {\n\t\t\tconst leavingId = store.getState().activeConversationId;\n\t\t\tif (leavingId && !leavingId.startsWith(\"temp-\")) {\n\t\t\t\tstore.getState().clearUnread(leavingId);\n\t\t\t\tclient.widget.markSeen.mutate({ conversationId: leavingId }).catch(() => {});\n\t\t\t}\n\t\t\tsetIsClosing(true);\n\t\t\tcloseTimerRef.current = setTimeout(() => {\n\t\t\t\tsetIsClosing(false);\n\t\t\t\tsetStoreOpen(false);\n\t\t\t}, 200);\n\t\t} else {\n\t\t\tsetIsClosing(false);\n\t\t\tsetSubView(null);\n\t\t\tsetActiveTab(\"home\");\n\t\t\tsetStoreOpen(true);\n\t\t}\n\t}, [storeIsOpen, setStoreOpen, client, store]);\n\n\tconst handleClose = useCallback(() => {\n\t\tconst leavingId = store.getState().activeConversationId;\n\t\tif (leavingId && !leavingId.startsWith(\"temp-\")) {\n\t\t\tstore.getState().clearUnread(leavingId);\n\t\t\tclient.widget.markSeen.mutate({ conversationId: leavingId }).catch(() => {});\n\t\t}\n\t\tsetIsClosing(true);\n\t\tcloseTimerRef.current = setTimeout(() => {\n\t\t\tsetIsClosing(false);\n\t\t\tsetStoreOpen(false);\n\t\t}, 200);\n\t}, [setStoreOpen, client, store]);\n\n\tconst handleNewConversation = useCallback(async () => {\n\t\tconst trimmed = newText.trim();\n\t\tif (!trimmed || isCreating) return;\n\t\tconst conv = await create(trimmed);\n\t\tif (conv) {\n\t\t\tsetNewText(\"\");\n\t\t\tsetSubView(\"conversation\");\n\t\t}\n\t}, [newText, isCreating, create]);\n\n\tconst windowRef = useRef<HTMLDivElement>(null);\n\tconst bubbleRef = useRef<HTMLButtonElement>(null);\n\tconst tabStateRef = useRef<{ [tab: string]: { subView: SubView; activeId: string | null } }>({});\n\tconst touchStartY = useRef(0);\n\tconst touchDeltaY = useRef(0);\n\n\tconst handleTouchStart = useCallback((e: React.TouchEvent) => {\n\t\ttouchStartY.current = e.touches[0]?.clientY ?? 0;\n\t\ttouchDeltaY.current = 0;\n\t}, []);\n\n\tconst handleTouchMove = useCallback((e: React.TouchEvent) => {\n\t\tconst delta = (e.touches[0]?.clientY ?? 0) - touchStartY.current;\n\t\ttouchDeltaY.current = delta;\n\t\tif (delta > 0 && windowRef.current) {\n\t\t\twindowRef.current.style.transform = `translateY(${Math.min(delta, 200)}px)`;\n\t\t\twindowRef.current.style.opacity = `${Math.max(1 - delta / 400, 0.5)}`;\n\t\t}\n\t}, []);\n\n\tconst handleTouchEnd = useCallback(() => {\n\t\tif (windowRef.current) {\n\t\t\twindowRef.current.style.transform = \"\";\n\t\t\twindowRef.current.style.opacity = \"\";\n\t\t}\n\t\tif (touchDeltaY.current > 80) {\n\t\t\thandleClose();\n\t\t}\n\t}, [handleClose]);\n\n\t// iOS virtual keyboard — `height: 100%` in CSS refers to the LAYOUT\n\t// viewport, which doesn't shrink when the keyboard opens on iOS Safari.\n\t// The result: composer gets pushed below the visible area and visitors\n\t// can't see what they're typing. visualViewport.height is the one\n\t// reliable API that reflects post-keyboard space. We write it to a CSS\n\t// custom property the mobile @media block consumes.\n\tuseEffect(() => {\n\t\tif (!isOpen || !windowRef.current) return;\n\t\tconst vv = window.visualViewport;\n\t\tif (!vv) return;\n\t\tconst win = windowRef.current;\n\t\tconst applyHeight = () => {\n\t\t\twin.style.setProperty(\"--hw-visible-height\", `${vv.height}px`);\n\t\t};\n\t\tapplyHeight();\n\t\tvv.addEventListener(\"resize\", applyHeight);\n\t\tvv.addEventListener(\"scroll\", applyHeight);\n\t\treturn () => {\n\t\t\tvv.removeEventListener(\"resize\", applyHeight);\n\t\t\tvv.removeEventListener(\"scroll\", applyHeight);\n\t\t\twin.style.removeProperty(\"--hw-visible-height\");\n\t\t};\n\t}, [isOpen]);\n\n\t// Escape to close / back — listener attached to the widget window, NOT\n\t// document. Two reasons: (1) widget lives inside a shadow DOM; document\n\t// listeners fire for host-page key events too, which would close the\n\t// widget when a visitor presses ESC in the host site's own search box.\n\t// (2) WCAG 2.1 AA requires focus-scoped escape behavior for dialogs.\n\tuseEffect(() => {\n\t\tif (!isOpen || !windowRef.current) return;\n\t\tconst win = windowRef.current;\n\t\tconst handleKeyDown = (e: KeyboardEvent) => {\n\t\t\tif (e.key === \"Escape\") {\n\t\t\t\tif (subView) {\n\t\t\t\t\tgoBack();\n\t\t\t\t} else {\n\t\t\t\t\thandleClose();\n\t\t\t\t\tsetTimeout(() => bubbleRef.current?.focus(), 220);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\twin.addEventListener(\"keydown\", handleKeyDown);\n\t\treturn () => win.removeEventListener(\"keydown\", handleKeyDown);\n\t}, [isOpen, subView, handleClose, goBack]);\n\n\t// Focus trap — same rationale: listen on the widget window so only\n\t// keydowns inside the widget are trapped. `document.activeElement`\n\t// returns the shadow HOST when focus is inside a shadow root; to find\n\t// the actually-focused element we walk into the shadow root.\n\t//\n\t// Skipped entirely under `hideLauncher` (embedded/anchored consumers\n\t// like a sidebar Help item): in that mode the widget shares space\n\t// with the host's own inputs, so grabbing focus on open silently\n\t// steals the visitor's typing/paste context — Cmd+V after opening\n\t// the panel would land in our composer instead of whatever the host\n\t// had focused (paste hijack). Trapping Tab would also fight the\n\t// host's keyboard nav. Both belong to the modal launcher use case,\n\t// not to embedded consumption.\n\tuseEffect(() => {\n\t\tif (!isOpen || !windowRef.current || hideLauncher) return;\n\t\tconst win = windowRef.current;\n\t\tconst getFocusable = () =>\n\t\t\twin.querySelectorAll<HTMLElement>(\n\t\t\t\t'button:not([disabled]), [href], input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n\t\t\t);\n\t\tconst getActive = (): Element | null => {\n\t\t\t// Prefer the shadow root's activeElement so focus tracking works\n\t\t\t// even when the widget is mounted inside a closed/open shadow DOM.\n\t\t\tconst root = win.getRootNode();\n\t\t\tif (root instanceof ShadowRoot) return root.activeElement;\n\t\t\treturn document.activeElement;\n\t\t};\n\t\tconst handleTab = (e: KeyboardEvent) => {\n\t\t\tif (e.key !== \"Tab\") return;\n\t\t\tconst focusable = getFocusable();\n\t\t\tif (focusable.length === 0) return;\n\t\t\tconst first = focusable[0];\n\t\t\tconst last = focusable[focusable.length - 1];\n\t\t\tconst active = getActive();\n\t\t\tif (e.shiftKey && active === first) {\n\t\t\t\te.preventDefault();\n\t\t\t\tlast?.focus();\n\t\t\t} else if (!e.shiftKey && active === last) {\n\t\t\t\te.preventDefault();\n\t\t\t\tfirst?.focus();\n\t\t\t}\n\t\t};\n\t\twin.addEventListener(\"keydown\", handleTab);\n\t\t/* Docked keeps its focus where it was. The composer is the dock bar, which\n\t\t lives OUTSIDE this window — so pulling focus to the panel's first button\n\t\t took it off the field the visitor was mid-sentence in: type, press\n\t\t Enter, and the caret jumped to the header. In the bubble placement the\n\t\t composer IS inside the window, so focusing into it is the right move. */\n\t\tif (placement !== \"docked\") {\n\t\t\tconst focusable = getFocusable();\n\t\t\tif (focusable.length > 0) focusable[0]?.focus();\n\t\t}\n\t\treturn () => win.removeEventListener(\"keydown\", handleTab);\n\t}, [isOpen, hideLauncher, placement]);\n\n\tconst showTabBar = subView === null;\n\t/* Header identity lives in useHeaderIdentity so the per-bubble name label can\n\t compare against the same value instead of re-deriving its own. See the hook\n\t for what the two copies of this chain cost us. */\n\tconst { humanImage, hasTeamAgent, companyName, headerName } = useHeaderIdentity();\n\tconst subtitleMsg = agentConfig?.subtitleText;\n\tconst subtitleIsFactoryDefault =\n\t\t!subtitleMsg || subtitleMsg === DEFAULT_EN_SUBTITLE;\n\tconst subtitleText = subtitleMsg?.startsWith(\"widget.\")\n\t\t? t(subtitleMsg)\n\t\t: subtitleIsFactoryDefault\n\t\t\t? t(\"widget.subtitle_text\")\n\t\t\t: subtitleMsg;\n\tconst brandColor = agentConfig?.brandColor ?? \"#0a0a0a\";\n\tconst widgetPosition = agentConfig?.widgetPosition ?? \"bottom-right\";\n\tconst launcherStyle = agentConfig?.launcherStyle ?? \"icon\";\n\tconst bubbleStyle = agentConfig?.bubbleStyle ?? \"rounded\";\n\n\t// Smart default: when the org uploaded a logo as the agent avatar\n\t// (vs a face photo), tint the chat-header circle with the brand\n\t// color and switch the image to `contain` so the mark isn't cropped.\n\t// `--hw-agent-bg-default` is consumed by the styles.css fallback\n\t// chain — site-side `:root { --hw-agent-bg: ... }` still wins.\n\tconst hasUploadedAvatar = !!agentConfig?.avatarUrl;\n\n\treturn (\n\t\t<div\n\t\t\tclassName=\"hw-widget\"\n\t\t\tdata-hw-placement={placement}\n\t\t\t/* Lets the docked shell close the gap between the panel and the bar while a\n\t\t\t conversation is open: the two become one card with the composer at its\n\t\t\t foot, instead of a floating panel over a separate pill. */\n\t\t\tdata-hw-open={isOpen ? \"true\" : \"false\"}\n\t\t\tdata-theme={colorScheme === \"system\" ? undefined : colorScheme}\n\t\t\tdata-has-avatar={hasUploadedAvatar ? \"true\" : \"false\"}\n\t\t\tstyle={\n\t\t\t\t{\n\t\t\t\t\t\"--hw-primary\": brandColor,\n\t\t\t\t\t\"--hw-position-right\": widgetPosition === \"bottom-right\" ? \"20px\" : \"auto\",\n\t\t\t\t\t\"--hw-position-left\": widgetPosition === \"bottom-left\" ? \"20px\" : \"auto\",\n\t\t\t\t\t\"--hw-window-right\": widgetPosition === \"bottom-right\" ? \"0\" : \"auto\",\n\t\t\t\t\t\"--hw-window-left\": widgetPosition === \"bottom-left\" ? \"0\" : \"auto\",\n\t\t\t\t} as React.CSSProperties\n\t\t\t}\n\t\t>\n\t\t\t{placement === \"docked\" && isReady && (\n\t\t\t\t<DockedBar\n\t\t\t\t\tvalue={dockComposer.text}\n\t\t\t\t\tonChange={dockComposer.setText}\n\t\t\t\t\tonSubmit={() => submitFromDock()}\n\t\t\t\t\tdisabled={dockComposer.isSubmitting}\n\t\t\t\t\tsuggestions={activeId ? undefined : dockSuggestions}\n\t\t\t\t\tonSuggestion={(question) => submitFromDock(question)}\n\t\t\t\t\tattachments={dockComposer.attachments}\n\t\t\t\t\tonAddFiles={dockComposer.addFiles}\n\t\t\t\t\tonRemoveAttachment={dockComposer.removeAttachment}\n\t\t\t\t\tonReopen={reopenFromDock}\n\t\t\t\t\tsendError={dockComposer.sendError}\n\t\t\t\t\tonClearSendError={dockComposer.clearSendError}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{isOpen && !isReady && !hasBootstrapError && (\n\t\t\t\t<div className={`hw-window ${isClosing ? \"hw-window--closing\" : \"\"}`}>\n\t\t\t\t\t<div className=\"hw-skeleton-loading\">\n\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 120 }} />\n\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 200 }} />\n\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 160 }} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t{isOpen && hasBootstrapError && (\n\t\t\t\t<div className={`hw-window ${isClosing ? \"hw-window--closing\" : \"\"}`}>\n\t\t\t\t\t<div className=\"hw-bootstrap-error\">\n\t\t\t\t\t\t<div className=\"hw-bootstrap-error-text\">{t(\"widget.error_desc\")}</div>\n\t\t\t\t\t\t<button type=\"button\" className=\"hw-bootstrap-error-retry\" onClick={retryBootstrap}>\n\t\t\t\t\t\t\t{t(\"widget.retry\")}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t{isOpen && isReady && (\n\t\t\t\t<div\n\t\t\t\t\tref={windowRef}\n\t\t\t\t\tclassName={`hw-window ${isClosing ? \"hw-window--closing\" : \"\"} ${\n\t\t\t\t\t\tsubView === \"content-detail\" ? \"hw-window--reading\" : \"\"\n\t\t\t\t\t}`}\n\t\t\t\t\trole=\"dialog\"\n\t\t\t\t\taria-label={t(\"widget.aria_chat\")}\n\t\t\t\t\taria-modal=\"true\"\n\t\t\t\t\tonTouchStart={handleTouchStart}\n\t\t\t\t\tonTouchMove={handleTouchMove}\n\t\t\t\t\tonTouchEnd={handleTouchEnd}\n\t\t\t\t>\n\t\t\t\t\t{/* Drag handle for mobile swipe-down */}\n\t\t\t\t\t<div className=\"hw-drag-handle\">\n\t\t\t\t\t\t<div className=\"hw-drag-handle-pill\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t{/* WebSocket disconnect banner */}\n\t\t\t\t\t{wsDisconnected && (\n\t\t\t\t\t\t<div className=\"hw-disconnect\">\n\t\t\t\t\t\t\t<div className=\"hw-disconnect-spinner\" />\n\t\t\t\t\t\t\t{t(\"widget.reconnecting\")}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{/* ── Sub-view header: content-detail/content-category gets centered title ── */}\n\t\t\t\t\t{(subView === \"content-detail\" || subView === \"content-category\") &&\n\t\t\t\t\t\t(() => {\n\t\t\t\t\t\t\tconst tabId = activeTab.replace(\"content:\", \"\");\n\t\t\t\t\t\t\tconst contentTab = contentTabs.find((t) => t.id === tabId);\n\t\t\t\t\t\t\t// Show category name when viewing items within a category\n\t\t\t\t\t\t\tconst headerTitle =\n\t\t\t\t\t\t\t\tsubView === \"content-category\" && contentCategoryName\n\t\t\t\t\t\t\t\t\t? contentCategoryName\n\t\t\t\t\t\t\t\t\t: contentTab?.label\n\t\t\t\t\t\t\t\t\t\t? resolveLabel(contentTab.label)\n\t\t\t\t\t\t\t\t\t\t: t(\"widget.content\");\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div className=\"hw-header hw-header--centered\">\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"hw-header-back\"\n\t\t\t\t\t\t\t\t\t\tonClick={goBack}\n\t\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_back\")}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\t\t\tstrokeWidth={2}\n\t\t\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<path d=\"M15 18l-6-6 6-6\" />\n\t\t\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-title\">{headerTitle}</div>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"hw-header-close\"\n\t\t\t\t\t\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_close\")}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<CloseGlyph docked={placement === \"docked\"} />\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})()}\n\t\t\t\t\t{subView !== null && subView !== \"content-detail\" && subView !== \"content-category\" && (\n\t\t\t\t\t\t<div className=\"hw-header hw-header--sub\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"hw-header-back\"\n\t\t\t\t\t\t\t\tonClick={goBack}\n\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_back\")}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\tstrokeWidth={2}\n\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<path d=\"M15 18l-6-6 6-6\" />\n\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<div className=\"hw-header-identity\">\n\t\t\t\t\t\t\t\t<div className={`hw-header-bot-icon${hasTeamAgent ? \" hw-header-bot-icon--team\" : \"\"}`}>\n\t\t\t\t\t\t\t\t\t{hasTeamAgent && humanImage ? (\n\t\t\t\t\t\t\t\t\t\t<img src={humanImage} alt={headerName} className=\"hw-header-agent-img\" />\n\t\t\t\t\t\t\t\t\t) : hasTeamAgent ? (\n\t\t\t\t\t\t\t\t\t\t<span className=\"hw-header-agent-initials\">\n\t\t\t\t\t\t\t\t\t\t\t{headerName.split(\" \").map((w: string) => w[0]).join(\"\").slice(0, 2).toUpperCase()}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t<WidgetLogo />\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"hw-header-info\">\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-name\">{headerName}</div>\n\t\t\t\t\t\t\t\t\t{/* Keep the subtitle identical in both \"new\" and \"conversation\"\n\t\t\t\t\t\t\t\t\t sub-views — otherwise the header reads \"New conversation\"\n\t\t\t\t\t\t\t\t\t while composing and snaps to \"Usually replies in minutes\"\n\t\t\t\t\t\t\t\t\t the moment you send, which feels like the whole header\n\t\t\t\t\t\t\t\t\t rebuilt. */}\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-status\">{subtitleText}</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"hw-header-actions\">\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"hw-header-menu-btn\"\n\t\t\t\t\t\t\t\t\taria-haspopup=\"menu\"\n\t\t\t\t\t\t\t\t\taria-expanded={menuOpen}\n\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_options\")}\n\t\t\t\t\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t\t\t\t\tsetMenuOpen((open) => !open);\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<DotsIcon size={18} />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"hw-header-close\"\n\t\t\t\t\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_close\")}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<CloseGlyph docked={placement === \"docked\"} />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t{menuOpen && (\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-menu\" role=\"menu\">\n\t\t\t\t\t\t\t\t\t\t{/* The docked shell has no tab bar and no list screen, so a visitor\n\t\t\t\t\t\t\t\t\t\t with three threads had no way back to the other two — the menu\n\t\t\t\t\t\t\t\t\t\t offered starting a fourth. Their own conversations belong here,\n\t\t\t\t\t\t\t\t\t\t ahead of the button that makes new ones. */}\n\t\t\t\t\t\t\t\t\t\t{conversations.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"hw-header-menu-convs\">\n\t\t\t\t\t\t\t\t\t\t\t\t{conversations.slice(0, 3).map((conv) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={conv.id}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"hw-header-menu-conv\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-active={conv.id === activeId ? \"true\" : undefined}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetMenuOpen(false);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\topenConversation(conv.id);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"hw-header-menu-conv-top\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"hw-header-menu-conv-name\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{conv.assigneeName ??\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(conv.lastMessageSenderType === \"team\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? conv.lastMessageSenderName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: null) ??\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcompanyName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{conv.lastMessageAt && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"hw-header-menu-conv-time\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatRelativeTime(conv.lastMessageAt)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"hw-header-menu-conv-preview\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{conv.lastMessageText ?? t(\"widget.no_preview\")}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\t\tsetMenuOpen(false);\n\t\t\t\t\t\t\t\t\t\t\t\topenNewConversation();\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<NewChatIcon size={16} />\n\t\t\t\t\t\t\t\t\t\t\t{t(\"widget.new_conversation\")}\n\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* ── Home: hero header with gradient + sheet overlay ── */}\n\t\t\t\t\t{subView === null && activeTab === \"home\" && (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<div className=\"hw-hero\">\n\t\t\t\t\t\t\t\t<div className=\"hw-hero-top\">\n\t\t\t\t\t\t\t\t\t<div className=\"hw-hero-bot-icon\">\n\t\t\t\t\t\t\t\t\t\t<WidgetLogo />\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"hw-hero-close\"\n\t\t\t\t\t\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_close\")}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<CloseGlyph docked={placement === \"docked\"} />\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"hw-hero-greeting\">\n\t\t\t\t\t\t\t\t\t{welcomeMessage.split(\"\\n\").map((line, i) => (\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\t\t\t\t\tclassName={i === 0 ? \"hw-hero-greeting-name\" : \"hw-hero-greeting-question\"}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{i > 0 && <br />}\n\t\t\t\t\t\t\t\t\t\t\t{line}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"hw-hero-subtitle\">{subtitleText}</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t{/* Sheet — overlaps hero, Intercom-style white drawer */}\n\t\t\t\t\t\t\t<div className=\"hw-sheet\">\n\t\t\t\t\t\t\t\t<div className=\"hw-sheet-inner\">\n\t\t\t\t\t\t\t\t\t<button type=\"button\" className=\"hw-card\" onClick={openNewConversation}>\n\t\t\t\t\t\t\t\t\t\t<div className=\"hw-card-body\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"hw-card-title\">{t(\"widget.send_us_message\")}</div>\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"hw-card-meta\">{t(\"widget.reply_time\")}</div>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t<div className=\"hw-card-arrow\">\n\t\t\t\t\t\t\t\t\t\t\t<SendIcon />\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t{announcementTabs.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t<WhatsNewCard\n\t\t\t\t\t\t\t\t\t\t\tgetUnseenEntries={getUnseenEntries}\n\t\t\t\t\t\t\t\t\t\t\tannouncementTabs={announcementTabs}\n\t\t\t\t\t\t\t\t\t\t\tonViewAll={() => {\n\t\t\t\t\t\t\t\t\t\t\t\tswitchTab(`content:${announcementTabs[0]!.id}`);\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\tonSelect={(slug, tabId) => {\n\t\t\t\t\t\t\t\t\t\t\t\tswitchTab(`content:${tabId}`);\n\t\t\t\t\t\t\t\t\t\t\t\tsetContentDetailSlug(slug);\n\t\t\t\t\t\t\t\t\t\t\t\tsetSubView(\"content-detail\");\n\t\t\t\t\t\t\t\t\t\t\t\tmarkEntrySeen(slug);\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t<HomeView\n\t\t\t\t\t\t\t\t\t\tconversations={conversations}\n\t\t\t\t\t\t\t\t\t\tonSelect={openConversation}\n\t\t\t\t\t\t\t\t\t\tonMessagesClick={() => switchTab(\"messages\")}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* ── Messages tab header ── */}\n\t\t\t\t\t{subView === null && activeTab === \"messages\" && (\n\t\t\t\t\t\t<div className=\"hw-header hw-header--centered\">\n\t\t\t\t\t\t\t<div className=\"hw-header-spacer\" />\n\t\t\t\t\t\t\t<div className=\"hw-header-title\">{t(\"widget.messages\")}</div>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"hw-header-close\"\n\t\t\t\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_close\")}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<CloseGlyph docked={placement === \"docked\"} />\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* ── Content tab header (list view, not detail) ── */}\n\t\t\t\t\t{subView === null &&\n\t\t\t\t\t\tactiveTab.startsWith(\"content:\") &&\n\t\t\t\t\t\t(() => {\n\t\t\t\t\t\t\tconst tabId = activeTab.replace(\"content:\", \"\");\n\t\t\t\t\t\t\tconst contentTab = contentTabs.find((t) => t.id === tabId);\n\t\t\t\t\t\t\tif (!contentTab) return null;\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div className=\"hw-header hw-header--centered\">\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-spacer\" />\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-title\">{resolveLabel(contentTab.label)}</div>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"hw-header-close\"\n\t\t\t\t\t\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_close\")}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<CloseGlyph docked={placement === \"docked\"} />\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})()}\n\n\t\t\t\t\t{/* ── Content (non-home views) ── */}\n\t\t\t\t\t{(subView !== null || activeTab !== \"home\") && (\n\t\t\t\t\t\t<div className=\"hw-content\">\n\t\t\t\t\t\t\t{subView === null && activeTab === \"messages\" && (\n\t\t\t\t\t\t\t\t<MessagesView\n\t\t\t\t\t\t\t\t\tconversations={conversations}\n\t\t\t\t\t\t\t\t\tonSelect={openConversation}\n\t\t\t\t\t\t\t\t\tonNewClick={openNewConversation}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t{subView === \"new\" && (\n\t\t\t\t\t\t\t\t<NewConversationView\n\t\t\t\t\t\t\t\t\ttext={newText}\n\t\t\t\t\t\t\t\t\tonTextChange={setNewText}\n\t\t\t\t\t\t\t\t\tonSubmit={handleNewConversation}\n\t\t\t\t\t\t\t\t\tisSubmitting={isCreating}\n\t\t\t\t\t\t\t\t\twelcomeMessage={welcomeMessage}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t{subView === \"conversation\" && activeId && (\n\t\t\t\t\t\t\t\t<ConversationView conversationId={activeId} starters={dockSuggestions} />\n\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t{/* ── Content tab views ── */}\n\t\t\t\t\t\t\t{activeTab.startsWith(\"content:\") &&\n\t\t\t\t\t\t\t\t(() => {\n\t\t\t\t\t\t\t\t\tconst tabId = activeTab.replace(\"content:\", \"\");\n\t\t\t\t\t\t\t\t\tconst contentTab = contentTabs.find((t) => t.id === tabId);\n\t\t\t\t\t\t\t\t\tif (!contentTab) return null;\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<ContentTabView\n\t\t\t\t\t\t\t\t\t\t\ttab={contentTab}\n\t\t\t\t\t\t\t\t\t\t\tshowDetail={subView === \"content-detail\"}\n\t\t\t\t\t\t\t\t\t\t\tdetailSlug={contentDetailSlug}\n\t\t\t\t\t\t\t\t\t\t\tsubView={subView}\n\t\t\t\t\t\t\t\t\t\t\tonSelectEntry={(slug) => {\n\t\t\t\t\t\t\t\t\t\t\t\tsetContentDetailSlug(slug);\n\t\t\t\t\t\t\t\t\t\t\t\tsetSubView(\"content-detail\");\n\t\t\t\t\t\t\t\t\t\t\t\t// Mark seen on open, mirroring the home-tab and\n\t\t\t\t\t\t\t\t\t\t\t\t// deep-link paths. Without this, opening a changelog\n\t\t\t\t\t\t\t\t\t\t\t\t// entry from the content tab left the unseen badge\n\t\t\t\t\t\t\t\t\t\t\t\t// stuck until another path happened to clear it.\n\t\t\t\t\t\t\t\t\t\t\t\tmarkEntrySeen(slug);\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\tonSelectCategory={(cat) => {\n\t\t\t\t\t\t\t\t\t\t\t\tsetContentCategoryName(cat.title);\n\t\t\t\t\t\t\t\t\t\t\t\tsetSubView(\"content-category\");\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t})()}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* ── Tab Bar ── */}\n\t\t\t\t\t{showTabBar && (\n\t\t\t\t\t\t<TabBar\n\t\t\t\t\t\t\tactiveTab={activeTab}\n\t\t\t\t\t\t\tonTabChange={switchTab}\n\t\t\t\t\t\t\tunreadCount={totalUnread}\n\t\t\t\t\t\t\tcontentTabs={contentTabs}\n\t\t\t\t\t\t\tshowMessagesTab={agentConfig?.showMessagesTab ?? true}\n\t\t\t\t\t\t\tunseenAnnouncementCount={unseenAnnouncementCount}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* ── Footer ── */}\n\t\t\t\t\t<div className=\"hw-powered\">\n\t\t\t\t\t\t{t(\"widget.powered_by\")}{\" \"}\n\t\t\t\t\t\t<a href=\"https://helpway.ai\" target=\"_blank\" rel=\"noopener noreferrer\">\n\t\t\t\t\t\t\tHelpway\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Message Preview — shown when widget is closed and not dismissed.\n\t\t\t Gated on isReady alongside the bubble so the proactive teaser\n\t\t\t doesn't pop in with default content before bootstrap. */}\n\t\t\t{isReady && !isOpen && !isDismissed && !hideLauncher && (\n\t\t\t\t/* No auto-dismiss. This card only ever carries a real incoming reply,\n\t\t\t\t and the old 8-second timer deleted it: a visitor who looked away\n\t\t\t\t for a moment lost the notification entirely — the unread count\n\t\t\t\t stayed, the words did not. It now waits for the visitor to open\n\t\t\t\t the thread or close the card, which is what a notification is\n\t\t\t\t supposed to do. */\n\t\t\t\t<MessagePreview\n\t\t\t\t\tonOpen={handleBubbleClick}\n\t\t\t\t\tavatar={<WidgetLogo />}\n\t\t\t\t\tautoDismissMs={null}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{/* Announcement Previews — shown when widget is closed and unseen announcements exist */}\n\t\t\t{isReady && !isOpen && !isDismissed && !hideLauncher && (\n\t\t\t\t<AnnouncementPreviews\n\t\t\t\t\tavatar={<WidgetLogo />}\n\t\t\t\t\tonOpen={(slug, tabId) => {\n\t\t\t\t\t\tmarkEntrySeen(slug);\n\t\t\t\t\t\thandleBubbleClick();\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tswitchTab(`content:${tabId}`);\n\t\t\t\t\t\t\tsetContentDetailSlug(slug);\n\t\t\t\t\t\t\tsetSubView(\"content-detail\");\n\t\t\t\t\t\t}, 50);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{/* Dev-only debug overlay — activates via ?hwdebug=1 or localStorage hw:debug=1 */}\n\t\t\t<WidgetDebugOverlay />\n\n\t\t\t{/* Bubble — hidden until bootstrap completes so visitors don't\n\t\t\t see a flash of the default Helpway brand mark + neutral\n\t\t\t color before the org's custom icon + brand color arrive.\n\t\t\t isReady flips true once and stays true, so the bubble\n\t\t\t remains visible across the rest of the session. */}\n\t\t\t{isReady && !isDismissed && (!hideLauncher || isOpen) && (\n\t\t\t\t<button\n\t\t\t\t\tref={bubbleRef}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName={[\n\t\t\t\t\t\t\"hw-bubble\",\n\t\t\t\t\t\t`hw-bubble--${bubbleStyle}`,\n\t\t\t\t\t\tlauncherStyle !== \"icon\" ? `hw-bubble--launcher-${launcherStyle}` : \"\",\n\t\t\t\t\t\tisOpen ? \"hw-bubble--open\" : \"\",\n\t\t\t\t\t\t(agentConfig?.launcherIconUrl || agentConfig?.avatarUrl || website?.logoUrl) ? \"hw-bubble--avatar\" : \"\",\n\t\t\t\t\t]\n\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t.join(\" \")}\n\t\t\t\t\tonClick={handleBubbleClick}\n\t\t\t\t\taria-label={isOpen ? t(\"widget.aria_close_support\") : t(\"widget.aria_open\")}\n\t\t\t\t\taria-expanded={isOpen}\n\t\t\t\t\taria-haspopup=\"dialog\"\n\t\t\t\t>\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName={`hw-bubble-icon hw-bubble-icon--bot ${isOpen ? \"hw-bubble-icon--hidden\" : \"\"}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<LauncherIcon />\n\t\t\t\t\t</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName={`hw-bubble-icon hw-bubble-icon--close ${!isOpen ? \"hw-bubble-icon--hidden\" : \"\"}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<XIcon size={24} />\n\t\t\t\t\t</span>\n\t\t\t\t\t{launcherStyle !== \"icon\" && !isOpen && (\n\t\t\t\t\t\t<span className=\"hw-bubble-label\">\n\t\t\t\t\t\t\t{launcherStyle === \"help\" ? t(\"widget.help\") : companyName}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)}\n\t\t\t\t\t{!isOpen && (totalUnread > 0 || unseenAnnouncementCount > 0) && (\n\t\t\t\t\t\t<div className=\"hw-bubble-badge\">\n\t\t\t\t\t\t\t{totalUnread > 0 ? totalUnread : \"\"}\n\t\t\t\t\t\t\t{totalUnread === 0 && unseenAnnouncementCount > 0 && (\n\t\t\t\t\t\t\t\t<span className=\"hw-bubble-badge-dot\" />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// ── Tab Bar ─────────────────────────────────────────────\n\nfunction TabBar({\n\tactiveTab,\n\tonTabChange,\n\tunreadCount,\n\tcontentTabs,\n\tshowMessagesTab = true,\n\tunseenAnnouncementCount = 0,\n}: {\n\tactiveTab: Tab;\n\tonTabChange: (tab: Tab) => void;\n\tunreadCount: number;\n\tcontentTabs: WidgetContentTab[];\n\tshowMessagesTab?: boolean;\n\tunseenAnnouncementCount?: number;\n}) {\n\treturn (\n\t\t<div className=\"hw-tabs\" role=\"tablist\">\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tclassName={`hw-tabs-item ${activeTab === \"home\" ? \"hw-tabs-item--active\" : \"\"}`}\n\t\t\t\tonClick={() => onTabChange(\"home\")}\n\t\t\t\trole=\"tab\"\n\t\t\t\taria-selected={activeTab === \"home\"}\n\t\t\t>\n\t\t\t\t<HomeIcon />\n\t\t\t\t<span>{t(\"widget.home\")}</span>\n\t\t\t</button>\n\t\t\t{showMessagesTab && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName={`hw-tabs-item ${activeTab === \"messages\" ? \"hw-tabs-item--active\" : \"\"}`}\n\t\t\t\t\tonClick={() => onTabChange(\"messages\")}\n\t\t\t\t\trole=\"tab\"\n\t\t\t\t\taria-selected={activeTab === \"messages\"}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"hw-tabs-icon-wrap\">\n\t\t\t\t\t\t<MessagesIcon />\n\t\t\t\t\t\t{unreadCount > 0 && (\n\t\t\t\t\t\t\t<span className=\"hw-tabs-badge\">{unreadCount > 99 ? \"99+\" : unreadCount}</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span>{t(\"widget.messages\")}</span>\n\t\t\t\t</button>\n\t\t\t)}\n\t\t\t{/* Dynamic content tabs from Better i18n Content CMS */}\n\t\t\t{contentTabs.map((tab) => (\n\t\t\t\t<button\n\t\t\t\t\tkey={tab.id}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName={`hw-tabs-item ${activeTab === `content:${tab.id}` ? \"hw-tabs-item--active\" : \"\"}`}\n\t\t\t\t\tonClick={() => onTabChange(`content:${tab.id}`)}\n\t\t\t\t\trole=\"tab\"\n\t\t\t\t\taria-selected={activeTab === `content:${tab.id}`}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"hw-tabs-icon-wrap\">\n\t\t\t\t\t\t<ContentTabIconComponent icon={tab.icon} />\n\t\t\t\t\t\t{tab.isAnnouncements && unseenAnnouncementCount > 0 && (\n\t\t\t\t\t\t\t<span className=\"hw-tabs-dot\" />\n\t\t\t\t\t\t)}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span>{resolveLabel(tab.label)}</span>\n\t\t\t\t</button>\n\t\t\t))}\n\t\t</div>\n\t);\n}\n\n// ── Home Tab ────────────────────────────────────────────\n\nfunction HomeView({\n\tconversations,\n\tonSelect,\n\tonMessagesClick,\n}: {\n\tconversations: ConversationSummary[];\n\tonSelect: (id: string) => void;\n\tonMessagesClick: () => void;\n}) {\n\tconst recent = conversations.slice(0, 3);\n\tif (recent.length === 0) return null;\n\n\treturn (\n\t\t<div className=\"hw-recent-card\">\n\t\t\t<div className=\"hw-recent-header\">{t(\"widget.recent_conversations\")}</div>\n\t\t\t{recent.map((conv, i) => (\n\t\t\t\t<ConversationRow\n\t\t\t\t\tkey={conv.id}\n\t\t\t\t\tconversation={conv}\n\t\t\t\t\tonSelect={onSelect}\n\t\t\t\t\tisLast={i === recent.length - 1}\n\t\t\t\t/>\n\t\t\t))}\n\t\t\t{conversations.length > 3 && (\n\t\t\t\t<button type=\"button\" className=\"hw-recent-see-all\" onClick={onMessagesClick}>\n\t\t\t\t\t{t(\"widget.see_all\")}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// ── Messages Tab ────────────────────────────────────────\n\nfunction MessagesView({\n\tconversations,\n\tonSelect,\n\tonNewClick,\n}: {\n\tconversations: ConversationSummary[];\n\tonSelect: (id: string) => void;\n\tonNewClick: () => void;\n}) {\n\tif (conversations.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"hw-empty-state\">\n\t\t\t\t<div className=\"hw-empty-icon-wrap\">\n\t\t\t\t\t<MessagesIcon />\n\t\t\t\t</div>\n\t\t\t\t<div className=\"hw-empty-title\">{t(\"widget.no_messages\")}</div>\n\t\t\t\t<div className=\"hw-empty-desc\">{t(\"widget.no_messages_desc\")}</div>\n\t\t\t\t<button type=\"button\" className=\"hw-empty-btn\" onClick={onNewClick}>\n\t\t\t\t\t{t(\"widget.start_conversation\")}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"hw-msgs-tab\">\n\t\t\t{conversations.map((conv) => (\n\t\t\t\t<ConversationCard key={conv.id} conversation={conv} onSelect={onSelect} />\n\t\t\t))}\n\t\t</div>\n\t);\n}\n\n// ── Shared conversation body (avatar + name + time + preview) ──\n\nfunction ConvCardBody({ conv }: { conv: ConversationSummary }) {\n\tconst agentName = useWidgetStore((s) => s.agentConfig?.name) ?? \"Support\";\n\tconst isTeam = conv.lastMessageSenderType === \"team\" && conv.lastMessageSenderName;\n\tconst displayName = isTeam ? conv.lastMessageSenderName! : agentName;\n\tconst preview = conv.lastMessageText ?? t(\"widget.no_preview\");\n\treturn (\n\t\t<>\n\t\t\t<div className={`hw-conv-card-avatar${isTeam ? \" hw-conv-card-avatar--team\" : \"\"}`}>\n\t\t\t\t{isTeam ? (\n\t\t\t\t\tconv.lastMessageSenderImage ? (\n\t\t\t\t\t\t<img src={conv.lastMessageSenderImage} alt={displayName} className=\"hw-conv-card-avatar-img\" />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<span className=\"hw-conv-card-avatar-initials\">\n\t\t\t\t\t\t\t{displayName.split(\" \").map((w) => w[0]).join(\"\").slice(0, 2).toUpperCase()}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)\n\t\t\t\t) : (\n\t\t\t\t\t<WidgetLogo />\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div className=\"hw-conv-card-content\">\n\t\t\t\t<div className=\"hw-conv-card-top\">\n\t\t\t\t\t<span className=\"hw-conv-card-name\">{displayName}</span>\n\t\t\t\t\t{conv.lastMessageAt && (\n\t\t\t\t\t\t<span className=\"hw-conv-card-time\">{formatRelativeTime(conv.lastMessageAt)}</span>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"hw-conv-card-preview\">{preview}</div>\n\t\t\t</div>\n\t\t</>\n\t);\n}\n\n// ── Conversation Card (Intercom-style, Messages tab) ─────\n\nfunction ConversationCard({\n\tconversation: conv,\n\tonSelect,\n}: {\n\tconversation: ConversationSummary;\n\tonSelect: (id: string) => void;\n}) {\n\tconst hasUnread = conv.unreadCount > 0;\n\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclassName={`hw-conv-card ${hasUnread ? \"hw-conv-card--unread\" : \"\"}`}\n\t\t\tonClick={() => onSelect(conv.id)}\n\t\t>\n\t\t\t<div className=\"hw-conv-card-row\">\n\t\t\t\t<ConvCardBody conv={conv} />\n\t\t\t</div>\n\t\t\t{hasUnread && <div className=\"hw-conv-card-badge\">{conv.unreadCount}</div>}\n\t\t</button>\n\t);\n}\n\n// ── Conversation Row (inside Home tab grouped card) ───────\n\nfunction ConversationRow({\n\tconversation: conv,\n\tonSelect,\n\tisLast,\n}: {\n\tconversation: ConversationSummary;\n\tonSelect: (id: string) => void;\n\tisLast: boolean;\n}) {\n\tconst hasUnread = conv.unreadCount > 0;\n\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclassName={`hw-recent-row ${hasUnread ? \"hw-recent-row--unread\" : \"\"} ${isLast ? \"hw-recent-row--last\" : \"\"}`}\n\t\t\tonClick={() => onSelect(conv.id)}\n\t\t>\n\t\t\t<ConvCardBody conv={conv} />\n\t\t\t{hasUnread && <div className=\"hw-recent-row-badge\">{conv.unreadCount}</div>}\n\t\t</button>\n\t);\n}\n\n// ── Inline Email Prompt (post-first-reply) ─────────────\n\nfunction InlineEmailPrompt({ conversationId }: { conversationId?: string }) {\n\tconst { client, store } = useWidgetContext();\n\tconst updateContact = useWidgetStore((s) => s.updateVisitorContact);\n\tconst [email, setEmail] = useState(\"\");\n\tconst [isSubmitting, setIsSubmitting] = useState(false);\n\tconst [isSuccess, setIsSuccess] = useState(false);\n\tconst [hasError, setHasError] = useState(false);\n\n\tconst handleSubmit = async () => {\n\t\tconst trimmed = email.trim();\n\t\tif (!trimmed || !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(trimmed)) {\n\t\t\tsetHasError(true);\n\t\t\treturn;\n\t\t}\n\t\tsetHasError(false);\n\n\t\tconst previousContact = store.getState().visitor?.contact ?? null;\n\t\tconst optimisticContactId = previousContact?.id ?? `optimistic-contact-${Date.now()}`;\n\t\tupdateContact({\n\t\t\tid: optimisticContactId,\n\t\t\tname: previousContact?.name ?? null,\n\t\t\temail: trimmed,\n\t\t});\n\t\tsetIsSuccess(true);\n\t\tsetIsSubmitting(true);\n\t\ttry {\n\t\t\tconst result = await client.widget.collectEmail.mutate({\n\t\t\t\temail: trimmed,\n\t\t\t\t...(conversationId ? { conversationId } : {}),\n\t\t\t});\n\t\t\tif (result.contact) {\n\t\t\t\tupdateContact({\n\t\t\t\t\tid: result.contact.id,\n\t\t\t\t\tname: result.contact.name,\n\t\t\t\t\temail: result.contact.email,\n\t\t\t\t});\n\t\t\t}\n\t\t\t// needsEmail will become false via optimistic contact update\n\t\t} catch {\n\t\t\tif (previousContact) {\n\t\t\t\tupdateContact(previousContact);\n\t\t\t} else {\n\t\t\t\tupdateContact({ id: \"\", name: null, email: null });\n\t\t\t}\n\t\t\tsetIsSuccess(false);\n\t\t} finally {\n\t\t\tsetIsSubmitting(false);\n\t\t}\n\t};\n\n\tif (isSuccess) {\n\t\treturn (\n\t\t\t<div className=\"hw-email-card hw-email-card--success\">\n\t\t\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#22c55e\" strokeWidth={2.5} strokeLinecap=\"round\" strokeLinejoin=\"round\">\n\t\t\t\t\t<polyline points=\"20 6 9 17 4 12\" />\n\t\t\t\t</svg>\n\t\t\t\t{t(\"widget.email_saved\")}\n\t\t\t</div>\n\t\t);\n\t}\n\n\t/* Asking for an email is a one-field favour, and it was built like a form: an\n\t icon tile, two lines of header, a full-width input and a full-width button —\n\t four stacked blocks and about 150px of thread for one address. It is a\n\t labelled row now, with the submit inside the field, so it reads as part of\n\t the conversation rather than an interruption of it. */\n\treturn (\n\t\t<div className=\"hw-email-card\">\n\t\t\t<p className=\"hw-email-card-title\">{t(\"widget.email_title\")}</p>\n\t\t\t<p className=\"hw-email-card-subtitle\">{t(\"widget.email_subtitle\")}</p>\n\t\t\t<div className=\"hw-email-card-row\">\n\t\t\t\t<input\n\t\t\t\t\ttype=\"email\"\n\t\t\t\t\tclassName={`hw-email-card-input${hasError ? \" hw-email-card-input--error\" : \"\"}`}\n\t\t\t\t\tvalue={email}\n\t\t\t\t\tonChange={(e) => { setEmail(e.target.value); setHasError(false); }}\n\t\t\t\t\tonKeyDown={(e) => { if (e.key === \"Enter\") handleSubmit(); }}\n\t\t\t\t\tplaceholder={t(\"widget.email_placeholder\")}\n\t\t\t\t/>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"hw-email-card-submit\"\n\t\t\t\t\tonClick={handleSubmit}\n\t\t\t\t\tdisabled={isSubmitting || !email.trim()}\n\t\t\t\t\taria-label={t(\"widget.email_continue\")}\n\t\t\t\t>\n\t\t\t\t\t{isSubmitting ? (\n\t\t\t\t\t\t<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n\t\t\t\t\t\t\t<circle cx=\"12\" cy=\"12\" r=\"10\" strokeDasharray=\"32\" strokeDashoffset=\"32\">\n\t\t\t\t\t\t\t\t<animate attributeName=\"stroke-dashoffset\" values=\"32;0\" dur=\"1s\" repeatCount=\"indefinite\" />\n\t\t\t\t\t\t\t</circle>\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2.2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t<path d=\"M5 12h13M12 5l7 7-7 7\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ── New Conversation ────────────────────────────────────\n\nfunction NewConversationView({\n\ttext,\n\tonTextChange,\n\tonSubmit,\n\tisSubmitting,\n\twelcomeMessage,\n}: {\n\ttext: string;\n\tonTextChange: (t: string) => void;\n\tonSubmit: () => void;\n\tisSubmitting: boolean;\n\twelcomeMessage: string;\n}) {\n\t// Stable timestamp so the bubble doesn't tick/re-render while the user types.\n\treturn (\n\t\t<div className=\"hw-new\">\n\t\t\t{/* Use the same MessageBubble that renders inside ConversationView so\n\t\t\t the welcome message looks IDENTICAL before and after the first send\n\t\t\t — same markdown rendering (line breaks preserved), same styles,\n\t\t\t same meta row. Without this the \"new\" view uses a raw string render\n\t\t\t and the user sees the bubble visually change the moment the\n\t\t\t conversation is created. */}\n\t\t\t<div className=\"hw-new-welcome\">\n\t\t\t\t<MessageBubble\n\t\t\t\t\ttext={welcomeMessage}\n\t\t\t\t\tsender=\"ai\"\n\t\t\t\t\tparts={null}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<Composer\n\t\t\t\ttext={text}\n\t\t\t\tonTextChange={onTextChange}\n\t\t\t\tonSubmit={onSubmit}\n\t\t\t\tisSubmitting={isSubmitting}\n\t\t\t\tplaceholder={t(\"widget.placeholder_new\")}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\n// ── Conversation View ───────────────────────────────────\n\nfunction ConversationView({\n\tconversationId,\n\tstarters,\n}: {\n\tconversationId: string;\n\t/** Offered under the greeting until the visitor has said something. */\n\tstarters?: readonly DockSuggestion[];\n}) {\n\tconst { items, isLoading, hasMore, loadMore } = useTimeline(conversationId);\n\tconst {\n\t\ttext,\n\t\tsetText,\n\t\tsubmit,\n\t\tisSubmitting,\n\t\tattachments,\n\t\taddFiles,\n\t\tremoveAttachment,\n\t\tsendError,\n\t\tclearSendError,\n\t\temailGateConvId,\n\t} = useComposer(conversationId);\n\tconst { isTyping, isAiProcessing, setTyping } = usePresence(conversationId);\n\tconst streamingText = useWidgetStore((s) => s.streamingText.get(conversationId) ?? \"\");\n\tconst agentConfig = useWidgetStore((s) => s.agentConfig);\n\tconst visitorContact = useWidgetStore((s) => s.visitor?.contact);\n\n\t// Only while the thread is still nothing but the seeded welcome. The\n\t// first rule here checked for a visitor message, which left the\n\t// suggestions sitting under \"<name> joined the conversation\" — a human\n\t// arriving is exactly the moment canned questions stop being helpful.\n\t// Any second item at all means something happened, so that is the test.\n\tconst showStarters = !!starters?.length && items.length <= 1;\n\n\t// Reaching a human is something the agent offers, not a control the\n\t// visitor has to find. Fin has none anywhere and gates the request\n\t// behind an email form; this is one tap and never gated. Shown once\n\t// the agent has actually said something, and dropped as soon as a\n\t// human is in the thread.\n\n\n\tconst isResolved = useWidgetStore((s) => {\n\t\tconst conv = s.conversations.find((c) => c.id === conversationId);\n\t\treturn conv?.status === \"resolved\";\n\t});\n\n\t// Email prompt gate (BETTER-227 — Intercom pattern).\n\t// Show ONLY after:\n\t// (1) visitor sent at least one real message (not the welcome bubble), AND\n\t// (2) AI has replied at least once (so the visitor has seen value from the widget)\n\t// Prevents the \"Get notified when we reply\" card from appearing on widget open\n\t// before the visitor has even typed. Matches Intercom's post-first-response flow.\n\tconst visitorMessageCount = items.filter(\n\t\t(it) => it.type === \"message\" && Boolean((it as { visitorId?: string | null }).visitorId),\n\t).length;\n\tconst hasAiReply = items.some(\n\t\t(it) => it.type === \"message\" && Boolean((it as { aiAgentId?: string | null }).aiAgentId),\n\t);\n\t// Email is satisfied if EITHER the contact has one (fully identified\n\t// visitor) OR the visitor itself has one (collected via the gate but\n\t// not yet linked to a Contact row). Without the visitor.email fallback,\n\t// the gate re-shows on every refresh until a Contact is created.\n\tconst visitorOwnEmail = useWidgetStore((s) => s.visitor?.email);\n\tconst hasEmail = !!visitorContact?.email || !!visitorOwnEmail;\n\tconst needsEmailPostReply =\n\t\t!!agentConfig?.requireVisitorEmail &&\n\t\t!hasEmail &&\n\t\tvisitorMessageCount >= 2 &&\n\t\thasAiReply;\n\tconst needsEmail = needsEmailPostReply || !!emailGateConvId;\n\n\tif (isLoading && items.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"hw-messages\">\n\t\t\t\t<div className=\"hw-skeleton-messages\">\n\t\t\t\t\t{/* AI message skeleton */}\n\t\t\t\t\t<div className=\"hw-skeleton-msg\">\n\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-avatar\" />\n\t\t\t\t\t\t<div className=\"hw-skeleton-bubble\">\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 140 }} />\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 200 }} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t{/* Visitor message skeleton */}\n\t\t\t\t\t<div className=\"hw-skeleton-msg hw-skeleton-msg--right\">\n\t\t\t\t\t\t<div className=\"hw-skeleton-bubble\" style={{ alignItems: \"flex-end\" }}>\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 160 }} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t{/* AI reply skeleton */}\n\t\t\t\t\t<div className=\"hw-skeleton-msg\">\n\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-avatar\" />\n\t\t\t\t\t\t<div className=\"hw-skeleton-bubble\">\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 180 }} />\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 120 }} />\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 80 }} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<MessageList\n\t\t\t\titems={items}\n\t\t\t\tisTyping={isTyping}\n\t\t\t\tisAiProcessing={isAiProcessing}\n\t\t\t\tstreamingText={streamingText || undefined}\n\t\t\t\thasMore={hasMore}\n\t\t\t\tisLoadingMore={isLoading}\n\t\t\t\tonLoadMore={loadMore}\n\t\t\t\t/* No \"Talk to a human\" offer here any more. The pipeline escalates on its\n\t\t\t\t own the moment it cannot answer — that is what the escalate tool is\n\t\t\t\t for — so the button was a second, manual path to something that had\n\t\t\t\t already happened, and it sat under every answer including the ones\n\t\t\t\t that were fine. */\n\t\t\t\t/* The email ask belongs IN the thread. Pinned under the list it read as\n\t\t\t\t chrome — a form the panel had grown at the bottom, competing with the\n\t\t\t\t composer directly below it — when what it actually is is the agent\n\t\t\t\t asking one more question. Inside the scroller it arrives after the last\n\t\t\t\t message, scrolls with it, and the reader answers it the way they\n\t\t\t\t answered everything else. */\n\t\t\t\trenderAfterMessages={\n\t\t\t\t\tneedsEmail || showStarters ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t{needsEmail && (\n\t\t\t\t\t\t\t\t<InlineEmailPrompt conversationId={emailGateConvId ?? undefined} />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{showStarters && (\n\t\t\t\t\t\t\t\t<div className=\"hw-starters\">\n\t\t\t\t\t\t\t{starters?.map((entry, index) => {\n\t\t\t\t\t\t\t\tconst question = typeof entry === \"string\" ? entry : entry.question;\n\t\t\t\t\t\t\t\tconst label = typeof entry === \"string\" ? null : entry.label;\n\t\t\t\t\t\t\t\t/* The label leads and the question explains it. Side by side\n\t\t\t\t\t\t\t\t they fought for the same line: labels are short words in\n\t\t\t\t\t\t\t\t some configs (\"Pricing\") and half-sentences in others\n\t\t\t\t\t\t\t\t (\"Pick a framework\"), and a fixed-width column had to be\n\t\t\t\t\t\t\t\t wrong for one of them. Stacked, both lengths read the same.\n\t\t\t\t\t\t\t\t With no label the question IS the line, so it moves up. */\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tkey={question}\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"hw-starter\"\n\t\t\t\t\t\t\t\t\t\tstyle={{ animationDelay: `${90 + index * 70}ms` }}\n\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\tvoid submit({ text: question });\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<span className=\"hw-starter-text\">\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"hw-starter-k\">{label ?? question}</span>\n\t\t\t\t\t\t\t\t\t\t\t{label && <span className=\"hw-starter-q\">{question}</span>}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<ChevronRightIcon size={14} />\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : undefined\n\t\t\t\t}\n\t\t\t/>\n\t\t\t{/* Resolved → show the CSAT banner ABOVE the composer, never INSTEAD\n\t\t\t of it. Keeping the composer mounted means a follow-up just\n\t\t\t works: the server reopens the thread (widget.sendMessage →\n\t\t\t status: open) so resolved is never a dead-end. */}\n\t\t\t{isResolved && <ResolvedBanner conversationId={conversationId} />}\n\t\t\t{sendError && (\n\t\t\t\t<div className=\"hw-send-error\">\n\t\t\t\t\t{sendError}\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"hw-send-error-retry\"\n\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\tclearSendError();\n\t\t\t\t\t\t\tsubmit();\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(\"widget.retry\")}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<Composer\n\t\t\t\ttext={text}\n\t\t\t\tonTextChange={setText}\n\t\t\t\tonSubmit={submit}\n\t\t\t\tonTyping={setTyping}\n\t\t\t\tisSubmitting={isSubmitting}\n\t\t\t\tattachments={attachments}\n\t\t\t\tonAddFiles={addFiles}\n\t\t\t\tonRemoveAttachment={removeAttachment}\n\t\t\t\tdisabled={needsEmail}\n\t\t\t/>\n\t\t</>\n\t);\n}\n\n// ── Resolved Banner with CSAT ───────────────────────────\n\nfunction ResolvedBanner({ conversationId }: { conversationId: string }) {\n\tconst { client } = useWidgetContext();\n\tconst [csatRating, setCsatRating] = useState<\"good\" | \"bad\" | null>(null);\n\tconst [csatSubmitted, setCsatSubmitted] = useState(false);\n\n\tconst handleCsat = (rating: \"good\" | \"bad\") => {\n\t\tsetCsatRating(rating);\n\t\tsetCsatSubmitted(true);\n\t\t// Send CSAT via API (fire and forget)\n\t\tclient.widget.sendCsat.mutate({ conversationId, rating }).catch(() => {});\n\t};\n\n\treturn (\n\t\t<div className=\"hw-resolved\">\n\t\t\t<div className=\"hw-resolved-text\">{t(\"widget.resolved_text\")}</div>\n\t\t\t{!csatSubmitted ? (\n\t\t\t\t<div className=\"hw-csat\">\n\t\t\t\t\t<div className=\"hw-csat-label\">{t(\"widget.csat_label\")}</div>\n\t\t\t\t\t<div className=\"hw-csat-buttons\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName={`hw-csat-btn ${csatRating === \"good\" ? \"hw-csat-btn--selected\" : \"\"}`}\n\t\t\t\t\t\t\tonClick={() => handleCsat(\"good\")}\n\t\t\t\t\t\t\taria-label={t(\"widget.aria_good\")}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t👍\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName={`hw-csat-btn ${csatRating === \"bad\" ? \"hw-csat-btn--selected\" : \"\"}`}\n\t\t\t\t\t\t\tonClick={() => handleCsat(\"bad\")}\n\t\t\t\t\t\t\taria-label={t(\"widget.aria_bad\")}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t👎\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t) : (\n\t\t\t\t<div className=\"hw-csat-thanks\">{t(\"widget.csat_thanks\")}</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// ── Message Preview Bubble ─────────────────────\n// MessagePreview moved to ./message-preview.tsx so `hideLauncher`\n// integrations can render the same proactive bubble next to their own\n// trigger. DefaultWidget composes it with the launcher placement +\n// <WidgetLogo /> avatar above.\n\n// ── Announcement Preview Bubble ─────────────────\n// AnnouncementPreviews + AnnouncementPreviewItem (and the stripMarkdown\n// helper) moved to ./announcement-previews.tsx + ./strip-markdown.ts so\n// `hideLauncher` integrations can render the same proactive cards next\n// to their own trigger. DefaultWidget composes the export above with\n// the launcher placement + <WidgetLogo /> avatar.\n\n// ── What's New Card (Home tab) ──────────────────\n\nfunction WhatsNewCard({\n\tgetUnseenEntries,\n\tannouncementTabs,\n\tonViewAll,\n\tonSelect,\n}: {\n\tgetUnseenEntries: () => UnseenAnnouncementEntry[];\n\tannouncementTabs: WidgetContentTab[];\n\tonViewAll: () => void;\n\tonSelect: (slug: string, tabId: string) => void;\n}) {\n\tconst unseen = getUnseenEntries();\n\tif (unseen.length === 0) return null;\n\n\tconst display = unseen.slice(0, 3);\n\tconst badgeFieldMap = new Map(\n\t\tannouncementTabs.map((t) => [t.id, t.display?.badgeField]),\n\t);\n\n\treturn (\n\t\t<div className=\"hw-whats-new\">\n\t\t\t<div className=\"hw-whats-new-header\">\n\t\t\t\t<span className=\"hw-whats-new-title\">{resolveLabel(\"widget.whats_new\")}</span>\n\t\t\t\t<button type=\"button\" className=\"hw-whats-new-view-all\" onClick={onViewAll}>\n\t\t\t\t\t{resolveLabel(\"widget.view_all\")} →\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<div className=\"hw-whats-new-list\">\n\t\t\t\t{display.map((entry) => {\n\t\t\t\t\tconst badgeField = badgeFieldMap.get(entry.tabId);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tkey={entry.slug}\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"hw-whats-new-item\"\n\t\t\t\t\t\t\tonClick={() => onSelect(entry.slug, entry.tabId)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{badgeField && entry.customFields[badgeField] && (\n\t\t\t\t\t\t\t\t<div className=\"hw-whats-new-item-top\">\n\t\t\t\t\t\t\t\t\t<span className=\"hw-whats-new-badge\">\n\t\t\t\t\t\t\t\t\t\t{entry.customFields[badgeField]}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t{entry.publishedAt && (\n\t\t\t\t\t\t\t\t\t\t<span className=\"hw-whats-new-time\">\n\t\t\t\t\t\t\t\t\t\t\t{formatRelativeTime(entry.publishedAt)}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t<div className=\"hw-whats-new-item-title\">\n\t\t\t\t\t\t\t\t{entry.title}\n\t\t\t\t\t\t\t\t{!badgeField && entry.publishedAt && (\n\t\t\t\t\t\t\t\t\t<span className=\"hw-whats-new-time-inline\">\n\t\t\t\t\t\t\t\t\t\t{formatRelativeTime(entry.publishedAt)}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{entry.body && (() => {\n\t\t\t\t\t\t\t\tconst clean = stripMarkdown(entry.body);\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<div className=\"hw-whats-new-item-body\">\n\t\t\t\t\t\t\t\t\t\t{clean.length > 80 ? `${clean.slice(0, 80)}…` : clean}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})()}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","import { CONTENT_CACHE_TTL, getLocale } from \"@helpway/widget-core\";\nimport type { WidgetContentTab } from \"@helpway/widget-core\";\nimport { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\ninterface AnnouncementEntry {\n\tslug: string;\n\ttitle: string;\n\tbody: string | null;\n\tpublishedAt: string | null;\n\tcustomFields: Record<string, string | null>;\n}\n\nexport interface UnseenAnnouncementEntry extends AnnouncementEntry {\n\ttabId: string;\n}\n\n// ── Per-entry localStorage tracking ──\n\nfunction storageKey(websiteId: string, visitorId: string): string {\n\treturn `helpway:${websiteId}:${visitorId}:announcements:seen`;\n}\n\nfunction hasSeenKey(websiteId: string, visitorId: string): boolean {\n\ttry {\n\t\treturn localStorage.getItem(storageKey(websiteId, visitorId)) !== null;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction getSeenSlugs(websiteId: string, visitorId: string): Set<string> {\n\ttry {\n\t\tconst raw = localStorage.getItem(storageKey(websiteId, visitorId));\n\t\tif (!raw) return new Set();\n\t\treturn new Set(JSON.parse(raw) as string[]);\n\t} catch {\n\t\treturn new Set();\n\t}\n}\n\nfunction addSeenSlug(websiteId: string, visitorId: string, slug: string): void {\n\ttry {\n\t\tconst seen = getSeenSlugs(websiteId, visitorId);\n\t\tseen.add(slug);\n\t\tlocalStorage.setItem(storageKey(websiteId, visitorId), JSON.stringify([...seen]));\n\t} catch {\n\t\t// storage full or blocked\n\t}\n}\n\nfunction addSeenSlugs(websiteId: string, visitorId: string, slugs: string[]): void {\n\ttry {\n\t\tconst seen = getSeenSlugs(websiteId, visitorId);\n\t\tfor (const s of slugs) seen.add(s);\n\t\tlocalStorage.setItem(storageKey(websiteId, visitorId), JSON.stringify([...seen]));\n\t} catch {\n\t\t// storage full or blocked\n\t}\n}\n\nfunction filterUnseen(entries: AnnouncementEntry[], seen: Set<string>): AnnouncementEntry[] {\n\treturn entries.filter((e) => !seen.has(e.slug));\n}\n\nconst EMPTY_TABS: WidgetContentTab[] = [];\n\n/**\n * Per-entry announcement tracking across all tabs with isAnnouncements.\n *\n * Anonymous visitors (no contact) skip first-visit seeding — they always\n * see announcement previews. Identified visitors seed on first visit so\n * existing entries don't flood as unread.\n *\n * Multiple announcement tabs supported: previews stack, unseen count\n * aggregates, and each entry carries its tabId for correct navigation.\n */\nexport function useAnnouncements() {\n\tconst { client, store } = useWidgetContext();\n\tconst isReady = useWidgetStore((s) => s.isReady);\n\tconst websiteId = useWidgetStore((s) => s.website?.id) ?? null;\n\tconst visitorId = useWidgetStore((s) => s.visitor?.id) ?? null;\n\tconst isAnonymous = useWidgetStore((s) => !s.visitor?.contact);\n\tconst contentTabs = useWidgetStore((s) => s.agentConfig?.contentTabs) ?? EMPTY_TABS;\n\tconst announcementTabs = useMemo(\n\t\t() => contentTabs.filter((t) => t.isAnnouncements),\n\t\t[contentTabs],\n\t);\n\tconst checkedRef = useRef(false);\n\n\tuseEffect(() => {\n\t\tif (!isReady || !websiteId || !visitorId || announcementTabs.length === 0) return;\n\t\tif (checkedRef.current) return;\n\t\tcheckedRef.current = true;\n\n\t\tconst isFirstVisit = !hasSeenKey(websiteId, visitorId);\n\t\tlet pending = announcementTabs.length;\n\t\tlet totalUnseen = 0;\n\t\tconst allSlugs: string[] = [];\n\n\t\tfunction onTabDone(entries: AnnouncementEntry[], tab: WidgetContentTab) {\n\t\t\tallSlugs.push(...entries.map((e) => e.slug));\n\n\t\t\t// Identified user's first visit: defer unseen computation until\n\t\t\t// all tabs are collected so we can seed everything at once.\n\t\t\tif (!(isFirstVisit && !isAnonymous) && entries.length > 0) {\n\t\t\t\tconst seen = getSeenSlugs(websiteId!, visitorId!);\n\t\t\t\tconst unseen = filterUnseen(entries, seen);\n\t\t\t\ttotalUnseen += unseen.length;\n\n\t\t\t\tconst newest = unseen[0];\n\t\t\t\tif (newest && !store.getState().isOpen) {\n\t\t\t\t\tconst badgeField = tab.display?.badgeField;\n\t\t\t\t\tstore.getState().setAnnouncementPreview({\n\t\t\t\t\t\ttitle: newest.title,\n\t\t\t\t\t\tbody: newest.body,\n\t\t\t\t\t\tslug: newest.slug,\n\t\t\t\t\t\ttabId: tab.id,\n\t\t\t\t\t\tbadge: badgeField ? (newest.customFields[badgeField] ?? null) : null,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpending--;\n\t\t\tif (pending === 0) {\n\t\t\t\tif (isFirstVisit && !isAnonymous) {\n\t\t\t\t\t// Seed all entries across all tabs at once\n\t\t\t\t\tif (allSlugs.length > 0) {\n\t\t\t\t\t\taddSeenSlugs(websiteId!, visitorId!, allSlugs);\n\t\t\t\t\t}\n\t\t\t\t\tstore.getState().setUnseenAnnouncementCount(0);\n\t\t\t\t} else {\n\t\t\t\t\tstore.getState().setUnseenAnnouncementCount(totalUnseen);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const tab of announcementTabs) {\n\t\t\tconst cacheKey = `announcements:${tab.id}:${getLocale()}`;\n\t\t\tconst cached = store.getState().contentCache.get(cacheKey);\n\t\t\tif (cached && Date.now() - cached.ts < CONTENT_CACHE_TTL) {\n\t\t\t\tonTabDone(cached.data as AnnouncementEntry[], tab);\n\t\t\t} else {\n\t\t\t\tclient.widget.getContent\n\t\t\t\t\t.query({ tabId: tab.id, page: 1, limit: 5, language: getLocale() })\n\t\t\t\t\t.then((result: { items?: AnnouncementEntry[] }) => {\n\t\t\t\t\t\tconst entries = result.items ?? [];\n\t\t\t\t\t\tstore.getState().setContentCache(cacheKey, entries);\n\t\t\t\t\t\tonTabDone(entries, tab);\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tonTabDone([], tab);\n\t\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}, [isReady, websiteId, visitorId, isAnonymous, announcementTabs, client, store]);\n\n\tconst markEntrySeen = useCallback(\n\t\t(slug: string) => {\n\t\t\tif (!websiteId || !visitorId || announcementTabs.length === 0) return;\n\t\t\taddSeenSlug(websiteId, visitorId, slug);\n\n\t\t\t// Recompute total unseen count across all tabs\n\t\t\tconst seen = getSeenSlugs(websiteId, visitorId);\n\t\t\tlet total = 0;\n\t\t\tfor (const tab of announcementTabs) {\n\t\t\t\tconst cacheKey = `announcements:${tab.id}:${getLocale()}`;\n\t\t\t\tconst cached = store.getState().contentCache.get(cacheKey);\n\t\t\t\tif (cached) {\n\t\t\t\t\ttotal += filterUnseen(cached.data as AnnouncementEntry[], seen).length;\n\t\t\t\t}\n\t\t\t}\n\t\t\tstore.getState().setUnseenAnnouncementCount(total);\n\t\t\tstore.getState().dismissAnnouncementPreview(slug);\n\t\t},\n\t\t[websiteId, visitorId, announcementTabs, store],\n\t);\n\n\tconst markAllSeen = useCallback(() => {\n\t\tif (!websiteId || !visitorId || announcementTabs.length === 0) return;\n\t\tfor (const tab of announcementTabs) {\n\t\t\tconst cacheKey = `announcements:${tab.id}:${getLocale()}`;\n\t\t\tconst cached = store.getState().contentCache.get(cacheKey);\n\t\t\tif (cached) {\n\t\t\t\tconst entries = cached.data as AnnouncementEntry[];\n\t\t\t\taddSeenSlugs(websiteId, visitorId, entries.map((e) => e.slug));\n\t\t\t}\n\t\t}\n\t\tstore.getState().setUnseenAnnouncementCount(0);\n\t\tstore.getState().dismissAnnouncementPreview();\n\t}, [websiteId, visitorId, announcementTabs, store]);\n\n\tconst getUnseenEntries = useCallback((): UnseenAnnouncementEntry[] => {\n\t\tif (announcementTabs.length === 0 || !websiteId || !visitorId) return [];\n\t\tconst seen = getSeenSlugs(websiteId, visitorId);\n\t\tconst result: UnseenAnnouncementEntry[] = [];\n\t\tfor (const tab of announcementTabs) {\n\t\t\tconst cacheKey = `announcements:${tab.id}:${getLocale()}`;\n\t\t\tconst cached = store.getState().contentCache.get(cacheKey);\n\t\t\tif (cached) {\n\t\t\t\tfor (const entry of filterUnseen(cached.data as AnnouncementEntry[], seen)) {\n\t\t\t\t\tresult.push({ ...entry, tabId: tab.id });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}, [announcementTabs, websiteId, visitorId, store]);\n\n\treturn {\n\t\tannouncementTabs,\n\t\tmarkEntrySeen,\n\t\tmarkAllSeen,\n\t\tgetUnseenEntries,\n\t};\n}\n","import type { TimelineItem } from \"@helpway/types\";\nimport { t } from \"@helpway/widget-core\";\nimport { useCallback, useState } from \"react\";\nimport { useWidgetContext } from \"../provider\";\n\n/**\n * The page the visitor is on, shaped for `sendMessage`.\n *\n * Returns nothing off the browser (SSR) or when the URL is unreadable, so the\n * field simply stays absent rather than sending an empty page the server would\n * have to defend against.\n */\nfunction currentPagePayload(): { page?: { url: string; title: string } } {\n\tif (typeof window === \"undefined\") return {};\n\tconst url = window.location.href;\n\tif (!url) return {};\n\treturn { page: { url, title: document.title || window.location.pathname } };\n}\n\nexport interface PendingAttachment {\n\tid: string;\n\tfile: File;\n\tpreviewUrl: string | null; // blob URL for images\n\tisUploading: boolean;\n\terror: string | null;\n\t/** Resolved after upload — the part to include in sendMessage */\n\tpart:\n\t\t| { type: \"image\"; url: string; mimeType: string }\n\t\t| { type: \"file\"; url: string; fileName: string; fileSize: number; mimeType: string }\n\t\t| null;\n}\n\nconst MAX_ATTACHMENTS = 10;\nconst MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB\n\n/**\n * Composer state — text input + attachments + submit for a conversation.\n */\n/**\n * What the file picker will offer. Lives with the attachment hook rather than in\n * the composer that renders the picker: the docked bar has a picker of its own,\n * and two lists of accepted types drift the moment one of them gains a format.\n */\nexport const ACCEPTED_TYPES = [\n\t\"image/png\",\n\t\"image/jpeg\",\n\t\"image/gif\",\n\t\"image/webp\",\n\t\"image/svg+xml\",\n\t\"application/pdf\",\n\t\"text/plain\",\n\t\"text/csv\",\n\t\"application/zip\",\n\t\"application/msword\",\n\t\"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n\t\"application/vnd.ms-excel\",\n\t\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n].join(\",\");\n\nexport function useComposer(boundConversationId: string | null) {\n\tconst { client, ws, store } = useWidgetContext();\n\t// Alias so every callback below keeps reading `conversationId` while\n\t// `submit` is free to shadow it with a caller-supplied id (see there).\n\tconst conversationId = boundConversationId;\n\tconst [text, setText] = useState(\"\");\n\tconst [isSubmitting, setIsSubmitting] = useState(false);\n\tconst [attachments, setAttachments] = useState<PendingAttachment[]>([]);\n\tconst [sendError, setSendError] = useState<string | null>(null);\n\tconst [emailGateConvId, setEmailGateConvId] = useState<string | null>(null);\n\n\tconst addFiles = useCallback(\n\t\tasync (files: File[]) => {\n\t\t\tif (!conversationId) return;\n\n\t\t\tconst remaining = MAX_ATTACHMENTS - attachments.length;\n\t\t\tconst toAdd = files.slice(0, remaining);\n\t\t\tif (toAdd.length === 0) return;\n\n\t\t\t// Create pending entries\n\t\t\tconst pending: PendingAttachment[] = toAdd.map((file) => ({\n\t\t\t\tid: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n\t\t\t\tfile,\n\t\t\t\tpreviewUrl: file.type.startsWith(\"image/\") ? URL.createObjectURL(file) : null,\n\t\t\t\tisUploading: true,\n\t\t\t\terror: null,\n\t\t\t\tpart: null,\n\t\t\t}));\n\n\t\t\tsetAttachments((prev) => [...prev, ...pending]);\n\n\t\t\t// Upload each file\n\t\t\tfor (const item of pending) {\n\t\t\t\ttry {\n\t\t\t\t\tif (item.file.size > MAX_FILE_SIZE) {\n\t\t\t\t\t\tthrow new Error(t(\"widget.file_too_large\"));\n\t\t\t\t\t}\n\n\t\t\t\t\t// Read file as base64\n\t\t\t\t\tconst base64 = await fileToBase64(item.file);\n\n\t\t\t\t\t// For temp conversations (before first send) skip the\n\t\t\t\t\t// conversationId — server scopes the R2 key to the visitor\n\t\t\t\t\t// and the file is attached to the timeline item by\n\t\t\t\t\t// createConversation when submit fires.\n\t\t\t\t\tconst convIdForUpload = conversationId.startsWith(\"temp-\") ? undefined : conversationId;\n\t\t\t\t\tconst result = await client.widget.uploadAttachment.mutate({\n\t\t\t\t\t\t...(convIdForUpload ? { conversationId: convIdForUpload } : {}),\n\t\t\t\t\t\tbase64,\n\t\t\t\t\t\tmimeType: item.file.type || \"application/octet-stream\",\n\t\t\t\t\t\tfileName: item.file.name,\n\t\t\t\t\t});\n\n\t\t\t\t\tsetAttachments((prev) =>\n\t\t\t\t\t\tprev.map((a) =>\n\t\t\t\t\t\t\ta.id === item.id ? { ...a, isUploading: false, part: result.part } : a,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Upload failed\";\n\t\t\t\t\tsetAttachments((prev) =>\n\t\t\t\t\t\tprev.map((a) => (a.id === item.id ? { ...a, isUploading: false, error: message } : a)),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[conversationId, attachments.length, client],\n\t);\n\n\tconst removeAttachment = useCallback((id: string) => {\n\t\tsetAttachments((prev) => {\n\t\t\tconst item = prev.find((a) => a.id === id);\n\t\t\tif (item?.previewUrl) URL.revokeObjectURL(item.previewUrl);\n\t\t\treturn prev.filter((a) => a.id !== id);\n\t\t});\n\t}, []);\n\n\t/**\n\t * `override` exists because the caller sometimes knows the text and the\n\t * conversation before this closure does: a suggestion pill sends a question\n\t * the composer state has never held, and the docked shell creates the\n\t * conversation in the same click that sends its first message. Passing both\n\t * in replaces the old setText → wait-a-tick → submit dance, which dropped\n\t * the message whenever the re-render didn't land before the timer.\n\t */\n\tconst submit = useCallback(\n\t\tasync (override?: { text?: string; conversationId?: string }) => {\n\t\t\tconst conversationId = override?.conversationId ?? boundConversationId;\n\t\t\tconst source = override?.text ?? text;\n\t\t\tconst trimmed = source.trim();\n\t\t\tconst readyParts = attachments.filter((a) => a.part !== null).map((a) => a.part!);\n\t\t\tconst hasText = trimmed.length > 0;\n\t\t\tconst hasAttachments = readyParts.length > 0;\n\n\t\t\tif (!conversationId || isSubmitting) return;\n\n\t\t\t// Policy 2026-04-19: every outgoing message must have a text body.\n\t\t\t// An attachment on its own renders as an empty bubble in the\n\t\t\t// dashboard and leaves the AI with no caption to reason about.\n\t\t\t// Surface a soft inline error instead of silently no-op'ing so\n\t\t\t// the visitor understands *why* the send didn't go through.\n\t\t\tif (!hasText) {\n\t\t\t\tif (hasAttachments) {\n\t\t\t\t\tsetSendError(t(\"widget.caption_required\"));\n\t\t\t\t\tsetTimeout(() => setSendError(null), 4000);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Don't send while uploads are in progress\n\t\t\tconst stillUploading = attachments.some((a) => a.isUploading);\n\t\t\tif (stillUploading) return;\n\n\t\t\t// ── OPTIMISTIC: message appears in the widget INSTANTLY ──\n\t\t\t// The user sees their message the moment they hit send; the mutation\n\t\t\t// runs in the background. On success we swap the optimistic placeholder\n\t\t\t// for the server-confirmed item (preserving scroll + bubble position).\n\t\t\t// On failure we remove the placeholder and restore the composer text.\n\t\t\tconst optimisticId = `optimistic-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n\t\t\tconst now = new Date().toISOString();\n\t\t\tconst currentVisitorId = store.getState().visitor?.id ?? null;\n\t\t\tconst optimisticItem: TimelineItem = {\n\t\t\t\tid: optimisticId,\n\t\t\t\tconversationId,\n\t\t\t\torganizationId: \"\",\n\t\t\t\ttype: \"message\",\n\t\t\t\tvisibility: \"public\",\n\t\t\t\ttext: hasText ? trimmed : null,\n\t\t\t\tparts:\n\t\t\t\t\thasText || hasAttachments\n\t\t\t\t\t\t? ([\n\t\t\t\t\t\t\t\t...(hasText ? [{ type: \"text\" as const, text: trimmed }] : []),\n\t\t\t\t\t\t\t\t...readyParts,\n\t\t\t\t\t\t\t] as TimelineItem[\"parts\"])\n\t\t\t\t\t\t: null,\n\t\t\t\tuserId: null,\n\t\t\t\tvisitorId: currentVisitorId,\n\t\t\t\taiAgentId: null,\n\t\t\t\tcreatedAt: now,\n\t\t\t\teditedAt: null,\n\t\t\t\tdeletedAt: null,\n\t\t\t};\n\n\t\t\t// Flush UI immediately\n\t\t\tconst attachmentsSnapshot = attachments;\n\t\t\tconst textSnapshot = source;\n\t\t\tstore.getState().addMessage(conversationId, optimisticItem);\n\t\t\t/* Show that something is coming NOW, not when the server gets around to\n\t\t\t saying so. The thinking dots used to wait for aiProcessingProgress, which\n\t\t\t the pipeline emits only after the queue picks the job up — so the visitor\n\t\t\t pressed send and watched an empty panel for as long as that took. The\n\t\t\t visitor's own message is proof enough that a reply is on its way.\n\n\t\t\t Every path that ends the reply already clears this: aiStreamChunk,\n\t\t\t timelineItemCreated with an aiAgentId, aiProcessingCompleted, and the\n\t\t\t rollback below when the send itself fails. */\n\t\t\tstore.getState().setAiProcessing(conversationId, true);\n\t\t\tsetText(\"\");\n\t\t\tsetAttachments([]);\n\t\t\tws.sendTyping(conversationId, false);\n\t\t\tsetIsSubmitting(true);\n\t\t\ttry {\n\t\t\t\t// Temp conversation IDs (seeded by openNewConversation) don't exist on\n\t\t\t\t// the server yet. On the first send we have to call createConversation\n\t\t\t\t// instead — the API allocates the real ID and returns the visitor item.\n\t\t\t\t// The welcome item from the response is DROPPED because the widget is\n\t\t\t\t// already showing a seed welcome bubble; keeping the same bubble\n\t\t\t\t// instance across this transition is what prevents the \"git-gel\" flash.\n\t\t\t\tconst isTempConversation = conversationId.startsWith(\"temp-\");\n\t\t\t\t// Ephemeral proactive conversation — only exists in the widget\n\t\t\t\t// store, server hasn't seen it yet. First reply triggers\n\t\t\t\t// materialization (creates conversation + writes greeting +\n\t\t\t\t// visitor message in one go).\n\t\t\t\tconst isEphemeralConversation = conversationId.startsWith(\"eph-\");\n\t\t\t\tif (isEphemeralConversation) {\n\t\t\t\t\tconst workflowId = conversationId.slice(\"eph-\".length);\n\t\t\t\t\tconst result = await client.widget.materializeFromProactive.mutate({\n\t\t\t\t\t\tworkflowId,\n\t\t\t\t\t\t...(hasText ? { text: trimmed } : {}),\n\t\t\t\t\t});\n\t\t\t\t\t// Pull the real conversation onto the synthetic id so all the\n\t\t\t\t\t// in-flight optimistic state (visitor bubble, scroll position,\n\t\t\t\t\t// active id) carries over without a flash.\n\t\t\t\t\tstore.getState().remapConversationId(conversationId, result.conversationId);\n\t\t\t\t\t// Hydrate canonical timeline from server — replaces synthetic\n\t\t\t\t\t// greeting ids with real ULIDs and surfaces the persisted\n\t\t\t\t\t// visitor message. We keep the optimistic placeholder in the\n\t\t\t\t\t// store so the visitor sees their bubble immediately; the\n\t\t\t\t\t// canonical setMessages dedupes by id, but our optimistic id\n\t\t\t\t\t// won't collide so it'll be shadowed cleanly.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst timeline = await client.widget.getTimeline.query({\n\t\t\t\t\t\t\tconversationId: result.conversationId,\n\t\t\t\t\t\t\tlimit: 50,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (timeline?.items) {\n\t\t\t\t\t\t\tstore.getState().setMessages(result.conversationId, timeline.items as TimelineItem[]);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Best-effort: optimistic state is still on screen, next\n\t\t\t\t\t\t// WS event or refresh will hydrate.\n\t\t\t\t\t}\n\t\t\t\t} else if (isTempConversation) {\n\t\t\t\t\tconst result = await client.widget.createConversation.mutate({\n\t\t\t\t\t\t...(hasText ? { text: trimmed } : {}),\n\t\t\t\t\t\t...(hasAttachments ? { parts: readyParts } : {}),\n\t\t\t\t\t\t/* The first message is the one that most needs this — someone\n\t\t\t\t\t\t lands on a page and immediately asks what it is. */\n\t\t\t\t\t\t...currentPagePayload(),\n\t\t\t\t\t});\n\t\t\t\t\tconst conv = result.conversation;\n\t\t\t\t\t// Move the temp conversation's messages (seed welcome + optimistic\n\t\t\t\t\t// visitor) onto the server-assigned id. remapConversationId merges\n\t\t\t\t\t// with any existing items under the real id (WS races are fine).\n\t\t\t\t\tstore.getState().remapConversationId(conversationId, conv.id);\n\t\t\t\t\tif (result.item) {\n\t\t\t\t\t\tstore.getState().replaceMessage(conv.id, optimisticId, result.item as TimelineItem);\n\t\t\t\t\t}\n\t\t\t\t\tif (result.requireEmail) {\n\t\t\t\t\t\tsetEmailGateConvId(conv.id);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst result = await client.widget.sendMessage.mutate({\n\t\t\t\t\t\tconversationId,\n\t\t\t\t\t\t...(hasText ? { text: trimmed } : {}),\n\t\t\t\t\t\t...(hasAttachments ? { parts: readyParts } : {}),\n\t\t\t\t\t\t/* Carry the page with the question. The provider reports it on\n\t\t\t\t\t\t bootstrap too, but that call is fire-and-forget — a visitor who\n\t\t\t\t\t\t lands and immediately asks \"what is this page about\" beat it,\n\t\t\t\t\t\t and the agent answered with no idea where they were. */\n\t\t\t\t\t\t...currentPagePayload(),\n\t\t\t\t\t});\n\n\t\t\t\t\t// Replace optimistic placeholder with server-confirmed item.\n\t\t\t\t\t// If the WS echo already landed with the real id, replaceMessage\n\t\t\t\t\t// just drops the placeholder (race-safe, see store implementation).\n\t\t\t\t\tstore\n\t\t\t\t\t\t.getState()\n\t\t\t\t\t\t.replaceMessage(conversationId, optimisticId, result.item as TimelineItem);\n\t\t\t\t}\n\n\t\t\t\t// Clean up blob URLs for uploaded attachments\n\t\t\t\tfor (const a of attachmentsSnapshot) {\n\t\t\t\t\tif (a.previewUrl) URL.revokeObjectURL(a.previewUrl);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useComposer] Send failed:\", err);\n\t\t\t\t// Roll back: remove placeholder, restore text + attachments so user can retry\n\t\t\t\tstore.getState().removeMessage(conversationId, optimisticId);\n\t\t\t\t// Nothing is coming — take the dots back down with the message.\n\t\t\t\tstore.getState().setAiProcessing(conversationId, false);\n\t\t\t\tsetText(textSnapshot);\n\t\t\t\tsetAttachments(attachmentsSnapshot);\n\t\t\t\tsetSendError(err instanceof Error ? err.message : t(\"widget.send_error\"));\n\t\t\t\t// Auto-clear after 5 seconds\n\t\t\t\tsetTimeout(() => setSendError(null), 5000);\n\t\t\t} finally {\n\t\t\t\tsetIsSubmitting(false);\n\t\t\t}\n\t\t},\n\t\t[text, attachments, boundConversationId, isSubmitting, client, ws, store],\n\t);\n\n\tconst clearSendError = useCallback(() => setSendError(null), []);\n\n\treturn {\n\t\ttext,\n\t\tsetText,\n\t\tsubmit,\n\t\tisSubmitting,\n\t\tattachments,\n\t\taddFiles,\n\t\tremoveAttachment,\n\t\tsendError,\n\t\tclearSendError,\n\t\temailGateConvId,\n\t};\n}\n\n// ── Helpers ─────────────────────────────────────\n\nfunction fileToBase64(file: File): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst reader = new FileReader();\n\t\treader.onload = () => {\n\t\t\t// result is \"data:<mime>;base64,<data>\" — strip the prefix\n\t\t\tconst result = reader.result as string;\n\t\t\tconst base64 = result.split(\",\")[1];\n\t\t\tif (!base64) return reject(new Error(\"Failed to encode file\"));\n\t\t\tresolve(base64);\n\t\t};\n\t\treader.onerror = () => reject(new Error(\"Failed to read file\"));\n\t\treader.readAsDataURL(file);\n\t});\n}\n","import type { TimelineItem } from \"@helpway/types\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\n/**\n * Conversation list + create new conversation.\n */\nexport function useConversations() {\n\tconst { client, store } = useWidgetContext();\n\tconst conversations = useWidgetStore((s) => s.conversations);\n\tconst setActiveConversation = useWidgetStore((s) => s.setActiveConversation);\n\tconst [isCreating, setIsCreating] = useState(false);\n\n\tconst clientRef = useRef(client);\n\tconst storeRef = useRef(store);\n\n\t// Synced after commit, never during render. Every read of these refs\n\t// happens inside an effect or an async callback, all of which run after\n\t// this one, so the value is always current by the time it is used.\n\tuseEffect(() => {\n\t\tclientRef.current = client;\n\t\tstoreRef.current = store;\n\t});\n\n\tconst create = useCallback(async (text: string) => {\n\t\tsetIsCreating(true);\n\n\t\t// OPTIMISTIC: show the visitor's message + open the conversation view\n\t\t// BEFORE the server roundtrip completes. The conversation gets a temp\n\t\t// id (`temp-<random>`) that's remapped to the server id on success.\n\t\t// Welcome message + any AI reply flow in via the same path the API\n\t\t// returns them — either by replacing the temp conv or via WS.\n\t\tconst tempConversationId = `temp-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n\t\tconst now = new Date().toISOString();\n\t\tconst optimisticMessageId = `optimistic-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n\t\tconst currentVisitorId = storeRef.current.getState().visitor?.id ?? null;\n\n\t\tconst optimisticMsg: TimelineItem = {\n\t\t\tid: optimisticMessageId,\n\t\t\tconversationId: tempConversationId,\n\t\t\torganizationId: \"\",\n\t\t\ttype: \"message\",\n\t\t\tvisibility: \"public\",\n\t\t\ttext,\n\t\t\tparts: null,\n\t\t\tuserId: null,\n\t\t\tvisitorId: currentVisitorId,\n\t\t\taiAgentId: null,\n\t\t\tcreatedAt: now,\n\t\t\teditedAt: null,\n\t\t\tdeletedAt: null,\n\t\t};\n\n\t\t// Flush UI immediately: fake conversation + message + switch view\n\t\tconst store = storeRef.current.getState();\n\t\tstore.addConversation({\n\t\t\tid: tempConversationId,\n\t\t\ttitle: null,\n\t\t\tstatus: \"open\",\n\t\t\tlastMessageText: text,\n\t\t\tlastMessageAt: now,\n\t\t\tlastMessageSenderType: \"visitor\",\n\t\t\tlastMessageSenderName: null,\n\t\t\tlastMessageSenderImage: null,\n\t\t\tassigneeName: null,\n\t\t\tassigneeImage: null,\n\t\t\tunreadCount: 0,\n\t\t});\n\t\tstore.setMessages(tempConversationId, [optimisticMsg]);\n\t\tstore.setActiveConversation(tempConversationId);\n\n\t\ttry {\n\t\t\tconst result = await clientRef.current.widget.createConversation.mutate({ text });\n\t\t\tconst conv = result.conversation;\n\n\t\t\t// Remap temp ID → real ID (rewrites conversations list + messages map + active ref).\n\t\t\t// The optimistic message's id becomes stale (conversationId changed) — replaceMessage\n\t\t\t// with the server-confirmed item.\n\t\t\tstoreRef.current.getState().remapConversationId(tempConversationId, conv.id);\n\t\t\tif (result.item) {\n\t\t\t\tstoreRef.current\n\t\t\t\t\t.getState()\n\t\t\t\t\t.replaceMessage(conv.id, optimisticMessageId, result.item as TimelineItem);\n\t\t\t}\n\t\t\t// Insert welcome message if the agent sent one.\n\t\t\t// The welcome is ALWAYS the very first item in a new conversation, so\n\t\t\t// we place it at index 0 deterministically — never trust createdAt sort,\n\t\t\t// because client-clock (optimistic visitor) vs server-clock (welcome)\n\t\t\t// can be off by enough to re-order the pair. Dedup by id so a WS echo\n\t\t\t// doesn't double-insert.\n\t\t\tif (result.welcomeItem) {\n\t\t\t\tconst welcome = result.welcomeItem as TimelineItem;\n\t\t\t\tconst existing = storeRef.current.getState().messages.get(conv.id) ?? [];\n\t\t\t\tconst withoutWelcome = existing.filter((m) => m.id !== welcome.id);\n\t\t\t\tstoreRef.current.getState().setMessages(conv.id, [welcome, ...withoutWelcome]);\n\t\t\t}\n\t\t\treturn conv;\n\t\t} catch (err) {\n\t\t\t// Roll back: remove the fake conversation + message; let the caller surface the error\n\t\t\tstoreRef.current.getState().removeMessage(tempConversationId, optimisticMessageId);\n\t\t\tconst convs = storeRef.current\n\t\t\t\t.getState()\n\t\t\t\t.conversations.filter((c) => c.id !== tempConversationId);\n\t\t\tstoreRef.current.setState({ conversations: convs, activeConversationId: null });\n\t\t\tthrow err;\n\t\t} finally {\n\t\t\tsetIsCreating(false);\n\t\t}\n\t}, []);\n\n\treturn { conversations, create, isCreating, setActiveConversation };\n}\n","import { useWidgetStore } from \"../provider\";\n\n/**\n * Who the chat header is currently naming, and with which photo.\n *\n * This existed twice: once in `default-widget.tsx` (the chain the header\n * actually renders) and once in `message-list.tsx` (the chain the per-bubble\n * name label compared itself against, to avoid repeating a name the header\n * already shows). The two chains had drifted — the list's copy was missing the\n * `lastMessageSenderName` step — so on an unassigned thread that a teammate had\n * replied to, the header said \"Ali Osman Delişmen\" while the list thought the\n * header said the agent's name. Every one of his messages then printed his name\n * above the bubble AND under it, three times over, next to his name in the\n * header. A suppression rule that reads a different value than the thing it is\n * suppressing against cannot work, so the value now has one home.\n *\n * Resolution order mirrors WidgetLogo's avatar resolution, name and photo\n * decided together:\n * 1. the assigned support user — sticky once a human takes over\n * 2. the last team-side sender — a teammate jumped in without a formal assignment\n * 3. the agent / website name — nobody human is on this thread\n */\nexport function useHeaderIdentity() {\n\tconst activeConvSummary = useWidgetStore((s) => {\n\t\tconst id = s.activeConversationId;\n\t\treturn id ? s.conversations.find((c) => c.id === id) : null;\n\t});\n\tconst agentConfigName = useWidgetStore((s) => s.agentConfig?.name);\n\tconst websiteName = useWidgetStore((s) => s.website?.name);\n\n\t/* Assign someone who has not typed yet and the header must read as that\n\t person, not as whoever spoke last — so the assignee wins. But a bare\n\t `lastMessageSenderName` is not enough on its own: it is also set for\n\t visitor messages, hence the sender-type guard. */\n\tconst teamSender =\n\t\tactiveConvSummary?.lastMessageSenderType === \"team\" && activeConvSummary?.lastMessageSenderName\n\t\t\t? activeConvSummary\n\t\t\t: null;\n\n\tconst humanName = activeConvSummary?.assigneeName ?? teamSender?.lastMessageSenderName ?? null;\n\tconst humanImage = activeConvSummary?.assigneeImage ?? teamSender?.lastMessageSenderImage ?? null;\n\tconst companyName = agentConfigName ?? websiteName ?? \"Support\";\n\n\treturn {\n\t\thumanName,\n\t\thumanImage,\n\t\thasTeamAgent: !!humanName,\n\t\t/** Fallback identity when no human is on the thread — also how the AI signs its answers. */\n\t\tcompanyName,\n\t\t/** Exactly what the header prints. Compare per-bubble name labels against this. */\n\t\theaderName: humanName ?? companyName,\n\t};\n}\n","import { useEffect, useState } from \"react\";\nimport { onLocaleChange, getI18nRevision } from \"@helpway/widget-core\";\n\n/**\n * React hook that triggers re-render when widget translations load or locale changes.\n * Place this in the top-level widget component so all children get fresh t() values.\n *\n * Returns the current i18n revision number (for debugging).\n */\nexport function useI18n(): number {\n\tconst [rev, setRev] = useState(() => getI18nRevision());\n\n\tuseEffect(() => {\n\t\t// Subscribe to locale/translation changes\n\t\treturn onLocaleChange(() => {\n\t\t\tsetRev(getI18nRevision());\n\t\t});\n\t}, []);\n\n\treturn rev;\n}\n","import { useCallback, useRef } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\n/**\n * Typing presence — show \"is typing\" + send own typing status.\n *\n * Debounced: only sends WS event when typing state *changes*.\n * While typing, auto-stops after 3 seconds of inactivity.\n *\n * Usage:\n * ```tsx\n * const { isTyping, setTyping } = usePresence(conversationId)\n * ```\n */\nexport function usePresence(conversationId: string | null) {\n\tconst { ws } = useWidgetContext();\n\tconst isTyping = useWidgetStore((s) =>\n\t\tconversationId ? (s.typingUsers.get(conversationId) ?? false) : false,\n\t);\n\tconst isAiProcessing = useWidgetStore((s) =>\n\t\tconversationId ? (s.aiProcessing.get(conversationId) ?? false) : false,\n\t);\n\tconst typingTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\tconst isSendingTyping = useRef(false);\n\n\tconst setTyping = useCallback(\n\t\t(typing: boolean) => {\n\t\t\tif (!conversationId) return;\n\n\t\t\t// Clear any pending auto-stop\n\t\t\tif (typingTimer.current) clearTimeout(typingTimer.current);\n\n\t\t\tif (typing) {\n\t\t\t\t// Only send \"typing: true\" if we haven't already\n\t\t\t\tif (!isSendingTyping.current) {\n\t\t\t\t\tisSendingTyping.current = true;\n\t\t\t\t\tws.sendTyping(conversationId, true);\n\t\t\t\t}\n\t\t\t\t// Auto-stop after 3 seconds of inactivity\n\t\t\t\ttypingTimer.current = setTimeout(() => {\n\t\t\t\t\tisSendingTyping.current = false;\n\t\t\t\t\tws.sendTyping(conversationId, false);\n\t\t\t\t}, 3000);\n\t\t\t} else {\n\t\t\t\t// Immediately send stop\n\t\t\t\tif (isSendingTyping.current) {\n\t\t\t\t\tisSendingTyping.current = false;\n\t\t\t\t\tws.sendTyping(conversationId, false);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[conversationId, ws],\n\t);\n\n\treturn { isTyping, isAiProcessing, setTyping };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\nimport type { TimelineItem } from \"@helpway/types\";\n\nconst EMPTY_ITEMS: TimelineItem[] = [];\n\n/**\n * Timeline items for a conversation + real-time updates.\n */\nexport function useTimeline(conversationId: string | null) {\n\tconst { client, store } = useWidgetContext();\n\tconst messages = useWidgetStore((s) =>\n\t\tconversationId ? s.messages.get(conversationId) ?? EMPTY_ITEMS : EMPTY_ITEMS,\n\t);\n\tconst [isLoading, setIsLoading] = useState(false);\n\tconst [hasMore, setHasMore] = useState(false);\n\tconst cursorRef = useRef<string | undefined>(undefined);\n\n\t// Stable refs to avoid effect re-triggers\n\tconst clientRef = useRef(client);\n\tconst storeRef = useRef(store);\n\n\t// Synced after commit, never during render. Every read of these refs\n\t// happens inside an effect or an async callback, all of which run after\n\t// this one, so the value is always current by the time it is used.\n\tuseEffect(() => {\n\t\tclientRef.current = client;\n\t\tstoreRef.current = store;\n\t});\n\n\t// Load initial timeline when conversation changes\n\tuseEffect(() => {\n\t\tif (!conversationId) return;\n\n\t\t// Skip server fetch for optimistic temp IDs — they don't exist server-side.\n\t\t// useConversations.create() owns the seed for these; once remap fires this\n\t\t// effect re-runs with the real id and the fetch happens then.\n\t\tif (conversationId.startsWith(\"temp-\")) return;\n\n\t\tlet cancelled = false;\n\n\t\t// If createConversation already seeded the messages store (welcome + first\n\t\t// visitor message), the server has nothing new to tell us — skip the fetch.\n\t\t// Overwriting the seed with the server payload causes a full array-identity\n\t\t// flip, a brief key-swap for the optimistic→server id transition, and\n\t\t// restarts CSS enter animations — the \"mesajlar gidip tekrar geliyor\" flash.\n\t\t// New items still flow in via WS.addMessage, which dedupes by id.\n\t\tconst existingMessages = storeRef.current.getState().messages.get(conversationId);\n\t\tconst hasSeed = !!existingMessages && existingMessages.length > 0;\n\t\tif (hasSeed) {\n\t\t\tstoreRef.current.getState().clearUnread(conversationId);\n\t\t\tclientRef.current.widget.markSeen\n\t\t\t\t.mutate({ conversationId })\n\t\t\t\t.catch(() => {});\n\t\t\treturn () => {\n\t\t\t\tcancelled = true;\n\t\t\t};\n\t\t}\n\n\t\tsetIsLoading(true);\n\t\tasync function load() {\n\t\t\ttry {\n\t\t\t\tconst data = await clientRef.current.widget.getTimeline.query({\n\t\t\t\t\tconversationId: conversationId!,\n\t\t\t\t\tlimit: 50,\n\t\t\t\t});\n\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\t// Only overwrite if API returned items — don't wipe seed messages with empty response\n\t\t\t\tif (data.items.length > 0) {\n\t\t\t\t\tstoreRef.current.getState().setMessages(conversationId!, data.items as TimelineItem[]);\n\t\t\t\t}\n\t\t\t\tsetHasMore(data.hasMore);\n\t\t\t\tcursorRef.current = data.nextCursor ?? undefined;\n\n\t\t\t\t// Mark as seen + clear local unread count\n\t\t\t\tstoreRef.current.getState().clearUnread(conversationId!);\n\t\t\t\tclientRef.current.widget.markSeen.mutate({ conversationId: conversationId! }).catch(() => {});\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useTimeline] Failed to load:\", err);\n\t\t\t} finally {\n\t\t\t\tif (!cancelled) setIsLoading(false);\n\t\t\t}\n\t\t}\n\n\t\tload();\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, [conversationId]); // Only re-run when conversationId changes\n\n\tconst loadMore = useCallback(async () => {\n\t\tif (!conversationId || !hasMore || isLoading) return;\n\n\t\tsetIsLoading(true);\n\t\ttry {\n\t\t\tconst data = await clientRef.current.widget.getTimeline.query({\n\t\t\t\tconversationId,\n\t\t\t\tcursor: cursorRef.current,\n\t\t\t\tlimit: 50,\n\t\t\t});\n\n\t\t\tconst existing = storeRef.current.getState().messages.get(conversationId) ?? [];\n\t\t\tstoreRef.current.getState().setMessages(conversationId, [...data.items as TimelineItem[], ...existing]);\n\t\t\tsetHasMore(data.hasMore);\n\t\t\tcursorRef.current = data.nextCursor ?? undefined;\n\t\t} finally {\n\t\t\tsetIsLoading(false);\n\t\t}\n\t}, [conversationId, hasMore, isLoading]);\n\n\treturn { items: messages, isLoading, hasMore, loadMore };\n}\n","import { useWidgetStore } from \"../provider\";\n\n/**\n * Total unread count across all conversations.\n *\n * Usage:\n * ```tsx\n * const { totalUnread } = useUnread()\n * ```\n */\nexport function useUnread() {\n\tconst totalUnread = useWidgetStore((s) =>\n\t\ts.conversations.reduce((sum, c) => sum + c.unreadCount, 0),\n\t);\n\n\treturn { totalUnread };\n}\n","import { useWidgetContext, useWidgetStore } from \"../provider\";\n\n/**\n * Core widget state — connection status, visitor identity, website info.\n *\n * Usage:\n * ```tsx\n * const { isReady, visitor, website, identify } = useWidget()\n * ```\n */\nexport function useWidget() {\n\tconst { client } = useWidgetContext();\n\tconst isReady = useWidgetStore((s) => s.isReady);\n\tconst isConnecting = useWidgetStore((s) => s.isConnecting);\n\tconst visitor = useWidgetStore((s) => s.visitor);\n\tconst website = useWidgetStore((s) => s.website);\n\tconst agentConfig = useWidgetStore((s) => s.agentConfig);\n\n\tasync function identify(data: {\n\t\texternalId: string;\n\t\temail?: string;\n\t\tname?: string;\n\t\timage?: string;\n\t\tmetadata?: Record<string, unknown>;\n\t}) {\n\t\treturn client.widget.identify.mutate(data);\n\t}\n\n\treturn { isReady, isConnecting, visitor, website, agentConfig, identify };\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport { t } from \"@helpway/widget-core\";\nimport { ACCEPTED_TYPES, type PendingAttachment } from \"../hooks/use-composer\";\nimport { SendIcon, PaperclipIcon, XIcon } from \"./icons\";\n\nconst MAX_CHARS = 5000;\nconst CHAR_WARN_THRESHOLD = 4800;\n\n\ninterface ComposerProps {\n\ttext: string;\n\tonTextChange: (text: string) => void;\n\tonSubmit: () => void;\n\tonTyping?: (isTyping: boolean) => void;\n\tisSubmitting?: boolean;\n\tplaceholder?: string;\n\t/** Compact mode — single-line input without footer row */\n\tcompact?: boolean;\n\t/** Pending attachments to preview */\n\tattachments?: PendingAttachment[];\n\t/** Called when files are added (paste, drop, or file picker) */\n\tonAddFiles?: (files: File[]) => void;\n\t/** Called to remove a pending attachment */\n\tonRemoveAttachment?: (id: string) => void;\n\t/** Disable entire composer (e.g. email required before sending) */\n\tdisabled?: boolean;\n}\n\n/** Widget composer — auto-resize, Enter-to-send, paste/drop attachments */\nexport function Composer({\n\ttext,\n\tonTextChange,\n\tonSubmit,\n\tonTyping,\n\tisSubmitting,\n\tplaceholder,\n\tcompact,\n\tattachments,\n\tonAddFiles,\n\tonRemoveAttachment,\n\tdisabled,\n}: ComposerProps) {\n\tconst ref = useRef<HTMLTextAreaElement>(null);\n\tconst fileInputRef = useRef<HTMLInputElement>(null);\n\n\t// Feature-detect once per mount. CSS.supports is cheap but doing it\n\t// inside handleChange would run on every keystroke.\n\tconst supportsFieldSizing = useRef(\n\t\ttypeof CSS !== \"undefined\" && CSS.supports?.(\"field-sizing\", \"content\"),\n\t);\n\n\tconst handleKeyDown = useCallback(\n\t\t(e: React.KeyboardEvent) => {\n\t\t\tif (e.key === \"Enter\" && !e.shiftKey) {\n\t\t\t\te.preventDefault();\n\t\t\t\tonSubmit();\n\t\t\t}\n\t\t},\n\t\t[onSubmit],\n\t);\n\n\tconst handleChange = useCallback(\n\t\t(e: React.ChangeEvent<HTMLTextAreaElement>) => {\n\t\t\tconst value = e.target.value;\n\t\t\tif (value.length > MAX_CHARS) return; // Hard cap\n\t\t\tonTextChange(value);\n\t\t\tonTyping?.(value.length > 0);\n\n\t\t\t// Auto-resize fallback for engines without `field-sizing: content`\n\t\t\t// (Safari <17.4, Firefox <132, Chrome <123). Modern browsers handle\n\t\t\t// the resize in CSS — running this on every keystroke would force\n\t\t\t// a redundant reflow and briefly snap the textarea to min-height\n\t\t\t// before the new height is applied. Kept in sync with the 220px\n\t\t\t// max-height on .hw-composer-input.\n\t\t\tif (!supportsFieldSizing.current) {\n\t\t\t\tconst el = ref.current;\n\t\t\t\tif (el) {\n\t\t\t\t\tel.style.height = \"auto\";\n\t\t\t\t\tel.style.height = `${Math.min(el.scrollHeight, 220)}px`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[onTextChange, onTyping],\n\t);\n\n\t// ── Clipboard paste ──────────────────────────\n\tconst handlePaste = useCallback(\n\t\t(e: React.ClipboardEvent) => {\n\t\t\tif (!onAddFiles) return;\n\t\t\tconst files = extractFiles(e.clipboardData);\n\t\t\tif (files.length > 0) {\n\t\t\t\te.preventDefault();\n\t\t\t\tonAddFiles(files);\n\t\t\t}\n\t\t},\n\t\t[onAddFiles],\n\t);\n\n\t// ── Drag & drop ──────────────────────────────\n\tconst [isDragging, setIsDragging] = useState(false);\n\tconst dragCountRef = useRef(0);\n\n\tconst handleDragEnter = useCallback((e: React.DragEvent) => {\n\t\te.preventDefault();\n\t\tdragCountRef.current++;\n\t\tif (dragCountRef.current === 1) setIsDragging(true);\n\t}, []);\n\n\tconst handleDragLeave = useCallback((e: React.DragEvent) => {\n\t\te.preventDefault();\n\t\tdragCountRef.current--;\n\t\tif (dragCountRef.current === 0) setIsDragging(false);\n\t}, []);\n\n\tconst handleDragOver = useCallback((e: React.DragEvent) => {\n\t\te.preventDefault();\n\t\te.dataTransfer.dropEffect = \"copy\";\n\t}, []);\n\n\tconst handleDrop = useCallback(\n\t\t(e: React.DragEvent) => {\n\t\t\te.preventDefault();\n\t\t\tdragCountRef.current = 0;\n\t\t\tsetIsDragging(false);\n\t\t\tif (!onAddFiles) return;\n\t\t\tconst files = extractFiles(e.dataTransfer);\n\t\t\tif (files.length > 0) onAddFiles(files);\n\t\t},\n\t\t[onAddFiles],\n\t);\n\n\t// ── File picker ──────────────────────────────\n\tconst handleFileClick = useCallback(() => {\n\t\tfileInputRef.current?.click();\n\t}, []);\n\n\tconst handleFileChange = useCallback(\n\t\t(e: React.ChangeEvent<HTMLInputElement>) => {\n\t\t\tif (!onAddFiles || !e.target.files) return;\n\t\t\tonAddFiles(Array.from(e.target.files));\n\t\t\te.target.value = \"\"; // reset so same file can be picked again\n\t\t},\n\t\t[onAddFiles],\n\t);\n\n\tconst hasText = text.trim().length > 0;\n\tconst hasAttachments = attachments && attachments.some((a) => a.part !== null);\n\tconst stillUploading = attachments?.some((a) => a.isUploading) ?? false;\n\t// Button stays clickable whenever there's *something* to send — the\n\t// actual text-required guard lives in `useComposer.submit` and\n\t// surfaces as an inline error if the visitor tries to send an\n\t// attachment without a caption. Feels less sticky than a disabled\n\t// arrow the user can't interpret.\n\tconst canSend = (hasText || hasAttachments) && !stillUploading;\n\tconst showCharCount = text.length >= CHAR_WARN_THRESHOLD;\n\tconst isOverLimit = text.length > MAX_CHARS;\n\n\treturn (\n\t\t<div\n\t\t\tclassName={`hw-composer ${compact ? \"hw-composer--compact\" : \"\"} ${isDragging ? \"hw-composer--dragging\" : \"\"}`}\n\t\t\tonDragEnter={handleDragEnter}\n\t\t\tonDragLeave={handleDragLeave}\n\t\t\tonDragOver={handleDragOver}\n\t\t\tonDrop={handleDrop}\n\t\t>\n\t\t\t<div className=\"hw-composer-box\" style={{ position: \"relative\" }}>\n\t\t\t\t{/* Drag overlay */}\n\t\t\t\t{isDragging && (\n\t\t\t\t\t<div className=\"hw-composer-drop-overlay\">\n\t\t\t\t\t\t<span className=\"hw-composer-drop-text\">{t(\"widget.drop_files\")}</span>\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t{/* Attachment previews */}\n\t\t\t\t{attachments && attachments.length > 0 && (\n\t\t\t\t\t<div className=\"hw-composer-previews\">\n\t\t\t\t\t\t{attachments.map((a) => (\n\t\t\t\t\t\t\t<PreviewThumb\n\t\t\t\t\t\t\t\tkey={a.id}\n\t\t\t\t\t\t\t\tattachment={a}\n\t\t\t\t\t\t\t\tonRemove={onRemoveAttachment ? () => onRemoveAttachment(a.id) : undefined}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t<textarea\n\t\t\t\t\tref={ref}\n\t\t\t\t\tclassName=\"hw-composer-input\"\n\t\t\t\t\tvalue={text}\n\t\t\t\t\tonChange={handleChange}\n\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\tonPaste={handlePaste}\n\t\t\t\t\tplaceholder={placeholder ?? t(\"widget.placeholder\")}\n\t\t\t\t\trows={1}\n\t\t\t\t\tdisabled={disabled || isSubmitting}\n\t\t\t\t\taria-label={t(\"widget.aria_input\")}\n\t\t\t\t/>\n\t\t\t\t<div className=\"hw-composer-toolbar\">\n\t\t\t\t\t<div className=\"hw-composer-toolbar-left\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"hw-composer-attach\"\n\t\t\t\t\t\t\tonClick={handleFileClick}\n\t\t\t\t\t\t\tdisabled={disabled || isSubmitting}\n\t\t\t\t\t\t\taria-label={t(\"widget.aria_attach\")}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<PaperclipIcon />\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\tref={fileInputRef}\n\t\t\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t\t\taccept={ACCEPTED_TYPES}\n\t\t\t\t\t\t\tmultiple\n\t\t\t\t\t\t\thidden\n\t\t\t\t\t\t\tonChange={handleFileChange}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{showCharCount && (\n\t\t\t\t\t\t\t<span className={`hw-composer-charcount ${isOverLimit ? \"hw-composer-charcount--over\" : \"\"}`}>\n\t\t\t\t\t\t\t\t{MAX_CHARS - text.length}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName={`hw-composer-send ${canSend && !isOverLimit && !disabled ? \"hw-composer-send--active\" : \"hw-composer-send--inactive\"}`}\n\t\t\t\t\t\tonClick={() => onSubmit()}\n\t\t\t\t\t\tdisabled={disabled || !canSend || isSubmitting || isOverLimit}\n\t\t\t\t\t\taria-label={t(\"widget.aria_send\")}\n\t\t\t\t\t>\n\t\t\t\t\t\t<SendIcon />\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ── Preview thumbnail with hover ─────────────────\n\n/**\n * The thumbnail for a file staged in the composer.\n *\n * Deliberately has no hover popover. Sent attachments get one — peeking at an\n * image someone else posted is worth a 260px card. Here the visitor picked the\n * file a second ago; the card only threw a white rectangle across the page they\n * were reading, anchored to a 48px square they were about to type past.\n */\nexport function PreviewThumb({ attachment: a, onRemove }: { attachment: PendingAttachment; onRemove?: () => void }) {\n\treturn (\n\t\t<div className={`hw-composer-preview ${a.error ? \"hw-composer-preview--error\" : \"\"}`}>\n\t\t\t{a.previewUrl ? (\n\t\t\t\t<img src={a.previewUrl} alt={a.file.name} className=\"hw-composer-preview-img\" />\n\t\t\t) : (\n\t\t\t\t<div className=\"hw-composer-preview-file\">\n\t\t\t\t\t<span className=\"hw-composer-preview-ext\">\n\t\t\t\t\t\t{a.file.name.split(\".\").pop()?.toUpperCase() ?? \"FILE\"}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t{a.isUploading && <div className=\"hw-composer-preview-loader\" />}\n\t\t\t{a.error && <div className=\"hw-composer-preview-badge\" title={a.error}>!</div>}\n\t\t\t{onRemove && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"hw-composer-preview-remove\"\n\t\t\t\t\tonClick={onRemove}\n\t\t\t\t\taria-label={t(\"widget.aria_remove\")}\n\t\t\t\t>\n\t\t\t\t\t<XIcon />\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// ── Helpers ──────────────────────────────────────\n\nfunction extractFiles(data: DataTransfer): File[] {\n\tconst files: File[] = [];\n\tif (data.files) {\n\t\tfor (let i = 0; i < data.files.length; i++) {\n\t\t\tconst file = data.files[i];\n\t\t\tif (file) files.push(file);\n\t\t}\n\t}\n\treturn files;\n}\n","// AUTO-GENERATED — DO NOT EDIT.\n// Run `bun scripts/sync-icons.ts` to regenerate from\n// @central-icons-react/round-outlined-radius-2-stroke-2 (devDep, not shipped).\n//\n// To add or rename an icon: edit MANIFEST in scripts/sync-icons.ts, re-run.\n\nimport type { SVGProps } from \"react\";\n\ntype IconProps = SVGProps<SVGSVGElement> & { size?: number | string };\n\n// IconBubble2\nexport function MessageIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M5.00195 4H19.002C20.1065 4 21.002 4.89543 21.002 6V16C21.002 17.1046 20.1065 18 19.002 18H12.002L7.00195 21V18H5.00195C3.89738 18 3.00195 17.1046 3.00195 16V6C3.00195 4.89543 3.89738 4 5.00195 4Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"square\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconCrossMedium\nexport function XIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M6.5 6.5L17.5 17.5M17.5 6.5L6.5 17.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconArrowLeft\nexport function ArrowLeftIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M10 6L4 12L10 18\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t\t<path d=\"M5 12H20\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconChevronRight\nexport function ChevronRightIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M9 4L15.5858 10.5858C16.3668 11.3668 16.3668 12.6331 15.5858 13.4142L9 20\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconSparklesSoft\nexport function SparklesIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M19 13C14.0987 13.4243 11.4243 16.0987 11 21C10.5578 16.0225 7.89737 13.5547 3 13C7.97478 12.4262 10.4262 9.97478 11 5C11.5547 9.89737 14.0225 12.5578 19 13Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t\t<path d=\"M18.8864 2.34512C18.8642 2.14869 18.6981 2.0002 18.5004 2C18.3027 1.9998 18.1363 2.14794 18.1137 2.34433C18.0082 3.25861 17.7367 3.88584 17.3113 4.31127C16.8858 4.7367 16.2586 5.00822 15.3443 5.11367C15.1479 5.13632 14.9998 5.30271 15 5.5004C15.0002 5.69809 15.1487 5.86417 15.3451 5.88642C16.2439 5.98823 16.8855 6.25969 17.3217 6.68804C17.7556 7.11407 18.0322 7.74041 18.1126 8.64552C18.1305 8.84634 18.2988 9.00023 18.5004 9C18.702 8.99977 18.8701 8.84551 18.8874 8.64465C18.9645 7.75483 19.2409 7.11438 19.6776 6.67764C20.1144 6.24091 20.7548 5.96446 21.6446 5.88744C21.8455 5.87005 21.9998 5.70205 22 5.50044C22.0002 5.29883 21.8463 5.13048 21.6455 5.11264C20.7404 5.03224 20.1141 4.75557 19.688 4.3217C19.2597 3.88545 18.9882 3.24394 18.8864 2.34512Z\" fill=\"currentColor\" />\n\t\t</svg>\n\t);\n}\n\n// IconPaperPlaneTopRight\nexport function SendIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M9.61946 10.8613L20.9997 4.55422M9.04735 10.9043L4.10061 5.68812C3.49632 5.05091 3.94803 4 4.82621 4H20.2513C21.0247 4 21.5054 4.84039 21.1132 5.50702L13.1902 18.9762C12.7433 19.7358 11.6035 19.5879 11.3654 18.7393L9.28458 11.3223C9.24066 11.1658 9.15923 11.0223 9.04735 10.9043Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconPaperclip1\nexport function PaperclipIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M6 11V15C6 18.3137 8.68629 21 12 21C15.3137 21 18 18.3137 18 15V7C18 4.79086 16.2091 3 14 3C11.7909 3 10 4.79086 10 7V15C10 16.1046 10.8954 17 12 17C13.1046 17 14 16.1046 14 15V7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconArrowUp\nexport function ArrowUpIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M12 5V20\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t\t<path d=\"M6 10L12 4L18 10\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconHome\nexport function HomeIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M4 9.77313C4 9.2136 4 8.93383 4.07063 8.67517C4.1332 8.446 4.23609 8.22982 4.3745 8.03675C4.53071 7.81882 4.74784 7.6424 5.1821 7.28957L9.9821 3.38956C10.7014 2.80513 11.0611 2.51291 11.4609 2.40099C11.8135 2.30229 12.1865 2.30229 12.5391 2.40099C12.9389 2.51291 13.2986 2.80513 14.0179 3.38957L18.8179 7.28957C19.2522 7.6424 19.4693 7.81882 19.6255 8.03675C19.7639 8.22982 19.8668 8.446 19.9294 8.67517C20 8.93383 20 9.2136 20 9.77313V16.8C20 17.9201 20 18.4802 19.782 18.908C19.5903 19.2843 19.2843 19.5903 18.908 19.782C18.4802 20 17.9201 20 16.8 20H7.2C6.07989 20 5.51984 20 5.09202 19.782C4.71569 19.5903 4.40973 19.2843 4.21799 18.908C4 18.4802 4 17.9201 4 16.8V9.77313Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconBubbleDots\nexport function MessagesIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M4.00195 6.00003C4.00195 4.89546 4.89738 4.00003 6.00195 4.00002L18.0019 4C19.1065 4 20.002 4.89543 20.002 6V16.0358C20.002 17.1403 19.1065 18.0358 18.002 18.0358L15.3757 18.0358C15.1427 18.0358 14.9171 18.1171 14.7377 18.2657L11.9977 20.5358L9.29398 18.2694C9.11393 18.1185 8.8865 18.0358 8.65157 18.0358H6.00195C4.89738 18.0358 4.00195 17.1403 4.00195 16.0358V6.00003Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinejoin=\"round\" />\n\t\t\t<path d=\"M6.875 11.25C6.875 11.7332 7.26675 12.125 7.75 12.125C8.23325 12.125 8.625 11.7332 8.625 11.25C8.625 10.7668 8.23325 10.375 7.75 10.375C7.26675 10.375 6.875 10.7668 6.875 11.25ZM11.125 11.25C11.125 11.7332 11.5168 12.125 12 12.125C12.4832 12.125 12.875 11.7332 12.875 11.25C12.875 10.7668 12.4832 10.375 12 10.375C11.5168 10.375 11.125 10.7668 11.125 11.25ZM15.375 11.25C15.375 11.7332 15.7668 12.125 16.25 12.125C16.7332 12.125 17.125 11.7332 17.125 11.25C17.125 10.7668 16.7332 10.375 16.25 10.375C15.7668 10.375 15.375 10.7668 15.375 11.25Z\" fill=\"currentColor\" stroke=\"currentColor\" strokeWidth=\"0.75\" strokeLinecap=\"square\" />\n\t\t</svg>\n\t);\n}\n\n// IconMagnifyingGlass\nexport function SearchIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M11 18C14.866 18 18 14.866 18 11C18 7.13401 14.866 4 11 4C7.13401 4 4 7.13401 4 11C4 14.866 7.13401 18 11 18Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n\t\t\t<path d=\"M20 20L16.05 16.05\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconBubblePlus\nexport function NewChatIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M11.9998 8L11.9998 11M11.9998 11V14M11.9998 11H8.99976M11.9998 11H14.9998M11.9977 20.5358L14.7377 18.2657C14.9171 18.1171 15.1427 18.0358 15.3757 18.0358L18.002 18.0358C19.1065 18.0357 20.002 17.1403 20.002 16.0358V6C20.002 4.89543 19.1065 4 18.0019 4L6.00195 4.00002C4.89738 4.00002 4.00195 4.89545 4.00195 6.00002V16.0358C4.00195 17.1403 4.89738 18.0358 6.00195 18.0358H8.65157C8.8865 18.0358 9.11393 18.1185 9.29398 18.2694L11.9977 20.5358Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconAppleIntelligence\nexport function BotIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path fillRule=\"evenodd\" clipRule=\"evenodd\" d=\"M9.67904 3.29155C10.7467 1.56948 13.2537 1.56948 14.3214 3.29155L15.1308 4.59707C15.2462 4.7833 15.3634 4.9684 15.4823 5.15233C15.7005 5.1305 15.9185 5.10662 16.1363 5.08068L17.6626 4.89893C19.6747 4.65934 21.2396 6.61723 20.5571 8.52637L20.0401 9.97255C19.9664 10.1786 19.8947 10.3854 19.825 10.5927C19.9779 10.7493 20.1323 10.9045 20.2882 11.0583L21.3821 12.1371C22.8256 13.5609 22.2668 16.0039 20.3491 16.6605L18.895 17.1584C18.6876 17.2294 18.4809 17.3023 18.275 17.3772C18.2478 17.5943 18.2226 17.8117 18.1995 18.0294L18.0372 19.5565C17.823 21.572 15.5635 22.6577 13.8546 21.5695L12.5584 20.7442C12.3734 20.6264 12.1873 20.5103 12.0002 20.3961C11.8131 20.5103 11.627 20.6264 11.442 20.7442L10.1458 21.5695C8.4369 22.6577 6.17739 21.572 5.96321 19.5565L5.80094 18.0294C5.7778 17.8117 5.75263 17.5943 5.72541 17.3772C5.51949 17.3023 5.31282 17.2294 5.10542 17.1584L3.65133 16.6605C1.7336 16.0039 1.17475 13.5609 2.61829 12.1371L3.71216 11.0583C3.86807 10.9045 4.0225 10.7493 4.17541 10.5927C4.10567 10.3854 4.03395 10.1786 3.96028 9.97255L3.44329 8.52637C2.7608 6.61723 4.32567 4.65934 6.33777 4.89893L7.86408 5.08068C8.08191 5.10662 8.29993 5.1305 8.5181 5.15233C8.63698 4.9684 8.75417 4.7833 8.86963 4.59707L9.67904 3.29155ZM7.61407 6.4827L6.16966 6.31071C5.20357 6.19567 4.45578 7.13505 4.78207 8.04778L5.2716 9.41715C6.10452 8.48167 6.88648 7.5021 7.61407 6.4827ZM5.78854 10.961C7.04552 9.61105 8.19784 8.16742 9.23549 6.64268C11.076 6.78287 12.9244 6.78287 14.7649 6.64268C15.8026 8.16743 16.9549 9.61105 18.2119 10.961C17.6657 12.722 17.2545 14.522 16.9818 16.3454C15.2628 17.0169 13.5974 17.8181 12.0002 18.7422C10.403 17.8181 8.73761 17.0169 7.01863 16.3454C6.74592 14.522 6.3347 12.722 5.78854 10.961ZM4.65269 12.1275L3.61666 13.1494C2.92581 13.8308 3.19234 15.0006 4.11188 15.3154L5.48873 15.7868C5.27593 14.553 4.99684 13.3315 4.65269 12.1275ZM7.22343 17.9611L7.377 19.4062C7.47946 20.3704 8.56185 20.8926 9.38218 20.3703L10.6083 19.5895C9.51004 18.9865 8.38012 18.4429 7.22343 17.9611ZM13.3921 19.5895L14.6182 20.3703C15.4385 20.8926 16.5209 20.3704 16.6234 19.4062L16.777 17.9611C15.6203 18.4429 14.4903 18.9865 13.3921 19.5895ZM18.5117 15.7868L19.8885 15.3154C20.8081 15.0006 21.0746 13.8308 20.3837 13.1494L19.3477 12.1275C19.0035 13.3315 18.7245 14.553 18.5117 15.7868ZM18.7288 9.41715L19.2183 8.04778C19.5446 7.13505 18.7968 6.19567 17.8307 6.31071L16.3863 6.4827C17.1139 7.5021 17.8959 8.48167 18.7288 9.41715ZM13.8786 5.2756C12.6272 5.3429 11.3731 5.3429 10.1218 5.2756L10.8874 4.04072C11.3991 3.21542 12.6013 3.21542 13.113 4.04072L13.8786 5.2756Z\" fill=\"currentColor\" />\n\t\t</svg>\n\t);\n}\n\n// IconBook\nexport function BookIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M9 6C8.44772 6 8 6.44772 8 7C8 7.55228 8.44772 8 9 8V6ZM15 8C15.5523 8 16 7.55228 16 7C16 6.44772 15.5523 6 15 6V8ZM9 10C8.44772 10 8 10.4477 8 11C8 11.5523 8.44772 12 9 12V10ZM12 12C12.5523 12 13 11.5523 13 11C13 10.4477 12.5523 10 12 10V12ZM7 4H17V2H7V4ZM18 5V19H20V5H18ZM17 20H7V22H17V20ZM6 19V5H4V19H6ZM7 20C6.44771 20 6 19.5523 6 19H4C4 20.6569 5.34315 22 7 22V20ZM18 19C18 19.5523 17.5523 20 17 20V22C18.6569 22 20 20.6569 20 19H18ZM17 4C17.5523 4 18 4.44772 18 5H20C20 3.34315 18.6569 2 17 2V4ZM7 2C5.34315 2 4 3.34315 4 5H6C6 4.44772 6.44772 4 7 4V2ZM18 12V15H20V12H18ZM17 16H7V18H17V16ZM7 22H10V20H7V22ZM7 16C5.34315 16 4 17.3431 4 19H6C6 18.4477 6.44772 18 7 18V16ZM18 15C18 15.5523 17.5523 16 17 16V18C18.6569 18 20 16.6569 20 15H18ZM9 8H15V6H9V8ZM9 12H12V10H9V12Z\" fill=\"currentColor\" />\n\t\t</svg>\n\t);\n}\n\n// IconMegaphone\nexport function MegaphoneIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M17.9961 14.0001C19.6529 14.0001 20.9961 12.657 20.9961 11.0001C20.9961 9.34325 19.6529 8.0001 17.9961 8.0001M12.8254 18.0001C12.4136 19.1653 11.3023 20.0001 9.99609 20.0001C8.33924 20.0001 6.99609 18.657 6.99609 17.0001V15.5001M6.99829 6.5001V15.5001M17.9961 5.73752V16.2627C17.9961 17.617 16.6784 18.5797 15.3882 18.1681L4.38819 14.6585C3.55899 14.394 2.99609 13.6235 2.99609 12.7532V9.24704C2.99609 8.37667 3.55899 7.60622 4.38819 7.34167L15.3882 3.83215C16.6784 3.42051 17.9961 4.38325 17.9961 5.73752Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconLightBulb\nexport function LightbulbIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M10 21H14M15.6076 15C17.6404 13.7751 19 11.5463 19 9C19 5.13401 15.866 2 12 2C8.13401 2 5 5.13401 5 9C5 11.5463 6.35958 13.7751 8.39241 15M15.6076 15C15.4111 15.1184 15.2084 15.2274 15 15.3264V17C15 17.5523 14.5523 18 14 18H10C9.44772 18 9 17.5523 9 17V15.3264C8.7916 15.2274 8.58886 15.1184 8.39241 15M15.6076 15H8.39241\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconCircleQuestionmark\nexport function HelpCircleIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t\t<path d=\"M12 16V16.01\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n\t\t\t<path d=\"M12 13C12 11.3608 14 11.9319 14 10C14 8.89543 13.1046 8 12 8C11.2597 8 10.6134 8.4022 10.2676 9\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconNewspaper\nexport function NewspaperIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M16 12V6C16 4.89543 15.1046 4 14 4H5C3.89543 4 3 4.89543 3 6V17.5C3 18.8807 4.11929 20 5.5 20H18.5M16 12V17.5C16 18.8807 17.1193 20 18.5 20M16 12H19C20.1046 12 21 12.8954 21 14V17.5C21 18.8807 19.8807 20 18.5 20M7 16H12M7 8H12V12H7V8Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconStar\nexport function StarIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M11.5288 2.29524C11.7179 1.90159 12.2821 1.90159 12.4712 2.29524L14.9458 7.44648C15.0219 7.60491 15.1735 7.71434 15.3487 7.73728L21.0456 8.4832C21.4809 8.5402 21.6552 9.07312 21.3368 9.37342L17.1693 13.303C17.0412 13.4238 16.9832 13.6009 17.0154 13.7735L18.0616 19.3857C18.1416 19.8146 17.6852 20.144 17.2993 19.9359L12.249 17.2133C12.0937 17.1296 11.9063 17.1296 11.751 17.2133L6.70073 19.9359C6.3148 20.144 5.85841 19.8146 5.93837 19.3857L6.98459 13.7735C7.01677 13.6009 6.95885 13.4238 6.83068 13.303L2.66324 9.37342C2.34476 9.07312 2.51909 8.5402 2.95444 8.4832L8.65127 7.73728C8.82648 7.71434 8.97811 7.60491 9.05422 7.44648L11.5288 2.29524Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n/**\n * Conversation options. Not in the Central Icons snapshot — three dots on\n * the same 24 grid, filled to match the set's solid glyphs.\n */\nexport function DotsIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={size}\n\t\t\theight={size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\taria-hidden=\"true\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<circle cx=\"5\" cy=\"12\" r=\"1.7\" fill=\"currentColor\" />\n\t\t\t<circle cx=\"12\" cy=\"12\" r=\"1.7\" fill=\"currentColor\" />\n\t\t\t<circle cx=\"19\" cy=\"12\" r=\"1.7\" fill=\"currentColor\" />\n\t\t</svg>\n\t);\n}\n\n/** A person, for the hand-off-to-a-human offer. Same 24 grid as the set. */\nexport function PersonIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={size}\n\t\t\theight={size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\taria-hidden=\"true\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path\n\t\t\t\td=\"M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2\"\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t/>\n\t\t\t<circle cx=\"12\" cy=\"7\" r=\"4\" stroke=\"currentColor\" strokeWidth=\"2\" />\n\t\t</svg>\n\t);\n}\n","import type { TimelineItem } from \"@helpway/types\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\ninterface DebugEvent {\n\tid: string;\n\tt: number;\n\tkind: \"trpc\" | \"ws\" | \"store\" | \"error\";\n\tlabel: string;\n\tdetail?: string;\n}\n\nconst MAX_EVENTS = 60;\n\nfunction isDebugEnabled(): boolean {\n\tif (typeof window === \"undefined\") return false;\n\tif (typeof window.localStorage !== \"undefined\" && window.localStorage.getItem(\"hw:debug\") === \"1\") {\n\t\treturn true;\n\t}\n\tconst search = window.location?.search ?? \"\";\n\treturn search.includes(\"hwdebug=1\") || search.includes(\"debug=hw\");\n}\n\nfunction senderOf(item: TimelineItem): string {\n\tif (item.visitorId) return \"visitor\";\n\tif (item.aiAgentId) return \"ai\";\n\tif (item.userId) return \"team\";\n\treturn item.type;\n}\n\nexport function WidgetDebugOverlay() {\n\tconst [enabled, setEnabled] = useState(false);\n\tconst [open, setOpen] = useState(true);\n\tconst [events, setEvents] = useState<DebugEvent[]>([]);\n\tconst eventsRef = useRef<DebugEvent[]>([]);\n\n\t// Subscribe to each field individually — returning a fresh object from a\n\t// selector triggers an infinite re-render loop with zustand because each\n\t// render produces a new object reference.\n\tconst activeId = useWidgetStore((s) => s.activeConversationId);\n\tconst messagesMap = useWidgetStore((s) => s.messages);\n\tconst typingUsers = useWidgetStore((s) => s.typingUsers);\n\tconst aiProcessingMap = useWidgetStore((s) => s.aiProcessing);\n\tconst { store } = useWidgetContext();\n\n\tuseEffect(() => {\n\t\tsetEnabled(isDebugEnabled());\n\t}, []);\n\n\tconst pushEvent = useMemo(\n\t\t() => (ev: Omit<DebugEvent, \"id\" | \"t\">) => {\n\t\t\tconst e: DebugEvent = {\n\t\t\t\t...ev,\n\t\t\t\tid: `${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n\t\t\t\tt: Date.now(),\n\t\t\t};\n\t\t\teventsRef.current = [e, ...eventsRef.current].slice(0, MAX_EVENTS);\n\t\t\tsetEvents(eventsRef.current);\n\t\t},\n\t\t[],\n\t);\n\n\t// Intercept fetch to log tRPC calls — works with any tRPC proxy shape\n\t// because we observe at the network boundary, not the client object.\n\tuseEffect(() => {\n\t\tif (!enabled) return;\n\t\tif (typeof window === \"undefined\" || typeof window.fetch !== \"function\") return;\n\t\tconst originalFetch = window.fetch.bind(window);\n\t\tconst patched = (async (input: RequestInfo | URL, init?: RequestInit) => {\n\t\t\tconst url = typeof input === \"string\" ? input : input instanceof URL ? input.toString() : input.url;\n\t\t\tconst isTrpc = url.includes(\"/trpc/\");\n\t\t\tif (isTrpc) {\n\t\t\t\tconst method = init?.method ?? (typeof input !== \"string\" && !(input instanceof URL) ? input.method : \"GET\");\n\t\t\t\tconst label = url.split(\"/trpc/\")[1]?.split(\"?\")[0] ?? url;\n\t\t\t\tpushEvent({ kind: \"trpc\", label: `→ ${method} ${label}`, detail: shortJson(init?.body) });\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst res = await originalFetch(input, init);\n\t\t\t\tif (isTrpc) {\n\t\t\t\t\tconst label = url.split(\"/trpc/\")[1]?.split(\"?\")[0] ?? url;\n\t\t\t\t\tpushEvent({ kind: \"trpc\", label: `← ${res.status} ${label}` });\n\t\t\t\t}\n\t\t\t\treturn res;\n\t\t\t} catch (err) {\n\t\t\t\tif (isTrpc) {\n\t\t\t\t\tconst label = url.split(\"/trpc/\")[1]?.split(\"?\")[0] ?? url;\n\t\t\t\t\tpushEvent({ kind: \"error\", label: `✘ ${label}`, detail: err instanceof Error ? err.message : String(err) });\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t}) as unknown as typeof window.fetch;\n\t\twindow.fetch = patched;\n\t\treturn () => {\n\t\t\twindow.fetch = originalFetch;\n\t\t};\n\t}, [enabled, pushEvent]);\n\n\t// Tap WebSocket events by wrapping the store's handleRealtimeEvent\n\tuseEffect(() => {\n\t\tif (!enabled) return;\n\t\tconst original = store.getState().handleRealtimeEvent;\n\t\tstore.setState({\n\t\t\thandleRealtimeEvent: (ev) => {\n\t\t\t\tpushEvent({ kind: \"ws\", label: ev.type, detail: shortJson(ev) });\n\t\t\t\toriginal(ev);\n\t\t\t},\n\t\t});\n\t\treturn () => {\n\t\t\tstore.setState({ handleRealtimeEvent: original });\n\t\t};\n\t}, [enabled, store, pushEvent]);\n\n\t// Emit a marker when messages array changes for the active conversation\n\tconst activeMessages = activeId ? messagesMap.get(activeId) ?? [] : [];\n\tconst lastMsgSignature = useMemo(\n\t\t() => activeMessages.map((m) => `${m.id}:${senderOf(m)}:${m.createdAt}`).join(\"|\"),\n\t\t[activeMessages],\n\t);\n\tconst prevSigRef = useRef(lastMsgSignature);\n\tuseEffect(() => {\n\t\tif (!enabled) return;\n\t\tif (prevSigRef.current !== lastMsgSignature) {\n\t\t\tprevSigRef.current = lastMsgSignature;\n\t\t\tpushEvent({\n\t\t\t\tkind: \"store\",\n\t\t\t\tlabel: `messages[${activeMessages.length}]`,\n\t\t\t\tdetail: activeMessages\n\t\t\t\t\t.map((m, i) => `${i}:${senderOf(m)}=${(m.text ?? \"\").slice(0, 24)}`)\n\t\t\t\t\t.join(\" | \"),\n\t\t\t});\n\t\t}\n\t}, [lastMsgSignature, activeMessages, enabled, pushEvent]);\n\n\tif (!enabled) return null;\n\n\tconst isTyping = activeId ? typingUsers.get(activeId) : false;\n\tconst isAi = activeId ? aiProcessingMap.get(activeId) : false;\n\n\treturn (\n\t\t<div style={styles.wrap}>\n\t\t\t<div style={styles.header}>\n\t\t\t\t<strong>hw debug</strong>\n\t\t\t\t<span style={styles.meta}>\n\t\t\t\t\t{\" \"}· conv {activeId ? activeId.slice(0, 10) : \"—\"} · items {activeMessages.length} · typing {isTyping ? \"Y\" : \"n\"} · ai {isAi ? \"Y\" : \"n\"}\n\t\t\t\t</span>\n\t\t\t\t<button type=\"button\" style={styles.btn} onClick={() => setOpen((v) => !v)}>{open ? \"hide\" : \"show\"}</button>\n\t\t\t\t<button type=\"button\" style={styles.btn} onClick={() => { eventsRef.current = []; setEvents([]); }}>clear</button>\n\t\t\t</div>\n\t\t\t{open && (\n\t\t\t\t<div style={styles.body}>\n\t\t\t\t\t<div style={styles.section}>\n\t\t\t\t\t\t<div style={styles.sectionTitle}>messages (active)</div>\n\t\t\t\t\t\t{activeMessages.length === 0 ? (\n\t\t\t\t\t\t\t<div style={styles.empty}>empty</div>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tactiveMessages.map((m, i) => (\n\t\t\t\t\t\t\t\t<div key={m.id} style={styles.row}>\n\t\t\t\t\t\t\t\t\t<span style={{ ...styles.badge, background: colorFor(senderOf(m)) }}>{i}</span>\n\t\t\t\t\t\t\t\t\t<span style={styles.sender}>{senderOf(m)}</span>\n\t\t\t\t\t\t\t\t\t<span style={styles.ts}>{m.createdAt.slice(11, 23)}</span>\n\t\t\t\t\t\t\t\t\t<span style={styles.text}>{(m.text ?? \"\").slice(0, 60)}</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style={styles.section}>\n\t\t\t\t\t\t<div style={styles.sectionTitle}>events</div>\n\t\t\t\t\t\t{events.length === 0 ? (\n\t\t\t\t\t\t\t<div style={styles.empty}>no events yet — send a message</div>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tevents.map((e) => (\n\t\t\t\t\t\t\t\t<div key={e.id} style={styles.row}>\n\t\t\t\t\t\t\t\t\t<span style={{ ...styles.badge, background: kindColor(e.kind) }}>{e.kind}</span>\n\t\t\t\t\t\t\t\t\t<span style={styles.ts}>{new Date(e.t).toISOString().slice(11, 23)}</span>\n\t\t\t\t\t\t\t\t\t<span style={styles.evLabel}>{e.label}</span>\n\t\t\t\t\t\t\t\t\t{e.detail && <span style={styles.detail}>{e.detail}</span>}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction shortJson(v: unknown): string {\n\tif (v === undefined) return \"\";\n\ttry {\n\t\tconst s = JSON.stringify(v);\n\t\tif (!s) return \"\";\n\t\treturn s.length > 180 ? `${s.slice(0, 177)}…` : s;\n\t} catch {\n\t\treturn String(v);\n\t}\n}\n\nfunction colorFor(sender: string): string {\n\tswitch (sender) {\n\t\tcase \"visitor\":\n\t\t\treturn \"#1d4ed8\";\n\t\tcase \"ai\":\n\t\t\treturn \"#7c3aed\";\n\t\tcase \"team\":\n\t\t\treturn \"#16a34a\";\n\t\tdefault:\n\t\t\treturn \"#6b7280\";\n\t}\n}\n\nfunction kindColor(kind: DebugEvent[\"kind\"]): string {\n\tswitch (kind) {\n\t\tcase \"trpc\":\n\t\t\treturn \"#0ea5e9\";\n\t\tcase \"ws\":\n\t\t\treturn \"#f97316\";\n\t\tcase \"store\":\n\t\t\treturn \"#64748b\";\n\t\tcase \"error\":\n\t\t\treturn \"#dc2626\";\n\t}\n}\n\nconst styles: Record<string, React.CSSProperties> = {\n\twrap: {\n\t\tposition: \"fixed\",\n\t\tright: 12,\n\t\tbottom: 12,\n\t\tzIndex: 2147483000,\n\t\twidth: 420,\n\t\tmaxHeight: \"70vh\",\n\t\tbackground: \"rgba(9,9,11,0.94)\",\n\t\tcolor: \"#e5e7eb\",\n\t\tborderRadius: 10,\n\t\tfontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n\t\tfontSize: 11,\n\t\tboxShadow: \"0 12px 30px rgba(0,0,0,0.35)\",\n\t\toverflow: \"hidden\",\n\t\tpointerEvents: \"auto\",\n\t},\n\theader: {\n\t\tdisplay: \"flex\",\n\t\talignItems: \"center\",\n\t\tgap: 6,\n\t\tpadding: \"6px 10px\",\n\t\tbackground: \"#18181b\",\n\t\tborderBottom: \"1px solid #27272a\",\n\t},\n\tmeta: { flex: 1, color: \"#a1a1aa\", fontSize: 10 },\n\tbtn: {\n\t\tbackground: \"#27272a\",\n\t\tcolor: \"#e4e4e7\",\n\t\tborder: \"1px solid #3f3f46\",\n\t\tborderRadius: 4,\n\t\tpadding: \"2px 8px\",\n\t\tcursor: \"pointer\",\n\t\tfontSize: 10,\n\t},\n\tbody: { display: \"flex\", flexDirection: \"column\", maxHeight: \"calc(70vh - 32px)\", overflow: \"auto\" },\n\tsection: { borderBottom: \"1px solid #27272a\", padding: \"6px 10px\" },\n\tsectionTitle: { color: \"#a1a1aa\", fontSize: 10, textTransform: \"uppercase\", letterSpacing: 0.6, marginBottom: 4 },\n\trow: {\n\t\tdisplay: \"grid\",\n\t\tgridTemplateColumns: \"32px 56px 72px 1fr\",\n\t\tgap: 6,\n\t\talignItems: \"baseline\",\n\t\tpadding: \"2px 0\",\n\t\tborderTop: \"1px dashed #27272a\",\n\t},\n\tbadge: {\n\t\tdisplay: \"inline-block\",\n\t\tborderRadius: 3,\n\t\tpadding: \"1px 4px\",\n\t\tcolor: \"white\",\n\t\tfontSize: 9,\n\t\ttextAlign: \"center\",\n\t},\n\tsender: { color: \"#d4d4d8\" },\n\tts: { color: \"#71717a\", fontSize: 10 },\n\ttext: { color: \"#e4e4e7\", whiteSpace: \"nowrap\", overflow: \"hidden\", textOverflow: \"ellipsis\" },\n\tevLabel: { color: \"#e4e4e7\" },\n\tdetail: { gridColumn: \"1 / -1\", color: \"#a1a1aa\", fontSize: 10, whiteSpace: \"pre-wrap\", wordBreak: \"break-all\" },\n\tempty: { color: \"#52525b\", fontStyle: \"italic\", fontSize: 10 },\n};\n","import { t } from \"@helpway/widget-core\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport type { DockSuggestion } from \"@helpway/widget-core\";\n\nimport { ACCEPTED_TYPES, type PendingAttachment } from \"../hooks/use-composer\";\nimport { PreviewThumb } from \"../themed/composer\";\nimport { ArrowUpIcon, PaperclipIcon } from \"../themed/icons\";\n\n/**\n * The composer bar for `placement=\"docked\"`.\n *\n * Unlike the bubble shell, the bar is persistent chrome and it IS the\n * composer — the conversation panel above it renders without one. That\n * is why this lives in `shell/` rather than inside the conversation:\n * moving the widget must never change the conversation UI.\n *\n * It shares the panel's measure so bar and panel read as one column, and\n * it grows with its content instead of scrolling a one-line field.\n */\nexport interface DockedBarProps {\n\tvalue: string;\n\tonChange: (next: string) => void;\n\tonSubmit: () => void;\n\tdisabled?: boolean;\n\t/**\n\t * Ways in offered before the visitor has typed anything. Rendered as\n\t * pills floating above the bar, over the page — there is no panel to\n\t * put them in yet, and a panel would read as demanding attention\n\t * where pills read as offering.\n\t */\n\tsuggestions?: readonly DockSuggestion[];\n\tonSuggestion?: (question: string) => void;\n\tplaceholder?: string;\n\t/**\n\t * Attachment plumbing, same three pieces the bubble composer gets from\n\t * `useComposer`. The docked bar IS the composer, so leaving these out\n\t * meant the docked shell was the one place a visitor could not send a\n\t * screenshot — the single most common thing a support thread needs.\n\t */\n\tattachments?: PendingAttachment[];\n\tonAddFiles?: (files: File[]) => void;\n\tonRemoveAttachment?: (id: string) => void;\n\t/**\n\t * Reaching for the bar again after folding the panel away. The thread is still\n\t * there — the visitor closed a panel, not a conversation — so touching the\n\t * composer brings it back where they left it. Only wired to a pointer press:\n\t * on `focus` it would also fire for someone tabbing through the page, and a\n\t * panel that appears over the article you are reading because you pressed Tab\n\t * is worse than one that never reappears.\n\t */\n\tonReopen?: () => void;\n\t/**\n\t * Why a send did not happen. The composer refuses an attachment with no caption\n\t * on purpose and sets this instead of failing silently — but in the docked shell\n\t * there was nothing rendering it, so the refusal WAS silent: the file sat in the\n\t * bar, the button did nothing, and no reason was ever given.\n\t */\n\tsendError?: string | null;\n\tonClearSendError?: () => void;\n}\n\n/**\n * The pills float over the host page, so on a content-heavy page they sit on top of\n * whatever is behind them — a code block, a table row. Offering them is right; being\n * unable to put them away is not.\n *\n * One control clears the whole offer rather than one × per pill. The pills are a single\n * gesture from the agent (\"here are ways in\"), so declining them is a single gesture\n * back; asking the visitor to refuse three times to see the page under them is the\n * problem restated, not solved.\n *\n * The dismissal is keyed by the offer's own questions, not a bare boolean: local state,\n * so it returns on the next page load, but if the host swaps in a different set of\n * suggestions that IS a new offer and gets shown.\n */\nfunction useDismissableOffer(suggestions: readonly DockSuggestion[] | undefined) {\n\tconst [dismissedKey, setDismissedKey] = useState<string | null>(null);\n\tconst questions = (suggestions ?? []).map((entry) =>\n\t\ttypeof entry === \"string\" ? entry : entry.question,\n\t);\n\tconst key = questions.join(\"|\");\n\treturn {\n\t\tquestions: dismissedKey === key ? [] : questions,\n\t\tdismiss: () => setDismissedKey(key),\n\t};\n}\n\n/* ── Dictation ─────────────────────────────────────────────────────────────\n The reference composer we are matching offers a mic beside the clip, and on\n a docked bar — often the only input on a docs page — speaking a question is\n faster than typing it. Wired to the platform's own recognizer rather than an\n upload-and-transcribe round trip: no audio leaves the page, and there is no\n server cost to a visitor who trails off mid-sentence.\n\n Typed against a minimal surface instead of `any`: we touch six members, and\n the vendor-prefixed constructor is still the only one Safari exposes. The\n button renders only where the constructor exists, so it is never a control\n that looks live and does nothing. */\ninterface SpeechAlternative {\n\ttranscript: string;\n}\ninterface SpeechResult {\n\treadonly length: number;\n\tisFinal: boolean;\n\t[index: number]: SpeechAlternative;\n}\ninterface SpeechResultList {\n\treadonly length: number;\n\t[index: number]: SpeechResult;\n}\ninterface SpeechEvent {\n\tresultIndex: number;\n\tresults: SpeechResultList;\n}\ninterface Recognition {\n\tlang: string;\n\tcontinuous: boolean;\n\tinterimResults: boolean;\n\tstart(): void;\n\tstop(): void;\n\tonresult: ((event: SpeechEvent) => void) | null;\n\tonend: (() => void) | null;\n\tonerror: (() => void) | null;\n}\ntype RecognitionCtor = new () => Recognition;\n\nfunction recognitionCtor(): RecognitionCtor | null {\n\tif (typeof window === \"undefined\") return null;\n\tconst scope = window as unknown as {\n\t\tSpeechRecognition?: RecognitionCtor;\n\t\twebkitSpeechRecognition?: RecognitionCtor;\n\t};\n\treturn scope.SpeechRecognition ?? scope.webkitSpeechRecognition ?? null;\n}\n\n/**\n * Dictation as an append, not a replace: the visitor may have typed half a\n * sentence before reaching for the mic, and eating it would be worse than not\n * offering the mic at all. Interim results are ignored — a field that rewrites\n * itself while you speak is unreadable — so only settled phrases land.\n */\nfunction useDictation(onText: (chunk: string) => void) {\n\tconst [listening, setListening] = useState(false);\n\tconst recRef = useRef<Recognition | null>(null);\n\t/* The recognizer outlives the render that started it, so the callback is read\n\t through a ref — synced in an effect rather than assigned during render, which\n\t would be a write to shared state in the render phase. */\n\tconst onTextRef = useRef(onText);\n\tuseEffect(() => {\n\t\tonTextRef.current = onText;\n\t}, [onText]);\n\n\t// Support is a property of the browser, so it is resolved once rather than\n\t// on every render, and it decides whether the button exists at all.\n\tconst [supported] = useState(() => recognitionCtor() !== null);\n\n\t// A recognizer left running after unmount keeps the mic indicator lit in the\n\t// tab strip long after the widget is gone.\n\tuseEffect(\n\t\t() => () => {\n\t\t\trecRef.current?.stop();\n\t\t\trecRef.current = null;\n\t\t},\n\t\t[],\n\t);\n\n\tconst toggle = useCallback(() => {\n\t\tif (recRef.current) {\n\t\t\trecRef.current.stop();\n\t\t\treturn;\n\t\t}\n\t\tconst Ctor = recognitionCtor();\n\t\tif (!Ctor) return;\n\t\tconst rec = new Ctor();\n\t\trec.lang = typeof document !== \"undefined\" ? document.documentElement.lang || \"en\" : \"en\";\n\t\trec.continuous = false;\n\t\trec.interimResults = false;\n\t\trec.onresult = (event) => {\n\t\t\tfor (let i = event.resultIndex; i < event.results.length; i++) {\n\t\t\t\tconst result = event.results[i];\n\t\t\t\tif (!result?.isFinal) continue;\n\t\t\t\tconst said = result[0]?.transcript?.trim();\n\t\t\t\tif (said) onTextRef.current(said);\n\t\t\t}\n\t\t};\n\t\tconst finish = () => {\n\t\t\trecRef.current = null;\n\t\t\tsetListening(false);\n\t\t};\n\t\trec.onend = finish;\n\t\trec.onerror = finish;\n\t\trecRef.current = rec;\n\t\tsetListening(true);\n\t\trec.start();\n\t}, []);\n\n\t/* Stopping has to be callable from outside the button, because the button is not\n\t the only thing that ends a dictation — see the blur handler. */\n\tconst stop = useCallback(() => {\n\t\trecRef.current?.stop();\n\t}, []);\n\n\treturn { supported, listening, toggle, stop };\n}\n\n/** Matches --hw-bar-max-height in styles.css. */\nconst MAX_HEIGHT = 148;\n/** Above this the field is no longer one line, so the pill squares off. */\nconst GROWN_AT = 40;\n\n/** Paste and drop both hand us a DataTransfer; only files are interesting. */\nfunction filesFrom(data: DataTransfer | null): File[] {\n\tif (!data?.files) return [];\n\tconst out: File[] = [];\n\tfor (let i = 0; i < data.files.length; i++) {\n\t\tconst file = data.files[i];\n\t\tif (file) out.push(file);\n\t}\n\treturn out;\n}\n\nexport function DockedBar({\n\tvalue,\n\tonChange,\n\tonSubmit,\n\tdisabled = false,\n\tsuggestions,\n\tonSuggestion,\n\tplaceholder,\n\tattachments,\n\tonAddFiles,\n\tonRemoveAttachment,\n\tonReopen,\n\tsendError,\n\tonClearSendError,\n}: DockedBarProps) {\n\tconst [focused, setFocused] = useState(false);\n\tconst inputRef = useRef<HTMLTextAreaElement>(null);\n\tconst boxRef = useRef<HTMLDivElement>(null);\n\tconst fileInputRef = useRef<HTMLInputElement>(null);\n\tconst { questions: visibleQuestions, dismiss: dismissOffer } = useDismissableOffer(suggestions);\n\n\t/* Dictation writes into the same field as the keyboard, appended with a space\n\t so two dictated phrases don't fuse into one word. */\n\tconst dictation = useDictation((chunk) => {\n\t\tconst current = inputRef.current?.value ?? value;\n\t\tonChange(current ? `${current.replace(/\\s+$/, \"\")} ${chunk}` : chunk);\n\t\tinputRef.current?.focus();\n\t});\n\n\t// Height is derived from content on every change rather than held in\n\t// state — a render pass per keystroke to store a number the DOM\n\t// already knows is wasted work.\n\tconst grow = useCallback(() => {\n\t\tconst el = inputRef.current;\n\t\tconst box = boxRef.current;\n\t\tif (!el || !box) return;\n\t\tel.style.height = \"auto\";\n\t\tconst next = Math.min(MAX_HEIGHT, el.scrollHeight);\n\t\tel.style.height = `${next}px`;\n\t\tbox.dataset.grown = next > GROWN_AT ? \"true\" : \"false\";\n\t}, []);\n\n\t// Re-measure when the value is cleared from outside (submit, reset).\n\tuseEffect(grow, [grow, value]);\n\n\tconst handleKeyDown = useCallback(\n\t\t(event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n\t\t\tif (event.key !== \"Enter\" || event.shiftKey) return;\n\t\t\tevent.preventDefault();\n\t\t\tif (!value.trim() || disabled) return;\n\t\t\tonSubmit();\n\t\t},\n\t\t[value, disabled, onSubmit],\n\t);\n\n\t/* A screenshot pasted straight into the field is how most support threads start,\n\t so paste is handled here and not only behind the clip. */\n\tconst handlePaste = useCallback(\n\t\t(event: React.ClipboardEvent<HTMLTextAreaElement>) => {\n\t\t\tif (!onAddFiles) return;\n\t\t\tconst files = filesFrom(event.clipboardData);\n\t\t\tif (!files.length) return;\n\t\t\tevent.preventDefault();\n\t\t\tonAddFiles(files);\n\t\t},\n\t\t[onAddFiles],\n\t);\n\n\t/* Shown when the composer has the visitor's attention, not on arrival.\n\t Three pills stacked above the bar take roughly 240px of viewport, and they float\n\t over the page — so on every content page they landed on whatever was behind them:\n\t a card, a callout's body text, the one code line an install section exists to\n\t show. The visitor had asked for none of it. Offering ways in is right; doing it\n\t over the thing they came to read is not. Focus anywhere in the dock is the signal\n\t that they are looking at it rather than at the article. */\n\tconst showSuggestions = focused && !!visibleQuestions.length && !value.trim();\n\n\t/* Focus tracked on the whole dock rather than the textarea, so clicking a pill —\n\t which moves focus out of the field — does not unmount the pill under the pointer\n\t before the click lands. `relatedTarget` outside the dock is a real exit. */\n\tconst onDockBlur = (event: React.FocusEvent<HTMLDivElement>) => {\n\t\tconst next = event.relatedTarget as Node | null;\n\t\tif (next && event.currentTarget.contains(next)) return;\n\t\tsetFocused(false);\n\t\t/* And stop listening. The unmount cleanup was the wrong hook for this: the bar\n\t\t is persistent chrome, so folding the panel away — or clicking back into the\n\t\t article — never unmounts it, and a recognizer started here kept the browser's\n\t\t mic indicator lit long after the visitor thought they had closed the chat.\n\t\t Focus is the honest signal: dictation belongs to the composer being used. */\n\t\tdictation.stop();\n\t};\n\n\t/* Same rule as the bubble composer: an attachment that is still uploading is not\n\t sendable yet, and text alone or a settled attachment both are. */\n\tconst uploading = attachments?.some((a) => a.isUploading) ?? false;\n\tconst hasAttachment = attachments?.some((a) => a.part !== null) ?? false;\n\tconst canSend = (!!value.trim() || hasAttachment) && !uploading && !disabled;\n\n\treturn (\n\t\t<div className=\"hw-dock\" onFocus={() => setFocused(true)} onBlur={onDockBlur}>\n\t\t\t{showSuggestions && (\n\t\t\t\t<div className=\"hw-dock-suggestions\">\n\t\t\t\t\t{visibleQuestions.map((question, index) => (\n\t\t\t\t\t\t/* The pill stays a button and the dismiss is a sibling, not a nested\n\t\t\t\t\t\t button — a button inside a button is invalid and the inner click\n\t\t\t\t\t\t would still fire the outer one. Only the first row carries the ×,\n\t\t\t\t\t\t since it closes the whole offer. */\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tkey={question}\n\t\t\t\t\t\t\tclassName=\"hw-dock-pill-row\"\n\t\t\t\t\t\t\tstyle={{ animationDelay: `${120 + index * 90}ms` }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"hw-dock-pill\"\n\t\t\t\t\t\t\t\tonClick={() => onSuggestion?.(question)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{question}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t{index === 0 && (\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"hw-dock-pill-dismiss\"\n\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_dismiss\")}\n\t\t\t\t\t\t\t\t\tonClick={dismissOffer}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\t\tstrokeWidth=\"2.5\"\n\t\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<path d=\"M18 6 6 18M6 6l12 12\" />\n\t\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{sendError && (\n\t\t\t\t<div className=\"hw-dock-error\" role=\"alert\">\n\t\t\t\t\t{sendError}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\tclassName=\"hw-dock-bar\"\n\t\t\t\tref={boxRef}\n\t\t\t\tdata-grown=\"false\"\n\t\t\t\tonMouseDown={onReopen}\n\t\t\t\tonTouchStart={onReopen}\n\t\t\t>\n\t\t\t\t{/* Above the field rather than beside it: a thumbnail in the row would\n\t\t\t\t shove the caption into a sliver on the one bar width we control. */}\n\t\t\t\t{!!attachments?.length && (\n\t\t\t\t\t<div className=\"hw-dock-previews\">\n\t\t\t\t\t\t{attachments.map((a) => (\n\t\t\t\t\t\t\t<PreviewThumb\n\t\t\t\t\t\t\t\tkey={a.id}\n\t\t\t\t\t\t\t\tattachment={a}\n\t\t\t\t\t\t\t\tonRemove={onRemoveAttachment ? () => onRemoveAttachment(a.id) : undefined}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t{/* Never disabled while a send is in flight. The browser blurs a\n\t\t\t\t disabled element, so locking the field for the ~200ms round trip\n\t\t\t\t threw the caret out of it — the visitor pressed Enter and lost\n\t\t\t\t the field they were typing in. `canSend` and the Enter handler\n\t\t\t\t already refuse a second submit, which is the part that actually\n\t\t\t\t needed guarding. */}\n\t\t\t\t<textarea\n\t\t\t\t\tref={inputRef}\n\t\t\t\t\tclassName=\"hw-dock-input\"\n\t\t\t\t\trows={1}\n\t\t\t\t\tvalue={value}\n\t\t\t\t\tplaceholder={placeholder ?? t(\"widget.placeholder_new\")}\n\t\t\t\t\taria-label={t(\"widget.placeholder_new\")}\n\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\tonChange(event.target.value);\n\t\t\t\t\t\tif (sendError) onClearSendError?.();\n\t\t\t\t\t\tgrow();\n\t\t\t\t\t}}\n\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\tonPaste={handlePaste}\n\t\t\t\t/>\n\t\t\t\t<div className=\"hw-dock-actions\">\n\t\t\t\t\t{dictation.supported && (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"hw-dock-tool\"\n\t\t\t\t\t\t\tdata-active={dictation.listening ? \"true\" : undefined}\n\t\t\t\t\t\t\taria-label={t(\"widget.aria_dictate\")}\n\t\t\t\t\t\t\taria-pressed={dictation.listening}\n\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t\tonClick={dictation.toggle}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<MicGlyph />\n\t\t\t\t\t\t</button>\n\t\t\t\t\t)}\n\t\t\t\t\t{onAddFiles && (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"hw-dock-tool\"\n\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_attach\")}\n\t\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t\t\tonClick={() => fileInputRef.current?.click()}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<PaperclipIcon size={17} />\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\tref={fileInputRef}\n\t\t\t\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t\t\t\taccept={ACCEPTED_TYPES}\n\t\t\t\t\t\t\t\tmultiple\n\t\t\t\t\t\t\t\thidden\n\t\t\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\t\t\tif (!event.target.files) return;\n\t\t\t\t\t\t\t\t\tonAddFiles(Array.from(event.target.files));\n\t\t\t\t\t\t\t\t\t// Reset so picking the same file twice still fires a change.\n\t\t\t\t\t\t\t\t\tevent.target.value = \"\";\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</>\n\t\t\t\t\t)}\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"hw-dock-send\"\n\t\t\t\t\t\taria-label={t(\"widget.aria_send\")}\n\t\t\t\t\t\tdisabled={!canSend}\n\t\t\t\t\t\tonClick={onSubmit}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ArrowUpIcon size={16} />\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n/** Local glyph — the shipped icon snapshot has no mic, and one path is cheaper\n than another entry in the generated set. */\nfunction MicGlyph() {\n\treturn (\n\t\t<svg\n\t\t\twidth=\"17\"\n\t\t\theight=\"17\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<path d=\"M12 3.5a3 3 0 0 1 3 3v4.5a3 3 0 0 1-6 0V6.5a3 3 0 0 1 3-3Z\" />\n\t\t\t<path d=\"M5.5 11v.5a6.5 6.5 0 0 0 13 0V11\" />\n\t\t\t<path d=\"M12 18v3\" />\n\t\t</svg>\n\t);\n}\n","import { resolveLabel, t } from \"@helpway/widget-core\";\nimport type { WidgetContentTab } from \"@helpway/widget-core\";\nimport { useCallback, useEffect } from \"react\";\nimport { useContentTab } from \"../../hooks/use-content-tab\";\nimport type { ContentEntryItem } from \"../../hooks/use-content-tab\";\nimport { ContentDetailView } from \"./content-detail-view\";\nimport { ContentListView } from \"./content-list-view\";\nimport { GroupedContentTabView } from \"./grouped-content-tab-view\";\n\n/**\n * Content tab dispatcher:\n * - \"flat\" (default) → simple list → detail\n * - \"grouped\" → categories → items → detail\n */\nexport function ContentTabView({\n\ttab,\n\tshowDetail,\n\tdetailSlug,\n\tsubView,\n\tonSelectEntry,\n\tonSelectCategory,\n}: {\n\ttab: WidgetContentTab;\n\tshowDetail: boolean;\n\tdetailSlug: string | null;\n\tsubView?: string | null;\n\tonSelectEntry: (slug: string) => void;\n\tonSelectCategory?: (category: ContentEntryItem) => void;\n}) {\n\t// ── Grouped tab ──\n\tif (tab.tabType === \"grouped\" && tab.itemsModelSlug) {\n\t\treturn (\n\t\t\t<GroupedContentTabView\n\t\t\t\ttab={tab}\n\t\t\t\tsubView={subView ?? null}\n\t\t\t\tdetailSlug={detailSlug}\n\t\t\t\tonSelectCategory={onSelectCategory ?? (() => {})}\n\t\t\t\tonSelectEntry={onSelectEntry}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// ── Flat tab (default) ──\n\treturn (\n\t\t<FlatContentTabView\n\t\t\ttab={tab}\n\t\t\tshowDetail={showDetail}\n\t\t\tdetailSlug={detailSlug}\n\t\t\tonSelectEntry={onSelectEntry}\n\t\t/>\n\t);\n}\n\n// ── Flat (original behavior) ─────────────────────────────\n\nfunction FlatContentTabView({\n\ttab,\n\tshowDetail,\n\tdetailSlug,\n\tonSelectEntry,\n}: {\n\ttab: WidgetContentTab;\n\tshowDetail: boolean;\n\tdetailSlug: string | null;\n\tonSelectEntry: (slug: string) => void;\n}) {\n\tconst {\n\t\tentries,\n\t\tdetail,\n\t\tisLoading,\n\t\tisLoadingDetail,\n\t\thasMore,\n\t\tfetchEntries,\n\t\tloadMore,\n\t\tfetchDetail,\n\t} = useContentTab(tab.id);\n\n\tuseEffect(() => {\n\t\tif (detailSlug) fetchDetail(detailSlug);\n\t}, [detailSlug, fetchDetail]);\n\n\tconst handleSearch = useCallback(\n\t\t(query: string) => {\n\t\t\tfetchEntries({ page: 1, search: query || undefined, reset: true });\n\t\t},\n\t\t[fetchEntries],\n\t);\n\n\tif (showDetail && detailSlug) {\n\t\treturn <ContentDetailView entry={detail} isLoading={isLoadingDetail} />;\n\t}\n\n\treturn (\n\t\t<ContentListView\n\t\t\tentries={entries}\n\t\t\tisLoading={isLoading}\n\t\t\thasMore={hasMore}\n\t\t\tonSelect={onSelectEntry}\n\t\t\tonLoadMore={loadMore}\n\t\t\tonSearch={handleSearch}\n\t\t\tsearchPlaceholder={`${t(\"widget.search\")} ${resolveLabel(tab.label).toLowerCase()}...`}\n\t\t\tdisplay={tab.display}\n\t\t/>\n\t);\n}\n","import type { WidgetContentTab } from \"@helpway/widget-core\";\nimport { CONTENT_CACHE_TTL, getLocale } from \"@helpway/widget-core\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\ninterface ContentEntryItem {\n\tslug: string;\n\ttitle: string;\n\tbody: string | null;\n\tpublishedAt: string | null;\n\tcustomFields: Record<string, string | null>;\n}\n\ninterface ContentEntryDetail {\n\tslug: string;\n\ttitle: string;\n\tbody: string | null;\n\tbodyHtml: string | null;\n\tpublishedAt: string | null;\n\tsourceLanguage: string;\n\tavailableLanguages: string[];\n\tcustomFields: Record<string, string | null>;\n}\n\nconst EMPTY_TABS: WidgetContentTab[] = [];\n\n// ── Cache key helpers ──\n\nfunction listKey(tabId: string, lang: string) {\n\treturn `flat:${tabId}:${lang}:list`;\n}\n\nfunction detailKey(tabId: string, lang: string, slug: string) {\n\treturn `flat:${tabId}:${lang}:detail:${slug}`;\n}\n\ninterface CachedList {\n\titems: ContentEntryItem[];\n\ttotal: number;\n\thasMore: boolean;\n\tpage: number;\n}\n\nfunction readCache<T>(cache: Map<string, { data: unknown; ts: number }>, key: string): T | null {\n\tconst entry = cache.get(key);\n\tif (!entry) return null;\n\tif (Date.now() - entry.ts > CONTENT_CACHE_TTL) return null;\n\treturn entry.data as T;\n}\n\n/**\n * Hook for fetching content from a dynamic content tab.\n * Content is cached in the Zustand store so tab switches don't re-fetch.\n */\nexport function useContentTab(tabId: string) {\n\tconst { client, store } = useWidgetContext();\n\tconst contentTabs = useWidgetStore((s) => s.agentConfig?.contentTabs) ?? EMPTY_TABS;\n\tconst tab = contentTabs.find((t) => t.id === tabId) ?? null;\n\n\tconst lang = getLocale();\n\tconst cache = store.getState().contentCache;\n\n\tconst [entries, setEntries] = useState<ContentEntryItem[]>(\n\t\t() => readCache<CachedList>(cache, listKey(tabId, lang))?.items ?? [],\n\t);\n\tconst [detail, setDetail] = useState<ContentEntryDetail | null>(null);\n\tconst [isLoading, setIsLoading] = useState(false);\n\tconst [isLoadingDetail, setIsLoadingDetail] = useState(false);\n\tconst [hasMore, setHasMore] = useState(\n\t\t() => readCache<CachedList>(cache, listKey(tabId, lang))?.hasMore ?? false,\n\t);\n\tconst [total, setTotal] = useState(\n\t\t() => readCache<CachedList>(cache, listKey(tabId, lang))?.total ?? 0,\n\t);\n\tconst [page, setPage] = useState(\n\t\t() => readCache<CachedList>(cache, listKey(tabId, lang))?.page ?? 1,\n\t);\n\n\tconst fetchEntries = useCallback(\n\t\tasync (opts?: { page?: number; search?: string; reset?: boolean }) => {\n\t\t\tif (!tab) return;\n\t\t\tconst p = opts?.page ?? 1;\n\t\t\tconst reset = opts?.reset ?? p === 1;\n\n\t\t\tsetIsLoading(true);\n\t\t\ttry {\n\t\t\t\tconst result = await client.widget.getContent.query({\n\t\t\t\t\ttabId,\n\t\t\t\t\tpage: p,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t\tsearch: opts?.search,\n\t\t\t\t\tlanguage: getLocale(),\n\t\t\t\t});\n\n\t\t\t\tif (result.items) {\n\t\t\t\t\tsetEntries((prev) => {\n\t\t\t\t\t\tconst nextItems = reset ? result.items! : [...prev, ...result.items!];\n\t\t\t\t\t\tif (!opts?.search) {\n\t\t\t\t\t\t\tstore.getState().setContentCache(listKey(tabId, getLocale()), {\n\t\t\t\t\t\t\t\titems: nextItems,\n\t\t\t\t\t\t\t\ttotal: result.total,\n\t\t\t\t\t\t\t\thasMore: result.hasMore,\n\t\t\t\t\t\t\t\tpage: p,\n\t\t\t\t\t\t\t} satisfies CachedList);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nextItems;\n\t\t\t\t\t});\n\t\t\t\t\tsetHasMore(result.hasMore);\n\t\t\t\t\tsetTotal(result.total);\n\t\t\t\t\tsetPage(p);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useContentTab] fetch error:\", err);\n\t\t\t} finally {\n\t\t\t\tsetIsLoading(false);\n\t\t\t}\n\t\t},\n\t\t[client, tabId, tab, store],\n\t);\n\n\tconst loadMore = useCallback(() => {\n\t\tif (!hasMore || isLoading) return;\n\t\tfetchEntries({ page: page + 1 });\n\t}, [fetchEntries, hasMore, isLoading, page]);\n\n\tconst fetchDetail = useCallback(\n\t\tasync (slug: string) => {\n\t\t\tif (!tab) return;\n\n\t\t\t// Check detail cache\n\t\t\tconst cached = readCache<ContentEntryDetail>(\n\t\t\t\tstore.getState().contentCache,\n\t\t\t\tdetailKey(tabId, getLocale(), slug),\n\t\t\t);\n\t\t\tif (cached) {\n\t\t\t\tsetDetail(cached);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetIsLoadingDetail(true);\n\t\t\ttry {\n\t\t\t\tconst result = await client.widget.getContent.query({\n\t\t\t\t\ttabId,\n\t\t\t\t\tslug,\n\t\t\t\t\tlanguage: getLocale(),\n\t\t\t\t});\n\t\t\t\tif (result.entry) {\n\t\t\t\t\tconst entry = result.entry as ContentEntryDetail;\n\t\t\t\t\tsetDetail(entry);\n\t\t\t\t\tstore.getState().setContentCache(\n\t\t\t\t\t\tdetailKey(tabId, getLocale(), slug),\n\t\t\t\t\t\tentry,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useContentTab] detail error:\", err);\n\t\t\t} finally {\n\t\t\t\tsetIsLoadingDetail(false);\n\t\t\t}\n\t\t},\n\t\t[client, tabId, tab, store],\n\t);\n\n\tconst clearDetail = useCallback(() => {\n\t\tsetDetail(null);\n\t}, []);\n\n\t// Initial fetch — only if cache was empty\n\tuseEffect(() => {\n\t\tif (tab && entries.length === 0) {\n\t\t\tfetchEntries({ page: 1, reset: true });\n\t\t}\n\t}, [tab]); // eslint-disable-line react-hooks/exhaustive-deps\n\n\treturn {\n\t\ttab,\n\t\tentries,\n\t\tdetail,\n\t\tisLoading,\n\t\tisLoadingDetail,\n\t\thasMore,\n\t\ttotal,\n\t\tfetchEntries,\n\t\tloadMore,\n\t\tfetchDetail,\n\t\tclearDetail,\n\t};\n}\n\nexport type { ContentEntryItem, ContentEntryDetail, WidgetContentTab };\n","import { useEffect, useRef } from \"react\";\n\nconst COPY_ICON = `<svg class=\"hw-code-copy-icon\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"><path d=\"M15 9V4.25C15 3.55964 14.4404 3 13.75 3H4.25C3.55964 3 3 3.55964 3 4.25V13.75C3 14.4404 3.55964 15 4.25 15H9M10.25 9H19.75C20.4404 9 21 9.55964 21 10.25V19.75C21 20.4404 20.4404 21 19.75 21H10.25C9.55964 21 9 20.4404 9 19.75V10.25C9 9.55964 9.55964 9 10.25 9Z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`;\n\nconst CHECK_ICON = `<svg class=\"hw-code-check-icon\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"><path d=\"M8 13L11 16L16 8\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`;\n\nfunction inferCodeLanguage(code: string, lang?: string): string {\n\tif (lang) return lang;\n\tconst trimmed = code.trim();\n\tif (/^(npm|pnpm|yarn|bun|npx|curl|cd|mkdir|cp|mv|rm|export)\\b/m.test(trimmed)) return \"bash\";\n\tif (/\\b(import|export)\\b/.test(trimmed) && /<[A-Z_a-z][\\w.:-]*(\\s|>)/.test(trimmed)) return \"tsx\";\n\tif (/\\b(import|export|const|let|function|type|interface)\\b/.test(trimmed)) return \"ts\";\n\tif (/^\\s*[{[]/.test(trimmed)) return \"json\";\n\treturn \"code\";\n}\n\nexport function handleCodeBlockClick(e: Event, root: HTMLElement): void {\n\tconst target = e.target as HTMLElement | null;\n\tconst btn = target?.closest<HTMLButtonElement>(\".hw-code-copy\");\n\tif (!btn || !root.contains(btn)) return;\n\tconst block = btn.closest(\".hw-code\");\n\tconst code = block?.querySelector(\"pre code\");\n\tconst text = code?.textContent ?? \"\";\n\tif (!text) return;\n\tvoid navigator.clipboard?.writeText(text).then(\n\t\t() => flashCopied(btn),\n\t\t() => flashCopied(btn, true),\n\t);\n}\n\n/**\n * Lightweight Markdown → HTML renderer.\n * Zero dependencies. Handles common patterns:\n * headings, bold, italic, code, links, lists, blockquotes, images, hr.\n *\n * Security note: Content is served from Better i18n Content CMS which only\n * accepts authenticated writes (secret API key). The CMS sanitizes content\n * server-side. Additionally, our renderMarkdown escapes HTML entities before\n * processing markdown syntax, preventing injection of raw HTML tags.\n */\nexport function renderMarkdown(md: string): string {\n\t// Stash fenced code blocks BEFORE any other pass. Fence content must be\n\t// preserved verbatim: no bold, no autolink, no newline→<br> — otherwise\n\t// a curl command or JSON sample gets shredded. We also escape HTML inside\n\t// the block (the global escape below runs only on the remaining markdown).\n\tconst codeBlocks: string[] = [];\n\tconst codeBlockPlaceholder = (i: number) => `\\u0000CODEBLOCK${i}\\u0000`;\n\tconst body = md.replace(\n\t\t// Eat ALL newlines around the fence (zero-or-more both sides). The\n\t\t// replacement re-emits its own `\\n\\n` pair so the paragraph splitter\n\t\t// cleanly bookends the fence. Without this, `before\\n\\n` + `\\n\\n` from\n\t\t// us = 3 newlines, the extra one becomes <br /> and lands inside a <p>.\n\t\t/\\n*```(\\w+)?\\n?([\\s\\S]*?)```\\n*/g,\n\t\t(_match, lang: string | undefined, code: string) => {\n\t\t\tconst escaped = code.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n\t\t\tconst langLabel = inferCodeLanguage(code, lang);\n\t\t\tconst className = langLabel !== \"code\" ? ` class=\"language-${langLabel}\"` : \"\";\n\t\t\t// Render every fenced block with a header bar (language label + copy\n\t\t\t// button) so it reads like a proper code card, not a bare <pre>.\n\t\t\t// The actual copy action is wired up in MarkdownContent via event\n\t\t\t// delegation — we only need the markup + a stable attribute to key\n\t\t\t// off of.\n\t\t\tconst trimmed = escaped.replace(/\\n$/, \"\");\n\t\t\tcodeBlocks.push(\n\t\t\t\t`<div class=\"hw-code\" data-hw-code=\"1\"><div class=\"hw-code-header\"><span class=\"hw-code-lang\">${langLabel}</span><div class=\"hw-code-actions\"><button type=\"button\" class=\"hw-code-action hw-code-copy\" aria-label=\"Copy code\" title=\"Copy code\">${COPY_ICON}${CHECK_ICON}<span class=\"hw-code-copy-label\">Copy</span></button></div></div><pre><code${className}>${trimmed}</code></pre></div>`,\n\t\t\t);\n\t\t\t// Sandwich the placeholder in blank lines so the paragraph splitter\n\t\t\t// treats it as its own block. Otherwise a fence that follows a\n\t\t\t// paragraph without a separating blank line ends up inside a <p>\n\t\t\t// (invalid HTML, collapses the <pre>).\n\t\t\treturn `\\n\\n${codeBlockPlaceholder(codeBlocks.length - 1)}\\n\\n`;\n\t\t},\n\t);\n\n\tlet html = body\n\t\t// Escape HTML entities FIRST — prevents XSS from raw HTML in markdown\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t// Headings (### h3, ## h2, # h1)\n\t\t.replace(/^### (.+)$/gm, \"<h3>$1</h3>\")\n\t\t.replace(/^## (.+)$/gm, \"<h2>$1</h2>\")\n\t\t.replace(/^# (.+)$/gm, \"<h1>$1</h1>\")\n\t\t// Horizontal rule\n\t\t.replace(/^---$/gm, \"<hr />\")\n\t\t// Bold + italic\n\t\t.replace(/\\*\\*\\*(.+?)\\*\\*\\*/g, \"<strong><em>$1</em></strong>\")\n\t\t// Bold\n\t\t.replace(/\\*\\*(.+?)\\*\\*/g, \"<strong>$1</strong>\")\n\t\t// Italic\n\t\t.replace(/\\*(.+?)\\*/g, \"<em>$1</em>\")\n\t\t// Inline code\n\t\t.replace(/`([^`]+)`/g, \"<code>$1</code>\")\n\t\t// Images\n\t\t.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, '<img src=\"$2\" alt=\"$1\" />')\n\t\t// Links (markdown format)\n\t\t.replace(\n\t\t\t/\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n\t\t\t'<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>',\n\t\t)\n\t\t// Auto-link bare URLs (not already inside an href or markdown link)\n\t\t.replace(\n\t\t\t/(?<!\")(?<!=)(https?:\\/\\/[^\\s<)]+)/g,\n\t\t\t'<a href=\"$1\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>',\n\t\t)\n\t\t// Blockquotes\n\t\t.replace(/^&gt; (.+)$/gm, \"<blockquote>$1</blockquote>\")\n\t\t// Unordered lists\n\t\t.replace(/^[*-] (.+)$/gm, \"<li>$1</li>\")\n\t\t// Ordered lists — temp <oli> tag so the <ul> wrapper below can't claim\n\t\t// them; renamed to <li> when wrapped in <ol>.\n\t\t.replace(/^\\d+\\. (.+)$/gm, \"<oli>$1</oli>\");\n\n\t// Tables — must run while real newlines still exist (before the <br> pass).\n\t// Runs AFTER the inline passes so bold/links inside cells are already HTML.\n\t// Stashed as placeholders like code blocks so the paragraph splitter can't\n\t// chop a <table> in half.\n\tconst tables: string[] = [];\n\tconst tablePlaceholder = (i: number) => `\\u0000TABLE${i}\\u0000`;\n\thtml = html.replace(\n\t\t// header row | separator row (only - : | spaces) | 1+ body rows\n\t\t/^(\\|.+\\|)[ \\t]*\\n\\|[ \\t:|-]+\\|[ \\t]*\\n((?:\\|.+\\|[ \\t]*(?:\\n|$))+)/gm,\n\t\t(_match, headerLine: string, bodyLines: string) => {\n\t\t\tconst cells = (line: string) =>\n\t\t\t\tline.trim().replace(/^\\||\\|$/g, \"\").split(\"|\").map((c) => c.trim());\n\t\t\tconst head = cells(headerLine)\n\t\t\t\t.map((c) => `<th>${c}</th>`)\n\t\t\t\t.join(\"\");\n\t\t\tconst rows = bodyLines\n\t\t\t\t.trim()\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((line) => `<tr>${cells(line).map((c) => `<td>${c}</td>`).join(\"\")}</tr>`)\n\t\t\t\t.join(\"\");\n\t\t\ttables.push(\n\t\t\t\t`<div class=\"hw-table-wrap\"><table class=\"hw-table\"><thead><tr>${head}</tr></thead><tbody>${rows}</tbody></table></div>`,\n\t\t\t);\n\t\t\treturn `\\n\\n${tablePlaceholder(tables.length - 1)}\\n\\n`;\n\t\t},\n\t);\n\n\t// Wrap consecutive list items BEFORE newlines become <br /> — the old\n\t// post-<br> wrap could only ever see one <li> at a time, producing a\n\t// separate <ul> per item with stray <br />s in between.\n\thtml = html\n\t\t.replace(/((?:<li>.*<\\/li>\\n?)+)/g, (m) => `<ul>${m.replace(/\\n/g, \"\")}</ul>\\n`)\n\t\t.replace(\n\t\t\t/((?:<oli>.*<\\/oli>\\n?)+)/g,\n\t\t\t(m) => `<ol>${m.replace(/\\n/g, \"\").replace(/<(\\/?)oli>/g, \"<$1li>\")}</ol>\\n`,\n\t\t);\n\n\thtml = html\n\t\t// Paragraphs (double newline)\n\t\t.replace(/\\n\\n/g, \"</p><p>\")\n\t\t// Single newlines → br\n\t\t.replace(/\\n/g, \"<br />\");\n\n\t// Lists glued to surrounding text by a single newline pick up a stray\n\t// <br /> neighbor — drop it so spacing comes from CSS, not phantom breaks.\n\t// Same for a <br /> opening a paragraph (left over from placeholder seams).\n\thtml = html\n\t\t.replace(/<br \\/>(\\s*<(?:ul|ol)>)/g, \"$1\")\n\t\t.replace(/(<\\/(?:ul|ol)>\\s*)<br \\/>/g, \"$1\")\n\t\t.replace(/<p><br \\/>/g, \"<p>\");\n\n\t// Wrap in paragraph if not starting with a block element\n\tif (\n\t\t!html.startsWith(\"<h\") &&\n\t\t!html.startsWith(\"<ul\") &&\n\t\t!html.startsWith(\"<ol\") &&\n\t\t!html.startsWith(\"<blockquote\") &&\n\t\t!html.startsWith(\"<hr\")\n\t) {\n\t\thtml = `<p>${html}</p>`;\n\t}\n\n\t// Re-inject tables (same placeholder mechanics as code blocks below).\n\tif (tables.length > 0) {\n\t\t// biome-ignore lint/suspicious/noControlCharactersInRegex: placeholders use NUL sentinels intentionally.\n\t\thtml = html.replace(/\\u0000TABLE(\\d+)\\u0000/g, (_m, idx: string) => {\n\t\t\tconst i = Number.parseInt(idx, 10);\n\t\t\treturn tables[i] ?? \"\";\n\t\t});\n\t\t// Unwrap a <p> that ended up directly around a table (no blank-line\n\t\t// separator in the source) — invalid nesting collapses the layout.\n\t\thtml = html.replace(/<p>(\\s*<div class=\"hw-table-wrap\"[\\s\\S]*?<\\/div>\\s*)<\\/p>/g, \"$1\");\n\t}\n\n\t// A list that landed inside a <p> (single blank line before it) is invalid\n\t// nesting — unwrap like the code-block case below.\n\thtml = html.replace(/<p>(\\s*<(?:ul|ol)>[\\s\\S]*?<\\/(?:ul|ol)>\\s*)<\\/p>/g, \"$1\");\n\n\t// Re-inject code blocks now that surrounding paragraphs / <br> passes are\n\t// done. Placeholders used NUL sentinels so they can't collide with user\n\t// content or be accidentally wrapped by the block-element heuristics above.\n\tif (codeBlocks.length > 0) {\n\t\t// biome-ignore lint/suspicious/noControlCharactersInRegex: placeholders use NUL sentinels intentionally.\n\t\thtml = html.replace(/\\u0000CODEBLOCK(\\d+)\\u0000/g, (_m, idx: string) => {\n\t\t\tconst i = Number.parseInt(idx, 10);\n\t\t\treturn codeBlocks[i] ?? \"\";\n\t\t});\n\t\t// A code block that landed inside a <p> (because the preceding line had no\n\t\t// blank-line separator) becomes invalid nesting (<p><div><pre>). Unwrap\n\t\t// the outer <p> so the block stands on its own.\n\t\thtml = html.replace(/<p>(\\s*<div class=\"hw-code\"[\\s\\S]*?<\\/div>\\s*)<\\/p>/g, \"$1\");\n\t}\n\n\treturn html;\n}\n\n/**\n * Convert bare URLs in plain text to clickable links.\n * Used for visitor/team messages (not full markdown).\n * HTML-escaped for safety.\n */\nexport function linkifyText(text: string): string {\n\treturn text\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t.replace(\n\t\t\t/(https?:\\/\\/[^\\s<]+)/g,\n\t\t\t'<a href=\"$1\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>',\n\t\t)\n\t\t.replace(/\\n/g, \"<br />\");\n}\n\n/**\n * Renders markdown or pre-rendered HTML content.\n * Prefers bodyHtml (server-sanitized by CMS) when available,\n * falls back to client-side markdown rendering (HTML-escaped).\n */\nexport function MarkdownContent({\n\tbodyHtml,\n\tbodyMarkdown,\n\tclassName,\n}: {\n\tbodyHtml?: string | null;\n\tbodyMarkdown?: string | null;\n\tclassName?: string;\n}) {\n\tconst rootRef = useRef<HTMLDivElement>(null);\n\tconst html = bodyHtml ?? (bodyMarkdown ? renderMarkdown(bodyMarkdown) : \"\");\n\n\t// Strip whitespace-only block elements after the HTML lands in the DOM.\n\t// PlateJS/Slate/ProseMirror CMS bodies emit <p>&nbsp;</p> or <div> </div>\n\t// to represent visual line breaks. CSS `:empty` doesn't match these (the\n\t// nbsp/space is a text node) and CSS has no text-content selector, so we\n\t// clean them up here. Runs once per html change.\n\tuseEffect(() => {\n\t\tconst root = rootRef.current;\n\t\tif (!root) return;\n\n\t\tconst isWhitespaceOnly = (el: Element): boolean => {\n\t\t\t// No element children OR only <br> children, AND text is whitespace/empty\n\t\t\tconst hasNonBrChild = Array.from(el.children).some(\n\t\t\t\t(c) => c.tagName !== \"BR\",\n\t\t\t);\n\t\t\tif (hasNonBrChild) return false;\n\t\t\tconst text = el.textContent ?? \"\";\n\t\t\treturn text.replace(/[\\s ]/g, \"\") === \"\";\n\t\t};\n\n\t\tconst removeEmpties = () => {\n\t\t\tconst candidates = root.querySelectorAll(\"p, div\");\n\t\t\tcandidates.forEach((el) => {\n\t\t\t\tif (isWhitespaceOnly(el)) el.remove();\n\t\t\t});\n\t\t};\n\t\tremoveEmpties();\n\t}, [html]);\n\n\t// Event-delegated copy handler for any `.hw-code-copy` button inside the\n\t// rendered tree. Using delegation instead of rendering each code block as\n\t// a React component keeps the markdown → HTML path zero-dep.\n\tuseEffect(() => {\n\t\tconst root = rootRef.current;\n\t\tif (!root) return;\n\t\tconst handler = (e: Event) => {\n\t\t\thandleCodeBlockClick(e, root);\n\t\t};\n\t\troot.addEventListener(\"click\", handler);\n\t\treturn () => {\n\t\t\troot.removeEventListener(\"click\", handler);\n\t\t};\n\t}, []);\n\n\tif (!html) return null;\n\n\treturn (\n\t\t<div\n\t\t\tref={rootRef}\n\t\t\tclassName={`hw-markdown ${className ?? \"\"}`}\n\t\t\t// Content is from authenticated CMS (server-sanitized bodyHtml)\n\t\t\t// or client-side rendered with HTML entity escaping (renderMarkdown).\n\t\t\t// biome-ignore lint/security/noDangerouslySetInnerHtml: trusted CMS content\n\t\t\tdangerouslySetInnerHTML={{ __html: html }}\n\t\t/>\n\t);\n}\n\nfunction flashCopied(btn: HTMLButtonElement, failed = false) {\n\tconst label = btn.querySelector(\".hw-code-copy-label\");\n\tif (!label) return;\n\tconst original = label.textContent ?? \"Copy\";\n\tlabel.textContent = failed ? \"Failed\" : \"Copied\";\n\tbtn.classList.add(failed ? \"hw-code-copy--failed\" : \"hw-code-copy--copied\");\n\tsetTimeout(() => {\n\t\tlabel.textContent = original;\n\t\tbtn.classList.remove(\"hw-code-copy--copied\", \"hw-code-copy--failed\");\n\t}, 1500);\n}\n\n/**\n * Close dangling markdown delimiters in a partial (still-streaming) message\n * so renderMarkdown doesn't show raw syntax mid-stream: an unclosed ```fence\n * renders as literal backticks, an odd ** shows asterisks. The final message\n * replaces this bubble entirely, so the patch only ever affects transient UI.\n */\nexport function closeDanglingMarkdown(partial: string): string {\n\tlet out = partial;\n\tconst fences = (out.match(/```/g) ?? []).length;\n\tif (fences % 2 === 1) out += \"\\n```\";\n\t// Inline code / bold counted on the remainder outside fences is overkill\n\t// for a transient frame — a simple global parity check is good enough.\n\tconst bold = (out.match(/\\*\\*/g) ?? []).length;\n\tif (bold % 2 === 1) out += \"**\";\n\treturn out;\n}\n","import { formatRelativeTime } from \"@helpway/widget-core\";\nimport type { ContentEntryDetail } from \"../../hooks/use-content-tab\";\nimport { MarkdownContent } from \"./simple-markdown\";\n\nexport function ContentDetailView({\n\tentry,\n\tisLoading,\n}: {\n\tentry: ContentEntryDetail | null;\n\tisLoading: boolean;\n}) {\n\tif (isLoading || !entry) {\n\t\treturn <ArticleSkeleton />;\n\t}\n\n\tconst badge = entry.customFields.version ?? entry.customFields.priority ?? entry.customFields.type ?? null;\n\n\treturn (\n\t\t<div className=\"hw-content-detail\">\n\t\t\t<div className=\"hw-content-detail-header\">\n\t\t\t\t<h1 className=\"hw-content-detail-title\">{entry.title}</h1>\n\t\t\t\t{(badge || entry.publishedAt) && (\n\t\t\t\t\t<div className=\"hw-content-detail-meta\">\n\t\t\t\t\t\t{badge && <span className=\"hw-content-entry-badge\">{badge}</span>}\n\t\t\t\t\t\t{entry.publishedAt && (\n\t\t\t\t\t\t\t<span className=\"hw-content-detail-date\">\n\t\t\t\t\t\t\t\t{formatRelativeTime(entry.publishedAt)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t{(entry.body || entry.bodyHtml) && (\n\t\t\t\t<div className=\"hw-content-detail-body\">\n\t\t\t\t\t<MarkdownContent bodyHtml={entry.bodyHtml} bodyMarkdown={entry.body} />\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n/**\n * Article-shaped skeleton.\n *\n * Uses the real .hw-content-detail / .hw-content-detail-header / .hw-content-detail-body / .hw-markdown\n * wrapper classes so all padding, font metrics, and adjacency-spacing rules\n * apply identically to the skeleton — guaranteeing the content lands without\n * any reflow when it arrives.\n *\n * Layout maps 1:1 to the rendered changelog:\n * <h1>Title</h1>\n * <div class=\"meta\"> badge + date </div>\n * <h2>Section</h2>\n * <ul><li>Bullet 1, 2 lines</li></ul>\n * <ul><li>Bullet 2, 2 lines</li></ul>\n * ...\n */\nfunction ArticleSkeleton() {\n\tconst sections: { headerWidth: string; items: { l1: string; l2: string }[] }[] = [\n\t\t{\n\t\t\theaderWidth: \"30%\",\n\t\t\titems: [\n\t\t\t\t{ l1: \"98%\", l2: \"62%\" },\n\t\t\t\t{ l1: \"94%\", l2: \"48%\" },\n\t\t\t\t{ l1: \"96%\", l2: \"70%\" },\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\theaderWidth: \"26%\",\n\t\t\titems: [\n\t\t\t\t{ l1: \"92%\", l2: \"55%\" },\n\t\t\t\t{ l1: \"88%\", l2: \"40%\" },\n\t\t\t],\n\t\t},\n\t];\n\n\treturn (\n\t\t<div className=\"hw-content-detail\">\n\t\t\t<div className=\"hw-content-detail-header\">\n\t\t\t\t<h1 className=\"hw-content-detail-title\">\n\t\t\t\t\t<span className=\"hw-skeleton hw-skeleton-title\" />\n\t\t\t\t</h1>\n\t\t\t\t<div className=\"hw-content-detail-meta\">\n\t\t\t\t\t<span className=\"hw-skeleton hw-skeleton-badge\" />\n\t\t\t\t\t<span className=\"hw-skeleton hw-skeleton-date\" />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div className=\"hw-content-detail-body\">\n\t\t\t\t<div className=\"hw-markdown\">\n\t\t\t\t\t{sections.map((s, i) => (\n\t\t\t\t\t\t<SkeletonSection\n\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\theaderWidth={s.headerWidth}\n\t\t\t\t\t\t\titems={s.items}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction SkeletonSection({\n\theaderWidth,\n\titems,\n}: {\n\theaderWidth: string;\n\titems: { l1: string; l2: string }[];\n}) {\n\treturn (\n\t\t<>\n\t\t\t<h2>\n\t\t\t\t<span\n\t\t\t\t\tclassName=\"hw-skeleton hw-skeleton-h2\"\n\t\t\t\t\tstyle={{ display: \"block\", width: headerWidth }}\n\t\t\t\t/>\n\t\t\t</h2>\n\t\t\t{items.map((item, j) => (\n\t\t\t\t<ul key={j}>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<div className=\"hw-skeleton-bullet-lines\">\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName=\"hw-skeleton hw-skeleton-bullet-line\"\n\t\t\t\t\t\t\t\tstyle={{ display: \"block\", width: item.l1 }}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName=\"hw-skeleton hw-skeleton-bullet-line\"\n\t\t\t\t\t\t\t\tstyle={{ display: \"block\", width: item.l2, marginTop: 8 }}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t))}\n\t\t</>\n\t);\n}\n","import { formatRelativeTime, t } from \"@helpway/widget-core\";\nimport type { ContentTabDisplay } from \"@helpway/types\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { ContentEntryItem } from \"../../hooks/use-content-tab\";\n\n/**\n * Content entry list — Intercom-style clean card layout.\n * Search bar at top, card entries with title + description + chevron.\n */\nexport function ContentListView({\n\tentries,\n\tisLoading,\n\thasMore,\n\tonSelect,\n\tonLoadMore,\n\tonSearch,\n\tsearchPlaceholder,\n\tdisplay,\n}: {\n\tentries: ContentEntryItem[];\n\tisLoading: boolean;\n\thasMore: boolean;\n\tonSelect: (slug: string) => void;\n\tonLoadMore: () => void;\n\tonSearch?: (query: string) => void;\n\tsearchPlaceholder?: string;\n\tdisplay?: ContentTabDisplay;\n}) {\n\tconst [searchText, setSearchText] = useState(\"\");\n\tconst debounceRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n\tconst handleSearch = useCallback(\n\t\t(value: string) => {\n\t\t\tsetSearchText(value);\n\t\t\tif (!onSearch) return;\n\t\t\tclearTimeout(debounceRef.current);\n\t\t\tdebounceRef.current = setTimeout(() => {\n\t\t\t\tonSearch(value.trim());\n\t\t\t}, 300);\n\t\t},\n\t\t[onSearch],\n\t);\n\n\treturn (\n\t\t<div className=\"hw-content-list\">\n\t\t\t{/* Search */}\n\t\t\t{onSearch && (\n\t\t\t\t<div className=\"hw-content-search\">\n\t\t\t\t\t<div className=\"hw-content-search-box\">\n\t\t\t\t\t\t<svg className=\"hw-content-search-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n\t\t\t\t\t\t\t<circle cx=\"11\" cy=\"11\" r=\"8\" />\n\t\t\t\t\t\t\t<line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\tclassName=\"hw-content-search-input\"\n\t\t\t\t\t\t\tplaceholder={searchPlaceholder ?? t(\"widget.search\")}\n\t\t\t\t\t\t\tvalue={searchText}\n\t\t\t\t\t\t\tonChange={(e) => handleSearch(e.target.value)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Loading */}\n\t\t\t{isLoading && entries.length === 0 && (\n\t\t\t\t<div className=\"hw-skeleton-content\">\n\t\t\t\t\t{[1, 2, 3].map((i) => (\n\t\t\t\t\t\t<div key={i} className=\"hw-skeleton-content-item\">\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: \"70%\", height: 14 }} />\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: \"90%\", height: 12 }} />\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: \"40%\", height: 10 }} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Empty */}\n\t\t\t{!isLoading && entries.length === 0 && (\n\t\t\t\t<div className=\"hw-content-empty\">\n\t\t\t\t\t<div className=\"hw-content-empty-title\">\n\t\t\t\t\t\t{searchText ? t(\"widget.no_results\") : t(\"widget.nothing_yet\")}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"hw-content-empty-desc\">\n\t\t\t\t\t\t{searchText ? t(\"widget.try_different\") : t(\"widget.check_back\")}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Entries */}\n\t\t\t{entries.length > 0 && (\n\t\t\t\t<div className=\"hw-content-entries\">\n\t\t\t\t\t{entries.map((entry) => (\n\t\t\t\t\t\t<ContentEntryCard key={entry.slug} entry={entry} onSelect={onSelect} display={display} />\n\t\t\t\t\t))}\n\t\t\t\t\t{hasMore && (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"hw-content-load-more\"\n\t\t\t\t\t\t\tonClick={onLoadMore}\n\t\t\t\t\t\t\tdisabled={isLoading}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{isLoading ? t(\"widget.loading\") : t(\"widget.load_more\")}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// ── Entry Card — Intercom-style ──────────────────────────\n\nfunction truncateText(text: string | null, maxLen = 80): string {\n\tif (!text) return \"\";\n\tconst clean = text.replace(/[#*_`>\\[\\]!()-]/g, \"\").trim();\n\treturn clean.length > maxLen ? `${clean.slice(0, maxLen)}...` : clean;\n}\n\nfunction ContentEntryCard({\n\tentry,\n\tonSelect,\n\tdisplay,\n}: {\n\tentry: ContentEntryItem;\n\tonSelect: (slug: string) => void;\n\tdisplay?: ContentTabDisplay;\n}) {\n\tconst { customFields } = entry;\n\n\t// Use display mapping if configured, otherwise auto-detect from common field names\n\tconst badge = display?.badgeField\n\t\t? customFields[display.badgeField] ?? null\n\t\t: customFields.version ?? customFields.priority ?? customFields.type ?? null;\n\n\tconst subtitleValue = display?.subtitleField\n\t\t? (display.subtitleField === \"body\" ? entry.body : customFields[display.subtitleField]) ?? null\n\t\t: customFields.excerpt ?? customFields.summary ?? customFields.description ?? null;\n\n\tconst preview = subtitleValue ? truncateText(subtitleValue) : truncateText(entry.body);\n\n\treturn (\n\t\t<button type=\"button\" className=\"hw-content-entry\" onClick={() => onSelect(entry.slug)}>\n\t\t\t<div className=\"hw-content-entry-main\">\n\t\t\t\t<div className=\"hw-content-entry-text\">\n\t\t\t\t\t<span className=\"hw-content-entry-title\">{entry.title}</span>\n\t\t\t\t\t{preview && (\n\t\t\t\t\t\t<span className=\"hw-content-entry-desc\">{preview}</span>\n\t\t\t\t\t)}\n\t\t\t\t\t{(badge || entry.publishedAt) && (\n\t\t\t\t\t\t<div className=\"hw-content-entry-meta\">\n\t\t\t\t\t\t\t{badge && <span className=\"hw-content-entry-badge\">{badge}</span>}\n\t\t\t\t\t\t\t{entry.publishedAt && (\n\t\t\t\t\t\t\t\t<span className=\"hw-content-entry-date\">{formatRelativeTime(entry.publishedAt)}</span>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<svg className=\"hw-content-entry-chevron\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n\t\t\t\t\t<polyline points=\"9 18 15 12 9 6\" />\n\t\t\t\t</svg>\n\t\t\t</div>\n\t\t</button>\n\t);\n}\n","import type { WidgetContentTab } from \"@helpway/widget-core\";\nimport { t } from \"@helpway/widget-core\";\nimport { useEffect, useRef } from \"react\";\nimport { useGroupedContentTab } from \"../../hooks/use-grouped-content-tab\";\nimport type { ContentEntryItem } from \"../../hooks/use-content-tab\";\nimport { ContentDetailView } from \"./content-detail-view\";\nimport { ContentListView } from \"./content-list-view\";\n\n/**\n * Grouped content tab — category → items → detail drill-down.\n *\n * Three views managed by parent (DefaultWidget):\n * - subView = null → show categories\n * - subView = \"content-category\" → show items for activeCategory\n * - subView = \"content-detail\" → show item detail\n */\nexport function GroupedContentTabView({\n\ttab,\n\tsubView,\n\tdetailSlug,\n\tonSelectCategory,\n\tonSelectEntry,\n}: {\n\ttab: WidgetContentTab;\n\tsubView: string | null;\n\tdetailSlug: string | null;\n\tonSelectCategory: (category: ContentEntryItem) => void;\n\tonSelectEntry: (slug: string) => void;\n}) {\n\tconst {\n\t\tcategories,\n\t\tisCategoriesLoading,\n\t\titems,\n\t\tisItemsLoading,\n\t\titemsHasMore,\n\t\tactiveCategory,\n\t\tdetail,\n\t\tisLoadingDetail,\n\t\tinitFetch,\n\t\tselectCategory,\n\t\tsearchCategories,\n\t\tloadMoreItems,\n\t\tsearchItems,\n\t\tfetchDetail,\n\t\tclearCategory,\n\t} = useGroupedContentTab(tab.id);\n\n\t// Init fetch categories on mount\n\tuseEffect(() => {\n\t\tinitFetch();\n\t}, [initFetch]);\n\n\t// Fetch detail when slug changes\n\tuseEffect(() => {\n\t\tif (detailSlug && subView === \"content-detail\") {\n\t\t\tfetchDetail(detailSlug);\n\t\t}\n\t}, [detailSlug, subView, fetchDetail]);\n\n\t// Clean up hook state when navigating back to category list\n\tconst prevSubView = useRef(subView);\n\tuseEffect(() => {\n\t\tif (prevSubView.current === \"content-category\" && subView === null) {\n\t\t\tclearCategory();\n\t\t}\n\t\tprevSubView.current = subView;\n\t}, [subView, clearCategory]);\n\n\t// ── Detail view ──\n\tif (subView === \"content-detail\" && detailSlug) {\n\t\treturn <ContentDetailView entry={detail} isLoading={isLoadingDetail} />;\n\t}\n\n\t// ── Items list (within a category) ──\n\tif (subView === \"content-category\" && activeCategory) {\n\t\treturn (\n\t\t\t<ContentListView\n\t\t\t\tentries={items}\n\t\t\t\tisLoading={isItemsLoading}\n\t\t\t\thasMore={itemsHasMore}\n\t\t\t\tonSelect={onSelectEntry}\n\t\t\t\tonLoadMore={loadMoreItems}\n\t\t\t\tonSearch={searchItems}\n\t\t\t\tsearchPlaceholder={t(\"widget.search\")}\n\t\t\t\tdisplay={tab.display}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// ── Categories list (with search) ──\n\treturn (\n\t\t<ContentListView\n\t\t\tentries={categories}\n\t\t\tisLoading={isCategoriesLoading}\n\t\t\thasMore={false}\n\t\t\tonSelect={(slug) => {\n\t\t\t\tconst cat = categories.find((c) => c.slug === slug);\n\t\t\t\tif (cat) {\n\t\t\t\t\tselectCategory(cat);\n\t\t\t\t\tonSelectCategory(cat);\n\t\t\t\t}\n\t\t\t}}\n\t\t\tonLoadMore={() => {}}\n\t\t\tonSearch={searchCategories}\n\t\t\tsearchPlaceholder={t(\"widget.search\")}\n\t\t/>\n\t);\n}\n","import type { WidgetContentTab } from \"@helpway/widget-core\";\nimport { CONTENT_CACHE_TTL, getLocale } from \"@helpway/widget-core\";\nimport { useCallback, useRef, useState } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\nimport type { ContentEntryItem, ContentEntryDetail } from \"./use-content-tab\";\n\nconst EMPTY_TABS: WidgetContentTab[] = [];\n\n// ── Cache key helpers ──\n\nfunction categoriesKey(tabId: string, lang: string) {\n\treturn `grouped:${tabId}:${lang}:categories`;\n}\n\nfunction itemsKey(tabId: string, lang: string, groupSlug: string) {\n\treturn `grouped:${tabId}:${lang}:items:${groupSlug}`;\n}\n\nfunction detailKey(tabId: string, lang: string, slug: string) {\n\treturn `grouped:${tabId}:${lang}:detail:${slug}`;\n}\n\ninterface CachedItems {\n\titems: ContentEntryItem[];\n\thasMore: boolean;\n\tpage: number;\n}\n\nfunction readCache<T>(cache: Map<string, { data: unknown; ts: number }>, key: string): T | null {\n\tconst entry = cache.get(key);\n\tif (!entry) return null;\n\tif (Date.now() - entry.ts > CONTENT_CACHE_TTL) return null;\n\treturn entry.data as T;\n}\n\n/**\n * Hook for grouped content tabs (category → items drill-down).\n * Content is cached in the Zustand store so tab switches don't re-fetch.\n */\nexport function useGroupedContentTab(tabId: string) {\n\tconst { client, store } = useWidgetContext();\n\tconst contentTabs = useWidgetStore((s) => s.agentConfig?.contentTabs) ?? EMPTY_TABS;\n\tconst tab = contentTabs.find((t) => t.id === tabId) ?? null;\n\n\tconst lang = getLocale();\n\tconst cache = store.getState().contentCache;\n\n\t// ── Categories (top level) ──\n\tconst cachedCategories = readCache<ContentEntryItem[]>(cache, categoriesKey(tabId, lang));\n\tconst [categories, setCategories] = useState<ContentEntryItem[]>(cachedCategories ?? []);\n\tconst [isCategoriesLoading, setIsCategoriesLoading] = useState(false);\n\n\t// ── Items (within a category) ──\n\tconst [items, setItems] = useState<ContentEntryItem[]>([]);\n\tconst [isItemsLoading, setIsItemsLoading] = useState(false);\n\tconst [itemsHasMore, setItemsHasMore] = useState(false);\n\tconst itemsPageRef = useRef(1);\n\n\t// ── Detail (single item) ──\n\tconst [detail, setDetail] = useState<ContentEntryDetail | null>(null);\n\tconst [isLoadingDetail, setIsLoadingDetail] = useState(false);\n\n\t// ── Active category ──\n\tconst [activeCategory, setActiveCategory] = useState<ContentEntryItem | null>(null);\n\n\t// ── All categories (unfiltered, for client-side search) ──\n\tconst allCategoriesRef = useRef<ContentEntryItem[]>(cachedCategories ?? []);\n\n\t// ── Fetch categories ──\n\tconst fetchCategories = useCallback(async () => {\n\t\tif (!tab) return;\n\t\tsetIsCategoriesLoading(true);\n\t\ttry {\n\t\t\tconst result = await client.widget.getContent.query({\n\t\t\t\ttabId,\n\t\t\t\tpage: 1,\n\t\t\t\tlimit: 50,\n\t\t\t\tlanguage: getLocale(),\n\t\t\t});\n\t\t\tif (result.items) {\n\t\t\t\tallCategoriesRef.current = result.items;\n\t\t\t\tsetCategories(result.items);\n\t\t\t\tstore.getState().setContentCache(categoriesKey(tabId, getLocale()), result.items);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconsole.error(\"[useGroupedContentTab] categories error:\", err);\n\t\t} finally {\n\t\t\tsetIsCategoriesLoading(false);\n\t\t}\n\t}, [client, tabId, tab, store]);\n\n\t// Init — only fetch if cache was empty\n\tconst initFetch = useCallback(() => {\n\t\tif (tab && categories.length === 0) {\n\t\t\tfetchCategories();\n\t\t}\n\t}, [fetchCategories, tab, categories.length]);\n\n\t// ── Fetch items for a category ──\n\tconst fetchItems = useCallback(\n\t\tasync (opts?: { page?: number; search?: string; reset?: boolean; groupSlug?: string }) => {\n\t\t\tif (!tab?.itemsModelSlug) return;\n\t\t\tconst p = opts?.page ?? 1;\n\t\t\tconst reset = opts?.reset ?? p === 1;\n\n\t\t\tsetIsItemsLoading(true);\n\t\t\ttry {\n\t\t\t\tconst result = await client.widget.getContent.query({\n\t\t\t\t\ttabId,\n\t\t\t\t\tpage: p,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t\tsearch: opts?.search,\n\t\t\t\t\tgroupSlug: opts?.groupSlug,\n\t\t\t\t\titemsModel: tab.itemsModelSlug,\n\t\t\t\t\tlanguage: getLocale(),\n\t\t\t\t});\n\t\t\t\tif (result.items) {\n\t\t\t\t\tsetItems((prev) => {\n\t\t\t\t\t\tconst nextItems = reset ? result.items! : [...prev, ...result.items!];\n\t\t\t\t\t\tif (!opts?.search && opts?.groupSlug) {\n\t\t\t\t\t\t\tstore.getState().setContentCache(\n\t\t\t\t\t\t\t\titemsKey(tabId, getLocale(), opts.groupSlug),\n\t\t\t\t\t\t\t\t{ items: nextItems, hasMore: result.hasMore, page: p } satisfies CachedItems,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nextItems;\n\t\t\t\t\t});\n\t\t\t\t\tsetItemsHasMore(result.hasMore);\n\t\t\t\t\titemsPageRef.current = p;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useGroupedContentTab] items error:\", err);\n\t\t\t} finally {\n\t\t\t\tsetIsItemsLoading(false);\n\t\t\t}\n\t\t},\n\t\t[client, tabId, tab, store],\n\t);\n\n\t// ── Select a category → load items from cache or fetch ──\n\tconst selectCategory = useCallback(\n\t\t(category: ContentEntryItem) => {\n\t\t\tsetActiveCategory(category);\n\t\t\tsetDetail(null);\n\n\t\t\tconst cached = readCache<CachedItems>(\n\t\t\t\tstore.getState().contentCache,\n\t\t\t\titemsKey(tabId, getLocale(), category.slug),\n\t\t\t);\n\t\t\tif (cached) {\n\t\t\t\tsetItems(cached.items);\n\t\t\t\tsetItemsHasMore(cached.hasMore);\n\t\t\t\titemsPageRef.current = cached.page;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetItems([]);\n\t\t\tfetchItems({ page: 1, reset: true, groupSlug: category.slug });\n\t\t},\n\t\t[fetchItems, store, tabId],\n\t);\n\n\t// ── Load more items ──\n\tconst loadMoreItems = useCallback(() => {\n\t\tif (!itemsHasMore || isItemsLoading || !activeCategory) return;\n\t\tfetchItems({\n\t\t\tpage: itemsPageRef.current + 1,\n\t\t\tgroupSlug: activeCategory.slug,\n\t\t});\n\t}, [fetchItems, itemsHasMore, isItemsLoading, activeCategory]);\n\n\t// ── Search items (cross-category) ──\n\tconst searchItems = useCallback(\n\t\t(query: string) => {\n\t\t\tsetItems([]);\n\t\t\tfetchItems({\n\t\t\t\tpage: 1,\n\t\t\t\treset: true,\n\t\t\t\tsearch: query || undefined,\n\t\t\t\tgroupSlug: query ? undefined : activeCategory?.slug,\n\t\t\t});\n\t\t},\n\t\t[fetchItems, activeCategory],\n\t);\n\n\t// ── Fetch item detail ──\n\tconst fetchDetail = useCallback(\n\t\tasync (slug: string) => {\n\t\t\tif (!tab?.itemsModelSlug) return;\n\n\t\t\tconst cached = readCache<ContentEntryDetail>(\n\t\t\t\tstore.getState().contentCache,\n\t\t\t\tdetailKey(tabId, getLocale(), slug),\n\t\t\t);\n\t\t\tif (cached) {\n\t\t\t\tsetDetail(cached);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetIsLoadingDetail(true);\n\t\t\ttry {\n\t\t\t\tconst result = await client.widget.getContent.query({\n\t\t\t\t\ttabId,\n\t\t\t\t\tslug,\n\t\t\t\t\titemsModel: tab.itemsModelSlug,\n\t\t\t\t\tlanguage: getLocale(),\n\t\t\t\t});\n\t\t\t\tif (result.entry) {\n\t\t\t\t\tconst entry = result.entry as ContentEntryDetail;\n\t\t\t\t\tsetDetail(entry);\n\t\t\t\t\tstore.getState().setContentCache(\n\t\t\t\t\t\tdetailKey(tabId, getLocale(), slug),\n\t\t\t\t\t\tentry,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useGroupedContentTab] detail error:\", err);\n\t\t\t} finally {\n\t\t\t\tsetIsLoadingDetail(false);\n\t\t\t}\n\t\t},\n\t\t[client, tabId, tab, store],\n\t);\n\n\t// ── Search categories (client-side, instant) ──\n\tconst searchCategories = useCallback(\n\t\t(query: string) => {\n\t\t\tif (!query.trim()) {\n\t\t\t\tsetCategories(allCategoriesRef.current);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst q = query.toLowerCase();\n\t\t\tsetCategories(\n\t\t\t\tallCategoriesRef.current.filter((cat) =>\n\t\t\t\t\tcat.title.toLowerCase().includes(q) ||\n\t\t\t\t\t(cat.customFields.description ?? \"\").toLowerCase().includes(q),\n\t\t\t\t),\n\t\t\t);\n\t\t},\n\t\t[],\n\t);\n\n\tconst clearDetail = useCallback(() => {\n\t\tsetDetail(null);\n\t}, []);\n\n\tconst clearCategory = useCallback(() => {\n\t\tsetActiveCategory(null);\n\t\tsetItems([]);\n\t\tsetDetail(null);\n\t}, []);\n\n\treturn {\n\t\ttab,\n\t\tcategories,\n\t\tisCategoriesLoading,\n\t\titems,\n\t\tisItemsLoading,\n\t\titemsHasMore,\n\t\tactiveCategory,\n\t\tdetail,\n\t\tisLoadingDetail,\n\t\tinitFetch,\n\t\tselectCategory,\n\t\tsearchCategories,\n\t\tloadMoreItems,\n\t\tsearchItems,\n\t\tfetchDetail,\n\t\tclearDetail,\n\t\tclearCategory,\n\t};\n}\n","import {\n\tBookIcon,\n\tHelpCircleIcon,\n\tLightbulbIcon,\n\tMegaphoneIcon,\n\tNewspaperIcon,\n\tStarIcon,\n} from \"../icons\";\n\n/**\n * Maps icon string keys to Central Icons components.\n * Dashboard lets users pick from this set when configuring a content tab.\n * Falls back to BookIcon for unknown keys.\n */\nconst ICON_MAP: Record<string, React.FC> = {\n\tbook: BookIcon,\n\tmegaphone: MegaphoneIcon,\n\tlightbulb: LightbulbIcon,\n\t\"help-circle\": HelpCircleIcon,\n\tnewspaper: NewspaperIcon,\n\tstar: StarIcon,\n};\n\nexport function ContentTabIconComponent({ icon }: { icon: string }) {\n\tconst Icon = ICON_MAP[icon] ?? BookIcon;\n\treturn <Icon />;\n}\n","\"use client\";\n\nimport { t } from \"@helpway/widget-core\";\nimport type { MouseEvent, ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport { useWidgetStore } from \"../provider\";\nimport { XIcon } from \"./icons\";\nimport { stripMarkdown } from \"./strip-markdown\";\n\n/** Placement of the announcement stack — mirrors `MessagePreviewPlacement`. */\nexport type AnnouncementPreviewsPlacement = \"launcher\" | \"anchored\";\n\n/** Shape of a single announcement entry as it lives in the widget store. */\nexport interface AnnouncementPreviewEntry {\n\ttitle: string;\n\tbody: string | null;\n\tslug: string;\n\ttabId: string;\n\tbadge: string | null;\n}\n\nexport interface AnnouncementPreviewsProps {\n\t/** Called when the visitor taps an announcement card. Receives the\n\t * entry's slug + the parent tab id. The consumer decides what to\n\t * do — at minimum `setOpen(true)`, optionally deep-link into the\n\t * matching content tab + detail. */\n\tonOpen: (slug: string, tabId: string) => void;\n\t/** The avatar node shown in each card's header. Injected so the\n\t * component is decoupled from avatar resolution; pass\n\t * `<WidgetLogo />` for the SDK default. */\n\tavatar: ReactNode;\n\t/**\n\t * Outer positioning mode. `\"launcher\"` (default) keeps the stack\n\t * pinned above the floating bubble; `\"anchored\"` drops that and\n\t * lets the consumer's positioned wrapper place the stack — and\n\t * each card stretches to the wrapper width instead of the launcher\n\t * 300px (via the same `.hw-preview--anchored` modifier the\n\t * message preview uses).\n\t */\n\tplacement?: AnnouncementPreviewsPlacement;\n\t/**\n\t * Optional caption rendered as a separated footer beneath each\n\t * card (e.g. a \"via X\" provenance line). Omitted on the launcher\n\t * so its visual stays byte-identical to the original.\n\t */\n\tfooter?: ReactNode;\n}\n\n/**\n * `<AnnouncementPreviews>` — proactive \"new content\" cards shown when\n * the widget panel is closed and the visitor hasn't seen the latest\n * entries from a \"Promote new content\" tab yet. Stacks multiple\n * entries vertically.\n *\n * Extracted from the default widget so `hideLauncher` integrations can\n * surface the *exact same* cards next to their own UI instead of the\n * floating launcher. Visual/markup is byte-identical to the launcher\n * version — only the outer positioning is parameterised via\n * `placement`. Announcements never auto-dismiss (visitors need time to\n * read); they're cleared by tapping the card or the ✕.\n *\n * Must be rendered inside `<SupportProvider>`.\n */\nexport function AnnouncementPreviews({\n\tonOpen,\n\tavatar,\n\tplacement = \"launcher\",\n\tfooter,\n}: AnnouncementPreviewsProps) {\n\tconst previews = useWidgetStore((s) => s.announcementPreviews);\n\tconst dismissPreview = useWidgetStore((s) => s.dismissAnnouncementPreview);\n\tconst agentName = useWidgetStore((s) => s.agentConfig?.name) ?? \"Support\";\n\n\tif (previews.length === 0) return null;\n\n\tconst stackPlacementClass =\n\t\tplacement === \"anchored\" ? \"hw-preview-stack--anchored \" : \"\";\n\n\treturn (\n\t\t<div className={`hw-preview-stack ${stackPlacementClass}`.trim()}>\n\t\t\t{previews.map((preview) => (\n\t\t\t\t<AnnouncementPreviewItem\n\t\t\t\t\tkey={preview.slug}\n\t\t\t\t\tpreview={preview}\n\t\t\t\t\tagentName={agentName}\n\t\t\t\t\tavatar={avatar}\n\t\t\t\t\tplacement={placement}\n\t\t\t\t\tfooter={footer}\n\t\t\t\t\tonOpen={onOpen}\n\t\t\t\t\tonDismiss={(slug) => dismissPreview(slug)}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</div>\n\t);\n}\n\nfunction AnnouncementPreviewItem({\n\tpreview,\n\tagentName,\n\tavatar,\n\tplacement,\n\tfooter,\n\tonOpen,\n\tonDismiss,\n}: {\n\tpreview: AnnouncementPreviewEntry;\n\tagentName: string;\n\tavatar: ReactNode;\n\tplacement: AnnouncementPreviewsPlacement;\n\tfooter?: ReactNode;\n\tonOpen: (slug: string, tabId: string) => void;\n\tonDismiss: (slug: string) => void;\n}) {\n\tconst [closing, setClosing] = useState(false);\n\n\tconst handleClose = (e: MouseEvent) => {\n\t\te.stopPropagation();\n\t\tsetClosing(true);\n\t\tsetTimeout(() => {\n\t\t\tonDismiss(preview.slug);\n\t\t\tsetClosing(false);\n\t\t}, 200);\n\t};\n\n\tconst placementClass = placement === \"anchored\" ? \"hw-preview--anchored \" : \"\";\n\n\treturn (\n\t\t<div\n\t\t\tclassName={`hw-preview hw-preview--announcement ${placementClass}${closing ? \"hw-preview--closing\" : \"\"}`.trim()}\n\t\t\tonClick={() => onOpen(preview.slug, preview.tabId)}\n\t\t\trole=\"button\"\n\t\t\ttabIndex={0}\n\t\t>\n\t\t\t<div className=\"hw-preview-header\">\n\t\t\t\t<div className=\"hw-preview-avatar\">{avatar}</div>\n\t\t\t\t<div className=\"hw-preview-name\">{agentName}</div>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"hw-preview-close\"\n\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\taria-label={t(\"widget.aria_dismiss\")}\n\t\t\t\t>\n\t\t\t\t\t<XIcon size={20} />\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<div className=\"hw-preview-body hw-preview-body--title\">{preview.title}</div>\n\t\t\t{preview.body &&\n\t\t\t\t(() => {\n\t\t\t\t\tconst clean = stripMarkdown(preview.body);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div className=\"hw-preview-body hw-preview-body--desc\">\n\t\t\t\t\t\t\t{clean.length > 120 ? `${clean.slice(0, 120)}…` : clean}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t);\n\t\t\t\t})()}\n\t\t\t{preview.badge && (\n\t\t\t\t<div className=\"hw-announcement-badge\">{preview.badge}</div>\n\t\t\t)}\n\t\t\t{footer != null && footer !== false && (\n\t\t\t\t<div className=\"hw-preview-footer\">{footer}</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","/**\n * Strip the most common Markdown affordances so a body excerpt reads as\n * plain text inside a preview bubble. Intentionally minimal — covers\n * headings, bold/italic, lists, links, inline code, and newlines. Not\n * a full Markdown renderer; meant for short truncated descriptions\n * where the rendered styling would clash with the surrounding chrome.\n */\nexport function stripMarkdown(text: string): string {\n\treturn text\n\t\t.replace(/^#{1,6}\\s+/gm, \"\")\n\t\t.replace(/\\*\\*(.+?)\\*\\*/g, \"$1\")\n\t\t.replace(/\\*(.+?)\\*/g, \"$1\")\n\t\t.replace(/^[-*+]\\s+/gm, \"\")\n\t\t.replace(/\\[(.+?)\\]\\(.+?\\)/g, \"$1\")\n\t\t.replace(/`(.+?)`/g, \"$1\")\n\t\t.replace(/\\n{2,}/g, \" \")\n\t\t.replace(/\\n/g, \" \")\n\t\t.trim();\n}\n","import type { LinkPreviewPart, TimelineItemMetadata, TimelineItemPart } from \"@helpway/types\";\nimport { t } from \"@helpway/widget-core\";\nimport { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { closeDanglingMarkdown, handleCodeBlockClick, linkifyText, renderMarkdown } from \"./content/simple-markdown\";\n\ninterface MessageBubbleProps {\n\ttext: string;\n\tsender: \"visitor\" | \"team\" | \"ai\";\n\t/**\n\t * Explicit label for the meta row, overriding the sender's role. The widget's\n\t * own timeline never passes this — it labels by role — but a caller embedding\n\t * a single bubble may need to name someone.\n\t */\n\tsenderName?: string;\n\tparts?: TimelineItemPart[] | null;\n\ttimestamp?: string;\n\t/**\n\t * Whether this message closes a run from the same sender — the point where\n\t * the author's name belongs. Kept separate from `timestamp` so a clock label\n\t * that would only repeat the one above it can be dropped without taking the\n\t * signature with it.\n\t */\n\tshowAuthor?: boolean;\n\t/** Variant payload for interactive messages (quick replies, …). */\n\tmetadata?: TimelineItemMetadata | null;\n\t/** Called when the visitor taps a quick-reply option. */\n\tonQuickReplyTap?: (optionId: string, stepId: string) => void;\n\t/**\n\t * This bubble is a stream still arriving. Closes dangling markdown so an\n\t * unfinished ```fence does not flash as literal backticks, and shows the\n\t * caret.\n\t *\n\t * The stream is rendered through THIS component, not a hand-rolled copy of\n\t * its markup, so that the streamed bubble and the message that replaces it are\n\t * the same element type under the same key — React then reuses the DOM node\n\t * instead of tearing it down and mounting a replacement, which is what made\n\t * the answer visibly render a second time the moment it finished.\n\t */\n\tstreaming?: boolean;\n}\n\n/** Single message bubble — Intercom-style, renders text + image/file parts */\nexport function MessageBubble({\n\ttext,\n\tsender,\n\tsenderName,\n\tparts,\n\ttimestamp,\n\tshowAuthor,\n\tmetadata,\n\tonQuickReplyTap,\n\tstreaming,\n}: MessageBubbleProps) {\n\tconst senderClass = `hw-msg--${sender}`;\n\tconst bubbleRef = useRef<HTMLDivElement>(null);\n\n\tconst imageParts =\n\t\tparts?.filter((p): p is Extract<TimelineItemPart, { type: \"image\" }> => p.type === \"image\") ??\n\t\t[];\n\tconst fileParts =\n\t\tparts?.filter((p): p is Extract<TimelineItemPart, { type: \"file\" }> => p.type === \"file\") ?? [];\n\tconst linkPreviews =\n\t\tparts?.filter(\n\t\t\t(p): p is Extract<TimelineItemPart, { type: \"link-preview\" }> => p.type === \"link-preview\",\n\t\t) ?? [];\n\t// Where the answer came from. Shown as a short numbered list under the\n\t// message rather than a footnote block, so the visitor can check the\n\t// claim without leaving the thread.\n\tconst sources =\n\t\tparts?.filter(\n\t\t\t(p): p is Extract<TimelineItemPart, { type: \"source\" }> => p.type === \"source\",\n\t\t) ?? [];\n\tconst hasText = text.length > 0;\n\n\tuseEffect(() => {\n\t\tconst bubble = bubbleRef.current;\n\t\tif (!bubble || (sender !== \"ai\" && sender !== \"team\")) return;\n\t\tconst handleClick = (event: Event) => {\n\t\t\thandleCodeBlockClick(event, bubble);\n\t\t};\n\t\tbubble.addEventListener(\"click\", handleClick);\n\t\treturn () => {\n\t\t\tbubble.removeEventListener(\"click\", handleClick);\n\t\t};\n\t}, [sender]);\n\n\n\treturn (\n\t\t<div className={`hw-msg ${senderClass}`}>\n\t\t\t<div className=\"hw-msg-body\">\n\t\t\t\t{/* Image attachments */}\n\t\t\t\t{imageParts.length > 0 && (\n\t\t\t\t\t<div className=\"hw-msg-images\">\n\t\t\t\t\t\t{imageParts.map((img, i) => (\n\t\t\t\t\t\t\t<PreviewableThumbnail key={i} src={img.url} />\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t{/* Text bubble.\n\t\t\t\t - AI + team messages → renderMarkdown (team composer uses Tiptap → markdown output).\n\t\t\t\t - Visitor messages → linkifyText (widget composer is plain text).\n\t\t\t\t renderMarkdown escapes HTML entities first (&, <, >), so raw HTML cannot be injected.\n\t\t\t\t See packages/widget-react/src/themed/content/simple-markdown.ts for the safety guarantee. */}\n\t\t\t\t{hasText && (\n\t\t\t\t\t<div className=\"hw-msg-bubble\" ref={bubbleRef}>\n\t\t\t\t\t\t{sender === \"ai\" || sender === \"team\" ? (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t\t\t\t\t\t__html: renderMarkdown(streaming ? closeDanglingMarkdown(text) : text),\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<span dangerouslySetInnerHTML={{ __html: linkifyText(text) }} />\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{streaming && <span className=\"hw-streaming-cursor\" />}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t{/* File attachments */}\n\t\t\t\t{fileParts.length > 0 && (\n\t\t\t\t\t<div className=\"hw-msg-files\">\n\t\t\t\t\t\t{fileParts.map((file, i) => (\n\t\t\t\t\t\t\t<FileCard key={i} file={file} />\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t{/* Link preview cards */}\n\t\t\t\t{linkPreviews.length > 0 && (\n\t\t\t\t\t<div className=\"hw-msg-links\">\n\t\t\t\t\t\t{linkPreviews.map((lp, i) => (\n\t\t\t\t\t\t\t<LinkPreviewCard key={i} preview={lp} />\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t{/* Sources for the answer above */}\n\t\t\t\t{sources.length > 0 && (\n\t\t\t\t\t<div className=\"hw-sources\">\n\t\t\t\t\t\t{sources.map((src, i) =>\n\t\t\t\t\t\t\tsrc.sourceUrl ? (\n\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\tkey={src.knowledgeId}\n\t\t\t\t\t\t\t\t\thref={src.sourceUrl}\n\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\tclassName=\"hw-source\"\n\t\t\t\t\t\t\t\t\tonClick={(e) => e.stopPropagation()}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span className=\"hw-source-n\">{i + 1}</span>\n\t\t\t\t\t\t\t\t\t<span className=\"hw-source-title\">{src.title}</span>\n\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<div key={src.knowledgeId} className=\"hw-source\">\n\t\t\t\t\t\t\t\t\t<span className=\"hw-source-n\">{i + 1}</span>\n\t\t\t\t\t\t\t\t\t<span className=\"hw-source-title\">{src.title}</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t{/* Quick reply buttons — workflow is paused awaiting visitor input.\n\t\t\t\t Disabled when metadata.cancelled is set (visitor typed instead). */}\n\t\t\t\t{metadata?.kind === \"quick_replies\" && (\n\t\t\t\t\t<QuickReplyButtons metadata={metadata} onTap={onQuickReplyTap} />\n\t\t\t\t)}\n\n\t\t\t\t{/* Clock only, last message of a run.\n\n\t\t\t\t This row has now been wrong three ways, and the third is worth\n\t\t\t\t recording so it does not come back. Printing the sender's NAME\n\t\t\t\t repeated whoever the header already showed. Printing nothing left the\n\t\t\t\t clock alone under a paragraph, reading as debris. Printing the ROLE —\n\t\t\t\t \"AI agent\" — was the answer to a question the reader had already\n\t\t\t\t answered: they opened a chat widget whose header carries the agent's\n\t\t\t\t name and avatar, so being told an agent replied is not news either.\n\t\t\t\t Tested on a real thread it reads as a label with nothing to label.\n\n\t\t\t\t So the row carries the one thing that is genuinely not on screen\n\t\t\t\t anywhere else: when the message arrived. And since a repeated clock\n\t\t\t\t is dropped upstream, most runs end with no row at all — which is the\n\t\t\t\t correct amount of chrome under an answer.\n\n\t\t\t\t `senderName` still overrides, for a caller rendering one bubble\n\t\t\t\t outside the timeline; the timeline itself never passes it. */}\n\t\t\t\t{(() => {\n\t\t\t\t\tconst isVisitor = sender === \"visitor\";\n\t\t\t\t\tconst lead = isVisitor ? null : (senderName ?? null);\n\t\t\t\t\tconst withLead = (showAuthor ?? !!timestamp) && !!lead;\n\t\t\t\t\tif (!withLead && !timestamp) return null;\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div className=\"hw-msg-meta\">\n\t\t\t\t\t\t\t{withLead && <span className=\"hw-msg-author\">{lead}</span>}\n\t\t\t\t\t\t\t{withLead && timestamp && <span className=\"hw-msg-meta-sep\">·</span>}\n\t\t\t\t\t\t\t{timestamp && <span className=\"hw-msg-time\">{timestamp}</span>}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t);\n\t\t\t\t})()}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ── Quick reply buttons (interactive workflow) ────────\n\nfunction QuickReplyButtons({\n\tmetadata,\n\tonTap,\n}: {\n\tmetadata: Extract<TimelineItemMetadata, { kind: \"quick_replies\" }>;\n\tonTap?: (optionId: string, stepId: string) => void;\n}) {\n\tconst [tappedId, setTappedId] = useState<string | null>(null);\n\tconst isLocked = metadata.cancelled || tappedId !== null;\n\n\tconst handleTap = (optionId: string) => {\n\t\tif (isLocked) return;\n\t\tsetTappedId(optionId);\n\t\tonTap?.(optionId, metadata.stepId);\n\t};\n\n\treturn (\n\t\t<div\n\t\t\tclassName=\"hw-quick-replies\"\n\t\t\tdata-cancelled={metadata.cancelled ? \"true\" : undefined}\n\t\t>\n\t\t\t{metadata.options.map((opt) => {\n\t\t\t\tconst isTapped = tappedId === opt.id;\n\t\t\t\treturn (\n\t\t\t\t\t<button\n\t\t\t\t\t\tkey={opt.id}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"hw-quick-reply-btn\"\n\t\t\t\t\t\tdata-tapped={isTapped ? \"true\" : undefined}\n\t\t\t\t\t\tdisabled={isLocked}\n\t\t\t\t\t\tonClick={() => handleTap(opt.id)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{opt.label}\n\t\t\t\t\t</button>\n\t\t\t\t);\n\t\t\t})}\n\t\t</div>\n\t);\n}\n\n// ── Previewable thumbnail (image) ────────────────\n\nfunction PreviewableThumbnail({ src }: { src: string }) {\n\tconst [hover, setHover] = useState(false);\n\tconst ref = useRef<HTMLAnchorElement>(null);\n\n\treturn (\n\t\t<>\n\t\t\t<a\n\t\t\t\tref={ref}\n\t\t\t\thref={src}\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tclassName=\"hw-msg-image-link\"\n\t\t\t\taria-label={t(\"widget.aria_open_image\")}\n\t\t\t\tonMouseEnter={() => setHover(true)}\n\t\t\t\tonMouseLeave={() => setHover(false)}\n\t\t\t>\n\t\t\t\t{/* alt=\"\" is right — the image is decorative inside a labelled\n\t\t\t\t link — but that leaves the anchor itself nameless, so the\n\t\t\t\t label goes on the anchor. */}\n\t\t\t\t<img src={src} alt=\"\" className=\"hw-msg-image\" loading=\"lazy\" />\n\t\t\t</a>\n\t\t\t{hover && <AnchoredPreview src={src} anchorRef={ref} href={src} />}\n\t\t</>\n\t);\n}\n\n// ── File card with hover preview for previewable types ───\n\nconst PREVIEWABLE_EXTS = new Set([\"pdf\", \"csv\", \"png\", \"jpg\", \"jpeg\", \"gif\", \"webp\", \"svg\"]);\n\nfunction FileCard({ file }: { file: Extract<TimelineItemPart, { type: \"file\" }> }) {\n\tconst [hover, setHover] = useState(false);\n\tconst ref = useRef<HTMLAnchorElement>(null);\n\tconst ext = file.fileName.split(\".\").pop()?.toLowerCase() ?? \"\";\n\tconst isPreviewable = PREVIEWABLE_EXTS.has(ext);\n\tconst isImage = file.mimeType.startsWith(\"image/\");\n\n\treturn (\n\t\t<>\n\t\t\t<a\n\t\t\t\tref={ref}\n\t\t\t\thref={file.url}\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tclassName=\"hw-msg-file\"\n\t\t\t\tonMouseEnter={() => isPreviewable && setHover(true)}\n\t\t\t\tonMouseLeave={() => setHover(false)}\n\t\t\t>\n\t\t\t\t<span className=\"hw-msg-file-icon\">\n\t\t\t\t\t<FileTypeIcon ext={ext} />\n\t\t\t\t</span>\n\t\t\t\t<span className=\"hw-msg-file-info\">\n\t\t\t\t\t<span className=\"hw-msg-file-name\">{file.fileName}</span>\n\t\t\t\t\t<span className=\"hw-msg-file-size\">{formatFileSize(file.fileSize)}</span>\n\t\t\t\t</span>\n\t\t\t</a>\n\t\t\t{hover &&\n\t\t\t\tisPreviewable &&\n\t\t\t\t(isImage ? (\n\t\t\t\t\t<AnchoredPreview src={file.url} anchorRef={ref} href={file.url} />\n\t\t\t\t) : (\n\t\t\t\t\t<AnchoredDocPreview fileName={file.fileName} ext={ext} anchorRef={ref} href={file.url} />\n\t\t\t\t))}\n\t\t</>\n\t);\n}\n\n// ── Anchored preview — card popover above the element ──\n\nexport function AnchoredPreview({\n\tsrc,\n\tanchorRef,\n\thref,\n\tonOpen,\n}: {\n\tsrc: string;\n\tanchorRef: React.RefObject<HTMLElement | null>;\n\thref?: string;\n\tonOpen?: () => void;\n}) {\n\tconst [style, setStyle] = useState<React.CSSProperties>({ opacity: 0 });\n\tconst [portalTarget, setPortalTarget] = useState<Element | DocumentFragment | null>(null);\n\n\tuseLayoutEffect(() => {\n\t\tconst anchor = anchorRef.current;\n\t\tif (!anchor) return;\n\n\t\tconst rect = anchor.getBoundingClientRect();\n\t\tconst pw = 260;\n\t\tconst gap = 8;\n\t\tconst vw = window.innerWidth;\n\n\t\tlet left = rect.left + rect.width / 2 - pw / 2;\n\t\tif (left < 8) left = 8;\n\t\tif (left + pw > vw - 8) left = vw - pw - 8;\n\n\t\tconst estimatedH = 200;\n\t\tlet top = rect.top - estimatedH - gap;\n\t\tif (top < 8) top = rect.bottom + gap;\n\n\t\tsetStyle({ left, top, width: pw, opacity: 1 });\n\t\t// Portal into the same root as the anchor so shadow-DOM widgets keep\n\t\t// --hw-* CSS token inheritance and the preview participates in the\n\t\t// widget's z-index stack. Falls back to document.body when the widget\n\t\t// isn't shadow-encapsulated.\n\t\tconst root = anchor.getRootNode();\n\t\tsetPortalTarget(root instanceof ShadowRoot ? root : document.body);\n\t}, [anchorRef]);\n\n\tconst handleClick = () => {\n\t\tif (onOpen) onOpen();\n\t\t// noopener: without it the opened page gets a handle on window.opener\n\t\t// and can navigate the host page out from under the visitor.\n\t\telse if (href) window.open(href, \"_blank\", \"noopener,noreferrer\");\n\t};\n\n\tif (!portalTarget) return null;\n\n\treturn createPortal(\n\t\t<div className=\"hw-hover-preview\" style={style} onClick={handleClick}>\n\t\t\t<img src={src} alt=\"\" className=\"hw-hover-preview-img\" />\n\t\t</div>,\n\t\tportalTarget,\n\t);\n}\n\n// ── Document preview popover (PDF, CSV) ──────────\n\nfunction AnchoredDocPreview({\n\tfileName,\n\text,\n\tanchorRef,\n\thref,\n}: {\n\tfileName: string;\n\text: string;\n\tanchorRef: React.RefObject<HTMLElement | null>;\n\thref: string;\n}) {\n\tconst [style, setStyle] = useState<React.CSSProperties>({ opacity: 0 });\n\tconst [portalTarget, setPortalTarget] = useState<Element | DocumentFragment | null>(null);\n\n\tuseLayoutEffect(() => {\n\t\tconst anchor = anchorRef.current;\n\t\tif (!anchor) return;\n\n\t\tconst rect = anchor.getBoundingClientRect();\n\t\tconst pw = 220;\n\t\tconst ph = 80;\n\t\tconst gap = 8;\n\t\tconst vw = window.innerWidth;\n\n\t\tlet left = rect.left + rect.width / 2 - pw / 2;\n\t\tif (left < 8) left = 8;\n\t\tif (left + pw > vw - 8) left = vw - pw - 8;\n\n\t\tlet top = rect.top - ph - gap;\n\t\tif (top < 8) top = rect.bottom + gap;\n\n\t\tsetStyle({ left, top, width: pw, opacity: 1 });\n\t\tconst root = anchor.getRootNode();\n\t\tsetPortalTarget(root instanceof ShadowRoot ? root : document.body);\n\t}, [anchorRef]);\n\n\tif (!portalTarget) return null;\n\n\treturn createPortal(\n\t\t<div\n\t\t\tclassName=\"hw-hover-preview hw-hover-preview--doc\"\n\t\t\tstyle={style}\n\t\t\tonClick={() => window.open(href, \"_blank\", \"noopener,noreferrer\")}\n\t\t>\n\t\t\t<div className=\"hw-hover-preview-doc-icon\">\n\t\t\t\t<FileTypeIcon ext={ext} />\n\t\t\t</div>\n\t\t\t<div className=\"hw-hover-preview-doc-info\">\n\t\t\t\t<span className=\"hw-hover-preview-doc-name\">{fileName}</span>\n\t\t\t\t<span className=\"hw-hover-preview-doc-hint\">{t(\"widget.click_to_open\")}</span>\n\t\t\t</div>\n\t\t</div>,\n\t\tportalTarget,\n\t);\n}\n\n// ── Helpers ──────────────────────────────────────\n\nfunction formatFileSize(bytes: number): string {\n\tif (bytes < 1024) return `${bytes} B`;\n\tif (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} KB`;\n\treturn `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n// Module scope: the palette never varies, so rebuilding it per render was\n// allocation for nothing.\nconst FILE_TYPE_COLORS: Record<string, string> = {\n\tpdf: \"#ef4444\",\n\tcsv: \"#22c55e\",\n\tdoc: \"#3b82f6\",\n\tdocx: \"#3b82f6\",\n\txls: \"#22c55e\",\n\txlsx: \"#22c55e\",\n\ttxt: \"#6b7280\",\n\tzip: \"#f59e0b\",\n};\n\nfunction FileTypeIcon({ ext }: { ext: string }) {\n\tconst color = FILE_TYPE_COLORS[ext] ?? \"currentColor\";\n\n\treturn (\n\t\t<svg\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke={color}\n\t\t\tstrokeWidth={1.5}\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t>\n\t\t\t<path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n\t\t\t<polyline points=\"14 2 14 8 20 8\" />\n\t\t\t{ext === \"pdf\" && (\n\t\t\t\t<text x=\"8\" y=\"18\" fontSize=\"6\" fill={color} stroke=\"none\" fontWeight=\"700\">\n\t\t\t\t\tPDF\n\t\t\t\t</text>\n\t\t\t)}\n\t\t\t{ext === \"csv\" && (\n\t\t\t\t<text x=\"7\" y=\"18\" fontSize=\"6\" fill={color} stroke=\"none\" fontWeight=\"700\">\n\t\t\t\t\tCSV\n\t\t\t\t</text>\n\t\t\t)}\n\t\t</svg>\n\t);\n}\n\n// ── Link preview card (Intercom-style) ──────────────\n\nfunction LinkPreviewCard({ preview }: { preview: LinkPreviewPart }) {\n\tconst hostname = (() => {\n\t\ttry { return new URL(preview.url).hostname; } catch { return preview.url; }\n\t})();\n\treturn (\n\t\t<a\n\t\t\thref={preview.url}\n\t\t\ttarget=\"_blank\"\n\t\t\trel=\"noopener noreferrer\"\n\t\t\tclassName=\"hw-link-preview\"\n\t\t\tonClick={(e) => e.stopPropagation()}\n\t\t>\n\t\t\t{preview.imageUrl && (\n\t\t\t\t<img\n\t\t\t\t\tsrc={preview.imageUrl}\n\t\t\t\t\talt=\"\"\n\t\t\t\t\tclassName=\"hw-link-preview-img\"\n\t\t\t\t\tloading=\"lazy\"\n\t\t\t\t\tonError={(e) => { (e.target as HTMLImageElement).style.display = \"none\"; }}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<div className=\"hw-link-preview-body\">\n\t\t\t\t{preview.favicon && (\n\t\t\t\t\t<img\n\t\t\t\t\t\tsrc={preview.favicon}\n\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\tclassName=\"hw-link-preview-favicon\"\n\t\t\t\t\t\twidth={16}\n\t\t\t\t\t\theight={16}\n\t\t\t\t\t\tonError={(e) => { (e.target as HTMLImageElement).style.display = \"none\"; }}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t{preview.title && <div className=\"hw-link-preview-title\">{preview.title}</div>}\n\t\t\t\t{preview.description && (\n\t\t\t\t\t<div className=\"hw-link-preview-desc\">{preview.description.slice(0, 120)}</div>\n\t\t\t\t)}\n\t\t\t\t<div className=\"hw-link-preview-url\">{hostname}</div>\n\t\t\t</div>\n\t\t</a>\n\t);\n}\n","import type { TimelineItem, TimelineItemMetadata, TimelineItemPart } from \"@helpway/types\";\nimport { getInitials, getLocale, streamingKeyFor, t } from \"@helpway/widget-core\";\nimport React, { useEffect, useRef } from \"react\";\nimport { useWidgetClient, useWidgetStore } from \"../provider\";\nimport { MessageBubble } from \"./message-bubble\";\n\nfunction parseParts(raw: TimelineItemPart[] | string | null): TimelineItemPart[] | null {\n\tif (!raw) return null;\n\tif (Array.isArray(raw)) return raw;\n\ttry {\n\t\tconst parsed = JSON.parse(raw);\n\t\treturn Array.isArray(parsed) ? parsed : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Tolerate both shapes: when the API hydrates metadata it's already an\n * object; when it round-trips through CF tRPC over the wire it can land\n * as a JSON string. parseMetadata covers both.\n */\nfunction parseMetadata(\n\traw: TimelineItemMetadata | string | null | undefined,\n): TimelineItemMetadata | null {\n\tif (!raw) return null;\n\tif (typeof raw === \"object\") return raw;\n\ttry {\n\t\tconst parsed = JSON.parse(raw);\n\t\treturn parsed && typeof parsed === \"object\" ? (parsed as TimelineItemMetadata) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\ninterface MessageListProps {\n\titems: TimelineItem[];\n\tisTyping?: boolean;\n\tisAiProcessing?: boolean;\n\tstreamingText?: string;\n\thasMore?: boolean;\n\tisLoadingMore?: boolean;\n\tonLoadMore?: () => void;\n\t/** Slot rendered after all messages but before typing indicators (e.g. email prompt) */\n\trenderAfterMessages?: React.ReactNode;\n}\n\n/** Timeline with date separators, typing indicator, infinite scroll, and AI processing state */\nexport function MessageList({\n\titems,\n\tisTyping,\n\tisAiProcessing,\n\tstreamingText,\n\thasMore,\n\tisLoadingMore,\n\tonLoadMore,\n\trenderAfterMessages,\n}: MessageListProps) {\n\tconst bottomRef = useRef<HTMLDivElement>(null);\n\tconst topRef = useRef<HTMLDivElement>(null);\n\tconst containerRef = useRef<HTMLDivElement>(null);\n\tconst prevItemCountRef = useRef(items.length);\n\tconst isInitialLoadRef = useRef(true);\n\t/** Whether a streamed bubble was on screen at the previous render. */\n\tconst hadStreamRef = useRef(false);\n\t/* No sender-name plumbing here any more. The timeline labels a message by the\n\t sender's ROLE, which MessageBubble derives on its own, so this file no longer\n\t needs to know who the header is naming or what the AI is called — and the\n\t name-vs-header comparison that used to live here, with its own drifting copy\n\t of the header's resolution chain, is gone with it. useHeaderIdentity still\n\t exists for the header itself, in default-widget. */\n\tconst client = useWidgetClient();\n\tconst activeConversationId = useWidgetStore((s) => s.activeConversationId);\n\n\tconst handleQuickReplyTap = React.useCallback(\n\t\t(optionId: string, stepId: string) => {\n\t\t\tif (!activeConversationId) return;\n\t\t\t// Fire-and-forget — orchestrator runs the resume in the background\n\t\t\t// and emits new messages over WebSocket. Failure is swallowed so\n\t\t\t// the visitor never sees a tRPC error toast for this UX action.\n\t\t\tclient.widget.workflowReply\n\t\t\t\t.mutate({ conversationId: activeConversationId, stepId, optionId })\n\t\t\t\t.catch((err: unknown) => {\n\t\t\t\t\tconsole.warn(\"[helpway] workflowReply failed:\", err);\n\t\t\t\t});\n\t\t},\n\t\t[client, activeConversationId],\n\t);\n\n\t// Auto-scroll to bottom on new messages (but NOT when loading older ones at top)\n\tuseEffect(() => {\n\t\tconst prevCount = prevItemCountRef.current;\n\t\tconst newCount = items.length;\n\t\tprevItemCountRef.current = newCount;\n\n\t\t// Initial load or new messages added at the end → scroll to bottom\n\t\tif (isInitialLoadRef.current || newCount > prevCount) {\n\t\t\t// Only scroll if the new items were appended (not prepended)\n\t\t\tconst lastItem = items[items.length - 1];\n\t\t\tconst prevLastItem = prevCount > 0 ? items[prevCount - 1] : null;\n\n\t\t\tif (isInitialLoadRef.current || !prevLastItem || lastItem?.id !== prevLastItem?.id) {\n\t\t\t\t/* A message that replaces a stream is not new content arriving — it is\n\t\t\t\t the same text, already at the bottom, changing which component owns\n\t\t\t\t it. Animating to a position the reader is already at is the small\n\t\t\t\t slide they notice at the end of every answer. Jump instead. */\n\t\t\t\tconst replacedAStream = hadStreamRef.current;\n\t\t\t\tbottomRef.current?.scrollIntoView({\n\t\t\t\t\tbehavior: isInitialLoadRef.current || replacedAStream ? \"instant\" : \"smooth\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tisInitialLoadRef.current = false;\n\t\t}\n\t}, [items]);\n\n\t/* Follow the answer as it is written.\n\t\n\t The scroll effect above only fires when `items` changes, so nothing moved\n\t while a stream grew: the text ran past the bottom of the panel and the\n\t reader watched a sentence get cut off mid-word until the message finally\n\t landed. Streaming grows the same node continuously, which is not an items\n\t change, so it needs its own follow.\n\t\n\t \"instant\", not \"smooth\": this runs on every chunk, and a smooth scroll\n\t restarted a few times a second fights itself and never arrives.\n\t\n\t Also the read the items effect depends on — whether the render it is\n\t reacting to came out of a stream finishing. */\n\tuseEffect(() => {\n\t\tif (streamingText) {\n\t\t\tbottomRef.current?.scrollIntoView({ behavior: \"instant\" as ScrollBehavior });\n\t\t}\n\t\thadStreamRef.current = !!streamingText;\n\t}, [streamingText]);\n\n\t// Scroll to bottom when typing/AI indicators appear\n\tuseEffect(() => {\n\t\tif (isTyping || isAiProcessing) {\n\t\t\tbottomRef.current?.scrollIntoView({ behavior: \"smooth\" });\n\t\t}\n\t}, [isTyping, isAiProcessing]);\n\n\t// Infinite scroll — IntersectionObserver on the top sentinel\n\tuseEffect(() => {\n\t\tif (!hasMore || !onLoadMore || !topRef.current) return;\n\n\t\tconst observer = new IntersectionObserver(\n\t\t\t(entries) => {\n\t\t\t\tif (entries[0]?.isIntersecting && !isLoadingMore) {\n\t\t\t\t\t// Save scroll position before loading\n\t\t\t\t\tconst container = containerRef.current;\n\t\t\t\t\tconst prevScrollHeight = container?.scrollHeight ?? 0;\n\t\t\t\t\tconst prevScrollTop = container?.scrollTop ?? 0;\n\n\t\t\t\t\tonLoadMore();\n\n\t\t\t\t\t// Restore scroll position after DOM update (next frame)\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tif (container) {\n\t\t\t\t\t\t\tconst newScrollHeight = container.scrollHeight;\n\t\t\t\t\t\t\tcontainer.scrollTop = prevScrollTop + (newScrollHeight - prevScrollHeight);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ root: containerRef.current, threshold: 0.1 },\n\t\t);\n\n\t\tobserver.observe(topRef.current);\n\t\treturn () => observer.disconnect();\n\t}, [hasMore, onLoadMore, isLoadingMore]);\n\n\tif (items.length === 0) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName=\"hw-messages\"\n\t\t\t\trole=\"log\"\n\t\t\t\taria-label={t(\"widget.aria_messages\")}\n\t\t\t\taria-live=\"polite\"\n\t\t\t>\n\t\t\t\t<div className=\"hw-empty\">\n\t\t\t\t\t<div className=\"hw-empty-icon\">\n\t\t\t\t\t\t<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.5}>\n\t\t\t\t\t\t\t<path d=\"M7.9 20A9 9 0 1 0 4 16.1L2 22Z\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"hw-empty-text\">{t(\"widget.start_a_conversation\")}</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\tlet lastDateKey = \"\";\n\t// Stable \"today\" key (YYYY-MM-DD in local time) for separator gating.\n\t// We HIDE the separator for today entirely — matches Intercom/WhatsApp:\n\t// the date is implicit when \"now\", and showing it on every fresh\n\t// conversation creates a jarring vertical jump as the view fills in.\n\tconst todayKey = new Date().toLocaleDateString(\"en-CA\"); // en-CA is YYYY-MM-DD\n\tconst yesterday = new Date();\n\tyesterday.setDate(yesterday.getDate() - 1);\n\tconst yesterdayKey = yesterday.toLocaleDateString(\"en-CA\");\n\n\treturn (\n\t\t<div\n\t\t\tref={containerRef}\n\t\t\tclassName=\"hw-messages\"\n\t\t\trole=\"log\"\n\t\t\taria-label={t(\"widget.aria_messages\")}\n\t\t\taria-live=\"polite\"\n\t\t>\n\t\t\t{/* Top sentinel for infinite scroll */}\n\t\t\t<div ref={topRef} className=\"hw-load-more-trigger\">\n\t\t\t\t{isLoadingMore && (\n\t\t\t\t\t<div className=\"hw-load-more-spinner\">\n\t\t\t\t\t\t<div />\n\t\t\t\t\t\t<div />\n\t\t\t\t\t\t<div />\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t{[\n\t\t\t\t...items.map((item) => {\n\t\t\t\t\tif (item.type === \"event\") {\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<EventCard\n\t\t\t\t\t\t\t\tkey={(item as unknown as { _stableKey?: string })._stableKey ?? item.id}\n\t\t\t\t\t\t\t\ttext={item.text ?? \"\"}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Date separator — bucket by local YYYY-MM-DD; skip rendering\n\t\t\t\t\t// when the bucket is \"today\" so today's chats stay flush at the top.\n\t\t\t\t\tconst itemDate = new Date(item.createdAt);\n\t\t\t\t\tconst dateKey = itemDate.toLocaleDateString(\"en-CA\");\n\t\t\t\t\tconst isNewBucket = dateKey !== lastDateKey;\n\t\t\t\t\tif (isNewBucket) lastDateKey = dateKey;\n\t\t\t\t\tconst showDateSep = isNewBucket && dateKey !== todayKey;\n\t\t\t\t\tconst dateLabel =\n\t\t\t\t\t\tdateKey === yesterdayKey\n\t\t\t\t\t\t\t? t(\"widget.yesterday\")\n\t\t\t\t\t\t\t: itemDate.toLocaleDateString(getLocale(), {\n\t\t\t\t\t\t\t\t\tweekday: \"long\",\n\t\t\t\t\t\t\t\t\tmonth: \"short\",\n\t\t\t\t\t\t\t\t\tday: \"numeric\",\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t// Determine sender\n\t\t\t\t\tconst sender = item.visitorId ? \"visitor\" : item.aiAgentId ? \"ai\" : \"team\";\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<React.Fragment\n\t\t\t\t\t\t\tkey={(item as unknown as { _stableKey?: string })._stableKey ?? item.id}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{showDateSep && (\n\t\t\t\t\t\t\t\t<div className=\"hw-date-sep\">\n\t\t\t\t\t\t\t\t\t<div className=\"hw-date-sep-line\" />\n\t\t\t\t\t\t\t\t\t<div className=\"hw-date-sep-text\">{dateLabel}</div>\n\t\t\t\t\t\t\t\t\t<div className=\"hw-date-sep-line\" />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t<MessageBubble\n\t\t\t\t\t\t\t\ttext={item.text ?? \"\"}\n\t\t\t\t\t\t\t\tsender={sender}\n\t\t\t\t\t\t\t\tparts={parseParts(item.parts)}\n\t\t\t\t\t\t\t\tmetadata={parseMetadata(\n\t\t\t\t\t\t\t\t\t(item as TimelineItem & { metadata?: TimelineItemMetadata | string | null })\n\t\t\t\t\t\t\t\t\t\t.metadata,\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tonQuickReplyTap={handleQuickReplyTap}\n\t\t\t\t\t\t\t\t/* No clock under a bubble, on either side. The day divider says\n\t\t\t\t\t\t\t which day; inside a day the minute a message landed is not\n\t\t\t\t\t\t\t something anyone came here to read, and printed under every run\n\t\t\t\t\t\t\t it was the last piece of chrome competing with the answer. Fin\n\t\t\t\t\t\t\t keeps relative time in the conversation LIST, where it helps you\n\t\t\t\t\t\t\t pick a thread, and out of the thread itself.\n\t\t\t\t\t\t\t MessageBubble still renders a meta row when a caller passes\n\t\t\t\t\t\t\t `timestamp` or `senderName`; the timeline passes neither. */\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</React.Fragment>\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\t\t/* The stream is the LAST ENTRY OF THIS SAME ARRAY, in the same\n\t\t\t\t React.Fragment wrapper, under the key the finished message arrives\n\t\t\t\t with (streamingKeyFor + addMessage). All three have to match or React\n\t\t\t\t cannot see the two as one thing:\n\n\t\t\t\t - same array, or they are different child slots\n\t\t\t\t - same key, or they are different children\n\t\t\t\t - same element type, or the key match is discarded anyway\n\n\t\t\t\t It had the key but not the other two: it sat after {items.map(...)}\n\t\t\t\t as its own slot, and it was a bare MessageBubble against the map's\n\t\t\t\t React.Fragment. So React tore it down and mounted the real bubble in\n\t\t\t\t its place, .hw-msg replayed hw-msg-appear (styles.css:1326), and the\n\t\t\t\t answer visibly animated in a second time just as it finished. */\n\t\t\t\t...(streamingText && activeConversationId\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t<React.Fragment key={streamingKeyFor(activeConversationId)}>\n\t\t\t\t\t\t\t\t{/* This null is load-bearing. React reconciles a Fragment's STATIC\n\t\t\t\t\t\t\t\t children by position, and the mapped entry's first child is\n\t\t\t\t\t\t\t\t `{showDateSep && <div className=\"hw-date-sep\">…}` — which\n\t\t\t\t\t\t\t\t evaluates to false for the last message but still occupies\n\t\t\t\t\t\t\t\t index 0. Without a placeholder here the bubble would sit at\n\t\t\t\t\t\t\t\t index 0 in the stream and index 1 in the message that replaces\n\t\t\t\t\t\t\t\t it, so React would remount it and hw-msg-appear would replay:\n\t\t\t\t\t\t\t\t the whole point of matching the key, undone by an off-by-one\n\t\t\t\t\t\t\t\t in the children array. */}\n\t\t\t\t\t\t\t\t{null}\n\t\t\t\t\t\t\t\t<MessageBubble text={streamingText} sender=\"ai\" parts={null} streaming />\n\t\t\t\t\t\t\t</React.Fragment>,\n\t\t\t\t\t\t]\n\t\t\t\t\t: []),\n\t\t\t]}\n\n\t\t\t{/* Slot for inline content after messages (e.g. email prompt) */}\n\t\t\t{renderAfterMessages}\n\n\t\t\t{/* ONE waiting indicator, for both reasons someone might be waiting.\n\n\t\t\t There were two, with byte-identical markup and mutually exclusive\n\t\t\t conditions — one for the AI, one for a teammate typing. So when the\n\t\t\t flags crossed, which they do on a normal reply (aiProcessingProgress\n\t\t\t sets both, aiStreamChunk clears both), React unmounted one element and\n\t\t\t mounted the other, and the dots restarted their bounce from frame zero.\n\t\t\t A reader cannot tell a restarted animation from a second wait\n\t\t\t beginning — which is exactly what it looked like.\n\n\t\t\t One node, one condition, so the flags can cross without the animation\n\t\t\t ever noticing. Streaming suppresses it: once text is arriving, the text\n\t\t\t IS the progress indicator.\n\n\t\t\t No name above the dots either: the answer that follows carries its own\n\t\t\t signature, and repeating it here printed the agent twice for one reply. */}\n\t\t\t{(isAiProcessing || isTyping) && !streamingText && (\n\t\t\t\t<div className=\"hw-typing\">\n\t\t\t\t\t<div className=\"hw-typing-dots\">\n\t\t\t\t\t\t<div className=\"hw-typing-dot\" />\n\t\t\t\t\t\t<div className=\"hw-typing-dot\" />\n\t\t\t\t\t\t<div className=\"hw-typing-dot\" />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t<div ref={bottomRef} />\n\t\t</div>\n\t);\n}\n\n// ── Event Card ────────────────────────────────────────\n\ninterface EventData {\n\taction: string;\n\tname: string;\n\timage?: string | null;\n}\n\nfunction parseEventData(text: string): EventData | null {\n\tif (!text.startsWith(\"{\")) return null;\n\ttry {\n\t\tconst data = JSON.parse(text);\n\t\tif (data.action && data.name) return data as EventData;\n\t} catch {\n\t\t/* plain text fallback */\n\t}\n\treturn null;\n}\n\nfunction EventCard({ text }: { text: string }) {\n\tconst data = parseEventData(text);\n\n\t// Structured event — rich card with avatar\n\tif (data) {\n\t\tconst message = data.action === \"joined\" ? t(\"widget.joined\") : t(\"widget.left\");\n\n\t\treturn (\n\t\t\t<div className=\"hw-event hw-event--card\">\n\t\t\t\t<div className=\"hw-event-avatar\">\n\t\t\t\t\t{data.image ? (\n\t\t\t\t\t\t<img src={data.image} alt=\"\" className=\"hw-event-avatar-img\" />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<span>{getInitials(data.name)}</span>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"hw-event-body\">\n\t\t\t\t\t<span className=\"hw-event-name\">{data.name}</span>{\" \"}\n\t\t\t\t\t<span className=\"hw-event-action\">{message}</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// Plain text event (resolve, reopen, etc.)\n\treturn (\n\t\t<div className=\"hw-event\">\n\t\t\t<div className=\"hw-event-text\">{text}</div>\n\t\t</div>\n\t);\n}\n","\"use client\";\n\nimport { t } from \"@helpway/widget-core\";\nimport type { MouseEvent, ReactNode } from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useWidgetStore } from \"../provider\";\nimport { XIcon } from \"./icons\";\n\n/** Where the preview is anchored — controls only the outer positioning. */\nexport type MessagePreviewPlacement = \"launcher\" | \"anchored\";\n\nexport interface MessagePreviewProps {\n\t/** Called when the visitor taps the preview (or a quick reply). The\n\t * active conversation is already switched to the one that pinged —\n\t * the consumer just has to reveal the chat surface. */\n\tonOpen: () => void;\n\t/**\n\t * The avatar node shown in the header. Injected by the consumer so\n\t * this component stays decoupled from avatar resolution — the default\n\t * widget passes `<WidgetLogo />`; a custom surface can pass its own.\n\t */\n\tavatar: ReactNode;\n\t/**\n\t * Outer positioning mode. `\"launcher\"` (default) keeps the original\n\t * absolute placement above the floating bubble — DefaultWidget relies\n\t * on this, so the default is unchanged. `\"anchored\"` drops the\n\t * absolute/bottom/right rules (via `hw-preview--anchored`) so a\n\t * consumer can pin it to their own trigger (e.g. a sidebar item).\n\t */\n\tplacement?: MessagePreviewPlacement;\n\t/**\n\t * Auto-dismiss delay in ms. Default `8000` (the launcher behaviour).\n\t * Pass `null` (or `0`) to keep the preview until the visitor acts on\n\t * it — useful for an anchored surface where it isn't competing with\n\t * page content for attention. Quick-reply previews never auto-dismiss\n\t * regardless, since the visitor needs time to choose.\n\t */\n\tautoDismissMs?: number | null;\n\t/**\n\t * Optional caption rendered as a separated footer beneath the message\n\t * (e.g. a source label like \"via Helpway\"). Omitted for the launcher\n\t * so its visual stays byte-identical to the original.\n\t */\n\tfooter?: ReactNode;\n}\n\n/**\n * `<MessagePreview>` — the proactive incoming-message bubble shown while\n * the chat surface is closed. Reads `incomingPreview` from the widget\n * store, auto-dismisses after 8s (unless quick replies are present), and\n * on tap switches to the pinging conversation before calling `onOpen`.\n *\n * Extracted from the default widget so `hideLauncher` integrations can\n * surface the *exact same* preview next to their own UI instead of the\n * floating launcher. Visual/markup is byte-identical to the launcher\n * version — only the outer positioning is parameterised via `placement`.\n *\n * Must be rendered inside `<SupportProvider>`.\n */\nexport function MessagePreview({\n\tonOpen,\n\tavatar,\n\tplacement = \"launcher\",\n\tautoDismissMs = 8000,\n\tfooter,\n}: MessagePreviewProps) {\n\tconst preview = useWidgetStore((s) => s.incomingPreview);\n\tconst dismissPreview = useWidgetStore((s) => s.dismissPreview);\n\tconst setActiveConversation = useWidgetStore((s) => s.setActiveConversation);\n\tconst agentName = useWidgetStore((s) => s.agentConfig?.name) ?? \"Support\";\n\t/* A human who replies signs with their own name. The card used to print the\n\t agent's name over every message, so a teammate's answer arrived as if the\n\t AI had written it — the one moment the visitor most needs to know a person\n\t picked this up. The AI keeps the agent name because for it that IS the\n\t sender. */\n\tconst senderName = preview?.senderName || agentName;\n\tconst senderImage = preview?.senderImage || null;\n\tconst [closing, setClosing] = useState(false);\n\n\t// Auto-dismiss after `autoDismissMs` (skip when quick replies are\n\t// present — visitor needs time to read and decide — or when the\n\t// consumer opted out with null/0 for a persistent anchored surface).\n\tuseEffect(() => {\n\t\tif (!preview || preview.quickReplies) return;\n\t\tif (autoDismissMs == null || autoDismissMs <= 0) return;\n\t\tconst timer = setTimeout(() => {\n\t\t\tsetClosing(true);\n\t\t\tsetTimeout(() => dismissPreview(), 200);\n\t\t}, autoDismissMs);\n\t\treturn () => clearTimeout(timer);\n\t}, [preview, dismissPreview, autoDismissMs]);\n\n\tif (!preview) return null;\n\n\tconst handleClose = (e: MouseEvent) => {\n\t\te.stopPropagation();\n\t\tsetClosing(true);\n\t\tsetTimeout(() => {\n\t\t\tdismissPreview();\n\t\t\tsetClosing(false);\n\t\t}, 200);\n\t};\n\n\tconst handleClick = () => {\n\t\t// Bubble click is an explicit \"I want to read this\" — open the\n\t\t// widget AND jump straight to the conversation that pinged. Without\n\t\t// the setActiveConversation, the visitor lands on the home screen\n\t\t// and has to find the unread row themselves.\n\t\tconst targetConvId = preview.conversationId;\n\t\tdismissPreview();\n\t\tsetActiveConversation(targetConvId);\n\t\tonOpen();\n\t};\n\n\tconst messages = preview.messages?.length ? preview.messages : [{ text: preview.text }];\n\tconst hasQr = preview.quickReplies && preview.quickReplies.options.length > 0;\n\n\tconst placementClass = placement === \"anchored\" ? \"hw-preview--anchored \" : \"\";\n\n\treturn (\n\t\t<div\n\t\t\tclassName={`hw-preview ${placementClass}${closing ? \"hw-preview--closing\" : \"\"}`}\n\t\t\tonClick={handleClick}\n\t\t\trole=\"button\"\n\t\t\ttabIndex={0}\n\t\t>\n\t\t\t<div className=\"hw-preview-header\">\n\t\t\t\t<div className=\"hw-preview-avatar\">\n\t\t\t\t\t{senderImage ? <img src={senderImage} alt=\"\" /> : avatar}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"hw-preview-name\">{senderName}</div>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"hw-preview-close\"\n\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\taria-label={t(\"widget.aria_dismiss\")}\n\t\t\t\t>\n\t\t\t\t\t<XIcon size={20} />\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t{messages.map((m, i) => (\n\t\t\t\t<div key={i} className=\"hw-preview-body\">\n\t\t\t\t\t{m.text}\n\t\t\t\t</div>\n\t\t\t))}\n\n\t\t\t{hasQr && (\n\t\t\t\t<>\n\t\t\t\t\t{preview.quickReplies!.prompt && (\n\t\t\t\t\t\t<div className=\"hw-preview-body\">{preview.quickReplies!.prompt}</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{/* Same classes the in-bubble list uses. There were two implementations\n\t\t\t\t\t of this control and they had drifted: the preview's copy sat on a\n\t\t\t\t\t transparent ground with a plain border, coloured by --hw-brand, and\n\t\t\t\t\t hovered on `var(--hw-hover, …)` — a token that does not exist\n\t\t\t\t\t anywhere in this stylesheet, so its hover was a hardcoded grey that\n\t\t\t\t\t ignored dark mode and the glass card entirely. One definition now,\n\t\t\t\t\t so the two cannot disagree about what a quick reply looks like. */}\n\t\t\t\t\t<div className=\"hw-preview-quick-replies hw-quick-replies\">\n\t\t\t\t\t\t{preview.quickReplies!.options.map((opt) => (\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tkey={opt.id}\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"hw-quick-reply-btn\"\n\t\t\t\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\t\t\t\tdismissPreview();\n\t\t\t\t\t\t\t\t\tsetActiveConversation(preview.conversationId);\n\t\t\t\t\t\t\t\t\tonOpen();\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{opt.label}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</>\n\t\t\t)}\n\n\t\t\t{footer != null && footer !== false && (\n\t\t\t\t<div className=\"hw-preview-footer\">{footer}</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\":host {\\n all: initial;\\n font-family:\\n -apple-system,\\n BlinkMacSystemFont,\\n \\\"Segoe UI\\\",\\n Roboto,\\n \\\"Helvetica Neue\\\",\\n Arial,\\n sans-serif;\\n font-size: 14px;\\n line-height: 1.5;\\n color: #1a1a1a;\\n -webkit-font-smoothing: antialiased;\\n -moz-osx-font-smoothing: grayscale;\\n}\\n.hw-widget {\\n font-family:\\n -apple-system,\\n BlinkMacSystemFont,\\n \\\"Segoe UI\\\",\\n Roboto,\\n \\\"Helvetica Neue\\\",\\n Arial,\\n sans-serif;\\n font-size: 14px;\\n line-height: 1.5;\\n color: #1a1a1a;\\n -webkit-font-smoothing: antialiased;\\n -moz-osx-font-smoothing: grayscale;\\n}\\n.hw-widget *,\\n.hw-widget *::before,\\n.hw-widget *::after {\\n box-sizing: border-box;\\n margin: 0;\\n padding: 0;\\n}\\n:where(.hw-widget) {\\n --hw-primary: #171717;\\n --hw-primary-hover: #2a2a2a;\\n --hw-brand: #171717;\\n --hw-on-brand: #ffffff;\\n --hw-focus-border: #9ca3af;\\n --hw-focus-ring: rgba(0, 0, 0, 0.06);\\n --hw-accent: #6366f1;\\n --hw-bg: #ffffff;\\n --hw-bg-subtle: #fafaf9;\\n --hw-bg-hover: #f5f5f4;\\n --hw-border: #ebe9e5;\\n --hw-border-md: #e5e5e5;\\n --hw-text: #1c1b19;\\n --hw-text-1: #111;\\n --hw-text-2: #666;\\n --hw-text-3: #8a847c;\\n --hw-text-4: #a8a29a;\\n --hw-radius: 20px;\\n --hw-visitor-bubble-bg: #f5f5f4;\\n --hw-visitor-bubble-text: #1a1a1a;\\n --hw-font:\\n -apple-system,\\n BlinkMacSystemFont,\\n \\\"Segoe UI\\\",\\n Roboto,\\n \\\"Helvetica Neue\\\",\\n Arial,\\n sans-serif;\\n}\\n.hw-agent-img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n}\\n.hw-agent-icon {\\n width: 100%;\\n height: 100%;\\n border-radius: inherit;\\n}\\n.hw-widget :focus-visible {\\n outline: 2px solid var(--hw-primary);\\n outline-offset: 2px;\\n}\\n.hw-widget :focus:not(:focus-visible) {\\n outline: none;\\n}\\n.hw-widget {\\n position: fixed;\\n bottom: 20px;\\n right: var(--hw-position-right, 20px);\\n left: var(--hw-position-left, auto);\\n z-index: 999999;\\n font-family: var(--hw-font);\\n}\\n@keyframes hw-bubble-enter {\\n from {\\n opacity: 0;\\n transform: scale(0.6);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n.hw-bubble {\\n width: 48px;\\n height: 48px;\\n border-radius: 14px;\\n background: var(--hw-primary);\\n color: white;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\\n transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease;\\n position: relative;\\n overflow: visible;\\n animation: hw-bubble-enter 0.25s cubic-bezier(0.34, 1.56, 0.64, 1) both;\\n}\\n.hw-bubble--rounded {\\n border-radius: 14px;\\n}\\n.hw-bubble--square {\\n border-radius: 8px;\\n}\\n.hw-bubble--pill {\\n border-radius: 24px;\\n}\\n.hw-bubble--launcher-bubble,\\n.hw-bubble--launcher-help {\\n width: auto;\\n padding: 0 16px 0 12px;\\n gap: 8px;\\n border-radius: 24px;\\n}\\n.hw-bubble--launcher-bubble.hw-bubble--square,\\n.hw-bubble--launcher-help.hw-bubble--square {\\n border-radius: 8px;\\n}\\n.hw-bubble--launcher-bubble.hw-bubble--rounded,\\n.hw-bubble--launcher-help.hw-bubble--rounded {\\n border-radius: 14px;\\n}\\n.hw-bubble-label {\\n font-size: 14px;\\n font-weight: 600;\\n white-space: nowrap;\\n line-height: 1;\\n position: static;\\n opacity: 1;\\n transform: none;\\n}\\n.hw-bubble--launcher-bubble .hw-bubble-icon,\\n.hw-bubble--launcher-help .hw-bubble-icon {\\n position: static;\\n}\\n.hw-bubble:hover {\\n transform: scale(1.05);\\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);\\n}\\n.hw-bubble:active {\\n transform: scale(0.95);\\n}\\n.hw-bubble--open {\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\\n}\\n.hw-bubble:focus-visible {\\n outline: 2px solid white;\\n outline-offset: 2px;\\n}\\n.hw-bubble-icon {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n position: absolute;\\n transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.2s ease;\\n}\\n.hw-bubble-icon svg {\\n width: 22px;\\n height: 22px;\\n}\\n.hw-bubble-icon--hidden {\\n transform: scale(0.3) rotate(90deg);\\n opacity: 0;\\n}\\n.hw-bubble-icon--bot {\\n}\\n.hw-bubble--avatar .hw-bubble-icon--bot {\\n width: 100%;\\n height: 100%;\\n}\\n.hw-bubble--avatar .hw-bubble-icon--bot .hw-agent-img {\\n width: 100%;\\n height: 100%;\\n border-radius: 0;\\n}\\n.hw-agent-img.hw-agent-img--logo {\\n object-fit: contain;\\n padding: 10px;\\n box-sizing: border-box;\\n}\\n.hw-bubble--avatar .hw-bubble-icon--bot .hw-agent-img.hw-agent-img--logo {\\n padding: 10px;\\n box-sizing: border-box;\\n object-fit: contain;\\n}\\n.hw-bubble-icon--close svg {\\n width: 22px;\\n height: 22px;\\n}\\n.hw-bubble-badge {\\n position: absolute;\\n top: -4px;\\n right: -4px;\\n min-width: 20px;\\n height: 20px;\\n border-radius: 10px;\\n background: var(--hw-primary);\\n color: white;\\n font-size: 11px;\\n font-weight: 700;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 0 5px;\\n border: 2px solid white;\\n animation: hw-badge-pop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\\n}\\n@keyframes hw-badge-pop {\\n from {\\n transform: scale(0);\\n }\\n to {\\n transform: scale(1);\\n }\\n}\\n.hw-bubble-badge::after {\\n content: \\\"\\\";\\n position: absolute;\\n inset: -2px;\\n border-radius: inherit;\\n background: var(--hw-primary);\\n opacity: 0;\\n animation: hw-badge-pulse 2s ease-out infinite;\\n}\\n@keyframes hw-badge-pulse {\\n 0% {\\n opacity: 0.5;\\n transform: scale(1);\\n }\\n 100% {\\n opacity: 0;\\n transform: scale(1.8);\\n }\\n}\\n.hw-window {\\n position: absolute;\\n bottom: 72px;\\n right: var(--hw-window-right, 0);\\n left: var(--hw-window-left, auto);\\n width: 440px;\\n height: 640px;\\n background: var(--hw-bg-subtle);\\n color: var(--hw-text);\\n border-radius: var(--hw-radius);\\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.04);\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n animation: hw-window-open 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);\\n transition: width 280ms cubic-bezier(0.4, 0, 0.2, 1), height 280ms cubic-bezier(0.4, 0, 0.2, 1);\\n}\\n.hw-window--reading {\\n width: min(720px, calc(100vw - 40px));\\n height: min(800px, calc(100vh - 112px));\\n}\\n@keyframes hw-window-open {\\n from {\\n opacity: 0;\\n transform: translateY(12px) scale(0.96);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0) scale(1);\\n }\\n}\\n.hw-window--closing {\\n animation: hw-window-close 0.2s ease forwards;\\n}\\n@keyframes hw-window-close {\\n from {\\n opacity: 1;\\n transform: translateY(0) scale(1);\\n }\\n to {\\n opacity: 0;\\n transform: translateY(8px) scale(0.98);\\n }\\n}\\n.hw-content {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n min-height: 0;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-window,\\n .hw-window--closing,\\n .hw-content,\\n .hw-msg,\\n .hw-bubble,\\n .hw-bubble-icon,\\n .hw-bubble-badge,\\n .hw-bubble-badge::after,\\n .hw-typing-dot,\\n .hw-loading-dot {\\n animation-duration: 0.01ms !important;\\n transition-duration: 0.01ms !important;\\n }\\n}\\n.hw-hero {\\n flex-shrink: 0;\\n background:\\n linear-gradient(\\n 160deg,\\n color-mix(in srgb, var(--hw-primary) 60%, black) 0%,\\n var(--hw-primary) 50%,\\n color-mix(in srgb, var(--hw-primary) 40%, black) 100%);\\n color: white;\\n padding: 20px 22px 40px;\\n}\\n.hw-hero-top {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n margin-bottom: 16px;\\n}\\n.hw-hero-close {\\n width: 30px;\\n height: 30px;\\n border-radius: 50%;\\n border: none;\\n background: rgba(255, 255, 255, 0.1);\\n color: rgba(255, 255, 255, 0.6);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n transition: background 0.15s, color 0.15s;\\n}\\n.hw-hero-close:hover {\\n background: rgba(255, 255, 255, 0.2);\\n color: white;\\n}\\n.hw-hero-close:active {\\n transform: scale(0.92);\\n transition:\\n transform 0.14s cubic-bezier(0.23, 1, 0.32, 1),\\n background 0.15s,\\n color 0.15s;\\n}\\n.hw-hero-close svg {\\n width: 20px;\\n height: 20px;\\n}\\n.hw-hero-bot-icon {\\n width: 36px;\\n height: 36px;\\n flex-shrink: 0;\\n color: white;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 10px;\\n}\\n.hw-hero-bot-icon svg {\\n width: 32px;\\n height: 32px;\\n}\\n.hw-hero-bot-icon .hw-agent-img,\\n.hw-hero-bot-icon .hw-agent-icon {\\n border-radius: inherit;\\n overflow: hidden;\\n object-fit: contain;\\n}\\n.hw-hero-greeting {\\n font-size: 26px;\\n font-weight: 700;\\n line-height: 1.15;\\n margin-bottom: 6px;\\n}\\n.hw-hero-greeting-name {\\n font-weight: 300;\\n}\\n.hw-hero-greeting-question {\\n font-weight: 700;\\n}\\n.hw-hero-subtitle {\\n font-size: 15px;\\n color: rgba(255, 255, 255, 0.5);\\n line-height: 1.35;\\n}\\n.hw-sheet {\\n flex: 1;\\n overflow-y: auto;\\n min-height: 0;\\n background: #ffffff;\\n border-radius: 20px 20px 0 0;\\n margin-top: -24px;\\n box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.08);\\n position: relative;\\n z-index: 1;\\n}\\n.hw-sheet-inner {\\n padding: 20px 16px;\\n display: flex;\\n flex-direction: column;\\n gap: 12px;\\n}\\n.hw-header {\\n display: flex;\\n align-items: center;\\n padding: 14px 12px 14px 16px;\\n background: var(--hw-primary);\\n color: white;\\n flex-shrink: 0;\\n gap: 10px;\\n}\\n.hw-header--sub {\\n justify-content: space-between;\\n background: transparent;\\n color: var(--hw-text);\\n border-bottom: 0;\\n}\\n.hw-header-back {\\n width: 28px;\\n height: 28px;\\n border-radius: 8px;\\n border: none;\\n background: transparent;\\n color: var(--hw-text-3);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n transition: color 0.15s, background 0.15s;\\n flex-shrink: 0;\\n}\\n.hw-header-back svg {\\n width: 18px;\\n height: 18px;\\n}\\n.hw-header-back:hover {\\n color: var(--hw-text);\\n background: var(--hw-bg-subtle);\\n}\\n.hw-header-identity {\\n display: flex;\\n align-items: center;\\n gap: 10px;\\n flex: 1;\\n min-width: 0;\\n}\\n.hw-header-bot-icon {\\n width: 32px;\\n height: 32px;\\n flex-shrink: 0;\\n color: var(--hw-text);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 9px;\\n background: var(--hw-agent-bg, var(--hw-agent-bg-default, transparent));\\n}\\n.hw-header-bot-icon svg {\\n width: 24px;\\n height: 24px;\\n}\\n.hw-header-bot-icon--team {\\n background: var(--hw-brand, #0a0a0a);\\n color: var(--hw-on-brand, #fff);\\n}\\n.hw-header-agent-img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n border-radius: inherit;\\n}\\n.hw-header-bot-icon .hw-agent-img,\\n.hw-header-bot-icon .hw-agent-icon {\\n border-radius: inherit;\\n overflow: hidden;\\n}\\n.hw-header-bot-icon .hw-agent-img {\\n object-fit: var(--hw-agent-fit, var(--hw-agent-fit-default, cover));\\n padding: var(--hw-agent-pad, var(--hw-agent-pad-default, 0));\\n box-sizing: border-box;\\n}\\n.hw-widget[data-has-avatar=true] {\\n --hw-agent-bg-default: var(--hw-primary);\\n --hw-agent-fit-default: contain;\\n --hw-agent-pad-default: 6px;\\n}\\n.hw-header-agent-initials {\\n font-size: 11px;\\n font-weight: 600;\\n line-height: 1;\\n}\\n.hw-header-info {\\n flex: 1;\\n min-width: 0;\\n}\\n.hw-header-name {\\n font-size: 15px;\\n font-weight: 600;\\n line-height: 1.3;\\n}\\n.hw-header-status {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n line-height: 1.3;\\n}\\n.hw-header-close {\\n width: 28px;\\n height: 28px;\\n border-radius: 8px;\\n border: none;\\n background: transparent;\\n color: var(--hw-text-3);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n transition:\\n background-color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\\n flex-shrink: 0;\\n}\\n.hw-header-close svg {\\n width: 20px;\\n height: 20px;\\n}\\n.hw-header-close:hover {\\n background: var(--hw-bg-subtle);\\n color: var(--hw-text);\\n}\\n.hw-header-close:active {\\n transform: scale(0.92);\\n}\\n.hw-header--centered {\\n justify-content: space-between;\\n background: transparent;\\n color: var(--hw-text);\\n border-bottom: 0;\\n}\\n.hw-header--centered .hw-header-title {\\n position: absolute;\\n left: 50%;\\n transform: translateX(-50%);\\n max-width: calc(100% - 88px);\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n text-align: center;\\n}\\n.hw-header-spacer {\\n width: 28px;\\n flex-shrink: 0;\\n}\\n.hw-header--messages {\\n justify-content: space-between;\\n background: transparent;\\n color: var(--hw-text);\\n border-bottom: 0;\\n}\\n.hw-header-title {\\n font-size: 16px;\\n font-weight: 600;\\n}\\n.hw-header-actions {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n}\\n.hw-header-action {\\n width: 28px;\\n height: 28px;\\n border-radius: 8px;\\n border: none;\\n background: transparent;\\n color: var(--hw-text-3);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n transition:\\n background-color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\\n}\\n.hw-header-action svg {\\n width: 16px;\\n height: 16px;\\n}\\n.hw-header-action:hover {\\n background: var(--hw-bg-subtle);\\n color: var(--hw-text);\\n}\\n.hw-header-action:active {\\n transform: scale(0.94);\\n}\\n.hw-card {\\n display: flex;\\n align-items: center;\\n gap: 12px;\\n width: 100%;\\n padding: 14px 16px;\\n border-radius: 14px;\\n background: var(--hw-bg);\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.03);\\n cursor: pointer;\\n transition: box-shadow 180ms cubic-bezier(0.23, 1, 0.32, 1), transform 180ms cubic-bezier(0.23, 1, 0.32, 1);\\n text-align: left;\\n color: var(--hw-text);\\n font-family: inherit;\\n}\\n.hw-card:hover {\\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08), 0 0 0 1px rgba(0, 0, 0, 0.05);\\n transform: translateY(-1px);\\n}\\n.hw-card:active {\\n transform: translateY(0) scale(0.99);\\n transition-duration: 120ms;\\n}\\n.hw-card-body {\\n flex: 1;\\n min-width: 0;\\n}\\n.hw-card-title {\\n font-size: 14px;\\n font-weight: 600;\\n line-height: 1.3;\\n color: var(--hw-text);\\n}\\n.hw-card-meta {\\n font-size: 12px;\\n color: var(--hw-text-3);\\n line-height: 1.3;\\n margin-top: 1px;\\n}\\n.hw-card-arrow {\\n width: 32px;\\n height: 32px;\\n border-radius: 50%;\\n background: var(--hw-primary);\\n color: white;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n flex-shrink: 0;\\n}\\n.hw-card-arrow svg {\\n width: 14px;\\n height: 14px;\\n}\\n.hw-msgs-tab {\\n flex: 1;\\n overflow-y: auto;\\n padding: 12px 16px;\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n}\\n.hw-recent-card {\\n border-radius: 14px;\\n background: var(--hw-bg);\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.03);\\n overflow: hidden;\\n}\\n.hw-recent-header {\\n font-size: 12px;\\n font-weight: 600;\\n color: var(--hw-text-2);\\n padding: 12px 14px 0;\\n}\\n.hw-recent-row {\\n display: flex;\\n align-items: center;\\n gap: 10px;\\n width: 100%;\\n padding: 10px 14px;\\n border: none;\\n border-bottom: 1px solid var(--hw-border);\\n background: none;\\n cursor: pointer;\\n text-align: left;\\n font-family: inherit;\\n color: var(--hw-text);\\n transition: background-color 140ms cubic-bezier(0.23, 1, 0.32, 1), transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\\n position: relative;\\n}\\n.hw-recent-row:hover {\\n background: rgba(0, 0, 0, 0.03);\\n}\\n.hw-recent-row:active {\\n transform: scale(0.995);\\n}\\n.hw-recent-row--last {\\n border-bottom: none;\\n}\\n.hw-recent-row .hw-conv-card-avatar {\\n width: 32px;\\n height: 32px;\\n border-radius: 8px;\\n}\\n.hw-recent-row .hw-conv-card-avatar svg {\\n width: 18px;\\n height: 18px;\\n}\\n.hw-recent-row .hw-conv-card-name {\\n font-size: 13px;\\n}\\n.hw-recent-row .hw-conv-card-preview {\\n font-size: 12px;\\n}\\n.hw-recent-row--unread .hw-conv-card-name {\\n color: var(--hw-text);\\n}\\n.hw-recent-row--unread .hw-conv-card-time {\\n color: var(--hw-primary);\\n font-weight: 500;\\n}\\n.hw-recent-row-badge {\\n min-width: 18px;\\n height: 18px;\\n border-radius: 9px;\\n background: var(--hw-primary);\\n color: white;\\n font-size: 11px;\\n font-weight: 600;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 0 5px;\\n flex-shrink: 0;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-recent-see-all {\\n display: block;\\n width: 100%;\\n padding: 10px 14px;\\n text-align: center;\\n font-size: 13px;\\n font-weight: 500;\\n color: var(--hw-text);\\n background: none;\\n border: none;\\n border-top: 1px solid var(--hw-border);\\n cursor: pointer;\\n font-family: inherit;\\n transition: background 0.1s;\\n}\\n.hw-recent-see-all:hover {\\n background: rgba(0, 0, 0, 0.02);\\n}\\n.hw-conv-card {\\n position: relative;\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n width: 100%;\\n padding: 14px 16px;\\n border-radius: 14px;\\n background: var(--hw-bg);\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.03);\\n cursor: pointer;\\n transition: box-shadow 0.15s, transform 0.1s;\\n text-align: left;\\n font-family: inherit;\\n color: var(--hw-text);\\n}\\n.hw-conv-card:hover {\\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.04);\\n}\\n.hw-conv-card:active {\\n transform: scale(0.99);\\n}\\n.hw-conv-card-row {\\n display: flex;\\n align-items: center;\\n gap: 12px;\\n}\\n.hw-conv-card-avatar {\\n width: 36px;\\n height: 36px;\\n border-radius: 10px;\\n background: var(--hw-agent-bg, var(--hw-agent-bg-default, var(--hw-bg-subtle)));\\n color: var(--hw-text-3);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n flex-shrink: 0;\\n overflow: hidden;\\n}\\n.hw-conv-card-avatar svg {\\n width: 20px;\\n height: 20px;\\n}\\n.hw-conv-card-avatar-img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n}\\n.hw-conv-card-avatar .hw-agent-img {\\n object-fit: var(--hw-agent-fit, var(--hw-agent-fit-default, cover));\\n padding: var(--hw-agent-pad, var(--hw-agent-pad-default, 0));\\n box-sizing: border-box;\\n}\\n.hw-conv-card-avatar--team {\\n background: var(--hw-brand, #0a0a0a);\\n color: var(--hw-on-brand, #fff);\\n}\\n.hw-conv-card-avatar-initials {\\n font-size: 12px;\\n font-weight: 600;\\n line-height: 1;\\n letter-spacing: 0.02em;\\n}\\n.hw-conv-card-content {\\n flex: 1;\\n min-width: 0;\\n}\\n.hw-conv-card-top {\\n display: flex;\\n align-items: baseline;\\n gap: 8px;\\n}\\n.hw-conv-card-name {\\n flex: 1;\\n font-size: 14px;\\n font-weight: 600;\\n color: var(--hw-text);\\n}\\n.hw-conv-card-time {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n flex-shrink: 0;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-conv-card-preview {\\n font-size: 13px;\\n color: var(--hw-text-2);\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n line-height: 1.4;\\n margin-top: 1px;\\n}\\n.hw-conv-card--unread .hw-conv-card-name {\\n color: var(--hw-text);\\n}\\n.hw-conv-card--unread .hw-conv-card-time {\\n color: var(--hw-primary);\\n font-weight: 500;\\n}\\n.hw-conv-card-badge {\\n position: absolute;\\n top: 12px;\\n right: 12px;\\n min-width: 18px;\\n height: 18px;\\n border-radius: 9px;\\n background: var(--hw-primary);\\n color: white;\\n font-size: 11px;\\n font-weight: 600;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 0 5px;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-empty-state {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n padding: 32px;\\n text-align: center;\\n}\\n.hw-empty-icon-wrap {\\n width: 48px;\\n height: 48px;\\n border-radius: 50%;\\n background: var(--hw-bg-subtle);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n margin-bottom: 16px;\\n color: var(--hw-text-3);\\n}\\n.hw-empty-icon-wrap svg {\\n width: 24px;\\n height: 24px;\\n}\\n.hw-empty-title {\\n font-size: 15px;\\n font-weight: 600;\\n color: var(--hw-text);\\n margin-bottom: 4px;\\n}\\n.hw-empty-desc {\\n font-size: 13px;\\n color: var(--hw-text-3);\\n margin-bottom: 20px;\\n}\\n.hw-empty-btn {\\n padding: 8px 20px;\\n border-radius: 10px;\\n background: var(--hw-primary);\\n color: white;\\n border: none;\\n font-size: 13px;\\n font-weight: 500;\\n cursor: pointer;\\n font-family: inherit;\\n transition: background 0.15s;\\n}\\n.hw-empty-btn:hover {\\n background: var(--hw-primary-hover);\\n}\\n.hw-tabs {\\n display: flex;\\n border-top: 1px solid var(--hw-border);\\n flex-shrink: 0;\\n background: var(--hw-bg-subtle);\\n}\\n.hw-tabs-item {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 2px;\\n padding: 8px 0;\\n border: none;\\n background: none;\\n cursor: pointer;\\n font-family: inherit;\\n font-size: 11px;\\n font-weight: 500;\\n color: var(--hw-text-3);\\n transition: color 0.15s;\\n}\\n.hw-tabs-item svg {\\n width: 22px;\\n height: 22px;\\n overflow: visible;\\n}\\n.hw-tabs-item--active {\\n color: var(--hw-text);\\n}\\n.hw-tabs-item:hover {\\n color: var(--hw-text-2);\\n}\\n.hw-tabs-item:active {\\n transform: scale(0.94);\\n transition: transform 0.14s cubic-bezier(0.23, 1, 0.32, 1), color 0.15s;\\n}\\n.hw-tabs-icon-wrap {\\n position: relative;\\n display: inline-flex;\\n}\\n.hw-tabs-badge {\\n position: absolute;\\n top: -6px;\\n right: -10px;\\n min-width: 16px;\\n height: 16px;\\n border-radius: 8px;\\n background: var(--hw-primary);\\n color: white;\\n font-size: 10px;\\n font-weight: 700;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 0 4px;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-messages {\\n flex: 1;\\n overflow-y: auto;\\n overflow-x: hidden;\\n padding: 16px 14px 8px;\\n background: var(--hw-bg-subtle);\\n display: flex;\\n flex-direction: column;\\n gap: 14px;\\n overscroll-behavior: contain;\\n min-width: 0;\\n scrollbar-color: rgba(0, 0, 0, 0.2) transparent;\\n scrollbar-width: thin;\\n}\\n.hw-messages::-webkit-scrollbar {\\n width: 10px;\\n height: 10px;\\n}\\n.hw-messages::-webkit-scrollbar-track {\\n background: transparent;\\n}\\n.hw-messages::-webkit-scrollbar-thumb {\\n background: rgba(0, 0, 0, 0.16);\\n background-clip: content-box;\\n border: 3px solid transparent;\\n border-radius: 999px;\\n}\\n.hw-messages::-webkit-scrollbar-thumb:hover {\\n background: rgba(0, 0, 0, 0.28);\\n background-clip: content-box;\\n}\\n.hw-widget[data-theme=dark] .hw-messages {\\n scrollbar-color: rgba(255, 255, 255, 0.26) transparent;\\n}\\n.hw-widget[data-theme=dark] .hw-messages::-webkit-scrollbar-thumb {\\n background: rgba(255, 255, 255, 0.2);\\n background-clip: content-box;\\n}\\n.hw-widget[data-theme=dark] .hw-messages::-webkit-scrollbar-thumb:hover {\\n background: rgba(255, 255, 255, 0.32);\\n background-clip: content-box;\\n}\\n.hw-empty {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n padding: 32px;\\n color: var(--hw-text-3);\\n text-align: center;\\n}\\n.hw-empty-icon {\\n width: 40px;\\n height: 40px;\\n margin-bottom: 12px;\\n opacity: 0.3;\\n}\\n.hw-empty-text {\\n font-size: 13px;\\n}\\n.hw-date-sep {\\n display: flex;\\n align-items: center;\\n gap: 12px;\\n padding: 12px 0;\\n}\\n.hw-date-sep-line {\\n flex: 1;\\n height: 1px;\\n background: var(--hw-border-md);\\n}\\n.hw-date-sep-text {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n font-weight: 500;\\n white-space: nowrap;\\n}\\n.hw-msg {\\n display: flex;\\n padding: 4px 0;\\n max-width: 75%;\\n min-width: 0;\\n animation: hw-msg-appear 0.25s ease-out;\\n}\\n@keyframes hw-msg-appear {\\n from {\\n opacity: 0;\\n transform: translateY(6px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n.hw-msg--visitor {\\n align-self: flex-end;\\n}\\n.hw-msg--team,\\n.hw-msg--ai {\\n align-self: flex-start;\\n}\\n.hw-msg--ai {\\n width: 100%;\\n max-width: 100%;\\n}\\n.hw-msg-body {\\n display: flex;\\n flex-direction: column;\\n min-width: 0;\\n max-width: 100%;\\n}\\n.hw-msg-bubble {\\n padding: 10px 14px;\\n border-radius: 16px;\\n font-size: 14px;\\n line-height: 1.45;\\n white-space: pre-wrap;\\n word-break: break-word;\\n overflow-wrap: anywhere;\\n max-width: 100%;\\n}\\n.hw-msg--visitor .hw-msg-bubble {\\n background: var(--hw-primary);\\n color: white;\\n border-bottom-right-radius: 4px;\\n}\\n.hw-msg--team .hw-msg-bubble {\\n background: var(--hw-visitor-bubble-bg);\\n color: var(--hw-visitor-bubble-text);\\n border-bottom-left-radius: 4px;\\n}\\n.hw-msg--ai .hw-msg-bubble {\\n background: var(--hw-visitor-bubble-bg);\\n color: var(--hw-text);\\n border-bottom-left-radius: 4px;\\n white-space: normal;\\n max-width: min(100%, 640px);\\n}\\n.hw-msg--ai .hw-msg-body {\\n width: 100%;\\n}\\n.hw-msg--ai .hw-msg-bubble:has(.hw-code),\\n.hw-msg--ai .hw-msg-bubble:has(pre) {\\n width: 100%;\\n}\\n.hw-quick-replies {\\n display: flex;\\n flex-wrap: wrap;\\n gap: 6px;\\n margin-top: 8px;\\n}\\n.hw-quick-reply-btn {\\n font: inherit;\\n font-size: 13px;\\n font-weight: 500;\\n padding: 6px 14px;\\n border-radius: 18px;\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n background: var(--hw-bg, #fff);\\n color: var(--hw-text-1, #1a1a1a);\\n cursor: pointer;\\n transition:\\n background 120ms ease,\\n border-color 120ms ease,\\n box-shadow 120ms ease,\\n transform 80ms ease;\\n line-height: 1.3;\\n}\\n.hw-quick-reply-btn:hover:not(:disabled) {\\n border-color: var(--hw-primary);\\n background: color-mix(in srgb, var(--hw-primary) 8%, transparent);\\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);\\n}\\n.hw-quick-reply-btn:active:not(:disabled) {\\n transform: scale(0.97);\\n}\\n.hw-quick-reply-btn:disabled {\\n cursor: default;\\n opacity: 0.4;\\n}\\n.hw-quick-reply-btn[data-tapped=true] {\\n background: var(--hw-primary);\\n color: white;\\n border-color: var(--hw-primary);\\n opacity: 1;\\n}\\n.hw-quick-replies[data-cancelled=true] .hw-quick-reply-btn {\\n border-color: var(--hw-border);\\n color: var(--hw-text-3);\\n}\\n.hw-msg--ai .hw-code {\\n width: 100%;\\n box-sizing: border-box;\\n}\\n.hw-msg-meta {\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n font-size: 11px;\\n color: var(--hw-text-2);\\n margin-top: 2px;\\n padding: 0 4px;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-msg-time {\\n white-space: nowrap;\\n}\\n.hw-msg--visitor .hw-msg-meta {\\n text-align: right;\\n}\\n.hw-msg--team .hw-msg-body,\\n.hw-msg--ai .hw-msg-body {\\n align-items: flex-start;\\n}\\n.hw-msg--visitor .hw-msg-body {\\n align-items: flex-end;\\n}\\n.hw-typing {\\n display: flex;\\n flex-direction: column;\\n gap: 3px;\\n padding: 8px 0;\\n width: fit-content;\\n animation: hw-msg-appear 0.25s ease-out;\\n}\\n.hw-typing-dots {\\n display: flex;\\n gap: 3px;\\n padding: 6px 2px;\\n width: fit-content;\\n}\\n.hw-typing-dot {\\n width: 6px;\\n height: 6px;\\n border-radius: 50%;\\n background: var(--hw-text-3);\\n animation: hw-typing-bounce 1.4s infinite;\\n}\\n.hw-typing-dot:nth-child(2) {\\n animation-delay: 0.2s;\\n}\\n.hw-typing-dot:nth-child(3) {\\n animation-delay: 0.4s;\\n}\\n@keyframes hw-typing-bounce {\\n 0%, 60%, 100% {\\n transform: translateY(0);\\n }\\n 30% {\\n transform: translateY(-4px);\\n }\\n}\\n.hw-streaming-cursor {\\n display: inline-block;\\n width: 2px;\\n height: 1em;\\n background: currentColor;\\n opacity: 0.6;\\n margin-left: 1px;\\n vertical-align: text-bottom;\\n animation: hw-cursor-blink 0.8s step-end infinite;\\n}\\n@keyframes hw-cursor-blink {\\n 50% {\\n opacity: 0;\\n }\\n}\\n.hw-link-preview {\\n display: flex;\\n flex-direction: column;\\n gap: 0;\\n border: 1px solid var(--hw-border, rgba(0, 0, 0, 0.08));\\n border-radius: 10px;\\n overflow: hidden;\\n text-decoration: none;\\n color: inherit;\\n margin-top: 6px;\\n transition: background 0.15s;\\n}\\n.hw-link-preview:hover {\\n background: var(--hw-bg-hover, rgba(0, 0, 0, 0.02));\\n}\\n.hw-link-preview-img {\\n width: 100%;\\n height: 56px;\\n flex: 0 0 56px;\\n object-fit: cover;\\n object-position: top;\\n border-radius: 0;\\n}\\n.hw-link-preview-body {\\n padding: 8px 10px;\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n min-width: 0;\\n justify-content: center;\\n}\\n.hw-link-preview-favicon {\\n width: 16px;\\n height: 16px;\\n border-radius: 2px;\\n}\\n.hw-link-preview-title {\\n font-size: 12.5px;\\n font-weight: 600;\\n line-height: 1.3;\\n color: var(--hw-text, #1a1a1a);\\n display: -webkit-box;\\n -webkit-line-clamp: 2;\\n -webkit-box-orient: vertical;\\n overflow: hidden;\\n}\\n.hw-link-preview-desc {\\n font-size: 11.5px;\\n line-height: 1.4;\\n color: var(--hw-text-2, #6b7280);\\n display: -webkit-box;\\n -webkit-line-clamp: 2;\\n -webkit-box-orient: vertical;\\n overflow: hidden;\\n}\\n.hw-link-preview-url {\\n font-size: 11px;\\n color: var(--hw-text-2);\\n}\\n.hw-msg-links {\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n max-width: 240px;\\n}\\n.hw-loading {\\n flex: 1;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.hw-loading-dots {\\n display: flex;\\n gap: 4px;\\n}\\n.hw-loading-dot {\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: var(--hw-text-4);\\n animation: hw-loading-pulse 1.4s infinite;\\n}\\n.hw-loading-dot:nth-child(2) {\\n animation-delay: 0.2s;\\n}\\n.hw-loading-dot:nth-child(3) {\\n animation-delay: 0.4s;\\n}\\n@keyframes hw-loading-pulse {\\n 0%, 60%, 100% {\\n opacity: 0.3;\\n transform: scale(0.8);\\n }\\n 30% {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n@keyframes hw-skeleton-shimmer {\\n 0% {\\n background-position: -200px 0;\\n }\\n 100% {\\n background-position: calc(200px + 100%) 0;\\n }\\n}\\n.hw-skeleton {\\n background:\\n linear-gradient(\\n 90deg,\\n var(--hw-bg-subtle) 25%,\\n rgba(0, 0, 0, 0.04) 50%,\\n var(--hw-bg-subtle) 75%);\\n background-size: 200px 100%;\\n animation: hw-skeleton-shimmer 1.5s ease-in-out infinite;\\n border-radius: 6px;\\n}\\n.hw-skeleton-messages {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n padding: 16px;\\n gap: 16px;\\n}\\n.hw-skeleton-msg {\\n display: flex;\\n gap: 10px;\\n align-items: flex-start;\\n}\\n.hw-skeleton-msg--right {\\n flex-direction: row-reverse;\\n}\\n.hw-skeleton-avatar {\\n width: 28px;\\n height: 28px;\\n border-radius: 8px;\\n flex-shrink: 0;\\n}\\n.hw-skeleton-bubble {\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n}\\n.hw-skeleton-line {\\n height: 12px;\\n border-radius: 6px;\\n}\\n.hw-skeleton-convs {\\n display: flex;\\n flex-direction: column;\\n padding: 8px 0;\\n}\\n.hw-skeleton-conv {\\n display: flex;\\n gap: 10px;\\n align-items: center;\\n padding: 10px 16px;\\n}\\n.hw-skeleton-conv-avatar {\\n width: 36px;\\n height: 36px;\\n border-radius: 8px;\\n flex-shrink: 0;\\n}\\n.hw-skeleton-conv-lines {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n}\\n.hw-skeleton-content {\\n display: flex;\\n flex-direction: column;\\n padding: 12px 16px;\\n gap: 12px;\\n}\\n.hw-skeleton-content-item {\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n padding: 12px;\\n border-radius: 10px;\\n background: var(--hw-bg);\\n}\\n.hw-skeleton-title {\\n height: 22px;\\n width: 65%;\\n border-radius: 6px;\\n}\\n.hw-skeleton-badge {\\n width: 42px;\\n height: 18px;\\n border-radius: 9px;\\n}\\n.hw-skeleton-date {\\n width: 60px;\\n height: 12px;\\n border-radius: 6px;\\n}\\n.hw-skeleton-h2 {\\n height: 16px;\\n border-radius: 6px;\\n}\\n.hw-skeleton-bullet {\\n padding-left: 20px;\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n}\\n.hw-skeleton-bullet-line {\\n height: 14px;\\n border-radius: 7px;\\n}\\n.hw-email-card {\\n max-width: min(100%, 340px);\\n margin: 0;\\n padding: 0;\\n border: 0;\\n border-radius: 0;\\n background: none;\\n box-shadow: none;\\n animation: hw-email-slide-in 0.25s ease-out;\\n}\\n@keyframes hw-email-slide-in {\\n from {\\n opacity: 0;\\n transform: translateY(8px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n.hw-email-card-title {\\n font-size: 14px;\\n font-weight: 550;\\n color: var(--hw-text, #1a1a1a);\\n line-height: 1.3;\\n margin: 0 0 2px;\\n}\\n.hw-email-card-subtitle {\\n font-size: 12px;\\n color: var(--hw-text-2, #888);\\n line-height: 1.4;\\n margin: 0;\\n}\\n.hw-email-card-row {\\n max-width: 300px;\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n margin-top: 9px;\\n padding: 3px 3px 3px 12px;\\n border-radius: 999px;\\n border: 1px solid var(--hw-border, rgba(0,0,0,0.1));\\n background: var(--hw-bg-subtle, #fafafa);\\n transition: border-color 0.15s, box-shadow 0.15s;\\n}\\n.hw-email-card-row:focus-within {\\n border-color: var(--hw-focus-border, rgba(0,0,0,0.2));\\n box-shadow: 0 0 0 2px var(--hw-focus-ring, rgba(0,0,0,0.06));\\n}\\n.hw-email-card-input {\\n flex: 1;\\n min-width: 0;\\n padding: 6px 0;\\n border: 0;\\n background: transparent;\\n color: var(--hw-text, #1a1a1a);\\n font: inherit;\\n font-size: 13px;\\n outline: none;\\n}\\n.hw-email-card-input::placeholder {\\n color: var(--hw-text-3, #999);\\n}\\n.hw-email-card-row:has(.hw-email-card-input--error) {\\n border-color: #ef4444;\\n}\\n.hw-email-card-submit {\\n flex: none;\\n display: grid;\\n place-items: center;\\n width: 28px;\\n height: 28px;\\n border: none;\\n border-radius: 50%;\\n background: var(--hw-brand, #0a0a0a);\\n color: var(--hw-on-brand, #fff);\\n cursor: pointer;\\n transition: opacity 0.15s, transform 0.15s;\\n}\\n.hw-email-card-submit:hover:not(:disabled) {\\n transform: scale(1.06);\\n}\\n.hw-email-card-submit:disabled {\\n opacity: 0.45;\\n cursor: default;\\n}\\n.hw-email-card--success {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n padding: 2px 0;\\n font-size: 13px;\\n color: var(--hw-text-2, #888);\\n animation: hw-email-slide-in 0.2s ease-out;\\n}\\n.hw-email-card--success svg {\\n flex-shrink: 0;\\n}\\n.hw-composer {\\n display: flex;\\n flex-direction: column;\\n padding: 12px 16px;\\n background: transparent;\\n flex-shrink: 0;\\n}\\n.hw-composer--compact {\\n padding: 8px 12px;\\n}\\n.hw-composer-box {\\n display: flex;\\n flex-direction: column;\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n border-radius: 16px;\\n overflow: hidden;\\n transition: border-color 0.2s;\\n background: var(--hw-bg);\\n}\\n.hw-composer-box:focus-within {\\n border-color: var(--hw-focus-border);\\n box-shadow: 0 0 0 3px var(--hw-focus-ring);\\n}\\n.hw-composer-input {\\n resize: none;\\n border: none;\\n padding: 12px 16px 4px;\\n font-size: 14px;\\n font-family: inherit;\\n line-height: 1.4;\\n outline: none;\\n min-height: 40px;\\n max-height: 220px;\\n background: transparent;\\n color: var(--hw-text);\\n field-sizing: content;\\n}\\n.hw-composer-input:focus {\\n outline: none;\\n}\\n.hw-composer-input:focus-visible {\\n outline: none;\\n}\\n.hw-composer-input::placeholder {\\n color: var(--hw-text-4);\\n}\\n.hw-composer-toolbar {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 4px 10px 10px;\\n}\\n.hw-composer-toolbar-left {\\n display: flex;\\n align-items: center;\\n gap: 4px;\\n}\\n.hw-composer-send {\\n width: 32px;\\n height: 32px;\\n border-radius: 50%;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n flex-shrink: 0;\\n transition:\\n background-color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\\n}\\n.hw-composer-send:active:not(:disabled) {\\n transform: scale(0.9);\\n}\\n.hw-composer-send--active {\\n background: var(--hw-primary);\\n color: white;\\n}\\n.hw-composer-send--inactive {\\n background: var(--hw-border);\\n color: var(--hw-text-4);\\n cursor: default;\\n}\\n.hw-composer-send svg {\\n width: 14px;\\n height: 14px;\\n}\\n.hw-composer-charcount {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n font-variant-numeric: tabular-nums;\\n opacity: 1;\\n transform: translateY(0);\\n transition:\\n color 180ms cubic-bezier(0.23, 1, 0.32, 1),\\n opacity 180ms cubic-bezier(0.23, 1, 0.32, 1),\\n transform 180ms cubic-bezier(0.23, 1, 0.32, 1);\\n}\\n@starting-style {\\n .hw-composer-charcount {\\n opacity: 0;\\n transform: translateY(3px);\\n }\\n}\\n.hw-composer-charcount--over {\\n color: #ef4444;\\n font-weight: 600;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-composer-charcount {\\n transform: none;\\n transition: color 160ms ease, opacity 160ms ease;\\n }\\n @starting-style {\\n .hw-composer-charcount {\\n transform: none;\\n }\\n }\\n}\\n.hw-composer-previews {\\n display: flex;\\n gap: 6px;\\n padding: 8px 10px 0;\\n overflow-x: auto;\\n scrollbar-width: none;\\n}\\n.hw-composer-previews::-webkit-scrollbar {\\n display: none;\\n}\\n.hw-composer-preview {\\n position: relative;\\n width: 48px;\\n height: 48px;\\n border-radius: 8px;\\n overflow: hidden;\\n flex-shrink: 0;\\n background: var(--hw-border);\\n cursor: pointer;\\n}\\n.hw-composer-preview--error {\\n outline: 2px solid #ef4444;\\n outline-offset: -2px;\\n}\\n.hw-composer-preview-img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n}\\n.hw-composer-preview-file {\\n width: 100%;\\n height: 100%;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n background: var(--hw-bg-subtle);\\n}\\n.hw-composer-preview-ext {\\n font-size: 10px;\\n font-weight: 700;\\n color: var(--hw-text-3);\\n text-transform: uppercase;\\n}\\n.hw-composer-preview-loader {\\n position: absolute;\\n inset: 0;\\n background: rgba(0, 0, 0, 0.35);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.hw-composer-preview-loader::after {\\n content: \\\"\\\";\\n width: 16px;\\n height: 16px;\\n border: 2px solid rgba(255, 255, 255, 0.3);\\n border-top-color: white;\\n border-radius: 50%;\\n animation: hw-spin 0.6s linear infinite;\\n}\\n@keyframes hw-spin {\\n to {\\n transform: rotate(360deg);\\n }\\n}\\n.hw-composer-preview-badge {\\n position: absolute;\\n top: 2px;\\n right: 2px;\\n width: 16px;\\n height: 16px;\\n border-radius: 50%;\\n background: #ef4444;\\n color: white;\\n font-size: 10px;\\n font-weight: 700;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.hw-composer-preview-remove {\\n position: absolute;\\n top: 2px;\\n right: 2px;\\n width: 18px;\\n height: 18px;\\n border-radius: 50%;\\n border: none;\\n background: rgba(0, 0, 0, 0.55);\\n color: white;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n opacity: 0;\\n transition: opacity 0.15s;\\n}\\n.hw-composer-preview-remove svg {\\n width: 10px;\\n height: 10px;\\n}\\n.hw-composer-preview:hover .hw-composer-preview-remove {\\n opacity: 1;\\n}\\n.hw-composer-attach {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n color: var(--hw-text-3);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n opacity: 0.7;\\n transition: opacity 0.15s;\\n}\\n.hw-composer-attach:hover {\\n opacity: 1;\\n}\\n.hw-composer-attach svg {\\n width: 16px;\\n height: 16px;\\n}\\n.hw-msg-images {\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n margin-bottom: 4px;\\n}\\n.hw-msg-image-link {\\n display: block;\\n border-radius: 14px;\\n overflow: hidden;\\n line-height: 0;\\n}\\n.hw-msg-image {\\n max-width: 140px;\\n max-height: 80px;\\n object-fit: cover;\\n border-radius: 8px;\\n outline: 1px solid rgba(0, 0, 0, 0.08);\\n outline-offset: -1px;\\n}\\n.hw-msg-files {\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n margin-top: 4px;\\n}\\n.hw-msg-file {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n padding: 8px 12px;\\n border-radius: 10px;\\n background: var(--hw-bg-subtle);\\n text-decoration: none;\\n color: var(--hw-text);\\n transition: background 0.15s;\\n}\\n.hw-msg-file:hover {\\n background: var(--hw-border);\\n}\\n.hw-msg-file-icon {\\n flex-shrink: 0;\\n width: 20px;\\n height: 20px;\\n color: var(--hw-text-3);\\n}\\n.hw-msg-file-icon svg {\\n width: 100%;\\n height: 100%;\\n}\\n.hw-msg-file-info {\\n display: flex;\\n flex-direction: column;\\n min-width: 0;\\n}\\n.hw-msg-file-name {\\n font-size: 13px;\\n font-weight: 500;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n.hw-msg-file-size {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n}\\n.hw-msg-image-link {\\n cursor: pointer;\\n border: none;\\n padding: 0;\\n background: none;\\n display: block;\\n line-height: 0;\\n}\\n.hw-hover-preview {\\n position: fixed;\\n z-index: 2147483001;\\n padding: 6px;\\n border-radius: 14px;\\n background: white;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.06);\\n cursor: pointer;\\n animation: hw-hover-in 0.15s ease-out;\\n}\\n@media (prefers-color-scheme: dark) {\\n .hw-hover-preview {\\n background: #1c1c1e;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.08);\\n }\\n}\\n@keyframes hw-hover-in {\\n from {\\n opacity: 0;\\n transform: scale(0.96) translateY(4px);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1) translateY(0);\\n }\\n}\\n.hw-hover-preview-img {\\n width: 100%;\\n max-height: 200px;\\n object-fit: contain;\\n border-radius: 10px;\\n display: block;\\n outline: 1px solid rgba(0, 0, 0, 0.08);\\n outline-offset: -1px;\\n}\\n.hw-hover-preview--doc {\\n display: flex;\\n align-items: center;\\n gap: 10px;\\n padding: 10px 14px;\\n}\\n.hw-hover-preview-doc-icon {\\n width: 28px;\\n height: 28px;\\n flex-shrink: 0;\\n}\\n.hw-hover-preview-doc-icon svg {\\n width: 100%;\\n height: 100%;\\n}\\n.hw-hover-preview-doc-info {\\n display: flex;\\n flex-direction: column;\\n min-width: 0;\\n}\\n.hw-hover-preview-doc-name {\\n font-size: 13px;\\n font-weight: 500;\\n color: var(--hw-text);\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n.hw-hover-preview-doc-hint {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n}\\n.hw-event {\\n display: flex;\\n justify-content: center;\\n padding: 8px 16px;\\n}\\n.hw-event-text {\\n font-size: 12px;\\n color: var(--hw-text-3);\\n text-align: center;\\n}\\n.hw-event--card {\\n justify-content: flex-start;\\n align-items: center;\\n gap: 10px;\\n background: var(--hw-bg-subtle);\\n padding: 10px 14px;\\n border-radius: 12px;\\n margin: 4px 16px;\\n}\\n.hw-event-avatar {\\n width: 32px;\\n height: 32px;\\n border-radius: 50%;\\n background: var(--hw-agent-bg, var(--hw-agent-bg-default, var(--hw-bg-hover, #e0e0e0)));\\n color: var(--hw-text-2, #555);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 11px;\\n font-weight: 600;\\n flex-shrink: 0;\\n overflow: hidden;\\n}\\n.hw-event-avatar-img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n}\\n.hw-event-avatar .hw-agent-img {\\n object-fit: var(--hw-agent-fit, var(--hw-agent-fit-default, cover));\\n padding: var(--hw-agent-pad, var(--hw-agent-pad-default, 0));\\n box-sizing: border-box;\\n}\\n.hw-event-body {\\n font-size: 13px;\\n line-height: 1.3;\\n}\\n.hw-event-name {\\n font-weight: 600;\\n color: var(--hw-text);\\n}\\n.hw-event-action {\\n color: var(--hw-text-2);\\n}\\n.hw-resolved-banner {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 12px 16px;\\n border-top: 1px solid var(--hw-border);\\n background: var(--hw-bg-subtle);\\n color: var(--hw-text-2);\\n font-size: 13px;\\n flex-shrink: 0;\\n}\\n.hw-new {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n background: var(--hw-bg-subtle);\\n}\\n.hw-new-body {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n padding: 32px 24px;\\n text-align: center;\\n}\\n.hw-new-welcome {\\n flex: 1;\\n padding: 16px 20px;\\n overflow-y: auto;\\n}\\n.hw-new-heading {\\n font-size: 17px;\\n font-weight: 600;\\n color: var(--hw-text);\\n margin-bottom: 6px;\\n}\\n.hw-new-desc {\\n font-size: 13px;\\n color: var(--hw-text-2);\\n margin-bottom: 24px;\\n}\\n.hw-powered {\\n text-align: center;\\n padding: 8px;\\n font-size: 11px;\\n color: var(--hw-text-4);\\n flex-shrink: 0;\\n}\\n.hw-powered a {\\n color: var(--hw-text-2);\\n text-decoration: none;\\n font-weight: 500;\\n}\\n.hw-powered a:hover {\\n color: var(--hw-text);\\n}\\n@media (max-width: 479px) {\\n .hw-widget {\\n bottom: 16px;\\n right: 16px;\\n left: auto;\\n }\\n .hw-window {\\n position: fixed;\\n top: 0;\\n left: 0;\\n right: 0;\\n bottom: 0;\\n width: 100%;\\n height: var(--hw-visible-height, 100%);\\n border-radius: 0;\\n animation: hw-mob-up 0.3s cubic-bezier(0.22, 1, 0.36, 1);\\n }\\n .hw-window--closing {\\n animation: hw-mob-down 0.2s ease forwards;\\n }\\n @keyframes hw-mob-up {\\n from {\\n opacity: 0;\\n transform: translateY(100%);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n }\\n @keyframes hw-mob-down {\\n from {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n to {\\n opacity: 0;\\n transform: translateY(100%);\\n }\\n }\\n .hw-hero {\\n padding-top: calc(20px + env(safe-area-inset-top, 0px));\\n }\\n .hw-header {\\n padding-top: env(safe-area-inset-top, 0px);\\n }\\n .hw-tabs {\\n padding-bottom: env(safe-area-inset-bottom, 0px);\\n }\\n .hw-composer {\\n padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));\\n }\\n .hw-powered {\\n padding-bottom: calc(5px + env(safe-area-inset-bottom, 0px));\\n }\\n .hw-header-close,\\n .hw-header-back,\\n .hw-header-action {\\n width: 34px;\\n height: 34px;\\n }\\n .hw-composer-send {\\n width: 40px;\\n height: 40px;\\n }\\n .hw-window ~ .hw-bubble {\\n display: none;\\n }\\n .hw-messages {\\n padding: 12px 14px;\\n }\\n .hw-msg {\\n max-width: 82%;\\n }\\n .hw-msg--ai {\\n max-width: 100%;\\n }\\n}\\n.hw-preview {\\n position: absolute;\\n bottom: calc(100% + 12px);\\n right: 0;\\n width: 300px;\\n max-width: calc(100vw - 40px);\\n background: var(--hw-bg);\\n border: 1px solid var(--hw-border);\\n border-radius: 16px;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);\\n animation: hw-preview-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\\n overflow: hidden;\\n cursor: pointer;\\n transition: transform 0.15s, box-shadow 0.15s;\\n}\\n.hw-preview.hw-preview--anchored {\\n position: static;\\n bottom: auto;\\n right: auto;\\n width: 100%;\\n max-width: 100%;\\n}\\n.hw-preview.hw-preview--anchored .hw-preview-avatar {\\n background: none;\\n}\\n.hw-preview.hw-preview--anchored .hw-preview-avatar img,\\n.hw-preview.hw-preview--anchored .hw-preview-avatar svg {\\n width: 100%;\\n height: 100%;\\n object-fit: contain;\\n}\\n.hw-preview:hover {\\n transform: translateY(-2px);\\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.08);\\n}\\n@keyframes hw-preview-in {\\n from {\\n opacity: 0;\\n transform: translateY(8px) scale(0.95);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0) scale(1);\\n }\\n}\\n@keyframes hw-preview-out {\\n from {\\n opacity: 1;\\n transform: translateY(0) scale(1);\\n }\\n to {\\n opacity: 0;\\n transform: translateY(8px) scale(0.95);\\n }\\n}\\n.hw-preview-header {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n padding: 12px 14px 0;\\n}\\n.hw-preview-avatar {\\n width: 28px;\\n height: 28px;\\n border-radius: 50%;\\n background:\\n linear-gradient(\\n 135deg,\\n var(--hw-primary),\\n color-mix(in srgb, var(--hw-primary) 50%, black));\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n color: white;\\n flex-shrink: 0;\\n overflow: hidden;\\n}\\n.hw-preview-avatar svg {\\n width: 16px;\\n height: 16px;\\n}\\n.hw-preview-avatar img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n display: block;\\n}\\n.hw-preview-name {\\n font-size: 13px;\\n font-weight: 600;\\n color: var(--hw-text);\\n flex: 1;\\n}\\n.hw-preview-close {\\n width: 24px;\\n height: 24px;\\n border: none;\\n background: transparent;\\n color: var(--hw-text-3);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 50%;\\n transition: background 0.15s, color 0.15s;\\n flex-shrink: 0;\\n}\\n.hw-preview-close:hover {\\n background: var(--hw-bg-subtle);\\n color: var(--hw-text-2);\\n}\\n.hw-preview-close:active {\\n transform: scale(0.90);\\n transition:\\n transform 0.14s cubic-bezier(0.23, 1, 0.32, 1),\\n background 0.15s,\\n color 0.15s;\\n}\\n.hw-preview-close svg {\\n width: 12px;\\n height: 12px;\\n}\\n.hw-preview-body {\\n padding: 4px 14px;\\n font-size: 14px;\\n line-height: 1.45;\\n color: var(--hw-text-2);\\n}\\n.hw-preview-body:first-of-type {\\n padding-top: 8px;\\n}\\n.hw-preview-body:last-child {\\n padding-bottom: 14px;\\n}\\n.hw-preview-footer {\\n margin-top: 2px;\\n padding: 8px 14px 12px;\\n border-top: 1px solid var(--hw-border);\\n font-size: 11px;\\n line-height: 1.3;\\n color: var(--hw-text-2);\\n opacity: 0.65;\\n}\\n.hw-preview-prompt {\\n padding: 2px 14px 6px;\\n font-size: 14px;\\n font-weight: 500;\\n color: var(--hw-text-1);\\n}\\n.hw-preview-quick-replies {\\n padding: 0 14px 14px;\\n margin-top: 0;\\n}\\n.hw-preview--closing {\\n animation: hw-preview-out 0.2s ease-in forwards;\\n}\\n.hw-preview-stack {\\n position: absolute;\\n bottom: calc(100% + 12px);\\n right: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n}\\n.hw-preview-stack .hw-preview {\\n position: relative;\\n bottom: auto;\\n right: auto;\\n}\\n.hw-preview-stack.hw-preview-stack--anchored {\\n position: static;\\n bottom: auto;\\n right: auto;\\n width: 100%;\\n}\\n.hw-preview--announcement {\\n width: 340px;\\n}\\n.hw-preview--announcement .hw-preview-body--title {\\n font-weight: 600;\\n color: var(--hw-text);\\n font-size: 15px;\\n line-height: 1.3;\\n padding-top: 10px;\\n}\\n.hw-preview--announcement .hw-preview-body--desc {\\n font-size: 13px;\\n color: var(--hw-text-2);\\n line-height: 1.5;\\n padding-bottom: 16px;\\n}\\n.hw-announcement-badge {\\n display: inline-block;\\n margin: 8px 14px 0;\\n padding: 2px 8px;\\n font-size: 10px;\\n font-weight: 700;\\n text-transform: uppercase;\\n letter-spacing: 0.04em;\\n color: var(--hw-primary);\\n background: color-mix(in srgb, var(--hw-primary) 10%, transparent);\\n border-radius: 4px;\\n}\\n.hw-whats-new {\\n border-radius: 14px;\\n background: var(--hw-bg);\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.03);\\n overflow: hidden;\\n}\\n.hw-whats-new-header {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 12px 14px 0;\\n}\\n.hw-whats-new-title {\\n font-size: 12px;\\n font-weight: 600;\\n color: var(--hw-text-2);\\n}\\n.hw-whats-new-view-all {\\n font-size: 11px;\\n font-weight: 500;\\n color: var(--hw-primary);\\n background: none;\\n border: none;\\n cursor: pointer;\\n padding: 0;\\n font-family: inherit;\\n}\\n.hw-whats-new-view-all:hover {\\n opacity: 0.8;\\n}\\n.hw-whats-new-list {\\n display: flex;\\n flex-direction: column;\\n}\\n.hw-whats-new-item {\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n width: 100%;\\n padding: 10px 14px;\\n border: none;\\n border-bottom: 1px solid var(--hw-border);\\n background: none;\\n cursor: pointer;\\n text-align: left;\\n font-family: inherit;\\n color: var(--hw-text);\\n transition: background-color 140ms ease;\\n}\\n.hw-whats-new-item:last-child {\\n border-bottom: none;\\n}\\n.hw-whats-new-item:hover {\\n background: rgba(0, 0, 0, 0.03);\\n}\\n.hw-whats-new-item-top {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n}\\n.hw-whats-new-badge {\\n font-size: 10px;\\n font-weight: 700;\\n text-transform: uppercase;\\n letter-spacing: 0.04em;\\n color: var(--hw-primary);\\n}\\n.hw-whats-new-time {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n margin-left: auto;\\n}\\n.hw-whats-new-item-title {\\n font-size: 13px;\\n font-weight: 600;\\n color: var(--hw-text);\\n line-height: 1.3;\\n display: flex;\\n align-items: baseline;\\n gap: 8px;\\n}\\n.hw-whats-new-time-inline {\\n font-size: 11px;\\n font-weight: 400;\\n color: var(--hw-text-3);\\n margin-left: auto;\\n flex-shrink: 0;\\n}\\n.hw-whats-new-item-body {\\n font-size: 12px;\\n color: var(--hw-text-2);\\n line-height: 1.4;\\n}\\n.hw-tabs-dot {\\n position: absolute;\\n top: -2px;\\n right: -6px;\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: var(--hw-primary);\\n animation: hw-badge-pop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\\n}\\n.hw-bubble-badge-dot {\\n display: block;\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: white;\\n}\\n.hw-content-search {\\n padding: 10px 16px;\\n}\\n.hw-content-search-box {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n padding: 8px 12px;\\n background: var(--hw-bg);\\n border: 1px solid var(--hw-border-md);\\n border-radius: 10px;\\n transition: border-color 0.15s, box-shadow 0.15s;\\n}\\n.hw-content-search-box:focus-within {\\n border-color: var(--hw-focus-border);\\n box-shadow: 0 0 0 3px var(--hw-focus-ring);\\n}\\n.hw-content-search-input {\\n flex: 1;\\n border: none !important;\\n outline: none !important;\\n box-shadow: none !important;\\n background: none;\\n font-size: 13px;\\n color: var(--hw-text-1);\\n font-family: inherit;\\n line-height: 1;\\n -webkit-appearance: none;\\n}\\n.hw-content-search-input:focus,\\n.hw-content-search-input:focus-visible {\\n outline: none !important;\\n box-shadow: none !important;\\n border: none !important;\\n}\\n.hw-content-search-input::placeholder {\\n color: var(--hw-text-3);\\n}\\n.hw-content-search-icon {\\n width: 15px;\\n height: 15px;\\n color: var(--hw-text-3);\\n flex-shrink: 0;\\n}\\n.hw-content-list {\\n display: flex;\\n flex-direction: column;\\n height: 100%;\\n}\\n.hw-content-entries {\\n flex: 1;\\n overflow-y: auto;\\n overscroll-behavior: contain;\\n}\\n.hw-content-entry {\\n display: block;\\n width: 100%;\\n padding: 14px 16px;\\n border: none;\\n border-bottom: 1px solid var(--hw-border);\\n background: none;\\n cursor: pointer;\\n text-align: left;\\n transition: background-color 0.15s ease;\\n -webkit-tap-highlight-color: transparent;\\n}\\n.hw-content-entry:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-content-entry:active {\\n background: var(--hw-border);\\n}\\n.hw-content-entry:last-child {\\n border-bottom: none;\\n}\\n.hw-content-entry-main {\\n display: flex;\\n align-items: center;\\n gap: 12px;\\n}\\n.hw-content-entry-text {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 3px;\\n}\\n.hw-content-entry-title {\\n font-size: 14px;\\n font-weight: 600;\\n color: var(--hw-text-1);\\n line-height: 1.3;\\n}\\n.hw-content-entry-desc {\\n font-size: 13px;\\n color: var(--hw-text-2);\\n line-height: 1.4;\\n display: -webkit-box;\\n -webkit-line-clamp: 2;\\n -webkit-box-orient: vertical;\\n overflow: hidden;\\n}\\n.hw-content-entry-meta {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n margin-top: 2px;\\n}\\n.hw-content-entry-badge {\\n font-size: 11px;\\n font-weight: 500;\\n color: var(--hw-text-3);\\n background: var(--hw-bg-hover);\\n padding: 1px 6px;\\n border-radius: 4px;\\n}\\n.hw-content-entry-date {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n}\\n.hw-content-entry-chevron {\\n width: 16px;\\n height: 16px;\\n color: var(--hw-text-3);\\n flex-shrink: 0;\\n opacity: 0.5;\\n}\\n.hw-content-detail {\\n padding: 16px;\\n overflow-y: auto;\\n overscroll-behavior: contain;\\n flex: 1;\\n min-height: 0;\\n}\\n.hw-content-detail-header {\\n margin-bottom: 16px;\\n}\\n.hw-content-detail-title {\\n font-size: 17px;\\n font-weight: 700;\\n color: var(--hw-text-1);\\n margin: 0 0 6px;\\n line-height: 1.3;\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n}\\n.hw-content-detail-meta {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n.hw-content-detail-date {\\n font-size: 12px;\\n color: var(--hw-text-3);\\n}\\n.hw-content-detail-body {\\n font-size: 14px;\\n line-height: 1.6;\\n color: var(--hw-text-1);\\n}\\n.hw-markdown h1 {\\n font-size: 17px;\\n font-weight: 700;\\n margin: 0;\\n}\\n.hw-markdown h2 {\\n font-size: 15px;\\n font-weight: 600;\\n margin: 0;\\n}\\n.hw-markdown h3 {\\n font-size: 14px;\\n font-weight: 600;\\n margin: 0;\\n}\\n.hw-markdown p {\\n margin: 0;\\n}\\n.hw-markdown p:empty,\\n.hw-markdown div:empty,\\n.hw-markdown p:has(> br:only-child),\\n.hw-markdown div:has(> br:only-child) {\\n display: none;\\n}\\n.hw-markdown > * + * {\\n margin-top: 12px;\\n}\\n.hw-markdown > * + h1,\\n.hw-markdown > * + h2 {\\n margin-top: 20px;\\n}\\n.hw-markdown > * + h3 {\\n margin-top: 16px;\\n}\\n.hw-markdown > h1 + *,\\n.hw-markdown > h2 + *,\\n.hw-markdown > h3 + * {\\n margin-top: 8px;\\n}\\n.hw-markdown > *:first-child {\\n margin-top: 0;\\n}\\n.hw-markdown > *:last-child {\\n margin-bottom: 0;\\n}\\n.hw-markdown > br {\\n display: none;\\n}\\n.hw-markdown ul,\\n.hw-markdown ol {\\n margin: 0;\\n padding-left: 20px;\\n}\\n.hw-markdown li {\\n margin: 4px 0;\\n}\\n.hw-markdown code {\\n font-family:\\n ui-monospace,\\n \\\"SF Mono\\\",\\n monospace;\\n font-size: 12px;\\n background: var(--hw-bg-hover);\\n padding: 1px 5px;\\n border-radius: 4px;\\n}\\n.hw-table-wrap {\\n margin: 10px 0;\\n overflow-x: auto;\\n border: 1px solid var(--hw-border, rgba(0, 0, 0, 0.08));\\n border-radius: 10px;\\n}\\n.hw-table {\\n width: 100%;\\n border-collapse: collapse;\\n font-size: 13px;\\n}\\n.hw-table th {\\n text-align: left;\\n font-weight: 600;\\n font-size: 12px;\\n padding: 8px 12px;\\n background: var(--hw-bg-hover, #f5f5f4);\\n border-bottom: 1px solid var(--hw-border, rgba(0, 0, 0, 0.08));\\n}\\n.hw-table td {\\n padding: 8px 12px;\\n border-bottom: 1px solid var(--hw-border, rgba(0, 0, 0, 0.06));\\n vertical-align: top;\\n}\\n.hw-table tbody tr:last-child td {\\n border-bottom: none;\\n}\\n.hw-code {\\n margin: 10px 0;\\n border-radius: 10px;\\n overflow: hidden;\\n border: 1px solid var(--hw-border, rgba(0, 0, 0, 0.08));\\n background: var(--hw-bg-hover, #f5f5f4);\\n font-family:\\n ui-monospace,\\n \\\"SF Mono\\\",\\n \\\"Menlo\\\",\\n monospace;\\n}\\n.hw-code-header {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 10px;\\n padding: 7px 8px 7px 12px;\\n font-size: 11px;\\n color: var(--hw-text-2, #6b7280);\\n background: rgba(0, 0, 0, 0.03);\\n border-bottom: 1px solid var(--hw-border, rgba(0, 0, 0, 0.06));\\n}\\n.hw-code-lang {\\n text-transform: lowercase;\\n letter-spacing: 0.02em;\\n font-weight: 500;\\n}\\n.hw-code-actions {\\n display: inline-flex;\\n align-items: center;\\n gap: 1px;\\n}\\n.hw-code-action {\\n position: relative;\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n width: 22px;\\n height: 22px;\\n padding: 0;\\n font-family: inherit;\\n color: var(--hw-text-2, #6b7280);\\n background: transparent;\\n border: 1px solid transparent;\\n border-radius: 6px;\\n cursor: pointer;\\n opacity: 0.62;\\n transition:\\n background 120ms ease,\\n color 120ms ease,\\n opacity 120ms ease,\\n scale 120ms ease;\\n}\\n.hw-code-action:hover {\\n color: var(--hw-text, #111);\\n background: rgba(0, 0, 0, 0.06);\\n opacity: 1;\\n}\\n.hw-code-action:active {\\n scale: 0.96;\\n}\\n.hw-code-action svg {\\n width: 13px;\\n height: 13px;\\n}\\n.hw-code-copy-icon,\\n.hw-code-check-icon {\\n position: absolute;\\n inset: 50% auto auto 50%;\\n transition:\\n opacity 180ms cubic-bezier(0.2, 0, 0, 1),\\n scale 180ms cubic-bezier(0.2, 0, 0, 1),\\n filter 180ms cubic-bezier(0.2, 0, 0, 1);\\n translate: -50% -50%;\\n}\\n.hw-code-check-icon {\\n filter: blur(4px);\\n opacity: 0;\\n scale: 0.25;\\n}\\n.hw-code-copy--copied .hw-code-copy-icon {\\n filter: blur(4px);\\n opacity: 0;\\n scale: 0.25;\\n}\\n.hw-code-copy--copied .hw-code-check-icon {\\n filter: blur(0);\\n opacity: 1;\\n scale: 1;\\n}\\n.hw-code-copy-label {\\n position: absolute;\\n width: 1px;\\n height: 1px;\\n overflow: hidden;\\n clip: rect(0, 0, 0, 0);\\n white-space: nowrap;\\n}\\n.hw-code-copy--copied {\\n color: #16a34a;\\n}\\n.hw-code-copy--failed {\\n color: #dc2626;\\n}\\n.hw-code pre {\\n margin: 0;\\n padding: 10px 12px;\\n background: transparent;\\n border-radius: 0;\\n overflow-x: auto;\\n max-width: 100%;\\n max-height: 320px;\\n scrollbar-color: rgba(0, 0, 0, 0.22) transparent;\\n scrollbar-width: thin;\\n}\\n.hw-code pre::-webkit-scrollbar {\\n width: 10px;\\n height: 10px;\\n}\\n.hw-code pre::-webkit-scrollbar-track {\\n background: transparent;\\n}\\n.hw-code pre::-webkit-scrollbar-thumb {\\n background: rgba(0, 0, 0, 0.18);\\n background-clip: content-box;\\n border: 3px solid transparent;\\n border-radius: 999px;\\n}\\n.hw-code pre::-webkit-scrollbar-thumb:hover {\\n background: rgba(0, 0, 0, 0.28);\\n background-clip: content-box;\\n}\\n.hw-code pre code {\\n display: block;\\n background: transparent;\\n padding: 0;\\n font-size: 12px;\\n line-height: 1.55;\\n white-space: pre;\\n color: var(--hw-text, #111);\\n}\\n@media (prefers-color-scheme: dark) {\\n .hw-code {\\n background: rgba(255, 255, 255, 0.04);\\n border-color: rgba(255, 255, 255, 0.08);\\n }\\n .hw-code-header {\\n background: rgba(255, 255, 255, 0.03);\\n border-bottom-color: rgba(255, 255, 255, 0.06);\\n }\\n .hw-code-action:hover,\\n .hw-code-action:focus-visible {\\n background: rgba(255, 255, 255, 0.08);\\n }\\n .hw-code pre {\\n scrollbar-color: rgba(255, 255, 255, 0.26) transparent;\\n }\\n .hw-code pre::-webkit-scrollbar-thumb {\\n background: rgba(255, 255, 255, 0.22);\\n background-clip: content-box;\\n }\\n .hw-code pre::-webkit-scrollbar-thumb:hover {\\n background: rgba(255, 255, 255, 0.32);\\n background-clip: content-box;\\n }\\n}\\n.hw-markdown pre {\\n margin: 8px 0;\\n padding: 10px 12px;\\n background: var(--hw-bg-hover);\\n border-radius: 8px;\\n overflow-x: auto;\\n max-width: 100%;\\n}\\n.hw-markdown pre code {\\n display: block;\\n background: transparent;\\n padding: 0;\\n border-radius: 0;\\n font-size: 12px;\\n line-height: 1.5;\\n white-space: pre;\\n word-break: normal;\\n color: inherit;\\n}\\n.hw-msg-bubble pre {\\n margin: 6px 0;\\n padding: 8px 10px;\\n background: rgba(0, 0, 0, 0.06);\\n border-radius: 6px;\\n overflow-x: auto;\\n max-width: 100%;\\n}\\n.hw-msg-bubble pre code {\\n background: transparent;\\n padding: 0;\\n font-size: 12px;\\n line-height: 1.5;\\n white-space: pre;\\n}\\n.hw-msg-bubble .hw-code pre {\\n margin: 0;\\n padding: 10px 12px;\\n background: transparent;\\n border-radius: 0;\\n}\\n.hw-msg-bubble .hw-code pre code {\\n background: transparent;\\n padding: 0;\\n font-size: 12px;\\n line-height: 1.55;\\n}\\n.hw-msg--team .hw-msg-bubble pre,\\n.hw-msg--visitor .hw-msg-bubble pre {\\n background: rgba(255, 255, 255, 0.12);\\n}\\n.hw-markdown blockquote {\\n margin: 0 0 12px;\\n padding: 8px 12px;\\n border-left: 3px solid var(--hw-border);\\n color: var(--hw-text-2);\\n font-style: italic;\\n}\\n.hw-markdown a {\\n color: var(--hw-primary);\\n text-decoration: underline;\\n text-underline-offset: 2px;\\n}\\n.hw-markdown img {\\n max-width: 100%;\\n border-radius: 8px;\\n margin: 8px 0;\\n outline: 1px solid rgba(0, 0, 0, 0.08);\\n outline-offset: -1px;\\n}\\n.hw-markdown hr {\\n border: none;\\n border-top: 1px solid var(--hw-border);\\n margin: 16px 0;\\n}\\n.hw-content-empty {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n padding: 40px 20px;\\n text-align: center;\\n}\\n.hw-content-empty-title {\\n font-size: 14px;\\n font-weight: 600;\\n color: var(--hw-text-1);\\n margin-bottom: 4px;\\n}\\n.hw-content-empty-desc {\\n font-size: 12px;\\n color: var(--hw-text-3);\\n}\\n.hw-content-loading {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 40px 20px;\\n}\\n.hw-content-load-more {\\n display: block;\\n width: 100%;\\n padding: 10px;\\n border: none;\\n background: none;\\n color: var(--hw-primary);\\n font-size: 13px;\\n font-weight: 500;\\n cursor: pointer;\\n text-align: center;\\n}\\n.hw-content-load-more:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-content-load-more:disabled {\\n opacity: 0.5;\\n cursor: default;\\n}\\n@media (hover: none) {\\n .hw-composer-preview-remove {\\n opacity: 0.7;\\n }\\n}\\n.hw-composer--dragging .hw-composer-box {\\n border-color: var(--hw-primary);\\n background: color-mix(in srgb, var(--hw-primary) 4%, transparent);\\n}\\n.hw-composer-drop-overlay {\\n position: absolute;\\n inset: 0;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n background: color-mix(in srgb, var(--hw-bg) 90%, transparent);\\n border: 2px dashed var(--hw-primary);\\n border-radius: 12px;\\n z-index: 10;\\n pointer-events: none;\\n animation: hw-drop-pulse 1.5s ease-in-out infinite;\\n}\\n.hw-composer-drop-text {\\n font-size: 13px;\\n font-weight: 500;\\n color: var(--hw-primary);\\n}\\n@keyframes hw-drop-pulse {\\n 0%, 100% {\\n opacity: 0.8;\\n }\\n 50% {\\n opacity: 1;\\n }\\n}\\n.hw-disconnect {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n gap: 7px;\\n padding: 7px 14px;\\n background: var(--hw-bg-hover);\\n color: var(--hw-text-2);\\n font-size: 11.5px;\\n font-weight: 500;\\n letter-spacing: -0.01em;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n flex-shrink: 0;\\n animation: hw-disconnect-in 0.18s cubic-bezier(0.22, 1, 0.36, 1);\\n}\\n@keyframes hw-disconnect-in {\\n from {\\n opacity: 0;\\n transform: translateY(-100%);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n.hw-disconnect-spinner {\\n width: 9px;\\n height: 9px;\\n border: 1.5px solid currentColor;\\n border-top-color: transparent;\\n border-radius: 50%;\\n opacity: 0.75;\\n flex-shrink: 0;\\n animation: hw-spin 0.7s linear infinite;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-disconnect {\\n animation: none;\\n }\\n .hw-disconnect-spinner {\\n animation: none;\\n border-top-color: currentColor;\\n opacity: 0.5;\\n }\\n}\\n.hw-error-state {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n padding: 32px 24px;\\n text-align: center;\\n gap: 12px;\\n}\\n.hw-error-icon {\\n width: 48px;\\n height: 48px;\\n border-radius: 50%;\\n background: #fef2f2;\\n color: #ef4444;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.hw-error-icon svg {\\n width: 24px;\\n height: 24px;\\n}\\n.hw-error-title {\\n font-size: 15px;\\n font-weight: 600;\\n color: var(--hw-text);\\n}\\n.hw-error-desc {\\n font-size: 13px;\\n color: var(--hw-text-2);\\n}\\n.hw-error-btn {\\n padding: 8px 20px;\\n border: 1px solid var(--hw-border-md);\\n border-radius: 8px;\\n background: var(--hw-bg);\\n color: var(--hw-text);\\n font-size: 13px;\\n font-weight: 500;\\n cursor: pointer;\\n transition: background 0.15s;\\n}\\n.hw-error-btn:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-send-error {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n padding: 8px 12px;\\n background: #fef2f2;\\n color: #dc2626;\\n font-size: 12px;\\n font-weight: 500;\\n flex-shrink: 0;\\n animation: hw-msg-appear 0.25s ease-out;\\n}\\n.hw-send-error-retry {\\n margin-left: auto;\\n padding: 2px 8px;\\n border: 1px solid #fca5a5;\\n border-radius: 4px;\\n background: none;\\n color: #dc2626;\\n font-size: 11px;\\n font-weight: 600;\\n cursor: pointer;\\n}\\n.hw-send-error-retry:hover {\\n background: #fee2e2;\\n}\\n.hw-resolved {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 12px;\\n padding: 16px 20px;\\n border-top: 1px solid var(--hw-border);\\n flex-shrink: 0;\\n}\\n.hw-resolved-text {\\n font-size: 13px;\\n color: var(--hw-text-3);\\n font-weight: 500;\\n}\\n.hw-resolved-actions {\\n display: flex;\\n gap: 8px;\\n}\\n.hw-resolved-reopen {\\n padding: 6px 16px;\\n border: 1px solid var(--hw-border-md);\\n border-radius: 8px;\\n background: var(--hw-bg);\\n color: var(--hw-text);\\n font-size: 13px;\\n font-weight: 500;\\n cursor: pointer;\\n transition: background 0.15s;\\n}\\n.hw-resolved-reopen:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-csat {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 8px;\\n}\\n.hw-csat-label {\\n font-size: 12px;\\n color: var(--hw-text-3);\\n}\\n.hw-csat-buttons {\\n display: flex;\\n gap: 8px;\\n}\\n.hw-csat-btn {\\n width: 36px;\\n height: 36px;\\n border: 1px solid var(--hw-border-md);\\n border-radius: 8px;\\n background: var(--hw-bg);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 18px;\\n transition:\\n transform 0.15s,\\n border-color 0.15s,\\n background 0.15s;\\n}\\n.hw-csat-btn:hover {\\n transform: scale(1.1);\\n border-color: var(--hw-text-3);\\n}\\n.hw-csat-btn--selected {\\n border-color: var(--hw-primary);\\n background: var(--hw-bg-hover);\\n transform: scale(1.15);\\n}\\n.hw-csat-thanks {\\n font-size: 12px;\\n color: #22c55e;\\n font-weight: 500;\\n animation: hw-msg-appear 0.25s ease-out;\\n}\\n.hw-load-more-trigger {\\n display: flex;\\n justify-content: center;\\n min-height: 1px;\\n}\\n.hw-load-more-trigger:has(.hw-load-more-spinner) {\\n padding: 8px 0;\\n}\\n.hw-load-more-spinner {\\n display: flex;\\n gap: 3px;\\n}\\n.hw-load-more-spinner > div {\\n width: 5px;\\n height: 5px;\\n border-radius: 50%;\\n background: var(--hw-text-4);\\n animation: hw-loading-pulse 1.4s infinite;\\n}\\n.hw-load-more-spinner > div:nth-child(2) {\\n animation-delay: 0.2s;\\n}\\n.hw-load-more-spinner > div:nth-child(3) {\\n animation-delay: 0.4s;\\n}\\n.hw-drag-handle {\\n display: none;\\n}\\n@media (max-width: 479px) {\\n .hw-drag-handle {\\n display: flex;\\n justify-content: center;\\n padding: 8px 0 4px;\\n flex-shrink: 0;\\n }\\n .hw-drag-handle-pill {\\n width: 32px;\\n height: 4px;\\n border-radius: 2px;\\n background: var(--hw-text-4);\\n }\\n}\\n.hw-msg-bubble p {\\n margin: 0 0 8px;\\n}\\n.hw-msg-bubble p:last-child {\\n margin-bottom: 0;\\n}\\n.hw-msg-bubble strong {\\n font-weight: 600;\\n}\\n.hw-msg-bubble em {\\n font-style: italic;\\n}\\n.hw-msg-bubble a {\\n color: inherit;\\n text-decoration: underline;\\n text-decoration-thickness: 1px;\\n text-underline-offset: 2px;\\n text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);\\n word-break: normal;\\n overflow-wrap: anywhere;\\n}\\n.hw-msg-bubble a:hover {\\n opacity: 0.8;\\n}\\n.hw-msg--visitor .hw-msg-bubble a {\\n color: rgba(255, 255, 255, 0.9);\\n}\\n.hw-msg--visitor .hw-msg-bubble a:hover {\\n color: white;\\n}\\n.hw-msg-bubble ul,\\n.hw-msg-bubble ol {\\n margin: 4px 0 8px;\\n padding-left: 20px;\\n}\\n.hw-msg-bubble li {\\n margin: 2px 0;\\n}\\n.hw-msg-bubble code {\\n padding: 1px 4px;\\n border-radius: 3px;\\n background: rgba(0, 0, 0, 0.06);\\n font-size: 0.9em;\\n font-family:\\n ui-monospace,\\n SFMono-Regular,\\n Menlo,\\n monospace;\\n}\\n.hw-msg-bubble pre {\\n margin: 4px 0 8px;\\n padding: 8px 10px;\\n border-radius: 6px;\\n background: rgba(0, 0, 0, 0.06);\\n overflow-x: auto;\\n font-size: 0.85em;\\n}\\n.hw-msg-bubble pre code {\\n padding: 0;\\n background: none;\\n}\\n.hw-msg-bubble blockquote {\\n margin: 4px 0 8px;\\n padding: 4px 0 4px 12px;\\n border-left: 3px solid var(--hw-border-md);\\n color: var(--hw-text-2);\\n}\\n.hw-widget[data-theme=dark] {\\n --hw-bg: #1c1c1e;\\n --hw-bg-subtle: #161618;\\n --hw-bg-hover: #2c2c2e;\\n --hw-border: rgba(255, 255, 255, 0.08);\\n --hw-border-md: rgba(255, 255, 255, 0.14);\\n --hw-text: #f5f5f5;\\n --hw-text-1: #f5f5f5;\\n --hw-text-2: #a1a1aa;\\n --hw-text-3: #71717a;\\n --hw-text-4: #52525b;\\n --hw-visitor-bubble-bg: #2c2c2e;\\n --hw-visitor-bubble-text: #f5f5f5;\\n --hw-focus-border: rgba(255, 255, 255, 0.28);\\n --hw-focus-ring: rgba(255, 255, 255, 0.08);\\n --hw-brand: #f5f5f5;\\n --hw-on-brand: #1c1c1e;\\n}\\n@media (prefers-color-scheme: dark) {\\n .hw-widget:not([data-theme=light]) .hw-messages {\\n scrollbar-color: rgba(255, 255, 255, 0.26) transparent;\\n }\\n .hw-widget:not([data-theme=light]) .hw-messages::-webkit-scrollbar-thumb {\\n background: rgba(255, 255, 255, 0.2);\\n background-clip: content-box;\\n }\\n .hw-widget:not([data-theme=light]) .hw-messages::-webkit-scrollbar-thumb:hover {\\n background: rgba(255, 255, 255, 0.32);\\n background-clip: content-box;\\n }\\n .hw-widget:not([data-theme=light]) {\\n --hw-bg: #1c1c1e;\\n --hw-bg-subtle: #161618;\\n --hw-bg-hover: #2c2c2e;\\n --hw-border: rgba(255, 255, 255, 0.08);\\n --hw-border-md: rgba(255, 255, 255, 0.14);\\n --hw-text: #f5f5f5;\\n --hw-text-1: #f5f5f5;\\n --hw-text-2: #a1a1aa;\\n --hw-text-3: #71717a;\\n --hw-text-4: #52525b;\\n --hw-visitor-bubble-bg: #2c2c2e;\\n --hw-visitor-bubble-text: #f5f5f5;\\n --hw-focus-border: rgba(255, 255, 255, 0.28);\\n --hw-focus-ring: rgba(255, 255, 255, 0.08);\\n --hw-brand: #f5f5f5;\\n --hw-on-brand: #1c1c1e;\\n }\\n}\\n@media (prefers-color-scheme: dark) {\\n .hw-widget:not([data-theme=light]) .hw-header {\\n background: var(--hw-bg);\\n border-color: var(--hw-border);\\n }\\n .hw-header-bot-icon {\\n background: var(--hw-bg-hover);\\n }\\n .hw-header-name,\\n .hw-header-title {\\n color: var(--hw-text);\\n }\\n .hw-header-status {\\n color: var(--hw-text-2);\\n }\\n .hw-header-close,\\n .hw-header-back {\\n color: var(--hw-text-2);\\n }\\n .hw-header-close:hover,\\n .hw-header-back:hover {\\n background: var(--hw-bg-hover);\\n color: var(--hw-text);\\n }\\n .hw-content-entry {\\n background: var(--hw-bg);\\n border-color: var(--hw-border);\\n }\\n .hw-content-entry:hover {\\n background: var(--hw-bg-hover);\\n border-color: var(--hw-border-md);\\n }\\n .hw-content-empty,\\n .hw-empty {\\n color: var(--hw-text-3);\\n }\\n .hw-conv-card {\\n border-color: var(--hw-border);\\n }\\n .hw-recent-row {\\n border-color: var(--hw-border);\\n }\\n .hw-composer-drop-overlay {\\n background: rgba(0, 0, 0, 0.6);\\n color: var(--hw-text);\\n }\\n .hw-composer--dragging .hw-composer-box {\\n border-color: var(--hw-focus-border);\\n box-shadow: 0 0 0 3px var(--hw-focus-ring);\\n }\\n .hw-hero {\\n background:\\n linear-gradient(\\n 160deg,\\n color-mix(in srgb, var(--hw-primary) 40%, black) 0%,\\n var(--hw-primary) 50%,\\n color-mix(in srgb, var(--hw-primary) 25%, black) 100%);\\n }\\n .hw-sheet {\\n background: var(--hw-bg);\\n }\\n .hw-card {\\n background: var(--hw-bg-hover);\\n border-color: var(--hw-border);\\n }\\n .hw-card:hover {\\n background: #333;\\n }\\n .hw-window {\\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.06);\\n }\\n .hw-bubble:focus-visible {\\n outline-color: var(--hw-text-3);\\n }\\n .hw-msg--visitor .hw-msg-bubble {\\n background: var(--hw-primary);\\n color: white;\\n }\\n .hw-msg-bubble code {\\n background: rgba(255, 255, 255, 0.08);\\n }\\n .hw-msg-bubble pre {\\n background: rgba(255, 255, 255, 0.08);\\n }\\n .hw-composer-box {\\n background: var(--hw-bg);\\n border-color: var(--hw-border);\\n }\\n .hw-composer-input {\\n color: var(--hw-text);\\n }\\n .hw-tabs {\\n background: var(--hw-bg);\\n border-color: var(--hw-border);\\n }\\n .hw-conv-card:hover,\\n .hw-recent-row:hover {\\n background: var(--hw-bg-hover);\\n }\\n .hw-send-error {\\n background: #450a0a;\\n color: #fca5a5;\\n }\\n .hw-error-icon {\\n background: #450a0a;\\n color: #f87171;\\n }\\n .hw-resolved {\\n border-color: var(--hw-border);\\n }\\n .hw-resolved-reopen,\\n .hw-csat-btn {\\n background: var(--hw-bg-hover);\\n border-color: var(--hw-border-md);\\n color: var(--hw-text);\\n }\\n .hw-hover-preview {\\n background: #1c1c1e;\\n border-color: var(--hw-border);\\n }\\n .hw-content-search-box {\\n background: var(--hw-bg-hover);\\n border-color: var(--hw-border-md);\\n }\\n .hw-preview {\\n background: var(--hw-bg);\\n border-color: var(--hw-border);\\n }\\n}\\n.hw-widget[data-hw-placement=docked] {\\n --hw-dock-width: 600px;\\n --hw-dock-bar-width: 480px;\\n --hw-dock-inset: 24px;\\n --hw-bar-max-height: 148px;\\n --hw-dock-surface: #ffffff;\\n --hw-dock-on-surface: #111111;\\n --hw-dock-pill-bg: rgba(44, 44, 48, 0.66);\\n --hw-dock-pill-fg: rgba(255, 255, 255, 0.94);\\n --hw-dock-pill-border: rgba(255, 255, 255, 0.14);\\n}\\n.hw-widget[data-hw-placement=docked] {\\n z-index: 2147483000;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-dock {\\n position: fixed;\\n left: 0;\\n right: 0;\\n bottom: var(--hw-dock-inset);\\n z-index: 2147483000;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n pointer-events: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-dock > * {\\n pointer-events: auto;\\n}\\n.hw-dock-suggestions {\\n display: flex;\\n flex-direction: column;\\n align-items: flex-start;\\n gap: 9px;\\n width: var(--hw-dock-bar-width, var(--hw-dock-width));\\n max-width: calc(100vw - 32px);\\n margin-bottom: 14px;\\n}\\n.hw-dock-pill-row {\\n align-self: flex-start;\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n animation: hw-dock-pill-in 0.42s cubic-bezier(0.2, 0.9, 0.3, 1) both;\\n}\\n.hw-dock-pill-dismiss {\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n width: 20px;\\n height: 20px;\\n flex-shrink: 0;\\n padding: 0;\\n border: 0;\\n background: none;\\n color: var(--hw-dock-pill-fg);\\n cursor: pointer;\\n align-self: flex-start;\\n margin-top: 8px;\\n opacity: 0;\\n transform: scale(0.85);\\n transition:\\n opacity 0.12s linear,\\n transform 0.12s cubic-bezier(0.25, 1, 0.5, 1),\\n color 0.12s linear;\\n}\\n.hw-dock-pill-dismiss svg {\\n width: 11px;\\n height: 11px;\\n}\\n.hw-dock-suggestions:hover .hw-dock-pill-dismiss,\\n.hw-dock-suggestions:focus-within .hw-dock-pill-dismiss {\\n opacity: 1;\\n transform: none;\\n}\\n.hw-dock-pill-dismiss:hover {\\n color: var(--hw-dock-on-surface);\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-dock-pill-dismiss {\\n transition: none;\\n }\\n}\\n@media (hover: none) {\\n .hw-dock-pill-dismiss {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n.hw-dock-pill {\\n align-self: flex-start;\\n padding: 10px 18px;\\n border: 1px solid var(--hw-dock-pill-border, transparent);\\n border-radius: 999px;\\n cursor: pointer;\\n font: inherit;\\n font-size: 14px;\\n font-weight: 500;\\n text-align: left;\\n background: var(--hw-dock-pill-bg);\\n color: var(--hw-dock-pill-fg);\\n backdrop-filter: blur(10px) saturate(1.2);\\n -webkit-backdrop-filter: blur(10px) saturate(1.2);\\n box-shadow: 0 4px 14px -8px rgba(12, 11, 10, 0.28);\\n transition:\\n background 0.16s,\\n border-color 0.16s,\\n transform 0.16s;\\n}\\n.hw-dock-pill {\\n backdrop-filter: blur(18px);\\n -webkit-backdrop-filter: blur(18px);\\n}\\n.hw-dock-pill:hover {\\n background: color-mix(in srgb, var(--hw-dock-pill-bg) 100%, var(--hw-dock-on-surface) 8%);\\n border-color: color-mix(in srgb, var(--hw-dock-pill-border) 100%, var(--hw-dock-on-surface) 10%);\\n transform: translateX(3px);\\n}\\n@keyframes hw-dock-pill-in {\\n from {\\n opacity: 0;\\n transform: translateY(10px) scale(0.97);\\n }\\n to {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n.hw-dock-bar {\\n display: flex;\\n align-items: flex-end;\\n gap: 10px;\\n width: var(--hw-dock-bar-width, var(--hw-dock-width));\\n max-width: calc(100vw - 32px);\\n min-height: 52px;\\n padding: 10px 10px 10px 18px;\\n border: 0;\\n border-radius: 26px;\\n background: var(--hw-dock-surface);\\n color: var(--hw-dock-on-surface);\\n box-shadow:\\n inset 0 1px 0 color-mix(in srgb, var(--hw-dock-on-surface) 9%, transparent),\\n 0 0 0 1px color-mix(in srgb, var(--hw-dock-on-surface) 7%, transparent),\\n 0 2px 6px rgba(12, 11, 10, 0.18),\\n 0 20px 48px -14px rgba(12, 11, 10, 0.45);\\n transition:\\n border-radius 0.18s ease,\\n box-shadow 0.2s cubic-bezier(0.2, 0.8, 0.2, 1),\\n width 0.26s cubic-bezier(0.2, 0.8, 0.2, 1);\\n}\\n.hw-dock-bar:focus-within {\\n box-shadow:\\n inset 0 1px 0 color-mix(in srgb, var(--hw-dock-on-surface) 9%, transparent),\\n 0 0 0 1px color-mix(in srgb, var(--hw-primary, #fb923c) 60%, transparent),\\n 0 2px 6px rgba(12, 11, 10, 0.18),\\n 0 20px 48px -14px rgba(12, 11, 10, 0.45);\\n}\\n.hw-dock-bar[data-grown=true] {\\n border-radius: 20px;\\n}\\n.hw-dock-input {\\n flex: 1;\\n min-width: 0;\\n min-height: 20px;\\n max-height: var(--hw-bar-max-height);\\n padding: 6px 0;\\n border: 0;\\n outline: none;\\n resize: none;\\n overflow-y: auto;\\n background: transparent;\\n color: var(--hw-dock-on-surface);\\n font: inherit;\\n font-size: 14px;\\n line-height: 1.45;\\n transition: height 0.12s ease;\\n}\\n.hw-dock-input::placeholder {\\n color: color-mix(in srgb, var(--hw-dock-on-surface) 45%, transparent);\\n}\\n.hw-dock-send {\\n flex: none;\\n width: 32px;\\n height: 32px;\\n margin-bottom: 1px;\\n border: 0;\\n border-radius: 50%;\\n display: grid;\\n place-items: center;\\n cursor: pointer;\\n background: var(--hw-primary, #fb923c);\\n color: var(--hw-on-brand, #fff);\\n transition: transform 0.16s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.16s;\\n}\\n.hw-dock-send:hover:not(:disabled) {\\n transform: scale(1.06);\\n}\\n.hw-dock-send:disabled {\\n opacity: 0.45;\\n cursor: default;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window {\\n position: fixed;\\n left: 50%;\\n right: auto;\\n margin-left: calc(var(--hw-dock-width) / -2);\\n bottom: calc(var(--hw-dock-inset) + 66px);\\n width: var(--hw-dock-width);\\n max-width: calc(100vw - 32px);\\n height: 420px;\\n}\\n@media (max-width: 640px) {\\n .hw-widget[data-hw-placement=docked] .hw-window {\\n left: 16px;\\n right: 16px;\\n margin-left: 0;\\n width: auto;\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-bubble {\\n display: none;\\n}\\n.hw-widget[data-hw-placement=docked][data-hw-open=true] .hw-window {\\n bottom: calc(var(--hw-dock-inset) + 52px + 12px);\\n}\\n.hw-widget[data-hw-placement=docked][data-hw-open=true] .hw-dock-suggestions {\\n display: none;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-dock-pill,\\n .hw-dock-bar,\\n .hw-dock-input,\\n .hw-dock-send {\\n animation: none;\\n transition: none;\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-composer,\\n.hw-widget[data-hw-placement=docked] .hw-tabs,\\n.hw-widget[data-hw-placement=docked] .hw-footer-tabs {\\n display: none;\\n}\\n.hw-starters {\\n display: flex;\\n flex-direction: column;\\n margin-top: 10px;\\n border-radius: 14px;\\n overflow: hidden;\\n background: var(--hw-bg);\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n}\\n.hw-starter {\\n display: flex;\\n align-items: center;\\n gap: 10px;\\n width: 100%;\\n padding: 11px 14px;\\n border: 0;\\n border-radius: 0;\\n cursor: pointer;\\n background: transparent;\\n color: var(--hw-text);\\n font: inherit;\\n text-align: left;\\n animation: hw-starter-in 0.3s cubic-bezier(0.2, 0.8, 0.2, 1) both;\\n transition: background 0.12s;\\n}\\n.hw-starter + .hw-starter {\\n box-shadow: inset 0 1px 0 var(--hw-border);\\n}\\n.hw-starter:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-starter-text {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 1px;\\n}\\n.hw-starter-k {\\n font-size: 13px;\\n font-weight: 550;\\n line-height: 1.35;\\n color: var(--hw-text);\\n}\\n.hw-starter-q {\\n font-size: 12px;\\n line-height: 1.35;\\n color: var(--hw-text-3, var(--hw-text-muted));\\n}\\n.hw-starter svg {\\n flex: none;\\n color: var(--hw-text-3, var(--hw-text-muted));\\n opacity: 0.45;\\n transition: opacity 0.15s, transform 0.15s;\\n}\\n.hw-starter:hover svg {\\n opacity: 0.9;\\n transform: translateX(2px);\\n}\\n@keyframes hw-starter-in {\\n from {\\n opacity: 0;\\n transform: translateY(6px);\\n }\\n to {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-back {\\n display: none;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-starter {\\n animation: none;\\n }\\n}\\n@media (prefers-color-scheme: dark) {\\n .hw-widget:not([data-theme=light])[data-hw-placement=docked] {\\n --hw-dock-surface: #1f1f23;\\n --hw-dock-on-surface: #f4f4f6;\\n --hw-dock-pill-bg: rgba(255, 255, 255, 0.1);\\n --hw-dock-pill-fg: #e4e4e7;\\n --hw-dock-pill-border: rgba(255, 255, 255, 0.14);\\n }\\n}\\n.hw-widget[data-theme=dark][data-hw-placement=docked] {\\n --hw-dock-surface: #1f1f23;\\n --hw-dock-on-surface: #f4f4f6;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window {\\n --hw-bg: rgba(255, 255, 255, 0.08);\\n --hw-bg-subtle: transparent;\\n --hw-bg-hover: rgba(255, 255, 255, 0.1);\\n --hw-border: rgba(255, 255, 255, 0.14);\\n --hw-border-md: rgba(255, 255, 255, 0.22);\\n --hw-text: rgba(255, 255, 255, 0.94);\\n --hw-text-1: #ffffff;\\n --hw-text-2: rgba(255, 255, 255, 0.72);\\n --hw-text-3: rgba(255, 255, 255, 0.62);\\n --hw-text-4: rgba(255, 255, 255, 0.46);\\n --hw-visitor-bubble-bg: rgba(255, 255, 255, 0.16);\\n --hw-visitor-bubble-text: #ffffff;\\n --hw-brand: rgba(255, 255, 255, 0.92);\\n --hw-on-brand: #17161a;\\n --hw-focus-border: rgba(255, 255, 255, 0.34);\\n --hw-focus-ring: rgba(255, 255, 255, 0.1);\\n height: 500px;\\n max-height: calc(100vh - 180px);\\n border-radius: 24px;\\n color: var(--hw-text);\\n background:\\n linear-gradient(\\n 180deg,\\n rgba(40, 40, 44, 0.72) 0%,\\n rgba(46, 46, 50, 0.7) 55%,\\n rgba(52, 52, 56, 0.68) 100%);\\n backdrop-filter: blur(30px);\\n -webkit-backdrop-filter: blur(30px);\\n box-shadow: 0 24px 60px -20px rgba(12, 11, 10, 0.5), inset 0 0 0 1px rgba(255, 255, 255, 0.1);\\n}\\n@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {\\n .hw-widget[data-hw-placement=docked] .hw-window {\\n background: #2c2c2e;\\n }\\n}\\n@media (max-width: 640px) {\\n .hw-widget[data-hw-placement=docked] .hw-window {\\n height: min(60vh, 460px);\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header--sub {\\n padding: 14px 12px 8px 16px;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-status {\\n display: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-name {\\n font-size: 15.5px;\\n font-weight: 560;\\n letter-spacing: -0.006em;\\n color: var(--hw-text-1);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-menu-conv-name,\\n.hw-widget[data-hw-placement=docked] .hw-event-name {\\n font-weight: 545;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-bot-icon {\\n border-radius: 50%;\\n overflow: hidden;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-close:hover,\\n.hw-widget[data-hw-placement=docked] .hw-header-menu-btn:hover {\\n background: rgba(255, 255, 255, 0.12);\\n color: #ffffff;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-messages {\\n padding: 4px 22px 16px;\\n gap: 18px;\\n -webkit-mask-image:\\n linear-gradient(\\n 180deg,\\n transparent 0,\\n #000 16px);\\n mask-image:\\n linear-gradient(\\n 180deg,\\n transparent 0,\\n #000 16px);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-msg--ai .hw-msg-bubble,\\n.hw-widget[data-hw-placement=docked] .hw-msg--team .hw-msg-bubble {\\n padding: 0;\\n background: transparent;\\n border-radius: 0;\\n font-size: 15px;\\n line-height: 1.55;\\n color: var(--hw-text);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-msg--visitor .hw-msg-bubble {\\n background: rgba(255, 255, 255, 0.16);\\n color: #ffffff;\\n font-size: 14.5px;\\n line-height: 1.5;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-msg-bubble pre,\\n.hw-widget[data-hw-placement=docked] .hw-msg-bubble code {\\n background: rgba(0, 0, 0, 0.28);\\n color: var(--hw-text-1);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-email-card-row {\\n background: rgba(0, 0, 0, 0.26);\\n border-color: rgba(255, 255, 255, 0.14);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window :focus-visible {\\n outline-color: rgba(255, 255, 255, 0.55);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-email-card-input:focus,\\n.hw-widget[data-hw-placement=docked] .hw-email-card-input:focus-visible {\\n outline: none;\\n box-shadow: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-email-card-row:focus-within {\\n border-color: rgba(255, 255, 255, 0.42);\\n box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.08);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-email-card-submit {\\n background: #ffffff;\\n color: #17161a;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window .hw-header--sub {\\n position: relative;\\n z-index: 3;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-menu {\\n background: #3a3a3f;\\n box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.16), 0 18px 44px -12px rgba(12, 11, 10, 0.62);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-menu button:hover {\\n background: rgba(255, 255, 255, 0.11);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-menu button.hw-header-menu-conv[data-active=true] {\\n background: rgba(255, 255, 255, 0.09);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-menu-convs {\\n border-bottom-color: rgba(255, 255, 255, 0.12);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-event--card {\\n margin: 0;\\n background: rgba(255, 255, 255, 0.08);\\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-event-avatar {\\n background: rgba(255, 255, 255, 0.14);\\n color: var(--hw-text-1);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-preview {\\n position: fixed;\\n left: 50%;\\n right: auto;\\n margin-left: calc(var(--hw-dock-bar-width, var(--hw-dock-width)) / -2);\\n bottom: calc(var(--hw-dock-inset) + 52px + 12px);\\n width: var(--hw-dock-bar-width, var(--hw-dock-width));\\n max-width: calc(100vw - 32px);\\n border: 0;\\n border-radius: 24px;\\n color: rgba(255, 255, 255, 0.94);\\n background:\\n linear-gradient(\\n 180deg,\\n rgba(40, 40, 44, 0.74) 0%,\\n rgba(52, 52, 56, 0.7) 100%);\\n backdrop-filter: blur(30px);\\n -webkit-backdrop-filter: blur(30px);\\n box-shadow: 0 24px 60px -20px rgba(12, 11, 10, 0.5), inset 0 0 0 1px rgba(255, 255, 255, 0.1);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-preview-name,\\n.hw-widget[data-hw-placement=docked] .hw-preview-body {\\n color: rgba(255, 255, 255, 0.94);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-preview-close {\\n color: rgba(255, 255, 255, 0.6);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-preview-close:hover {\\n background: rgba(255, 255, 255, 0.12);\\n color: #ffffff;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-preview-footer {\\n color: rgba(255, 255, 255, 0.55);\\n border-top-color: rgba(255, 255, 255, 0.1);\\n}\\n@media (max-width: 640px) {\\n .hw-widget[data-hw-placement=docked] .hw-preview {\\n left: 16px;\\n right: 16px;\\n margin-left: 0;\\n width: auto;\\n }\\n}\\n@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {\\n .hw-widget[data-hw-placement=docked] .hw-preview {\\n background: #2c2c2e;\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-quick-reply-btn {\\n padding: 7px 14px;\\n font-size: 13px;\\n font-weight: 550;\\n border-radius: 999px;\\n background: rgba(255, 255, 255, 0.94);\\n box-shadow: 0 1px 3px rgba(12, 11, 10, 0.22);\\n color: #17161a;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-quick-reply-btn:hover:not(:disabled) {\\n background: #ffffff;\\n box-shadow: 0 4px 12px rgba(12, 11, 10, 0.28);\\n transform: translateY(-1px);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-quick-reply-btn[data-tapped=true] {\\n background: rgba(255, 255, 255, 0.22);\\n color: #ffffff;\\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3);\\n transform: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-quick-reply-btn svg {\\n opacity: 0.55;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-offer {\\n padding: 7px 14px;\\n font-size: 13px;\\n background: rgba(255, 255, 255, 0.94);\\n color: #17161a;\\n box-shadow: 0 1px 3px rgba(12, 11, 10, 0.22);\\n transition:\\n background 0.15s,\\n box-shadow 0.15s,\\n transform 0.15s;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-offer:hover {\\n background: #ffffff;\\n color: #17161a;\\n box-shadow: 0 4px 12px rgba(12, 11, 10, 0.28);\\n transform: translateY(-1px);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-offer svg {\\n opacity: 0.55;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-dock-bar {\\n --hw-dock-on-surface: rgba(255, 255, 255, 0.94);\\n color: rgba(255, 255, 255, 0.94);\\n background:\\n linear-gradient(\\n 180deg,\\n rgba(44, 44, 48, 0.74) 0%,\\n rgba(52, 52, 56, 0.72) 100%);\\n backdrop-filter: blur(30px);\\n -webkit-backdrop-filter: blur(30px);\\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12), 0 18px 40px -16px rgba(12, 11, 10, 0.45);\\n}\\n.hw-widget[data-hw-placement=docked][data-hw-open=true] .hw-dock-bar {\\n width: var(--hw-dock-width);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-dock-bar:focus-within {\\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.26), 0 18px 40px -16px rgba(12, 11, 10, 0.5);\\n}\\n.hw-widget[data-hw-placement=docked][data-hw-open=true] .hw-dock-bar {\\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14), 0 22px 52px -18px rgba(12, 11, 10, 0.52);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-dock-send:not(:disabled) {\\n background: #ffffff;\\n color: #17161a;\\n}\\n@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {\\n .hw-widget[data-hw-placement=docked] .hw-dock-bar {\\n background: #2c2c2e;\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window {\\n transform-origin: 50% 100%;\\n animation: hw-dock-panel-in 0.3s cubic-bezier(0.16, 1, 0.3, 1);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window--closing {\\n animation: hw-dock-panel-out 0.18s cubic-bezier(0.4, 0, 1, 1) forwards;\\n}\\n@keyframes hw-dock-panel-in {\\n from {\\n opacity: 0;\\n transform: translateY(14px) scale(0.98);\\n }\\n to {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n@keyframes hw-dock-panel-out {\\n from {\\n opacity: 1;\\n transform: none;\\n }\\n to {\\n opacity: 0;\\n transform: translateY(8px) scale(0.99);\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window .hw-header--sub {\\n animation: hw-dock-settle 0.32s cubic-bezier(0.16, 1, 0.3, 1) 0.06s both;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window .hw-messages {\\n animation: hw-dock-settle 0.34s cubic-bezier(0.16, 1, 0.3, 1) 0.11s both;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window--closing .hw-header--sub,\\n.hw-widget[data-hw-placement=docked] .hw-window--closing .hw-messages {\\n animation: none;\\n}\\n@keyframes hw-dock-settle {\\n from {\\n opacity: 0;\\n transform: translateY(7px);\\n }\\n to {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-widget[data-hw-placement=docked] .hw-window,\\n .hw-widget[data-hw-placement=docked] .hw-window--closing,\\n .hw-widget[data-hw-placement=docked] .hw-window .hw-header--sub,\\n .hw-widget[data-hw-placement=docked] .hw-window .hw-messages {\\n animation: none;\\n }\\n}\\n.hw-dock-bar {\\n flex-wrap: wrap;\\n padding-left: 18px;\\n padding-right: 8px;\\n}\\n.hw-dock-error {\\n width: var(--hw-dock-width);\\n max-width: calc(100vw - 32px);\\n margin-bottom: 8px;\\n padding: 8px 14px;\\n border-radius: 14px;\\n background: rgba(190, 24, 40, 0.92);\\n color: #ffffff;\\n font-size: 12.5px;\\n line-height: 1.35;\\n box-shadow: 0 10px 26px -12px rgba(12, 11, 10, 0.5);\\n animation: hw-dock-settle 0.22s cubic-bezier(0.16, 1, 0.3, 1) both;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-dock-error {\\n animation: none;\\n }\\n}\\n.hw-dock-previews {\\n flex: 0 0 100%;\\n order: -1;\\n display: flex;\\n flex-wrap: wrap;\\n gap: 8px;\\n padding: 2px 0 8px;\\n}\\n.hw-dock-actions {\\n flex: none;\\n display: flex;\\n align-items: center;\\n gap: 2px;\\n margin-bottom: 1px;\\n}\\n.hw-dock-tool {\\n display: grid;\\n place-items: center;\\n width: 30px;\\n height: 30px;\\n border: 0;\\n border-radius: 50%;\\n background: transparent;\\n color: color-mix(in srgb, var(--hw-dock-on-surface) 52%, transparent);\\n cursor: pointer;\\n transition: background 0.15s, color 0.15s;\\n}\\n.hw-dock-tool:hover:not(:disabled) {\\n background: color-mix(in srgb, var(--hw-dock-on-surface) 8%, transparent);\\n color: var(--hw-dock-on-surface);\\n}\\n.hw-dock-tool:disabled {\\n opacity: 0.4;\\n cursor: default;\\n}\\n.hw-dock-tool[data-active=true] {\\n color: #e11d48;\\n background: rgba(225, 29, 72, 0.12);\\n animation: hw-dock-listening 1.4s ease-in-out infinite;\\n}\\n@keyframes hw-dock-listening {\\n 0%, 100% {\\n box-shadow: 0 0 0 0 rgba(225, 29, 72, 0.35);\\n }\\n 50% {\\n box-shadow: 0 0 0 4px rgba(225, 29, 72, 0);\\n }\\n}\\n.hw-dock-send:disabled {\\n opacity: 1;\\n background: color-mix(in srgb, var(--hw-dock-on-surface) 9%, transparent);\\n color: color-mix(in srgb, var(--hw-dock-on-surface) 38%, transparent);\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-dock-tool[data-active=true] {\\n animation: none;\\n }\\n .hw-dock-bar {\\n transition: none;\\n }\\n}\\n.hw-dock-input:focus,\\n.hw-dock-input:focus-visible {\\n outline: none;\\n box-shadow: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-powered {\\n display: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-disconnect {\\n border-radius: 20px 20px 0 0;\\n}\\n.hw-msg-meta {\\n display: flex;\\n align-items: center;\\n gap: 5px;\\n}\\n.hw-msg-author {\\n font-weight: 550;\\n}\\n.hw-msg-meta-sep {\\n opacity: 0.55;\\n}\\n.hw-header-actions {\\n position: relative;\\n display: flex;\\n align-items: center;\\n gap: 2px;\\n}\\n.hw-header-menu-btn {\\n display: grid;\\n place-items: center;\\n width: 30px;\\n height: 30px;\\n border: 0;\\n border-radius: 8px;\\n cursor: pointer;\\n background: transparent;\\n color: var(--hw-text-2, var(--hw-text-muted));\\n transition: background 0.15s, color 0.15s;\\n}\\n.hw-header-menu-btn:hover {\\n background: var(--hw-bg-hover);\\n color: var(--hw-text);\\n}\\n.hw-header-menu {\\n position: absolute;\\n top: 36px;\\n right: 0;\\n z-index: 6;\\n min-width: 236px;\\n max-width: 288px;\\n padding: 5px;\\n border-radius: 14px;\\n background: var(--hw-bg);\\n color: var(--hw-text);\\n box-shadow: 0 0 0 1px var(--hw-border), 0 12px 32px -10px rgba(0, 0, 0, 0.32);\\n animation: hw-menu-in 0.16s cubic-bezier(0.2, 0.8, 0.2, 1) both;\\n}\\n@keyframes hw-menu-in {\\n from {\\n opacity: 0;\\n transform: translateY(-4px) scale(0.98);\\n }\\n to {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n.hw-header-menu button {\\n display: flex;\\n align-items: center;\\n gap: 10px;\\n width: 100%;\\n padding: 9px 10px;\\n border: 0;\\n border-radius: 9px;\\n cursor: pointer;\\n background: transparent;\\n color: var(--hw-text);\\n font: inherit;\\n font-size: 13px;\\n text-align: left;\\n transition: background 0.14s;\\n}\\n.hw-header-menu button:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-header-menu button svg {\\n flex: none;\\n color: var(--hw-text-3, var(--hw-text-muted));\\n}\\n.hw-header-menu button:hover svg {\\n color: var(--hw-brand, var(--hw-primary));\\n}\\n.hw-header-menu-convs {\\n display: flex;\\n flex-direction: column;\\n max-height: 168px;\\n overflow-y: auto;\\n padding-bottom: 5px;\\n margin-bottom: 5px;\\n border-bottom: 1px solid var(--hw-border);\\n}\\n.hw-header-menu button.hw-header-menu-conv {\\n flex-direction: column;\\n align-items: stretch;\\n gap: 2px;\\n padding: 8px 10px;\\n}\\n.hw-header-menu button.hw-header-menu-conv[data-active=true] {\\n background: var(--hw-bg-hover);\\n}\\n.hw-header-menu-conv-top {\\n display: flex;\\n align-items: baseline;\\n justify-content: space-between;\\n gap: 8px;\\n}\\n.hw-header-menu-conv-name {\\n overflow: hidden;\\n font-size: 12.5px;\\n font-weight: 600;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.hw-header-menu-conv-time {\\n flex: none;\\n font-size: 11px;\\n color: var(--hw-text-3, var(--hw-text-muted));\\n}\\n.hw-header-menu-conv-preview {\\n overflow: hidden;\\n font-size: 12px;\\n color: var(--hw-text-2);\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.hw-offers {\\n display: flex;\\n flex-wrap: wrap;\\n gap: 6px;\\n margin-top: 10px;\\n}\\n.hw-offer {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n padding: 8px 14px;\\n border: 0;\\n border-radius: 999px;\\n cursor: pointer;\\n background: var(--hw-bg-hover);\\n color: var(--hw-text);\\n font: inherit;\\n font-size: 12.5px;\\n font-weight: 550;\\n transition: background 0.15s, color 0.15s;\\n}\\n.hw-offer:hover {\\n background: var(--hw-brand, var(--hw-primary));\\n color: var(--hw-on-brand, #fff);\\n}\\n.hw-offer svg {\\n flex: none;\\n}\\n.hw-sources {\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n margin-top: 8px;\\n}\\n.hw-source {\\n display: flex;\\n align-items: center;\\n gap: 9px;\\n padding: 7px 10px;\\n border-radius: 9px;\\n background: transparent;\\n color: var(--hw-text);\\n text-decoration: none;\\n transition: background 0.15s;\\n}\\na.hw-source {\\n cursor: pointer;\\n}\\na.hw-source:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-source-n {\\n display: grid;\\n place-items: center;\\n flex: none;\\n width: 16px;\\n height: 16px;\\n border-radius: 4px;\\n background: var(--hw-brand, var(--hw-primary));\\n color: var(--hw-on-brand, #fff);\\n font-size: 10px;\\n font-weight: 700;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-source-title {\\n flex: 1;\\n min-width: 0;\\n font-size: 12px;\\n font-weight: 550;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\")","\"use client\";\n\n/**\n * `<HelpwayWidget />` — one-line drop-in React component that renders\n * the full Helpway widget natively in React.\n *\n * Since v0.2, this is a native React render (not a script tag injection).\n * The widget-core + widget-react code is bundled with your app, so widget\n * updates ship via `npm update @helpway/react` — no separate widget.js\n * deploy required. Bundle impact: ~120KB gzipped (shared with any other\n * helpway/react imports in your app, so subsequent uses are free).\n *\n * Power-user alternative: import `{ SupportProvider, DefaultWidget, useWidget, … }`\n * directly for programmatic control (render your own chat UI, expose\n * identify() via hook instead of global, etc.).\n *\n * @see https://helpway.ai/docs/quick-start for setup\n * @see https://helpway.ai/docs/react-sdk for the three integration layers\n * (drop-in, provider + hooks, fully headless)\n * @see https://helpway.ai/docs/customization for theming via `theme` prop\n * and the dashboard config\n * @see https://helpway.ai/docs/integration-notes for CSP, SSR, multi-tenant\n */\n\nimport type { DockSuggestion, WidgetPlacement, WidgetTheme } from \"@helpway/widget-core\";\nimport { SupportProvider } from \"./provider\";\nimport { DefaultWidget } from \"./themed/default-widget\";\n// Auto-import CSS so consumers don't need a separate `import \"@helpway/react/styles.css\"` step.\n// Side-effect import — evaluated once per bundle, tree-shaker preserves it via `sideEffects: [\"*.css\"]`.\nimport \"./themed/styles.css\";\n\nexport interface HelpwayWidgetProps {\n\t/**\n\t * Public API key from the Helpway dashboard. Required.\n\t * Format: `pk_live_…` or `pk_test_…`.\n\t */\n\tapiKey: string;\n\t/**\n\t * Override the default API URL. Almost no one needs this —\n\t * exposed for staging / self-hosted setups.\n\t * @default \"https://api.helpway.ai\"\n\t */\n\tapiUrl?: string;\n\t/**\n\t * Widget locale (e.g. \"tr\", \"en\", \"de\"). Falls back to server-side\n\t * detection (Accept-Language + CF-IPCountry) then widget-core default.\n\t */\n\tlocale?: string;\n\t/**\n\t * Deep link: auto-open this conversation after bootstrap.\n\t * Usually sourced from `?hw_conv=` URL param for email CTAs.\n\t */\n\tinitialConversationId?: string;\n\t/**\n\t * HMAC-signed token for cross-device visitor identity restoration.\n\t * Sourced from `#hw_token=` URL fragment in email deep-links.\n\t */\n\tdeepLinkToken?: string;\n\t/**\n\t * Called once after the widget has bootstrapped and exposes\n\t * the full programmatic API object (also available as `window.Helpway`).\n\t */\n\tonReady?: (api: HelpwayPublicAPI) => void;\n\t/**\n\t * Hide the default floating launcher button. Use with\n\t * `customLauncherSelector` or `window.Helpway.open()` to trigger\n\t * the widget from your own UI.\n\t */\n\thideLauncher?: boolean;\n\t/**\n\t * Where the widget lives on the page. The conversation UI is identical\n\t * across placements — only the shell moves.\n\t *\n\t * - `bubble` floating launcher bottom-right (default)\n\t * - `docked` composer bar pinned to the foot of the page; the bar is\n\t * the composer, so the panel above it renders without one\n\t * @default \"bubble\"\n\t */\n\tplacement?: WidgetPlacement;\n\t/**\n\t * Force the widget's appearance instead of following the visitor's OS.\n\t * Set this to match the page you are embedding in — a light page in a\n\t * dark-OS browser otherwise gets a dark widget.\n\t * @default \"system\"\n\t */\n\tcolorScheme?: \"light\" | \"dark\" | \"system\";\n\t/**\n\t * Ways in offered above the docked bar before the visitor types.\n\t * Only used when `placement=\"docked\"`.\n\t */\n\tdockSuggestions?: readonly DockSuggestion[];\n\t/**\n\t * CSS selector for a custom trigger element (e.g. `\"#support-btn\"`).\n\t * Clicking the matched element calls `Helpway.open()`. Combine with\n\t * `hideLauncher` to fully replace the default bubble.\n\t */\n\tcustomLauncherSelector?: string;\n\t/** Fires when the widget panel opens */\n\tonOpen?: () => void;\n\t/** Fires when the widget panel closes */\n\tonClose?: () => void;\n\t/** Fires when the unread count changes */\n\tonUnreadChange?: (count: number) => void;\n\t/**\n\t * Developer-side theme override. Most consumers should configure\n\t * appearance from the dashboard so changes apply without a redeploy\n\t * — see https://helpway.ai/docs/customization. Use this prop only\n\t * for runtime-resolved theming (multi-tenant brand colors, dark/\n\t * light sync with the host app, etc). Values map to CSS custom\n\t * properties on the widget host. See the `WidgetTheme` type for\n\t * the full set of supported keys.\n\t */\n\ttheme?: WidgetTheme;\n\t/**\n\t * @deprecated Legacy prop from the v0.1 script-loader era. If set,\n\t * the `/widget.js` suffix is stripped to derive `apiUrl`. New code\n\t * should use `apiUrl` instead.\n\t */\n\tsrc?: string;\n}\n\n// Re-export for consumers who use the onReady callback type.\n// `onReady` receives the programmatic methods object; the global\n// `window.Helpway` is the callable wrapper around it (HelpwayAPI).\nimport type { HelpwayMethods } from \"@helpway/widget-core\";\nexport type HelpwayPublicAPI = HelpwayMethods;\n\n/**\n * Render this once at the root of your app (e.g. in `_app.tsx`,\n * `layout.tsx`, or `main.tsx`). Unmounting cleanly tears down the\n * widget and its WebSocket connection — useful for route-scoped mounts.\n */\nexport function HelpwayWidget({\n\tapiKey,\n\tapiUrl,\n\tlocale,\n\tinitialConversationId,\n\tdeepLinkToken,\n\tonReady,\n\thideLauncher,\n\tplacement,\n\tcolorScheme,\n\tdockSuggestions,\n\tcustomLauncherSelector,\n\tonOpen,\n\tonClose,\n\tonUnreadChange,\n\ttheme,\n\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\tsrc,\n}: HelpwayWidgetProps) {\n\tconst resolvedApiUrl = apiUrl ?? (src ? src.replace(/\\/widget\\.js$/, \"\") : undefined);\n\n\treturn (\n\t\t<SupportProvider\n\t\t\tapiKey={apiKey}\n\t\t\tapiUrl={resolvedApiUrl}\n\t\t\tlocale={locale}\n\t\t\tinitialConversationId={initialConversationId}\n\t\t\tdeepLinkToken={deepLinkToken}\n\t\t\tonReady={onReady}\n\t\t\tcustomLauncherSelector={customLauncherSelector}\n\t\t\tonOpen={onOpen}\n\t\t\tonClose={onClose}\n\t\t\tonUnreadChange={onUnreadChange}\n\t\t\ttheme={theme}\n\t\t>\n\t\t\t<DefaultWidget\n\t\t\t\thideLauncher={hideLauncher}\n\t\t\t\tplacement={placement}\n\t\t\t\tcolorScheme={colorScheme}\n\t\t\t\tdockSuggestions={dockSuggestions}\n\t\t\t/>\n\t\t</SupportProvider>\n\t);\n}\n","import { useEffect } from \"react\";\nimport type { RealtimeEvent } from \"@helpway/types\";\nimport { useWidgetContext } from \"../provider\";\n\n/**\n * Subscribe to raw WebSocket events.\n * For advanced usage — most apps should use useTimeline/usePresence instead.\n *\n * Usage:\n * ```tsx\n * useRealtime((event) => {\n * if (event.type === 'timelineItemCreated') { ... }\n * })\n * ```\n */\nexport function useRealtime(handler: (event: RealtimeEvent) => void) {\n\tconst { ws } = useWidgetContext();\n\n\tuseEffect(() => {\n\t\treturn ws.onEvent(handler);\n\t}, [ws, handler]);\n}\n"],"mappings":";;;AAAA,SAAS,kBAAkB,qBAAqB;;;ACWhD,IAAM,SAAS;AACf,IAAM,aAAa;AAEnB,SAAS,OAAO,WAA2B;AAG1C,QAAM,SAAS,UAAU,MAAM,GAAG;AAClC,SAAO,GAAG,MAAM,IAAI,MAAM;AAC3B;AAEA,SAAS,aAAqB;AAC7B,QAAM,KAAK,KAAK,IAAI,EAAE,SAAS,EAAE;AACjC,QAAM,OAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;AACnD,SAAO,GAAG,EAAE,GAAG,IAAI;AACpB;AAMO,SAAS,qBAAqB,WAA2B;AAC/D,MAAI;AACH,UAAMA,cAAa,OAAO,SAAS;AACnC,UAAM,WAAW,aAAa,QAAQA,WAAU;AAChD,QAAI,SAAU,QAAO;AAKrB,UAAM,SAAS,aAAa,QAAQ,UAAU;AAC9C,QAAI,QAAQ;AACX,mBAAa,QAAQA,aAAY,MAAM;AACvC,mBAAa,WAAW,UAAU;AAClC,aAAO;AAAA,IACR;AAEA,UAAM,KAAK,WAAW;AACtB,iBAAa,QAAQA,aAAY,EAAE;AACnC,WAAO;AAAA,EACR,QAAQ;AAEP,WAAO,WAAW;AAAA,EACnB;AACD;AAGO,SAAS,cAAc,WAAmB,iBAA+B;AAC/E,MAAI;AACH,iBAAa,QAAQ,OAAO,SAAS,GAAG,eAAe;AAAA,EACxD,QAAQ;AAAA,EAER;AACD;AAGO,SAAS,eAAe,WAAyB;AACvD,MAAI;AACH,iBAAa,WAAW,OAAO,SAAS,CAAC;AAAA,EAC1C,QAAQ;AAAA,EAER;AACD;;;ADrDO,SAAS,mBAAmB,QAI3B;AACP,SAAO,iBAAiB;AAAA,IACvB,OAAO;AAAA,MACN,cAAc;AAAA,QACb,KAAK,GAAG,OAAO,MAAM;AAAA,QACrB,UAAU;AACT,iBAAO;AAAA,YACN,gBAAgB,OAAO;AAAA,YACvB,gBAAgB,qBAAqB,OAAO,MAAM;AAAA,UACnD;AAAA,QACD;AAAA,QACA,MAAM,KAAK,SAAS;AAEnB,iBAAO,WAAW,MAAM,KAAK,EAAE,GAAG,SAAS,aAAa,UAAU,CAAC;AAAA,QACpE;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD,CAAC;AACF;;;AEpCO,IAAM,cAAc;AAAA,EAC1B,uBAAuB;AAAA,EACvB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,eAAe;AAAA,EACf,wBAAwB;AAAA,EACxB,eAAe;AAAA,EACf,uBAAuB;AACxB;AA8HO,SAAS,gBAAgB,MAAsC;AACrE,SACC,OAAO,SAAS,YAChB,SAAS,QACT,UAAU,QACV,OAAQ,KAAuB,SAAS;AAE1C;;;AC3HO,IAAM,gBAA8B;AAAA,EAC1C;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG;AAAA,MACrC;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,YAAY,QAAQ,mBAAmB;AAAA,MAC5C,EAAE,GAAG,YAAY,QAAQ,gBAAgB;AAAA,IAC1C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,kCAAkC;AAAA,MAClD,EAAE,GAAG,QAAQ,GAAG,iEAAiE;AAAA,IAClF;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,MACA;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,MACA;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,YAAY,QAAQ,iBAAiB;AAAA,MAC1C,EAAE,GAAG,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AAAA,IAC7C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,OAAO,IAAI,QAAQ,IAAI,IAAI,EAAE;AAAA,MACtD,EAAE,GAAG,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,GAAG;AAAA,IAChD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,OAAO,IAAI,QAAQ,GAAG,IAAI,EAAE;AAAA,MACrD,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG,IAAI,OAAO,IAAI,QAAQ,GAAG,IAAI,EAAE;AAAA,MACtD,EAAE,GAAG,QAAQ,IAAI,GAAG,IAAI,GAAG,IAAI,MAAM,IAAI,EAAE;AAAA,MAC3C,EAAE,GAAG,QAAQ,IAAI,GAAG,IAAI,IAAI,IAAI,MAAM,IAAI,GAAG;AAAA,IAC9C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,KAAK,IAAI,MAAM,GAAG,IAAI;AAAA,MACzC,EAAE,GAAG,QAAQ,GAAG,yBAAyB;AAAA,IAC1C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,6DAA6D;AAAA,MAC7E,EAAE,GAAG,YAAY,QAAQ,iBAAiB;AAAA,IAC3C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE;AAAA,MACpC;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ,CAAC,EAAE,GAAG,WAAW,QAAQ,yCAAyC,CAAC;AAAA,EAC5E;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,WAAW,QAAQ,2BAA2B;AAAA,MACnD,EAAE,GAAG,YAAY,QAAQ,mBAAmB;AAAA,MAC5C,EAAE,GAAG,YAAY,QAAQ,mBAAmB;AAAA,IAC7C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,YAAY;AAAA,MAC5B,EAAE,GAAG,QAAQ,GAAG,gBAAgB;AAAA,MAChC,EAAE,GAAG,QAAQ,GAAG,4BAA4B;AAAA,IAC7C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ,CAAC,EAAE,GAAG,QAAQ,GAAG,gEAAgE,CAAC;AAAA,EAC3F;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,YAAY,QAAQ,oCAAoC;AAAA,MAC7D;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,4CAA4C;AAAA,MAC5D,EAAE,GAAG,UAAU,IAAI,GAAG,IAAI,GAAG,GAAG,EAAE;AAAA,MAClC,EAAE,GAAG,QAAQ,GAAG,sDAAsD;AAAA,IACvE;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,OAAO,IAAI,QAAQ,IAAI,IAAI,EAAE;AAAA,MACtD,EAAE,GAAG,QAAQ,GAAG,iBAAiB;AAAA,IAClC;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,OAAO,IAAI,QAAQ,IAAI,IAAI,EAAE;AAAA,MACtD,EAAE,GAAG,QAAQ,IAAI,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AAAA,IAC5C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,4CAA4C;AAAA,MAC5D,EAAE,GAAG,QAAQ,GAAG,iCAAiC;AAAA,IAClD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE;AAAA,MACpC,EAAE,GAAG,QAAQ,GAAG,iBAAiB;AAAA,IAClC;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,8CAA8C;AAAA,MAC9D,EAAE,GAAG,QAAQ,GAAG,gBAAgB;AAAA,IACjC;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG;AAAA,MACrC,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE;AAAA,MACpC,EAAE,GAAG,QAAQ,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK;AAAA,MACpD,EAAE,GAAG,QAAQ,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM;AAAA,MACxD,EAAE,GAAG,QAAQ,IAAI,OAAO,IAAI,MAAM,IAAI,OAAO,IAAI,KAAK;AAAA,MACtD,EAAE,GAAG,QAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,IAAI,MAAM;AAAA,IACvD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AAAA,MAC5C,EAAE,GAAG,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE;AAAA,MAC3C,EAAE,GAAG,QAAQ,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,IAAI,GAAG;AAAA,IAC3C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,GAAG,GAAG,EAAE;AAAA,MACnC,EAAE,GAAG,UAAU,IAAI,GAAG,IAAI,IAAI,GAAG,EAAE;AAAA,MACnC,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE;AAAA,MACpC,EAAE,GAAG,QAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM;AAAA,MACvD,EAAE,GAAG,QAAQ,IAAI,OAAO,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM;AAAA,IACvD;AAAA,EACD;AACD;AAGO,IAAM,qBAA+B,cAAc,IAAI,CAAC,MAAM,EAAE,IAAI;AAE3E,IAAM,mBAA+C,OAAO;AAAA,EAC3D,cAAc,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AACrC;;;ACrQO,IAAM,mBAAN,MAAuB;AAAA,EACrB,KAAuB;AAAA,EACvB,WAAW,oBAAI,IAAkB;AAAA,EACjC;AAAA,EACA,oBAAoB;AAAA,EACpB,uBAAuB;AAAA,EACvB,iBAAuD;AAAA,EACvD,YAAmD;AAAA,EACnD,cAAc;AAAA,EACd,oBAAyC;AAAA,EAEjD,YAAY,QAAgC;AAC3C,SAAK,SAAS;AACd,SAAK,wBAAwB;AAAA,EAC9B;AAAA,EAEQ,0BAAgC;AACvC,QAAI,OAAO,aAAa,YAAa;AACrC,SAAK,oBAAoB,MAAM;AAC9B,UAAI,SAAS,oBAAoB,UAAU;AAE1C,aAAK,SAAS;AAAA,MACf,WAAW,KAAK,IAAI,eAAe,UAAU,MAAM;AAElD,aAAK,UAAU;AACf,aAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AAAA,MAC3B;AAAA,IACD;AACA,aAAS,iBAAiB,oBAAoB,KAAK,iBAAiB;AAAA,EACrE;AAAA;AAAA,EAGA,UAAU,QAA+C;AACxD,WAAO,OAAO,KAAK,QAAQ,MAAM;AAAA,EAClC;AAAA;AAAA,EAGA,UAAgB;AACf,QAAI,KAAK,IAAI,eAAe,UAAU,KAAM;AAE5C,SAAK,cAAc;AAEnB,UAAM,WAAW,KAAK,OAAO,OAAO,WAAW,OAAO,IAAI,QAAQ;AAClE,UAAM,OAAO,KAAK,OAAO,OAAO,QAAQ,WAAW,QAAQ;AAC3D,UAAM,SAAS,IAAI,gBAAgB;AAAA,MAClC,MAAM;AAAA,MACN,IAAI,KAAK,OAAO;AAAA,MAChB,WAAW,KAAK,OAAO;AAAA,MACvB,KAAK,KAAK,OAAO;AAAA,IAClB,CAAC;AAED,UAAM,KAAK,IAAI,UAAU,GAAG,IAAI,OAAO,MAAM,EAAE;AAE/C,OAAG,SAAS,MAAM;AACjB,WAAK,oBAAoB;AAGzB,UAAI,OAAO,aAAa,eAAe,SAAS,oBAAoB,WAAW;AAC9E,aAAK,UAAU;AAAA,MAChB;AAAA,IACD;AAEA,OAAG,YAAY,CAAC,UAAU;AACzB,UAAI;AACH,cAAM,OAAO,KAAK,MAAM,MAAM,IAAc;AAC5C,YAAI,KAAK,SAAS,OAAQ;AAC1B,YAAI,gBAAgB,IAAI,GAAG;AAC1B,qBAAW,WAAW,KAAK,UAAU;AACpC,oBAAQ,IAAI;AAAA,UACb;AAAA,QACD;AAAA,MACD,QAAQ;AAAA,MAER;AAAA,IACD;AAEA,OAAG,UAAU,MAAM;AAClB,WAAK,SAAS;AACd,WAAK,KAAK;AACV,UAAI,CAAC,KAAK,aAAa;AACtB,aAAK,kBAAkB;AAAA,MACxB;AAAA,IACD;AAEA,OAAG,UAAU,MAAM;AAAA,IAEnB;AAEA,SAAK,KAAK;AAAA,EACX;AAAA;AAAA,EAGA,aAAmB;AAClB,SAAK,cAAc;AACnB,SAAK,SAAS;AACd,QAAI,KAAK,gBAAgB;AACxB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACvB;AACA,QAAI,KAAK,qBAAqB,OAAO,aAAa,aAAa;AAC9D,eAAS,oBAAoB,oBAAoB,KAAK,iBAAiB;AACvE,WAAK,oBAAoB;AAAA,IAC1B;AACA,QAAI,KAAK,IAAI;AACZ,WAAK,GAAG,MAAM,KAAM,mBAAmB;AACvC,WAAK,KAAK;AAAA,IACX;AAAA,EACD;AAAA;AAAA,EAGA,KAAK,MAAqC;AACzC,QAAI,KAAK,IAAI,eAAe,UAAU,MAAM;AAC3C,WAAK,GAAG,KAAK,KAAK,UAAU,IAAI,CAAC;AAAA,IAClC;AAAA,EACD;AAAA;AAAA,EAGA,WAAW,gBAAwB,UAAyB;AAC3D,SAAK,KAAK,EAAE,MAAM,UAAU,gBAAgB,SAAS,CAAC;AAAA,EACvD;AAAA;AAAA,EAGA,QAAQ,SAAmC;AAC1C,SAAK,SAAS,IAAI,OAAO;AACzB,WAAO,MAAM;AACZ,WAAK,SAAS,OAAO,OAAO;AAAA,IAC7B;AAAA,EACD;AAAA;AAAA,EAGA,IAAI,cAAuB;AAC1B,WAAO,KAAK,IAAI,eAAe,UAAU;AAAA,EAC1C;AAAA;AAAA,EAIQ,oBAA0B;AACjC,QAAI,KAAK,qBAAqB,KAAK,qBAAsB;AAEzD,UAAM,QAAQ,KAAK,IAAI,MAAO,KAAK,KAAK,mBAAmB,GAAK;AAChE,SAAK;AAEL,SAAK,iBAAiB,WAAW,MAAM;AACtC,WAAK,QAAQ;AAAA,IACd,GAAG,KAAK;AAAA,EACT;AAAA,EAEQ,YAAkB;AACzB,SAAK,SAAS;AACd,SAAK,YAAY,YAAY,MAAM;AAClC,WAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AAAA,IAC3B,GAAG,IAAK;AAAA,EACT;AAAA,EAEQ,WAAiB;AACxB,QAAI,KAAK,WAAW;AACnB,oBAAc,KAAK,SAAS;AAC5B,WAAK,YAAY;AAAA,IAClB;AAAA,EACD;AACD;;;ACvLA,SAAS,mBAAmB;AAoDrB,IAAM,oBAAoB,IAAI,KAAK;AAoL1C,IAAM,sBAAsB;AAUrB,SAAS,gBAAgB,gBAAgC;AAC/D,SAAO,aAAa,cAAc;AACnC;AAEA,SAAS,uBAAuD;AAC/D,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI;AACH,UAAM,MAAM,OAAO,aAAa,QAAQ,mBAAmB;AAC3D,WAAO,MAAO,KAAK,MAAM,GAAG,IAAuC;AAAA,EACpE,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,eAAe,SAA+C;AACtE,MAAI,OAAO,WAAW,YAAa;AACnC,MAAI;AACH,QAAI,SAAS;AACZ,aAAO,aAAa,QAAQ,qBAAqB,KAAK,UAAU,OAAO,CAAC;AAAA,IACzE,OAAO;AACN,aAAO,aAAa,WAAW,mBAAmB;AAAA,IACnD;AAAA,EACD,QAAQ;AAAA,EAER;AACD;AAQA,SAAS,eAAe,MAAoE;AAC3F,MAAI,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO;AAClC,MAAI;AACH,UAAM,SAAS,KAAK,MAAM,IAAI;AAK9B,QAAI,OAAO,WAAW,SAAU,QAAO;AACvC,WAAO,EAAE,MAAM,OAAO,QAAQ,MAAM,OAAO,OAAO,SAAS,KAAK;AAAA,EACjE,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAYA,SAAS,eACR,OACuD;AACvD,WAAS,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,UAAM,OAAO,MAAM,CAAC;AACpB,QAAI,MAAM,SAAS,WAAW,CAAC,KAAK,KAAM;AAC1C,UAAM,SAAS,eAAe,KAAK,IAAI;AACvC,QAAI,OAAQ,QAAO;AAAA,EACpB;AACA,SAAO;AACR;AAEO,SAAS,oBAAoB;AACnC,QAAM,QAAQ,YAAyB,CAAC,KAAK,SAAS;AAAA;AAAA,IAErD,SAAS;AAAA,IACT,cAAc;AAAA,IACd,SAAS;AAAA,IACT,SAAS;AAAA,IACT,aAAa;AAAA,IACb,eAAe,CAAC;AAAA,IAChB,sBAAsB;AAAA,IACtB,UAAU,oBAAI,IAAI;AAAA,IAClB,aAAa,oBAAI,IAAI;AAAA,IACrB,cAAc,oBAAI,IAAI;AAAA,IACtB,eAAe,oBAAI,IAAI;AAAA,IACvB,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,iBAAiB,qBAAqB;AAAA,IACtC,sBAAsB,CAAC;AAAA,IACvB,yBAAyB;AAAA,IACzB,wBAAwB;AAAA,IACxB,sBAAsB;AAAA,IACtB,cAAc,oBAAI,IAAI;AAAA;AAAA,IAItB,SAAS,SAAS,SAAS,aAAa;AACvC,UAAI;AAAA,QACH,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,QACA;AAAA,QACA,aAAa,eAAe;AAAA,MAC7B,CAAC;AAAA,IACF;AAAA,IAEA,cAAc,YAAY;AACzB,UAAI,EAAE,cAAc,WAAW,CAAC;AAAA,IACjC;AAAA;AAAA,IAIA,iBAAiB,eAAe;AAC/B,UAAI,EAAE,cAAc,CAAC;AAAA,IACtB;AAAA,IAEA,gBAAgB,cAAc;AAC7B,UAAI,CAAC,WAAW;AAAA,QACf,eAAe,CAAC,cAAc,GAAG,MAAM,aAAa;AAAA,MACrD,EAAE;AAAA,IACH;AAAA,IAEA,sBAAsB,IAAI;AACzB,UAAI,EAAE,sBAAsB,IAAI,MAAM,KAAK,iBAAiB,OAAO,CAAC;AAAA,IACrE;AAAA;AAAA,IAIA,YAAY,gBAAgB,OAAO;AAClC,YAAM,SAAS,eAAe,KAAK;AACnC,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,QAAQ;AACnC,aAAK,IAAI,gBAAgB,KAAK;AAC9B,eAAO;AAAA,UACN,UAAU;AAAA;AAAA;AAAA,UAGV,GAAI,SACD;AAAA,YACA,eAAe,MAAM,cAAc;AAAA,cAAI,CAAC,MACvC,EAAE,OAAO,iBACN;AAAA,gBACA,GAAG;AAAA,gBACH,cAAc,OAAO,QAAQ,EAAE;AAAA,gBAC/B,eAAe,OAAO,SAAS,EAAE;AAAA,cAClC,IACC;AAAA,YACJ;AAAA,UACD,IACC,CAAC;AAAA,QACL;AAAA,MACD,CAAC;AAAA,IACF;AAAA,IAEA,WAAW,gBAAgB,MAAM;AAChC,YAAM,SAAS,KAAK,SAAS,WAAW,KAAK,OAAO,eAAe,KAAK,IAAI,IAAI;AAChF,UAAI,QAAQ;AACX,YAAI,CAAC,WAAW;AAAA,UACf,eAAe,MAAM,cAAc;AAAA,YAAI,CAAC,MACvC,EAAE,OAAO,iBACN;AAAA,cACA,GAAG;AAAA,cACH,cAAc,OAAO,QAAQ,EAAE;AAAA,cAC/B,eAAe,OAAO,SAAS,EAAE;AAAA,YAClC,IACC;AAAA,UACJ;AAAA,QACD,EAAE;AAAA,MACH;AACA,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,QAAQ;AACnC,cAAM,WAAW,KAAK,IAAI,cAAc,KAAK,CAAC;AAG9C,YAAI,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE,EAAG,QAAO;AAenD,cAAM,YAAY,gBAAgB,cAAc;AAChD,YAAI,CAAC,KAAK,aAAa,KAAK,aAAa,MAAM,cAAc,IAAI,cAAc,GAAG;AACjF,eAAK,IAAI,gBAAgB;AAAA,YACxB,GAAG;AAAA,YACH,EAAE,GAAG,MAAM,YAAY,UAAU;AAAA,UAClC,CAAC;AACD,iBAAO,EAAE,UAAU,KAAK;AAAA,QACzB;AACA,cAAM,YAAY,KAAK,YACpB,SAAS;AAAA,UACT,CAAC,MAAM,CAAC,CAAC,EAAE,aAAa,EAAE,SAAS,KAAK,QAAQ,EAAE,GAAG,WAAW,aAAa;AAAA,QAC9E,IACC;AACH,YAAI,aAAa,GAAG;AACnB,gBAAM,aAAa,SAAS,SAAS;AACrC,gBAAMC,UAAS,CAAC,GAAG,QAAQ;AAC3B,UAAAA,QAAO,SAAS,IAAI;AAAA,YACnB,GAAG;AAAA,YACH,YAAY,WAAW,cAAc,WAAW;AAAA,UACjD;AACA,eAAK,IAAI,gBAAgBA,OAAM;AAC/B,iBAAO,EAAE,UAAU,KAAK;AAAA,QACzB;AAKA,cAAM,iBAAiB,CAAC,CAAC,KAAK,aAAa,CAAC,KAAK;AACjD,cAAM,iBAAiB,SAAS,CAAC,GAAG,aAAa;AACjD,YAAI,kBAAkB,gBAAgB;AACrC,eAAK,IAAI,gBAAgB,CAAC,MAAM,GAAG,QAAQ,CAAC;AAC5C,iBAAO,EAAE,UAAU,KAAK;AAAA,QACzB;AAGA,cAAM,OAAO,SAAS,SAAS,SAAS,CAAC;AACzC,cAAM,eAAe,QAAQ,KAAK,YAAY,KAAK;AACnD,cAAM,SAAS,CAAC,GAAG,UAAU,IAAI;AACjC,YAAI,cAAc;AACjB,iBAAO,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AAAA,QAC7D;AACA,aAAK,IAAI,gBAAgB,MAAM;AAC/B,eAAO,EAAE,UAAU,KAAK;AAAA,MACzB,CAAC;AAAA,IACF;AAAA,IAEA,eAAe,gBAAgB,OAAO,MAAM;AAC3C,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,QAAQ;AACnC,cAAM,WAAW,KAAK,IAAI,cAAc,KAAK,CAAC;AAE9C,YAAI,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,EAAE,OAAO,KAAK,GAAG;AAC7D,eAAK;AAAA,YACJ;AAAA,YACA,SAAS,OAAO,CAAC,MAAM,EAAE,OAAO,KAAK;AAAA,UACtC;AACA,iBAAO,EAAE,UAAU,KAAK;AAAA,QACzB;AAGA,aAAK;AAAA,UACJ;AAAA,UACA,SAAS;AAAA,YAAI,CAAC,MACb,EAAE,OAAO,QACN;AAAA,cACA,GAAG;AAAA,cACH,YAAa,EAAyC,cAAc;AAAA,YACrE,IACC;AAAA,UACJ;AAAA,QACD;AACA,eAAO,EAAE,UAAU,KAAK;AAAA,MACzB,CAAC;AAAA,IACF;AAAA,IAEA,cAAc,gBAAgB,IAAI;AACjC,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,QAAQ;AACnC,cAAM,WAAW,KAAK,IAAI,cAAc;AACxC,YAAI,CAAC,SAAU,QAAO;AACtB,aAAK;AAAA,UACJ;AAAA,UACA,SAAS,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAAA,QACnC;AACA,eAAO,EAAE,UAAU,KAAK;AAAA,MACzB,CAAC;AAAA,IACF;AAAA,IAEA,oBAAoB,OAAO,OAAO;AACjC,UAAI,CAAC,UAAU;AAId,cAAM,eAAe,IAAI,IAAI,MAAM,QAAQ;AAC3C,cAAM,YAAY,aAAa,IAAI,KAAK,KAAK,CAAC;AAC9C,cAAM,gBAAgB,aAAa,IAAI,KAAK,KAAK,CAAC;AAClD,cAAM,gBAAgB,UAAU,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,gBAAgB,MAAM,EAAE;AAC5E,cAAM,aAAa,CAAC,MAAoB,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,aAAa,CAAC,EAAE;AAM5E,cAAM,OAAO,oBAAI,IAAY;AAC7B,cAAM,SAAyB,CAAC;AAChC,YAAI,mBAAmB;AACvB,mBAAW,KAAK,eAAe;AAC9B,cAAI,KAAK,IAAI,EAAE,EAAE,EAAG;AACpB,eAAK,IAAI,EAAE,EAAE;AACb,iBAAO,KAAK,CAAC;AACb,cAAI,WAAW,CAAC,KAAK,OAAO,WAAW,EAAG,oBAAmB;AAAA,QAC9D;AASA,cAAM,kBAAkB,cAAc,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG;AAOhE,cAAM,eAAe,CAAC,MAAoB,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,aAAa,CAAC,EAAE;AAC9E,cAAM,iBAAiB,oBAAI,IAAoB;AAC/C,eAAO,QAAQ,CAAC,GAAG,MAAM;AACxB,cAAI,aAAa,CAAC,KAAK,OAAO,EAAE,SAAS,YAAY,CAAC,eAAe,IAAI,EAAE,IAAI,GAAG;AACjF,2BAAe,IAAI,EAAE,MAAM,CAAC;AAAA,UAC7B;AAAA,QACD,CAAC;AACD,YAAI,iBAAiB;AACrB,mBAAW,KAAK,eAAe;AAC9B,cAAI,KAAK,IAAI,EAAE,EAAE,EAAG;AACpB,cAAI,aAAa,CAAC,KAAK,OAAO,EAAE,SAAS,YAAY,eAAe,IAAI,EAAE,IAAI,GAAG;AAChF,kBAAM,MAAM,eAAe,IAAI,EAAE,IAAI;AACrC,2BAAe,OAAO,EAAE,IAAI;AAC5B,kBAAM,aAAa,OAAO,GAAG;AAC7B,mBAAO,GAAG,IAAI;AAAA,cACb,GAAG;AAAA,cACH,YAAY,aACP,WAAkD,cAAc,WAAW,KAC7E,EAAE;AAAA,YACN;AACA,iBAAK,IAAI,EAAE,EAAE;AACb;AAAA,UACD;AACA,gBAAM,gBACL,WAAW,CAAC,KACZ,oBACA,CAAC,mBACA,CAAC,mBAAmB,EAAE,aAAa;AACrC,cAAI,eAAe;AAClB,kBAAM,OAAO,OAAO,CAAC;AACrB,mBAAO,CAAC,IAAI;AAAA,cACX,GAAG;AAAA,cACH,YAAY,OACP,KAA4C,cAAc,KAAK,KACjE,EAAE;AAAA,YACN;AACA,iBAAK,IAAI,EAAE,EAAE;AACb,6BAAiB;AACjB;AAAA,UACD;AACA,eAAK,IAAI,EAAE,EAAE;AACb,iBAAO,KAAK,CAAC;AAAA,QACd;AACA,qBAAa,OAAO,KAAK;AACzB,qBAAa,IAAI,OAAO,MAAM;AAI9B,cAAM,WAAW,MAAM,cAAc,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK;AAC/D,cAAM,gBAAgB,WACnB,MAAM,cAAc,OAAO,CAAC,MAAM,EAAE,OAAO,KAAK,IAChD,MAAM,cAAc,IAAI,CAAC,MAAO,EAAE,OAAO,QAAQ,EAAE,GAAG,GAAG,IAAI,MAAM,IAAI,CAAE;AAe5E,cAAM,UAAU,CAAK,MAAsC;AAC1D,cAAI,CAAC,EAAE,IAAI,KAAK,EAAG,QAAO;AAC1B,gBAAM,OAAO,IAAI,IAAI,CAAC;AACtB,gBAAM,UAAU,KAAK,IAAI,KAAK;AAC9B,eAAK,OAAO,KAAK;AAEjB,cAAI,CAAC,KAAK,IAAI,KAAK,EAAG,MAAK,IAAI,OAAO,OAAO;AAC7C,iBAAO;AAAA,QACR;AAEA,eAAO;AAAA,UACN,UAAU;AAAA,UACV;AAAA,UACA,aAAa,QAAQ,MAAM,WAAW;AAAA,UACtC,cAAc,QAAQ,MAAM,YAAY;AAAA,UACxC,eAAe,QAAQ,MAAM,aAAa;AAAA,UAC1C,sBACC,MAAM,yBAAyB,QAAQ,QAAQ,MAAM;AAAA,QACvD;AAAA,MACD,CAAC;AAAA,IACF;AAAA;AAAA,IAIA,UAAU,gBAAgB,UAAU;AACnC,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,WAAW;AACtC,aAAK,IAAI,gBAAgB,QAAQ;AACjC,eAAO,EAAE,aAAa,KAAK;AAAA,MAC5B,CAAC;AAAA,IACF;AAAA,IAEA,gBAAgB,gBAAgB,YAAY;AAC3C,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,YAAY;AACvC,aAAK,IAAI,gBAAgB,UAAU;AACnC,eAAO,EAAE,cAAc,KAAK;AAAA,MAC7B,CAAC;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkBA,kBAAkB,gBAAgB,OAAO,MAAM;AAQ9C,WAAK;AACL,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,aAAa;AACxC,cAAM,OAAO,KAAK,IAAI,cAAc,KAAK;AACzC,aAAK,IAAI,gBAAgB,OAAO,KAAK;AACrC,eAAO,EAAE,eAAe,KAAK;AAAA,MAC9B,CAAC;AAAA,IACF;AAAA,IAEA,YAAY,gBAAgB;AAC3B,UAAI,CAAC,UAAU;AACd,YAAI,CAAC,MAAM,cAAc,IAAI,cAAc,EAAG,QAAO,CAAC;AACtD,cAAM,OAAO,IAAI,IAAI,MAAM,aAAa;AACxC,aAAK,OAAO,cAAc;AAC1B,eAAO,EAAE,eAAe,KAAK;AAAA,MAC9B,CAAC;AAAA,IACF;AAAA;AAAA,IAIA,qBAAqB,SAAS;AAC7B,UAAI,CAAC,WAAW;AAAA,QACf,SAAS,MAAM,UAAU,EAAE,GAAG,MAAM,SAAS,QAAQ,IAAI,MAAM;AAAA,MAChE,EAAE;AAAA,IACH;AAAA;AAAA,IAIA,YAAY,gBAAgB;AAC3B,UAAI,CAAC,OAAO;AAAA,QACX,eAAe,EAAE,cAAc;AAAA,UAAI,CAAC,MACnC,EAAE,OAAO,iBAAiB,EAAE,GAAG,GAAG,aAAa,EAAE,IAAI;AAAA,QACtD;AAAA,MACD,EAAE;AAAA,IACH;AAAA;AAAA,IAIA,QAAQ,MAAM;AACb,UAAI,CAAC,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,iBAAiB,OAAO,OAAO,EAAE;AAAA,QACjC,sBAAsB,OAAO,CAAC,IAAI,EAAE;AAAA,MACrC,EAAE;AAAA,IACH;AAAA,IAEA,wBAAwB,OAAO;AAC9B,UAAI,EAAE,sBAAsB,MAAM,CAAC;AAAA,IACpC;AAAA,IAEA,aAAa,WAAW;AACvB,UAAI,EAAE,aAAa,UAAU,CAAC;AAAA,IAC/B;AAAA,IAEA,QAAQ,MAAM;AACb,UAAI,EAAE,KAAK,CAAC;AAAA,IACb;AAAA,IAEA,0BAA0B,MAAM;AAC/B,UAAI,EAAE,wBAAwB,KAAK,CAAC;AAAA,IACrC;AAAA,IAEA,iBAAiB;AAChB,UAAI,EAAE,iBAAiB,KAAK,CAAC;AAAA,IAC9B;AAAA;AAAA,IAIA,uBAAuB,SAAS;AAC/B,UAAI,CAAC,OAAO;AAAA,QACX,sBAAsB;AAAA,UACrB,GAAG,EAAE,qBAAqB,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ,KAAK;AAAA,UACjE;AAAA,QACD;AAAA,MACD,EAAE;AAAA,IACH;AAAA,IAEA,2BAA2B,MAAM;AAChC,UAAI,MAAM;AACT,YAAI,CAAC,OAAO;AAAA,UACX,sBAAsB,EAAE,qBAAqB,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,QAC3E,EAAE;AAAA,MACH,OAAO;AACN,YAAI,EAAE,sBAAsB,CAAC,EAAE,CAAC;AAAA,MACjC;AAAA,IACD;AAAA,IAEA,2BAA2B,OAAO;AACjC,UAAI,EAAE,yBAAyB,MAAM,CAAC;AAAA,IACvC;AAAA;AAAA,IAIA,gBAAgB,KAAK,MAAM;AAC1B,UAAI,EAAE,aAAa,IAAI,KAAK,EAAE,MAAM,IAAI,KAAK,IAAI,EAAE,CAAC;AAAA,IACrD;AAAA;AAAA,IAIA,oBAAoB,OAAO;AAC1B,YAAM,QAAQ,IAAI;AAElB,cAAQ,MAAM,MAAM;AAAA,QACnB,KAAK,YAAY,qBAAqB;AAErC,cAAI,MAAM,KAAK,eAAe,UAAU;AAWvC,kBAAM,kBACL,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,KAAK;AAChE,kBAAM,WAAW,MAAM,SAAS,IAAI,MAAM,cAAc;AACxD,kBAAM,SAAS,WAAW,CAAC,GAAG;AAC9B,kBAAM,iBAAiB,OAAO,WAAW,YAAY,OAAO,WAAW,eAAe;AACtF,gBAAI,mBAAmB,gBAAgB;AACtC,oBAAM,iBAAiB,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG;AAC3D,oBAAM,gBAAgB,CAAC,kBAAkB,MAAM,KAAK,aAAa;AACjE,kBAAI,eAAe;AAKlB,sBAAM,eAAe,MAAM,gBAAgB,QAAQ,MAAM,IAAI;AAC7D;AAAA,cACD;AAAA,YACD;AACA,kBAAM,WAAW,MAAM,gBAAgB,MAAM,IAAI;AAAA,UAClD;AAGA,cAAI,MAAM,KAAK,WAAW;AACzB,kBAAM,gBAAgB,MAAM,gBAAgB,KAAK;AACjD,kBAAM,UAAU,MAAM,gBAAgB,KAAK;AAI3C,kBAAM,YAAY,MAAM,cAAc;AAAA,UACvC;AAEA,cAAI,MAAM,KAAK,SAAS,aAAa,MAAM,KAAK,MAAM;AACrD,kBAAM,aAAa,CAAC,MAAM,KAAK;AAC/B,kBAAM,eAAe,IAAI;AACzB,kBAAM,gBACL,aAAa,UAAU,aAAa,yBAAyB,MAAM;AAEpE,gBAAI,CAAC,OAAO;AAAA,cACX,eAAe,EAAE,cAAc;AAAA,gBAAI,CAAC,MACnC,EAAE,OAAO,MAAM,iBACZ;AAAA,kBACA,GAAG;AAAA,kBACH,iBAAiB,MAAM,KAAK;AAAA,kBAC5B,eAAe,MAAM,KAAK;AAAA;AAAA,kBAE1B,GAAI,cAAc,CAAC,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,IAAI,CAAC;AAAA,gBAC1E,IACC;AAAA,cACJ;AAAA;AAAA,cAEA,GAAI,cAAc,CAAC,aAAa,SAC7B;AAAA,gBACA,iBAAiB;AAAA,kBAChB,MAAM,MAAM,KAAK,QAAQ;AAAA,kBACzB,gBAAgB,MAAM;AAAA,kBACtB,WAAW,KAAK,IAAI;AAAA,kBACpB,YACE,MAAM,KAAsC,YAAY;AAAA,kBAC1D,aACE,MAAM,KAAuC,aAAa;AAAA,gBAC7D;AAAA,cACD,IACC,CAAC;AAAA,YACL,EAAE;AAAA,UACH;AACA;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,qBAAqB;AACrC,cAAI,CAAC,OAAO;AAAA,YACX,eAAe,EAAE,cAAc;AAAA,cAAI,CAAC,MACnC,EAAE,OAAO,MAAM,iBAAiB,EAAE,GAAG,GAAG,GAAG,MAAM,QAAQ,IAAI;AAAA,YAC9D;AAAA,UACD,EAAE;AACF;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,oBAAoB;AAEpC,cAAI,CAAC,MAAM,WAAW;AACrB,kBAAM,UAAU,MAAM,gBAAgB,MAAM,QAAQ;AAEpD,gBAAI,MAAM,UAAU;AACnB,yBAAW,MAAM;AAChB,sBAAM,UAAU,MAAM,gBAAgB,KAAK;AAAA,cAC5C,GAAG,GAAI;AAAA,YACR;AAAA,UACD;AACA;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,sBAAsB;AAEtC,gBAAM,gBAAgB,MAAM,gBAAgB,IAAI;AAChD,gBAAM,UAAU,MAAM,gBAAgB,IAAI;AAC1C;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,uBAAuB;AACvC,gBAAM,gBAAgB,MAAM,gBAAgB,KAAK;AACjD,gBAAM,UAAU,MAAM,gBAAgB,KAAK;AAK3C,gBAAM,YAAY,MAAM,cAAc;AACtC;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,eAAe;AAC/B,gBAAM,gBAAgB,MAAM,gBAAgB,KAAK;AACjD,gBAAM,UAAU,MAAM,gBAAgB,KAAK;AAC3C,gBAAM,kBAAkB,MAAM,gBAAgB,MAAM,OAAO,MAAM,IAAI;AACrE;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,qBAAqB;AAMrC,gBAAM,OAAO,MAAM;AAQnB,gBAAM,iBAAiB,MAAM,cAAc,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE;AACvE,cAAI,eAAgB;AACpB,gBAAM,gBAAgB;AAAA,YACrB,IAAI,KAAK;AAAA,YACT,OAAO,KAAK;AAAA,YACZ,QAAQ,KAAK;AAAA,YACb,iBAAiB,KAAK,mBAAmB;AAAA,YACzC,eAAe,KAAK,iBAAiB;AAAA,YACrC,uBAAuB,KAAK,yBAAyB;AAAA,YACrD,uBAAuB;AAAA,YACvB,wBAAwB;AAAA,YACxB,cAAc;AAAA,YACd,eAAe;AAAA,YACf,aAAa;AAAA,UACd,CAAC;AACD;AAAA,QACD;AAAA,QAEA;AACC;AAAA,MACF;AAAA,IACD;AAAA,EACD,EAAE;AAKF,MAAI,OAAO,WAAW,aAAa;AAClC,QAAI,OAAO,MAAM,SAAS,EAAE;AAC5B,UAAM,UAAU,CAAC,MAAM;AACtB,UAAI,EAAE,oBAAoB,MAAM;AAC/B,eAAO,EAAE;AACT,uBAAe,EAAE,eAAe;AAAA,MACjC;AAAA,IACD,CAAC;AAAA,EACF;AAEA,SAAO;AACR;;;AC74BO,SAAS,gBACf,SACyD;AACzD,QAAM,WAAW,CAAC,YAAoB,SAA6B;AAClE,UAAM,KAAM,QAA+C,OAAO;AAClE,QAAI,OAAO,OAAO,YAAY;AAC7B,aAAQ,GAAoC,GAAG,IAAI;AAAA,IACpD;AACA,YAAQ,KAAK,8BAA8B,OAAO,EAAE;AACpD,WAAO;AAAA,EACR;AACA,QAAM,WAAW,OAAO,OAAO,UAAU,OAAO;AAChD,QAAM,WAAW,OAAO;AACxB,SAAO,UAAU;AACjB,QAAM,QAAQ,UAAU;AACxB,MAAI,OAAO,QAAQ;AAClB,eAAW,SAAS,OAAO;AAC1B,UAAI;AACH,iBAAS,GAAI,KAAgC;AAAA,MAC9C,SAAS,KAAK;AACb,gBAAQ,MAAM,iCAAiC,GAAG;AAAA,MACnD;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAEO,SAAS,iBAAiB,MAWd;AAClB,QAAM,EAAE,OAAO,SAAS,UAAU,OAAO,IAAI;AAE7C,SAAO;AAAA,IACN,OAAO;AACN,YAAM,SAAS,EAAE,QAAQ,IAAI;AAC7B,YAAM,SAAS,EAAE,aAAa,KAAK;AAAA,IACpC;AAAA,IAEA,QAAQ;AACP,YAAM,SAAS,EAAE,QAAQ,KAAK;AAAA,IAC/B;AAAA,IAEA,SAAS;AACR,YAAM,IAAI,MAAM,SAAS;AACzB,UAAI,EAAE,aAAa;AAClB,UAAE,aAAa,KAAK;AACpB,UAAE,QAAQ,IAAI;AACd,gBAAQ,KAAK,MAAM;AAAA,MACpB,OAAO;AACN,UAAE,QAAQ,CAAC,EAAE,MAAM;AAAA,MACpB;AAAA,IACD;AAAA,IAEA,UAAU;AACT,YAAM,SAAS,EAAE,QAAQ,KAAK;AAC9B,YAAM,SAAS,EAAE,aAAa,IAAI;AAClC,cAAQ,KAAK,SAAS;AAAA,IACvB;AAAA,IAEA,OAAO;AACN,YAAM,SAAS,EAAE,aAAa,KAAK;AACnC,cAAQ,KAAK,MAAM;AAAA,IACpB;AAAA,IAEA,WAAW;AACV,YAAM,SAAS,EAAE,QAAQ,KAAK;AAC9B,YAAM,SAAS,EAAE,aAAa,KAAK;AACnC,qBAAe,MAAM;AACrB,UAAI,OAAO,aAAa,aAAa;AACpC,iBAAS,SAAS;AAAA,MACnB;AAAA,IACD;AAAA,IAEA;AAAA,IAEA,gBAAgB,SAAkB;AACjC,YAAM,IAAI,MAAM,SAAS;AACzB,QAAE,aAAa,KAAK;AACpB,QAAE,QAAQ,IAAI;AACd,QAAE,0BAA0B,WAAW,EAAE;AAAA,IAC1C;AAAA,IAEA,iBAAiB,IAAY;AAC5B,YAAM,IAAI,MAAM,SAAS;AACzB,QAAE,aAAa,KAAK;AACpB,QAAE,sBAAsB,EAAE;AAC1B,QAAE,QAAQ,IAAI;AAAA,IACf;AAAA,IAEA,IAAI,cAAc;AACjB,aAAO,MAAM,SAAS,EAAE,cAAc,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC;AAAA,IAChF;AAAA,IAEA,IAAI,SAAS;AACZ,aAAO,MAAM,SAAS,EAAE;AAAA,IACzB;AAAA,IAEA,GAAG,OAAO,IAAI;AACb,cAAQ,GAAG,OAAO,EAAE;AAAA,IACrB;AAAA,IAEA,IAAI,OAAO,IAAI;AACd,cAAQ,IAAI,OAAO,EAAE;AAAA,IACtB;AAAA,EACD;AACD;;;AC/EA,SAAS,WAAW,OAAwB;AAC3C,SAAO,oBAAoB,KAAK,KAAK;AACtC;AAOA,SAAS,QAAQ,KAAqB;AACrC,MAAI,CAAC,WAAW,GAAG,EAAG,QAAO;AAC7B,QAAM,IAAI,KAAK,IAAI,KAAK,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE;AACjE,QAAM,IAAI,KAAK,IAAI,KAAK,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE;AACjE,QAAM,IAAI,KAAK,IAAI,KAAK,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE;AACjE,QAAM,OAAO,CAAC,MAAc,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAC1D,SAAO,IAAI,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;AACvC;AAGA,SAAS,OAAO,MAAmB,MAAc,OAA2B;AAC3E,MAAI,SAAS,QAAQ,UAAU,GAAI;AACnC,OAAK,MAAM,YAAY,MAAM,KAAK;AACnC;AAQO,SAAS,WAAW,MAAmB,OAAgC;AAC7E,MAAI,CAAC,QAAQ,CAAC,MAAO;AAErB,MAAI,MAAM,cAAc;AACvB,WAAO,MAAM,gBAAgB,MAAM,YAAY;AAC/C,WAAO,MAAM,sBAAsB,QAAQ,MAAM,YAAY,CAAC;AAC9D,WAAO,MAAM,cAAc,MAAM,YAAY;AAAA,EAC9C;AACA,SAAO,MAAM,iBAAiB,MAAM,cAAc;AAClD,SAAO,MAAM,0BAA0B,MAAM,eAAe,MAAM,YAAY;AAC9E,SAAO,MAAM,4BAA4B,MAAM,mBAAmB,MAAM,cAAc;AACtF,SAAO,MAAM,WAAW,MAAM,eAAe;AAC7C,SAAO,MAAM,aAAa,MAAM,SAAS;AACzC,SAAO,MAAM,eAAe,MAAM,WAAW;AAC7C,SAAO,MAAM,eAAe,MAAM,MAAM;AACxC,SAAO,MAAM,aAAa,MAAM,UAAU;AAE1C,MAAI,MAAM,aAAa,eAAe;AACrC,WAAO,MAAM,uBAAuB,MAAM;AAC1C,WAAO,MAAM,sBAAsB,MAAM;AACzC,WAAO,MAAM,qBAAqB,MAAM;AACxC,WAAO,MAAM,oBAAoB,GAAG;AAAA,EACrC,WAAW,MAAM,aAAa,gBAAgB;AAC7C,SAAK,MAAM,eAAe,qBAAqB;AAC/C,SAAK,MAAM,eAAe,oBAAoB;AAC9C,SAAK,MAAM,eAAe,mBAAmB;AAC7C,SAAK,MAAM,eAAe,kBAAkB;AAAA,EAC7C;AAKA,MAAI,MAAM,UAAW,MAAK,QAAQ,cAAc,MAAM;AAMtD,MAAI,MAAM,gBAAgB,WAAW,MAAM,gBAAgB,QAAQ;AAClE,SAAK,QAAQ,QAAQ,MAAM;AAAA,EAC5B,WAAW,MAAM,gBAAgB,UAAU;AAC1C,WAAO,KAAK,QAAQ;AAAA,EACrB;AAEA,MAAI,MAAM,cAAc;AACvB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,YAAY,GAAG;AAC9D,UAAI,IAAI,WAAW,IAAI,EAAG,MAAK,MAAM,YAAY,KAAK,KAAK;AAAA,IAC5D;AAAA,EACD;AACD;;;ACpKO,IAAM,qBAAN,MAAyB;AAAA,EACvB,YAAY,oBAAI,IAA2B;AAAA,EAEnD,GAA8B,OAAU,IAAqC;AAC5E,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,EAAG,MAAK,UAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AACnE,SAAK,UAAU,IAAI,KAAK,EAAG,IAAI,EAAc;AAAA,EAC9C;AAAA,EAEA,IAA+B,OAAU,IAAqC;AAC7E,SAAK,UAAU,IAAI,KAAK,GAAG,OAAO,EAAc;AAAA,EACjD;AAAA,EAEA,KACC,UACG,MACI;AACP,UAAM,OAAO,KAAK,CAAC;AACnB,SAAK,UAAU,IAAI,KAAK,GAAG,QAAQ,CAAC,OAAO;AAC1C,UAAI;AACH,WAAG,IAAI;AAAA,MACR,SAAS,KAAK;AACb,gBAAQ,MAAM,kCAAkC,KAAK,MAAM,GAAG;AAAA,MAC/D;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAEA,YAAkB;AACjB,SAAK,UAAU,MAAM;AAAA,EACtB;AACD;;;AC7BA,IAAM,KAA6B;AAAA;AAAA,EAElC,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,eAAe;AAAA;AAAA,EAGf,0BAA0B;AAAA,EAC1B,qBAAqB;AAAA,EACrB,+BAA+B;AAAA,EAC/B,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA;AAAA,EAGnB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA,EAC3B,6BAA6B;AAAA,EAC7B,qBAAqB;AAAA;AAAA,EAGrB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,gCAAgC;AAAA,EAChC,uBAAuB;AAAA,EACvB,wBAAwB;AAAA,EACxB,wBAAwB;AAAA,EACxB,+BAA+B;AAAA;AAAA,EAG/B,sBAAsB;AAAA,EACtB,0BAA0B;AAAA,EAC1B,qBAAqB;AAAA;AAAA,EAGrB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA;AAAA,EAGtB,sBAAsB;AAAA,EACtB,yBAAyB;AAAA,EACzB,4BAA4B;AAAA,EAC5B,yBAAyB;AAAA,EACzB,sBAAsB;AAAA,EACtB,wBAAwB;AAAA;AAAA,EAGxB,sBAAsB;AAAA,EACtB,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,qBAAqB;AAAA;AAAA,EAGrB,oBAAoB;AAAA;AAAA,EAGpB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA;AAAA,EAGlB,iBAAiB;AAAA,EACjB,eAAe;AAAA;AAAA,EAGf,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,sBAAsB;AAAA,EACtB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,kBAAkB;AAAA;AAAA,EAGlB,eAAe;AAAA,EACf,iBAAiB;AAAA;AAAA,EAGjB,yBAAyB;AAAA,EACzB,wBAAwB;AAAA,EACxB,2BAA2B;AAAA;AAAA,EAG3B,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,oBAAoB;AAAA,EACpB,6BAA6B;AAAA,EAC7B,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,wBAAwB;AAAA;AAAA,EAGxB,mBAAmB;AAAA,EACnB,yBAAyB;AAAA;AAAA,EAGzB,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMrB,0BAA0B;AAAA,EAC1B,wBAAwB;AACzB;AAIA,IAAI,gBAAgB;AACpB,IAAI,eAAuC,CAAC;AAC5C,IAAI,WAAW;AACf,IAAI,WAAW;AACf,IAAM,YAA+B,CAAC;AAU/B,SAAS,EAAE,KAAa,QAAkD;AAChF,QAAM,QAAQ,aAAa,GAAG,KAAK,GAAG,GAAG,KAAK;AAE9C,MAAI,CAAC,OAAQ,QAAO;AAEpB,SAAO,MAAM,QAAQ,kBAAkB,CAAC,GAAG,MAAc;AACxD,WAAO,OAAO,CAAC,GAAG,SAAS,KAAK,KAAK,CAAC;AAAA,EACvC,CAAC;AACF;AAGO,SAAS,YAAoB;AACnC,SAAO;AACR;AAGO,SAAS,kBAA0B;AACzC,SAAO;AACR;AAQO,SAAS,eAAe,IAA4B;AAC1D,YAAU,KAAK,EAAE;AACjB,SAAO,MAAM;AACZ,UAAM,MAAM,UAAU,QAAQ,EAAE;AAChC,QAAI,OAAO,EAAG,WAAU,OAAO,KAAK,CAAC;AAAA,EACtC;AACD;AAYA,eAAsB,SAAS,SAAgE;AAC9F,MAAI,SAAS,SAAS;AACrB,cAAU,QAAQ;AAAA,EACnB;AAEA,QAAM,WACL,SAAS,WAAW,OAAO,cAAc,cAAc,UAAU,WAAW;AAG7E,kBAAgB,gBAAgB,QAAQ;AAGxC,MAAI,kBAAkB,MAAM;AAC3B,eAAW;AACX,WAAO;AACP;AAAA,EACD;AAGA,MAAI;AACH,UAAM,OAAO,MAAM,kBAAkB,aAAa;AAClD,QAAI,MAAM;AAET,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAChD,YAAI,OAAO,UAAU,UAAU;AAC9B,uBAAa,UAAU,GAAG,EAAE,IAAI;AAAA,QACjC;AAAA,MACD;AAAA,IACD;AAAA,EACD,SAAS,KAAK;AACb,YAAQ,KAAK,6BAA6B,aAAa,gCAAgC,GAAG;AAAA,EAC3F;AAEA,aAAW;AACX,SAAO;AACR;AAMA,eAAsB,UAAU,QAA+B;AAC9D,QAAM,aAAa,gBAAgB,MAAM;AACzC,MAAI,eAAe,cAAe;AAElC,kBAAgB;AAChB,iBAAe,CAAC;AAEhB,MAAI,eAAe,MAAM;AACxB,WAAO;AACP;AAAA,EACD;AAEA,MAAI;AACH,UAAM,OAAO,MAAM,kBAAkB,UAAU;AAC/C,QAAI,MAAM;AACT,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAChD,YAAI,OAAO,UAAU,UAAU;AAC9B,uBAAa,UAAU,GAAG,EAAE,IAAI;AAAA,QACjC;AAAA,MACD;AAAA,IACD;AAAA,EACD,QAAQ;AAAA,EAER;AAEA,SAAO;AACR;AAIA,IAAI,UAAU;AAEd,eAAe,kBAAkB,QAAwD;AAExF,QAAM,MAAM,GAAG,OAAO,IAAI,MAAM;AAEhC,MAAI,MAAM,MAAM,MAAM,GAAG;AACzB,MAAI,CAAC,IAAI,MAAM,OAAO,SAAS,GAAG,GAAG;AAEpC,UAAM,OAAO,OAAO,MAAM,GAAG,EAAE,CAAC;AAChC,UAAM,MAAM,MAAM,GAAG,OAAO,IAAI,IAAI,oBAAoB;AAAA,EACzD;AACA,MAAI,CAAC,IAAI,GAAI,QAAO;AAEpB,QAAM,OAAgC,MAAM,IAAI,KAAK;AAErD,QAAM,WAAW,KAAK;AACtB,MAAI,YAAY,OAAO,aAAa,YAAY,CAAC,MAAM,QAAQ,QAAQ,GAAG;AACzE,UAAM,SAAiC,CAAC;AACxC,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,GAAG;AAC9C,UAAI,OAAO,MAAM,SAAU,QAAO,CAAC,IAAI;AAAA,IACxC;AACA,WAAO;AAAA,EACR;AACA,SAAO;AACR;AAEA,SAAS,gBAAgB,OAAuB;AAE/C,QAAM,WAAW,CAAC,SAAS,SAAS,SAAS,OAAO;AACpD,QAAM,QAAQ,MAAM,YAAY,EAAE,QAAQ,KAAK,GAAG;AAElD,aAAW,KAAK,UAAU;AACzB,QAAI,MAAM,WAAW,CAAC,EAAG,QAAO;AAAA,EACjC;AAGA,SAAO,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK;AAC/B;AAEA,SAAS,SAAe;AACvB;AACA,aAAW,MAAM,WAAW;AAC3B,QAAI;AACH,SAAG;AAAA,IACJ,QAAQ;AAAA,IAER;AAAA,EACD;AACD;;;AC/SO,SAAS,mBAAmB,MAA6B;AAC/D,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,OAAO,OAAO,SAAS,WAAW,IAAI,KAAK,IAAI,EAAE,QAAQ,IAAI,KAAK,QAAQ;AAChF,QAAM,SAAS,MAAM;AACrB,QAAM,UAAU,KAAK,MAAM,SAAS,GAAK;AACzC,QAAM,WAAW,KAAK,MAAM,SAAS,IAAO;AAC5C,QAAM,UAAU,KAAK,MAAM,SAAS,KAAQ;AAE5C,MAAI,UAAU,EAAG,QAAO,EAAE,iBAAiB;AAC3C,MAAI,UAAU,GAAI,QAAO,GAAG,OAAO;AACnC,MAAI,WAAW,GAAI,QAAO,GAAG,QAAQ;AACrC,MAAI,YAAY,EAAG,QAAO,EAAE,uBAAuB;AACnD,MAAI,UAAU,EAAG,QAAO,GAAG,OAAO;AAElC,QAAM,IAAI,OAAO,SAAS,WAAW,IAAI,KAAK,IAAI,IAAI;AACtD,SAAO,EAAE,mBAAmB,UAAU,GAAG,EAAE,OAAO,SAAS,KAAK,UAAU,CAAC;AAC5E;AAKO,SAAS,WAAW,MAA6B;AACvD,QAAM,IAAI,OAAO,SAAS,WAAW,IAAI,KAAK,IAAI,IAAI;AACtD,SAAO,EAAE,mBAAmB,QAAW,EAAE,MAAM,WAAW,QAAQ,UAAU,CAAC;AAC9E;AAOO,SAAS,aAAa,OAAuB;AACnD,MAAI,CAAC,MAAM,WAAW,SAAS,EAAG,QAAO;AACzC,QAAM,WAAW,EAAE,KAAK;AACxB,MAAI,aAAa,OAAO;AACvB,WAAO,MACL,QAAQ,WAAW,EAAE,EACrB,QAAQ,MAAM,GAAG,EACjB,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC;AAAA,EACxC;AACA,SAAO;AACR;AAKO,SAAS,YAAY,OAAuB;AAClD,MAAI,CAAC,MAAO,QAAO;AAGnB,MAAI,MAAM,SAAS,GAAG,EAAG,SAAQ,MAAM,CAAC,KAAK,KAAK,YAAY;AAG9D,QAAM,QAAQ,MAAM,KAAK,EAAE,MAAM,KAAK;AACtC,MAAI,MAAM,UAAU,GAAG;AACtB,aAAS,MAAM,CAAC,IAAI,CAAC,KAAK,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY;AAAA,EACpE;AACA,UAAQ,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY;AAC3C;;;AC9CA;AAAA,EAEC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAwB,gBAAgB;AA2hBhC;AAngBR,IAAM,gBAAgB,cAAyC,IAAI;AAE5D,SAAS,mBAAuC;AACtD,QAAM,MAAM,WAAW,aAAa;AACpC,MAAI,CAAC,KAAK;AACT,UAAM,IAAI,MAAM,wDAAwD;AAAA,EACzE;AACA,SAAO;AACR;AAGO,SAAS,eAAkB,UAAwC;AACzE,QAAM,EAAE,MAAM,IAAI,iBAAiB;AACnC,SAAO,SAAS,OAAO,QAAQ;AAChC;AAGO,SAAS,cAAc;AAC7B,QAAM,EAAE,SAAS,IAAI,iBAAiB;AACtC,SAAO;AACR;AAOO,SAAS,kBAAgC;AAC/C,QAAM,EAAE,OAAO,IAAI,iBAAiB;AACpC,SAAO;AACR;AAoCO,SAAS,gBAAgB;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;AACD,GAAyB;AACxB,QAAM,UAAU,OAON,IAAI;AACd,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAS,KAAK;AAChE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,KAAK;AAC1D,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAS,CAAC;AAE1D,MAAI,CAAC,QAAQ,SAAS;AACrB,UAAM,iBAAiB,UAAU,YAAY;AAE7C,UAAMC,UAAS,mBAAmB;AAAA,MACjC,QAAQ;AAAA,MACR;AAAA,IACD,CAAC;AAED,UAAMC,SAAQ,kBAAkB;AAChC,UAAMC,WAAU,IAAI,mBAAmB;AAEvC,UAAMC,MAAK,IAAI,iBAAiB;AAAA,MAC/B,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW;AAAA,MACX;AAAA,IACD,CAAC;AAED,UAAMC,YAAW,OAAO,SAAuB;AAC9C,UAAI;AACH,cAAM,SAAS,MAAMJ,QAAO,OAAO,SAAS,OAAO,IAAI;AACvD,YAAI,OAAO,SAAS;AACnB,UAAAC,OAAM,SAAS,EAAE,qBAAqB;AAAA,YACrC,IAAI,OAAO,QAAQ;AAAA,YACnB,MAAM,OAAO,QAAQ,QAAQ;AAAA,YAC7B,OAAO,OAAO,QAAQ,SAAS;AAAA,UAChC,CAAC;AAAA,QACF;AACA,cAAM,aAAa,KAAK,UAAU;AAClC,YAAI,OAAO,eAAe,YAAY,WAAW,SAAS,GAAG;AAC5D,oBAAU,UAAU;AAAA,QACrB;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,8BAA8B,GAAG;AAAA,MAChD;AAAA,IACD;AAEA,UAAMI,OAAM,iBAAiB,EAAE,OAAAJ,QAAO,SAAAC,UAAS,UAAAE,WAAU,OAAO,CAAC;AAOjE,YAAQ,UAAU,EAAE,QAAAJ,SAAQ,OAAAC,QAAO,IAAAE,KAAI,UAAAC,WAAU,KAAAC,MAAK,SAAAH,SAAQ;AAAA,EAC/D;AAEA,QAAM,EAAE,QAAQ,OAAO,IAAI,UAAU,KAAK,QAAQ,IAAI,QAAQ;AAE9D,QAAM,iBAAiB,YAAY,MAAM;AACxC,yBAAqB,KAAK;AAC1B,wBAAoB,CAAC,MAAM,IAAI,CAAC;AAAA,EACjC,GAAG,CAAC,CAAC;AAGL,YAAU,MAAM;AACf,QAAI,YAAY;AAEhB,mBAAe,YAAY;AAC1B,UAAI;AACH,cAAM,OAAO,MAAM,OAAO,OAAO,UAAU,MAAM;AACjD,YAAI,UAAW;AAKf,cAAM,iBACL,UAAW,KAA4C,kBAAkB;AAC1E,cAAM,SAAS;AAAA,UACd,QAAQ;AAAA,UACR,SAAU,KAAK,aAAiD,eAAe;AAAA,QAChF,CAAC;AAED,cAAM,SAAS,EAAE,SAAS,KAAK,SAAS,KAAK,SAAS,KAAK,WAAW;AACtE,6BAAqB,KAAK;AAI1B,YAAI,KAAK,SAAS,IAAI;AACrB,wBAAc,QAAQ,KAAK,QAAQ,EAAE;AAAA,QACtC;AAEA,cAAM,WAAW,MAAM,OAAO,OAAO,kBAAkB,MAAM;AAC7D,YAAI,UAAW;AAEf,cAAM,kBAAkB,CAAC,OASlB;AAAA,UACN,IAAI,EAAE;AAAA,UACN,OAAO,EAAE;AAAA,UACT,QAAQ,EAAE;AAAA,UACV,iBAAiB,EAAE;AAAA,UACnB,eAAe,EAAE;AAAA,UACjB,uBAAuB,EAAE;AAAA,UACzB,uBAAuB,EAAE;AAAA,UACzB,wBAAwB,EAAE;AAAA,UAC1B,aAAa;AAAA,QACd;AAEA,cAAM,SAAS,EAAE;AAAA,UAChB,SAAS,cAAc,IAAI,eAAe;AAAA,QAC3C;AAOA,YAAI,KAAK,SAAS,MAAM,KAAK,SAAS,IAAI;AACzC,aAAG,UAAU,EAAE,WAAW,KAAK,QAAQ,IAAI,WAAW,KAAK,QAAQ,GAAG,CAAC;AACvE,aAAG,QAAQ;AAAA,QACZ;AAEA,YAAI,SAAS,cAAc,WAAW,KAAK,CAAC,uBAAuB;AAClE,cAAI;AACH,kBAAM,YAAY,MAAM,OAAO,OAAO,eAAe,OAAO;AAC5D,gBAAI,aAAa,CAAC,UAAU,WAAW;AAAA,YAEvC,WAAW,UAAU,WAAW;AAI/B,uCAAyB,OAAO,UAAU,SAAS;AAAA,YACpD,WAAW,UAAU,gBAAgB;AAIpC,oBAAM,UAAS,oBAAI,KAAK,GAAE,YAAY;AACtC,oBAAM,SAAS,EAAE,gBAAgB;AAAA,gBAChC,IAAI,UAAU;AAAA,gBACd,OAAO;AAAA,gBACP,QAAQ;AAAA,gBACR,iBAAiB,UAAU,mBAAmB;AAAA,gBAC9C,eAAe,UAAU,iBAAiB;AAAA,gBAC1C,uBAAuB,UAAU,yBAAyB;AAAA,gBAC1D,uBAAuB;AAAA,gBACvB,wBAAwB;AAAA,gBACxB,cAAc;AAAA,gBACd,eAAe;AAAA,gBACf,aAAa;AAAA,cACd,CAAC;AACD,kBAAI,UAAU,mBAAmB,CAAC,MAAM,SAAS,EAAE,QAAQ;AAC1D,sBAAM,SAAS;AAAA,kBACd,iBAAiB;AAAA,oBAChB,MAAM,UAAU;AAAA,oBAChB,gBAAgB,UAAU;AAAA,oBAC1B,WAAW,KAAK,IAAI;AAAA,kBACrB;AAAA,gBACD,CAAC;AAAA,cACF;AAAA,YACD;AAAA,UACD,QAAQ;AAAA,UAER;AAAA,QACD;AAEA,YAAI,OAAO,WAAW,aAAa;AAClC,iBAAO,OAAO,WACZ,OAAO;AAAA,YACP,KAAK,OAAO,SAAS;AAAA,YACrB,OAAO,SAAS,SAAS,OAAO,SAAS;AAAA,UAC1C,CAAC,EACA,MAAM,MAAM;AAAA,UAAC,CAAC;AAAA,QACjB;AAEA,YAAI,yBAAyB,CAAC,WAAW;AACxC,cAAI,eAAe;AAClB,gBAAI;AACH,oBAAM,WAAW,MAAM,OAAO,OAAO,eAAe,OAAO,EAAE,OAAO,cAAc,CAAC;AACnF,kBAAI,CAAC,aAAa,UAAU,aAAa,SAAS,cAAc,KAAK,SAAS,IAAI;AACjF,8BAAc,QAAQ,SAAS,SAAS;AACxC,sBAAM,YAAY,MAAM,OAAO,OAAO,UAAU,MAAM;AACtD,oBAAI,CAAC,WAAW;AACf,wBAAM,SAAS,EAAE,SAAS,UAAU,SAAS,UAAU,SAAS,UAAU,WAAW;AACrF,wBAAM,aAAa,MAAM,OAAO,OAAO,kBAAkB,MAAM;AAC/D,sBAAI,CAAC,WAAW;AACf,0BAAM,SAAS,EAAE;AAAA,sBAChB,WAAW,cAAc,IAAI,eAAe;AAAA,oBAC7C;AAAA,kBACD;AAAA,gBACD;AAAA,cACD;AAAA,YACD,QAAQ;AAAA,YAER;AAAA,UACD;AACA,cAAI,CAAC,WAAW;AACf,kBAAM,SAAS,EAAE,sBAAsB,qBAAqB;AAC5D,kBAAM,SAAS,EAAE,QAAQ,IAAI;AAAA,UAC9B;AAAA,QACD;AAEA,gBAAQ,KAAK,OAAO;AACpB,kBAAU,QAAQ,QAAS,GAAG;AAAA,MAC/B,SAAS,KAAK;AACb,gBAAQ,MAAM,+BAA+B,GAAG;AAChD,YAAI,CAAC,WAAW;AACf,gBAAM,SAAS,EAAE,cAAc,KAAK;AACpC,+BAAqB,IAAI;AAAA,QAC1B;AAAA,MACD;AAAA,IACD;AAEA,cAAU;AAMV,QAAI,eAAqD;AACzD,UAAM,aAAa,MAAM;AACxB,UAAI,OAAO,WAAW,YAAa;AACnC,UAAI,aAAc,cAAa,YAAY;AAC3C,qBAAe,WAAW,MAAM;AAC/B,eAAO,OAAO,WACZ,OAAO;AAAA,UACP,KAAK,OAAO,SAAS;AAAA,UACrB,OAAO,SAAS,SAAS,OAAO,SAAS;AAAA,QAC1C,CAAC,EACA,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MACjB,GAAG,GAAG;AAAA,IACP;AAEA,UAAM,WAAW,OAAO,QAAQ,UAAU,KAAK,OAAO,OAAO;AAC7D,UAAM,cAAc,OAAO,QAAQ,aAAa,KAAK,OAAO,OAAO;AACnE,WAAO,QAAQ,YAAY,SAAS,eAAe,MAAM;AACxD,eAAS,GAAG,IAAI;AAChB,iBAAW;AAAA,IACZ;AACA,WAAO,QAAQ,eAAe,SAAS,kBAAkB,MAAM;AAC9D,kBAAY,GAAG,IAAI;AACnB,iBAAW;AAAA,IACZ;AACA,WAAO,iBAAiB,YAAY,UAAU;AAI9C,QAAI,gBAAsD;AAC1D,UAAM,mBAAmB,CAAC,mBAA2B;AACpD,UAAI,cAAe,cAAa,aAAa;AAC7C,sBAAgB,WAAW,MAAM;AAChC,eAAO,OAAO,SAAS,OAAO,EAAE,eAAe,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAChE,cAAM,SAAS,EAAE,YAAY,cAAc;AAAA,MAC5C,GAAG,GAAG;AAAA,IACP;AAEA,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AACnC,YAAM,SAAS,EAAE,oBAAoB,KAAK;AAE1C,UAAI,MAAM,SAAS,uBAAuB;AACzC,cAAM,OAAO,MAAM;AACnB,cAAM,mBAAmB,MAAM,eAAe,YAAY,CAAC,KAAK;AAGhE,YAAI,oBAAoB,MAAM,MAAM;AACnC,kBAAQ,KAAK,mBAAmB;AAAA,YAC/B,gBAAgB,MAAM;AAAA,YACtB,MAAM,KAAK;AAAA,YACX,YAAY,eAAe,QAAQ,KAAK,YAAY,OAAO;AAAA,UAC5D,CAAC;AAAA,QACF;AAEA,YAAI,CAAC,iBAAkB;AACvB,cAAM,IAAI,MAAM,SAAS;AACzB,cAAM,YAAY,EAAE,UAAU,EAAE,yBAAyB,MAAM;AAC/D,YAAI,UAAW,kBAAiB,MAAM,cAAc;AAAA,MACrD;AAAA,IACD,CAAC;AAcD,UAAM,gBAAgB;AACtB,QAAI,YAA2B;AAC/B,UAAM,UAAU,YAAY,MAAM;AACjC,UAAI,GAAG,aAAa;AACnB,oBAAY;AACZ,0BAAkB,KAAK;AACvB;AAAA,MACD;AACA,UAAI,cAAc,KAAM,aAAY,KAAK,IAAI;AAC7C,wBAAkB,KAAK,IAAI,IAAI,aAAa,aAAa;AAAA,IAC1D,GAAG,GAAI;AAEP,WAAO,MAAM;AACZ,kBAAY;AACZ,YAAM;AACN,oBAAc,OAAO;AACrB,UAAI,cAAe,cAAa,aAAa;AAC7C,UAAI,aAAc,cAAa,YAAY;AAC3C,aAAO,QAAQ,YAAY;AAC3B,aAAO,QAAQ,eAAe;AAC9B,aAAO,oBAAoB,YAAY,UAAU;AACjD,SAAG,WAAW;AAAA,IACf;AAAA,EACD,GAAG,CAAC,QAAQ,OAAO,IAAI,gBAAgB,CAAC;AAGxC,YAAU,MAAM;AACf,QAAI,UAAU,MAAM;AACnB,gBAAU,MAAM;AAAA,IACjB;AAAA,EACD,GAAG,CAAC,MAAM,CAAC;AAGX,YAAU,MAAM;AACf,UAAM,QAAQ,MAAM,UAAU,CAAC,OAAO,SAAS;AAC9C,UAAI,MAAM,UAAU,CAAC,KAAK,QAAQ;AACjC,gBAAQ,KAAK,MAAM;AACnB,iBAAS;AAAA,MACV;AACA,UAAI,CAAC,MAAM,UAAU,KAAK,QAAQ;AACjC,gBAAQ,KAAK,OAAO;AACpB,kBAAU;AAAA,MACX;AACA,YAAM,aAAa,KAAK,cAAc,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,aAAa,CAAC;AAC3E,YAAM,aAAa,MAAM,cAAc,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,aAAa,CAAC;AAC5E,UAAI,eAAe,YAAY;AAC9B,gBAAQ,KAAK,gBAAgB,UAAU;AACvC,yBAAiB,UAAU;AAAA,MAC5B;AAAA,IACD,CAAC;AACD,WAAO;AAAA,EACR,GAAG,CAAC,OAAO,SAAS,QAAQ,SAAS,cAAc,CAAC;AAGpD,YAAU,MAAM;AACf,QAAI,CAAC,uBAAwB;AAC7B,UAAM,UAAU,CAAC,MAAa;AAC7B,QAAE,eAAe;AACjB,UAAI,OAAO;AAAA,IACZ;AAEA,UAAM,SAAS,MAAM;AACpB,YAAMI,MAAK,SAAS,cAAc,sBAAsB;AACxD,UAAIA,KAAI;AACP,QAAAA,IAAG,iBAAiB,SAAS,OAAO;AACpC,eAAOA;AAAA,MACR;AACA,aAAO;AAAA,IACR;AAEA,QAAI,KAAK,OAAO;AAChB,QAAI,WAAoC;AAExC,QAAI,CAAC,IAAI;AACR,iBAAW,IAAI,iBAAiB,MAAM;AACrC,aAAK,OAAO;AACZ,YAAI,GAAI,WAAU,WAAW;AAAA,MAC9B,CAAC;AACD,eAAS,QAAQ,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS,KAAK,CAAC;AAAA,IACnE;AAEA,WAAO,MAAM;AACZ,UAAI,oBAAoB,SAAS,OAAO;AACxC,gBAAU,WAAW;AAAA,IACtB;AAAA,EACD,GAAG,CAAC,wBAAwB,GAAG,CAAC;AAmBhC,YAAU,MAAM;AACf,QAAI,CAAC,SAAS,OAAO,aAAa,YAAa;AAC/C,UAAM,SACJ,SAAS,eAAe,gBAAgB,KACzC,SAAS;AACV,eAAW,QAAQ,KAAK;AAAA,EACzB,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM;AACf,QAAI,OAAO,WAAW,YAAa;AACnC,UAAM,WAAW,gBAAgB,GAAG;AACpC,WAAO,MAAM;AACZ,UAAI,OAAO,YAAY,UAAU;AAChC,eAAO,UAAU;AAAA,MAClB;AACA,cAAQ,UAAU;AAAA,IACnB;AAAA,EACD,GAAG,CAAC,KAAK,OAAO,CAAC;AAEjB,QAAM,WAA+B;AAAA,IACpC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAEA,SAAO,oBAAC,cAAc,UAAd,EAAuB,OAAO,UAAW,UAAS;AAC3D;AA2BO,IAAM,wBAAwB;AAarC,SAAS,yBACR,OACA,SACC;AACD,QAAM,UAAU,GAAG,qBAAqB,GAAG,QAAQ,UAAU;AAC7D,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,cAAc,QAAQ,SAAS,QAAQ,SAAS,SAAS,CAAC;AAChE,QAAM,cAAc,aAAa,QAAQ;AAKzC,QAAM,QAAQ,QAAQ,SAAS,IAAI,CAAC,GAAG,OAAO;AAAA,IAC7C,IAAI,GAAG,OAAO,QAAQ,EAAE,MAAM;AAAA,IAC9B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,MAAM,EAAE;AAAA,IACR,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW,IAAI,KAAK,OAAO,QAAQ,SAAS,SAAS,KAAK,GAAG,EAAE,YAAY;AAAA,IAC3E,UAAU;AAAA,IACV,WAAW;AAAA,EACZ,EAAE;AAEF,MAAI,QAAQ,cAAc;AACzB,UAAM,aACL,QAAQ,aAAa,UACrB,QAAQ,aAAa,QAAQ,IAAI,CAAC,MAAM,UAAK,EAAE,KAAK,EAAE,EAAE,KAAK,IAAI;AAClE,UAAM,KAAK;AAAA,MACV,IAAI,GAAG,OAAO,OAAO,QAAQ,aAAa,MAAM;AAAA,MAChD,gBAAgB;AAAA,MAChB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW;AAAA,MACX,WAAW,IAAI,KAAK,GAAG,EAAE,YAAY;AAAA,MACrC,UAAU;AAAA,MACV,WAAW;AAAA,MACX,UAAU;AAAA,QACT,MAAM;AAAA,QACN,QAAQ,QAAQ,aAAa,UAAU;AAAA,QACvC,SAAS,QAAQ,aAAa,QAAQ,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,MAAM,EAAE;AAAA,QAC/E,QAAQ,QAAQ,aAAa;AAAA,MAC9B;AAAA;AAAA,IAED,CAAQ;AAAA,EACT;AAEA,QAAM,IAAI,MAAM,SAAS;AACzB,IAAE,gBAAgB;AAAA,IACjB,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,eAAe,IAAI,KAAK,GAAG,EAAE,YAAY;AAAA,IACzC,uBAAuB;AAAA,IACvB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,aAAa,MAAM;AAAA,EACpB,CAAC;AAED,IAAE,YAAY,SAAS,KAAY;AAEnC,MAAI,CAAC,EAAE,UAAU,aAAa;AAC7B,UAAM,SAAS;AAAA,MACd,iBAAiB;AAAA,QAChB,MAAM;AAAA,QACN,gBAAgB;AAAA,QAChB,WAAW;AAAA,QACX,UAAU,QAAQ,SAAS,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE;AAAA,QACxD,GAAI,QAAQ,eACT;AAAA,UACA,cAAc;AAAA,YACb,QAAQ,QAAQ,aAAa;AAAA,YAC7B,QAAQ,QAAQ,aAAa,UAAU;AAAA,YACvC,SAAS,QAAQ,aAAa,QAAQ,IAAI,CAAC,OAAO;AAAA,cACjD,IAAI,EAAE;AAAA,cACN,OAAO,EAAE;AAAA,YACV,EAAE;AAAA,UACH;AAAA,QACD,IACC,CAAC;AAAA,MACL;AAAA,IACD,CAAC;AAAA,EACF;AACD;AAEA,SAAS,cAAsB;AAC9B,MAAI,OAAO,aAAa,aAAa;AACpC,UAAM,SAAS,SAAS,cAAc,uBAAuB;AAC7D,QAAI,QAAQ;AACX,YAAM,MAAM,OAAO,aAAa,KAAK;AACrC,UAAI,KAAK;AACR,YAAI;AACH,gBAAM,MAAM,IAAI,IAAI,GAAG;AACvB,iBAAO,GAAG,IAAI,QAAQ,KAAK,IAAI,IAAI;AAAA,QACpC,QAAQ;AAAA,QAER;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;;;AClsBA,SAAS,eAAAC,eAAa,aAAAC,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;;;ACRzD,SAAS,eAAAC,cAAa,aAAAC,YAAW,SAAS,UAAAC,eAAc;AAiBxD,SAAS,WAAW,WAAmB,WAA2B;AACjE,SAAO,WAAW,SAAS,IAAI,SAAS;AACzC;AAEA,SAAS,WAAW,WAAmB,WAA4B;AAClE,MAAI;AACH,WAAO,aAAa,QAAQ,WAAW,WAAW,SAAS,CAAC,MAAM;AAAA,EACnE,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,aAAa,WAAmB,WAAgC;AACxE,MAAI;AACH,UAAM,MAAM,aAAa,QAAQ,WAAW,WAAW,SAAS,CAAC;AACjE,QAAI,CAAC,IAAK,QAAO,oBAAI,IAAI;AACzB,WAAO,IAAI,IAAI,KAAK,MAAM,GAAG,CAAa;AAAA,EAC3C,QAAQ;AACP,WAAO,oBAAI,IAAI;AAAA,EAChB;AACD;AAEA,SAAS,YAAY,WAAmB,WAAmB,MAAoB;AAC9E,MAAI;AACH,UAAM,OAAO,aAAa,WAAW,SAAS;AAC9C,SAAK,IAAI,IAAI;AACb,iBAAa,QAAQ,WAAW,WAAW,SAAS,GAAG,KAAK,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,EACjF,QAAQ;AAAA,EAER;AACD;AAEA,SAAS,aAAa,WAAmB,WAAmB,OAAuB;AAClF,MAAI;AACH,UAAM,OAAO,aAAa,WAAW,SAAS;AAC9C,eAAW,KAAK,MAAO,MAAK,IAAI,CAAC;AACjC,iBAAa,QAAQ,WAAW,WAAW,SAAS,GAAG,KAAK,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,EACjF,QAAQ;AAAA,EAER;AACD;AAEA,SAAS,aAAa,SAA8B,MAAwC;AAC3F,SAAO,QAAQ,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,IAAI,CAAC;AAC/C;AAEA,IAAM,aAAiC,CAAC;AAYjC,SAAS,mBAAmB;AAClC,QAAM,EAAE,QAAQ,MAAM,IAAI,iBAAiB;AAC3C,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,OAAO;AAC/C,QAAM,YAAY,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK;AAC1D,QAAM,YAAY,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK;AAC1D,QAAM,cAAc,eAAe,CAAC,MAAM,CAAC,EAAE,SAAS,OAAO;AAC7D,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,aAAa,WAAW,KAAK;AACzE,QAAM,mBAAmB;AAAA,IACxB,MAAM,YAAY,OAAO,CAACC,OAAMA,GAAE,eAAe;AAAA,IACjD,CAAC,WAAW;AAAA,EACb;AACA,QAAM,aAAaC,QAAO,KAAK;AAE/B,EAAAC,WAAU,MAAM;AACf,QAAI,CAAC,WAAW,CAAC,aAAa,CAAC,aAAa,iBAAiB,WAAW,EAAG;AAC3E,QAAI,WAAW,QAAS;AACxB,eAAW,UAAU;AAErB,UAAM,eAAe,CAAC,WAAW,WAAW,SAAS;AACrD,QAAI,UAAU,iBAAiB;AAC/B,QAAI,cAAc;AAClB,UAAM,WAAqB,CAAC;AAE5B,aAAS,UAAU,SAA8B,KAAuB;AACvE,eAAS,KAAK,GAAG,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAI3C,UAAI,EAAE,gBAAgB,CAAC,gBAAgB,QAAQ,SAAS,GAAG;AAC1D,cAAM,OAAO,aAAa,WAAY,SAAU;AAChD,cAAM,SAAS,aAAa,SAAS,IAAI;AACzC,uBAAe,OAAO;AAEtB,cAAM,SAAS,OAAO,CAAC;AACvB,YAAI,UAAU,CAAC,MAAM,SAAS,EAAE,QAAQ;AACvC,gBAAM,aAAa,IAAI,SAAS;AAChC,gBAAM,SAAS,EAAE,uBAAuB;AAAA,YACvC,OAAO,OAAO;AAAA,YACd,MAAM,OAAO;AAAA,YACb,MAAM,OAAO;AAAA,YACb,OAAO,IAAI;AAAA,YACX,OAAO,aAAc,OAAO,aAAa,UAAU,KAAK,OAAQ;AAAA,UACjE,CAAC;AAAA,QACF;AAAA,MACD;AAEA;AACA,UAAI,YAAY,GAAG;AAClB,YAAI,gBAAgB,CAAC,aAAa;AAEjC,cAAI,SAAS,SAAS,GAAG;AACxB,yBAAa,WAAY,WAAY,QAAQ;AAAA,UAC9C;AACA,gBAAM,SAAS,EAAE,2BAA2B,CAAC;AAAA,QAC9C,OAAO;AACN,gBAAM,SAAS,EAAE,2BAA2B,WAAW;AAAA,QACxD;AAAA,MACD;AAAA,IACD;AAEA,eAAW,OAAO,kBAAkB;AACnC,YAAM,WAAW,iBAAiB,IAAI,EAAE,IAAI,UAAU,CAAC;AACvD,YAAM,SAAS,MAAM,SAAS,EAAE,aAAa,IAAI,QAAQ;AACzD,UAAI,UAAU,KAAK,IAAI,IAAI,OAAO,KAAK,mBAAmB;AACzD,kBAAU,OAAO,MAA6B,GAAG;AAAA,MAClD,OAAO;AACN,eAAO,OAAO,WACZ,MAAM,EAAE,OAAO,IAAI,IAAI,MAAM,GAAG,OAAO,GAAG,UAAU,UAAU,EAAE,CAAC,EACjE,KAAK,CAAC,WAA4C;AAClD,gBAAM,UAAU,OAAO,SAAS,CAAC;AACjC,gBAAM,SAAS,EAAE,gBAAgB,UAAU,OAAO;AAClD,oBAAU,SAAS,GAAG;AAAA,QACvB,CAAC,EACA,MAAM,MAAM;AACZ,oBAAU,CAAC,GAAG,GAAG;AAAA,QAClB,CAAC;AAAA,MACH;AAAA,IACD;AAAA,EACD,GAAG,CAAC,SAAS,WAAW,WAAW,aAAa,kBAAkB,QAAQ,KAAK,CAAC;AAEhF,QAAM,gBAAgBC;AAAA,IACrB,CAAC,SAAiB;AACjB,UAAI,CAAC,aAAa,CAAC,aAAa,iBAAiB,WAAW,EAAG;AAC/D,kBAAY,WAAW,WAAW,IAAI;AAGtC,YAAM,OAAO,aAAa,WAAW,SAAS;AAC9C,UAAI,QAAQ;AACZ,iBAAW,OAAO,kBAAkB;AACnC,cAAM,WAAW,iBAAiB,IAAI,EAAE,IAAI,UAAU,CAAC;AACvD,cAAM,SAAS,MAAM,SAAS,EAAE,aAAa,IAAI,QAAQ;AACzD,YAAI,QAAQ;AACX,mBAAS,aAAa,OAAO,MAA6B,IAAI,EAAE;AAAA,QACjE;AAAA,MACD;AACA,YAAM,SAAS,EAAE,2BAA2B,KAAK;AACjD,YAAM,SAAS,EAAE,2BAA2B,IAAI;AAAA,IACjD;AAAA,IACA,CAAC,WAAW,WAAW,kBAAkB,KAAK;AAAA,EAC/C;AAEA,QAAM,cAAcA,aAAY,MAAM;AACrC,QAAI,CAAC,aAAa,CAAC,aAAa,iBAAiB,WAAW,EAAG;AAC/D,eAAW,OAAO,kBAAkB;AACnC,YAAM,WAAW,iBAAiB,IAAI,EAAE,IAAI,UAAU,CAAC;AACvD,YAAM,SAAS,MAAM,SAAS,EAAE,aAAa,IAAI,QAAQ;AACzD,UAAI,QAAQ;AACX,cAAM,UAAU,OAAO;AACvB,qBAAa,WAAW,WAAW,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAAA,MAC9D;AAAA,IACD;AACA,UAAM,SAAS,EAAE,2BAA2B,CAAC;AAC7C,UAAM,SAAS,EAAE,2BAA2B;AAAA,EAC7C,GAAG,CAAC,WAAW,WAAW,kBAAkB,KAAK,CAAC;AAElD,QAAM,mBAAmBA,aAAY,MAAiC;AACrE,QAAI,iBAAiB,WAAW,KAAK,CAAC,aAAa,CAAC,UAAW,QAAO,CAAC;AACvE,UAAM,OAAO,aAAa,WAAW,SAAS;AAC9C,UAAM,SAAoC,CAAC;AAC3C,eAAW,OAAO,kBAAkB;AACnC,YAAM,WAAW,iBAAiB,IAAI,EAAE,IAAI,UAAU,CAAC;AACvD,YAAM,SAAS,MAAM,SAAS,EAAE,aAAa,IAAI,QAAQ;AACzD,UAAI,QAAQ;AACX,mBAAW,SAAS,aAAa,OAAO,MAA6B,IAAI,GAAG;AAC3E,iBAAO,KAAK,EAAE,GAAG,OAAO,OAAO,IAAI,GAAG,CAAC;AAAA,QACxC;AAAA,MACD;AAAA,IACD;AACA,WAAO;AAAA,EACR,GAAG,CAAC,kBAAkB,WAAW,WAAW,KAAK,CAAC;AAElD,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;;;ACpNA,SAAS,eAAAC,cAAa,YAAAC,iBAAgB;AAUtC,SAAS,qBAAgE;AACxE,MAAI,OAAO,WAAW,YAAa,QAAO,CAAC;AAC3C,QAAM,MAAM,OAAO,SAAS;AAC5B,MAAI,CAAC,IAAK,QAAO,CAAC;AAClB,SAAO,EAAE,MAAM,EAAE,KAAK,OAAO,SAAS,SAAS,OAAO,SAAS,SAAS,EAAE;AAC3E;AAeA,IAAM,kBAAkB;AACxB,IAAM,gBAAgB,KAAK,OAAO;AAU3B,IAAM,iBAAiB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,EAAE,KAAK,GAAG;AAEH,SAAS,YAAY,qBAAoC;AAC/D,QAAM,EAAE,QAAQ,IAAI,MAAM,IAAI,iBAAiB;AAG/C,QAAM,iBAAiB;AACvB,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAS,EAAE;AACnC,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAS,KAAK;AACtD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAA8B,CAAC,CAAC;AACtE,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAwB,IAAI;AAC9D,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAAwB,IAAI;AAE1E,QAAM,WAAWC;AAAA,IAChB,OAAO,UAAkB;AACxB,UAAI,CAAC,eAAgB;AAErB,YAAM,YAAY,kBAAkB,YAAY;AAChD,YAAM,QAAQ,MAAM,MAAM,GAAG,SAAS;AACtC,UAAI,MAAM,WAAW,EAAG;AAGxB,YAAM,UAA+B,MAAM,IAAI,CAAC,UAAU;AAAA,QACzD,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,QAC3D;AAAA,QACA,YAAY,KAAK,KAAK,WAAW,QAAQ,IAAI,IAAI,gBAAgB,IAAI,IAAI;AAAA,QACzE,aAAa;AAAA,QACb,OAAO;AAAA,QACP,MAAM;AAAA,MACP,EAAE;AAEF,qBAAe,CAAC,SAAS,CAAC,GAAG,MAAM,GAAG,OAAO,CAAC;AAG9C,iBAAW,QAAQ,SAAS;AAC3B,YAAI;AACH,cAAI,KAAK,KAAK,OAAO,eAAe;AACnC,kBAAM,IAAI,MAAM,EAAE,uBAAuB,CAAC;AAAA,UAC3C;AAGA,gBAAM,SAAS,MAAM,aAAa,KAAK,IAAI;AAM3C,gBAAM,kBAAkB,eAAe,WAAW,OAAO,IAAI,SAAY;AACzE,gBAAM,SAAS,MAAM,OAAO,OAAO,iBAAiB,OAAO;AAAA,YAC1D,GAAI,kBAAkB,EAAE,gBAAgB,gBAAgB,IAAI,CAAC;AAAA,YAC7D;AAAA,YACA,UAAU,KAAK,KAAK,QAAQ;AAAA,YAC5B,UAAU,KAAK,KAAK;AAAA,UACrB,CAAC;AAED;AAAA,YAAe,CAAC,SACf,KAAK;AAAA,cAAI,CAAC,MACT,EAAE,OAAO,KAAK,KAAK,EAAE,GAAG,GAAG,aAAa,OAAO,MAAM,OAAO,KAAK,IAAI;AAAA,YACtE;AAAA,UACD;AAAA,QACD,SAAS,KAAK;AACb,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD;AAAA,YAAe,CAAC,SACf,KAAK,IAAI,CAAC,MAAO,EAAE,OAAO,KAAK,KAAK,EAAE,GAAG,GAAG,aAAa,OAAO,OAAO,QAAQ,IAAI,CAAE;AAAA,UACtF;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAC,gBAAgB,YAAY,QAAQ,MAAM;AAAA,EAC5C;AAEA,QAAM,mBAAmBA,aAAY,CAAC,OAAe;AACpD,mBAAe,CAAC,SAAS;AACxB,YAAM,OAAO,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACzC,UAAI,MAAM,WAAY,KAAI,gBAAgB,KAAK,UAAU;AACzD,aAAO,KAAK,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAAA,IACtC,CAAC;AAAA,EACF,GAAG,CAAC,CAAC;AAUL,QAAM,SAASA;AAAA,IACd,OAAO,aAA0D;AAChE,YAAMC,kBAAiB,UAAU,kBAAkB;AACnD,YAAM,SAAS,UAAU,QAAQ;AACjC,YAAM,UAAU,OAAO,KAAK;AAC5B,YAAM,aAAa,YAAY,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAK;AAChF,YAAM,UAAU,QAAQ,SAAS;AACjC,YAAM,iBAAiB,WAAW,SAAS;AAE3C,UAAI,CAACA,mBAAkB,aAAc;AAOrC,UAAI,CAAC,SAAS;AACb,YAAI,gBAAgB;AACnB,uBAAa,EAAE,yBAAyB,CAAC;AACzC,qBAAW,MAAM,aAAa,IAAI,GAAG,GAAI;AAAA,QAC1C;AACA;AAAA,MACD;AAGA,YAAM,iBAAiB,YAAY,KAAK,CAAC,MAAM,EAAE,WAAW;AAC5D,UAAI,eAAgB;AAOpB,YAAM,eAAe,cAAc,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AACvF,YAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,YAAM,mBAAmB,MAAM,SAAS,EAAE,SAAS,MAAM;AACzD,YAAM,iBAA+B;AAAA,QACpC,IAAI;AAAA,QACJ,gBAAAA;AAAA,QACA,gBAAgB;AAAA,QAChB,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,MAAM,UAAU,UAAU;AAAA,QAC1B,OACC,WAAW,iBACP;AAAA,UACD,GAAI,UAAU,CAAC,EAAE,MAAM,QAAiB,MAAM,QAAQ,CAAC,IAAI,CAAC;AAAA,UAC5D,GAAG;AAAA,QACJ,IACC;AAAA,QACJ,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,QACX,UAAU;AAAA,QACV,WAAW;AAAA,MACZ;AAGA,YAAM,sBAAsB;AAC5B,YAAM,eAAe;AACrB,YAAM,SAAS,EAAE,WAAWA,iBAAgB,cAAc;AAU1D,YAAM,SAAS,EAAE,gBAAgBA,iBAAgB,IAAI;AACrD,cAAQ,EAAE;AACV,qBAAe,CAAC,CAAC;AACjB,SAAG,WAAWA,iBAAgB,KAAK;AACnC,sBAAgB,IAAI;AACpB,UAAI;AAOH,cAAM,qBAAqBA,gBAAe,WAAW,OAAO;AAK5D,cAAM,0BAA0BA,gBAAe,WAAW,MAAM;AAChE,YAAI,yBAAyB;AAC5B,gBAAM,aAAaA,gBAAe,MAAM,OAAO,MAAM;AACrD,gBAAM,SAAS,MAAM,OAAO,OAAO,yBAAyB,OAAO;AAAA,YAClE;AAAA,YACA,GAAI,UAAU,EAAE,MAAM,QAAQ,IAAI,CAAC;AAAA,UACpC,CAAC;AAID,gBAAM,SAAS,EAAE,oBAAoBA,iBAAgB,OAAO,cAAc;AAO1E,cAAI;AACH,kBAAM,WAAW,MAAM,OAAO,OAAO,YAAY,MAAM;AAAA,cACtD,gBAAgB,OAAO;AAAA,cACvB,OAAO;AAAA,YACR,CAAC;AACD,gBAAI,UAAU,OAAO;AACpB,oBAAM,SAAS,EAAE,YAAY,OAAO,gBAAgB,SAAS,KAAuB;AAAA,YACrF;AAAA,UACD,QAAQ;AAAA,UAGR;AAAA,QACD,WAAW,oBAAoB;AAC9B,gBAAM,SAAS,MAAM,OAAO,OAAO,mBAAmB,OAAO;AAAA,YAC5D,GAAI,UAAU,EAAE,MAAM,QAAQ,IAAI,CAAC;AAAA,YACnC,GAAI,iBAAiB,EAAE,OAAO,WAAW,IAAI,CAAC;AAAA;AAAA;AAAA,YAG9C,GAAG,mBAAmB;AAAA,UACvB,CAAC;AACD,gBAAM,OAAO,OAAO;AAIpB,gBAAM,SAAS,EAAE,oBAAoBA,iBAAgB,KAAK,EAAE;AAC5D,cAAI,OAAO,MAAM;AAChB,kBAAM,SAAS,EAAE,eAAe,KAAK,IAAI,cAAc,OAAO,IAAoB;AAAA,UACnF;AACA,cAAI,OAAO,cAAc;AACxB,+BAAmB,KAAK,EAAE;AAAA,UAC3B;AAAA,QACD,OAAO;AACN,gBAAM,SAAS,MAAM,OAAO,OAAO,YAAY,OAAO;AAAA,YACrD,gBAAAA;AAAA,YACA,GAAI,UAAU,EAAE,MAAM,QAAQ,IAAI,CAAC;AAAA,YACnC,GAAI,iBAAiB,EAAE,OAAO,WAAW,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,YAK9C,GAAG,mBAAmB;AAAA,UACvB,CAAC;AAKD,gBACE,SAAS,EACT,eAAeA,iBAAgB,cAAc,OAAO,IAAoB;AAAA,QAC3E;AAGA,mBAAW,KAAK,qBAAqB;AACpC,cAAI,EAAE,WAAY,KAAI,gBAAgB,EAAE,UAAU;AAAA,QACnD;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,8BAA8B,GAAG;AAE/C,cAAM,SAAS,EAAE,cAAcA,iBAAgB,YAAY;AAE3D,cAAM,SAAS,EAAE,gBAAgBA,iBAAgB,KAAK;AACtD,gBAAQ,YAAY;AACpB,uBAAe,mBAAmB;AAClC,qBAAa,eAAe,QAAQ,IAAI,UAAU,EAAE,mBAAmB,CAAC;AAExE,mBAAW,MAAM,aAAa,IAAI,GAAG,GAAI;AAAA,MAC1C,UAAE;AACD,wBAAgB,KAAK;AAAA,MACtB;AAAA,IACD;AAAA,IACA,CAAC,MAAM,aAAa,qBAAqB,cAAc,QAAQ,IAAI,KAAK;AAAA,EACzE;AAEA,QAAM,iBAAiBD,aAAY,MAAM,aAAa,IAAI,GAAG,CAAC,CAAC;AAE/D,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;AAIA,SAAS,aAAa,MAA6B;AAClD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACvC,UAAM,SAAS,IAAI,WAAW;AAC9B,WAAO,SAAS,MAAM;AAErB,YAAM,SAAS,OAAO;AACtB,YAAM,SAAS,OAAO,MAAM,GAAG,EAAE,CAAC;AAClC,UAAI,CAAC,OAAQ,QAAO,OAAO,IAAI,MAAM,uBAAuB,CAAC;AAC7D,cAAQ,MAAM;AAAA,IACf;AACA,WAAO,UAAU,MAAM,OAAO,IAAI,MAAM,qBAAqB,CAAC;AAC9D,WAAO,cAAc,IAAI;AAAA,EAC1B,CAAC;AACF;;;AChWA,SAAS,eAAAE,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAMlD,SAAS,mBAAmB;AAClC,QAAM,EAAE,QAAQ,MAAM,IAAI,iBAAiB;AAC3C,QAAM,gBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa;AAC3D,QAAM,wBAAwB,eAAe,CAAC,MAAM,EAAE,qBAAqB;AAC3E,QAAM,CAAC,YAAY,aAAa,IAAIC,UAAS,KAAK;AAElD,QAAM,YAAYC,QAAO,MAAM;AAC/B,QAAM,WAAWA,QAAO,KAAK;AAK7B,EAAAC,WAAU,MAAM;AACf,cAAU,UAAU;AACpB,aAAS,UAAU;AAAA,EACpB,CAAC;AAED,QAAM,SAASC,aAAY,OAAO,SAAiB;AAClD,kBAAc,IAAI;AAOlB,UAAM,qBAAqB,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AACvF,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,sBAAsB,cAAc,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC9F,UAAM,mBAAmB,SAAS,QAAQ,SAAS,EAAE,SAAS,MAAM;AAEpE,UAAM,gBAA8B;AAAA,MACnC,IAAI;AAAA,MACJ,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,MAChB,MAAM;AAAA,MACN,YAAY;AAAA,MACZ;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW;AAAA,MACX,WAAW;AAAA,MACX,UAAU;AAAA,MACV,WAAW;AAAA,IACZ;AAGA,UAAMC,SAAQ,SAAS,QAAQ,SAAS;AACxC,IAAAA,OAAM,gBAAgB;AAAA,MACrB,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,iBAAiB;AAAA,MACjB,eAAe;AAAA,MACf,uBAAuB;AAAA,MACvB,uBAAuB;AAAA,MACvB,wBAAwB;AAAA,MACxB,cAAc;AAAA,MACd,eAAe;AAAA,MACf,aAAa;AAAA,IACd,CAAC;AACD,IAAAA,OAAM,YAAY,oBAAoB,CAAC,aAAa,CAAC;AACrD,IAAAA,OAAM,sBAAsB,kBAAkB;AAE9C,QAAI;AACH,YAAM,SAAS,MAAM,UAAU,QAAQ,OAAO,mBAAmB,OAAO,EAAE,KAAK,CAAC;AAChF,YAAM,OAAO,OAAO;AAKpB,eAAS,QAAQ,SAAS,EAAE,oBAAoB,oBAAoB,KAAK,EAAE;AAC3E,UAAI,OAAO,MAAM;AAChB,iBAAS,QACP,SAAS,EACT,eAAe,KAAK,IAAI,qBAAqB,OAAO,IAAoB;AAAA,MAC3E;AAOA,UAAI,OAAO,aAAa;AACvB,cAAM,UAAU,OAAO;AACvB,cAAM,WAAW,SAAS,QAAQ,SAAS,EAAE,SAAS,IAAI,KAAK,EAAE,KAAK,CAAC;AACvE,cAAM,iBAAiB,SAAS,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ,EAAE;AACjE,iBAAS,QAAQ,SAAS,EAAE,YAAY,KAAK,IAAI,CAAC,SAAS,GAAG,cAAc,CAAC;AAAA,MAC9E;AACA,aAAO;AAAA,IACR,SAAS,KAAK;AAEb,eAAS,QAAQ,SAAS,EAAE,cAAc,oBAAoB,mBAAmB;AACjF,YAAM,QAAQ,SAAS,QACrB,SAAS,EACT,cAAc,OAAO,CAAC,MAAM,EAAE,OAAO,kBAAkB;AACzD,eAAS,QAAQ,SAAS,EAAE,eAAe,OAAO,sBAAsB,KAAK,CAAC;AAC9E,YAAM;AAAA,IACP,UAAE;AACD,oBAAc,KAAK;AAAA,IACpB;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,eAAe,QAAQ,YAAY,sBAAsB;AACnE;;;ACzFO,SAAS,oBAAoB;AACnC,QAAM,oBAAoB,eAAe,CAAC,MAAM;AAC/C,UAAM,KAAK,EAAE;AACb,WAAO,KAAK,EAAE,cAAc,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI;AAAA,EACxD,CAAC;AACD,QAAM,kBAAkB,eAAe,CAAC,MAAM,EAAE,aAAa,IAAI;AACjE,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,SAAS,IAAI;AAMzD,QAAM,aACL,mBAAmB,0BAA0B,UAAU,mBAAmB,wBACvE,oBACA;AAEJ,QAAM,YAAY,mBAAmB,gBAAgB,YAAY,yBAAyB;AAC1F,QAAM,aAAa,mBAAmB,iBAAiB,YAAY,0BAA0B;AAC7F,QAAM,cAAc,mBAAmB,eAAe;AAEtD,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA,cAAc,CAAC,CAAC;AAAA;AAAA,IAEhB;AAAA;AAAA,IAEA,YAAY,aAAa;AAAA,EAC1B;AACD;;;ACpDA,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;AAS7B,SAAS,UAAkB;AACjC,QAAM,CAAC,KAAK,MAAM,IAAIC,UAAS,MAAM,gBAAgB,CAAC;AAEtD,EAAAC,WAAU,MAAM;AAEf,WAAO,eAAe,MAAM;AAC3B,aAAO,gBAAgB,CAAC;AAAA,IACzB,CAAC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO;AACR;;;ACpBA,SAAS,eAAAC,cAAa,UAAAC,eAAc;AAc7B,SAAS,YAAY,gBAA+B;AAC1D,QAAM,EAAE,GAAG,IAAI,iBAAiB;AAChC,QAAM,WAAW;AAAA,IAAe,CAAC,MAChC,iBAAkB,EAAE,YAAY,IAAI,cAAc,KAAK,QAAS;AAAA,EACjE;AACA,QAAM,iBAAiB;AAAA,IAAe,CAAC,MACtC,iBAAkB,EAAE,aAAa,IAAI,cAAc,KAAK,QAAS;AAAA,EAClE;AACA,QAAM,cAAcC,QAA6C,IAAI;AACrE,QAAM,kBAAkBA,QAAO,KAAK;AAEpC,QAAM,YAAYC;AAAA,IACjB,CAAC,WAAoB;AACpB,UAAI,CAAC,eAAgB;AAGrB,UAAI,YAAY,QAAS,cAAa,YAAY,OAAO;AAEzD,UAAI,QAAQ;AAEX,YAAI,CAAC,gBAAgB,SAAS;AAC7B,0BAAgB,UAAU;AAC1B,aAAG,WAAW,gBAAgB,IAAI;AAAA,QACnC;AAEA,oBAAY,UAAU,WAAW,MAAM;AACtC,0BAAgB,UAAU;AAC1B,aAAG,WAAW,gBAAgB,KAAK;AAAA,QACpC,GAAG,GAAI;AAAA,MACR,OAAO;AAEN,YAAI,gBAAgB,SAAS;AAC5B,0BAAgB,UAAU;AAC1B,aAAG,WAAW,gBAAgB,KAAK;AAAA,QACpC;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAC,gBAAgB,EAAE;AAAA,EACpB;AAEA,SAAO,EAAE,UAAU,gBAAgB,UAAU;AAC9C;;;ACvDA,SAAS,eAAAC,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAKzD,IAAM,cAA8B,CAAC;AAK9B,SAAS,YAAY,gBAA+B;AAC1D,QAAM,EAAE,QAAQ,MAAM,IAAI,iBAAiB;AAC3C,QAAM,WAAW;AAAA,IAAe,CAAC,MAChC,iBAAiB,EAAE,SAAS,IAAI,cAAc,KAAK,cAAc;AAAA,EAClE;AACA,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAS,KAAK;AAChD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,YAAYC,QAA2B,MAAS;AAGtD,QAAM,YAAYA,QAAO,MAAM;AAC/B,QAAM,WAAWA,QAAO,KAAK;AAK7B,EAAAC,WAAU,MAAM;AACf,cAAU,UAAU;AACpB,aAAS,UAAU;AAAA,EACpB,CAAC;AAGD,EAAAA,WAAU,MAAM;AACf,QAAI,CAAC,eAAgB;AAKrB,QAAI,eAAe,WAAW,OAAO,EAAG;AAExC,QAAI,YAAY;AAQhB,UAAM,mBAAmB,SAAS,QAAQ,SAAS,EAAE,SAAS,IAAI,cAAc;AAChF,UAAM,UAAU,CAAC,CAAC,oBAAoB,iBAAiB,SAAS;AAChE,QAAI,SAAS;AACZ,eAAS,QAAQ,SAAS,EAAE,YAAY,cAAc;AACtD,gBAAU,QAAQ,OAAO,SACvB,OAAO,EAAE,eAAe,CAAC,EACzB,MAAM,MAAM;AAAA,MAAC,CAAC;AAChB,aAAO,MAAM;AACZ,oBAAY;AAAA,MACb;AAAA,IACD;AAEA,iBAAa,IAAI;AACjB,mBAAe,OAAO;AACrB,UAAI;AACH,cAAM,OAAO,MAAM,UAAU,QAAQ,OAAO,YAAY,MAAM;AAAA,UAC7D;AAAA,UACA,OAAO;AAAA,QACR,CAAC;AAED,YAAI,UAAW;AAGf,YAAI,KAAK,MAAM,SAAS,GAAG;AAC1B,mBAAS,QAAQ,SAAS,EAAE,YAAY,gBAAiB,KAAK,KAAuB;AAAA,QACtF;AACA,mBAAW,KAAK,OAAO;AACvB,kBAAU,UAAU,KAAK,cAAc;AAGvC,iBAAS,QAAQ,SAAS,EAAE,YAAY,cAAe;AACvD,kBAAU,QAAQ,OAAO,SAAS,OAAO,EAAE,eAAgC,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAC7F,SAAS,KAAK;AACb,gBAAQ,MAAM,iCAAiC,GAAG;AAAA,MACnD,UAAE;AACD,YAAI,CAAC,UAAW,cAAa,KAAK;AAAA,MACnC;AAAA,IACD;AAEA,SAAK;AACL,WAAO,MAAM;AACZ,kBAAY;AAAA,IACb;AAAA,EACD,GAAG,CAAC,cAAc,CAAC;AAEnB,QAAM,WAAWC,aAAY,YAAY;AACxC,QAAI,CAAC,kBAAkB,CAAC,WAAW,UAAW;AAE9C,iBAAa,IAAI;AACjB,QAAI;AACH,YAAM,OAAO,MAAM,UAAU,QAAQ,OAAO,YAAY,MAAM;AAAA,QAC7D;AAAA,QACA,QAAQ,UAAU;AAAA,QAClB,OAAO;AAAA,MACR,CAAC;AAED,YAAM,WAAW,SAAS,QAAQ,SAAS,EAAE,SAAS,IAAI,cAAc,KAAK,CAAC;AAC9E,eAAS,QAAQ,SAAS,EAAE,YAAY,gBAAgB,CAAC,GAAG,KAAK,OAAyB,GAAG,QAAQ,CAAC;AACtG,iBAAW,KAAK,OAAO;AACvB,gBAAU,UAAU,KAAK,cAAc;AAAA,IACxC,UAAE;AACD,mBAAa,KAAK;AAAA,IACnB;AAAA,EACD,GAAG,CAAC,gBAAgB,SAAS,SAAS,CAAC;AAEvC,SAAO,EAAE,OAAO,UAAU,WAAW,SAAS,SAAS;AACxD;;;ACxGO,SAAS,YAAY;AAC3B,QAAM,cAAc;AAAA,IAAe,CAAC,MACnC,EAAE,cAAc,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC;AAAA,EAC1D;AAEA,SAAO,EAAE,YAAY;AACtB;;;ACNO,SAAS,YAAY;AAC3B,QAAM,EAAE,OAAO,IAAI,iBAAiB;AACpC,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,OAAO;AAC/C,QAAM,eAAe,eAAe,CAAC,MAAM,EAAE,YAAY;AACzD,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,OAAO;AAC/C,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,OAAO;AAC/C,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AAEvD,iBAAe,SAAS,MAMrB;AACF,WAAO,OAAO,OAAO,SAAS,OAAO,IAAI;AAAA,EAC1C;AAEA,SAAO,EAAE,SAAS,cAAc,SAAS,SAAS,aAAa,SAAS;AACzE;;;AC7BA,SAAS,eAAAC,cAAa,UAAAC,SAAQ,YAAAC,iBAAgB;;;ACsB3C,gBAAAC,MAyBD,YAzBC;AAMI,SAAS,MAAM,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACzD,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,wCAAuC,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ;AAAA;AAAA,EAC5G;AAEF;AAqBO,SAAS,iBAAiB,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACpE,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,6EAA4E,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACxK;AAEF;AAqBO,SAAS,SAAS,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC5D,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,2RAA0R,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACtX;AAEF;AAGO,SAAS,cAAc,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACjE,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,sLAAqL,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ;AAAA;AAAA,EAC1P;AAEF;AAGO,SAAS,YAAY,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC/D,SACC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ;AAAA,wBAAAA,KAAC,UAAK,GAAE,YAAW,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA,QACtG,gBAAAA,KAAC,UAAK,GAAE,oBAAmB,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA;AAAA,EAC/G;AAEF;AAGO,SAAS,SAAS,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC5D,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,wqBAAuqB,QAAO,gBAAe,aAAY,KAAI,gBAAe,SAAQ;AAAA;AAAA,EAC7uB;AAEF;AAGO,SAAS,aAAa,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAChE,SACC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ;AAAA,wBAAAA,KAAC,UAAK,GAAE,sXAAqX,QAAO,gBAAe,aAAY,KAAI,gBAAe,SAAQ;AAAA,QAC1b,gBAAAA,KAAC,UAAK,GAAE,miBAAkiB,MAAK,gBAAe,QAAO,gBAAe,aAAY,QAAO,eAAc,UAAS;AAAA;AAAA;AAAA,EAC/nB;AAEF;AAqBO,SAAS,YAAY,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC/D,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,+bAA8b,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EAC1hB;AAEF;AAoBO,SAAS,SAAS,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC5D,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,2wBAA0wB,MAAK,gBAAe;AAAA;AAAA,EACvyB;AAEF;AAGO,SAAS,cAAc,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACjE,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,8fAA6f,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACzlB;AAEF;AAGO,SAAS,cAAc,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACjE,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,qUAAoU,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACha;AAEF;AAGO,SAAS,eAAe,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAClE,SACC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ;AAAA,wBAAAA,KAAC,UAAK,GAAE,qHAAoH,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA,QAC/M,gBAAAA,KAAC,UAAK,GAAE,gBAAe,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ;AAAA,QACnF,gBAAAA,KAAC,UAAK,GAAE,mGAAkG,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA;AAAA,EAC9L;AAEF;AAGO,SAAS,cAAc,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACjE,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,8OAA6O,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACzU;AAEF;AAGO,SAAS,SAAS,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC5D,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,0oBAAyoB,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACruB;AAEF;AAMO,SAAS,SAAS,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC5D,SACC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,eAAY;AAAA,MACX,GAAG;AAAA,MAEJ;AAAA,wBAAAA,KAAC,YAAO,IAAG,KAAI,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe;AAAA,QACnD,gBAAAA,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe;AAAA,QACpD,gBAAAA,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe;AAAA;AAAA;AAAA,EACrD;AAEF;;;AD/LM,gBAAAC,MA6BD,QAAAC,aA7BC;AApKN,IAAM,YAAY;AAClB,IAAM,sBAAsB;AAuBrB,SAAS,SAAS;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAkB;AACjB,QAAM,MAAMC,QAA4B,IAAI;AAC5C,QAAM,eAAeA,QAAyB,IAAI;AAIlD,QAAM,sBAAsBA;AAAA,IAC3B,OAAO,QAAQ,eAAe,IAAI,WAAW,gBAAgB,SAAS;AAAA,EACvE;AAEA,QAAM,gBAAgBC;AAAA,IACrB,CAAC,MAA2B;AAC3B,UAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,UAAU;AACrC,UAAE,eAAe;AACjB,iBAAS;AAAA,MACV;AAAA,IACD;AAAA,IACA,CAAC,QAAQ;AAAA,EACV;AAEA,QAAM,eAAeA;AAAA,IACpB,CAAC,MAA8C;AAC9C,YAAM,QAAQ,EAAE,OAAO;AACvB,UAAI,MAAM,SAAS,UAAW;AAC9B,mBAAa,KAAK;AAClB,iBAAW,MAAM,SAAS,CAAC;AAQ3B,UAAI,CAAC,oBAAoB,SAAS;AACjC,cAAM,KAAK,IAAI;AACf,YAAI,IAAI;AACP,aAAG,MAAM,SAAS;AAClB,aAAG,MAAM,SAAS,GAAG,KAAK,IAAI,GAAG,cAAc,GAAG,CAAC;AAAA,QACpD;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAC,cAAc,QAAQ;AAAA,EACxB;AAGA,QAAM,cAAcA;AAAA,IACnB,CAAC,MAA4B;AAC5B,UAAI,CAAC,WAAY;AACjB,YAAM,QAAQ,aAAa,EAAE,aAAa;AAC1C,UAAI,MAAM,SAAS,GAAG;AACrB,UAAE,eAAe;AACjB,mBAAW,KAAK;AAAA,MACjB;AAAA,IACD;AAAA,IACA,CAAC,UAAU;AAAA,EACZ;AAGA,QAAM,CAAC,YAAY,aAAa,IAAIC,UAAS,KAAK;AAClD,QAAM,eAAeF,QAAO,CAAC;AAE7B,QAAM,kBAAkBC,aAAY,CAAC,MAAuB;AAC3D,MAAE,eAAe;AACjB,iBAAa;AACb,QAAI,aAAa,YAAY,EAAG,eAAc,IAAI;AAAA,EACnD,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkBA,aAAY,CAAC,MAAuB;AAC3D,MAAE,eAAe;AACjB,iBAAa;AACb,QAAI,aAAa,YAAY,EAAG,eAAc,KAAK;AAAA,EACpD,GAAG,CAAC,CAAC;AAEL,QAAM,iBAAiBA,aAAY,CAAC,MAAuB;AAC1D,MAAE,eAAe;AACjB,MAAE,aAAa,aAAa;AAAA,EAC7B,GAAG,CAAC,CAAC;AAEL,QAAM,aAAaA;AAAA,IAClB,CAAC,MAAuB;AACvB,QAAE,eAAe;AACjB,mBAAa,UAAU;AACvB,oBAAc,KAAK;AACnB,UAAI,CAAC,WAAY;AACjB,YAAM,QAAQ,aAAa,EAAE,YAAY;AACzC,UAAI,MAAM,SAAS,EAAG,YAAW,KAAK;AAAA,IACvC;AAAA,IACA,CAAC,UAAU;AAAA,EACZ;AAGA,QAAM,kBAAkBA,aAAY,MAAM;AACzC,iBAAa,SAAS,MAAM;AAAA,EAC7B,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmBA;AAAA,IACxB,CAAC,MAA2C;AAC3C,UAAI,CAAC,cAAc,CAAC,EAAE,OAAO,MAAO;AACpC,iBAAW,MAAM,KAAK,EAAE,OAAO,KAAK,CAAC;AACrC,QAAE,OAAO,QAAQ;AAAA,IAClB;AAAA,IACA,CAAC,UAAU;AAAA,EACZ;AAEA,QAAM,UAAU,KAAK,KAAK,EAAE,SAAS;AACrC,QAAM,iBAAiB,eAAe,YAAY,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC7E,QAAM,iBAAiB,aAAa,KAAK,CAAC,MAAM,EAAE,WAAW,KAAK;AAMlE,QAAM,WAAW,WAAW,mBAAmB,CAAC;AAChD,QAAM,gBAAgB,KAAK,UAAU;AACrC,QAAM,cAAc,KAAK,SAAS;AAElC,SACC,gBAAAH;AAAA,IAAC;AAAA;AAAA,MACA,WAAW,eAAe,UAAU,yBAAyB,EAAE,IAAI,aAAa,0BAA0B,EAAE;AAAA,MAC5G,aAAa;AAAA,MACb,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,QAAQ;AAAA,MAER,0BAAAC,MAAC,SAAI,WAAU,mBAAkB,OAAO,EAAE,UAAU,WAAW,GAE7D;AAAA,sBACA,gBAAAD,KAAC,SAAI,WAAU,4BACd,0BAAAA,KAAC,UAAK,WAAU,yBAAyB,YAAE,mBAAmB,GAAE,GACjE;AAAA,QAGA,eAAe,YAAY,SAAS,KACpC,gBAAAA,KAAC,SAAI,WAAU,wBACb,sBAAY,IAAI,CAAC,MACjB,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAEA,YAAY;AAAA,YACZ,UAAU,qBAAqB,MAAM,mBAAmB,EAAE,EAAE,IAAI;AAAA;AAAA,UAF3D,EAAE;AAAA,QAGR,CACA,GACF;AAAA,QAGD,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACA;AAAA,YACA,WAAU;AAAA,YACV,OAAO;AAAA,YACP,UAAU;AAAA,YACV,WAAW;AAAA,YACX,SAAS;AAAA,YACT,aAAa,eAAe,EAAE,oBAAoB;AAAA,YAClD,MAAM;AAAA,YACN,UAAU,YAAY;AAAA,YACtB,cAAY,EAAE,mBAAmB;AAAA;AAAA,QAClC;AAAA,QACA,gBAAAC,MAAC,SAAI,WAAU,uBACd;AAAA,0BAAAA,MAAC,SAAI,WAAU,4BACd;AAAA,4BAAAD;AAAA,cAAC;AAAA;AAAA,gBACA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,SAAS;AAAA,gBACT,UAAU,YAAY;AAAA,gBACtB,cAAY,EAAE,oBAAoB;AAAA,gBAElC,0BAAAA,KAAC,iBAAc;AAAA;AAAA,YAChB;AAAA,YACA,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACA,KAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ;AAAA,gBACR,UAAQ;AAAA,gBACR,QAAM;AAAA,gBACN,UAAU;AAAA;AAAA,YACX;AAAA,YACC,iBACA,gBAAAA,KAAC,UAAK,WAAW,yBAAyB,cAAc,gCAAgC,EAAE,IACxF,sBAAY,KAAK,QACnB;AAAA,aAEF;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACA,MAAK;AAAA,cACL,WAAW,oBAAoB,WAAW,CAAC,eAAe,CAAC,WAAW,6BAA6B,4BAA4B;AAAA,cAC/H,SAAS,MAAM,SAAS;AAAA,cACxB,UAAU,YAAY,CAAC,WAAW,gBAAgB;AAAA,cAClD,cAAY,EAAE,kBAAkB;AAAA,cAEhC,0BAAAA,KAAC,YAAS;AAAA;AAAA,UACX;AAAA,WACD;AAAA,SACD;AAAA;AAAA,EACD;AAEF;AAYO,SAAS,aAAa,EAAE,YAAY,GAAG,SAAS,GAA6D;AACnH,SACC,gBAAAC,MAAC,SAAI,WAAW,uBAAuB,EAAE,QAAQ,+BAA+B,EAAE,IAChF;AAAA,MAAE,aACF,gBAAAD,KAAC,SAAI,KAAK,EAAE,YAAY,KAAK,EAAE,KAAK,MAAM,WAAU,2BAA0B,IAE9E,gBAAAA,KAAC,SAAI,WAAU,4BACd,0BAAAA,KAAC,UAAK,WAAU,2BACd,YAAE,KAAK,KAAK,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,KAAK,QACjD,GACD;AAAA,IAEA,EAAE,eAAe,gBAAAA,KAAC,SAAI,WAAU,8BAA6B;AAAA,IAC7D,EAAE,SAAS,gBAAAA,KAAC,SAAI,WAAU,6BAA4B,OAAO,EAAE,OAAO,eAAC;AAAA,IACvE,YACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS;AAAA,QACT,cAAY,EAAE,oBAAoB;AAAA,QAElC,0BAAAA,KAAC,SAAM;AAAA;AAAA,IACR;AAAA,KAEF;AAEF;AAIA,SAAS,aAAa,MAA4B;AACjD,QAAM,QAAgB,CAAC;AACvB,MAAI,KAAK,OAAO;AACf,aAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC3C,YAAM,OAAO,KAAK,MAAM,CAAC;AACzB,UAAI,KAAM,OAAM,KAAK,IAAI;AAAA,IAC1B;AAAA,EACD;AACA,SAAO;AACR;;;AE7RA,SAAS,aAAAK,YAAW,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,iBAAgB;AA4IjD,gBAAAC,MACA,QAAAC,aADA;AAjIJ,IAAM,aAAa;AAEnB,SAAS,iBAA0B;AAClC,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI,OAAO,OAAO,iBAAiB,eAAe,OAAO,aAAa,QAAQ,UAAU,MAAM,KAAK;AAClG,WAAO;AAAA,EACR;AACA,QAAM,SAAS,OAAO,UAAU,UAAU;AAC1C,SAAO,OAAO,SAAS,WAAW,KAAK,OAAO,SAAS,UAAU;AAClE;AAEA,SAAS,SAAS,MAA4B;AAC7C,MAAI,KAAK,UAAW,QAAO;AAC3B,MAAI,KAAK,UAAW,QAAO;AAC3B,MAAI,KAAK,OAAQ,QAAO;AACxB,SAAO,KAAK;AACb;AAEO,SAAS,qBAAqB;AACpC,QAAM,CAAC,SAAS,UAAU,IAAIC,UAAS,KAAK;AAC5C,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAS,IAAI;AACrC,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAAuB,CAAC,CAAC;AACrD,QAAM,YAAYC,QAAqB,CAAC,CAAC;AAKzC,QAAM,WAAW,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAC7D,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,QAAQ;AACpD,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AACvD,QAAM,kBAAkB,eAAe,CAAC,MAAM,EAAE,YAAY;AAC5D,QAAM,EAAE,MAAM,IAAI,iBAAiB;AAEnC,EAAAC,WAAU,MAAM;AACf,eAAW,eAAe,CAAC;AAAA,EAC5B,GAAG,CAAC,CAAC;AAEL,QAAM,YAAYC;AAAA,IACjB,MAAM,CAAC,OAAqC;AAC3C,YAAM,IAAgB;AAAA,QACrB,GAAG;AAAA,QACH,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,QAC3D,GAAG,KAAK,IAAI;AAAA,MACb;AACA,gBAAU,UAAU,CAAC,GAAG,GAAG,UAAU,OAAO,EAAE,MAAM,GAAG,UAAU;AACjE,gBAAU,UAAU,OAAO;AAAA,IAC5B;AAAA,IACA,CAAC;AAAA,EACF;AAIA,EAAAD,WAAU,MAAM;AACf,QAAI,CAAC,QAAS;AACd,QAAI,OAAO,WAAW,eAAe,OAAO,OAAO,UAAU,WAAY;AACzE,UAAM,gBAAgB,OAAO,MAAM,KAAK,MAAM;AAC9C,UAAM,WAAW,OAAO,OAA0B,SAAuB;AACxE,YAAM,MAAM,OAAO,UAAU,WAAW,QAAQ,iBAAiB,MAAM,MAAM,SAAS,IAAI,MAAM;AAChG,YAAM,SAAS,IAAI,SAAS,QAAQ;AACpC,UAAI,QAAQ;AACX,cAAM,SAAS,MAAM,WAAW,OAAO,UAAU,YAAY,EAAE,iBAAiB,OAAO,MAAM,SAAS;AACtG,cAAM,QAAQ,IAAI,MAAM,QAAQ,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AACvD,kBAAU,EAAE,MAAM,QAAQ,OAAO,UAAK,MAAM,IAAI,KAAK,IAAI,QAAQ,UAAU,MAAM,IAAI,EAAE,CAAC;AAAA,MACzF;AACA,UAAI;AACH,cAAM,MAAM,MAAM,cAAc,OAAO,IAAI;AAC3C,YAAI,QAAQ;AACX,gBAAM,QAAQ,IAAI,MAAM,QAAQ,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AACvD,oBAAU,EAAE,MAAM,QAAQ,OAAO,UAAK,IAAI,MAAM,IAAI,KAAK,GAAG,CAAC;AAAA,QAC9D;AACA,eAAO;AAAA,MACR,SAAS,KAAK;AACb,YAAI,QAAQ;AACX,gBAAM,QAAQ,IAAI,MAAM,QAAQ,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AACvD,oBAAU,EAAE,MAAM,SAAS,OAAO,UAAK,KAAK,IAAI,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE,CAAC;AAAA,QAC3G;AACA,cAAM;AAAA,MACP;AAAA,IACD;AACA,WAAO,QAAQ;AACf,WAAO,MAAM;AACZ,aAAO,QAAQ;AAAA,IAChB;AAAA,EACD,GAAG,CAAC,SAAS,SAAS,CAAC;AAGvB,EAAAA,WAAU,MAAM;AACf,QAAI,CAAC,QAAS;AACd,UAAM,WAAW,MAAM,SAAS,EAAE;AAClC,UAAM,SAAS;AAAA,MACd,qBAAqB,CAAC,OAAO;AAC5B,kBAAU,EAAE,MAAM,MAAM,OAAO,GAAG,MAAM,QAAQ,UAAU,EAAE,EAAE,CAAC;AAC/D,iBAAS,EAAE;AAAA,MACZ;AAAA,IACD,CAAC;AACD,WAAO,MAAM;AACZ,YAAM,SAAS,EAAE,qBAAqB,SAAS,CAAC;AAAA,IACjD;AAAA,EACD,GAAG,CAAC,SAAS,OAAO,SAAS,CAAC;AAG9B,QAAM,iBAAiB,WAAW,YAAY,IAAI,QAAQ,KAAK,CAAC,IAAI,CAAC;AACrE,QAAM,mBAAmBC;AAAA,IACxB,MAAM,eAAe,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE,IAAI,SAAS,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,KAAK,GAAG;AAAA,IACjF,CAAC,cAAc;AAAA,EAChB;AACA,QAAM,aAAaF,QAAO,gBAAgB;AAC1C,EAAAC,WAAU,MAAM;AACf,QAAI,CAAC,QAAS;AACd,QAAI,WAAW,YAAY,kBAAkB;AAC5C,iBAAW,UAAU;AACrB,gBAAU;AAAA,QACT,MAAM;AAAA,QACN,OAAO,YAAY,eAAe,MAAM;AAAA,QACxC,QAAQ,eACN,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,KAAK,EAAE,QAAQ,IAAI,MAAM,GAAG,EAAE,CAAC,EAAE,EAClE,KAAK,KAAK;AAAA,MACb,CAAC;AAAA,IACF;AAAA,EACD,GAAG,CAAC,kBAAkB,gBAAgB,SAAS,SAAS,CAAC;AAEzD,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,WAAW,WAAW,YAAY,IAAI,QAAQ,IAAI;AACxD,QAAM,OAAO,WAAW,gBAAgB,IAAI,QAAQ,IAAI;AAExD,SACC,gBAAAH,MAAC,SAAI,OAAO,OAAO,MAClB;AAAA,oBAAAA,MAAC,SAAI,OAAO,OAAO,QAClB;AAAA,sBAAAD,KAAC,YAAO,sBAAQ;AAAA,MAChB,gBAAAC,MAAC,UAAK,OAAO,OAAO,MAClB;AAAA;AAAA,QAAI;AAAA,QAAQ,WAAW,SAAS,MAAM,GAAG,EAAE,IAAI;AAAA,QAAI;AAAA,QAAU,eAAe;AAAA,QAAO;AAAA,QAAW,WAAW,MAAM;AAAA,QAAI;AAAA,QAAO,OAAO,MAAM;AAAA,SACzI;AAAA,MACA,gBAAAD,KAAC,YAAO,MAAK,UAAS,OAAO,OAAO,KAAK,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAI,iBAAO,SAAS,QAAO;AAAA,MACpG,gBAAAA,KAAC,YAAO,MAAK,UAAS,OAAO,OAAO,KAAK,SAAS,MAAM;AAAE,kBAAU,UAAU,CAAC;AAAG,kBAAU,CAAC,CAAC;AAAA,MAAG,GAAG,mBAAK;AAAA,OAC1G;AAAA,IACC,QACA,gBAAAC,MAAC,SAAI,OAAO,OAAO,MAClB;AAAA,sBAAAA,MAAC,SAAI,OAAO,OAAO,SAClB;AAAA,wBAAAD,KAAC,SAAI,OAAO,OAAO,cAAc,+BAAiB;AAAA,QACjD,eAAe,WAAW,IAC1B,gBAAAA,KAAC,SAAI,OAAO,OAAO,OAAO,mBAAK,IAE/B,eAAe,IAAI,CAAC,GAAG,MACtB,gBAAAC,MAAC,SAAe,OAAO,OAAO,KAC7B;AAAA,0BAAAD,KAAC,UAAK,OAAO,EAAE,GAAG,OAAO,OAAO,YAAY,SAAS,SAAS,CAAC,CAAC,EAAE,GAAI,aAAE;AAAA,UACxE,gBAAAA,KAAC,UAAK,OAAO,OAAO,QAAS,mBAAS,CAAC,GAAE;AAAA,UACzC,gBAAAA,KAAC,UAAK,OAAO,OAAO,IAAK,YAAE,UAAU,MAAM,IAAI,EAAE,GAAE;AAAA,UACnD,gBAAAA,KAAC,UAAK,OAAO,OAAO,MAAQ,aAAE,QAAQ,IAAI,MAAM,GAAG,EAAE,GAAE;AAAA,aAJ9C,EAAE,EAKZ,CACA;AAAA,SAEH;AAAA,MACA,gBAAAC,MAAC,SAAI,OAAO,OAAO,SAClB;AAAA,wBAAAD,KAAC,SAAI,OAAO,OAAO,cAAc,oBAAM;AAAA,QACtC,OAAO,WAAW,IAClB,gBAAAA,KAAC,SAAI,OAAO,OAAO,OAAO,iDAA8B,IAExD,OAAO,IAAI,CAAC,MACX,gBAAAC,MAAC,SAAe,OAAO,OAAO,KAC7B;AAAA,0BAAAD,KAAC,UAAK,OAAO,EAAE,GAAG,OAAO,OAAO,YAAY,UAAU,EAAE,IAAI,EAAE,GAAI,YAAE,MAAK;AAAA,UACzE,gBAAAA,KAAC,UAAK,OAAO,OAAO,IAAK,cAAI,KAAK,EAAE,CAAC,EAAE,YAAY,EAAE,MAAM,IAAI,EAAE,GAAE;AAAA,UACnE,gBAAAA,KAAC,UAAK,OAAO,OAAO,SAAU,YAAE,OAAM;AAAA,UACrC,EAAE,UAAU,gBAAAA,KAAC,UAAK,OAAO,OAAO,QAAS,YAAE,QAAO;AAAA,aAJ1C,EAAE,EAKZ,CACA;AAAA,SAEH;AAAA,OACD;AAAA,KAEF;AAEF;AAEA,SAAS,UAAU,GAAoB;AACtC,MAAI,MAAM,OAAW,QAAO;AAC5B,MAAI;AACH,UAAM,IAAI,KAAK,UAAU,CAAC;AAC1B,QAAI,CAAC,EAAG,QAAO;AACf,WAAO,EAAE,SAAS,MAAM,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,WAAM;AAAA,EACjD,QAAQ;AACP,WAAO,OAAO,CAAC;AAAA,EAChB;AACD;AAEA,SAAS,SAAS,QAAwB;AACzC,UAAQ,QAAQ;AAAA,IACf,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR;AACC,aAAO;AAAA,EACT;AACD;AAEA,SAAS,UAAU,MAAkC;AACpD,UAAQ,MAAM;AAAA,IACb,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,EACT;AACD;AAEA,IAAM,SAA8C;AAAA,EACnD,MAAM;AAAA,IACL,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,EAChB;AAAA,EACA,QAAQ;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,cAAc;AAAA,EACf;AAAA,EACA,MAAM,EAAE,MAAM,GAAG,OAAO,WAAW,UAAU,GAAG;AAAA,EAChD,KAAK;AAAA,IACJ,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,UAAU;AAAA,EACX;AAAA,EACA,MAAM,EAAE,SAAS,QAAQ,eAAe,UAAU,WAAW,qBAAqB,UAAU,OAAO;AAAA,EACnG,SAAS,EAAE,cAAc,qBAAqB,SAAS,WAAW;AAAA,EAClE,cAAc,EAAE,OAAO,WAAW,UAAU,IAAI,eAAe,aAAa,eAAe,KAAK,cAAc,EAAE;AAAA,EAChH,KAAK;AAAA,IACJ,SAAS;AAAA,IACT,qBAAqB;AAAA,IACrB,KAAK;AAAA,IACL,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,WAAW;AAAA,EACZ;AAAA,EACA,OAAO;AAAA,IACN,SAAS;AAAA,IACT,cAAc;AAAA,IACd,SAAS;AAAA,IACT,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,EACZ;AAAA,EACA,QAAQ,EAAE,OAAO,UAAU;AAAA,EAC3B,IAAI,EAAE,OAAO,WAAW,UAAU,GAAG;AAAA,EACrC,MAAM,EAAE,OAAO,WAAW,YAAY,UAAU,UAAU,UAAU,cAAc,WAAW;AAAA,EAC7F,SAAS,EAAE,OAAO,UAAU;AAAA,EAC5B,QAAQ,EAAE,YAAY,UAAU,OAAO,WAAW,UAAU,IAAI,YAAY,YAAY,WAAW,YAAY;AAAA,EAC/G,OAAO,EAAE,OAAO,WAAW,WAAW,UAAU,UAAU,GAAG;AAC9D;;;AC1RA,SAAS,eAAAM,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAwUnD,SAiGA,UA5FC,OAAAC,MALD,QAAAC,aAAA;AA7PN,SAAS,oBAAoB,aAAoD;AAChF,QAAM,CAAC,cAAc,eAAe,IAAIC,UAAwB,IAAI;AACpE,QAAM,aAAa,eAAe,CAAC,GAAG;AAAA,IAAI,CAAC,UAC1C,OAAO,UAAU,WAAW,QAAQ,MAAM;AAAA,EAC3C;AACA,QAAM,MAAM,UAAU,KAAK,GAAG;AAC9B,SAAO;AAAA,IACN,WAAW,iBAAiB,MAAM,CAAC,IAAI;AAAA,IACvC,SAAS,MAAM,gBAAgB,GAAG;AAAA,EACnC;AACD;AAyCA,SAAS,kBAA0C;AAClD,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,QAAQ;AAId,SAAO,MAAM,qBAAqB,MAAM,2BAA2B;AACpE;AAQA,SAAS,aAAa,QAAiC;AACtD,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAChD,QAAM,SAASC,QAA2B,IAAI;AAI9C,QAAM,YAAYA,QAAO,MAAM;AAC/B,EAAAC,WAAU,MAAM;AACf,cAAU,UAAU;AAAA,EACrB,GAAG,CAAC,MAAM,CAAC;AAIX,QAAM,CAAC,SAAS,IAAIF,UAAS,MAAM,gBAAgB,MAAM,IAAI;AAI7D,EAAAE;AAAA,IACC,MAAM,MAAM;AACX,aAAO,SAAS,KAAK;AACrB,aAAO,UAAU;AAAA,IAClB;AAAA,IACA,CAAC;AAAA,EACF;AAEA,QAAM,SAASC,aAAY,MAAM;AAChC,QAAI,OAAO,SAAS;AACnB,aAAO,QAAQ,KAAK;AACpB;AAAA,IACD;AACA,UAAM,OAAO,gBAAgB;AAC7B,QAAI,CAAC,KAAM;AACX,UAAM,MAAM,IAAI,KAAK;AACrB,QAAI,OAAO,OAAO,aAAa,cAAc,SAAS,gBAAgB,QAAQ,OAAO;AACrF,QAAI,aAAa;AACjB,QAAI,iBAAiB;AACrB,QAAI,WAAW,CAAC,UAAU;AACzB,eAAS,IAAI,MAAM,aAAa,IAAI,MAAM,QAAQ,QAAQ,KAAK;AAC9D,cAAM,SAAS,MAAM,QAAQ,CAAC;AAC9B,YAAI,CAAC,QAAQ,QAAS;AACtB,cAAM,OAAO,OAAO,CAAC,GAAG,YAAY,KAAK;AACzC,YAAI,KAAM,WAAU,QAAQ,IAAI;AAAA,MACjC;AAAA,IACD;AACA,UAAM,SAAS,MAAM;AACpB,aAAO,UAAU;AACjB,mBAAa,KAAK;AAAA,IACnB;AACA,QAAI,QAAQ;AACZ,QAAI,UAAU;AACd,WAAO,UAAU;AACjB,iBAAa,IAAI;AACjB,QAAI,MAAM;AAAA,EACX,GAAG,CAAC,CAAC;AAIL,QAAM,OAAOA,aAAY,MAAM;AAC9B,WAAO,SAAS,KAAK;AAAA,EACtB,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,WAAW,WAAW,QAAQ,KAAK;AAC7C;AAGA,IAAM,aAAa;AAEnB,IAAM,WAAW;AAGjB,SAAS,UAAU,MAAmC;AACrD,MAAI,CAAC,MAAM,MAAO,QAAO,CAAC;AAC1B,QAAM,MAAc,CAAC;AACrB,WAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC3C,UAAM,OAAO,KAAK,MAAM,CAAC;AACzB,QAAI,KAAM,KAAI,KAAK,IAAI;AAAA,EACxB;AACA,SAAO;AACR;AAEO,SAAS,UAAU;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAmB;AAClB,QAAM,CAAC,SAAS,UAAU,IAAIH,UAAS,KAAK;AAC5C,QAAM,WAAWC,QAA4B,IAAI;AACjD,QAAM,SAASA,QAAuB,IAAI;AAC1C,QAAM,eAAeA,QAAyB,IAAI;AAClD,QAAM,EAAE,WAAW,kBAAkB,SAAS,aAAa,IAAI,oBAAoB,WAAW;AAI9F,QAAM,YAAY,aAAa,CAAC,UAAU;AACzC,UAAM,UAAU,SAAS,SAAS,SAAS;AAC3C,aAAS,UAAU,GAAG,QAAQ,QAAQ,QAAQ,EAAE,CAAC,IAAI,KAAK,KAAK,KAAK;AACpE,aAAS,SAAS,MAAM;AAAA,EACzB,CAAC;AAKD,QAAM,OAAOE,aAAY,MAAM;AAC9B,UAAM,KAAK,SAAS;AACpB,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,MAAM,CAAC,IAAK;AACjB,OAAG,MAAM,SAAS;AAClB,UAAM,OAAO,KAAK,IAAI,YAAY,GAAG,YAAY;AACjD,OAAG,MAAM,SAAS,GAAG,IAAI;AACzB,QAAI,QAAQ,QAAQ,OAAO,WAAW,SAAS;AAAA,EAChD,GAAG,CAAC,CAAC;AAGL,EAAAD,WAAU,MAAM,CAAC,MAAM,KAAK,CAAC;AAE7B,QAAM,gBAAgBC;AAAA,IACrB,CAAC,UAAoD;AACpD,UAAI,MAAM,QAAQ,WAAW,MAAM,SAAU;AAC7C,YAAM,eAAe;AACrB,UAAI,CAAC,MAAM,KAAK,KAAK,SAAU;AAC/B,eAAS;AAAA,IACV;AAAA,IACA,CAAC,OAAO,UAAU,QAAQ;AAAA,EAC3B;AAIA,QAAM,cAAcA;AAAA,IACnB,CAAC,UAAqD;AACrD,UAAI,CAAC,WAAY;AACjB,YAAM,QAAQ,UAAU,MAAM,aAAa;AAC3C,UAAI,CAAC,MAAM,OAAQ;AACnB,YAAM,eAAe;AACrB,iBAAW,KAAK;AAAA,IACjB;AAAA,IACA,CAAC,UAAU;AAAA,EACZ;AASA,QAAM,kBAAkB,WAAW,CAAC,CAAC,iBAAiB,UAAU,CAAC,MAAM,KAAK;AAK5E,QAAM,aAAa,CAAC,UAA4C;AAC/D,UAAM,OAAO,MAAM;AACnB,QAAI,QAAQ,MAAM,cAAc,SAAS,IAAI,EAAG;AAChD,eAAW,KAAK;AAMhB,cAAU,KAAK;AAAA,EAChB;AAIA,QAAM,YAAY,aAAa,KAAK,CAAC,MAAM,EAAE,WAAW,KAAK;AAC7D,QAAM,gBAAgB,aAAa,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,KAAK;AACnE,QAAM,WAAW,CAAC,CAAC,MAAM,KAAK,KAAK,kBAAkB,CAAC,aAAa,CAAC;AAEpE,SACC,gBAAAJ,MAAC,SAAI,WAAU,WAAU,SAAS,MAAM,WAAW,IAAI,GAAG,QAAQ,YAChE;AAAA,uBACA,gBAAAD,KAAC,SAAI,WAAU,uBACb,2BAAiB,IAAI,CAAC,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,MAKhC,gBAAAC;AAAA,QAAC;AAAA;AAAA,UAEA,WAAU;AAAA,UACV,OAAO,EAAE,gBAAgB,GAAG,MAAM,QAAQ,EAAE,KAAK;AAAA,UAEjD;AAAA,4BAAAD;AAAA,cAAC;AAAA;AAAA,gBACA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,SAAS,MAAM,eAAe,QAAQ;AAAA,gBAErC;AAAA;AAAA,YACF;AAAA,YACC,UAAU,KACV,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,cAAY,EAAE,qBAAqB;AAAA,gBACnC,SAAS;AAAA,gBAET,0BAAAA;AAAA,kBAAC;AAAA;AAAA,oBACA,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,QAAO;AAAA,oBACP,aAAY;AAAA,oBACZ,eAAc;AAAA,oBACd,eAAY;AAAA,oBAEZ,0BAAAA,KAAC,UAAK,GAAE,wBAAuB;AAAA;AAAA,gBAChC;AAAA;AAAA,YACD;AAAA;AAAA;AAAA,QA5BI;AAAA,MA8BN;AAAA,KACA,GACF;AAAA,IAGA,aACA,gBAAAA,KAAC,SAAI,WAAU,iBAAgB,MAAK,SAClC,qBACF;AAAA,IAED,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACA,WAAU;AAAA,QACV,KAAK;AAAA,QACL,cAAW;AAAA,QACX,aAAa;AAAA,QACb,cAAc;AAAA,QAIb;AAAA,WAAC,CAAC,aAAa,UACf,gBAAAD,KAAC,SAAI,WAAU,oBACb,sBAAY,IAAI,CAAC,MACjB,gBAAAA;AAAA,YAAC;AAAA;AAAA,cAEA,YAAY;AAAA,cACZ,UAAU,qBAAqB,MAAM,mBAAmB,EAAE,EAAE,IAAI;AAAA;AAAA,YAF3D,EAAE;AAAA,UAGR,CACA,GACF;AAAA,UAQD,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACA,KAAK;AAAA,cACL,WAAU;AAAA,cACV,MAAM;AAAA,cACN;AAAA,cACA,aAAa,eAAe,EAAE,wBAAwB;AAAA,cACtD,cAAY,EAAE,wBAAwB;AAAA,cACtC,UAAU,CAAC,UAAU;AACpB,yBAAS,MAAM,OAAO,KAAK;AAC3B,oBAAI,UAAW,oBAAmB;AAClC,qBAAK;AAAA,cACN;AAAA,cACA,WAAW;AAAA,cACX,SAAS;AAAA;AAAA,UACV;AAAA,UACA,gBAAAC,MAAC,SAAI,WAAU,mBACb;AAAA,sBAAU,aACV,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,eAAa,UAAU,YAAY,SAAS;AAAA,gBAC5C,cAAY,EAAE,qBAAqB;AAAA,gBACnC,gBAAc,UAAU;AAAA,gBACxB;AAAA,gBACA,SAAS,UAAU;AAAA,gBAEnB,0BAAAA,KAAC,YAAS;AAAA;AAAA,YACX;AAAA,YAEA,cACA,gBAAAC,MAAA,YACC;AAAA,8BAAAD;AAAA,gBAAC;AAAA;AAAA,kBACA,MAAK;AAAA,kBACL,WAAU;AAAA,kBACV,cAAY,EAAE,oBAAoB;AAAA,kBAClC;AAAA,kBACA,SAAS,MAAM,aAAa,SAAS,MAAM;AAAA,kBAE3C,0BAAAA,KAAC,iBAAc,MAAM,IAAI;AAAA;AAAA,cAC1B;AAAA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACA,KAAK;AAAA,kBACL,MAAK;AAAA,kBACL,QAAQ;AAAA,kBACR,UAAQ;AAAA,kBACR,QAAM;AAAA,kBACN,UAAU,CAAC,UAAU;AACpB,wBAAI,CAAC,MAAM,OAAO,MAAO;AACzB,+BAAW,MAAM,KAAK,MAAM,OAAO,KAAK,CAAC;AAEzC,0BAAM,OAAO,QAAQ;AAAA,kBACtB;AAAA;AAAA,cACD;AAAA,eACD;AAAA,YAED,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,cAAY,EAAE,kBAAkB;AAAA,gBAChC,UAAU,CAAC;AAAA,gBACX,SAAS;AAAA,gBAET,0BAAAA,KAAC,eAAY,MAAM,IAAI;AAAA;AAAA,YACxB;AAAA,aACD;AAAA;AAAA;AAAA,IACD;AAAA,KACD;AAEF;AAIA,SAAS,WAAW;AACnB,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ;AAAA,wBAAAD,KAAC,UAAK,GAAE,8DAA6D;AAAA,QACrE,gBAAAA,KAAC,UAAK,GAAE,oCAAmC;AAAA,QAC3C,gBAAAA,KAAC,UAAK,GAAE,YAAW;AAAA;AAAA;AAAA,EACpB;AAEF;;;ACpeA,SAAS,eAAAM,eAAa,aAAAC,mBAAiB;;;ACAvC,SAAS,eAAAC,cAAa,aAAAC,YAAW,YAAAC,iBAAgB;AAsBjD,IAAMC,cAAiC,CAAC;AAIxC,SAAS,QAAQ,OAAe,MAAc;AAC7C,SAAO,QAAQ,KAAK,IAAI,IAAI;AAC7B;AAEA,SAAS,UAAU,OAAe,MAAc,MAAc;AAC7D,SAAO,QAAQ,KAAK,IAAI,IAAI,WAAW,IAAI;AAC5C;AASA,SAAS,UAAa,OAAmD,KAAuB;AAC/F,QAAM,QAAQ,MAAM,IAAI,GAAG;AAC3B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,KAAK,IAAI,IAAI,MAAM,KAAK,kBAAmB,QAAO;AACtD,SAAO,MAAM;AACd;AAMO,SAAS,cAAc,OAAe;AAC5C,QAAM,EAAE,QAAQ,MAAM,IAAI,iBAAiB;AAC3C,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,aAAa,WAAW,KAAKA;AACzE,QAAM,MAAM,YAAY,KAAK,CAACC,OAAMA,GAAE,OAAO,KAAK,KAAK;AAEvD,QAAM,OAAO,UAAU;AACvB,QAAM,QAAQ,MAAM,SAAS,EAAE;AAE/B,QAAM,CAAC,SAAS,UAAU,IAAIC;AAAA,IAC7B,MAAM,UAAsB,OAAO,QAAQ,OAAO,IAAI,CAAC,GAAG,SAAS,CAAC;AAAA,EACrE;AACA,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAAoC,IAAI;AACpE,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAChD,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAAS,KAAK;AAC5D,QAAM,CAAC,SAAS,UAAU,IAAIA;AAAA,IAC7B,MAAM,UAAsB,OAAO,QAAQ,OAAO,IAAI,CAAC,GAAG,WAAW;AAAA,EACtE;AACA,QAAM,CAAC,OAAO,QAAQ,IAAIA;AAAA,IACzB,MAAM,UAAsB,OAAO,QAAQ,OAAO,IAAI,CAAC,GAAG,SAAS;AAAA,EACpE;AACA,QAAM,CAAC,MAAM,OAAO,IAAIA;AAAA,IACvB,MAAM,UAAsB,OAAO,QAAQ,OAAO,IAAI,CAAC,GAAG,QAAQ;AAAA,EACnE;AAEA,QAAM,eAAeC;AAAA,IACpB,OAAO,SAA+D;AACrE,UAAI,CAAC,IAAK;AACV,YAAM,IAAI,MAAM,QAAQ;AACxB,YAAM,QAAQ,MAAM,SAAS,MAAM;AAEnC,mBAAa,IAAI;AACjB,UAAI;AACH,cAAM,SAAS,MAAM,OAAO,OAAO,WAAW,MAAM;AAAA,UACnD;AAAA,UACA,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ,MAAM;AAAA,UACd,UAAU,UAAU;AAAA,QACrB,CAAC;AAED,YAAI,OAAO,OAAO;AACjB,qBAAW,CAAC,SAAS;AACpB,kBAAM,YAAY,QAAQ,OAAO,QAAS,CAAC,GAAG,MAAM,GAAG,OAAO,KAAM;AACpE,gBAAI,CAAC,MAAM,QAAQ;AAClB,oBAAM,SAAS,EAAE,gBAAgB,QAAQ,OAAO,UAAU,CAAC,GAAG;AAAA,gBAC7D,OAAO;AAAA,gBACP,OAAO,OAAO;AAAA,gBACd,SAAS,OAAO;AAAA,gBAChB,MAAM;AAAA,cACP,CAAsB;AAAA,YACvB;AACA,mBAAO;AAAA,UACR,CAAC;AACD,qBAAW,OAAO,OAAO;AACzB,mBAAS,OAAO,KAAK;AACrB,kBAAQ,CAAC;AAAA,QACV;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,gCAAgC,GAAG;AAAA,MAClD,UAAE;AACD,qBAAa,KAAK;AAAA,MACnB;AAAA,IACD;AAAA,IACA,CAAC,QAAQ,OAAO,KAAK,KAAK;AAAA,EAC3B;AAEA,QAAM,WAAWA,aAAY,MAAM;AAClC,QAAI,CAAC,WAAW,UAAW;AAC3B,iBAAa,EAAE,MAAM,OAAO,EAAE,CAAC;AAAA,EAChC,GAAG,CAAC,cAAc,SAAS,WAAW,IAAI,CAAC;AAE3C,QAAM,cAAcA;AAAA,IACnB,OAAO,SAAiB;AACvB,UAAI,CAAC,IAAK;AAGV,YAAM,SAAS;AAAA,QACd,MAAM,SAAS,EAAE;AAAA,QACjB,UAAU,OAAO,UAAU,GAAG,IAAI;AAAA,MACnC;AACA,UAAI,QAAQ;AACX,kBAAU,MAAM;AAChB;AAAA,MACD;AAEA,yBAAmB,IAAI;AACvB,UAAI;AACH,cAAM,SAAS,MAAM,OAAO,OAAO,WAAW,MAAM;AAAA,UACnD;AAAA,UACA;AAAA,UACA,UAAU,UAAU;AAAA,QACrB,CAAC;AACD,YAAI,OAAO,OAAO;AACjB,gBAAM,QAAQ,OAAO;AACrB,oBAAU,KAAK;AACf,gBAAM,SAAS,EAAE;AAAA,YAChB,UAAU,OAAO,UAAU,GAAG,IAAI;AAAA,YAClC;AAAA,UACD;AAAA,QACD;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,iCAAiC,GAAG;AAAA,MACnD,UAAE;AACD,2BAAmB,KAAK;AAAA,MACzB;AAAA,IACD;AAAA,IACA,CAAC,QAAQ,OAAO,KAAK,KAAK;AAAA,EAC3B;AAEA,QAAM,cAAcA,aAAY,MAAM;AACrC,cAAU,IAAI;AAAA,EACf,GAAG,CAAC,CAAC;AAGL,EAAAC,WAAU,MAAM;AACf,QAAI,OAAO,QAAQ,WAAW,GAAG;AAChC,mBAAa,EAAE,MAAM,GAAG,OAAO,KAAK,CAAC;AAAA,IACtC;AAAA,EACD,GAAG,CAAC,GAAG,CAAC;AAER,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;;;AC3LA,SAAS,aAAAC,YAAW,UAAAC,eAAc;AAiShC,gBAAAC,YAAA;AA/RF,IAAM,YAAY;AAElB,IAAM,aAAa;AAEnB,SAAS,kBAAkB,MAAc,MAAuB;AAC/D,MAAI,KAAM,QAAO;AACjB,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,4DAA4D,KAAK,OAAO,EAAG,QAAO;AACtF,MAAI,sBAAsB,KAAK,OAAO,KAAK,2BAA2B,KAAK,OAAO,EAAG,QAAO;AAC5F,MAAI,wDAAwD,KAAK,OAAO,EAAG,QAAO;AAClF,MAAI,WAAW,KAAK,OAAO,EAAG,QAAO;AACrC,SAAO;AACR;AAEO,SAAS,qBAAqB,GAAU,MAAyB;AACvE,QAAM,SAAS,EAAE;AACjB,QAAM,MAAM,QAAQ,QAA2B,eAAe;AAC9D,MAAI,CAAC,OAAO,CAAC,KAAK,SAAS,GAAG,EAAG;AACjC,QAAM,QAAQ,IAAI,QAAQ,UAAU;AACpC,QAAM,OAAO,OAAO,cAAc,UAAU;AAC5C,QAAM,OAAO,MAAM,eAAe;AAClC,MAAI,CAAC,KAAM;AACX,OAAK,UAAU,WAAW,UAAU,IAAI,EAAE;AAAA,IACzC,MAAM,YAAY,GAAG;AAAA,IACrB,MAAM,YAAY,KAAK,IAAI;AAAA,EAC5B;AACD;AAYO,SAAS,eAAe,IAAoB;AAKlD,QAAM,aAAuB,CAAC;AAC9B,QAAM,uBAAuB,CAAC,MAAc,cAAkB,CAAC;AAC/D,QAAM,OAAO,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA,IAKf;AAAA,IACA,CAAC,QAAQ,MAA0B,SAAiB;AACnD,YAAM,UAAU,KAAK,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM;AACtF,YAAM,YAAY,kBAAkB,MAAM,IAAI;AAC9C,YAAM,YAAY,cAAc,SAAS,oBAAoB,SAAS,MAAM;AAM5E,YAAM,UAAU,QAAQ,QAAQ,OAAO,EAAE;AACzC,iBAAW;AAAA,QACV,gGAAgG,SAAS,0IAA0I,SAAS,GAAG,UAAU,8EAA8E,SAAS,IAAI,OAAO;AAAA,MAC5W;AAKA,aAAO;AAAA;AAAA,EAAO,qBAAqB,WAAW,SAAS,CAAC,CAAC;AAAA;AAAA;AAAA,IAC1D;AAAA,EACD;AAEA,MAAI,OAAO,KAET,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EAEpB,QAAQ,gBAAgB,aAAa,EACrC,QAAQ,eAAe,aAAa,EACpC,QAAQ,cAAc,aAAa,EAEnC,QAAQ,WAAW,QAAQ,EAE3B,QAAQ,sBAAsB,8BAA8B,EAE5D,QAAQ,kBAAkB,qBAAqB,EAE/C,QAAQ,cAAc,aAAa,EAEnC,QAAQ,cAAc,iBAAiB,EAEvC,QAAQ,6BAA6B,2BAA2B,EAEhE;AAAA,IACA;AAAA,IACA;AAAA,EACD,EAEC;AAAA,IACA;AAAA,IACA;AAAA,EACD,EAEC,QAAQ,iBAAiB,6BAA6B,EAEtD,QAAQ,iBAAiB,aAAa,EAGtC,QAAQ,kBAAkB,eAAe;AAM3C,QAAM,SAAmB,CAAC;AAC1B,QAAM,mBAAmB,CAAC,MAAc,UAAc,CAAC;AACvD,SAAO,KAAK;AAAA;AAAA,IAEX;AAAA,IACA,CAAC,QAAQ,YAAoB,cAAsB;AAClD,YAAM,QAAQ,CAAC,SACd,KAAK,KAAK,EAAE,QAAQ,YAAY,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AACnE,YAAM,OAAO,MAAM,UAAU,EAC3B,IAAI,CAAC,MAAM,OAAO,CAAC,OAAO,EAC1B,KAAK,EAAE;AACT,YAAM,OAAO,UACX,KAAK,EACL,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,OAAO,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,OAAO,EAC5E,KAAK,EAAE;AACT,aAAO;AAAA,QACN,iEAAiE,IAAI,uBAAuB,IAAI;AAAA,MACjG;AACA,aAAO;AAAA;AAAA,EAAO,iBAAiB,OAAO,SAAS,CAAC,CAAC;AAAA;AAAA;AAAA,IAClD;AAAA,EACD;AAKA,SAAO,KACL,QAAQ,2BAA2B,CAAC,MAAM,OAAO,EAAE,QAAQ,OAAO,EAAE,CAAC;AAAA,CAAS,EAC9E;AAAA,IACA;AAAA,IACA,CAAC,MAAM,OAAO,EAAE,QAAQ,OAAO,EAAE,EAAE,QAAQ,eAAe,QAAQ,CAAC;AAAA;AAAA,EACpE;AAED,SAAO,KAEL,QAAQ,SAAS,SAAS,EAE1B,QAAQ,OAAO,QAAQ;AAKzB,SAAO,KACL,QAAQ,4BAA4B,IAAI,EACxC,QAAQ,8BAA8B,IAAI,EAC1C,QAAQ,eAAe,KAAK;AAG9B,MACC,CAAC,KAAK,WAAW,IAAI,KACrB,CAAC,KAAK,WAAW,KAAK,KACtB,CAAC,KAAK,WAAW,KAAK,KACtB,CAAC,KAAK,WAAW,aAAa,KAC9B,CAAC,KAAK,WAAW,KAAK,GACrB;AACD,WAAO,MAAM,IAAI;AAAA,EAClB;AAGA,MAAI,OAAO,SAAS,GAAG;AAEtB,WAAO,KAAK,QAAQ,2BAA2B,CAAC,IAAI,QAAgB;AACnE,YAAM,IAAI,OAAO,SAAS,KAAK,EAAE;AACjC,aAAO,OAAO,CAAC,KAAK;AAAA,IACrB,CAAC;AAGD,WAAO,KAAK,QAAQ,8DAA8D,IAAI;AAAA,EACvF;AAIA,SAAO,KAAK,QAAQ,qDAAqD,IAAI;AAK7E,MAAI,WAAW,SAAS,GAAG;AAE1B,WAAO,KAAK,QAAQ,+BAA+B,CAAC,IAAI,QAAgB;AACvE,YAAM,IAAI,OAAO,SAAS,KAAK,EAAE;AACjC,aAAO,WAAW,CAAC,KAAK;AAAA,IACzB,CAAC;AAID,WAAO,KAAK,QAAQ,wDAAwD,IAAI;AAAA,EACjF;AAEA,SAAO;AACR;AAOO,SAAS,YAAY,MAAsB;AACjD,SAAO,KACL,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB;AAAA,IACA;AAAA,IACA;AAAA,EACD,EACC,QAAQ,OAAO,QAAQ;AAC1B;AAOO,SAAS,gBAAgB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACD,GAIG;AACF,QAAM,UAAUD,QAAuB,IAAI;AAC3C,QAAM,OAAO,aAAa,eAAe,eAAe,YAAY,IAAI;AAOxE,EAAAD,WAAU,MAAM;AACf,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AAEX,UAAM,mBAAmB,CAAC,OAAyB;AAElD,YAAM,gBAAgB,MAAM,KAAK,GAAG,QAAQ,EAAE;AAAA,QAC7C,CAAC,MAAM,EAAE,YAAY;AAAA,MACtB;AACA,UAAI,cAAe,QAAO;AAC1B,YAAM,OAAO,GAAG,eAAe;AAC/B,aAAO,KAAK,QAAQ,UAAU,EAAE,MAAM;AAAA,IACvC;AAEA,UAAM,gBAAgB,MAAM;AAC3B,YAAM,aAAa,KAAK,iBAAiB,QAAQ;AACjD,iBAAW,QAAQ,CAAC,OAAO;AAC1B,YAAI,iBAAiB,EAAE,EAAG,IAAG,OAAO;AAAA,MACrC,CAAC;AAAA,IACF;AACA,kBAAc;AAAA,EACf,GAAG,CAAC,IAAI,CAAC;AAKT,EAAAA,WAAU,MAAM;AACf,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AACX,UAAM,UAAU,CAAC,MAAa;AAC7B,2BAAqB,GAAG,IAAI;AAAA,IAC7B;AACA,SAAK,iBAAiB,SAAS,OAAO;AACtC,WAAO,MAAM;AACZ,WAAK,oBAAoB,SAAS,OAAO;AAAA,IAC1C;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,MAAI,CAAC,KAAM,QAAO;AAElB,SACC,gBAAAE;AAAA,IAAC;AAAA;AAAA,MACA,KAAK;AAAA,MACL,WAAW,eAAe,aAAa,EAAE;AAAA,MAIzC,yBAAyB,EAAE,QAAQ,KAAK;AAAA;AAAA,EACzC;AAEF;AAEA,SAAS,YAAY,KAAwB,SAAS,OAAO;AAC5D,QAAM,QAAQ,IAAI,cAAc,qBAAqB;AACrD,MAAI,CAAC,MAAO;AACZ,QAAM,WAAW,MAAM,eAAe;AACtC,QAAM,cAAc,SAAS,WAAW;AACxC,MAAI,UAAU,IAAI,SAAS,yBAAyB,sBAAsB;AAC1E,aAAW,MAAM;AAChB,UAAM,cAAc;AACpB,QAAI,UAAU,OAAO,wBAAwB,sBAAsB;AAAA,EACpE,GAAG,IAAI;AACR;AAQO,SAAS,sBAAsB,SAAyB;AAC9D,MAAI,MAAM;AACV,QAAM,UAAU,IAAI,MAAM,MAAM,KAAK,CAAC,GAAG;AACzC,MAAI,SAAS,MAAM,EAAG,QAAO;AAG7B,QAAM,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,GAAG;AACxC,MAAI,OAAO,MAAM,EAAG,QAAO;AAC3B,SAAO;AACR;;;AC3TS,SAkGP,YAAAC,WAlGO,OAAAC,MAUJ,QAAAC,aAVI;AARF,SAAS,kBAAkB;AAAA,EACjC;AAAA,EACA;AACD,GAGG;AACF,MAAI,aAAa,CAAC,OAAO;AACxB,WAAO,gBAAAD,KAAC,mBAAgB;AAAA,EACzB;AAEA,QAAM,QAAQ,MAAM,aAAa,WAAW,MAAM,aAAa,YAAY,MAAM,aAAa,QAAQ;AAEtG,SACC,gBAAAC,MAAC,SAAI,WAAU,qBACd;AAAA,oBAAAA,MAAC,SAAI,WAAU,4BACd;AAAA,sBAAAD,KAAC,QAAG,WAAU,2BAA2B,gBAAM,OAAM;AAAA,OACnD,SAAS,MAAM,gBAChB,gBAAAC,MAAC,SAAI,WAAU,0BACb;AAAA,iBAAS,gBAAAD,KAAC,UAAK,WAAU,0BAA0B,iBAAM;AAAA,QACzD,MAAM,eACN,gBAAAA,KAAC,UAAK,WAAU,0BACd,6BAAmB,MAAM,WAAW,GACtC;AAAA,SAEF;AAAA,OAEF;AAAA,KACE,MAAM,QAAQ,MAAM,aACrB,gBAAAA,KAAC,SAAI,WAAU,0BACd,0BAAAA,KAAC,mBAAgB,UAAU,MAAM,UAAU,cAAc,MAAM,MAAM,GACtE;AAAA,KAEF;AAEF;AAkBA,SAAS,kBAAkB;AAC1B,QAAM,WAA2E;AAAA,IAChF;AAAA,MACC,aAAa;AAAA,MACb,OAAO;AAAA,QACN,EAAE,IAAI,OAAO,IAAI,MAAM;AAAA,QACvB,EAAE,IAAI,OAAO,IAAI,MAAM;AAAA,QACvB,EAAE,IAAI,OAAO,IAAI,MAAM;AAAA,MACxB;AAAA,IACD;AAAA,IACA;AAAA,MACC,aAAa;AAAA,MACb,OAAO;AAAA,QACN,EAAE,IAAI,OAAO,IAAI,MAAM;AAAA,QACvB,EAAE,IAAI,OAAO,IAAI,MAAM;AAAA,MACxB;AAAA,IACD;AAAA,EACD;AAEA,SACC,gBAAAC,MAAC,SAAI,WAAU,qBACd;AAAA,oBAAAA,MAAC,SAAI,WAAU,4BACd;AAAA,sBAAAD,KAAC,QAAG,WAAU,2BACb,0BAAAA,KAAC,UAAK,WAAU,iCAAgC,GACjD;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,0BACd;AAAA,wBAAAD,KAAC,UAAK,WAAU,iCAAgC;AAAA,QAChD,gBAAAA,KAAC,UAAK,WAAU,gCAA+B;AAAA,SAChD;AAAA,OACD;AAAA,IACA,gBAAAA,KAAC,SAAI,WAAU,0BACd,0BAAAA,KAAC,SAAI,WAAU,eACb,mBAAS,IAAI,CAAC,GAAG,MACjB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEA,aAAa,EAAE;AAAA,QACf,OAAO,EAAE;AAAA;AAAA,MAFJ;AAAA,IAGN,CACA,GACF,GACD;AAAA,KACD;AAEF;AAEA,SAAS,gBAAgB;AAAA,EACxB;AAAA,EACA;AACD,GAGG;AACF,SACC,gBAAAC,MAAAF,WAAA,EACC;AAAA,oBAAAC,KAAC,QACA,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACA,WAAU;AAAA,QACV,OAAO,EAAE,SAAS,SAAS,OAAO,YAAY;AAAA;AAAA,IAC/C,GACD;AAAA,IACC,MAAM,IAAI,CAAC,MAAM,MACjB,gBAAAA,KAAC,QACA,0BAAAA,KAAC,QACA,0BAAAC,MAAC,SAAI,WAAU,4BACd;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACA,WAAU;AAAA,UACV,OAAO,EAAE,SAAS,SAAS,OAAO,KAAK,GAAG;AAAA;AAAA,MAC3C;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACA,WAAU;AAAA,UACV,OAAO,EAAE,SAAS,SAAS,OAAO,KAAK,IAAI,WAAW,EAAE;AAAA;AAAA,MACzD;AAAA,OACD,GACD,KAZQ,CAaT,CACA;AAAA,KACF;AAEF;;;ACrIA,SAAS,eAAAE,eAAa,UAAAC,UAAQ,YAAAC,kBAAgB;AA+CxC,SACC,OAAAC,MADD,QAAAC,aAAA;AAxCC,SAAS,gBAAgB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GASG;AACF,QAAM,CAAC,YAAY,aAAa,IAAIF,WAAS,EAAE;AAC/C,QAAM,cAAcD,SAAsC,MAAS;AAEnE,QAAM,eAAeD;AAAA,IACpB,CAAC,UAAkB;AAClB,oBAAc,KAAK;AACnB,UAAI,CAAC,SAAU;AACf,mBAAa,YAAY,OAAO;AAChC,kBAAY,UAAU,WAAW,MAAM;AACtC,iBAAS,MAAM,KAAK,CAAC;AAAA,MACtB,GAAG,GAAG;AAAA,IACP;AAAA,IACA,CAAC,QAAQ;AAAA,EACV;AAEA,SACC,gBAAAI,MAAC,SAAI,WAAU,mBAEb;AAAA,gBACA,gBAAAD,KAAC,SAAI,WAAU,qBACd,0BAAAC,MAAC,SAAI,WAAU,yBACd;AAAA,sBAAAA,MAAC,SAAI,WAAU,0BAAyB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAClJ;AAAA,wBAAAD,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,QAC9B,gBAAAA,KAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,SAAQ;AAAA,SAC7C;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,aAAa,qBAAqB,EAAE,eAAe;AAAA,UACnD,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAK;AAAA;AAAA,MAC7C;AAAA,OACD,GACD;AAAA,IAIA,aAAa,QAAQ,WAAW,KAChC,gBAAAA,KAAC,SAAI,WAAU,uBACb,WAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACf,gBAAAC,MAAC,SAAY,WAAU,4BACtB;AAAA,sBAAAD,KAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,OAAO,QAAQ,GAAG,GAAG;AAAA,MACnF,gBAAAA,KAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,OAAO,QAAQ,GAAG,GAAG;AAAA,MACnF,gBAAAA,KAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,OAAO,QAAQ,GAAG,GAAG;AAAA,SAH1E,CAIV,CACA,GACF;AAAA,IAIA,CAAC,aAAa,QAAQ,WAAW,KACjC,gBAAAC,MAAC,SAAI,WAAU,oBACd;AAAA,sBAAAD,KAAC,SAAI,WAAU,0BACb,uBAAa,EAAE,mBAAmB,IAAI,EAAE,oBAAoB,GAC9D;AAAA,MACA,gBAAAA,KAAC,SAAI,WAAU,yBACb,uBAAa,EAAE,sBAAsB,IAAI,EAAE,mBAAmB,GAChE;AAAA,OACD;AAAA,IAIA,QAAQ,SAAS,KACjB,gBAAAC,MAAC,SAAI,WAAU,sBACb;AAAA,cAAQ,IAAI,CAAC,UACb,gBAAAD,KAAC,oBAAkC,OAAc,UAAoB,WAA9C,MAAM,IAA0D,CACvF;AAAA,MACA,WACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS;AAAA,UACT,UAAU;AAAA,UAET,sBAAY,EAAE,gBAAgB,IAAI,EAAE,kBAAkB;AAAA;AAAA,MACxD;AAAA,OAEF;AAAA,KAEF;AAEF;AAIA,SAAS,aAAa,MAAqB,SAAS,IAAY;AAC/D,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,QAAQ,KAAK,QAAQ,oBAAoB,EAAE,EAAE,KAAK;AACxD,SAAO,MAAM,SAAS,SAAS,GAAG,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ;AACjE;AAEA,SAAS,iBAAiB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACD,GAIG;AACF,QAAM,EAAE,aAAa,IAAI;AAGzB,QAAM,QAAQ,SAAS,aACpB,aAAa,QAAQ,UAAU,KAAK,OACpC,aAAa,WAAW,aAAa,YAAY,aAAa,QAAQ;AAEzE,QAAM,gBAAgB,SAAS,iBAC3B,QAAQ,kBAAkB,SAAS,MAAM,OAAO,aAAa,QAAQ,aAAa,MAAM,OACzF,aAAa,WAAW,aAAa,WAAW,aAAa,eAAe;AAE/E,QAAM,UAAU,gBAAgB,aAAa,aAAa,IAAI,aAAa,MAAM,IAAI;AAErF,SACC,gBAAAA,KAAC,YAAO,MAAK,UAAS,WAAU,oBAAmB,SAAS,MAAM,SAAS,MAAM,IAAI,GACpF,0BAAAC,MAAC,SAAI,WAAU,yBACd;AAAA,oBAAAA,MAAC,SAAI,WAAU,yBACd;AAAA,sBAAAD,KAAC,UAAK,WAAU,0BAA0B,gBAAM,OAAM;AAAA,MACrD,WACA,gBAAAA,KAAC,UAAK,WAAU,yBAAyB,mBAAQ;AAAA,OAEhD,SAAS,MAAM,gBAChB,gBAAAC,MAAC,SAAI,WAAU,yBACb;AAAA,iBAAS,gBAAAD,KAAC,UAAK,WAAU,0BAA0B,iBAAM;AAAA,QACzD,MAAM,eACN,gBAAAA,KAAC,UAAK,WAAU,yBAAyB,6BAAmB,MAAM,WAAW,GAAE;AAAA,SAEjF;AAAA,OAEF;AAAA,IACA,gBAAAA,KAAC,SAAI,WAAU,4BAA2B,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACpJ,0BAAAA,KAAC,cAAS,QAAO,kBAAiB,GACnC;AAAA,KACD,GACD;AAEF;;;AClKA,SAAS,aAAAE,aAAW,UAAAC,gBAAc;;;ACAlC,SAAS,eAAAC,eAAa,UAAAC,UAAQ,YAAAC,kBAAgB;AAI9C,IAAMC,cAAiC,CAAC;AAIxC,SAAS,cAAc,OAAe,MAAc;AACnD,SAAO,WAAW,KAAK,IAAI,IAAI;AAChC;AAEA,SAAS,SAAS,OAAe,MAAc,WAAmB;AACjE,SAAO,WAAW,KAAK,IAAI,IAAI,UAAU,SAAS;AACnD;AAEA,SAASC,WAAU,OAAe,MAAc,MAAc;AAC7D,SAAO,WAAW,KAAK,IAAI,IAAI,WAAW,IAAI;AAC/C;AAQA,SAASC,WAAa,OAAmD,KAAuB;AAC/F,QAAM,QAAQ,MAAM,IAAI,GAAG;AAC3B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,KAAK,IAAI,IAAI,MAAM,KAAK,kBAAmB,QAAO;AACtD,SAAO,MAAM;AACd;AAMO,SAAS,qBAAqB,OAAe;AACnD,QAAM,EAAE,QAAQ,MAAM,IAAI,iBAAiB;AAC3C,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,aAAa,WAAW,KAAKF;AACzE,QAAM,MAAM,YAAY,KAAK,CAACG,OAAMA,GAAE,OAAO,KAAK,KAAK;AAEvD,QAAM,OAAO,UAAU;AACvB,QAAM,QAAQ,MAAM,SAAS,EAAE;AAG/B,QAAM,mBAAmBD,WAA8B,OAAO,cAAc,OAAO,IAAI,CAAC;AACxF,QAAM,CAAC,YAAY,aAAa,IAAIE,WAA6B,oBAAoB,CAAC,CAAC;AACvF,QAAM,CAAC,qBAAqB,sBAAsB,IAAIA,WAAS,KAAK;AAGpE,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAA6B,CAAC,CAAC;AACzD,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,WAAS,KAAK;AAC1D,QAAM,CAAC,cAAc,eAAe,IAAIA,WAAS,KAAK;AACtD,QAAM,eAAeC,SAAO,CAAC;AAG7B,QAAM,CAAC,QAAQ,SAAS,IAAID,WAAoC,IAAI;AACpE,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,WAAS,KAAK;AAG5D,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,WAAkC,IAAI;AAGlF,QAAM,mBAAmBC,SAA2B,oBAAoB,CAAC,CAAC;AAG1E,QAAM,kBAAkBC,cAAY,YAAY;AAC/C,QAAI,CAAC,IAAK;AACV,2BAAuB,IAAI;AAC3B,QAAI;AACH,YAAM,SAAS,MAAM,OAAO,OAAO,WAAW,MAAM;AAAA,QACnD;AAAA,QACA,MAAM;AAAA,QACN,OAAO;AAAA,QACP,UAAU,UAAU;AAAA,MACrB,CAAC;AACD,UAAI,OAAO,OAAO;AACjB,yBAAiB,UAAU,OAAO;AAClC,sBAAc,OAAO,KAAK;AAC1B,cAAM,SAAS,EAAE,gBAAgB,cAAc,OAAO,UAAU,CAAC,GAAG,OAAO,KAAK;AAAA,MACjF;AAAA,IACD,SAAS,KAAK;AACb,cAAQ,MAAM,4CAA4C,GAAG;AAAA,IAC9D,UAAE;AACD,6BAAuB,KAAK;AAAA,IAC7B;AAAA,EACD,GAAG,CAAC,QAAQ,OAAO,KAAK,KAAK,CAAC;AAG9B,QAAM,YAAYA,cAAY,MAAM;AACnC,QAAI,OAAO,WAAW,WAAW,GAAG;AACnC,sBAAgB;AAAA,IACjB;AAAA,EACD,GAAG,CAAC,iBAAiB,KAAK,WAAW,MAAM,CAAC;AAG5C,QAAM,aAAaA;AAAA,IAClB,OAAO,SAAmF;AACzF,UAAI,CAAC,KAAK,eAAgB;AAC1B,YAAM,IAAI,MAAM,QAAQ;AACxB,YAAM,QAAQ,MAAM,SAAS,MAAM;AAEnC,wBAAkB,IAAI;AACtB,UAAI;AACH,cAAM,SAAS,MAAM,OAAO,OAAO,WAAW,MAAM;AAAA,UACnD;AAAA,UACA,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ,MAAM;AAAA,UACd,WAAW,MAAM;AAAA,UACjB,YAAY,IAAI;AAAA,UAChB,UAAU,UAAU;AAAA,QACrB,CAAC;AACD,YAAI,OAAO,OAAO;AACjB,mBAAS,CAAC,SAAS;AAClB,kBAAM,YAAY,QAAQ,OAAO,QAAS,CAAC,GAAG,MAAM,GAAG,OAAO,KAAM;AACpE,gBAAI,CAAC,MAAM,UAAU,MAAM,WAAW;AACrC,oBAAM,SAAS,EAAE;AAAA,gBAChB,SAAS,OAAO,UAAU,GAAG,KAAK,SAAS;AAAA,gBAC3C,EAAE,OAAO,WAAW,SAAS,OAAO,SAAS,MAAM,EAAE;AAAA,cACtD;AAAA,YACD;AACA,mBAAO;AAAA,UACR,CAAC;AACD,0BAAgB,OAAO,OAAO;AAC9B,uBAAa,UAAU;AAAA,QACxB;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,uCAAuC,GAAG;AAAA,MACzD,UAAE;AACD,0BAAkB,KAAK;AAAA,MACxB;AAAA,IACD;AAAA,IACA,CAAC,QAAQ,OAAO,KAAK,KAAK;AAAA,EAC3B;AAGA,QAAM,iBAAiBA;AAAA,IACtB,CAAC,aAA+B;AAC/B,wBAAkB,QAAQ;AAC1B,gBAAU,IAAI;AAEd,YAAM,SAASJ;AAAA,QACd,MAAM,SAAS,EAAE;AAAA,QACjB,SAAS,OAAO,UAAU,GAAG,SAAS,IAAI;AAAA,MAC3C;AACA,UAAI,QAAQ;AACX,iBAAS,OAAO,KAAK;AACrB,wBAAgB,OAAO,OAAO;AAC9B,qBAAa,UAAU,OAAO;AAC9B;AAAA,MACD;AAEA,eAAS,CAAC,CAAC;AACX,iBAAW,EAAE,MAAM,GAAG,OAAO,MAAM,WAAW,SAAS,KAAK,CAAC;AAAA,IAC9D;AAAA,IACA,CAAC,YAAY,OAAO,KAAK;AAAA,EAC1B;AAGA,QAAM,gBAAgBI,cAAY,MAAM;AACvC,QAAI,CAAC,gBAAgB,kBAAkB,CAAC,eAAgB;AACxD,eAAW;AAAA,MACV,MAAM,aAAa,UAAU;AAAA,MAC7B,WAAW,eAAe;AAAA,IAC3B,CAAC;AAAA,EACF,GAAG,CAAC,YAAY,cAAc,gBAAgB,cAAc,CAAC;AAG7D,QAAM,cAAcA;AAAA,IACnB,CAAC,UAAkB;AAClB,eAAS,CAAC,CAAC;AACX,iBAAW;AAAA,QACV,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ,SAAS;AAAA,QACjB,WAAW,QAAQ,SAAY,gBAAgB;AAAA,MAChD,CAAC;AAAA,IACF;AAAA,IACA,CAAC,YAAY,cAAc;AAAA,EAC5B;AAGA,QAAM,cAAcA;AAAA,IACnB,OAAO,SAAiB;AACvB,UAAI,CAAC,KAAK,eAAgB;AAE1B,YAAM,SAASJ;AAAA,QACd,MAAM,SAAS,EAAE;AAAA,QACjBD,WAAU,OAAO,UAAU,GAAG,IAAI;AAAA,MACnC;AACA,UAAI,QAAQ;AACX,kBAAU,MAAM;AAChB;AAAA,MACD;AAEA,yBAAmB,IAAI;AACvB,UAAI;AACH,cAAM,SAAS,MAAM,OAAO,OAAO,WAAW,MAAM;AAAA,UACnD;AAAA,UACA;AAAA,UACA,YAAY,IAAI;AAAA,UAChB,UAAU,UAAU;AAAA,QACrB,CAAC;AACD,YAAI,OAAO,OAAO;AACjB,gBAAM,QAAQ,OAAO;AACrB,oBAAU,KAAK;AACf,gBAAM,SAAS,EAAE;AAAA,YAChBA,WAAU,OAAO,UAAU,GAAG,IAAI;AAAA,YAClC;AAAA,UACD;AAAA,QACD;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,wCAAwC,GAAG;AAAA,MAC1D,UAAE;AACD,2BAAmB,KAAK;AAAA,MACzB;AAAA,IACD;AAAA,IACA,CAAC,QAAQ,OAAO,KAAK,KAAK;AAAA,EAC3B;AAGA,QAAM,mBAAmBK;AAAA,IACxB,CAAC,UAAkB;AAClB,UAAI,CAAC,MAAM,KAAK,GAAG;AAClB,sBAAc,iBAAiB,OAAO;AACtC;AAAA,MACD;AACA,YAAM,IAAI,MAAM,YAAY;AAC5B;AAAA,QACC,iBAAiB,QAAQ;AAAA,UAAO,CAAC,QAChC,IAAI,MAAM,YAAY,EAAE,SAAS,CAAC,MACjC,IAAI,aAAa,eAAe,IAAI,YAAY,EAAE,SAAS,CAAC;AAAA,QAC9D;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAC;AAAA,EACF;AAEA,QAAM,cAAcA,cAAY,MAAM;AACrC,cAAU,IAAI;AAAA,EACf,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgBA,cAAY,MAAM;AACvC,sBAAkB,IAAI;AACtB,aAAS,CAAC,CAAC;AACX,cAAU,IAAI;AAAA,EACf,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;;;ADzMS,gBAAAC,YAAA;AAtDF,SAAS,sBAAsB;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAMG;AACF,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI,qBAAqB,IAAI,EAAE;AAG/B,EAAAC,YAAU,MAAM;AACf,cAAU;AAAA,EACX,GAAG,CAAC,SAAS,CAAC;AAGd,EAAAA,YAAU,MAAM;AACf,QAAI,cAAc,YAAY,kBAAkB;AAC/C,kBAAY,UAAU;AAAA,IACvB;AAAA,EACD,GAAG,CAAC,YAAY,SAAS,WAAW,CAAC;AAGrC,QAAM,cAAcC,SAAO,OAAO;AAClC,EAAAD,YAAU,MAAM;AACf,QAAI,YAAY,YAAY,sBAAsB,YAAY,MAAM;AACnE,oBAAc;AAAA,IACf;AACA,gBAAY,UAAU;AAAA,EACvB,GAAG,CAAC,SAAS,aAAa,CAAC;AAG3B,MAAI,YAAY,oBAAoB,YAAY;AAC/C,WAAO,gBAAAD,KAAC,qBAAkB,OAAO,QAAQ,WAAW,iBAAiB;AAAA,EACtE;AAGA,MAAI,YAAY,sBAAsB,gBAAgB;AACrD,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,SAAS;AAAA,QACT,WAAW;AAAA,QACX,SAAS;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,mBAAmB,EAAE,eAAe;AAAA,QACpC,SAAS,IAAI;AAAA;AAAA,IACd;AAAA,EAEF;AAGA,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,SAAS;AAAA,MACT,WAAW;AAAA,MACX,SAAS;AAAA,MACT,UAAU,CAAC,SAAS;AACnB,cAAM,MAAM,WAAW,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAClD,YAAI,KAAK;AACR,yBAAe,GAAG;AAClB,2BAAiB,GAAG;AAAA,QACrB;AAAA,MACD;AAAA,MACA,YAAY,MAAM;AAAA,MAAC;AAAA,MACnB,UAAU;AAAA,MACV,mBAAmB,EAAE,eAAe;AAAA;AAAA,EACrC;AAEF;;;AL3EG,gBAAAG,aAAA;AAlBI,SAAS,eAAe;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAOG;AAEF,MAAI,IAAI,YAAY,aAAa,IAAI,gBAAgB;AACpD,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA,SAAS,WAAW;AAAA,QACpB;AAAA,QACA,kBAAkB,qBAAqB,MAAM;AAAA,QAAC;AAAA,QAC9C;AAAA;AAAA,IACD;AAAA,EAEF;AAGA,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACD;AAEF;AAIA,SAAS,mBAAmB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAKG;AACF,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI,cAAc,IAAI,EAAE;AAExB,EAAAC,YAAU,MAAM;AACf,QAAI,WAAY,aAAY,UAAU;AAAA,EACvC,GAAG,CAAC,YAAY,WAAW,CAAC;AAE5B,QAAM,eAAeC;AAAA,IACpB,CAAC,UAAkB;AAClB,mBAAa,EAAE,MAAM,GAAG,QAAQ,SAAS,QAAW,OAAO,KAAK,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,YAAY;AAAA,EACd;AAEA,MAAI,cAAc,YAAY;AAC7B,WAAO,gBAAAF,MAAC,qBAAkB,OAAO,QAAQ,WAAW,iBAAiB;AAAA,EACtE;AAEA,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,mBAAmB,GAAG,EAAE,eAAe,CAAC,IAAI,aAAa,IAAI,KAAK,EAAE,YAAY,CAAC;AAAA,MACjF,SAAS,IAAI;AAAA;AAAA,EACd;AAEF;;;AO/EQ,gBAAAG,aAAA;AAXR,IAAM,WAAqC;AAAA,EAC1C,MAAM;AAAA,EACN,WAAW;AAAA,EACX,WAAW;AAAA,EACX,eAAe;AAAA,EACf,WAAW;AAAA,EACX,MAAM;AACP;AAEO,SAAS,wBAAwB,EAAE,KAAK,GAAqB;AACnE,QAAM,OAAO,SAAS,IAAI,KAAK;AAC/B,SAAO,gBAAAA,MAAC,QAAK;AACd;;;ACtBA,SAAS,YAAAC,kBAAgB;;;ACGlB,SAAS,cAAc,MAAsB;AACnD,SAAO,KACL,QAAQ,gBAAgB,EAAE,EAC1B,QAAQ,kBAAkB,IAAI,EAC9B,QAAQ,cAAc,IAAI,EAC1B,QAAQ,eAAe,EAAE,EACzB,QAAQ,qBAAqB,IAAI,EACjC,QAAQ,YAAY,IAAI,EACxB,QAAQ,WAAW,GAAG,EACtB,QAAQ,OAAO,GAAG,EAClB,KAAK;AACR;;;AD+DI,gBAAAC,OAoDD,QAAAC,aApDC;AAlBG,SAAS,qBAAqB;AAAA,EACpC;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AACD,GAA8B;AAC7B,QAAM,WAAW,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAC7D,QAAM,iBAAiB,eAAe,CAAC,MAAM,EAAE,0BAA0B;AACzE,QAAM,YAAY,eAAe,CAAC,MAAM,EAAE,aAAa,IAAI,KAAK;AAEhE,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,QAAM,sBACL,cAAc,aAAa,gCAAgC;AAE5D,SACC,gBAAAD,MAAC,SAAI,WAAW,oBAAoB,mBAAmB,GAAG,KAAK,GAC7D,mBAAS,IAAI,CAAC,YACd,gBAAAA;AAAA,IAAC;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,CAAC,SAAS,eAAe,IAAI;AAAA;AAAA,IAPnC,QAAQ;AAAA,EAQd,CACA,GACF;AAEF;AAEA,SAAS,wBAAwB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAQG;AACF,QAAM,CAAC,SAAS,UAAU,IAAIE,WAAS,KAAK;AAE5C,QAAM,cAAc,CAAC,MAAkB;AACtC,MAAE,gBAAgB;AAClB,eAAW,IAAI;AACf,eAAW,MAAM;AAChB,gBAAU,QAAQ,IAAI;AACtB,iBAAW,KAAK;AAAA,IACjB,GAAG,GAAG;AAAA,EACP;AAEA,QAAM,iBAAiB,cAAc,aAAa,0BAA0B;AAE5E,SACC,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACA,WAAW,uCAAuC,cAAc,GAAG,UAAU,wBAAwB,EAAE,GAAG,KAAK;AAAA,MAC/G,SAAS,MAAM,OAAO,QAAQ,MAAM,QAAQ,KAAK;AAAA,MACjD,MAAK;AAAA,MACL,UAAU;AAAA,MAEV;AAAA,wBAAAA,MAAC,SAAI,WAAU,qBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,qBAAqB,kBAAO;AAAA,UAC3C,gBAAAA,MAAC,SAAI,WAAU,mBAAmB,qBAAU;AAAA,UAC5C,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACA,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS;AAAA,cACT,cAAY,EAAE,qBAAqB;AAAA,cAEnC,0BAAAA,MAAC,SAAM,MAAM,IAAI;AAAA;AAAA,UAClB;AAAA,WACD;AAAA,QACA,gBAAAA,MAAC,SAAI,WAAU,0CAA0C,kBAAQ,OAAM;AAAA,QACtE,QAAQ,SACP,MAAM;AACN,gBAAM,QAAQ,cAAc,QAAQ,IAAI;AACxC,iBACC,gBAAAA,MAAC,SAAI,WAAU,yCACb,gBAAM,SAAS,MAAM,GAAG,MAAM,MAAM,GAAG,GAAG,CAAC,WAAM,OACnD;AAAA,QAEF,GAAG;AAAA,QACH,QAAQ,SACR,gBAAAA,MAAC,SAAI,WAAU,yBAAyB,kBAAQ,OAAM;AAAA,QAEtD,UAAU,QAAQ,WAAW,SAC7B,gBAAAA,MAAC,SAAI,WAAU,qBAAqB,kBAAO;AAAA;AAAA;AAAA,EAE7C;AAEF;;;AEjKA,SAAS,aAAAG,aAAW,iBAAiB,UAAAC,UAAQ,YAAAC,kBAAgB;AAC7D,SAAS,oBAAoB;AA4FtB,SAgKL,YAAAC,WAhKK,OAAAC,OAWF,QAAAC,aAXE;AApDA,SAAS,cAAc;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAuB;AACtB,QAAM,cAAc,WAAW,MAAM;AACrC,QAAM,YAAYC,SAAuB,IAAI;AAE7C,QAAM,aACL,OAAO,OAAO,CAAC,MAAyD,EAAE,SAAS,OAAO,KAC1F,CAAC;AACF,QAAM,YACL,OAAO,OAAO,CAAC,MAAwD,EAAE,SAAS,MAAM,KAAK,CAAC;AAC/F,QAAM,eACL,OAAO;AAAA,IACN,CAAC,MAAgE,EAAE,SAAS;AAAA,EAC7E,KAAK,CAAC;AAIP,QAAM,UACL,OAAO;AAAA,IACN,CAAC,MAA0D,EAAE,SAAS;AAAA,EACvE,KAAK,CAAC;AACP,QAAM,UAAU,KAAK,SAAS;AAE9B,EAAAC,YAAU,MAAM;AACf,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,UAAW,WAAW,QAAQ,WAAW,OAAS;AACvD,UAAM,cAAc,CAAC,UAAiB;AACrC,2BAAqB,OAAO,MAAM;AAAA,IACnC;AACA,WAAO,iBAAiB,SAAS,WAAW;AAC5C,WAAO,MAAM;AACZ,aAAO,oBAAoB,SAAS,WAAW;AAAA,IAChD;AAAA,EACD,GAAG,CAAC,MAAM,CAAC;AAGX,SACC,gBAAAH,MAAC,SAAI,WAAW,UAAU,WAAW,IACpC,0BAAAC,MAAC,SAAI,WAAU,eAEb;AAAA,eAAW,SAAS,KACpB,gBAAAD,MAAC,SAAI,WAAU,iBACb,qBAAW,IAAI,CAAC,KAAK,MACrB,gBAAAA,MAAC,wBAA6B,KAAK,IAAI,OAAZ,CAAiB,CAC5C,GACF;AAAA,IAQA,WACA,gBAAAC,MAAC,SAAI,WAAU,iBAAgB,KAAK,WAClC;AAAA,iBAAW,QAAQ,WAAW,SAC9B,gBAAAD;AAAA,QAAC;AAAA;AAAA,UACA,yBAAyB;AAAA,YACxB,QAAQ,eAAe,YAAY,sBAAsB,IAAI,IAAI,IAAI;AAAA,UACtE;AAAA;AAAA,MACD,IAEA,gBAAAA,MAAC,UAAK,yBAAyB,EAAE,QAAQ,YAAY,IAAI,EAAE,GAAG;AAAA,MAE9D,aAAa,gBAAAA,MAAC,UAAK,WAAU,uBAAsB;AAAA,OACrD;AAAA,IAIA,UAAU,SAAS,KACnB,gBAAAA,MAAC,SAAI,WAAU,gBACb,oBAAU,IAAI,CAAC,MAAM,MACrB,gBAAAA,MAAC,YAAiB,QAAH,CAAe,CAC9B,GACF;AAAA,IAIA,aAAa,SAAS,KACtB,gBAAAA,MAAC,SAAI,WAAU,gBACb,uBAAa,IAAI,CAAC,IAAI,MACtB,gBAAAA,MAAC,mBAAwB,SAAS,MAAZ,CAAgB,CACtC,GACF;AAAA,IAIA,QAAQ,SAAS,KACjB,gBAAAA,MAAC,SAAI,WAAU,cACb,kBAAQ;AAAA,MAAI,CAAC,KAAK,MAClB,IAAI,YACH,gBAAAC;AAAA,QAAC;AAAA;AAAA,UAEA,MAAM,IAAI;AAAA,UACV,QAAO;AAAA,UACP,KAAI;AAAA,UACJ,WAAU;AAAA,UACV,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,UAElC;AAAA,4BAAAD,MAAC,UAAK,WAAU,eAAe,cAAI,GAAE;AAAA,YACrC,gBAAAA,MAAC,UAAK,WAAU,mBAAmB,cAAI,OAAM;AAAA;AAAA;AAAA,QARxC,IAAI;AAAA,MASV,IAEA,gBAAAC,MAAC,SAA0B,WAAU,aACpC;AAAA,wBAAAD,MAAC,UAAK,WAAU,eAAe,cAAI,GAAE;AAAA,QACrC,gBAAAA,MAAC,UAAK,WAAU,mBAAmB,cAAI,OAAM;AAAA,WAFpC,IAAI,WAGd;AAAA,IAEF,GACD;AAAA,IAKA,UAAU,SAAS,mBACnB,gBAAAA,MAAC,qBAAkB,UAAoB,OAAO,iBAAiB;AAAA,KAqB9D,MAAM;AACP,YAAM,YAAY,WAAW;AAC7B,YAAM,OAAO,YAAY,OAAQ,cAAc;AAC/C,YAAM,YAAY,cAAc,CAAC,CAAC,cAAc,CAAC,CAAC;AAClD,UAAI,CAAC,YAAY,CAAC,UAAW,QAAO;AACpC,aACC,gBAAAC,MAAC,SAAI,WAAU,eACb;AAAA,oBAAY,gBAAAD,MAAC,UAAK,WAAU,iBAAiB,gBAAK;AAAA,QAClD,YAAY,aAAa,gBAAAA,MAAC,UAAK,WAAU,mBAAkB,kBAAC;AAAA,QAC5D,aAAa,gBAAAA,MAAC,UAAK,WAAU,eAAe,qBAAU;AAAA,SACxD;AAAA,IAEF,GAAG;AAAA,KACJ,GACD;AAEF;AAIA,SAAS,kBAAkB;AAAA,EAC1B;AAAA,EACA;AACD,GAGG;AACF,QAAM,CAAC,UAAU,WAAW,IAAII,WAAwB,IAAI;AAC5D,QAAM,WAAW,SAAS,aAAa,aAAa;AAEpD,QAAM,YAAY,CAAC,aAAqB;AACvC,QAAI,SAAU;AACd,gBAAY,QAAQ;AACpB,YAAQ,UAAU,SAAS,MAAM;AAAA,EAClC;AAEA,SACC,gBAAAJ;AAAA,IAAC;AAAA;AAAA,MACA,WAAU;AAAA,MACV,kBAAgB,SAAS,YAAY,SAAS;AAAA,MAE7C,mBAAS,QAAQ,IAAI,CAAC,QAAQ;AAC9B,cAAM,WAAW,aAAa,IAAI;AAClC,eACC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAEA,MAAK;AAAA,YACL,WAAU;AAAA,YACV,eAAa,WAAW,SAAS;AAAA,YACjC,UAAU;AAAA,YACV,SAAS,MAAM,UAAU,IAAI,EAAE;AAAA,YAE9B,cAAI;AAAA;AAAA,UAPA,IAAI;AAAA,QAQV;AAAA,MAEF,CAAC;AAAA;AAAA,EACF;AAEF;AAIA,SAAS,qBAAqB,EAAE,IAAI,GAAoB;AACvD,QAAM,CAAC,OAAO,QAAQ,IAAII,WAAS,KAAK;AACxC,QAAM,MAAMF,SAA0B,IAAI;AAE1C,SACC,gBAAAD,MAAAF,WAAA,EACC;AAAA,oBAAAC;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,QAAO;AAAA,QACP,KAAI;AAAA,QACJ,WAAU;AAAA,QACV,cAAY,EAAE,wBAAwB;AAAA,QACtC,cAAc,MAAM,SAAS,IAAI;AAAA,QACjC,cAAc,MAAM,SAAS,KAAK;AAAA,QAKlC,0BAAAA,MAAC,SAAI,KAAU,KAAI,IAAG,WAAU,gBAAe,SAAQ,QAAO;AAAA;AAAA,IAC/D;AAAA,IACC,SAAS,gBAAAA,MAAC,mBAAgB,KAAU,WAAW,KAAK,MAAM,KAAK;AAAA,KACjE;AAEF;AAIA,IAAM,mBAAmB,oBAAI,IAAI,CAAC,OAAO,OAAO,OAAO,OAAO,QAAQ,OAAO,QAAQ,KAAK,CAAC;AAE3F,SAAS,SAAS,EAAE,KAAK,GAA0D;AAClF,QAAM,CAAC,OAAO,QAAQ,IAAII,WAAS,KAAK;AACxC,QAAM,MAAMF,SAA0B,IAAI;AAC1C,QAAM,MAAM,KAAK,SAAS,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,KAAK;AAC7D,QAAM,gBAAgB,iBAAiB,IAAI,GAAG;AAC9C,QAAM,UAAU,KAAK,SAAS,WAAW,QAAQ;AAEjD,SACC,gBAAAD,MAAAF,WAAA,EACC;AAAA,oBAAAE;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA,MAAM,KAAK;AAAA,QACX,QAAO;AAAA,QACP,KAAI;AAAA,QACJ,WAAU;AAAA,QACV,cAAc,MAAM,iBAAiB,SAAS,IAAI;AAAA,QAClD,cAAc,MAAM,SAAS,KAAK;AAAA,QAElC;AAAA,0BAAAD,MAAC,UAAK,WAAU,oBACf,0BAAAA,MAAC,gBAAa,KAAU,GACzB;AAAA,UACA,gBAAAC,MAAC,UAAK,WAAU,oBACf;AAAA,4BAAAD,MAAC,UAAK,WAAU,oBAAoB,eAAK,UAAS;AAAA,YAClD,gBAAAA,MAAC,UAAK,WAAU,oBAAoB,yBAAe,KAAK,QAAQ,GAAE;AAAA,aACnE;AAAA;AAAA;AAAA,IACD;AAAA,IACC,SACA,kBACC,UACA,gBAAAA,MAAC,mBAAgB,KAAK,KAAK,KAAK,WAAW,KAAK,MAAM,KAAK,KAAK,IAEhE,gBAAAA,MAAC,sBAAmB,UAAU,KAAK,UAAU,KAAU,WAAW,KAAK,MAAM,KAAK,KAAK;AAAA,KAE1F;AAEF;AAIO,SAAS,gBAAgB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAKG;AACF,QAAM,CAAC,OAAO,QAAQ,IAAII,WAA8B,EAAE,SAAS,EAAE,CAAC;AACtE,QAAM,CAAC,cAAc,eAAe,IAAIA,WAA4C,IAAI;AAExF,kBAAgB,MAAM;AACrB,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ;AAEb,UAAM,OAAO,OAAO,sBAAsB;AAC1C,UAAM,KAAK;AACX,UAAM,MAAM;AACZ,UAAM,KAAK,OAAO;AAElB,QAAI,OAAO,KAAK,OAAO,KAAK,QAAQ,IAAI,KAAK;AAC7C,QAAI,OAAO,EAAG,QAAO;AACrB,QAAI,OAAO,KAAK,KAAK,EAAG,QAAO,KAAK,KAAK;AAEzC,UAAM,aAAa;AACnB,QAAI,MAAM,KAAK,MAAM,aAAa;AAClC,QAAI,MAAM,EAAG,OAAM,KAAK,SAAS;AAEjC,aAAS,EAAE,MAAM,KAAK,OAAO,IAAI,SAAS,EAAE,CAAC;AAK7C,UAAM,OAAO,OAAO,YAAY;AAChC,oBAAgB,gBAAgB,aAAa,OAAO,SAAS,IAAI;AAAA,EAClE,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,cAAc,MAAM;AACzB,QAAI,OAAQ,QAAO;AAAA,aAGV,KAAM,QAAO,KAAK,MAAM,UAAU,qBAAqB;AAAA,EACjE;AAEA,MAAI,CAAC,aAAc,QAAO;AAE1B,SAAO;AAAA,IACN,gBAAAJ,MAAC,SAAI,WAAU,oBAAmB,OAAc,SAAS,aACxD,0BAAAA,MAAC,SAAI,KAAU,KAAI,IAAG,WAAU,wBAAuB,GACxD;AAAA,IACA;AAAA,EACD;AACD;AAIA,SAAS,mBAAmB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAKG;AACF,QAAM,CAAC,OAAO,QAAQ,IAAII,WAA8B,EAAE,SAAS,EAAE,CAAC;AACtE,QAAM,CAAC,cAAc,eAAe,IAAIA,WAA4C,IAAI;AAExF,kBAAgB,MAAM;AACrB,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ;AAEb,UAAM,OAAO,OAAO,sBAAsB;AAC1C,UAAM,KAAK;AACX,UAAM,KAAK;AACX,UAAM,MAAM;AACZ,UAAM,KAAK,OAAO;AAElB,QAAI,OAAO,KAAK,OAAO,KAAK,QAAQ,IAAI,KAAK;AAC7C,QAAI,OAAO,EAAG,QAAO;AACrB,QAAI,OAAO,KAAK,KAAK,EAAG,QAAO,KAAK,KAAK;AAEzC,QAAI,MAAM,KAAK,MAAM,KAAK;AAC1B,QAAI,MAAM,EAAG,OAAM,KAAK,SAAS;AAEjC,aAAS,EAAE,MAAM,KAAK,OAAO,IAAI,SAAS,EAAE,CAAC;AAC7C,UAAM,OAAO,OAAO,YAAY;AAChC,oBAAgB,gBAAgB,aAAa,OAAO,SAAS,IAAI;AAAA,EAClE,GAAG,CAAC,SAAS,CAAC;AAEd,MAAI,CAAC,aAAc,QAAO;AAE1B,SAAO;AAAA,IACN,gBAAAH;AAAA,MAAC;AAAA;AAAA,QACA,WAAU;AAAA,QACV;AAAA,QACA,SAAS,MAAM,OAAO,KAAK,MAAM,UAAU,qBAAqB;AAAA,QAEhE;AAAA,0BAAAD,MAAC,SAAI,WAAU,6BACd,0BAAAA,MAAC,gBAAa,KAAU,GACzB;AAAA,UACA,gBAAAC,MAAC,SAAI,WAAU,6BACd;AAAA,4BAAAD,MAAC,UAAK,WAAU,6BAA6B,oBAAS;AAAA,YACtD,gBAAAA,MAAC,UAAK,WAAU,6BAA6B,YAAE,sBAAsB,GAAE;AAAA,aACxE;AAAA;AAAA;AAAA,IACD;AAAA,IACA;AAAA,EACD;AACD;AAIA,SAAS,eAAe,OAAuB;AAC9C,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC5D,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,CAAC,CAAC;AAC7C;AAIA,IAAM,mBAA2C;AAAA,EAChD,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AACN;AAEA,SAAS,aAAa,EAAE,IAAI,GAAoB;AAC/C,QAAM,QAAQ,iBAAiB,GAAG,KAAK;AAEvC,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAc;AAAA,MACd,gBAAe;AAAA,MAEf;AAAA,wBAAAD,MAAC,UAAK,GAAE,8DAA6D;AAAA,QACrE,gBAAAA,MAAC,cAAS,QAAO,kBAAiB;AAAA,QACjC,QAAQ,SACR,gBAAAA,MAAC,UAAK,GAAE,KAAI,GAAE,MAAK,UAAS,KAAI,MAAM,OAAO,QAAO,QAAO,YAAW,OAAM,iBAE5E;AAAA,QAEA,QAAQ,SACR,gBAAAA,MAAC,UAAK,GAAE,KAAI,GAAE,MAAK,UAAS,KAAI,MAAM,OAAO,QAAO,QAAO,YAAW,OAAM,iBAE5E;AAAA;AAAA;AAAA,EAEF;AAEF;AAIA,SAAS,gBAAgB,EAAE,QAAQ,GAAiC;AACnE,QAAM,YAAY,MAAM;AACvB,QAAI;AAAE,aAAO,IAAI,IAAI,QAAQ,GAAG,EAAE;AAAA,IAAU,QAAQ;AAAE,aAAO,QAAQ;AAAA,IAAK;AAAA,EAC3E,GAAG;AACH,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,MAAM,QAAQ;AAAA,MACd,QAAO;AAAA,MACP,KAAI;AAAA,MACJ,WAAU;AAAA,MACV,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,MAEjC;AAAA,gBAAQ,YACR,gBAAAD;AAAA,UAAC;AAAA;AAAA,YACA,KAAK,QAAQ;AAAA,YACb,KAAI;AAAA,YACJ,WAAU;AAAA,YACV,SAAQ;AAAA,YACR,SAAS,CAAC,MAAM;AAAE,cAAC,EAAE,OAA4B,MAAM,UAAU;AAAA,YAAQ;AAAA;AAAA,QAC1E;AAAA,QAED,gBAAAC,MAAC,SAAI,WAAU,wBACb;AAAA,kBAAQ,WACR,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACA,KAAK,QAAQ;AAAA,cACb,KAAI;AAAA,cACJ,WAAU;AAAA,cACV,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,SAAS,CAAC,MAAM;AAAE,gBAAC,EAAE,OAA4B,MAAM,UAAU;AAAA,cAAQ;AAAA;AAAA,UAC1E;AAAA,UAEA,QAAQ,SAAS,gBAAAA,MAAC,SAAI,WAAU,yBAAyB,kBAAQ,OAAM;AAAA,UACvE,QAAQ,eACR,gBAAAA,MAAC,SAAI,WAAU,wBAAwB,kBAAQ,YAAY,MAAM,GAAG,GAAG,GAAE;AAAA,UAE1E,gBAAAA,MAAC,SAAI,WAAU,uBAAuB,oBAAS;AAAA,WAChD;AAAA;AAAA;AAAA,EACD;AAEF;;;AC3gBA,OAAO,SAAS,aAAAK,aAAW,UAAAC,gBAAc;AAkLrC,SAGG,OAAAC,OAHH,QAAAC,aAAA;AA9KJ,SAAS,WAAW,KAAoE;AACvF,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,MAAM,QAAQ,GAAG,EAAG,QAAO;AAC/B,MAAI;AACH,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO,MAAM,QAAQ,MAAM,IAAI,SAAS;AAAA,EACzC,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAOA,SAAS,cACR,KAC8B;AAC9B,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,MAAI;AACH,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO,UAAU,OAAO,WAAW,WAAY,SAAkC;AAAA,EAClF,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAeO,SAAS,YAAY;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAqB;AACpB,QAAM,YAAYC,SAAuB,IAAI;AAC7C,QAAM,SAASA,SAAuB,IAAI;AAC1C,QAAM,eAAeA,SAAuB,IAAI;AAChD,QAAM,mBAAmBA,SAAO,MAAM,MAAM;AAC5C,QAAM,mBAAmBA,SAAO,IAAI;AAEpC,QAAM,eAAeA,SAAO,KAAK;AAOjC,QAAM,SAAS,gBAAgB;AAC/B,QAAM,uBAAuB,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAEzE,QAAM,sBAAsB,MAAM;AAAA,IACjC,CAAC,UAAkB,WAAmB;AACrC,UAAI,CAAC,qBAAsB;AAI3B,aAAO,OAAO,cACZ,OAAO,EAAE,gBAAgB,sBAAsB,QAAQ,SAAS,CAAC,EACjE,MAAM,CAAC,QAAiB;AACxB,gBAAQ,KAAK,mCAAmC,GAAG;AAAA,MACpD,CAAC;AAAA,IACH;AAAA,IACA,CAAC,QAAQ,oBAAoB;AAAA,EAC9B;AAGA,EAAAC,YAAU,MAAM;AACf,UAAM,YAAY,iBAAiB;AACnC,UAAM,WAAW,MAAM;AACvB,qBAAiB,UAAU;AAG3B,QAAI,iBAAiB,WAAW,WAAW,WAAW;AAErD,YAAM,WAAW,MAAM,MAAM,SAAS,CAAC;AACvC,YAAM,eAAe,YAAY,IAAI,MAAM,YAAY,CAAC,IAAI;AAE5D,UAAI,iBAAiB,WAAW,CAAC,gBAAgB,UAAU,OAAO,cAAc,IAAI;AAKnF,cAAM,kBAAkB,aAAa;AACrC,kBAAU,SAAS,eAAe;AAAA,UACjC,UAAU,iBAAiB,WAAW,kBAAkB,YAAY;AAAA,QACrE,CAAC;AAAA,MACF;AACA,uBAAiB,UAAU;AAAA,IAC5B;AAAA,EACD,GAAG,CAAC,KAAK,CAAC;AAeV,EAAAA,YAAU,MAAM;AACf,QAAI,eAAe;AAClB,gBAAU,SAAS,eAAe,EAAE,UAAU,UAA4B,CAAC;AAAA,IAC5E;AACA,iBAAa,UAAU,CAAC,CAAC;AAAA,EAC1B,GAAG,CAAC,aAAa,CAAC;AAGlB,EAAAA,YAAU,MAAM;AACf,QAAI,YAAY,gBAAgB;AAC/B,gBAAU,SAAS,eAAe,EAAE,UAAU,SAAS,CAAC;AAAA,IACzD;AAAA,EACD,GAAG,CAAC,UAAU,cAAc,CAAC;AAG7B,EAAAA,YAAU,MAAM;AACf,QAAI,CAAC,WAAW,CAAC,cAAc,CAAC,OAAO,QAAS;AAEhD,UAAM,WAAW,IAAI;AAAA,MACpB,CAAC,YAAY;AACZ,YAAI,QAAQ,CAAC,GAAG,kBAAkB,CAAC,eAAe;AAEjD,gBAAM,YAAY,aAAa;AAC/B,gBAAM,mBAAmB,WAAW,gBAAgB;AACpD,gBAAM,gBAAgB,WAAW,aAAa;AAE9C,qBAAW;AAGX,gCAAsB,MAAM;AAC3B,gBAAI,WAAW;AACd,oBAAM,kBAAkB,UAAU;AAClC,wBAAU,YAAY,iBAAiB,kBAAkB;AAAA,YAC1D;AAAA,UACD,CAAC;AAAA,QACF;AAAA,MACD;AAAA,MACA,EAAE,MAAM,aAAa,SAAS,WAAW,IAAI;AAAA,IAC9C;AAEA,aAAS,QAAQ,OAAO,OAAO;AAC/B,WAAO,MAAM,SAAS,WAAW;AAAA,EAClC,GAAG,CAAC,SAAS,YAAY,aAAa,CAAC;AAEvC,MAAI,MAAM,WAAW,GAAG;AACvB,WACC,gBAAAH;AAAA,MAAC;AAAA;AAAA,QACA,WAAU;AAAA,QACV,MAAK;AAAA,QACL,cAAY,EAAE,sBAAsB;AAAA,QACpC,aAAU;AAAA,QAEV,0BAAAC,MAAC,SAAI,WAAU,YACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,iBACd,0BAAAA,MAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,KACvE,0BAAAA,MAAC,UAAK,GAAE,kCAAiC,GAC1C,GACD;AAAA,UACA,gBAAAA,MAAC,SAAI,WAAU,iBAAiB,YAAE,6BAA6B,GAAE;AAAA,WAClE;AAAA;AAAA,IACD;AAAA,EAEF;AAEA,MAAI,cAAc;AAKlB,QAAM,YAAW,oBAAI,KAAK,GAAE,mBAAmB,OAAO;AACtD,QAAM,YAAY,oBAAI,KAAK;AAC3B,YAAU,QAAQ,UAAU,QAAQ,IAAI,CAAC;AACzC,QAAM,eAAe,UAAU,mBAAmB,OAAO;AAEzD,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,KAAK;AAAA,MACL,WAAU;AAAA,MACV,MAAK;AAAA,MACL,cAAY,EAAE,sBAAsB;AAAA,MACpC,aAAU;AAAA,MAGV;AAAA,wBAAAD,MAAC,SAAI,KAAK,QAAQ,WAAU,wBAC1B,2BACA,gBAAAC,MAAC,SAAI,WAAU,wBACd;AAAA,0BAAAD,MAAC,SAAI;AAAA,UACL,gBAAAA,MAAC,SAAI;AAAA,UACL,gBAAAA,MAAC,SAAI;AAAA,WACN,GAEF;AAAA,QAEC;AAAA,UACA,GAAG,MAAM,IAAI,CAAC,SAAS;AACtB,gBAAI,KAAK,SAAS,SAAS;AAC1B,qBACC,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBAEA,MAAM,KAAK,QAAQ;AAAA;AAAA,gBADb,KAA4C,cAAc,KAAK;AAAA,cAEtE;AAAA,YAEF;AAIA,kBAAM,WAAW,IAAI,KAAK,KAAK,SAAS;AACxC,kBAAM,UAAU,SAAS,mBAAmB,OAAO;AACnD,kBAAM,cAAc,YAAY;AAChC,gBAAI,YAAa,eAAc;AAC/B,kBAAM,cAAc,eAAe,YAAY;AAC/C,kBAAM,YACL,YAAY,eACT,EAAE,kBAAkB,IACpB,SAAS,mBAAmB,UAAU,GAAG;AAAA,cACzC,SAAS;AAAA,cACT,OAAO;AAAA,cACP,KAAK;AAAA,YACN,CAAC;AAGJ,kBAAM,SAAS,KAAK,YAAY,YAAY,KAAK,YAAY,OAAO;AAEpE,mBACC,gBAAAC;AAAA,cAAC,MAAM;AAAA,cAAN;AAAA,gBAGC;AAAA,iCACA,gBAAAA,MAAC,SAAI,WAAU,eACd;AAAA,oCAAAD,MAAC,SAAI,WAAU,oBAAmB;AAAA,oBAClC,gBAAAA,MAAC,SAAI,WAAU,oBAAoB,qBAAU;AAAA,oBAC7C,gBAAAA,MAAC,SAAI,WAAU,oBAAmB;AAAA,qBACnC;AAAA,kBAED,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAM,KAAK,QAAQ;AAAA,sBACnB;AAAA,sBACA,OAAO,WAAW,KAAK,KAAK;AAAA,sBAC5B,UAAU;AAAA,wBACR,KACC;AAAA,sBACH;AAAA,sBACA,iBAAiB;AAAA;AAAA,kBASlB;AAAA;AAAA;AAAA,cA1BM,KAA4C,cAAc,KAAK;AAAA,YA2BtE;AAAA,UAEF,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAeD,GAAI,iBAAiB,uBAClB;AAAA,YACA,gBAAAC,MAAC,MAAM,UAAN,EAUC;AAAA;AAAA,cACD,gBAAAD,MAAC,iBAAc,MAAM,eAAe,QAAO,MAAK,OAAO,MAAM,WAAS,MAAC;AAAA,iBAXnD,gBAAgB,oBAAoB,CAYzD;AAAA,UACD,IACC,CAAC;AAAA,QACL;AAAA,QAGC;AAAA,SAkBC,kBAAkB,aAAa,CAAC,iBACjC,gBAAAA,MAAC,SAAI,WAAU,aACd,0BAAAC,MAAC,SAAI,WAAU,kBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,iBAAgB;AAAA,UAC/B,gBAAAA,MAAC,SAAI,WAAU,iBAAgB;AAAA,UAC/B,gBAAAA,MAAC,SAAI,WAAU,iBAAgB;AAAA,WAChC,GACD;AAAA,QAGD,gBAAAA,MAAC,SAAI,KAAK,WAAW;AAAA;AAAA;AAAA,EACtB;AAEF;AAUA,SAAS,eAAe,MAAgC;AACvD,MAAI,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO;AAClC,MAAI;AACH,UAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,QAAI,KAAK,UAAU,KAAK,KAAM,QAAO;AAAA,EACtC,QAAQ;AAAA,EAER;AACA,SAAO;AACR;AAEA,SAAS,UAAU,EAAE,KAAK,GAAqB;AAC9C,QAAM,OAAO,eAAe,IAAI;AAGhC,MAAI,MAAM;AACT,UAAM,UAAU,KAAK,WAAW,WAAW,EAAE,eAAe,IAAI,EAAE,aAAa;AAE/E,WACC,gBAAAC,MAAC,SAAI,WAAU,2BACd;AAAA,sBAAAD,MAAC,SAAI,WAAU,mBACb,eAAK,QACL,gBAAAA,MAAC,SAAI,KAAK,KAAK,OAAO,KAAI,IAAG,WAAU,uBAAsB,IAE7D,gBAAAA,MAAC,UAAM,sBAAY,KAAK,IAAI,GAAE,GAEhC;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,iBACd;AAAA,wBAAAD,MAAC,UAAK,WAAU,iBAAiB,eAAK,MAAK;AAAA,QAAQ;AAAA,QACnD,gBAAAA,MAAC,UAAK,WAAU,mBAAmB,mBAAQ;AAAA,SAC5C;AAAA,OACD;AAAA,EAEF;AAGA,SACC,gBAAAA,MAAC,SAAI,WAAU,YACd,0BAAAA,MAAC,SAAI,WAAU,iBAAiB,gBAAK,GACtC;AAEF;;;AC3YA,SAAS,aAAAI,aAAW,YAAAC,kBAAgB;AA0HjC,SAsBC,YAAAC,WApBgB,OAAAC,OAFjB,QAAAC,cAAA;AAnEI,SAAS,eAAe;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB;AACD,GAAwB;AACvB,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,eAAe;AACvD,QAAM,iBAAiB,eAAe,CAAC,MAAM,EAAE,cAAc;AAC7D,QAAM,wBAAwB,eAAe,CAAC,MAAM,EAAE,qBAAqB;AAC3E,QAAM,YAAY,eAAe,CAAC,MAAM,EAAE,aAAa,IAAI,KAAK;AAMhE,QAAM,aAAa,SAAS,cAAc;AAC1C,QAAM,cAAc,SAAS,eAAe;AAC5C,QAAM,CAAC,SAAS,UAAU,IAAIC,WAAS,KAAK;AAK5C,EAAAC,YAAU,MAAM;AACf,QAAI,CAAC,WAAW,QAAQ,aAAc;AACtC,QAAI,iBAAiB,QAAQ,iBAAiB,EAAG;AACjD,UAAM,QAAQ,WAAW,MAAM;AAC9B,iBAAW,IAAI;AACf,iBAAW,MAAM,eAAe,GAAG,GAAG;AAAA,IACvC,GAAG,aAAa;AAChB,WAAO,MAAM,aAAa,KAAK;AAAA,EAChC,GAAG,CAAC,SAAS,gBAAgB,aAAa,CAAC;AAE3C,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,cAAc,CAAC,MAAkB;AACtC,MAAE,gBAAgB;AAClB,eAAW,IAAI;AACf,eAAW,MAAM;AAChB,qBAAe;AACf,iBAAW,KAAK;AAAA,IACjB,GAAG,GAAG;AAAA,EACP;AAEA,QAAM,cAAc,MAAM;AAKzB,UAAM,eAAe,QAAQ;AAC7B,mBAAe;AACf,0BAAsB,YAAY;AAClC,WAAO;AAAA,EACR;AAEA,QAAM,WAAW,QAAQ,UAAU,SAAS,QAAQ,WAAW,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC;AACtF,QAAM,QAAQ,QAAQ,gBAAgB,QAAQ,aAAa,QAAQ,SAAS;AAE5E,QAAM,iBAAiB,cAAc,aAAa,0BAA0B;AAE5E,SACC,gBAAAF;AAAA,IAAC;AAAA;AAAA,MACA,WAAW,cAAc,cAAc,GAAG,UAAU,wBAAwB,EAAE;AAAA,MAC9E,SAAS;AAAA,MACT,MAAK;AAAA,MACL,UAAU;AAAA,MAEV;AAAA,wBAAAA,OAAC,SAAI,WAAU,qBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,qBACb,wBAAc,gBAAAA,MAAC,SAAI,KAAK,aAAa,KAAI,IAAG,IAAK,QACnD;AAAA,UACA,gBAAAA,MAAC,SAAI,WAAU,mBAAmB,sBAAW;AAAA,UAC7C,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACA,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS;AAAA,cACT,cAAY,EAAE,qBAAqB;AAAA,cAEnC,0BAAAA,MAAC,SAAM,MAAM,IAAI;AAAA;AAAA,UAClB;AAAA,WACD;AAAA,QAEC,SAAS,IAAI,CAAC,GAAG,MACjB,gBAAAA,MAAC,SAAY,WAAU,mBACrB,YAAE,QADM,CAEV,CACA;AAAA,QAEA,SACA,gBAAAC,OAAAF,WAAA,EACE;AAAA,kBAAQ,aAAc,UACtB,gBAAAC,MAAC,SAAI,WAAU,mBAAmB,kBAAQ,aAAc,QAAO;AAAA,UAShE,gBAAAA,MAAC,SAAI,WAAU,6CACb,kBAAQ,aAAc,QAAQ,IAAI,CAAC,QACnC,gBAAAA;AAAA,YAAC;AAAA;AAAA,cAEA,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS,CAAC,MAAM;AACf,kBAAE,gBAAgB;AAClB,+BAAe;AACf,sCAAsB,QAAQ,cAAc;AAC5C,uBAAO;AAAA,cACR;AAAA,cAEC,cAAI;AAAA;AAAA,YAVA,IAAI;AAAA,UAWV,CACA,GACF;AAAA,WACD;AAAA,QAGA,UAAU,QAAQ,WAAW,SAC7B,gBAAAA,MAAC,SAAI,WAAU,qBAAqB,kBAAO;AAAA;AAAA;AAAA,EAE7C;AAEF;;;A1BpGG,SAuhCG,YAAAI,WAvhCH,OAAAC,OAw0BE,QAAAC,cAx0BF;AAvEH,SAASC,cAAa,OAAuB;AAC5C,MAAI,CAAC,MAAM,WAAW,SAAS,EAAG,QAAO;AACzC,QAAM,WAAW,EAAE,KAAK;AAExB,MAAI,aAAa;AAChB,WAAO,MACL,QAAQ,WAAW,EAAE,EACrB,QAAQ,MAAM,GAAG,EACjB,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC;AACxC,SAAO;AACR;AA4BA,IAAM,qBAAyC,CAAC;AAahD,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB;AAQ5B,SAAS,YAAY,EAAE,UAAU,GAA2B;AAC3D,SACC,gBAAAF;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,eAAY;AAAA,MAEZ,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACA,GAAE;AAAA,UACF,MAAK;AAAA;AAAA,MACN;AAAA;AAAA,EACD;AAEF;AAkBO,SAAS,WAAW;AAAA,EAC1B;AAAA,EACA,aAAa;AACd,GAGG;AACF,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AACvD,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,SAAS,OAAO;AACxD,QAAM,WAAW,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAC7D,QAAM,WAAW,eAAe,CAAC,MAAM;AACtC,QAAI,cAAc,CAAC,EAAE,qBAAsB,QAAO;AAClD,UAAM,IAAI,EAAE,cAAc,KAAK,CAACG,OAAMA,GAAE,OAAO,EAAE,oBAAoB;AACrE,WAAO,GAAG,gBAAgB,GAAG,gBAAgB,IAAI;AAAA,EAClD,CAAC;AAMD,QAAM,YAAY,aAAa,uBAAuB;AAItD,MAAI,CAAC,cAAc,YAAY,UAAU,eAAe;AACvD,WACC,gBAAAH;AAAA,MAAC;AAAA;AAAA,QACA,KAAK,SAAS;AAAA,QACd,KAAK,SAAS,gBAAgB;AAAA,QAC9B,WAAW,gBAAgB,aAAa,EAAE;AAAA;AAAA,IAC3C;AAAA,EAEF;AAGA,MAAI,aAAa,WAAW;AAC3B,WAAO,gBAAAA,MAAC,SAAI,KAAK,YAAY,WAAW,KAAI,IAAG,WAAW,gBAAgB,SAAS,IAAI,aAAa,EAAE,IAAI;AAAA,EAC3G;AAOA,MAAI,aAAa,cAAc;AAC9B,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,WAAW,iBAAiB,aAAa,EAAE;AAAA,QAC3C,OAAO;AAAA,UACN,iBAAiB;AAAA,UACjB,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,gBAAgB;AAAA,UAChB,cAAc;AAAA,QACf;AAAA,QAEA,0BAAAA,MAAC,mBAAgB,UAAU,YAAY,cAAc;AAAA;AAAA,IACtD;AAAA,EAEF;AAKA,MAAI,SAAS;AACZ,WAAO,gBAAAA,MAAC,SAAI,KAAK,SAAS,KAAI,IAAG,WAAW,mCAAmC,aAAa,EAAE,IAAI;AAAA,EACnG;AAEA,SAAO,gBAAAA,MAAC,eAAY,WAAsB;AAC3C;AAYA,SAAS,aAAa,EAAE,UAAU,GAA2B;AAC5D,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AACvD,QAAM,CAAC,WAAW,YAAY,IAAII,WAAS,KAAK;AAChD,QAAM,SAAS,aAAa,mBAAmB;AAE/C,EAAAC,YAAU,MAAM;AACf,QAAI,CAAC,OAAQ;AACb,iBAAa,KAAK;AAClB,UAAM,MAAM,IAAI,MAAM;AACtB,QAAI,MAAM;AACV,QAAI,IAAI,UAAU;AAAE,mBAAa,IAAI;AAAG;AAAA,IAAQ;AAChD,QAAI,SAAS,MAAM,aAAa,IAAI;AACpC,QAAI,UAAU,MAAM,aAAa,IAAI;AAAA,EACtC,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,QAAQ;AACX,WACC,gBAAAL;AAAA,MAAC;AAAA;AAAA,QACA,KAAK;AAAA,QACL,KAAI;AAAA,QACJ,WAAW,mCAAmC,aAAa,EAAE;AAAA,QAC7D,OAAO,EAAE,SAAS,YAAY,IAAI,GAAG,YAAY,qBAAqB;AAAA;AAAA,IACvE;AAAA,EAEF;AACA,SAAO,gBAAAA,MAAC,cAAW,WAAsB,YAAU,MAAC;AACrD;AAQA,IAAM,aAAqC;AAAA;AAAA;AAAA,EAG1C,SACC;AAAA,EACD,MAAM;AAAA,EACN,OACC;AAAA,EACD,OACC;AAAA,EACD,SACC;AAAA,EACD,MAAM;AAAA,EACN,OACC;AAAA,EACD,QACC;AAAA,EACD,WACC;AAAA,EACD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,WACC;AAAA,EACD,MAAM;AAAA,EACN,SACC;AAAA,EACD,SACC;AAAA,EACD,QACC;AAAA,EACD,OACC;AAAA,EACD,QACC;AAAA,EACD,SACC;AAAA,EACD,MAAM;AAAA,EACN,OACC;AAAA,EACD,QACC;AAAA,EACD,QACC;AAAA,EACD,OACC;AAAA,EACD,QACC;AAAA,EACD,SACC;AAAA,EACD,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,UACC;AAAA,EACD,OACC;AAAA,EACD,KAAK;AAAA,EACL,eACC;AAAA,EACD,SACC;AAAA,EACD,MAAM;AAAA,EACN,QACC;AAAA,EACD,SACC;AAAA,EACD,OACC;AAAA,EACD,WACC;AAAA,EACD,OACC;AAAA,EACD,MAAM;AAAA,EACN,QACC;AAAA,EACD,SACC;AAAA,EACD,WACC;AAAA,EACD,MAAM;AAAA,EACN,cACC;AAAA,EACD,MAAM;AAAA,EACN,UACC;AACF;AAOA,SAAS,gBAAgB,EAAE,SAAS,GAAyB;AAC5D,QAAM,aAAa,WAAW,QAAQ,KAAK,WAAW;AACtD;AAAA;AAAA,IAEC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,OAAM;AAAA,QACN,OAAO,EAAE,OAAO,OAAO,QAAQ,MAAM;AAAA,QACrC,yBAAyB,EAAE,QAAQ,cAAc,GAAG;AAAA;AAAA,IACrD;AAAA;AAEF;AAUA,SAAS,WAAW,EAAE,OAAO,GAAwB;AACpD,MAAI,CAAC,OAAQ,QAAO,gBAAAA,MAAC,SAAM,MAAM,IAAI;AACrC,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ,0BAAAA,MAAC,UAAK,GAAE,yBAAwB;AAAA;AAAA,EACjC;AAEF;AAMO,SAAS,cAAc;AAAA,EAC7B,eAAe;AAAA,EACf,YAAY;AAAA,EACZ;AAAA,EACA;AACD,IAeI,CAAC,GAAG;AACP,QAAM,EAAE,SAAS,SAAS,YAAY,IAAI,UAAU;AACpD,UAAQ;AACR,QAAM,EAAE,QAAQ,OAAO,mBAAmB,gBAAgB,eAAe,IAAI,iBAAiB;AAC9F,QAAM,EAAE,eAAe,QAAQ,YAAY,sBAAsB,IAAI,iBAAiB;AACtF,QAAM,WAAW,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAC7D,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AACvD,QAAM,EAAE,YAAY,IAAI,UAAU;AAElC,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,aAAa,WAAW,KAAK;AACzE,QAAM,EAAE,kBAAkB,eAAe,iBAAiB,IAAI,iBAAiB;AAC/E,QAAM,0BAA0B,eAAe,CAAC,MAAM,EAAE,uBAAuB;AAE/E,QAAM,iBAAiB,eAAe,CAAC,MAAM,EAAE,SAAS,OAAO;AAG/D,MAAI,QAAQ,IAAI,aAAa,cAAc;AAC1C,YAAQ,MAAM,YAAY;AAAA,MACzB,UAAU,aAAa;AAAA,MACvB,SAAS,gBAAgB,SAAS;AAAA,MAClC;AAAA,IACD,CAAC;AAAA,EACF;AAEA,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,MAAM;AAClD,QAAM,CAAC,WAAW,YAAY,IAAII,WAAS,KAAK;AAChD,QAAM,SAAS,eAAe;AAC9B,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAc,MAAM;AACtD,QAAM,CAAC,SAAS,UAAU,IAAIA,WAAkB,IAAI;AACpD,QAAM,CAAC,SAAS,UAAU,IAAIA,WAAS,EAAE;AACzC,QAAM,CAAC,mBAAmB,oBAAoB,IAAIA,WAAwB,IAAI;AAC9E,QAAM,CAAC,qBAAqB,sBAAsB,IAAIA,WAAwB,IAAI;AAIlF,QAAM,kBAAkBE,SAAO,QAAQ;AACvC,EAAAD,YAAU,MAAM;AACf,QAAI,YAAY,aAAa,gBAAgB,WAAW,YAAY,gBAAgB;AACnF,iBAAW,cAAc;AAAA,IAC1B;AACA,oBAAgB,UAAU;AAAA,EAC3B,GAAG,CAAC,UAAU,OAAO,CAAC;AAGtB,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,sBAAsB;AAC9D,EAAAA,YAAU,MAAM;AACf,QAAI,YAAY,MAAM;AACrB,UAAI,QAAQ,SAAS,EAAG,YAAW,OAAO;AAC1C,iBAAW,KAAK;AAChB,mBAAa,MAAM;AACnB,YAAM,SAAS,EAAE,0BAA0B,IAAI;AAAA,IAChD;AAAA,EACD,GAAG,CAAC,SAAS,KAAK,CAAC;AAEnB,QAAM,gBAAgBC,SAAsC,MAAS;AAKrE,QAAM,gBAAgB,aAAa;AACnC,QAAM,0BACL,CAAC,iBAAiB,kBAAkB;AACrC,QAAM,iBAAiB,eAAe,WAAW,SAAS,IACvD,EAAE,aAAa,IACf,0BACC,EAAE,wBAAwB,IAC1B;AAEJ,QAAM,mBAAmBC;AAAA,IACxB,CAAC,OAAe;AACf,4BAAsB,EAAE;AACxB,iBAAW,cAAc;AAAA,IAC1B;AAAA,IACA,CAAC,qBAAqB;AAAA,EACvB;AAEA,QAAM,sBAAsBA,cAAY,MAAM;AAS7C,UAAM,UAAU,aAAa;AAC7B,QAAI,CAAC,SAAS;AAGb,iBAAW,KAAK;AAChB;AAAA,IACD;AACA,UAAM,SAAS,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC3E,UAAM,cAA4B;AAAA,MACjC,IAAI,gBAAgB,MAAM;AAAA,MAC1B,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,MAChB,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,UAAU;AAAA,MACV,WAAW;AAAA,IACZ;AACA,UAAM,SAAS,EAAE,YAAY,QAAQ,CAAC,WAAW,CAAC;AAClD,0BAAsB,MAAM;AAC5B,eAAW,cAAc;AAAA,EAC1B,GAAG,CAAC,aAAa,IAAI,OAAO,uBAAuB,cAAc,CAAC;AASlE,QAAM,iBAAiBD,SAAO,KAAK;AACnC,EAAAD,YAAU,MAAM;AACf,QAAI,CAAC,QAAQ;AACZ,qBAAe,UAAU;AACzB;AAAA,IACD;AACA,QAAI,eAAe,WAAW,CAAC,QAAS;AACxC,mBAAe,UAAU;AACzB,QAAI,YAAY,KAAM;AACtB,UAAM,aAAa,cAAc,CAAC;AAClC,QAAI,WAAY,kBAAiB,WAAW,EAAE;AAAA,QACzC,qBAAoB;AAAA,EAC1B,GAAG;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,CAAC;AAQD,QAAM,eAAe,YAAY,QAAQ;AACzC,QAAM,UAAUC,SAAO,YAAY;AAGnC,EAAAD,YAAU,MAAM;AACf,YAAQ,UAAU;AAAA,EACnB,CAAC;AACD,QAAM,kBAAkBC,SAAsB,IAAI;AAOlD,QAAM,iBAAiBC,cAAY,MAAM;AACxC,UAAM,QAAQ,MAAM,SAAS;AAC7B,QAAI,MAAM,OAAQ;AAClB,UAAM,YAAY,MAAM,cAAc,KAAK,CAAC,SAAS,CAAC,KAAK,GAAG,WAAW,OAAO,CAAC;AACjF,QAAI,CAAC,UAAW;AAChB,UAAM,QAAQ,IAAI;AAAA,EACnB,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,iBAAiBA;AAAA,IACtB,CAAC,aAAsB;AACtB,YAAM,QAAQ,YAAY,QAAQ,QAAQ,MAAM,KAAK;AAOrD,YAAM,mBAAmB,QAAQ,QAAQ,YAAY,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAChF,UAAI,CAAC,QAAQ,CAAC,iBAAkB;AAMhC,YAAM,SAAS,EAAE,QAAQ,IAAI;AAC7B,UAAI,UAAU;AACb,gBAAQ,QAAQ,QAAQ,EAAE;AAC1B,aAAK,QAAQ,QAAQ,OAAO,EAAE,MAAM,gBAAgB,SAAS,CAAC;AAC9D;AAAA,MACD;AAOA,0BAAoB;AACpB,YAAM,WAAW,MAAM,SAAS,EAAE;AAClC,cAAQ,QAAQ,QAAQ,EAAE;AAC1B,UAAI,CAAC,UAAU;AAGd,wBAAgB,UAAU;AAC1B;AAAA,MACD;AACA,WAAK,QAAQ,QAAQ,OAAO,EAAE,MAAM,gBAAgB,SAAS,CAAC;AAAA,IAC/D;AAAA,IACA,CAAC,UAAU,qBAAqB,KAAK;AAAA,EACtC;AAEA,EAAAF,YAAU,MAAM;AACf,QAAI,CAAC,YAAY,gBAAgB,WAAW,KAAM;AAClD,UAAM,OAAO,gBAAgB;AAC7B,oBAAgB,UAAU;AAC1B,SAAK,QAAQ,QAAQ,OAAO,EAAE,MAAM,gBAAgB,SAAS,CAAC;AAAA,EAC/D,GAAG,CAAC,QAAQ,CAAC;AAIb,QAAM,CAAC,UAAU,WAAW,IAAID,WAAS,KAAK;AAC9C,EAAAC,YAAU,MAAM;AACf,QAAI,CAAC,SAAU;AACf,UAAM,QAAQ,MAAM,YAAY,KAAK;AACrC,UAAM,QAAQ,CAAC,UAAyB;AACvC,UAAI,MAAM,QAAQ,SAAU,aAAY,KAAK;AAAA,IAC9C;AACA,aAAS,iBAAiB,SAAS,KAAK;AACxC,aAAS,iBAAiB,WAAW,KAAK;AAC1C,WAAO,MAAM;AACZ,eAAS,oBAAoB,SAAS,KAAK;AAC3C,eAAS,oBAAoB,WAAW,KAAK;AAAA,IAC9C;AAAA,EACD,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,SAASE,cAAY,MAAM;AAChC,QAAI,YAAY,kBAAkB;AAEjC,YAAM,QAAQ,UAAU,WAAW,UAAU,IAAI,UAAU,MAAM,CAAC,IAAI;AACtE,YAAM,mBAAmB,QAAQ,YAAY,KAAK,CAACC,OAAMA,GAAE,OAAO,KAAK,IAAI;AAC3E,UAAI,kBAAkB,YAAY,aAAa,qBAAqB;AACnE,mBAAW,kBAAkB;AAC7B,6BAAqB,IAAI;AACzB;AAAA,MACD;AACA,iBAAW,IAAI;AACf,2BAAqB,IAAI;AACzB;AAAA,IACD;AACA,QAAI,YAAY,oBAAoB;AACnC,iBAAW,IAAI;AACf,6BAAuB,IAAI;AAC3B;AAAA,IACD;AAOA,UAAM,YAAY,MAAM,SAAS,EAAE;AACnC,QAAI,aAAa,CAAC,UAAU,WAAW,OAAO,GAAG;AAChD,YAAM,SAAS,EAAE,YAAY,SAAS;AACtC,aAAO,OAAO,SAAS,OAAO,EAAE,gBAAgB,UAAU,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC5E;AACA,0BAAsB,IAAI;AAC1B,eAAW,IAAI;AAAA,EAChB,GAAG,CAAC,uBAAuB,SAAS,WAAW,aAAa,qBAAqB,QAAQ,KAAK,CAAC;AAE/F,QAAM,YAAYD;AAAA,IACjB,CAAC,QAAa;AAEb,kBAAY,QAAQ,SAAS,IAAI,EAAE,SAAS,SAAS;AAErD,YAAM,QAAQ,YAAY,QAAQ,GAAG;AACrC,mBAAa,GAAG;AAChB,iBAAW,OAAO,WAAW,IAAI;AACjC,UAAI,OAAO,YAAY,MAAM;AAC5B,8BAAsB,MAAM,QAAQ;AAAA,MACrC,WAAW,CAAC,OAAO;AAClB,8BAAsB,IAAI;AAAA,MAC3B;AAAA,IACD;AAAA,IACA,CAAC,WAAW,SAAS,UAAU,qBAAqB;AAAA,EACrD;AASA,QAAM,uBAAuB,eAAe,CAAC,MAAM,EAAE,oBAAoB;AACzE,EAAAF,YAAU,MAAM;AACf,QAAI,CAAC,qBAAsB;AAC3B,UAAM,EAAE,MAAM,MAAM,IAAI;AACxB,kBAAc,IAAI;AAClB,cAAU,WAAW,KAAK,EAAE;AAC5B,yBAAqB,IAAI;AACzB,eAAW,gBAAgB;AAC3B,UAAM,SAAS,EAAE,wBAAwB,IAAI;AAAA,EAC9C,GAAG,CAAC,sBAAsB,eAAe,WAAW,KAAK,CAAC;AAE1D,QAAM,eAAe,eAAe,CAAC,MAAM,EAAE,OAAO;AAEpD,QAAM,oBAAoBE,cAAY,MAAM;AAC3C,QAAI,aAAa;AAChB,YAAM,YAAY,MAAM,SAAS,EAAE;AACnC,UAAI,aAAa,CAAC,UAAU,WAAW,OAAO,GAAG;AAChD,cAAM,SAAS,EAAE,YAAY,SAAS;AACtC,eAAO,OAAO,SAAS,OAAO,EAAE,gBAAgB,UAAU,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAC5E;AACA,mBAAa,IAAI;AACjB,oBAAc,UAAU,WAAW,MAAM;AACxC,qBAAa,KAAK;AAClB,qBAAa,KAAK;AAAA,MACnB,GAAG,GAAG;AAAA,IACP,OAAO;AACN,mBAAa,KAAK;AAClB,iBAAW,IAAI;AACf,mBAAa,MAAM;AACnB,mBAAa,IAAI;AAAA,IAClB;AAAA,EACD,GAAG,CAAC,aAAa,cAAc,QAAQ,KAAK,CAAC;AAE7C,QAAM,cAAcA,cAAY,MAAM;AACrC,UAAM,YAAY,MAAM,SAAS,EAAE;AACnC,QAAI,aAAa,CAAC,UAAU,WAAW,OAAO,GAAG;AAChD,YAAM,SAAS,EAAE,YAAY,SAAS;AACtC,aAAO,OAAO,SAAS,OAAO,EAAE,gBAAgB,UAAU,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC5E;AACA,iBAAa,IAAI;AACjB,kBAAc,UAAU,WAAW,MAAM;AACxC,mBAAa,KAAK;AAClB,mBAAa,KAAK;AAAA,IACnB,GAAG,GAAG;AAAA,EACP,GAAG,CAAC,cAAc,QAAQ,KAAK,CAAC;AAEhC,QAAM,wBAAwBA,cAAY,YAAY;AACrD,UAAM,UAAU,QAAQ,KAAK;AAC7B,QAAI,CAAC,WAAW,WAAY;AAC5B,UAAM,OAAO,MAAM,OAAO,OAAO;AACjC,QAAI,MAAM;AACT,iBAAW,EAAE;AACb,iBAAW,cAAc;AAAA,IAC1B;AAAA,EACD,GAAG,CAAC,SAAS,YAAY,MAAM,CAAC;AAEhC,QAAM,YAAYD,SAAuB,IAAI;AAC7C,QAAM,YAAYA,SAA0B,IAAI;AAChD,QAAM,cAAcA,SAAyE,CAAC,CAAC;AAC/F,QAAM,cAAcA,SAAO,CAAC;AAC5B,QAAM,cAAcA,SAAO,CAAC;AAE5B,QAAM,mBAAmBC,cAAY,CAAC,MAAwB;AAC7D,gBAAY,UAAU,EAAE,QAAQ,CAAC,GAAG,WAAW;AAC/C,gBAAY,UAAU;AAAA,EACvB,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkBA,cAAY,CAAC,MAAwB;AAC5D,UAAM,SAAS,EAAE,QAAQ,CAAC,GAAG,WAAW,KAAK,YAAY;AACzD,gBAAY,UAAU;AACtB,QAAI,QAAQ,KAAK,UAAU,SAAS;AACnC,gBAAU,QAAQ,MAAM,YAAY,cAAc,KAAK,IAAI,OAAO,GAAG,CAAC;AACtE,gBAAU,QAAQ,MAAM,UAAU,GAAG,KAAK,IAAI,IAAI,QAAQ,KAAK,GAAG,CAAC;AAAA,IACpE;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,QAAM,iBAAiBA,cAAY,MAAM;AACxC,QAAI,UAAU,SAAS;AACtB,gBAAU,QAAQ,MAAM,YAAY;AACpC,gBAAU,QAAQ,MAAM,UAAU;AAAA,IACnC;AACA,QAAI,YAAY,UAAU,IAAI;AAC7B,kBAAY;AAAA,IACb;AAAA,EACD,GAAG,CAAC,WAAW,CAAC;AAQhB,EAAAF,YAAU,MAAM;AACf,QAAI,CAAC,UAAU,CAAC,UAAU,QAAS;AACnC,UAAM,KAAK,OAAO;AAClB,QAAI,CAAC,GAAI;AACT,UAAM,MAAM,UAAU;AACtB,UAAM,cAAc,MAAM;AACzB,UAAI,MAAM,YAAY,uBAAuB,GAAG,GAAG,MAAM,IAAI;AAAA,IAC9D;AACA,gBAAY;AACZ,OAAG,iBAAiB,UAAU,WAAW;AACzC,OAAG,iBAAiB,UAAU,WAAW;AACzC,WAAO,MAAM;AACZ,SAAG,oBAAoB,UAAU,WAAW;AAC5C,SAAG,oBAAoB,UAAU,WAAW;AAC5C,UAAI,MAAM,eAAe,qBAAqB;AAAA,IAC/C;AAAA,EACD,GAAG,CAAC,MAAM,CAAC;AAOX,EAAAA,YAAU,MAAM;AACf,QAAI,CAAC,UAAU,CAAC,UAAU,QAAS;AACnC,UAAM,MAAM,UAAU;AACtB,UAAM,gBAAgB,CAAC,MAAqB;AAC3C,UAAI,EAAE,QAAQ,UAAU;AACvB,YAAI,SAAS;AACZ,iBAAO;AAAA,QACR,OAAO;AACN,sBAAY;AACZ,qBAAW,MAAM,UAAU,SAAS,MAAM,GAAG,GAAG;AAAA,QACjD;AAAA,MACD;AAAA,IACD;AACA,QAAI,iBAAiB,WAAW,aAAa;AAC7C,WAAO,MAAM,IAAI,oBAAoB,WAAW,aAAa;AAAA,EAC9D,GAAG,CAAC,QAAQ,SAAS,aAAa,MAAM,CAAC;AAezC,EAAAA,YAAU,MAAM;AACf,QAAI,CAAC,UAAU,CAAC,UAAU,WAAW,aAAc;AACnD,UAAM,MAAM,UAAU;AACtB,UAAM,eAAe,MACpB,IAAI;AAAA,MACH;AAAA,IACD;AACD,UAAM,YAAY,MAAsB;AAGvC,YAAM,OAAO,IAAI,YAAY;AAC7B,UAAI,gBAAgB,WAAY,QAAO,KAAK;AAC5C,aAAO,SAAS;AAAA,IACjB;AACA,UAAM,YAAY,CAAC,MAAqB;AACvC,UAAI,EAAE,QAAQ,MAAO;AACrB,YAAM,YAAY,aAAa;AAC/B,UAAI,UAAU,WAAW,EAAG;AAC5B,YAAM,QAAQ,UAAU,CAAC;AACzB,YAAM,OAAO,UAAU,UAAU,SAAS,CAAC;AAC3C,YAAM,SAAS,UAAU;AACzB,UAAI,EAAE,YAAY,WAAW,OAAO;AACnC,UAAE,eAAe;AACjB,cAAM,MAAM;AAAA,MACb,WAAW,CAAC,EAAE,YAAY,WAAW,MAAM;AAC1C,UAAE,eAAe;AACjB,eAAO,MAAM;AAAA,MACd;AAAA,IACD;AACA,QAAI,iBAAiB,WAAW,SAAS;AAMzC,QAAI,cAAc,UAAU;AAC3B,YAAM,YAAY,aAAa;AAC/B,UAAI,UAAU,SAAS,EAAG,WAAU,CAAC,GAAG,MAAM;AAAA,IAC/C;AACA,WAAO,MAAM,IAAI,oBAAoB,WAAW,SAAS;AAAA,EAC1D,GAAG,CAAC,QAAQ,cAAc,SAAS,CAAC;AAEpC,QAAM,aAAa,YAAY;AAI/B,QAAM,EAAE,YAAY,cAAc,aAAa,WAAW,IAAI,kBAAkB;AAChF,QAAM,cAAc,aAAa;AACjC,QAAM,2BACL,CAAC,eAAe,gBAAgB;AACjC,QAAM,eAAe,aAAa,WAAW,SAAS,IACnD,EAAE,WAAW,IACb,2BACC,EAAE,sBAAsB,IACxB;AACJ,QAAM,aAAa,aAAa,cAAc;AAC9C,QAAM,iBAAiB,aAAa,kBAAkB;AACtD,QAAM,gBAAgB,aAAa,iBAAiB;AACpD,QAAM,cAAc,aAAa,eAAe;AAOhD,QAAM,oBAAoB,CAAC,CAAC,aAAa;AAEzC,SACC,gBAAAJ;AAAA,IAAC;AAAA;AAAA,MACA,WAAU;AAAA,MACV,qBAAmB;AAAA,MAInB,gBAAc,SAAS,SAAS;AAAA,MAChC,cAAY,gBAAgB,WAAW,SAAY;AAAA,MACnD,mBAAiB,oBAAoB,SAAS;AAAA,MAC9C,OACC;AAAA,QACC,gBAAgB;AAAA,QAChB,uBAAuB,mBAAmB,iBAAiB,SAAS;AAAA,QACpE,sBAAsB,mBAAmB,gBAAgB,SAAS;AAAA,QAClE,qBAAqB,mBAAmB,iBAAiB,MAAM;AAAA,QAC/D,oBAAoB,mBAAmB,gBAAgB,MAAM;AAAA,MAC9D;AAAA,MAGA;AAAA,sBAAc,YAAY,WAC1B,gBAAAD;AAAA,UAAC;AAAA;AAAA,YACA,OAAO,aAAa;AAAA,YACpB,UAAU,aAAa;AAAA,YACvB,UAAU,MAAM,eAAe;AAAA,YAC/B,UAAU,aAAa;AAAA,YACvB,aAAa,WAAW,SAAY;AAAA,YACpC,cAAc,CAAC,aAAa,eAAe,QAAQ;AAAA,YACnD,aAAa,aAAa;AAAA,YAC1B,YAAY,aAAa;AAAA,YACzB,oBAAoB,aAAa;AAAA,YACjC,UAAU;AAAA,YACV,WAAW,aAAa;AAAA,YACxB,kBAAkB,aAAa;AAAA;AAAA,QAChC;AAAA,QAEA,UAAU,CAAC,WAAW,CAAC,qBACvB,gBAAAA,MAAC,SAAI,WAAW,aAAa,YAAY,uBAAuB,EAAE,IACjE,0BAAAC,OAAC,SAAI,WAAU,uBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,UACrE,gBAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,UACrE,gBAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,WACtE,GACD;AAAA,QAEA,UAAU,qBACV,gBAAAA,MAAC,SAAI,WAAW,aAAa,YAAY,uBAAuB,EAAE,IACjE,0BAAAC,OAAC,SAAI,WAAU,sBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,2BAA2B,YAAE,mBAAmB,GAAE;AAAA,UACjE,gBAAAA,MAAC,YAAO,MAAK,UAAS,WAAU,4BAA2B,SAAS,gBAClE,YAAE,cAAc,GAClB;AAAA,WACD,GACD;AAAA,QAEA,UAAU,WACV,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACA,KAAK;AAAA,YACL,WAAW,aAAa,YAAY,uBAAuB,EAAE,IAC5D,YAAY,mBAAmB,uBAAuB,EACvD;AAAA,YACA,MAAK;AAAA,YACL,cAAY,EAAE,kBAAkB;AAAA,YAChC,cAAW;AAAA,YACX,cAAc;AAAA,YACd,aAAa;AAAA,YACb,YAAY;AAAA,YAGZ;AAAA,8BAAAD,MAAC,SAAI,WAAU,kBACd,0BAAAA,MAAC,SAAI,WAAU,uBAAsB,GACtC;AAAA,cAEC,kBACA,gBAAAC,OAAC,SAAI,WAAU,iBACd;AAAA,gCAAAD,MAAC,SAAI,WAAU,yBAAwB;AAAA,gBACtC,EAAE,qBAAqB;AAAA,iBACzB;AAAA,eAGC,YAAY,oBAAoB,YAAY,wBAC5C,MAAM;AACN,sBAAM,QAAQ,UAAU,QAAQ,YAAY,EAAE;AAC9C,sBAAM,aAAa,YAAY,KAAK,CAACQ,OAAMA,GAAE,OAAO,KAAK;AAEzD,sBAAM,cACL,YAAY,sBAAsB,sBAC/B,sBACA,YAAY,QACXN,cAAa,WAAW,KAAK,IAC7B,EAAE,gBAAgB;AACvB,uBACC,gBAAAD,OAAC,SAAI,WAAU,iCACd;AAAA,kCAAAD;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,SAAS;AAAA,sBACT,cAAY,EAAE,kBAAkB;AAAA,sBAEhC,0BAAAA;AAAA,wBAAC;AAAA;AAAA,0BACA,SAAQ;AAAA,0BACR,MAAK;AAAA,0BACL,QAAO;AAAA,0BACP,aAAa;AAAA,0BACb,eAAc;AAAA,0BACd,gBAAe;AAAA,0BAEf,0BAAAA,MAAC,UAAK,GAAE,mBAAkB;AAAA;AAAA,sBAC3B;AAAA;AAAA,kBACD;AAAA,kBACA,gBAAAA,MAAC,SAAI,WAAU,mBAAmB,uBAAY;AAAA,kBAC9C,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,SAAS;AAAA,sBACT,cAAY,EAAE,mBAAmB;AAAA,sBAEjC,0BAAAA,MAAC,cAAW,QAAQ,cAAc,UAAU;AAAA;AAAA,kBAC7C;AAAA,mBACD;AAAA,cAEF,GAAG;AAAA,cACH,YAAY,QAAQ,YAAY,oBAAoB,YAAY,sBAChE,gBAAAC,OAAC,SAAI,WAAU,4BACd;AAAA,gCAAAD;AAAA,kBAAC;AAAA;AAAA,oBACA,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,SAAS;AAAA,oBACT,cAAY,EAAE,kBAAkB;AAAA,oBAEhC,0BAAAA;AAAA,sBAAC;AAAA;AAAA,wBACA,SAAQ;AAAA,wBACR,MAAK;AAAA,wBACL,QAAO;AAAA,wBACP,aAAa;AAAA,wBACb,eAAc;AAAA,wBACd,gBAAe;AAAA,wBAEf,0BAAAA,MAAC,UAAK,GAAE,mBAAkB;AAAA;AAAA,oBAC3B;AAAA;AAAA,gBACD;AAAA,gBACA,gBAAAC,OAAC,SAAI,WAAU,sBACd;AAAA,kCAAAD,MAAC,SAAI,WAAW,qBAAqB,eAAe,8BAA8B,EAAE,IAClF,0BAAgB,aAChB,gBAAAA,MAAC,SAAI,KAAK,YAAY,KAAK,YAAY,WAAU,uBAAsB,IACpE,eACH,gBAAAA,MAAC,UAAK,WAAU,4BACd,qBAAW,MAAM,GAAG,EAAE,IAAI,CAAC,MAAc,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,GAAG,CAAC,EAAE,YAAY,GAClF,IAEA,gBAAAA,MAAC,cAAW,GAEd;AAAA,kBACA,gBAAAC,OAAC,SAAI,WAAU,kBACd;AAAA,oCAAAD,MAAC,SAAI,WAAU,kBAAkB,sBAAW;AAAA,oBAM5C,gBAAAA,MAAC,SAAI,WAAU,oBAAoB,wBAAa;AAAA,qBACjD;AAAA,mBACD;AAAA,gBACA,gBAAAC,OAAC,SAAI,WAAU,qBACd;AAAA,kCAAAD;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,iBAAc;AAAA,sBACd,iBAAe;AAAA,sBACf,cAAY,EAAE,qBAAqB;AAAA,sBACnC,SAAS,CAAC,UAAU;AACnB,8BAAM,gBAAgB;AACtB,oCAAY,CAAC,SAAS,CAAC,IAAI;AAAA,sBAC5B;AAAA,sBAEA,0BAAAA,MAAC,YAAS,MAAM,IAAI;AAAA;AAAA,kBACrB;AAAA,kBACA,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,SAAS;AAAA,sBACT,cAAY,EAAE,mBAAmB;AAAA,sBAEjC,0BAAAA,MAAC,cAAW,QAAQ,cAAc,UAAU;AAAA;AAAA,kBAC7C;AAAA,kBACC,YACA,gBAAAC,OAAC,SAAI,WAAU,kBAAiB,MAAK,QAKnC;AAAA,kCAAc,SAAS,KACvB,gBAAAD,MAAC,SAAI,WAAU,wBACb,wBAAc,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,SAC/B,gBAAAC;AAAA,sBAAC;AAAA;AAAA,wBACA,MAAK;AAAA,wBACL,MAAK;AAAA,wBAEL,WAAU;AAAA,wBACV,eAAa,KAAK,OAAO,WAAW,SAAS;AAAA,wBAC7C,SAAS,MAAM;AACd,sCAAY,KAAK;AACjB,2CAAiB,KAAK,EAAE;AAAA,wBACzB;AAAA,wBAEA;AAAA,0CAAAA,OAAC,UAAK,WAAU,2BACf;AAAA,4CAAAD,MAAC,UAAK,WAAU,4BACd,eAAK,iBACJ,KAAK,0BAA0B,SAC7B,KAAK,wBACL,SACH,aACF;AAAA,4BACC,KAAK,iBACL,gBAAAA,MAAC,UAAK,WAAU,4BACd,6BAAmB,KAAK,aAAa,GACvC;AAAA,6BAEF;AAAA,0BACA,gBAAAA,MAAC,UAAK,WAAU,+BACd,eAAK,mBAAmB,EAAE,mBAAmB,GAC/C;AAAA;AAAA;AAAA,sBAxBK,KAAK;AAAA,oBAyBX,CACA,GACF;AAAA,oBAED,gBAAAC;AAAA,sBAAC;AAAA;AAAA,wBACA,MAAK;AAAA,wBACL,MAAK;AAAA,wBACL,SAAS,MAAM;AACd,sCAAY,KAAK;AACjB,8CAAoB;AAAA,wBACrB;AAAA,wBAEA;AAAA,0CAAAD,MAAC,eAAY,MAAM,IAAI;AAAA,0BACtB,EAAE,yBAAyB;AAAA;AAAA;AAAA,oBAC7B;AAAA,qBACD;AAAA,mBAEF;AAAA,iBACD;AAAA,cAIA,YAAY,QAAQ,cAAc,UAClC,gBAAAC,OAAAF,WAAA,EACC;AAAA,gCAAAE,OAAC,SAAI,WAAU,WACd;AAAA,kCAAAA,OAAC,SAAI,WAAU,eACd;AAAA,oCAAAD,MAAC,SAAI,WAAU,oBACd,0BAAAA,MAAC,cAAW,GACb;AAAA,oBACA,gBAAAA;AAAA,sBAAC;AAAA;AAAA,wBACA,MAAK;AAAA,wBACL,WAAU;AAAA,wBACV,SAAS;AAAA,wBACT,cAAY,EAAE,mBAAmB;AAAA,wBAEjC,0BAAAA,MAAC,cAAW,QAAQ,cAAc,UAAU;AAAA;AAAA,oBAC7C;AAAA,qBACD;AAAA,kBACA,gBAAAA,MAAC,SAAI,WAAU,oBACb,yBAAe,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,MACtC,gBAAAC;AAAA,oBAAC;AAAA;AAAA,sBAEA,WAAW,MAAM,IAAI,0BAA0B;AAAA,sBAE9C;AAAA,4BAAI,KAAK,gBAAAD,MAAC,QAAG;AAAA,wBACb;AAAA;AAAA;AAAA,oBAJI;AAAA,kBAKN,CACA,GACF;AAAA,kBACA,gBAAAA,MAAC,SAAI,WAAU,oBAAoB,wBAAa;AAAA,mBACjD;AAAA,gBAGA,gBAAAA,MAAC,SAAI,WAAU,YACd,0BAAAC,OAAC,SAAI,WAAU,kBACd;AAAA,kCAAAA,OAAC,YAAO,MAAK,UAAS,WAAU,WAAU,SAAS,qBAClD;AAAA,oCAAAA,OAAC,SAAI,WAAU,gBACd;AAAA,sCAAAD,MAAC,SAAI,WAAU,iBAAiB,YAAE,wBAAwB,GAAE;AAAA,sBAC5D,gBAAAA,MAAC,SAAI,WAAU,gBAAgB,YAAE,mBAAmB,GAAE;AAAA,uBACvD;AAAA,oBACA,gBAAAA,MAAC,SAAI,WAAU,iBACd,0BAAAA,MAAC,YAAS,GACX;AAAA,qBACD;AAAA,kBACC,iBAAiB,SAAS,KAC1B,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA,WAAW,MAAM;AAChB,kCAAU,WAAW,iBAAiB,CAAC,EAAG,EAAE,EAAE;AAAA,sBAC/C;AAAA,sBACA,UAAU,CAAC,MAAM,UAAU;AAC1B,kCAAU,WAAW,KAAK,EAAE;AAC5B,6CAAqB,IAAI;AACzB,mCAAW,gBAAgB;AAC3B,sCAAc,IAAI;AAAA,sBACnB;AAAA;AAAA,kBACD;AAAA,kBAED,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACA;AAAA,sBACA,UAAU;AAAA,sBACV,iBAAiB,MAAM,UAAU,UAAU;AAAA;AAAA,kBAC5C;AAAA,mBACD,GACD;AAAA,iBACD;AAAA,cAIA,YAAY,QAAQ,cAAc,cAClC,gBAAAC,OAAC,SAAI,WAAU,iCACd;AAAA,gCAAAD,MAAC,SAAI,WAAU,oBAAmB;AAAA,gBAClC,gBAAAA,MAAC,SAAI,WAAU,mBAAmB,YAAE,iBAAiB,GAAE;AAAA,gBACvD,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACA,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,SAAS;AAAA,oBACT,cAAY,EAAE,mBAAmB;AAAA,oBAEjC,0BAAAA,MAAC,cAAW,QAAQ,cAAc,UAAU;AAAA;AAAA,gBAC7C;AAAA,iBACD;AAAA,cAIA,YAAY,QACZ,UAAU,WAAW,UAAU,MAC9B,MAAM;AACN,sBAAM,QAAQ,UAAU,QAAQ,YAAY,EAAE;AAC9C,sBAAM,aAAa,YAAY,KAAK,CAACQ,OAAMA,GAAE,OAAO,KAAK;AACzD,oBAAI,CAAC,WAAY,QAAO;AACxB,uBACC,gBAAAP,OAAC,SAAI,WAAU,iCACd;AAAA,kCAAAD,MAAC,SAAI,WAAU,oBAAmB;AAAA,kBAClC,gBAAAA,MAAC,SAAI,WAAU,mBAAmB,UAAAE,cAAa,WAAW,KAAK,GAAE;AAAA,kBACjE,gBAAAF;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,SAAS;AAAA,sBACT,cAAY,EAAE,mBAAmB;AAAA,sBAEjC,0BAAAA,MAAC,cAAW,QAAQ,cAAc,UAAU;AAAA;AAAA,kBAC7C;AAAA,mBACD;AAAA,cAEF,GAAG;AAAA,eAGF,YAAY,QAAQ,cAAc,WACnC,gBAAAC,OAAC,SAAI,WAAU,cACb;AAAA,4BAAY,QAAQ,cAAc,cAClC,gBAAAD;AAAA,kBAAC;AAAA;AAAA,oBACA;AAAA,oBACA,UAAU;AAAA,oBACV,YAAY;AAAA;AAAA,gBACb;AAAA,gBAGA,YAAY,SACZ,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACA,MAAM;AAAA,oBACN,cAAc;AAAA,oBACd,UAAU;AAAA,oBACV,cAAc;AAAA,oBACd;AAAA;AAAA,gBACD;AAAA,gBAGA,YAAY,kBAAkB,YAC9B,gBAAAA,MAAC,oBAAiB,gBAAgB,UAAU,UAAU,iBAAiB;AAAA,gBAIvE,UAAU,WAAW,UAAU,MAC9B,MAAM;AACN,wBAAM,QAAQ,UAAU,QAAQ,YAAY,EAAE;AAC9C,wBAAM,aAAa,YAAY,KAAK,CAACQ,OAAMA,GAAE,OAAO,KAAK;AACzD,sBAAI,CAAC,WAAY,QAAO;AACxB,yBACC,gBAAAR;AAAA,oBAAC;AAAA;AAAA,sBACA,KAAK;AAAA,sBACL,YAAY,YAAY;AAAA,sBACxB,YAAY;AAAA,sBACZ;AAAA,sBACA,eAAe,CAAC,SAAS;AACxB,6CAAqB,IAAI;AACzB,mCAAW,gBAAgB;AAK3B,sCAAc,IAAI;AAAA,sBACnB;AAAA,sBACA,kBAAkB,CAAC,QAAQ;AAC1B,+CAAuB,IAAI,KAAK;AAChC,mCAAW,kBAAkB;AAAA,sBAC9B;AAAA;AAAA,kBACD;AAAA,gBAEF,GAAG;AAAA,iBACL;AAAA,cAIA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACA;AAAA,kBACA,aAAa;AAAA,kBACb,aAAa;AAAA,kBACb;AAAA,kBACA,iBAAiB,aAAa,mBAAmB;AAAA,kBACjD;AAAA;AAAA,cACD;AAAA,cAID,gBAAAC,OAAC,SAAI,WAAU,cACb;AAAA,kBAAE,mBAAmB;AAAA,gBAAG;AAAA,gBACzB,gBAAAD,MAAC,OAAE,MAAK,sBAAqB,QAAO,UAAS,KAAI,uBAAsB,qBAEvE;AAAA,iBACD;AAAA;AAAA;AAAA,QACD;AAAA,QAMA,WAAW,CAAC,UAAU,CAAC,eAAe,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOvC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACA,QAAQ;AAAA,YACR,QAAQ,gBAAAA,MAAC,cAAW;AAAA,YACpB,eAAe;AAAA;AAAA,QAChB;AAAA,QAIA,WAAW,CAAC,UAAU,CAAC,eAAe,CAAC,gBACvC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACA,QAAQ,gBAAAA,MAAC,cAAW;AAAA,YACpB,QAAQ,CAAC,MAAM,UAAU;AACxB,4BAAc,IAAI;AAClB,gCAAkB;AAClB,yBAAW,MAAM;AAChB,0BAAU,WAAW,KAAK,EAAE;AAC5B,qCAAqB,IAAI;AACzB,2BAAW,gBAAgB;AAAA,cAC5B,GAAG,EAAE;AAAA,YACN;AAAA;AAAA,QACD;AAAA,QAID,gBAAAA,MAAC,sBAAmB;AAAA,QAOnB,WAAW,CAAC,gBAAgB,CAAC,gBAAgB,WAC7C,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACA,KAAK;AAAA,YACL,MAAK;AAAA,YACL,WAAW;AAAA,cACV;AAAA,cACA,cAAc,WAAW;AAAA,cACzB,kBAAkB,SAAS,uBAAuB,aAAa,KAAK;AAAA,cACpE,SAAS,oBAAoB;AAAA,cAC5B,aAAa,mBAAmB,aAAa,aAAa,SAAS,UAAW,sBAAsB;AAAA,YACtG,EACE,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,YACV,SAAS;AAAA,YACT,cAAY,SAAS,EAAE,2BAA2B,IAAI,EAAE,kBAAkB;AAAA,YAC1E,iBAAe;AAAA,YACf,iBAAc;AAAA,YAEd;AAAA,8BAAAD;AAAA,gBAAC;AAAA;AAAA,kBACA,WAAW,sCAAsC,SAAS,2BAA2B,EAAE;AAAA,kBAEvF,0BAAAA,MAAC,gBAAa;AAAA;AAAA,cACf;AAAA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACA,WAAW,wCAAwC,CAAC,SAAS,2BAA2B,EAAE;AAAA,kBAE1F,0BAAAA,MAAC,SAAM,MAAM,IAAI;AAAA;AAAA,cAClB;AAAA,cACC,kBAAkB,UAAU,CAAC,UAC7B,gBAAAA,MAAC,UAAK,WAAU,mBACd,4BAAkB,SAAS,EAAE,aAAa,IAAI,aAChD;AAAA,cAEA,CAAC,WAAW,cAAc,KAAK,0BAA0B,MACzD,gBAAAC,OAAC,SAAI,WAAU,mBACb;AAAA,8BAAc,IAAI,cAAc;AAAA,gBAChC,gBAAgB,KAAK,0BAA0B,KAC/C,gBAAAD,MAAC,UAAK,WAAU,uBAAsB;AAAA,iBAExC;AAAA;AAAA;AAAA,QAEF;AAAA;AAAA;AAAA,EAEF;AAEF;AAIA,SAAS,OAAO;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,0BAA0B;AAC3B,GAOG;AACF,SACC,gBAAAC,OAAC,SAAI,WAAU,WAAU,MAAK,WAC7B;AAAA,oBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAW,gBAAgB,cAAc,SAAS,yBAAyB,EAAE;AAAA,QAC7E,SAAS,MAAM,YAAY,MAAM;AAAA,QACjC,MAAK;AAAA,QACL,iBAAe,cAAc;AAAA,QAE7B;AAAA,0BAAAD,MAAC,YAAS;AAAA,UACV,gBAAAA,MAAC,UAAM,YAAE,aAAa,GAAE;AAAA;AAAA;AAAA,IACzB;AAAA,IACC,mBACA,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAW,gBAAgB,cAAc,aAAa,yBAAyB,EAAE;AAAA,QACjF,SAAS,MAAM,YAAY,UAAU;AAAA,QACrC,MAAK;AAAA,QACL,iBAAe,cAAc;AAAA,QAE7B;AAAA,0BAAAA,OAAC,UAAK,WAAU,qBACf;AAAA,4BAAAD,MAAC,gBAAa;AAAA,YACb,cAAc,KACd,gBAAAA,MAAC,UAAK,WAAU,iBAAiB,wBAAc,KAAK,QAAQ,aAAY;AAAA,aAE1E;AAAA,UACA,gBAAAA,MAAC,UAAM,YAAE,iBAAiB,GAAE;AAAA;AAAA;AAAA,IAC7B;AAAA,IAGA,YAAY,IAAI,CAAC,QACjB,gBAAAC;AAAA,MAAC;AAAA;AAAA,QAEA,MAAK;AAAA,QACL,WAAW,gBAAgB,cAAc,WAAW,IAAI,EAAE,KAAK,yBAAyB,EAAE;AAAA,QAC1F,SAAS,MAAM,YAAY,WAAW,IAAI,EAAE,EAAE;AAAA,QAC9C,MAAK;AAAA,QACL,iBAAe,cAAc,WAAW,IAAI,EAAE;AAAA,QAE9C;AAAA,0BAAAA,OAAC,UAAK,WAAU,qBACf;AAAA,4BAAAD,MAAC,2BAAwB,MAAM,IAAI,MAAM;AAAA,YACxC,IAAI,mBAAmB,0BAA0B,KACjD,gBAAAA,MAAC,UAAK,WAAU,eAAc;AAAA,aAEhC;AAAA,UACA,gBAAAA,MAAC,UAAM,UAAAE,cAAa,IAAI,KAAK,GAAE;AAAA;AAAA;AAAA,MAb1B,IAAI;AAAA,IAcV,CACA;AAAA,KACF;AAEF;AAIA,SAAS,SAAS;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACD,GAIG;AACF,QAAM,SAAS,cAAc,MAAM,GAAG,CAAC;AACvC,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,SACC,gBAAAD,OAAC,SAAI,WAAU,kBACd;AAAA,oBAAAD,MAAC,SAAI,WAAU,oBAAoB,YAAE,6BAA6B,GAAE;AAAA,IACnE,OAAO,IAAI,CAAC,MAAM,MAClB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEA,cAAc;AAAA,QACd;AAAA,QACA,QAAQ,MAAM,OAAO,SAAS;AAAA;AAAA,MAHzB,KAAK;AAAA,IAIX,CACA;AAAA,IACA,cAAc,SAAS,KACvB,gBAAAA,MAAC,YAAO,MAAK,UAAS,WAAU,qBAAoB,SAAS,iBAC3D,YAAE,gBAAgB,GACpB;AAAA,KAEF;AAEF;AAIA,SAAS,aAAa;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AACD,GAIG;AACF,MAAI,cAAc,WAAW,GAAG;AAC/B,WACC,gBAAAC,OAAC,SAAI,WAAU,kBACd;AAAA,sBAAAD,MAAC,SAAI,WAAU,sBACd,0BAAAA,MAAC,gBAAa,GACf;AAAA,MACA,gBAAAA,MAAC,SAAI,WAAU,kBAAkB,YAAE,oBAAoB,GAAE;AAAA,MACzD,gBAAAA,MAAC,SAAI,WAAU,iBAAiB,YAAE,yBAAyB,GAAE;AAAA,MAC7D,gBAAAA,MAAC,YAAO,MAAK,UAAS,WAAU,gBAAe,SAAS,YACtD,YAAE,2BAA2B,GAC/B;AAAA,OACD;AAAA,EAEF;AAEA,SACC,gBAAAA,MAAC,SAAI,WAAU,eACb,wBAAc,IAAI,CAAC,SACnB,gBAAAA,MAAC,oBAA+B,cAAc,MAAM,YAA7B,KAAK,EAA4C,CACxE,GACF;AAEF;AAIA,SAAS,aAAa,EAAE,KAAK,GAAkC;AAC9D,QAAM,YAAY,eAAe,CAAC,MAAM,EAAE,aAAa,IAAI,KAAK;AAChE,QAAM,SAAS,KAAK,0BAA0B,UAAU,KAAK;AAC7D,QAAM,cAAc,SAAS,KAAK,wBAAyB;AAC3D,QAAM,UAAU,KAAK,mBAAmB,EAAE,mBAAmB;AAC7D,SACC,gBAAAC,OAAAF,WAAA,EACC;AAAA,oBAAAC,MAAC,SAAI,WAAW,sBAAsB,SAAS,+BAA+B,EAAE,IAC9E,mBACA,KAAK,yBACJ,gBAAAA,MAAC,SAAI,KAAK,KAAK,wBAAwB,KAAK,aAAa,WAAU,2BAA0B,IAE7F,gBAAAA,MAAC,UAAK,WAAU,gCACd,sBAAY,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,GAAG,CAAC,EAAE,YAAY,GAC3E,IAGD,gBAAAA,MAAC,cAAW,GAEd;AAAA,IACA,gBAAAC,OAAC,SAAI,WAAU,wBACd;AAAA,sBAAAA,OAAC,SAAI,WAAU,oBACd;AAAA,wBAAAD,MAAC,UAAK,WAAU,qBAAqB,uBAAY;AAAA,QAChD,KAAK,iBACL,gBAAAA,MAAC,UAAK,WAAU,qBAAqB,6BAAmB,KAAK,aAAa,GAAE;AAAA,SAE9E;AAAA,MACA,gBAAAA,MAAC,SAAI,WAAU,wBAAwB,mBAAQ;AAAA,OAChD;AAAA,KACD;AAEF;AAIA,SAAS,iBAAiB;AAAA,EACzB,cAAc;AAAA,EACd;AACD,GAGG;AACF,QAAM,YAAY,KAAK,cAAc;AAErC,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,MAAK;AAAA,MACL,WAAW,gBAAgB,YAAY,yBAAyB,EAAE;AAAA,MAClE,SAAS,MAAM,SAAS,KAAK,EAAE;AAAA,MAE/B;AAAA,wBAAAD,MAAC,SAAI,WAAU,oBACd,0BAAAA,MAAC,gBAAa,MAAY,GAC3B;AAAA,QACC,aAAa,gBAAAA,MAAC,SAAI,WAAU,sBAAsB,eAAK,aAAY;AAAA;AAAA;AAAA,EACrE;AAEF;AAIA,SAAS,gBAAgB;AAAA,EACxB,cAAc;AAAA,EACd;AAAA,EACA;AACD,GAIG;AACF,QAAM,YAAY,KAAK,cAAc;AAErC,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,MAAK;AAAA,MACL,WAAW,iBAAiB,YAAY,0BAA0B,EAAE,IAAI,SAAS,wBAAwB,EAAE;AAAA,MAC3G,SAAS,MAAM,SAAS,KAAK,EAAE;AAAA,MAE/B;AAAA,wBAAAD,MAAC,gBAAa,MAAY;AAAA,QACzB,aAAa,gBAAAA,MAAC,SAAI,WAAU,uBAAuB,eAAK,aAAY;AAAA;AAAA;AAAA,EACtE;AAEF;AAIA,SAAS,kBAAkB,EAAE,eAAe,GAAgC;AAC3E,QAAM,EAAE,QAAQ,MAAM,IAAI,iBAAiB;AAC3C,QAAM,gBAAgB,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAClE,QAAM,CAAC,OAAO,QAAQ,IAAII,WAAS,EAAE;AACrC,QAAM,CAAC,cAAc,eAAe,IAAIA,WAAS,KAAK;AACtD,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAS,KAAK;AAChD,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAS,KAAK;AAE9C,QAAM,eAAe,YAAY;AAChC,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,CAAC,WAAW,CAAC,6BAA6B,KAAK,OAAO,GAAG;AAC5D,kBAAY,IAAI;AAChB;AAAA,IACD;AACA,gBAAY,KAAK;AAEjB,UAAM,kBAAkB,MAAM,SAAS,EAAE,SAAS,WAAW;AAC7D,UAAM,sBAAsB,iBAAiB,MAAM,sBAAsB,KAAK,IAAI,CAAC;AACnF,kBAAc;AAAA,MACb,IAAI;AAAA,MACJ,MAAM,iBAAiB,QAAQ;AAAA,MAC/B,OAAO;AAAA,IACR,CAAC;AACD,iBAAa,IAAI;AACjB,oBAAgB,IAAI;AACpB,QAAI;AACH,YAAM,SAAS,MAAM,OAAO,OAAO,aAAa,OAAO;AAAA,QACtD,OAAO;AAAA,QACP,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;AAAA,MAC5C,CAAC;AACD,UAAI,OAAO,SAAS;AACnB,sBAAc;AAAA,UACb,IAAI,OAAO,QAAQ;AAAA,UACnB,MAAM,OAAO,QAAQ;AAAA,UACrB,OAAO,OAAO,QAAQ;AAAA,QACvB,CAAC;AAAA,MACF;AAAA,IAED,QAAQ;AACP,UAAI,iBAAiB;AACpB,sBAAc,eAAe;AAAA,MAC9B,OAAO;AACN,sBAAc,EAAE,IAAI,IAAI,MAAM,MAAM,OAAO,KAAK,CAAC;AAAA,MAClD;AACA,mBAAa,KAAK;AAAA,IACnB,UAAE;AACD,sBAAgB,KAAK;AAAA,IACtB;AAAA,EACD;AAEA,MAAI,WAAW;AACd,WACC,gBAAAH,OAAC,SAAI,WAAU,wCACd;AAAA,sBAAAD,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,WAAU,aAAa,KAAK,eAAc,SAAQ,gBAAe,SACnI,0BAAAA,MAAC,cAAS,QAAO,kBAAiB,GACnC;AAAA,MACC,EAAE,oBAAoB;AAAA,OACxB;AAAA,EAEF;AAOA,SACC,gBAAAC,OAAC,SAAI,WAAU,iBACd;AAAA,oBAAAD,MAAC,OAAE,WAAU,uBAAuB,YAAE,oBAAoB,GAAE;AAAA,IAC5D,gBAAAA,MAAC,OAAE,WAAU,0BAA0B,YAAE,uBAAuB,GAAE;AAAA,IAClE,gBAAAC,OAAC,SAAI,WAAU,qBACd;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAW,sBAAsB,WAAW,gCAAgC,EAAE;AAAA,UAC9E,OAAO;AAAA,UACP,UAAU,CAAC,MAAM;AAAE,qBAAS,EAAE,OAAO,KAAK;AAAG,wBAAY,KAAK;AAAA,UAAG;AAAA,UACjE,WAAW,CAAC,MAAM;AAAE,gBAAI,EAAE,QAAQ,QAAS,cAAa;AAAA,UAAG;AAAA,UAC3D,aAAa,EAAE,0BAA0B;AAAA;AAAA,MAC1C;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS;AAAA,UACT,UAAU,gBAAgB,CAAC,MAAM,KAAK;AAAA,UACtC,cAAY,EAAE,uBAAuB;AAAA,UAEpC,yBACA,gBAAAA,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,GAAG,eAAY,QAC7G,0BAAAA,MAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK,iBAAgB,MAAK,kBAAiB,MACpE,0BAAAA,MAAC,aAAQ,eAAc,qBAAoB,QAAO,QAAO,KAAI,MAAK,aAAY,cAAa,GAC5F,GACD,IAEA,gBAAAA,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,KAAK,eAAc,SAAQ,gBAAe,SAAQ,eAAY,QAC5J,0BAAAA,MAAC,UAAK,GAAE,yBAAwB,GACjC;AAAA;AAAA,MAEF;AAAA,OACD;AAAA,KACD;AAEF;AAIA,SAAS,oBAAoB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAMG;AAEF,SACC,gBAAAC,OAAC,SAAI,WAAU,UAOd;AAAA,oBAAAD,MAAC,SAAI,WAAU,kBACd,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACA,MAAM;AAAA,QACN,QAAO;AAAA,QACP,OAAO;AAAA;AAAA,IACR,GACD;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,EAAE,wBAAwB;AAAA;AAAA,IACxC;AAAA,KACD;AAEF;AAIA,SAAS,iBAAiB;AAAA,EACzB;AAAA,EACA;AACD,GAIG;AACF,QAAM,EAAE,OAAO,WAAW,SAAS,SAAS,IAAI,YAAY,cAAc;AAC1E,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI,YAAY,cAAc;AAC9B,QAAM,EAAE,UAAU,gBAAgB,UAAU,IAAI,YAAY,cAAc;AAC1E,QAAM,gBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,IAAI,cAAc,KAAK,EAAE;AACrF,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AACvD,QAAM,iBAAiB,eAAe,CAAC,MAAM,EAAE,SAAS,OAAO;AAO/D,QAAM,eAAe,CAAC,CAAC,UAAU,UAAU,MAAM,UAAU;AAS3D,QAAM,aAAa,eAAe,CAAC,MAAM;AACxC,UAAM,OAAO,EAAE,cAAc,KAAK,CAAC,MAAM,EAAE,OAAO,cAAc;AAChE,WAAO,MAAM,WAAW;AAAA,EACzB,CAAC;AAQD,QAAM,sBAAsB,MAAM;AAAA,IACjC,CAAC,OAAO,GAAG,SAAS,aAAa,QAAS,GAAqC,SAAS;AAAA,EACzF,EAAE;AACF,QAAM,aAAa,MAAM;AAAA,IACxB,CAAC,OAAO,GAAG,SAAS,aAAa,QAAS,GAAqC,SAAS;AAAA,EACzF;AAKA,QAAM,kBAAkB,eAAe,CAAC,MAAM,EAAE,SAAS,KAAK;AAC9D,QAAM,WAAW,CAAC,CAAC,gBAAgB,SAAS,CAAC,CAAC;AAC9C,QAAM,sBACL,CAAC,CAAC,aAAa,uBACf,CAAC,YACD,uBAAuB,KACvB;AACD,QAAM,aAAa,uBAAuB,CAAC,CAAC;AAE5C,MAAI,aAAa,MAAM,WAAW,GAAG;AACpC,WACC,gBAAAA,MAAC,SAAI,WAAU,eACd,0BAAAC,OAAC,SAAI,WAAU,wBAEd;AAAA,sBAAAA,OAAC,SAAI,WAAU,mBACd;AAAA,wBAAAD,MAAC,SAAI,WAAU,kCAAiC;AAAA,QAChD,gBAAAC,OAAC,SAAI,WAAU,sBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,UACrE,gBAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,WACtE;AAAA,SACD;AAAA,MAEA,gBAAAA,MAAC,SAAI,WAAU,0CACd,0BAAAA,MAAC,SAAI,WAAU,sBAAqB,OAAO,EAAE,YAAY,WAAW,GACnE,0BAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG,GACtE,GACD;AAAA,MAEA,gBAAAC,OAAC,SAAI,WAAU,mBACd;AAAA,wBAAAD,MAAC,SAAI,WAAU,kCAAiC;AAAA,QAChD,gBAAAC,OAAC,SAAI,WAAU,sBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,UACrE,gBAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,UACrE,gBAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,GAAG,GAAG;AAAA,WACrE;AAAA,SACD;AAAA,OACD,GACD;AAAA,EAEF;AAEA,SACC,gBAAAC,OAAAF,WAAA,EACC;AAAA,oBAAAC;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe,iBAAiB;AAAA,QAChC;AAAA,QACA,eAAe;AAAA,QACf,YAAY;AAAA,QAYZ,qBACC,cAAc,eACb,gBAAAC,OAAAF,WAAA,EACE;AAAA,wBACA,gBAAAC,MAAC,qBAAkB,gBAAgB,mBAAmB,QAAW;AAAA,UAEjE,gBACA,gBAAAA,MAAC,SAAI,WAAU,eACf,oBAAU,IAAI,CAAC,OAAO,UAAU;AAChC,kBAAM,WAAW,OAAO,UAAU,WAAW,QAAQ,MAAM;AAC3D,kBAAM,QAAQ,OAAO,UAAU,WAAW,OAAO,MAAM;AAOvD,mBACC,gBAAAC;AAAA,cAAC;AAAA;AAAA,gBAEA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,OAAO,EAAE,gBAAgB,GAAG,KAAK,QAAQ,EAAE,KAAK;AAAA,gBAChD,SAAS,MAAM;AACd,uBAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAAA,gBAC/B;AAAA,gBAEA;AAAA,kCAAAA,OAAC,UAAK,WAAU,mBACf;AAAA,oCAAAD,MAAC,UAAK,WAAU,gBAAgB,mBAAS,UAAS;AAAA,oBACjD,SAAS,gBAAAA,MAAC,UAAK,WAAU,gBAAgB,oBAAS;AAAA,qBACpD;AAAA,kBACA,gBAAAA,MAAC,oBAAiB,MAAM,IAAI;AAAA;AAAA;AAAA,cAZvB;AAAA,YAaN;AAAA,UAEA,CAAC,GACF;AAAA,WAEF,IACG;AAAA;AAAA,IAEN;AAAA,IAKC,cAAc,gBAAAA,MAAC,kBAAe,gBAAgC;AAAA,IAC9D,aACA,gBAAAC,OAAC,SAAI,WAAU,iBACb;AAAA;AAAA,MACD,gBAAAD;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS,MAAM;AACd,2BAAe;AACf,mBAAO;AAAA,UACR;AAAA,UAEC,YAAE,cAAc;AAAA;AAAA,MAClB;AAAA,OACD;AAAA,IAED,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA,cAAc;AAAA,QACd,UAAU;AAAA,QACV,UAAU;AAAA,QACV;AAAA,QACA;AAAA,QACA,YAAY;AAAA,QACZ,oBAAoB;AAAA,QACpB,UAAU;AAAA;AAAA,IACX;AAAA,KACD;AAEF;AAIA,SAAS,eAAe,EAAE,eAAe,GAA+B;AACvE,QAAM,EAAE,OAAO,IAAI,iBAAiB;AACpC,QAAM,CAAC,YAAY,aAAa,IAAII,WAAgC,IAAI;AACxE,QAAM,CAAC,eAAe,gBAAgB,IAAIA,WAAS,KAAK;AAExD,QAAM,aAAa,CAAC,WAA2B;AAC9C,kBAAc,MAAM;AACpB,qBAAiB,IAAI;AAErB,WAAO,OAAO,SAAS,OAAO,EAAE,gBAAgB,OAAO,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACzE;AAEA,SACC,gBAAAH,OAAC,SAAI,WAAU,eACd;AAAA,oBAAAD,MAAC,SAAI,WAAU,oBAAoB,YAAE,sBAAsB,GAAE;AAAA,IAC5D,CAAC,gBACD,gBAAAC,OAAC,SAAI,WAAU,WACd;AAAA,sBAAAD,MAAC,SAAI,WAAU,iBAAiB,YAAE,mBAAmB,GAAE;AAAA,MACvD,gBAAAC,OAAC,SAAI,WAAU,mBACd;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACA,MAAK;AAAA,YACL,WAAW,eAAe,eAAe,SAAS,0BAA0B,EAAE;AAAA,YAC9E,SAAS,MAAM,WAAW,MAAM;AAAA,YAChC,cAAY,EAAE,kBAAkB;AAAA,YAChC;AAAA;AAAA,QAED;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACA,MAAK;AAAA,YACL,WAAW,eAAe,eAAe,QAAQ,0BAA0B,EAAE;AAAA,YAC7E,SAAS,MAAM,WAAW,KAAK;AAAA,YAC/B,cAAY,EAAE,iBAAiB;AAAA,YAC/B;AAAA;AAAA,QAED;AAAA,SACD;AAAA,OACD,IAEA,gBAAAA,MAAC,SAAI,WAAU,kBAAkB,YAAE,oBAAoB,GAAE;AAAA,KAE3D;AAEF;AAiBA,SAAS,aAAa;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAKG;AACF,QAAM,SAAS,iBAAiB;AAChC,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,QAAM,UAAU,OAAO,MAAM,GAAG,CAAC;AACjC,QAAM,gBAAgB,IAAI;AAAA,IACzB,iBAAiB,IAAI,CAACQ,OAAM,CAACA,GAAE,IAAIA,GAAE,SAAS,UAAU,CAAC;AAAA,EAC1D;AAEA,SACC,gBAAAP,OAAC,SAAI,WAAU,gBACd;AAAA,oBAAAA,OAAC,SAAI,WAAU,uBACd;AAAA,sBAAAD,MAAC,UAAK,WAAU,sBAAsB,UAAAE,cAAa,kBAAkB,GAAE;AAAA,MACvE,gBAAAD,OAAC,YAAO,MAAK,UAAS,WAAU,yBAAwB,SAAS,WAC/D;AAAA,QAAAC,cAAa,iBAAiB;AAAA,QAAE;AAAA,SAClC;AAAA,OACD;AAAA,IACA,gBAAAF,MAAC,SAAI,WAAU,qBACb,kBAAQ,IAAI,CAAC,UAAU;AACvB,YAAM,aAAa,cAAc,IAAI,MAAM,KAAK;AAChD,aACC,gBAAAC;AAAA,QAAC;AAAA;AAAA,UAEA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS,MAAM,SAAS,MAAM,MAAM,MAAM,KAAK;AAAA,UAE9C;AAAA,0BAAc,MAAM,aAAa,UAAU,KAC3C,gBAAAA,OAAC,SAAI,WAAU,yBACd;AAAA,8BAAAD,MAAC,UAAK,WAAU,sBACd,gBAAM,aAAa,UAAU,GAC/B;AAAA,cACC,MAAM,eACN,gBAAAA,MAAC,UAAK,WAAU,qBACd,6BAAmB,MAAM,WAAW,GACtC;AAAA,eAEF;AAAA,YAED,gBAAAC,OAAC,SAAI,WAAU,2BACb;AAAA,oBAAM;AAAA,cACN,CAAC,cAAc,MAAM,eACrB,gBAAAD,MAAC,UAAK,WAAU,4BACd,6BAAmB,MAAM,WAAW,GACtC;AAAA,eAEF;AAAA,YACC,MAAM,SAAS,MAAM;AACrB,oBAAM,QAAQ,cAAc,MAAM,IAAI;AACtC,qBACC,gBAAAA,MAAC,SAAI,WAAU,0BACb,gBAAM,SAAS,KAAK,GAAG,MAAM,MAAM,GAAG,EAAE,CAAC,WAAM,OACjD;AAAA,YAEF,GAAG;AAAA;AAAA;AAAA,QAhCE,MAAM;AAAA,MAiCZ;AAAA,IAEF,CAAC,GACF;AAAA,KACD;AAEF;;;A2BxjEyB,SAAR,YAA6B,KAAK,EAAE,SAAS,IAAI,CAAC,GAAG;AAC1D,MAAI,CAAC,OAAO,OAAO,aAAa,YAAa;AAE7C,QAAM,OAAO,SAAS,QAAQ,SAAS,qBAAqB,MAAM,EAAE,CAAC;AACrE,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,OAAO;AAEb,MAAI,aAAa,OAAO;AACtB,QAAI,KAAK,YAAY;AACnB,WAAK,aAAa,OAAO,KAAK,UAAU;AAAA,IAC1C,OAAO;AACL,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF,OAAO;AACL,SAAK,YAAY,KAAK;AAAA,EACxB;AAEA,MAAI,MAAM,YAAY;AACpB,UAAM,WAAW,UAAU;AAAA,EAC7B,OAAO;AACL,UAAM,YAAY,SAAS,eAAe,GAAG,CAAC;AAAA,EAChD;AACF;;;ACvB8B,YAAY,gjlGAAsklG;;;ACuKvnlG,gBAAAS,aAAA;AAnCI,SAAS,cAAc;AAAA,EAC7B;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;AAAA,EACA;AAAA;AAAA,EAEA;AACD,GAAuB;AACtB,QAAM,iBAAiB,WAAW,MAAM,IAAI,QAAQ,iBAAiB,EAAE,IAAI;AAE3E,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAEA,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACD;AAAA;AAAA,EACD;AAEF;;;AC/KA,SAAS,aAAAC,mBAAiB;AAenB,SAAS,YAAY,SAAyC;AACpE,QAAM,EAAE,GAAG,IAAI,iBAAiB;AAEhC,EAAAC,YAAU,MAAM;AACf,WAAO,GAAG,QAAQ,OAAO;AAAA,EAC1B,GAAG,CAAC,IAAI,OAAO,CAAC;AACjB;","names":["storageKey","merged","client","store","emitter","ws","identify","api","el","useCallback","useEffect","useRef","useState","useCallback","useEffect","useRef","t","useRef","useEffect","useCallback","useCallback","useState","useState","useCallback","conversationId","useCallback","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","store","useEffect","useState","useState","useEffect","useCallback","useRef","useRef","useCallback","useCallback","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","useCallback","useRef","useState","jsx","jsx","jsx","jsx","jsx","jsx","jsx","jsxs","useRef","useCallback","useState","useEffect","useMemo","useRef","useState","jsx","jsxs","useState","useRef","useEffect","useMemo","useCallback","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect","useCallback","useCallback","useEffect","useCallback","useEffect","useState","EMPTY_TABS","t","useState","useCallback","useEffect","useEffect","useRef","jsx","Fragment","jsx","jsxs","useCallback","useRef","useState","jsx","jsxs","useEffect","useRef","useCallback","useRef","useState","EMPTY_TABS","detailKey","readCache","t","useState","useRef","useCallback","jsx","useEffect","useRef","jsx","useEffect","useCallback","jsx","useState","jsx","jsxs","useState","useEffect","useRef","useState","Fragment","jsx","jsxs","useRef","useEffect","useState","useEffect","useRef","jsx","jsxs","useRef","useEffect","useEffect","useState","Fragment","jsx","jsxs","useState","useEffect","Fragment","jsx","jsxs","resolveLabel","c","useState","useEffect","useRef","useCallback","t","jsx","useEffect","useEffect"]}
1
+ {"version":3,"sources":["../../widget-core/src/client.ts","../../widget-core/src/visitor-id.ts","../../types/src/model-registry.ts","../../types/src/realtime-events.ts","../../types/src/doc-nav-icons.ts","../../widget-core/src/version.ts","../../widget-core/src/ws.ts","../../widget-core/src/store.ts","../../widget-core/src/i18n.ts","../../widget-core/src/utils.ts","../../widget-core/src/api.ts","../../widget-core/src/theme.ts","../../widget-core/src/events.ts","../../widget-core/src/page-tracker.ts","../src/provider.tsx","../src/themed/default-widget.tsx","../src/hooks/use-announcements.ts","../src/hooks/use-awaiting-reply.ts","../src/hooks/use-composer.ts","../src/hooks/use-conversations.ts","../src/hooks/use-header-identity.ts","../src/hooks/use-i18n.ts","../src/hooks/use-presence.ts","../src/hooks/use-timeline.ts","../src/hooks/use-unread.ts","../src/hooks/use-widget.ts","../src/shell/docked-bar.tsx","../src/themed/composer.tsx","../src/themed/icons.tsx","../src/themed/announcement-previews.tsx","../src/themed/strip-markdown.ts","../src/themed/content/content-tab-view.tsx","../src/hooks/use-content-tab.ts","../src/themed/content/simple-markdown.tsx","../src/themed/content/content-detail-view.tsx","../src/themed/content/content-list-view.tsx","../src/themed/content/grouped-content-tab-view.tsx","../src/hooks/use-grouped-content-tab.ts","../src/themed/content/tab-icon.tsx","../src/themed/debug-overlay.tsx","../src/themed/message-bubble.tsx","../src/themed/message-list.tsx","../src/themed/message-preview.tsx","#style-inject:#style-inject","../src/themed/styles.css","../src/helpway-widget.tsx","../src/hooks/use-realtime.ts"],"sourcesContent":["import { createTRPCClient, httpBatchLink } from \"@trpc/client\";\nimport { getOrCreateVisitorId } from \"./visitor-id\";\n\n// The real AppRouter lives in apps/api/src/trpc/ but importing it pulls in CF Worker\n// source files. We type the client as `any` here — real type safety is in the\n// Zustand store (widget-react). The tRPC link config is the same at runtime.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type WidgetClient = any;\n\n/**\n * Create a tRPC vanilla client for widget API calls.\n *\n * Visitor identity uses a dual strategy:\n * 1. X-Visitor-Id header (localStorage-based) — always works, even cross-origin\n * 2. hw_visitor cookie (server-set) — additional persistence layer\n *\n * This ensures visitor identity survives 3rd-party cookie blocking\n * (Safari ITP, Firefox ETP, Chrome Privacy Sandbox).\n */\nexport function createWidgetClient(config: {\n\tapiUrl: string;\n\tapiKey: string;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n}): any {\n\treturn createTRPCClient({\n\t\tlinks: [\n\t\t\thttpBatchLink({\n\t\t\t\turl: `${config.apiUrl}/trpc`,\n\t\t\t\theaders() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t\"X-Public-Key\": config.apiKey,\n\t\t\t\t\t\t\"X-Visitor-Id\": getOrCreateVisitorId(config.apiKey),\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tfetch(url, options) {\n\t\t\t\t\t// credentials: \"include\" sends cookies cross-origin (when not blocked)\n\t\t\t\t\treturn globalThis.fetch(url, { ...options, credentials: \"include\" });\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t});\n}\n","/**\n * Per-site visitor identity storage (localStorage).\n *\n * Matches Intercom's `intercom-id-[app_id]` pattern — each publicKey gets\n * its own localStorage slot so a single browser visiting multiple Helpway\n * workspaces never bleeds identities across them.\n *\n * Storage key: `helpway:visitor:<publicKey-suffix>` (last 16 chars of the key,\n * which is always random — see `generatePublicKey` in apps/api/src/lib/id.ts).\n */\n\nconst PREFIX = \"helpway:visitor\";\nconst LEGACY_KEY = \"helpway:visitor-id\";\n\nfunction keyFor(publicKey: string): string {\n\t// Last 16 chars of publicKey — enough uniqueness (2^80 collision space for nanoid alphabet)\n\t// and keeps localStorage key short. Stable for a given site.\n\tconst suffix = publicKey.slice(-16);\n\treturn `${PREFIX}:${suffix}`;\n}\n\nfunction generateId(): string {\n\tconst ts = Date.now().toString(36);\n\tconst rand = Math.random().toString(36).slice(2, 10);\n\treturn `${ts}${rand}`;\n}\n\n/**\n * Get or create a persistent visitor ID scoped to `publicKey`.\n * Returns a stable per-site ID across page loads.\n */\nexport function getOrCreateVisitorId(publicKey: string): string {\n\ttry {\n\t\tconst storageKey = keyFor(publicKey);\n\t\tconst existing = localStorage.getItem(storageKey);\n\t\tif (existing) return existing;\n\n\t\t// One-time migration: if a legacy global key exists AND no per-site key\n\t\t// is set yet, seed this site with it. Keeps returning visitors identified\n\t\t// on their FIRST post-upgrade site load. Subsequent sites get fresh IDs.\n\t\tconst legacy = localStorage.getItem(LEGACY_KEY);\n\t\tif (legacy) {\n\t\t\tlocalStorage.setItem(storageKey, legacy);\n\t\t\tlocalStorage.removeItem(LEGACY_KEY);\n\t\t\treturn legacy;\n\t\t}\n\n\t\tconst id = generateId();\n\t\tlocalStorage.setItem(storageKey, id);\n\t\treturn id;\n\t} catch {\n\t\t// localStorage unavailable (SSR, private mode, quota exceeded)\n\t\treturn generateId();\n\t}\n}\n\n/** Sync the server-assigned canonical visitor ID back into localStorage. */\nexport function syncVisitorId(publicKey: string, serverVisitorId: string): void {\n\ttry {\n\t\tlocalStorage.setItem(keyFor(publicKey), serverVisitorId);\n\t} catch {\n\t\t// ignore\n\t}\n}\n\n/** Clear the visitor ID for a specific site (used by playground \"simulate anonymous\"). */\nexport function clearVisitorId(publicKey: string): void {\n\ttry {\n\t\tlocalStorage.removeItem(keyFor(publicKey));\n\t} catch {\n\t\t// ignore\n\t}\n}\n","/**\n * The AI models an agent can be configured with — the full catalog\n * `apps/api` accepts writes for (`ai/models.ts` re-exports this) and the\n * only list `apps/dashboard`'s model picker is allowed to build its options\n * from (`components/ai/behavior-content.tsx`).\n *\n * Single source of truth on purpose (helpway#76 follow-up): before this,\n * the dashboard's `MODEL_OPTIONS` and the api's `MODELS` allowlist were two\n * hand-maintained lists that had already drifted — the picker offered\n * `anthropic/claude-sonnet-4` and `google/gemini-2.5-flash`, neither of\n * which the api would accept. `trpc/agent.ts`'s write schema was\n * `z.string().optional()` — anything validated — so a pick outside the\n * allowlist wasn't rejected, it was silently swapped for `DEFAULT_MODEL`\n * server-side with no error surfaced to the admin who chose it. Both sides\n * now read this one object; there is nowhere left for them to disagree.\n *\n * OpenAI only — the stack runs on Azure OpenAI, which serves no other\n * vendor. Ids keep the `openai/` prefix: that's how they're stored in\n * `ai_agent.model` and how OpenRouter (the non-Azure fallback) addresses\n * them; `apps/api/src/ai/provider.ts` strips it for Azure.\n */\nexport const AI_MODELS = {\n\t\"openai/gpt-5.5\": {\n\t\tlabel: \"GPT-5.5\",\n\t\tprovider: \"OpenAI\",\n\t\tmaxTokens: 32768,\n\t},\n\t\"openai/gpt-4.1\": {\n\t\tlabel: \"GPT-4.1\",\n\t\tprovider: \"OpenAI\",\n\t\tmaxTokens: 32768,\n\t},\n\t\"openai/gpt-4.1-mini\": {\n\t\tlabel: \"GPT-4.1 Mini\",\n\t\tprovider: \"OpenAI\",\n\t\tmaxTokens: 32768,\n\t},\n\t\"openai/gpt-4o\": {\n\t\tlabel: \"GPT-4o\",\n\t\tprovider: \"OpenAI\",\n\t\tmaxTokens: 4096,\n\t},\n\t\"openai/gpt-4o-mini\": {\n\t\tlabel: \"GPT-4o Mini\",\n\t\tprovider: \"OpenAI\",\n\t\tmaxTokens: 4096,\n\t},\n} as const;\n\nexport type AiModelId = keyof typeof AI_MODELS;\n\n/** Non-empty tuple form of the ids — what `z.enum()` needs. Derived, not\n * hand-maintained, so a new entry in `AI_MODELS` above is automatically\n * both an accepted write and an offered dashboard option. */\nexport const AI_MODEL_IDS = Object.keys(AI_MODELS) as [AiModelId, ...AiModelId[]];\n\n/** True when `id` is one of the curated ids this registry recognises.\n * `apps/api/src/ai/models.ts` `isModelId` wraps this for its existing\n * consumers; the dashboard uses it directly to keep from re-displaying (and\n * re-submitting) a stale id an agent row was saved with before this\n * allowlist existed — `ai_agent.model`'s own column default is\n * `\"anthropic/claude-sonnet-4\"`, itself outside this registry. */\nexport function isAiModelId(id: string): id is AiModelId {\n\treturn Object.hasOwn(AI_MODELS, id);\n}\n\n/**\n * What a new agent gets, and what the pipeline falls back to when\n * `agent.model` is empty or names something outside this registry\n * (`apps/api/src/ai/models.ts` `resolveAgentModel`). Also the fallback the\n * dashboard's model picker resolves to before an agent has ever saved a\n * choice — it used to be a literal `\"anthropic/claude-sonnet-4\"`, an id\n * outside this same registry.\n */\nexport const DEFAULT_AI_MODEL_ID: AiModelId = \"openai/gpt-5.5\";\n","import type { Conversation } from \"./conversation\";\nimport type { TimelineItem } from \"./timeline-item\";\n\n// ── Event type constants ─────────────────────────────────\n\nexport const WsEventType = {\n\tConnectionEstablished: \"connectionEstablished\",\n\tConversationCreated: \"conversationCreated\",\n\tConversationUpdated: \"conversationUpdated\",\n\tTimelineItemCreated: \"timelineItemCreated\",\n\tTimelineItemUpdated: \"timelineItemUpdated\",\n\tTimelineItemDeleted: \"timelineItemDeleted\",\n\tConversationSeen: \"conversationSeen\",\n\tConversationTyping: \"conversationTyping\",\n\tAiProcessingProgress: \"aiProcessingProgress\",\n\tAiProcessingCompleted: \"aiProcessingCompleted\",\n\tAiStreamChunk: \"aiStreamChunk\",\n\tVisitorPresenceChanged: \"visitorPresenceChanged\",\n\tMemberUpdated: \"memberUpdated\",\n\tWorkspaceUnreadCounts: \"workspaceUnreadCounts\",\n} as const;\n\n// ── Union of all realtime events ──────────────────────────\n\nexport type RealtimeEvent =\n\t| ConnectionEstablishedEvent\n\t| ConversationCreatedEvent\n\t| ConversationUpdatedEvent\n\t| TimelineItemCreatedEvent\n\t| TimelineItemUpdatedEvent\n\t| TimelineItemDeletedEvent\n\t| ConversationSeenEvent\n\t| ConversationTypingEvent\n\t| AiProcessingProgressEvent\n\t| AiProcessingCompletedEvent\n\t| AiStreamChunkEvent\n\t| VisitorPresenceChangedEvent\n\t| MemberUpdatedEvent\n\t| WorkspaceUnreadCountsEvent;\n\n// ── Connection ────────────────────────────────────────────\n\nexport interface ConnectionEstablishedEvent {\n\ttype: \"connectionEstablished\";\n\tconnectionId: string;\n}\n\n// ── Conversation lifecycle ────────────────────────────────\n\nexport interface ConversationCreatedEvent {\n\ttype: \"conversationCreated\";\n\tconversation: Conversation;\n}\n\nexport interface ConversationUpdatedEvent {\n\ttype: \"conversationUpdated\";\n\tconversationId: string;\n\tupdates: Partial<Conversation>;\n}\n\n// ── Timeline items ────────────────────────────────────────\n\nexport interface TimelineItemCreatedEvent {\n\ttype: \"timelineItemCreated\";\n\tconversationId: string;\n\titem: TimelineItem;\n}\n\nexport interface TimelineItemUpdatedEvent {\n\ttype: \"timelineItemUpdated\";\n\tconversationId: string;\n\titem: TimelineItem;\n}\n\nexport interface TimelineItemDeletedEvent {\n\ttype: \"timelineItemDeleted\";\n\tconversationId: string;\n\titemId: string;\n}\n\n// ── Presence / read receipts ──────────────────────────────\n\nexport interface ConversationSeenEvent {\n\ttype: \"conversationSeen\";\n\tconversationId: string;\n\tuserId?: string;\n\tvisitorId?: string;\n\tlastSeenAt: string;\n}\n\nexport interface ConversationTypingEvent {\n\ttype: \"conversationTyping\";\n\tconversationId: string;\n\tuserId?: string;\n\tvisitorId?: string;\n\tisTyping: boolean;\n}\n\n// ── AI processing indicators ──────────────────────────────\n\nexport interface AiProcessingProgressEvent {\n\ttype: \"aiProcessingProgress\";\n\tconversationId: string;\n\tphase: \"thinking\" | \"searching\" | \"responding\";\n}\n\nexport interface AiProcessingCompletedEvent {\n\ttype: \"aiProcessingCompleted\";\n\tconversationId: string;\n\tstatus: \"success\" | \"error\" | \"skipped\";\n}\n\nexport interface AiStreamChunkEvent {\n\ttype: \"aiStreamChunk\";\n\tconversationId: string;\n\t/** Incremental text delta — widget appends to the streaming bubble. */\n\tdelta: string;\n\t/** True when this is the final chunk — widget should finalize the bubble. */\n\tdone: boolean;\n}\n\n// ── Visitor presence ─────────────────────────────────────\n\nexport interface VisitorPresenceChangedEvent {\n\ttype: \"visitorPresenceChanged\";\n\tvisitorId: string;\n\tstatus: \"online\" | \"offline\";\n}\n\n// ── Organization team ────────────────────────────────────\n\nexport interface MemberUpdatedEvent {\n\ttype: \"memberUpdated\";\n\taction: \"added\" | \"removed\" | \"roleChanged\";\n\tmemberId: string;\n}\n\n// ── Workspace meta events ───────────────────────────────\n\nexport interface WorkspaceUnreadCountsEvent {\n\ttype: \"workspaceUnreadCounts\";\n\tcounts: Record<string, number>;\n}\n\n// ── Event type guard helper ───────────────────────────────\n\nexport function isRealtimeEvent(data: unknown): data is RealtimeEvent {\n\treturn (\n\t\ttypeof data === \"object\" &&\n\t\tdata !== null &&\n\t\t\"type\" in data &&\n\t\ttypeof (data as RealtimeEvent).type === \"string\"\n\t);\n}\n","/**\n * Single source of truth for the docs/help-center sidebar nav icon allowlist.\n *\n * Shared so the content portal (dashboard) and the public content-site never\n * drift: the portal lists/validates these names, the content-site renders them.\n * Stored as structured primitives (not raw SVG markup) so consumers render real\n * SVG elements — no `dangerouslySetInnerHTML`, no XSS surface, no React in this\n * (types) package. Each consumer wraps these in its own `<svg viewBox=\"0 0 24\n * 24\" stroke=\"currentColor\" stroke-width=\"1.75\">`.\n *\n * Authors may still set a raw `<svg>` string instead of a name (rendered by the\n * content-site through an <img> data-URI); this allowlist is the curated set.\n */\n\nexport type DocNavIconShape =\n\t| { t: \"path\"; d: string }\n\t| { t: \"polyline\"; points: string }\n\t| { t: \"polygon\"; points: string }\n\t| { t: \"circle\"; cx: number; cy: number; r: number }\n\t| { t: \"rect\"; x: number; y: number; width: number; height: number; rx?: number }\n\t| { t: \"line\"; x1: number; y1: number; x2: number; y2: number };\n\nexport interface DocNavIcon {\n\t/** Stable key authors type (lowercase). */\n\tname: string;\n\t/** Human label for a picker. */\n\tlabel: string;\n\tshapes: DocNavIconShape[];\n}\n\nexport const DOC_NAV_ICONS: DocNavIcon[] = [\n\t{\n\t\tname: \"globe\",\n\t\tlabel: \"Globe\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 12, cy: 12, r: 10 },\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"code\",\n\t\tlabel: \"Code\",\n\t\tshapes: [\n\t\t\t{ t: \"polyline\", points: \"16 18 22 12 16 6\" },\n\t\t\t{ t: \"polyline\", points: \"8 6 2 12 8 18\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"book\",\n\t\tlabel: \"Book\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M4 19.5A2.5 2.5 0 0 1 6.5 17H20\" },\n\t\t\t{ t: \"path\", d: \"M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"rocket\",\n\t\tlabel: \"Rocket\",\n\t\tshapes: [\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"terminal\",\n\t\tlabel: \"Terminal\",\n\t\tshapes: [\n\t\t\t{ t: \"polyline\", points: \"4 17 10 11 4 5\" },\n\t\t\t{ t: \"line\", x1: 12, y1: 19, x2: 20, y2: 19 },\n\t\t],\n\t},\n\t{\n\t\tname: \"smartphone\",\n\t\tlabel: \"Smartphone\",\n\t\tshapes: [\n\t\t\t{ t: \"rect\", x: 5, y: 2, width: 14, height: 20, rx: 2 },\n\t\t\t{ t: \"line\", x1: 12, y1: 18, x2: 12.01, y2: 18 },\n\t\t],\n\t},\n\t{\n\t\tname: \"server\",\n\t\tlabel: \"Server\",\n\t\tshapes: [\n\t\t\t{ t: \"rect\", x: 2, y: 2, width: 20, height: 8, rx: 2 },\n\t\t\t{ t: \"rect\", x: 2, y: 14, width: 20, height: 8, rx: 2 },\n\t\t\t{ t: \"line\", x1: 6, y1: 6, x2: 6.01, y2: 6 },\n\t\t\t{ t: \"line\", x1: 6, y1: 18, x2: 6.01, y2: 18 },\n\t\t],\n\t},\n\t{\n\t\tname: \"key\",\n\t\tlabel: \"Key\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 7.5, cy: 15.5, r: 5.5 },\n\t\t\t{ t: \"path\", d: \"m21 2-9.6 9.6M16 6l4 4\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"puzzle\",\n\t\tlabel: \"Puzzle\",\n\t\tshapes: [\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M19.439 7.85c-.049.322.059.648.289.878l1.568 1.568c.47.47.706 1.087.706 1.704s-.235 1.233-.706 1.704l-1.611 1.611a.98.98 0 0 1-.837.276c-.47-.07-.802-.48-.968-.925a2.501 2.501 0 1 0-3.214 3.214c.446.166.855.497.925.968a.979.979 0 0 1-.276.837l-1.61 1.61a2.404 2.404 0 0 1-1.704.706 2.402 2.402 0 0 1-1.704-.706l-1.568-1.568a1.026 1.026 0 0 0-.877-.29c-.493.074-.84.504-1.02.968a2.5 2.5 0 1 1-3.237-3.237c.464-.18.894-.527.967-1.02a1.026 1.026 0 0 0-.289-.877l-1.568-1.568A2.402 2.402 0 0 1 1.998 12c0-.617.236-1.234.706-1.704L4.28 8.687c.24-.24.581-.353.925-.29.493.074.84.504 1.02.968a2.5 2.5 0 1 0 3.237-3.237c-.464-.18-.894-.527-.967-1.02a1.026 1.026 0 0 1 .289-.877l1.568-1.568A2.402 2.402 0 0 1 12 1.998c.617 0 1.234.236 1.704.706l1.568 1.568c.23.23.556.338.877.29.493-.074.84-.504 1.02-.968a2.5 2.5 0 1 1 3.237 3.237c-.18.464-.527.894-1.02.968z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"file\",\n\t\tlabel: \"File\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" },\n\t\t\t{ t: \"polyline\", points: \"14 2 14 8 20 8\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"settings\",\n\t\tlabel: \"Settings\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 12, cy: 12, r: 3 },\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"zap\",\n\t\tlabel: \"Zap\",\n\t\tshapes: [{ t: \"polygon\", points: \"13 2 3 14 12 14 11 22 21 10 12 10 13 2\" }],\n\t},\n\t{\n\t\tname: \"layers\",\n\t\tlabel: \"Layers\",\n\t\tshapes: [\n\t\t\t{ t: \"polygon\", points: \"12 2 2 7 12 12 22 7 12 2\" },\n\t\t\t{ t: \"polyline\", points: \"2 17 12 22 22 17\" },\n\t\t\t{ t: \"polyline\", points: \"2 12 12 17 22 12\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"plug\",\n\t\tlabel: \"Plug\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M12 22v-5\" },\n\t\t\t{ t: \"path\", d: \"M9 8V2M15 8V2\" },\n\t\t\t{ t: \"path\", d: \"M18 8v5a6 6 0 0 1-12 0V8z\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"message\",\n\t\tlabel: \"Message\",\n\t\tshapes: [{ t: \"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\t},\n\t{\n\t\tname: \"inbox\",\n\t\tlabel: \"Inbox\",\n\t\tshapes: [\n\t\t\t{ t: \"polyline\", points: \"22 12 16 12 14 15 10 15 8 12 2 12\" },\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"users\",\n\t\tlabel: \"Users\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\" },\n\t\t\t{ t: \"circle\", cx: 9, cy: 7, r: 4 },\n\t\t\t{ t: \"path\", d: \"M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"mail\",\n\t\tlabel: \"Mail\",\n\t\tshapes: [\n\t\t\t{ t: \"rect\", x: 2, y: 4, width: 20, height: 16, rx: 2 },\n\t\t\t{ t: \"path\", d: \"m22 7-10 5L2 7\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"credit-card\",\n\t\tlabel: \"Credit card\",\n\t\tshapes: [\n\t\t\t{ t: \"rect\", x: 1, y: 4, width: 22, height: 16, rx: 2 },\n\t\t\t{ t: \"line\", x1: 1, y1: 10, x2: 23, y2: 10 },\n\t\t],\n\t},\n\t{\n\t\tname: \"sparkles\",\n\t\tlabel: \"Sparkles\",\n\t\tshapes: [\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"m12 3-1.9 5.8a2 2 0 0 1-1.3 1.3L3 12l5.8 1.9a2 2 0 0 1 1.3 1.3L12 21l1.9-5.8a2 2 0 0 1 1.3-1.3L21 12l-5.8-1.9a2 2 0 0 1-1.3-1.3z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"bell\",\n\t\tlabel: \"Bell\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9\" },\n\t\t\t{ t: \"path\", d: \"M10.3 21a1.94 1.94 0 0 0 3.4 0\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"search\",\n\t\tlabel: \"Search\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 11, cy: 11, r: 8 },\n\t\t\t{ t: \"path\", d: \"m21 21-4.3-4.3\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"wrench\",\n\t\tlabel: \"Wrench\",\n\t\tshapes: [\n\t\t\t{\n\t\t\t\tt: \"path\",\n\t\t\t\td: \"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z\",\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: \"shield\",\n\t\tlabel: \"Shield\",\n\t\tshapes: [\n\t\t\t{ t: \"path\", d: \"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\" },\n\t\t\t{ t: \"path\", d: \"m9 12 2 2 4-4\" },\n\t\t],\n\t},\n\t{\n\t\tname: \"lifebuoy\",\n\t\tlabel: \"Life buoy\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 12, cy: 12, r: 10 },\n\t\t\t{ t: \"circle\", cx: 12, cy: 12, r: 4 },\n\t\t\t{ t: \"line\", x1: 4.93, y1: 4.93, x2: 9.17, y2: 9.17 },\n\t\t\t{ t: \"line\", x1: 14.83, y1: 14.83, x2: 19.07, y2: 19.07 },\n\t\t\t{ t: \"line\", x1: 14.83, y1: 9.17, x2: 19.07, y2: 4.93 },\n\t\t\t{ t: \"line\", x1: 4.93, y1: 19.07, x2: 9.17, y2: 14.83 },\n\t\t],\n\t},\n\t{\n\t\tname: \"chart\",\n\t\tlabel: \"Chart\",\n\t\tshapes: [\n\t\t\t{ t: \"line\", x1: 12, y1: 20, x2: 12, y2: 10 },\n\t\t\t{ t: \"line\", x1: 18, y1: 20, x2: 18, y2: 4 },\n\t\t\t{ t: \"line\", x1: 6, y1: 20, x2: 6, y2: 16 },\n\t\t],\n\t},\n\t{\n\t\tname: \"share\",\n\t\tlabel: \"Share\",\n\t\tshapes: [\n\t\t\t{ t: \"circle\", cx: 18, cy: 5, r: 3 },\n\t\t\t{ t: \"circle\", cx: 6, cy: 12, r: 3 },\n\t\t\t{ t: \"circle\", cx: 18, cy: 19, r: 3 },\n\t\t\t{ t: \"line\", x1: 8.59, y1: 13.51, x2: 15.42, y2: 17.49 },\n\t\t\t{ t: \"line\", x1: 15.41, y1: 6.51, x2: 8.59, y2: 10.49 },\n\t\t],\n\t},\n];\n\n/** Lowercase name set for O(1) validation. */\nexport const DOC_NAV_ICON_NAMES: string[] = DOC_NAV_ICONS.map((i) => i.name);\n\nconst DOC_NAV_ICON_MAP: Record<string, DocNavIcon> = Object.fromEntries(\n\tDOC_NAV_ICONS.map((i) => [i.name, i]),\n);\n\n/**\n * Lucide names the imported docs corpus uses, mapped to the nearest icon we ship.\n *\n * The MDX cards were authored against fumadocs, which passes icon names straight to\n * lucide — so a card can ask for `FileCode` or `WifiOff`, which this allowlist has\n * never heard of. Unresolved, they showed as nothing at best: `Box` is three\n * characters, so it fell through to the emoji branch and the word \"Box\" rendered on\n * the card where its icon belonged.\n *\n * These are deliberate approximations, not a lucide port: the goal is a card that\n * looks intentional, and every entry here is a name that actually appears in the\n * corpus. Add to it when a new name shows up rather than widening the emoji branch.\n */\nconst DOC_NAV_ICON_ALIASES: Record<string, string> = {\n\tfilecode: \"file\",\n\tbookopen: \"book\",\n\tdatabase: \"server\",\n\tbot: \"message\",\n\troute: \"share\",\n\trepeat: \"share\",\n\twifioff: \"plug\",\n\thook: \"plug\",\n\tbox: \"puzzle\",\n\tshoppingcart: \"credit-card\",\n\ttype: \"code\",\n\tcalendar: \"bell\",\n\tpause: \"settings\",\n\tflaskconical: \"wrench\",\n};\n\n/** Resolve a named icon (case-insensitive). Returns undefined for unknown names. */\nexport function getDocNavIcon(name: string): DocNavIcon | undefined {\n\tconst key = name.trim().toLowerCase();\n\treturn DOC_NAV_ICON_MAP[key] ?? DOC_NAV_ICON_MAP[DOC_NAV_ICON_ALIASES[key] ?? \"\"];\n}\n","/**\n * The SDK version the widget announces on its WebSocket hello (helpway#167).\n *\n * Injected at build time by the publishing package's bundler (`define`\n * of `__HELPWAY_SDK_VERSION__` from its package.json); \"dev\" when running\n * from source. The server logs it per connect so the question \"is anyone\n * still on a version before X\" can be answered from logs instead of guessed.\n */\ndeclare const __HELPWAY_SDK_VERSION__: string | undefined;\n\nexport const SDK_VERSION: string =\n\ttypeof __HELPWAY_SDK_VERSION__ === \"string\" && __HELPWAY_SDK_VERSION__.length > 0\n\t\t? __HELPWAY_SDK_VERSION__\n\t\t: \"dev\";\n","import { type RealtimeEvent, isRealtimeEvent } from \"@helpway/types\";\nimport { SDK_VERSION } from \"./version\";\n\nexport type EventHandler = (event: RealtimeEvent) => void;\n\ninterface WebSocketManagerConfig {\n\tapiUrl: string;\n\tvisitorId: string;\n\twebsiteId: string;\n\t/** Public API key — appended as ?key= on the WS upgrade URL so the server\n\t * can authenticate the widget without relying on custom headers (which the\n\t * browser's native WebSocket API does not support). */\n\tapiKey: string;\n}\n\n/**\n * WebSocket connection manager for ChatRoom Durable Object.\n * Handles connect, disconnect, auto-reconnect with exponential backoff,\n * ping/pong keep-alive, and event dispatching.\n *\n * Ping gating — visibility-aware:\n * Ping doubles as a presence heartbeat on the server (refreshes KV\n * presence key with a 150s TTL). When the tab is hidden we pause the\n * ping so a forgotten background tab naturally drops offline within\n * ~2.5 minutes. The socket itself stays open; only the heartbeat stops.\n */\nexport class WebSocketManager {\n\tprivate ws: WebSocket | null = null;\n\tprivate handlers = new Set<EventHandler>();\n\tprivate config: WebSocketManagerConfig;\n\tprivate reconnectAttempts = 0;\n\tprivate maxReconnectAttempts = 10;\n\tprivate reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate pingTimer: ReturnType<typeof setInterval> | null = null;\n\tprivate isDestroyed = false;\n\tprivate visibilityHandler: (() => void) | null = null;\n\n\tconstructor(config: WebSocketManagerConfig) {\n\t\tthis.config = config;\n\t\tthis.setupVisibilityListener();\n\t}\n\n\tprivate setupVisibilityListener(): void {\n\t\tif (typeof document === \"undefined\") return;\n\t\tthis.visibilityHandler = () => {\n\t\t\tif (document.visibilityState === \"hidden\") {\n\t\t\t\t// Tab backgrounded — stop heartbeat so KV TTL drops user offline.\n\t\t\t\tthis.stopPing();\n\t\t\t} else if (this.ws?.readyState === WebSocket.OPEN) {\n\t\t\t\t// Tab visible again — resume heartbeat immediately to restore presence.\n\t\t\t\tthis.startPing();\n\t\t\t\tthis.send({ type: \"ping\" });\n\t\t\t}\n\t\t};\n\t\tdocument.addEventListener(\"visibilitychange\", this.visibilityHandler);\n\t}\n\n\t/** Update connection parameters (call before connect) */\n\tconfigure(params: Partial<WebSocketManagerConfig>): void {\n\t\tObject.assign(this.config, params);\n\t}\n\n\t/** Connect to the ChatRoom Durable Object WebSocket */\n\tconnect(): void {\n\t\tif (this.ws?.readyState === WebSocket.OPEN) return;\n\t\t// Reset destroyed flag — allows reconnect after React StrictMode remount\n\t\tthis.isDestroyed = false;\n\n\t\tconst protocol = this.config.apiUrl.startsWith(\"https\") ? \"wss\" : \"ws\";\n\t\tconst base = this.config.apiUrl.replace(/^https?/, protocol);\n\t\tconst params = new URLSearchParams({\n\t\t\ttype: \"visitor\",\n\t\t\tid: this.config.visitorId,\n\t\t\twebsiteId: this.config.websiteId,\n\t\t\tkey: this.config.apiKey,\n\t\t\t// SDK version on the hello (#167): the server logs it per connect.\n\t\t\tv: SDK_VERSION,\n\t\t});\n\n\t\tconst ws = new WebSocket(`${base}/ws?${params}`);\n\n\t\tws.onopen = () => {\n\t\t\tthis.reconnectAttempts = 0;\n\t\t\t// Only start heartbeat if the tab is visible — the visibility\n\t\t\t// listener resumes it automatically when the user returns.\n\t\t\tif (typeof document === \"undefined\" || document.visibilityState === \"visible\") {\n\t\t\t\tthis.startPing();\n\t\t\t}\n\t\t};\n\n\t\tws.onmessage = (event) => {\n\t\t\ttry {\n\t\t\t\tconst data = JSON.parse(event.data as string);\n\t\t\t\tif (data.type === \"pong\") return;\n\t\t\t\tif (isRealtimeEvent(data)) {\n\t\t\t\t\tfor (const handler of this.handlers) {\n\t\t\t\t\t\thandler(data);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Malformed message — ignore\n\t\t\t}\n\t\t};\n\n\t\tws.onclose = () => {\n\t\t\tthis.stopPing();\n\t\t\tthis.ws = null;\n\t\t\tif (!this.isDestroyed) {\n\t\t\t\tthis.scheduleReconnect();\n\t\t\t}\n\t\t};\n\n\t\tws.onerror = () => {\n\t\t\t// onclose will fire after onerror\n\t\t};\n\n\t\tthis.ws = ws;\n\t}\n\n\t/** Disconnect and stop reconnecting */\n\tdisconnect(): void {\n\t\tthis.isDestroyed = true;\n\t\tthis.stopPing();\n\t\tif (this.reconnectTimer) {\n\t\t\tclearTimeout(this.reconnectTimer);\n\t\t\tthis.reconnectTimer = null;\n\t\t}\n\t\tif (this.visibilityHandler && typeof document !== \"undefined\") {\n\t\t\tdocument.removeEventListener(\"visibilitychange\", this.visibilityHandler);\n\t\t\tthis.visibilityHandler = null;\n\t\t}\n\t\tif (this.ws) {\n\t\t\tthis.ws.close(1000, \"Client disconnect\");\n\t\t\tthis.ws = null;\n\t\t}\n\t}\n\n\t/** Send a JSON message through the WebSocket */\n\tsend(data: Record<string, unknown>): void {\n\t\tif (this.ws?.readyState === WebSocket.OPEN) {\n\t\t\tthis.ws.send(JSON.stringify(data));\n\t\t}\n\t}\n\n\t/** Send typing indicator */\n\tsendTyping(conversationId: string, isTyping: boolean): void {\n\t\tthis.send({ type: \"typing\", conversationId, isTyping });\n\t}\n\n\t/** Subscribe to realtime events */\n\tonEvent(handler: EventHandler): () => void {\n\t\tthis.handlers.add(handler);\n\t\treturn () => {\n\t\t\tthis.handlers.delete(handler);\n\t\t};\n\t}\n\n\t/** Check if connected */\n\tget isConnected(): boolean {\n\t\treturn this.ws?.readyState === WebSocket.OPEN;\n\t}\n\n\t// ── Private ──────────────────────────────────────────\n\n\tprivate scheduleReconnect(): void {\n\t\tif (this.reconnectAttempts >= this.maxReconnectAttempts) return;\n\n\t\tconst delay = Math.min(1000 * 2 ** this.reconnectAttempts, 30000);\n\t\tthis.reconnectAttempts++;\n\n\t\tthis.reconnectTimer = setTimeout(() => {\n\t\t\tthis.connect();\n\t\t}, delay);\n\t}\n\n\tprivate startPing(): void {\n\t\tthis.stopPing();\n\t\tthis.pingTimer = setInterval(() => {\n\t\t\tthis.send({ type: \"ping\" });\n\t\t}, 25000);\n\t}\n\n\tprivate stopPing(): void {\n\t\tif (this.pingTimer) {\n\t\t\tclearInterval(this.pingTimer);\n\t\t\tthis.pingTimer = null;\n\t\t}\n\t}\n}\n","import { WsEventType } from \"@helpway/types\";\nimport type { PublicVisitor, RealtimeEvent, TimelineItem } from \"@helpway/types\";\nimport { createStore } from \"zustand/vanilla\";\nimport { previewQuickReplies } from \"./utils\";\n\n// ── Agent Config (from bootstrap) ────────────────────────\n\nexport interface WidgetContentTab {\n\tid: string;\n\tlabel: string;\n\ticon: string;\n\tmodelSlug: string;\n\tdisplay?: {\n\t\tsubtitleField?: string;\n\t\tbadgeField?: string;\n\t\timageField?: string;\n\t\tdateField?: string;\n\t};\n\ttabType?: \"flat\" | \"grouped\";\n\titemsModelSlug?: string;\n\tgroupField?: string;\n\t/** Marks this tab as the \"What's New\" / announcements source.\n\t * Only one tab should have this flag — the first match wins. */\n\tisAnnouncements?: boolean;\n}\n\nexport interface AgentConfig {\n\tid: string;\n\tname: string;\n\tavatarUrl: string | null;\n\tavatarPreset: string | null;\n\twelcomeMessage: string | null;\n\tsubtitleText: string | null;\n\tbrandColor: string;\n\twidgetPosition: \"bottom-right\" | \"bottom-left\";\n\tlauncherStyle: \"icon\" | \"bubble\" | \"help\";\n\t/** Custom image rendered inside the launcher bubble. NULL → fall back\n\t * to the chat-header chain (avatarUrl → avatarPreset → website logo). */\n\tlauncherIconUrl: string | null;\n\tbubbleStyle: \"rounded\" | \"square\" | \"pill\";\n\t/** Show/hide Messages tab in widget footer */\n\tshowMessagesTab: boolean;\n\t/** Require visitor to provide email before starting a conversation */\n\trequireVisitorEmail: boolean;\n\t/** Dynamic content tabs from Better i18n Content CMS integration */\n\tcontentTabs: WidgetContentTab[];\n}\n\n// ── Content Cache ──────────────────────────────────────────\n\nexport interface ContentCacheEntry {\n\tdata: unknown;\n\tts: number;\n}\n\nexport const CONTENT_CACHE_TTL = 5 * 60 * 1000; // 5 minutes\n\n// ── State Shape ──────────────────────────────────────────\n\nexport interface WidgetState {\n\t// Connection\n\tisReady: boolean;\n\tisConnecting: boolean;\n\n\t// Identity\n\tvisitor: PublicVisitor | null;\n\twebsite: { id: string; name: string; domain: string | null; logoUrl: string | null } | null;\n\n\t// Agent config (from bootstrap)\n\tagentConfig: AgentConfig | null;\n\n\t// Conversations\n\tconversations: ConversationSummary[];\n\tactiveConversationId: string | null;\n\n\t// Messages per conversation\n\tmessages: Map<string, TimelineItem[]>;\n\n\t// Presence\n\ttypingUsers: Map<string, boolean>; // conversationId → someone is typing\n\taiProcessing: Map<string, boolean>; // conversationId → AI is processing\n\tstreamingText: Map<string, string>; // conversationId → accumulated streamed text\n\n\t// UI state\n\tisOpen: boolean;\n\tisDismissed: boolean;\n\tview: \"home\" | \"conversation\" | \"new\";\n\n\t// Incoming message preview (shown when widget is closed)\n\tincomingPreview: {\n\t\ttext: string;\n\t\tconversationId: string;\n\t\ttimestamp: number;\n\t\t/** Who sent it. A human reply used to surface under the AI's name\n\t\t * because the card only ever read agentConfig — the event carries\n\t\t * userName/userImage, they were simply dropped here. Null for the AI,\n\t\t * which is the case the agent name is actually right for. */\n\t\tsenderName?: string | null;\n\t\tsenderImage?: string | null;\n\t\tmessages?: Array<{ text: string }>;\n\t\tquickReplies?: {\n\t\t\tstepId: string;\n\t\t\tprompt: string | null;\n\t\t\toptions: Array<{ id: string; label: string }>;\n\t\t};\n\t} | null;\n\n\t// Announcement previews (shown when widget is closed and unseen content exists)\n\t// Multiple previews stack when several isAnnouncements tabs have new content.\n\tannouncementPreviews: Array<{\n\t\ttitle: string;\n\t\tbody: string | null;\n\t\tslug: string;\n\t\ttabId: string;\n\t\tbadge: string | null;\n\t}>;\n\n\t// Number of unseen announcement entries (drives launcher dot + tab badge)\n\tunseenAnnouncementCount: number;\n\n\t// Pre-filled text for new conversation (set via global API)\n\tnewConversationPrefill: string | null;\n\n\t// Pending content-detail open intent — when set, DefaultWidget\n\t// navigates to the matching content tab + entry detail on the next\n\t// render and clears it. Used so consumers rendering anchored\n\t// announcement previews (or any external trigger) can deep-link a\n\t// visitor straight into a specific entry instead of dropping them\n\t// on the home surface. The launcher's onOpen does this internally;\n\t// this field makes the same navigation reachable from outside\n\t// DefaultWidget's local state.\n\tpendingContentDetail: { slug: string; tabId: string } | null;\n\n\t// Content cache (survives tab switches — keyed by request params)\n\tcontentCache: Map<string, ContentCacheEntry>;\n}\n\nexport interface ConversationSummary {\n\tid: string;\n\ttitle: string | null;\n\tstatus: string;\n\tlastMessageText: string | null;\n\tlastMessageAt: string | null;\n\tlastMessageSenderType: string | null;\n\tlastMessageSenderName: string | null;\n\tlastMessageSenderImage: string | null;\n\t/** Display-only fields for the assigned support user. NULL when no\n\t * human is assigned (AI agent is handling). UserId is intentionally\n\t * not exposed — only what the chat header needs to render. */\n\tassigneeName: string | null;\n\tassigneeImage: string | null;\n\tunreadCount: number;\n}\n\n// ── Actions ──────────────────────────────────────────────\n\nexport interface WidgetActions {\n\t// Lifecycle\n\tsetReady(\n\t\tvisitor: WidgetState[\"visitor\"],\n\t\twebsite: WidgetState[\"website\"],\n\t\tagentConfig?: AgentConfig | null,\n\t): void;\n\tsetConnecting(connecting: boolean): void;\n\n\t// Conversations\n\tsetConversations(conversations: ConversationSummary[]): void;\n\taddConversation(conversation: ConversationSummary): void;\n\tsetActiveConversation(id: string | null): void;\n\n\t// Messages\n\tsetMessages(conversationId: string, items: TimelineItem[]): void;\n\taddMessage(conversationId: string, item: TimelineItem): void;\n\t/**\n\t * Replace a message by ID (used by optimistic send — swaps\n\t * temp `optimistic-*` id for the server-confirmed item).\n\t */\n\treplaceMessage(conversationId: string, oldId: string, item: TimelineItem): void;\n\t/** Remove a message by ID (used for optimistic rollback on send failure) */\n\tremoveMessage(conversationId: string, id: string): void;\n\t/**\n\t * Move an optimistic conversation to its server-assigned ID.\n\t * Copies messages + updates activeConversationId + conversations list.\n\t */\n\tremapConversationId(oldId: string, newId: string): void;\n\n\t// Presence\n\tsetTyping(conversationId: string, isTyping: boolean): void;\n\tsetAiProcessing(conversationId: string, processing: boolean): void;\n\tappendStreamChunk(conversationId: string, delta: string, done: boolean): void;\n\t/** Drop a finished stream once its real message is on screen. See appendStreamChunk. */\n\tclearStream(conversationId: string): void;\n\n\t// Identity\n\tupdateVisitorContact(contact: { id: string; name: string | null; email: string | null }): void;\n\n\t// Unread\n\tclearUnread(conversationId: string): void;\n\n\t// UI\n\tsetOpen(open: boolean): void;\n\tsetDismissed(dismissed: boolean): void;\n\tsetView(view: WidgetState[\"view\"]): void;\n\tsetNewConversationPrefill(text: string | null): void;\n\t/** Schedule a deep-link into a specific content entry's detail\n\t * view. DefaultWidget consumes it on the next render — call\n\t * `setOpen(true)` alongside to reveal the panel. Pass `null` to\n\t * clear (DefaultWidget does this automatically once it\n\t * navigates). */\n\tsetPendingContentDetail(value: { slug: string; tabId: string } | null): void;\n\tdismissPreview(): void;\n\n\t// Announcements\n\tsetAnnouncementPreview(preview: WidgetState[\"announcementPreviews\"][number]): void;\n\tdismissAnnouncementPreview(slug?: string): void;\n\tsetUnseenAnnouncementCount(count: number): void;\n\n\t// Content cache\n\tsetContentCache(key: string, data: unknown): void;\n\n\t// Realtime\n\thandleRealtimeEvent(event: RealtimeEvent): void;\n}\n\nexport type WidgetStore = WidgetState & WidgetActions;\n\n// ── Store Factory ────────────────────────────────────────\n\n// Proactive incoming-message previews must survive a page reload —\n// otherwise an agent/AI ping vanishes the moment the visitor refreshes\n// (it lived only in the in-memory store). Persist the single\n// `incomingPreview` field to localStorage; the existing clear paths\n// (setOpen-when-open, dismissPreview) flow through the subscription\n// below, so closing or replying still wipes it. Per-browser only\n// (localStorage) — not cross-device, fine for a transient affordance.\nconst PREVIEW_STORAGE_KEY = \"helpway:incoming-preview\";\n\n/**\n * React key for the bubble that carries an AI answer, streamed or final.\n *\n * The streamed copy and the persisted message are two different objects but one\n * thing on screen, so they have to occupy the same slot in the same keyed list or\n * React tears the first down to build the second. MessageList renders the stream\n * under this key; addMessage hands the arriving item the same one.\n */\nexport function streamingKeyFor(conversationId: string): string {\n\treturn `streaming-${conversationId}`;\n}\n\nfunction loadPersistedPreview(): WidgetStore[\"incomingPreview\"] {\n\tif (typeof window === \"undefined\") return null;\n\ttry {\n\t\tconst raw = window.localStorage.getItem(PREVIEW_STORAGE_KEY);\n\t\treturn raw ? (JSON.parse(raw) as WidgetStore[\"incomingPreview\"]) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction persistPreview(preview: WidgetStore[\"incomingPreview\"]): void {\n\tif (typeof window === \"undefined\") return;\n\ttry {\n\t\tif (preview) {\n\t\t\twindow.localStorage.setItem(PREVIEW_STORAGE_KEY, JSON.stringify(preview));\n\t\t} else {\n\t\t\twindow.localStorage.removeItem(PREVIEW_STORAGE_KEY);\n\t\t}\n\t} catch {\n\t\t// quota / privacy-mode / SSR — non-fatal, preview just won't persist\n\t}\n}\n\n/**\n * The escalation/join event carries its payload as JSON in the item's text:\n * `{action:\"joined\", name, image}` when a specific person took the thread. The\n * unassigned case is a plain sentence (\"Connecting you with a team member…\"), and\n * that is not a handoff to anyone in particular — so only the JSON shape counts.\n */\nfunction parseJoinEvent(text: string): { name: string | null; image: string | null } | null {\n\tif (!text.startsWith(\"{\")) return null;\n\ttry {\n\t\tconst parsed = JSON.parse(text) as {\n\t\t\taction?: string;\n\t\t\tname?: string | null;\n\t\t\timage?: string | null;\n\t\t};\n\t\tif (parsed.action !== \"joined\") return null;\n\t\treturn { name: parsed.name ?? null, image: parsed.image ?? null };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Who, if anyone, has taken this thread — read off the timeline rather than waited\n * for as a separate signal.\n *\n * The obvious place for this was the realtime reducer, and it does not work there:\n * the join event reaches the widget through the timeline refetch that follows the\n * AI's turn, not through a `timelineItemCreated` frame, so a reducer branch never\n * fires. Both paths end in the message list, so the message list is where the\n * handoff is learned. Last join wins — reassignment is a later join.\n */\nfunction latestAssignee(\n\titems: readonly { type?: string | null; text?: string | null }[],\n): { name: string | null; image: string | null } | null {\n\tfor (let i = items.length - 1; i >= 0; i--) {\n\t\tconst item = items[i];\n\t\tif (item?.type !== \"event\" || !item.text) continue;\n\t\tconst joined = parseJoinEvent(item.text);\n\t\tif (joined) return joined;\n\t}\n\treturn null;\n}\n\n/**\n * How long the thinking indicator may stay up with no word from the server.\n *\n * The widget raises it optimistically on send and, until now, could only lower\n * it on a server event. That made the UI's correctness depend on every server\n * exit path remembering to emit one — and the exits kept forgetting: four\n * guards in the AI pipeline, then two more a layer above it in the queue\n * consumer, each leaving the dots spinning for the rest of the session. Fixing\n * them one at a time protects the paths that exist today and nothing else.\n *\n * A ceiling makes the whole class impossible, including the cases no server fix\n * can reach: a worker that dies mid-job, a socket that drops between send and\n * reply, a queue message lost on retry. Measured against a real local run, a\n * plain answer takes about 11s end to end (3s retrieval, 8s generation), and a\n * multi-tool answer more; 45s is comfortably past that, and streamed chunks\n * re-arm it, so a long answer that is visibly arriving is never cut off.\n *\n * When it fires, the indicator simply stops claiming a reply is on its way. It\n * does not invent an error message — whether the visitor should be told\n * something failed is a product decision, not this timer's to make.\n */\nconst AI_INDICATOR_MAX_MS = 45_000;\n\nexport function createWidgetStore() {\n\t/* Keyed by conversation, scoped to this store instance rather than the\n\t module, so two widgets on one page cannot cancel each other's timers. */\n\tconst indicatorWatchdogs = new Map<string, ReturnType<typeof setTimeout>>();\n\tconst clearWatchdog = (conversationId: string) => {\n\t\tconst timer = indicatorWatchdogs.get(conversationId);\n\t\tif (timer !== undefined) {\n\t\t\tclearTimeout(timer);\n\t\t\tindicatorWatchdogs.delete(conversationId);\n\t\t}\n\t};\n\n\tconst store = createStore<WidgetStore>((set, get) => ({\n\t\t// Initial state\n\t\tisReady: false,\n\t\tisConnecting: true,\n\t\tvisitor: null,\n\t\twebsite: null,\n\t\tagentConfig: null,\n\t\tconversations: [],\n\t\tactiveConversationId: null,\n\t\tmessages: new Map(),\n\t\ttypingUsers: new Map(),\n\t\taiProcessing: new Map(),\n\t\tstreamingText: new Map(),\n\t\tisOpen: false,\n\t\tisDismissed: false,\n\t\tview: \"home\",\n\t\tincomingPreview: loadPersistedPreview(),\n\t\tannouncementPreviews: [],\n\t\tunseenAnnouncementCount: 0,\n\t\tnewConversationPrefill: null,\n\t\tpendingContentDetail: null,\n\t\tcontentCache: new Map(),\n\n\t\t// ── Lifecycle ────────────────────────────────────\n\n\t\tsetReady(visitor, website, agentConfig) {\n\t\t\tset({\n\t\t\t\tisReady: true,\n\t\t\t\tisConnecting: false,\n\t\t\t\tvisitor,\n\t\t\t\twebsite,\n\t\t\t\tagentConfig: agentConfig ?? null,\n\t\t\t});\n\t\t},\n\n\t\tsetConnecting(connecting) {\n\t\t\tset({ isConnecting: connecting });\n\t\t},\n\n\t\t// ── Conversations ────────────────────────────────\n\n\t\tsetConversations(conversations) {\n\t\t\tset({ conversations });\n\t\t},\n\n\t\taddConversation(conversation) {\n\t\t\tset((state) => ({\n\t\t\t\tconversations: [conversation, ...state.conversations],\n\t\t\t}));\n\t\t},\n\n\t\tsetActiveConversation(id) {\n\t\t\tset({ activeConversationId: id, view: id ? \"conversation\" : \"home\" });\n\t\t},\n\n\t\t// ── Messages ─────────────────────────────────────\n\n\t\tsetMessages(conversationId, items) {\n\t\t\tconst joined = latestAssignee(items);\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.messages);\n\t\t\t\tnext.set(conversationId, items);\n\t\t\t\treturn {\n\t\t\t\t\tmessages: next,\n\t\t\t\t\t/* Hydrating a thread that already contains a handoff means the header\n\t\t\t\t\t should open as that person, not as the AI who answered before them. */\n\t\t\t\t\t...(joined\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tconversations: state.conversations.map((c) =>\n\t\t\t\t\t\t\t\t\tc.id === conversationId\n\t\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t\t...c,\n\t\t\t\t\t\t\t\t\t\t\t\tassigneeName: joined.name ?? c.assigneeName,\n\t\t\t\t\t\t\t\t\t\t\t\tassigneeImage: joined.image ?? c.assigneeImage,\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t: c,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\n\t\taddMessage(conversationId, item) {\n\t\t\tconst joined = item.type === \"event\" && item.text ? parseJoinEvent(item.text) : null;\n\t\t\tif (joined) {\n\t\t\t\tset((state) => ({\n\t\t\t\t\tconversations: state.conversations.map((c) =>\n\t\t\t\t\t\tc.id === conversationId\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t...c,\n\t\t\t\t\t\t\t\t\tassigneeName: joined.name ?? c.assigneeName,\n\t\t\t\t\t\t\t\t\tassigneeImage: joined.image ?? c.assigneeImage,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: c,\n\t\t\t\t\t),\n\t\t\t\t}));\n\t\t\t}\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.messages);\n\t\t\t\tconst existing = next.get(conversationId) ?? [];\n\t\t\t\t// Deduplicate by ID — WS echoes may arrive twice (once from broadcast,\n\t\t\t\t// once from the mutation response path).\n\t\t\t\tif (existing.some((m) => m.id === item.id)) return state;\n\t\t\t\t/* The visitor's own message, echoed back under its server id while the\n\t\t\t\t optimistic copy is still on screen. Appending it and letting\n\t\t\t\t replaceMessage drop the optimistic one later costs a REMOUNT: the\n\t\t\t\t node the visitor is looking at is destroyed and a new one takes its\n\t\t\t\t place ~180ms after, so the appear animation runs a second time and\n\t\t\t\t the bubble visibly flashes. Swapping in place keeps _stableKey, so\n\t\t\t\t React reuses the same DOM node and nothing replays. */\n\t\t\t\t/* Same remount cost as the echo case below, on the AI's side. The streamed\n\t\t\t\t bubble is rendered as the last entry of the same keyed list this item\n\t\t\t\t is about to join (see MessageList), so handing the arriving item the\n\t\t\t\t stream's key lets React reuse that DOM node instead of destroying it\n\t\t\t\t and mounting a replacement — which is the \"it renders again when the\n\t\t\t\t stream finishes\" that survived making the state swap atomic. State\n\t\t\t\t continuity stopped the blank frame; key continuity stops the repaint. */\n\t\t\t\tconst streamKey = streamingKeyFor(conversationId);\n\t\t\t\tif (!item.visitorId && item.aiAgentId && state.streamingText.has(conversationId)) {\n\t\t\t\t\tnext.set(conversationId, [\n\t\t\t\t\t\t...existing,\n\t\t\t\t\t\t{ ...item, _stableKey: streamKey } as TimelineItem,\n\t\t\t\t\t]);\n\t\t\t\t\treturn { messages: next };\n\t\t\t\t}\n\t\t\t\tconst echoIndex = item.visitorId\n\t\t\t\t\t? existing.findIndex(\n\t\t\t\t\t\t\t(m) => !!m.visitorId && m.text === item.text && m.id.startsWith(\"optimistic-\"),\n\t\t\t\t\t\t)\n\t\t\t\t\t: -1;\n\t\t\t\tif (echoIndex >= 0) {\n\t\t\t\t\tconst optimistic = existing[echoIndex] as TimelineItem & { _stableKey?: string };\n\t\t\t\t\tconst merged = [...existing];\n\t\t\t\t\tmerged[echoIndex] = {\n\t\t\t\t\t\t...item,\n\t\t\t\t\t\t_stableKey: optimistic._stableKey ?? optimistic.id,\n\t\t\t\t\t} as TimelineItem;\n\t\t\t\t\tnext.set(conversationId, merged);\n\t\t\t\t\treturn { messages: next };\n\t\t\t\t}\n\t\t\t\t// Agent welcome messages are always the opener of a conversation.\n\t\t\t\t// If the first existing item is a visitor message, prepend the welcome\n\t\t\t\t// so the greeting stays above — don't rely on createdAt (client clock\n\t\t\t\t// vs server clock drift can flip the order).\n\t\t\t\tconst isAgentWelcome = !!item.aiAgentId && !item.visitorId;\n\t\t\t\tconst firstIsVisitor = existing[0]?.visitorId != null;\n\t\t\t\tif (isAgentWelcome && firstIsVisitor) {\n\t\t\t\t\tnext.set(conversationId, [item, ...existing]);\n\t\t\t\t\treturn { messages: next };\n\t\t\t\t}\n\t\t\t\t// General case: insert chronologically. Sort only when the newcomer\n\t\t\t\t// is older than the current tail (rare — WS reorders).\n\t\t\t\tconst last = existing[existing.length - 1];\n\t\t\t\tconst isOutOfOrder = last && item.createdAt < last.createdAt;\n\t\t\t\tconst merged = [...existing, item];\n\t\t\t\tif (isOutOfOrder) {\n\t\t\t\t\tmerged.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n\t\t\t\t}\n\t\t\t\tnext.set(conversationId, merged);\n\t\t\t\treturn { messages: next };\n\t\t\t});\n\t\t},\n\n\t\treplaceMessage(conversationId, oldId, item) {\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.messages);\n\t\t\t\tconst existing = next.get(conversationId) ?? [];\n\t\t\t\t// Race with WS echo: if the real item already landed, just drop the optimistic\n\t\t\t\tif (existing.some((m) => m.id === item.id && m.id !== oldId)) {\n\t\t\t\t\tnext.set(\n\t\t\t\t\t\tconversationId,\n\t\t\t\t\t\texisting.filter((m) => m.id !== oldId),\n\t\t\t\t\t);\n\t\t\t\t\treturn { messages: next };\n\t\t\t\t}\n\t\t\t\t// Preserve the optimistic ID as _stableKey so the React key\n\t\t\t\t// stays constant across the optimistic → real ID swap.\n\t\t\t\tnext.set(\n\t\t\t\t\tconversationId,\n\t\t\t\t\texisting.map((m) =>\n\t\t\t\t\t\tm.id === oldId\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t...item,\n\t\t\t\t\t\t\t\t\t_stableKey: (m as unknown as { _stableKey?: string })._stableKey ?? oldId,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: m,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\treturn { messages: next };\n\t\t\t});\n\t\t},\n\n\t\tremoveMessage(conversationId, id) {\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.messages);\n\t\t\t\tconst existing = next.get(conversationId);\n\t\t\t\tif (!existing) return state;\n\t\t\t\tnext.set(\n\t\t\t\t\tconversationId,\n\t\t\t\t\texisting.filter((m) => m.id !== id),\n\t\t\t\t);\n\t\t\t\treturn { messages: next };\n\t\t\t});\n\t\t},\n\n\t\tremapConversationId(oldId, newId) {\n\t\t\t/* The watchdog was armed under the temp id. Move it with the flag it\n\t\t\t guards, or the real id inherits a raised indicator that nothing is\n\t\t\t counting down — the one gap a ceiling keyed by conversation has. */\n\t\t\tif (indicatorWatchdogs.has(oldId)) {\n\t\t\t\tclearWatchdog(oldId);\n\t\t\t\tindicatorWatchdogs.set(\n\t\t\t\t\tnewId,\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tindicatorWatchdogs.delete(newId);\n\t\t\t\t\t\tget().setAiProcessing(newId, false);\n\t\t\t\t\t\tget().setTyping(newId, false);\n\t\t\t\t\t}, AI_INDICATOR_MAX_MS),\n\t\t\t\t);\n\t\t\t}\n\t\t\tset((state) => {\n\t\t\t\t// Merge messages from tempId + newId — WS echo may have inserted\n\t\t\t\t// items under the real id BEFORE the createConversation mutation\n\t\t\t\t// resolved. Dedupe by id so we don't lose the WS-delivered items.\n\t\t\t\tconst nextMessages = new Map(state.messages);\n\t\t\t\tconst tempItems = nextMessages.get(oldId) ?? [];\n\t\t\t\tconst existingItems = nextMessages.get(newId) ?? [];\n\t\t\t\tconst tempRewritten = tempItems.map((m) => ({ ...m, conversationId: newId }));\n\t\t\t\tconst isAgentMsg = (m: TimelineItem) => !!m.aiAgentId && !m.visitorId && !m.userId;\n\t\t\t\t// Prefer the seed welcome that came in via the temp conversation.\n\t\t\t\t// Keeping its DOM node stable is the whole point of openNewConversation\n\t\t\t\t// seeding; if we let the server-welcome (different id, same text)\n\t\t\t\t// take its slot, React unmounts the seed bubble and the animation\n\t\t\t\t// replays — exactly the \"git-gel\" the seed exists to prevent.\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\tconst merged: TimelineItem[] = [];\n\t\t\t\tlet keptAgentWelcome = false;\n\t\t\t\tfor (const m of tempRewritten) {\n\t\t\t\t\tif (seen.has(m.id)) continue;\n\t\t\t\t\tseen.add(m.id);\n\t\t\t\t\tmerged.push(m);\n\t\t\t\t\tif (isAgentMsg(m) && merged.length === 1) keptAgentWelcome = true;\n\t\t\t\t}\n\t\t\t\t// The server's welcome echo is the agent item that predates the\n\t\t\t\t// visitor's first server item (the API stamps it visitorTs - 1ms).\n\t\t\t\t// WS delivery is ordered, so if a genuine AI reply made it into\n\t\t\t\t// existingItems, the visitor item did too — when no visitor item\n\t\t\t\t// is present, the only agent item that can have arrived is the\n\t\t\t\t// welcome. Graft its identity onto the seed bubble (same DOM node\n\t\t\t\t// via _stableKey, real ULID for future dedup) instead of dropping\n\t\t\t\t// it; later agent items are genuine AI replies and MUST be kept.\n\t\t\t\tconst serverVisitorTs = existingItems.find((x) => x.visitorId)?.createdAt;\n\t\t\t\t/* The visitor's own message needs the same graft the welcome gets.\n\t\t\t\t It was sent optimistically under the temp conversation with a\n\t\t\t\t client id, and the server echoes it back under a real ULID — two\n\t\t\t\t different ids, so the id-only dedupe above keeps both and the\n\t\t\t\t visitor watches their own bubble render twice. Matched on text and\n\t\t\t\t claimed once, so sending the same words twice still shows twice. */\n\t\t\t\tconst isVisitorMsg = (m: TimelineItem) => !!m.visitorId && !m.aiAgentId && !m.userId;\n\t\t\t\tconst pendingVisitor = new Map<string, number>();\n\t\t\t\tmerged.forEach((m, i) => {\n\t\t\t\t\tif (isVisitorMsg(m) && typeof m.text === \"string\" && !pendingVisitor.has(m.text)) {\n\t\t\t\t\t\tpendingVisitor.set(m.text, i);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tlet graftedWelcome = false;\n\t\t\t\tfor (const m of existingItems) {\n\t\t\t\t\tif (seen.has(m.id)) continue;\n\t\t\t\t\tif (isVisitorMsg(m) && typeof m.text === \"string\" && pendingVisitor.has(m.text)) {\n\t\t\t\t\t\tconst idx = pendingVisitor.get(m.text) as number;\n\t\t\t\t\t\tpendingVisitor.delete(m.text);\n\t\t\t\t\t\tconst optimistic = merged[idx];\n\t\t\t\t\t\tmerged[idx] = {\n\t\t\t\t\t\t\t...m,\n\t\t\t\t\t\t\t_stableKey: optimistic\n\t\t\t\t\t\t\t\t? ((optimistic as unknown as { _stableKey?: string })._stableKey ?? optimistic.id)\n\t\t\t\t\t\t\t\t: m.id,\n\t\t\t\t\t\t} as TimelineItem;\n\t\t\t\t\t\tseen.add(m.id);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst isWelcomeEcho =\n\t\t\t\t\t\tisAgentMsg(m) &&\n\t\t\t\t\t\tkeptAgentWelcome &&\n\t\t\t\t\t\t!graftedWelcome &&\n\t\t\t\t\t\t(!serverVisitorTs || m.createdAt <= serverVisitorTs);\n\t\t\t\t\tif (isWelcomeEcho) {\n\t\t\t\t\t\tconst seed = merged[0];\n\t\t\t\t\t\tmerged[0] = {\n\t\t\t\t\t\t\t...m,\n\t\t\t\t\t\t\t_stableKey: seed\n\t\t\t\t\t\t\t\t? ((seed as unknown as { _stableKey?: string })._stableKey ?? seed.id)\n\t\t\t\t\t\t\t\t: m.id,\n\t\t\t\t\t\t} as TimelineItem;\n\t\t\t\t\t\tseen.add(m.id);\n\t\t\t\t\t\tgraftedWelcome = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tseen.add(m.id);\n\t\t\t\t\tmerged.push(m);\n\t\t\t\t}\n\t\t\t\tnextMessages.delete(oldId);\n\t\t\t\tnextMessages.set(newId, merged);\n\n\t\t\t\t// Dedupe conversation list — WS conversationCreated may have\n\t\t\t\t// prepended newId already; in that case drop the temp entry.\n\t\t\t\tconst hasNewId = state.conversations.some((c) => c.id === newId);\n\t\t\t\tconst conversations = hasNewId\n\t\t\t\t\t? state.conversations.filter((c) => c.id !== oldId)\n\t\t\t\t\t: state.conversations.map((c) => (c.id === oldId ? { ...c, id: newId } : c));\n\n\t\t\t\t/* Every map keyed by conversationId has to move, not just `messages`.\n\t\t\t\t This dropped three of them, and the visible cost was on the very\n\t\t\t\t first message of a thread: the composer marks aiProcessing under the\n\t\t\t\t TEMP id, createConversation resolves, activeConversationId becomes\n\t\t\t\t the real id — and the panel starts reading aiProcessing.get(realId),\n\t\t\t\t which nothing had written. So the dots appeared, vanished at the\n\t\t\t\t remap, and came back a second or two later when the server's own\n\t\t\t\t aiProcessingProgress finally arrived under the real id. Two loading\n\t\t\t\t phases for one reply, with a hole between them.\n\n\t\t\t\t Renaming a conversation means renaming it everywhere it is keyed;\n\t\t\t\t doing it per-map by hand is how the next map added here inherits the\n\t\t\t\t same bug, so this moves whatever is present under `oldId`. */\n\t\t\t\tconst moveKey = <V>(m: Map<string, V>): Map<string, V> => {\n\t\t\t\t\tif (!m.has(oldId)) return m;\n\t\t\t\t\tconst next = new Map(m);\n\t\t\t\t\tconst carried = next.get(oldId) as V;\n\t\t\t\t\tnext.delete(oldId);\n\t\t\t\t\t// A value already under newId came from the server and is newer.\n\t\t\t\t\tif (!next.has(newId)) next.set(newId, carried);\n\t\t\t\t\treturn next;\n\t\t\t\t};\n\n\t\t\t\treturn {\n\t\t\t\t\tmessages: nextMessages,\n\t\t\t\t\tconversations,\n\t\t\t\t\ttypingUsers: moveKey(state.typingUsers),\n\t\t\t\t\taiProcessing: moveKey(state.aiProcessing),\n\t\t\t\t\tstreamingText: moveKey(state.streamingText),\n\t\t\t\t\tactiveConversationId:\n\t\t\t\t\t\tstate.activeConversationId === oldId ? newId : state.activeConversationId,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\n\t\t// ── Presence ─────────────────────────────────────\n\n\t\tsetTyping(conversationId, isTyping) {\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.typingUsers);\n\t\t\t\tnext.set(conversationId, isTyping);\n\t\t\t\treturn { typingUsers: next };\n\t\t\t});\n\t\t},\n\n\t\tsetAiProcessing(conversationId, processing) {\n\t\t\t/* One funnel for both directions, so the watchdog is armed and disarmed\n\t\t\t in the same place the flag is written. Nothing else has to remember. */\n\t\t\tclearWatchdog(conversationId);\n\t\t\tif (processing) {\n\t\t\t\tindicatorWatchdogs.set(\n\t\t\t\t\tconversationId,\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tindicatorWatchdogs.delete(conversationId);\n\t\t\t\t\t\tget().setAiProcessing(conversationId, false);\n\t\t\t\t\t\tget().setTyping(conversationId, false);\n\t\t\t\t\t}, AI_INDICATOR_MAX_MS),\n\t\t\t\t);\n\t\t\t}\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.aiProcessing);\n\t\t\t\tnext.set(conversationId, processing);\n\t\t\t\treturn { aiProcessing: next };\n\t\t\t});\n\t\t},\n\n\t\t/**\n\t\t * `done` no longer clears the text, and that is the whole point.\n\t\t *\n\t\t * The final chunk and the real message are two separate WebSocket frames.\n\t\t * Deleting on `done` removed the streamed bubble in the first frame and the\n\t\t * persisted message only arrived in the second — so at the end of every\n\t\t * answer the text vanished and then came back, which is what a reader sees\n\t\t * as the message flickering just as it finishes. React batching cannot help:\n\t\t * two frames are two ticks.\n\t\t *\n\t\t * So a finished stream stays on screen and is retired by whoever proves it is\n\t\t * no longer needed — `timelineItemCreated` for that conversation, or\n\t\t * `aiProcessingCompleted` as a backstop. The server awaits those in that\n\t\t * order (pipeline.ts emits the item, then completion), so the swap happens in\n\t\t * the same tick as the real bubble mounting: one commit, no empty frame.\n\t\t */\n\t\tappendStreamChunk(conversationId, delta, done) {\n\t\t\t/* `done` changes nothing about the delta. The API chunks by four words and\n\t\t\t flags the LAST chunk done (ai/tools.ts), so that frame carries real text —\n\t\t\t skipping it dropped the closing words, and the bubble then had to repaint\n\t\t\t when the persisted message arrived with them. Which is the flicker,\n\t\t\t moved: not a blank frame any more, a rewrite of the final line. `done`\n\t\t\t only means \"no more is coming\"; retiring the text is the job of the\n\t\t\t message that replaces it. */\n\t\t\tvoid done;\n\t\t\t/* Text arriving IS the reply, so restart the ceiling rather than let a\n\t\t\t long answer trip it mid-sentence. */\n\t\t\tif (get().aiProcessing.get(conversationId)) {\n\t\t\t\tget().setAiProcessing(conversationId, true);\n\t\t\t}\n\t\t\tset((state) => {\n\t\t\t\tconst next = new Map(state.streamingText);\n\t\t\t\tconst prev = next.get(conversationId) ?? \"\";\n\t\t\t\tnext.set(conversationId, prev + delta);\n\t\t\t\treturn { streamingText: next };\n\t\t\t});\n\t\t},\n\n\t\tclearStream(conversationId) {\n\t\t\tset((state) => {\n\t\t\t\tif (!state.streamingText.has(conversationId)) return {};\n\t\t\t\tconst next = new Map(state.streamingText);\n\t\t\t\tnext.delete(conversationId);\n\t\t\t\treturn { streamingText: next };\n\t\t\t});\n\t\t},\n\n\t\t// ── Identity ─────────────────────────────────────\n\n\t\tupdateVisitorContact(contact) {\n\t\t\tset((state) => ({\n\t\t\t\tvisitor: state.visitor ? { ...state.visitor, contact } : state.visitor,\n\t\t\t}));\n\t\t},\n\n\t\t// ── Unread ───────────────────────────────────────\n\n\t\tclearUnread(conversationId) {\n\t\t\tset((s) => ({\n\t\t\t\tconversations: s.conversations.map((c) =>\n\t\t\t\t\tc.id === conversationId ? { ...c, unreadCount: 0 } : c,\n\t\t\t\t),\n\t\t\t}));\n\t\t},\n\n\t\t// ── UI ───────────────────────────────────────────\n\n\t\tsetOpen(open) {\n\t\t\tset((s) => ({\n\t\t\t\tisOpen: open,\n\t\t\t\tincomingPreview: open ? null : s.incomingPreview,\n\t\t\t\tannouncementPreviews: open ? [] : s.announcementPreviews,\n\t\t\t}));\n\t\t},\n\n\t\tsetPendingContentDetail(value) {\n\t\t\tset({ pendingContentDetail: value });\n\t\t},\n\n\t\tsetDismissed(dismissed) {\n\t\t\tset({ isDismissed: dismissed });\n\t\t},\n\n\t\tsetView(view) {\n\t\t\tset({ view });\n\t\t},\n\n\t\tsetNewConversationPrefill(text) {\n\t\t\tset({ newConversationPrefill: text });\n\t\t},\n\n\t\tdismissPreview() {\n\t\t\tset({ incomingPreview: null });\n\t\t},\n\n\t\t// ── Announcements ────────────────────────────────\n\n\t\tsetAnnouncementPreview(preview) {\n\t\t\tset((s) => ({\n\t\t\t\tannouncementPreviews: [\n\t\t\t\t\t...s.announcementPreviews.filter((p) => p.tabId !== preview.tabId),\n\t\t\t\t\tpreview,\n\t\t\t\t],\n\t\t\t}));\n\t\t},\n\n\t\tdismissAnnouncementPreview(slug) {\n\t\t\tif (slug) {\n\t\t\t\tset((s) => ({\n\t\t\t\t\tannouncementPreviews: s.announcementPreviews.filter((p) => p.slug !== slug),\n\t\t\t\t}));\n\t\t\t} else {\n\t\t\t\tset({ announcementPreviews: [] });\n\t\t\t}\n\t\t},\n\n\t\tsetUnseenAnnouncementCount(count) {\n\t\t\tset({ unseenAnnouncementCount: count });\n\t\t},\n\n\t\t// ── Content Cache ────────────────────────────────\n\n\t\tsetContentCache(key, data) {\n\t\t\tget().contentCache.set(key, { data, ts: Date.now() });\n\t\t},\n\n\t\t// ── Realtime Event Handler ───────────────────────\n\n\t\thandleRealtimeEvent(event) {\n\t\t\tconst state = get();\n\n\t\t\tswitch (event.type) {\n\t\t\t\tcase WsEventType.TimelineItemCreated: {\n\t\t\t\t\t// Only add public messages (widget shouldn't see private notes)\n\t\t\t\t\tif (event.item.visibility === \"public\") {\n\t\t\t\t\t\t// When the widget seeded a local welcome bubble (openNewConversation)\n\t\t\t\t\t\t// the server's createConversation path ALSO emits its own welcome\n\t\t\t\t\t\t// timeline item. The echo usually lands AFTER the optimistic visitor\n\t\t\t\t\t\t// message is already in the list, so we can't gate on list length.\n\t\t\t\t\t\t// The reliable discriminator is the timestamp: the API stamps the\n\t\t\t\t\t\t// welcome 1ms BEFORE the visitor's first message, while a genuine\n\t\t\t\t\t\t// AI reply is always stamped after it — and by the time the seed\n\t\t\t\t\t\t// exists under the server conversation id, the visitor item has\n\t\t\t\t\t\t// already been swapped to its server-stamped twin, so both sides\n\t\t\t\t\t\t// of the comparison come from the server clock (drift-safe).\n\t\t\t\t\t\tconst isAgentAuthored =\n\t\t\t\t\t\t\t!!event.item.aiAgentId && !event.item.visitorId && !event.item.userId;\n\t\t\t\t\t\tconst existing = state.messages.get(event.conversationId);\n\t\t\t\t\t\tconst seedId = existing?.[0]?.id;\n\t\t\t\t\t\tconst hasSeedWelcome = typeof seedId === \"string\" && seedId.startsWith(\"seed-welcome-\");\n\t\t\t\t\t\tif (isAgentAuthored && hasSeedWelcome) {\n\t\t\t\t\t\t\tconst firstVisitorTs = existing?.find((m) => m.visitorId)?.createdAt;\n\t\t\t\t\t\t\tconst isWelcomeEcho = !firstVisitorTs || event.item.createdAt <= firstVisitorTs;\n\t\t\t\t\t\t\tif (isWelcomeEcho) {\n\t\t\t\t\t\t\t\t// Adopt the server identity onto the seed bubble instead of\n\t\t\t\t\t\t\t\t// dropping the event — replaceMessage keeps the seed id as\n\t\t\t\t\t\t\t\t// _stableKey (no remount/flash) and future hydrations dedupe\n\t\t\t\t\t\t\t\t// against the real ULID instead of the synthetic seed id.\n\t\t\t\t\t\t\t\tstate.replaceMessage(event.conversationId, seedId, event.item);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstate.addMessage(event.conversationId, event.item);\n\t\t\t\t\t}\n\t\t\t\t\t// Clear typing/processing indicators as soon as the AI message arrives\n\t\t\t\t\t// (don't wait for aiProcessingCompleted which comes later after auto-title etc.)\n\t\t\t\t\tif (event.item.aiAgentId) {\n\t\t\t\t\t\tstate.setAiProcessing(event.conversationId, false);\n\t\t\t\t\t\tstate.setTyping(event.conversationId, false);\n\t\t\t\t\t\t/* Retire the streamed copy here, in the same tick that mounts the\n\t\t\t\t\t\t real one. Same tick means one React commit, so the reader never\n\t\t\t\t\t\t sees the frame where neither exists. */\n\t\t\t\t\t\tstate.clearStream(event.conversationId);\n\t\t\t\t\t}\n\t\t\t\t\t// Update conversation preview + unread count\n\t\t\t\t\tif (event.item.type === \"message\" && event.item.text) {\n\t\t\t\t\t\tconst isIncoming = !event.item.visitorId; // team or AI message\n\t\t\t\t\t\tconst currentState = get();\n\t\t\t\t\t\tconst isViewingThis =\n\t\t\t\t\t\t\tcurrentState.isOpen && currentState.activeConversationId === event.conversationId;\n\t\t\t\t\t\t/* A workflow's quick-replies step arrives here like any other\n\t\t\t\t\t\t message, and the card has to carry its buttons. Without this the\n\t\t\t\t\t\t notification printed the step's text fallback — a literal \"• Label\"\n\t\t\t\t\t\t bullet list — and the visitor's only way to answer was to open the\n\t\t\t\t\t\t widget and find the real buttons inside. Worse for the run itself:\n\t\t\t\t\t\t it is paused waiting on a choice, so a card that only describes the\n\t\t\t\t\t\t options stalls it behind an extra tap that looks like nothing is\n\t\t\t\t\t\t happening. */\n\t\t\t\t\t\tconst qr = previewQuickReplies(\n\t\t\t\t\t\t\t(event.item as TimelineItem & { metadata?: unknown }).metadata as never,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tset((s) => ({\n\t\t\t\t\t\t\tconversations: s.conversations.map((c) =>\n\t\t\t\t\t\t\t\tc.id === event.conversationId\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t...c,\n\t\t\t\t\t\t\t\t\t\t\tlastMessageText: event.item.text,\n\t\t\t\t\t\t\t\t\t\t\tlastMessageAt: event.item.createdAt,\n\t\t\t\t\t\t\t\t\t\t\t// Increment unread if incoming and not actively viewing\n\t\t\t\t\t\t\t\t\t\t\t...(isIncoming && !isViewingThis ? { unreadCount: c.unreadCount + 1 } : {}),\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: c,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t// Show preview bubble if widget is closed and message is incoming\n\t\t\t\t\t\t\t...(isIncoming && !currentState.isOpen\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tincomingPreview: {\n\t\t\t\t\t\t\t\t\t\t\t/* Empty for a quick-replies step, always. The prompt belongs to the\n\t\t\t\t\t\t\t\t\t\t\t card's quick-replies block, which prints it directly above the\n\t\t\t\t\t\t\t\t\t\t\t buttons — putting it here too rendered it twice, once as a message\n\t\t\t\t\t\t\t\t\t\t\t body and once as the prompt. And a prompt-less step persists the\n\t\t\t\t\t\t\t\t\t\t\t option labels as its bullet-list fallback, so carrying `text`\n\t\t\t\t\t\t\t\t\t\t\t through would enumerate in prose the buttons sitting underneath. */\n\t\t\t\t\t\t\t\t\t\t\ttext: qr ? \"\" : (event.item.text ?? \"\"),\n\t\t\t\t\t\t\t\t\t\t\tconversationId: event.conversationId,\n\t\t\t\t\t\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t\t\t\t\t\t\tsenderName: (event.item as { userName?: string | null }).userName ?? null,\n\t\t\t\t\t\t\t\t\t\t\tsenderImage: (event.item as { userImage?: string | null }).userImage ?? null,\n\t\t\t\t\t\t\t\t\t\t\t...(qr ? { quickReplies: qr } : {}),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t}));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.ConversationUpdated: {\n\t\t\t\t\tset((s) => ({\n\t\t\t\t\t\tconversations: s.conversations.map((c) =>\n\t\t\t\t\t\t\tc.id === event.conversationId ? { ...c, ...event.updates } : c,\n\t\t\t\t\t\t),\n\t\t\t\t\t}));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.ConversationTyping: {\n\t\t\t\t\t// Only show typing for non-visitor (team/AI typing)\n\t\t\t\t\tif (!event.visitorId) {\n\t\t\t\t\t\tstate.setTyping(event.conversationId, event.isTyping);\n\t\t\t\t\t\t// Auto-clear after 5 seconds\n\t\t\t\t\t\tif (event.isTyping) {\n\t\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\t\tstate.setTyping(event.conversationId, false);\n\t\t\t\t\t\t\t}, 5000);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.AiProcessingProgress: {\n\t\t\t\t\t// Track AI processing separately for distinct UI indicator\n\t\t\t\t\tstate.setAiProcessing(event.conversationId, true);\n\t\t\t\t\tstate.setTyping(event.conversationId, true);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.AiProcessingCompleted: {\n\t\t\t\t\tstate.setAiProcessing(event.conversationId, false);\n\t\t\t\t\tstate.setTyping(event.conversationId, false);\n\t\t\t\t\t/* Backstop: the server emits this after timelineItemCreated, so by now\n\t\t\t\t\t a finished stream has normally already been retired. If that frame\n\t\t\t\t\t was dropped, this is what stops the streamed text lingering as a\n\t\t\t\t\t ghost bubble forever. */\n\t\t\t\t\tstate.clearStream(event.conversationId);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.AiStreamChunk: {\n\t\t\t\t\tstate.setAiProcessing(event.conversationId, false);\n\t\t\t\t\tstate.setTyping(event.conversationId, false);\n\t\t\t\t\tstate.appendStreamChunk(event.conversationId, event.delta, event.done);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WsEventType.ConversationCreated: {\n\t\t\t\t\t// Race-safe insert: WS may arrive before OR after the HTTP\n\t\t\t\t\t// createConversation response. If after, remapConversationId\n\t\t\t\t\t// already renamed tempId → realId, so the entry exists.\n\t\t\t\t\t// If before, we prepend here; the later remap call hits the\n\t\t\t\t\t// `hasNewId=true` branch and drops the temp entry.\n\t\t\t\t\tconst conv = event.conversation as unknown as {\n\t\t\t\t\t\tid: string;\n\t\t\t\t\t\ttitle: string | null;\n\t\t\t\t\t\tstatus: string;\n\t\t\t\t\t\tlastMessageText?: string | null;\n\t\t\t\t\t\tlastMessageAt?: string | null;\n\t\t\t\t\t\tlastMessageSenderType?: string | null;\n\t\t\t\t\t};\n\t\t\t\t\tconst alreadyPresent = state.conversations.some((c) => c.id === conv.id);\n\t\t\t\t\tif (alreadyPresent) break;\n\t\t\t\t\tstate.addConversation({\n\t\t\t\t\t\tid: conv.id,\n\t\t\t\t\t\ttitle: conv.title,\n\t\t\t\t\t\tstatus: conv.status,\n\t\t\t\t\t\tlastMessageText: conv.lastMessageText ?? null,\n\t\t\t\t\t\tlastMessageAt: conv.lastMessageAt ?? null,\n\t\t\t\t\t\tlastMessageSenderType: conv.lastMessageSenderType ?? null,\n\t\t\t\t\t\tlastMessageSenderName: null,\n\t\t\t\t\t\tlastMessageSenderImage: null,\n\t\t\t\t\t\tassigneeName: null,\n\t\t\t\t\t\tassigneeImage: null,\n\t\t\t\t\t\tunreadCount: 0,\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t},\n\t}));\n\n\t// Single source of persistence for the proactive preview: every\n\t// transition (WS set, setOpen-clears, dismissPreview) passes through\n\t// here, so we don't have to touch each call site.\n\tif (typeof window !== \"undefined\") {\n\t\tlet last = store.getState().incomingPreview;\n\t\tstore.subscribe((s) => {\n\t\t\tif (s.incomingPreview !== last) {\n\t\t\t\tlast = s.incomingPreview;\n\t\t\t\tpersistPreview(s.incomingPreview);\n\t\t\t}\n\t\t});\n\t}\n\n\treturn store;\n}\n","/**\n * Widget i18n — lightweight, zero-dependency translation system.\n *\n * Architecture:\n * - English strings bundled as fallback (zero-latency, always works)\n * - Other locales fetched from Better i18n CDN at runtime\n * - Locale detection: data-locale > identify metadata > navigator.language > \"en\"\n * - Simple key-value lookup with t(\"widget.key\") syntax\n *\n * CDN URL: https://cdn.better-i18n.com/helpway/widget/{locale}/translations.json\n */\n\n// ── Bundled English fallback strings ────────────────────────\n\nconst en: Record<string, string> = {\n\t// Navigation & tabs\n\t\"widget.home\": \"Home\",\n\t\"widget.messages\": \"Messages\",\n\t\"widget.help\": \"Help\",\n\n\t// Home screen\n\t\"widget.send_us_message\": \"Send us a message\",\n\t\"widget.reply_time\": \"We typically reply in a few minutes\",\n\t\"widget.recent_conversations\": \"Recent conversations\",\n\t\"widget.see_all\": \"See all conversations\",\n\t\"widget.whats_new\": \"What's New\",\n\t\"widget.view_all\": \"View all\",\n\n\t// Messages tab\n\t\"widget.no_messages\": \"No messages yet\",\n\t\"widget.no_messages_desc\": \"Start a conversation to get help\",\n\t\"widget.start_conversation\": \"Start a conversation\",\n\t\"widget.no_preview\": \"No messages yet\",\n\n\t// Conversation\n\t\"widget.new_conversation\": \"New conversation\",\n\t\"widget.talk_to_human\": \"Talk to a human\",\n\t\"widget.talk_to_human_message\": \"I'd like to talk to a human, please.\",\n\t\"widget.aria_options\": \"Conversation options\",\n\t\"widget.resolved_text\": \"This conversation has been resolved\",\n\t\"widget.send_followup\": \"Send a follow-up\",\n\t\"widget.start_a_conversation\": \"Start a conversation\",\n\n\t// Composer\n\t\"widget.placeholder\": \"Send a message...\",\n\t\"widget.placeholder_new\": \"How can we help?\",\n\t\"widget.drop_files\": \"Drop files here\",\n\n\t// CSAT\n\t\"widget.csat_label\": \"How was your experience?\",\n\t\"widget.csat_thanks\": \"Thanks for your feedback!\",\n\n\t// Inline email collection (after AI reply)\n\t\"widget.email_title\": \"Don't miss our reply\",\n\t\"widget.email_subtitle\": \"We'll email you when we respond\",\n\t\"widget.email_placeholder\": \"you@email.com\",\n\t\"widget.email_continue\": \"Send\",\n\t\"widget.email_saved\": \"You'll be notified by email\",\n\t\"widget.email_dismiss\": \"No thanks\",\n\n\t// Errors\n\t\"widget.error_title\": \"Something went wrong\",\n\t\"widget.error_desc\": \"Failed to load. Please try again.\",\n\t\"widget.retry\": \"Retry\",\n\t\"widget.reconnecting\": \"Reconnecting...\",\n\t\"widget.send_error\": \"Message not sent\",\n\n\t// Date separators (today is implicit — never rendered)\n\t\"widget.yesterday\": \"Yesterday\",\n\n\t// Sender labels\n\t\"widget.helpway_ai\": \"Helpway AI\",\n\t\"widget.support\": \"Support\",\n\n\t// Events\n\t\"widget.joined\": \"joined the conversation\",\n\t\"widget.left\": \"left the conversation\",\n\n\t// Content/search\n\t\"widget.content\": \"Content\",\n\t\"widget.search\": \"Search...\",\n\t\"widget.no_results\": \"No results found\",\n\t\"widget.try_different\": \"Try a different search term\",\n\t\"widget.nothing_yet\": \"Nothing here yet\",\n\t\"widget.check_back\": \"Check back later for updates\",\n\t\"widget.load_more\": \"Load more\",\n\t\"widget.loading\": \"Loading...\",\n\n\t// Copy\n\t\"widget.copy\": \"Copy message\",\n\t\"widget.copied\": \"Copied\",\n\n\t// File upload\n\t\"widget.file_too_large\": \"File too large (max 10 MB)\",\n\t\"widget.click_to_open\": \"Click to open\",\n\t\"widget.caption_required\": \"Add a message to send with your attachment\",\n\n\t// Accessibility\n\t\"widget.aria_chat\": \"Support chat\",\n\t\"widget.aria_close\": \"Close\",\n\t\"widget.aria_back\": \"Back\",\n\t\"widget.aria_send\": \"Send message\",\n\t\"widget.aria_open_image\": \"Open image\",\n\t\"widget.aria_attach\": \"Attach file\",\n\t\"widget.aria_dictate\": \"Dictate message\",\n\t\"widget.aria_input\": \"Message input\",\n\t\"widget.aria_remove\": \"Remove\",\n\t\"widget.aria_dismiss\": \"Dismiss\",\n\t\"widget.aria_open\": \"Open support\",\n\t\"widget.aria_close_support\": \"Close support\",\n\t\"widget.aria_good\": \"Good\",\n\t\"widget.aria_bad\": \"Bad\",\n\t\"widget.aria_messages\": \"Messages\",\n\n\t// Time (relative)\n\t\"widget.time_now\": \"now\",\n\t\"widget.time_yesterday\": \"Yesterday\",\n\n\t// Powered by\n\t\"widget.powered_by\": \"Powered by\",\n\n\t// Closed-state dock — overflow row when the announcement stack is clipped\n\t/* Plural handled by two keys rather than a rule. The widget's `t()` does\n\t `{{var}}` substitution and nothing else, and inventing a plural engine for\n\t one string would be the larger mistake; the languages we ship differ on\n\t where the count sits, not on how many forms it needs here. */\n\t/* A state, not a count. \"3\" in a pill reads as unread; this row is telling the\n\t visitor the thread is waiting on THEM, which is a different thing and the one\n\t that decides whether an answered conversation gets abandoned. */\n\t\"widget.awaiting_your_reply\": \"Awaiting your reply\",\n\n\t\"widget.more_announcements_one\": \"+1 more update\",\n\t\"widget.more_announcements\": \"+{{count}} more updates\",\n\n\t// Hero / home screen\n\t/* One line, not two. The second line was \"How can we help?\" — the exact string\n\t the composer's own placeholder shows, two inches below it. The input is what\n\t asks the question; the greeting only has to say hello. */\n\t\"widget.welcome_message\": \"Hi there 👋\",\n\t\"widget.subtitle_text\": \"Usually replies in minutes\",\n};\n\n// ── State ───────────────────────────────────────────────────\n\nlet currentLocale = \"en\";\nlet translations: Record<string, string> = {};\nlet isLoaded = false;\nlet revision = 0; // Incremented on every translation change — React hook watches this\nconst listeners: Array<() => void> = [];\n\n// ── Public API ──────────────────────────────────────────────\n\n/**\n * Translate a key. Falls back to English bundled string, then to the key itself.\n *\n * Supports simple interpolation: t(\"widget.key\", { name: \"John\" })\n * Template: \"Hello {{name}}\" → \"Hello John\"\n */\nexport function t(key: string, params?: Record<string, string | number>): string {\n\tconst value = translations[key] ?? en[key] ?? key;\n\n\tif (!params) return value;\n\n\treturn value.replace(/\\{\\{(\\w+)\\}\\}/g, (_, k: string) => {\n\t\treturn params[k]?.toString() ?? `{{${k}}}`;\n\t});\n}\n\n/** Get the current locale code */\nexport function getLocale(): string {\n\treturn currentLocale;\n}\n\n/** Get current revision number — changes when translations are loaded/updated */\nexport function getI18nRevision(): number {\n\treturn revision;\n}\n\n/** Check if translations have been loaded */\nexport function isI18nReady(): boolean {\n\treturn isLoaded;\n}\n\n/** Subscribe to locale/translation changes. Returns unsubscribe fn. */\nexport function onLocaleChange(fn: () => void): () => void {\n\tlisteners.push(fn);\n\treturn () => {\n\t\tconst idx = listeners.indexOf(fn);\n\t\tif (idx >= 0) listeners.splice(idx, 1);\n\t};\n}\n\n// ── Initialization ──────────────────────────────────────────\n\n/**\n * Detect locale from available signals and fetch translations.\n *\n * Priority:\n * 1. Explicit `locale` param (from data-locale attribute)\n * 2. navigator.language (browser preference)\n * 3. \"en\" fallback\n */\nexport async function initI18n(options?: { locale?: string; cdnBase?: string }): Promise<void> {\n\tif (options?.cdnBase) {\n\t\tcdnBase = options.cdnBase;\n\t}\n\n\tconst detected =\n\t\toptions?.locale ?? (typeof navigator !== \"undefined\" ? navigator.language : \"en\");\n\n\t// Normalize: \"fr-FR\" → \"fr\", \"pt-BR\" → \"pt-BR\" (keep regional if meaningful)\n\tcurrentLocale = normalizeLocale(detected);\n\n\t// English is bundled — no fetch needed\n\tif (currentLocale === \"en\") {\n\t\tisLoaded = true;\n\t\tnotify();\n\t\treturn;\n\t}\n\n\t// Fetch from CDN\n\ttry {\n\t\tconst data = await fetchTranslations(currentLocale);\n\t\tif (data) {\n\t\t\t// Only pick widget.* keys from the full namespace bundle\n\t\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\ttranslations[`widget.${key}`] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch (err) {\n\t\tconsole.warn(`[Helpway] Failed to fetch ${currentLocale} translations, using English`, err);\n\t}\n\n\tisLoaded = true;\n\tnotify();\n}\n\n/**\n * Update locale at runtime (e.g., after identify() provides metadata.locale).\n * Re-fetches translations if locale changed.\n */\nexport async function setLocale(locale: string): Promise<void> {\n\tconst normalized = normalizeLocale(locale);\n\tif (normalized === currentLocale) return;\n\n\tcurrentLocale = normalized;\n\ttranslations = {}; // Clear old translations\n\n\tif (normalized === \"en\") {\n\t\tnotify();\n\t\treturn;\n\t}\n\n\ttry {\n\t\tconst data = await fetchTranslations(normalized);\n\t\tif (data) {\n\t\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\ttranslations[`widget.${key}`] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Silent fallback to English\n\t}\n\n\tnotify();\n}\n\n// ── Internals ───────────────────────────────────────────────\n\nlet cdnBase = \"https://cdn.better-i18n.com/helpway/widget\";\n\nasync function fetchTranslations(locale: string): Promise<Record<string, string> | null> {\n\t// All namespaces live in a single translations.json — widget keys nested under \"widget\" key\n\tconst url = `${cdnBase}/${locale}/translations.json`;\n\n\tlet res = await fetch(url);\n\tif (!res.ok && locale.includes(\"-\")) {\n\t\t// Try base locale: \"pt-BR\" → \"pt\"\n\t\tconst base = locale.split(\"-\")[0];\n\t\tres = await fetch(`${cdnBase}/${base}/translations.json`);\n\t}\n\tif (!res.ok) return null;\n\n\tconst data: Record<string, unknown> = await res.json();\n\t// CDN structure is nested: { \"widget\": { \"home\": \"Ana Sayfa\", ... }, \"sidebar\": {...} }\n\tconst widgetNs = data.widget;\n\tif (widgetNs && typeof widgetNs === \"object\" && !Array.isArray(widgetNs)) {\n\t\tconst result: Record<string, string> = {};\n\t\tfor (const [k, v] of Object.entries(widgetNs)) {\n\t\t\tif (typeof v === \"string\") result[k] = v;\n\t\t}\n\t\treturn result;\n\t}\n\treturn null;\n}\n\nfunction normalizeLocale(input: string): string {\n\t// Keep regional variants that are commonly distinct: pt-BR, zh-CN, zh-TW\n\tconst regional = [\"pt-br\", \"zh-cn\", \"zh-tw\", \"zh-hk\"];\n\tconst lower = input.toLowerCase().replace(\"_\", \"-\");\n\n\tfor (const r of regional) {\n\t\tif (lower.startsWith(r)) return r;\n\t}\n\n\t// Otherwise just use base: \"fr-FR\" → \"fr\"\n\treturn lower.split(\"-\")[0] ?? \"en\";\n}\n\nfunction notify(): void {\n\trevision++;\n\tfor (const fn of listeners) {\n\t\ttry {\n\t\t\tfn();\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t}\n}\n","import type { TimelineItemMetadata } from \"@helpway/types\";\nimport { getLocale, t } from \"./i18n\";\n\n/**\n * Format a date as relative time string.\n * Uses i18n for \"now\" and \"Yesterday\". Locale-aware date formatting.\n */\nexport function formatRelativeTime(date: string | Date): string {\n\tconst now = Date.now();\n\tconst then = typeof date === \"string\" ? new Date(date).getTime() : date.getTime();\n\tconst diffMs = now - then;\n\tconst diffMin = Math.floor(diffMs / 60000);\n\tconst diffHour = Math.floor(diffMs / 3600000);\n\tconst diffDay = Math.floor(diffMs / 86400000);\n\n\tif (diffMin < 1) return t(\"widget.time_now\");\n\tif (diffMin < 60) return `${diffMin}m`;\n\tif (diffHour < 24) return `${diffHour}h`;\n\tif (diffDay === 1) return t(\"widget.time_yesterday\");\n\tif (diffDay < 7) return `${diffDay}d`;\n\n\tconst d = typeof date === \"string\" ? new Date(date) : date;\n\treturn d.toLocaleDateString(getLocale(), { month: \"short\", day: \"numeric\" });\n}\n\n/**\n * Format time for message bubbles (HH:MM).\n */\nexport function formatTime(date: string | Date): string {\n\tconst d = typeof date === \"string\" ? new Date(date) : date;\n\treturn d.toLocaleTimeString(undefined, { hour: \"2-digit\", minute: \"2-digit\" });\n}\n\n/**\n * Resolve a label that may be a translation key (\"widget.*\") or plain text.\n * When the key resolves to itself (missing), falls back to a humanized form\n * so the UI never leaks raw \"widget.changelog\" strings to the visitor.\n */\nexport function resolveLabel(label: string): string {\n\tif (!label.startsWith(\"widget.\")) return label;\n\tconst resolved = t(label);\n\tif (resolved === label) {\n\t\treturn label\n\t\t\t.replace(\"widget.\", \"\")\n\t\t\t.replace(/_/g, \" \")\n\t\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n\t}\n\treturn resolved;\n}\n\n/**\n * Get initials from a name or email.\n */\nexport function getInitials(value: string): string {\n\tif (!value) return \"?\";\n\n\t// Email: take first letter\n\tif (value.includes(\"@\")) return (value[0] ?? \"?\").toUpperCase();\n\n\t// Name: take first letter of first two words\n\tconst parts = value.trim().split(/\\s+/);\n\tif (parts.length >= 2) {\n\t\treturn ((parts[0]?.[0] ?? \"\") + (parts[1]?.[0] ?? \"\")).toUpperCase();\n\t}\n\treturn (parts[0]?.[0] ?? \"?\").toUpperCase();\n}\n\n/**\n * Parse a timeline item's `metadata` into the discriminated union.\n *\n * The same field arrives in two shapes and both are real. D1 stores it as a\n * TEXT column, so `createTimelineItem` returns — and every realtime emit\n * forwards — a JSON *string*. The tRPC read paths hydrate it into an object\n * before responding. A caller that handles only one shape works on one surface\n * and silently degrades on the other, which is exactly how workflow quick\n * replies came out as literal \"• Label\" bullet text: the reducer read\n * `metadata.kind` off a string, got `undefined`, and fell through to the\n * plain-text fallback the metadata exists to replace.\n *\n * Returns null rather than throwing. Unparseable metadata means \"render the\n * text fallback\", never \"drop the message\".\n */\nexport function parseTimelineItemMetadata(\n\traw: TimelineItemMetadata | string | null | undefined,\n): TimelineItemMetadata | null {\n\tif (!raw) return null;\n\tif (typeof raw === \"object\") return raw;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(raw);\n\t\treturn parsed && typeof parsed === \"object\" ? (parsed as TimelineItemMetadata) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * The quick-replies slice of a closed-state preview card, or null when the\n * item is an ordinary message.\n *\n * Split out from the reducer because the preview card had two producers — the\n * realtime reducer and the ephemeral-workflow path in the provider — and only\n * the second one carried the buttons. Same derivation, one home.\n *\n * `text` is what the card prints above the buttons: the step's own prompt when\n * it has one, otherwise the item's stored fallback. Preferring the prompt\n * matters because the fallback for a prompt-less step is the bullet list, and\n * printing that above the very buttons it enumerates says everything twice.\n */\nexport function previewQuickReplies(\n\tmetadata: TimelineItemMetadata | string | null | undefined,\n): { stepId: string; prompt: string | null; options: Array<{ id: string; label: string }> } | null {\n\tconst parsed = parseTimelineItemMetadata(metadata);\n\tif (parsed?.kind !== \"quick_replies\") return null;\n\tif (!Array.isArray(parsed.options) || parsed.options.length === 0) return null;\n\t/* A cancelled set is history, not a question: the visitor already answered by\n\t typing instead. Offering the buttons again from a notification card would\n\t re-ask something the run has moved past. */\n\tif (parsed.cancelled) return null;\n\treturn {\n\t\tstepId: parsed.stepId,\n\t\tprompt: parsed.prompt ?? null,\n\t\toptions: parsed.options.map((o) => ({ id: o.id, label: o.label })),\n\t};\n}\n\n/**\n * Split an announcement stack into what the dock shows and what it collapses.\n *\n * Pure so the cap can be tested without a render. The rule it encodes is a\n * priority decision, not arithmetic: the strip above the launcher holds two\n * cards, a pending reply takes one of them, and announcements are what gives up\n * a slot — a reply is a conversation waiting on the visitor, an announcement is\n * content that can wait. Before the cap existed, four cards needed more vertical\n * space than a laptop viewport has and the overflow went off the top of the\n * screen rather than queueing anywhere.\n *\n * `hidden` keeps its order so the caller can open the NEXT unread one. Marking\n * every hidden entry seen on a single tap would consume announcements the\n * visitor never read.\n */\nexport function splitAnnouncementStack<T>(\n\tpreviews: readonly T[],\n\tmaxVisible: number,\n): { visible: T[]; hidden: T[] } {\n\t/* A negative or NaN cap collapses everything rather than throwing: the caller\n\t is a layout decision, and the safe reading of a nonsense cap is \"no room\". */\n\tconst room = Number.isFinite(maxVisible) ? Math.max(0, Math.trunc(maxVisible)) : previews.length;\n\treturn { visible: previews.slice(0, room), hidden: previews.slice(room) };\n}\n\n/**\n * Is this conversation waiting on the visitor?\n *\n * Open, and the last thing said was said by a person on the team. That is the\n * moment a support thread dies: we reply, the visitor never registers that we\n * replied, and the thread is abandoned with an unanswered message in it.\n *\n * `\"team\"`, deliberately not `\"ai\"`. An AI auto-reply follows nearly every\n * visitor message, so counting it would leave the indicator permanently lit for\n * anyone who has ever opened the widget — which teaches people to ignore it. A\n * human reply is the one that genuinely awaits an answer.\n *\n * `unreadCount` is OR'd in so a message landing live in this session counts\n * before the conversation summary refreshes. It answers a slightly different\n * question than \"unread\" and it is the one a launcher badge usually wants.\n */\nexport function isAwaitingVisitorReply(conversation: {\n\tstatus: string;\n\tlastMessageSenderType: string | null;\n\tunreadCount: number;\n}): boolean {\n\tif (conversation.status !== \"open\") return false;\n\treturn conversation.lastMessageSenderType === \"team\" || conversation.unreadCount > 0;\n}\n\n/** How many conversations are waiting on the visitor. */\nexport function awaitingReplyCount(\n\tconversations: ReadonlyArray<{\n\t\tstatus: string;\n\t\tlastMessageSenderType: string | null;\n\t\tunreadCount: number;\n\t}>,\n): number {\n\treturn conversations.filter(isAwaitingVisitorReply).length;\n}\n\n/**\n * Length a preview card body is cut to.\n *\n * 120, matching the announcement card, which has always truncated. The message\n * card did not, and with `autoDismissMs: null` — which the launcher passes, so a\n * real reply is never auto-deleted — a long agent answer grew without limit. In\n * an anchored placement it swallowed a host application's entire sidebar, and\n * the only workaround available to a consumer was CSS against\n * `.hw-preview-body`.\n *\n * A notification is a pointer to a conversation, not the conversation.\n */\nexport const PREVIEW_BODY_LIMIT = 120;\n\n/** Cut a preview body at the shared limit, adding an ellipsis when it bites. */\nexport function truncatePreviewBody(text: string, limit = PREVIEW_BODY_LIMIT): string {\n\tif (text.length <= limit) return text;\n\t/* Cut at the last space inside the budget so the ellipsis does not land\n\t mid-word; fall back to a hard cut for text with no spaces at all (CJK, a\n\t pasted URL). */\n\tconst slice = text.slice(0, limit);\n\tconst lastSpace = slice.lastIndexOf(\" \");\n\tconst cut = lastSpace > limit * 0.6 ? slice.slice(0, lastSpace) : slice;\n\treturn `${cut.trimEnd()}…`;\n}\n","import type { StoreApi } from \"zustand/vanilla\";\nimport type { Listener, WidgetEventEmitter, WidgetEventName, WidgetEvents } from \"./events\";\nimport type { WidgetStore } from \"./store\";\nimport { clearVisitorId } from \"./visitor-id\";\n\n/**\n * The programmatic widget API — all the methods consumers can call\n * once the widget is mounted. Returned by `createHelpwayAPI()`.\n *\n * The global `window.Helpway` is the *callable* wrapper around this\n * (see `HelpwayAPI` and `installCallable`).\n */\nexport interface HelpwayMethods {\n\t/** Open the widget panel */\n\topen(): void;\n\t/** Close the widget panel */\n\tclose(): void;\n\t/** Toggle the widget panel open/closed */\n\ttoggle(): void;\n\t/** Dismiss the widget entirely (launcher + panel). Use for page-specific hiding. */\n\tdismiss(): void;\n\t/** Show the widget again after dismiss */\n\tshow(): void;\n\t/** Full reset: clear session, cookies, visitor identity */\n\tshutdown(): void;\n\t/** Identify the visitor (link to contact) */\n\tidentify(data: {\n\t\texternalId: string;\n\t\temail?: string;\n\t\tname?: string;\n\t\timage?: string;\n\t\tmetadata?: Record<string, unknown>;\n\t\t/**\n\t\t * Move this browser's visitor to the contact above even if it already\n\t\t * belongs to a different contact. Dangerous: it merges whatever history\n\t\t * this browser has into that contact. Off by default; without it the\n\t\t * server keeps the existing link and returns that contact (#193).\n\t\t */\n\t\treassign?: boolean;\n\t}): Promise<void>;\n\t/** Open a new conversation, optionally pre-filling the message */\n\tnewConversation(prefill?: string): void;\n\t/** Open a specific conversation by ID */\n\topenConversation(id: string): void;\n\t/** Get the current unread count */\n\treadonly unreadCount: number;\n\t/** Whether the widget panel is currently open */\n\treadonly isOpen: boolean;\n\t/** Subscribe to widget events */\n\ton<K extends WidgetEventName>(event: K, fn: Listener<WidgetEvents[K]>): void;\n\t/** Unsubscribe from widget events */\n\toff<K extends WidgetEventName>(event: K, fn: Listener<WidgetEvents[K]>): void;\n}\n\n/**\n * The global `window.Helpway` shape: callable (Intercom-style snippet API)\n * AND object (typed methods). Build one of these from a `HelpwayMethods`\n * via `installCallable()`.\n */\nexport interface HelpwayAPI extends HelpwayMethods {\n\t(command: string, ...args: unknown[]): unknown;\n}\n\n/**\n * Install a callable wrapper around any methods object onto `window.Helpway`,\n * draining any calls that the snippet stub queued before the widget mounted.\n * Returns the callable so callers can compare identities on cleanup.\n *\n * Generic in `T` so both the rich `HelpwayMethods` (from widget-react) and\n * the slimmer script-tag API (from widget-embed) can use the same plumbing.\n */\nexport function installCallable<T extends object>(\n\tmethods: T,\n): T & ((command: string, ...args: unknown[]) => unknown) {\n\tconst dispatch = (command: string, ...args: unknown[]): unknown => {\n\t\tconst fn = (methods as unknown as Record<string, unknown>)[command];\n\t\tif (typeof fn === \"function\") {\n\t\t\treturn (fn as (...a: unknown[]) => unknown)(...args);\n\t\t}\n\t\tconsole.warn(`[Helpway] Unknown command: ${command}`);\n\t\treturn undefined;\n\t};\n\tconst callable = Object.assign(dispatch, methods);\n\tconst previous = window.Helpway as { q?: unknown[][] } | undefined;\n\twindow.Helpway = callable as unknown as HelpwayAPI;\n\tconst queue = previous?.q;\n\tif (queue?.length) {\n\t\tfor (const entry of queue) {\n\t\t\ttry {\n\t\t\t\tdispatch(...(entry as [string, ...unknown[]]));\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Helpway] queued call failed:\", err);\n\t\t\t}\n\t\t}\n\t}\n\treturn callable;\n}\n\nexport function createHelpwayAPI(deps: {\n\tstore: StoreApi<WidgetStore>;\n\temitter: WidgetEventEmitter;\n\tidentify: (data: {\n\t\texternalId: string;\n\t\temail?: string;\n\t\tname?: string;\n\t\timage?: string;\n\t\tmetadata?: Record<string, unknown>;\n\t\treassign?: boolean;\n\t}) => Promise<void>;\n\tapiKey: string;\n}): HelpwayMethods {\n\tconst { store, emitter, identify, apiKey } = deps;\n\n\treturn {\n\t\topen() {\n\t\t\tstore.getState().setOpen(true);\n\t\t\tstore.getState().setDismissed(false);\n\t\t},\n\n\t\tclose() {\n\t\t\tstore.getState().setOpen(false);\n\t\t},\n\n\t\ttoggle() {\n\t\t\tconst s = store.getState();\n\t\t\tif (s.isDismissed) {\n\t\t\t\ts.setDismissed(false);\n\t\t\t\ts.setOpen(true);\n\t\t\t\temitter.emit(\"show\");\n\t\t\t} else {\n\t\t\t\ts.setOpen(!s.isOpen);\n\t\t\t}\n\t\t},\n\n\t\tdismiss() {\n\t\t\tstore.getState().setOpen(false);\n\t\t\tstore.getState().setDismissed(true);\n\t\t\temitter.emit(\"dismiss\");\n\t\t},\n\n\t\tshow() {\n\t\t\tstore.getState().setDismissed(false);\n\t\t\temitter.emit(\"show\");\n\t\t},\n\n\t\tshutdown() {\n\t\t\tstore.getState().setOpen(false);\n\t\t\tstore.getState().setDismissed(false);\n\t\t\tclearVisitorId(apiKey);\n\t\t\tif (typeof document !== \"undefined\") {\n\t\t\t\tdocument.cookie = \"hw_visitor=; Path=/; Max-Age=0\";\n\t\t\t}\n\t\t},\n\n\t\tidentify,\n\n\t\tnewConversation(prefill?: string) {\n\t\t\tconst s = store.getState();\n\t\t\ts.setDismissed(false);\n\t\t\ts.setOpen(true);\n\t\t\ts.setNewConversationPrefill(prefill ?? \"\");\n\t\t},\n\n\t\topenConversation(id: string) {\n\t\t\tconst s = store.getState();\n\t\t\ts.setDismissed(false);\n\t\t\ts.setActiveConversation(id);\n\t\t\ts.setOpen(true);\n\t\t},\n\n\t\tget unreadCount() {\n\t\t\treturn store.getState().conversations.reduce((sum, c) => sum + c.unreadCount, 0);\n\t\t},\n\n\t\tget isOpen() {\n\t\t\treturn store.getState().isOpen;\n\t\t},\n\n\t\ton(event, fn) {\n\t\t\temitter.on(event, fn);\n\t\t},\n\n\t\toff(event, fn) {\n\t\t\temitter.off(event, fn);\n\t\t},\n\t};\n}\n","/**\n * Widget theming — typed surface over the CSS custom properties baked\n * into the default themed widget. Consumers pass a `WidgetTheme` object;\n * `applyTheme` writes the values onto the host element so the cascade\n * picks them up inside the Shadow DOM.\n *\n * Common cases (color, position, radius) get their own first-class\n * fields. Anything else can still be set via `cssVariables` — it's a\n * raw passthrough for custom var names we don't model yet.\n *\n * **Note for SDK consumers:** prefer dashboard-driven theming when you\n * can — changes go live without a redeploy. This API is for runtime-\n * resolved values (multi-tenant, dark/light sync with the host app).\n *\n * @see https://helpway.ai/docs/customization for the full reference,\n * the dashboard config UI, and the multi-tenant example.\n */\n\nexport type WidgetPosition = \"bottom-right\" | \"bottom-left\";\n\n/**\n * Where the widget lives on the page. The conversation UI is identical\n * across all of these — only the shell moves, so this is one prop rather\n * than six components.\n *\n * - `bubble` launcher bottom-right, panel above it (the default)\n * - `docked` composer bar pinned to the foot of the page; the bar IS\n * the composer, so the panel above it renders without one\n * - `spotlight` centred over a scrim, opened by a shortcut\n * - `sidebar` docked full-height rail that pushes page content\n * - `page` the widget is the whole route (e.g. /help)\n * - `mobile` full-height sheet; a placement, not a breakpoint\n */\nexport type WidgetPlacement =\n\t| \"bubble\"\n\t| \"docked\"\n\t| \"spotlight\"\n\t| \"sidebar\"\n\t| \"page\"\n\t| \"mobile\";\n\n/**\n * A way in offered before the visitor has said anything. A bare string is\n * the question; the object form adds the short category label that makes a\n * list of three scannable instead of three sentences to read.\n */\nexport type DockSuggestion = string | { label: string; question: string };\n\nexport interface WidgetTheme {\n\t/** Launcher background + accent color. Hover variant is auto-derived. */\n\tprimaryColor?: string;\n\t/** Text/icon color rendered ON TOP of `primaryColor`. Defaults to white. */\n\tonPrimaryColor?: string;\n\t/** Visitor (outgoing) message bubble background. Defaults to `primaryColor`. */\n\tbubbleColor?: string;\n\t/** Visitor message bubble text color. Defaults to `onPrimaryColor`. */\n\tbubbleTextColor?: string;\n\t/** Widget panel background color. */\n\tbackgroundColor?: string;\n\t/** Widget panel text color. */\n\ttextColor?: string;\n\t/** Border color used inside the panel. */\n\tborderColor?: string;\n\t/** Corner radius for the panel + cards (any valid CSS length). */\n\tradius?: string;\n\t/** Font family stack for everything inside the widget. */\n\tfontFamily?: string;\n\t/** Launcher + panel placement. Defaults to \"bottom-right\". */\n\tposition?: WidgetPosition;\n\t/**\n\t * Which appearance the widget takes.\n\t *\n\t * `\"system\"` follows the VISITOR'S OS, which is the historical default\n\t * and is usually wrong: an embedded support widget lives inside someone\n\t * else's page, and a light page in a dark-OS browser gets a dark widget\n\t * stapled to it. Pass `\"light\"` or `\"dark\"` to match the host page.\n\t * @default \"system\"\n\t */\n\tcolorScheme?: \"light\" | \"dark\" | \"system\";\n\t/**\n\t * Which shell the widget renders in. Defaults to \"bubble\".\n\t * See {@link WidgetPlacement}.\n\t */\n\tplacement?: WidgetPlacement;\n\t/**\n\t * Drop to the `mobile` sheet automatically below `mobileBreakpoint`.\n\t * Defaults to true — a 400px panel on a 390px screen is not a panel.\n\t */\n\tautoMobile?: boolean;\n\t/** Width under which `autoMobile` takes over, in px. Defaults to 480. */\n\tmobileBreakpoint?: number;\n\t/**\n\t * Escape hatch: any CSS custom property not modeled above. Keys must\n\t * start with `--`. Wins over the typed fields above when both set.\n\t */\n\tcssVariables?: Record<`--${string}`, string>;\n}\n\n/** Validate a hex like `#aabbcc`. We're conservative on purpose. */\nfunction isValidHex(color: string): boolean {\n\treturn /^#[0-9a-fA-F]{6}$/.test(color);\n}\n\n/**\n * Lighten a #rrggbb hex by a fixed amount (used as the hover variant\n * of `primaryColor`). Non-hex inputs return unchanged so callers can\n * pass `oklch(...)`, `hsl(...)`, etc. and bring their own hover.\n */\nfunction lighten(hex: string): string {\n\tif (!isValidHex(hex)) return hex;\n\tconst r = Math.min(255, Number.parseInt(hex.slice(1, 3), 16) + 30);\n\tconst g = Math.min(255, Number.parseInt(hex.slice(3, 5), 16) + 30);\n\tconst b = Math.min(255, Number.parseInt(hex.slice(5, 7), 16) + 30);\n\tconst hex2 = (n: number) => n.toString(16).padStart(2, \"0\");\n\treturn `#${hex2(r)}${hex2(g)}${hex2(b)}`;\n}\n\n/** Map a single typed field onto its CSS variable(s). */\nfunction setVar(host: HTMLElement, name: string, value: string | undefined) {\n\tif (value == null || value === \"\") return;\n\thost.style.setProperty(name, value);\n}\n\n/**\n * Write a `WidgetTheme` onto the host element. Safe to call multiple\n * times — every call is incremental, only the keys you provide are\n * touched. Pass `undefined` for a field to leave the existing value alone;\n * call `clearTheme()` if you want to reset.\n */\nexport function applyTheme(host: HTMLElement, theme: WidgetTheme | undefined) {\n\tif (!host || !theme) return;\n\n\tif (theme.primaryColor) {\n\t\tsetVar(host, \"--hw-primary\", theme.primaryColor);\n\t\tsetVar(host, \"--hw-primary-hover\", lighten(theme.primaryColor));\n\t\tsetVar(host, \"--hw-brand\", theme.primaryColor);\n\t}\n\tsetVar(host, \"--hw-on-brand\", theme.onPrimaryColor);\n\tsetVar(host, \"--hw-visitor-bubble-bg\", theme.bubbleColor ?? theme.primaryColor);\n\tsetVar(host, \"--hw-visitor-bubble-text\", theme.bubbleTextColor ?? theme.onPrimaryColor);\n\tsetVar(host, \"--hw-bg\", theme.backgroundColor);\n\tsetVar(host, \"--hw-text\", theme.textColor);\n\tsetVar(host, \"--hw-border\", theme.borderColor);\n\tsetVar(host, \"--hw-radius\", theme.radius);\n\tsetVar(host, \"--hw-font\", theme.fontFamily);\n\n\tif (theme.position === \"bottom-left\") {\n\t\tsetVar(host, \"--hw-position-right\", \"auto\");\n\t\tsetVar(host, \"--hw-position-left\", \"20px\");\n\t\tsetVar(host, \"--hw-window-right\", \"auto\");\n\t\tsetVar(host, \"--hw-window-left\", \"0\");\n\t} else if (theme.position === \"bottom-right\") {\n\t\thost.style.removeProperty(\"--hw-position-right\");\n\t\thost.style.removeProperty(\"--hw-position-left\");\n\t\thost.style.removeProperty(\"--hw-window-right\");\n\t\thost.style.removeProperty(\"--hw-window-left\");\n\t}\n\n\t// The shell reads placement off the host as a data attribute rather\n\t// than a CSS variable — CSS variables cannot drive selectors, and every\n\t// shell rule is a selector (`[data-hw-placement=\"docked\"] .hw-panel`).\n\tif (theme.placement) host.dataset.hwPlacement = theme.placement;\n\n\t// The dark-token blocks are all guarded with\n\t// `.hw-widget:not([data-theme=\"light\"])`, so writing this attribute is\n\t// what actually pins the appearance. \"system\" leaves it unset and the\n\t// prefers-color-scheme media query decides.\n\tif (theme.colorScheme === \"light\" || theme.colorScheme === \"dark\") {\n\t\thost.dataset.theme = theme.colorScheme;\n\t} else if (theme.colorScheme === \"system\") {\n\t\tdelete host.dataset.theme;\n\t}\n\n\tif (theme.cssVariables) {\n\t\tfor (const [key, value] of Object.entries(theme.cssVariables)) {\n\t\t\tif (key.startsWith(\"--\")) host.style.setProperty(key, value);\n\t\t}\n\t}\n}\n\n/**\n * Resolve the placement actually in effect, folding in the automatic\n * mobile drop. Kept out of `applyTheme` so the React layer can call it on\n * every resize without re-writing the whole token set.\n */\nexport function resolvePlacement(\n\ttheme: WidgetTheme | undefined,\n\tviewportWidth: number,\n): WidgetPlacement {\n\tconst requested = theme?.placement ?? \"bubble\";\n\tif (requested === \"mobile\") return \"mobile\";\n\tconst auto = theme?.autoMobile ?? true;\n\tconst breakpoint = theme?.mobileBreakpoint ?? 480;\n\t// `page` owns its whole route, so it stays a page on a phone — it is\n\t// already full-bleed and has no launcher to get in the way.\n\tif (auto && requested !== \"page\" && viewportWidth < breakpoint) return \"mobile\";\n\treturn requested;\n}\n","export type Listener<T = unknown> = (data: T) => void;\n\nexport interface WidgetEvents {\n\topen: undefined;\n\tclose: undefined;\n\tdismiss: undefined;\n\tshow: undefined;\n\tunreadChange: number;\n\tmessageReceived: { conversationId: string; text: string; senderName: string | null };\n\tready: undefined;\n}\n\nexport type WidgetEventName = keyof WidgetEvents;\n\nexport class WidgetEventEmitter {\n\tprivate listeners = new Map<string, Set<Listener>>();\n\n\ton<K extends WidgetEventName>(event: K, fn: Listener<WidgetEvents[K]>): void {\n\t\tif (!this.listeners.has(event)) this.listeners.set(event, new Set());\n\t\tthis.listeners.get(event)!.add(fn as Listener);\n\t}\n\n\toff<K extends WidgetEventName>(event: K, fn: Listener<WidgetEvents[K]>): void {\n\t\tthis.listeners.get(event)?.delete(fn as Listener);\n\t}\n\n\temit<K extends WidgetEventName>(\n\t\tevent: K,\n\t\t...args: WidgetEvents[K] extends undefined ? [] : [WidgetEvents[K]]\n\t): void {\n\t\tconst data = args[0];\n\t\tthis.listeners.get(event)?.forEach((fn) => {\n\t\t\ttry {\n\t\t\t\tfn(data);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[Helpway] Event handler error (${event}):`, err);\n\t\t\t}\n\t\t});\n\t}\n\n\tremoveAll(): void {\n\t\tthis.listeners.clear();\n\t}\n}\n","/**\n * Page tracking that waits for the title to belong to the URL (#186).\n *\n * `pushState` changes the URL synchronously; the host framework writes\n * `document.title` from its own head effect after the new route has rendered.\n * The old tracker sampled the title on a 250 ms timer after the URL change,\n * which is a guess about the framework's commit timing, and on a visitor\n * clicking through pages one to two seconds apart it lost every time: the\n * recorded history paired each new URL with the previous page's title, so an\n * agent reading it concluded the visitor was on a Svelte page when they were\n * on the CLI docs.\n *\n * This tracker does not sample. It captures the URL at navigation time and\n * reports when one of two things happens, whichever comes first:\n *\n * - the title changes (observed, not polled) — the framework has committed\n * the new head, so the pair is trustworthy;\n * - a bounded wait elapses with no title change — the route may keep the\n * same title on purpose, and a history with the right URL and a possibly\n * inherited title beats no history. If the title then changes while the\n * visitor is still on that URL, one correction is sent for it.\n *\n * Invariants the tests pin:\n * - a title that arrives after the URL is reported with that URL, never\n * with the previous one;\n * - a URL is reported at most once plus at most one correction;\n * - a navigation that is superseded before it settles is never reported;\n * - the same (url, title) pair is never reported twice in a row.\n *\n * Framework-free on purpose: `window`, `document` and `MutationObserver` are\n * injected, so the timing can be driven deterministically in a test, and the\n * React provider only supplies the browser bindings.\n */\n\nexport interface TrackedPage {\n\turl: string;\n\ttitle: string;\n}\n\nexport interface PageTrackerDeps {\n\t/** Current address, e.g. `window.location.href`. */\n\tgetUrl: () => string;\n\t/** Current title, already falling back to something non-empty. */\n\tgetTitle: () => string;\n\t/**\n\t * Call `onChange` whenever the document title may have changed. Returns the\n\t * unsubscribe. Return a no-op when observation is unavailable; the tracker\n\t * then relies on the bounded wait alone.\n\t */\n\tobserveTitle: (onChange: () => void) => () => void;\n\t/** Deliver one page view. Errors are the caller's to swallow. */\n\treport: (page: TrackedPage) => void;\n\t/** Coalesce a burst of head mutations before reading the title. */\n\tsettleMs?: number;\n\t/** How long to wait for a title change before reporting what is there. */\n\tmaxWaitMs?: number;\n\t/** Injectable clock, for tests. */\n\tsetTimeout?: (fn: () => void, ms: number) => unknown;\n\tclearTimeout?: (handle: unknown) => void;\n}\n\nexport interface PageTracker {\n\t/** The URL changed (pushState, replaceState, popstate, or first load). */\n\tnavigate: () => void;\n\t/** Stop observing and drop anything pending. Nothing is reported after this. */\n\tstop: () => void;\n}\n\nexport const DEFAULT_TITLE_SETTLE_MS = 50;\nexport const DEFAULT_TITLE_MAX_WAIT_MS = 1000;\n\nexport function createPageTracker(deps: PageTrackerDeps): PageTracker {\n\tconst settleMs = deps.settleMs ?? DEFAULT_TITLE_SETTLE_MS;\n\tconst maxWaitMs = deps.maxWaitMs ?? DEFAULT_TITLE_MAX_WAIT_MS;\n\tconst schedule = deps.setTimeout ?? ((fn, ms) => setTimeout(fn, ms));\n\tconst cancel = deps.clearTimeout ?? ((h) => clearTimeout(h as ReturnType<typeof setTimeout>));\n\n\tlet pending: { url: string; titleAtNavigate: string } | null = null;\n\tlet lastReported: TrackedPage | null = null;\n\t/** URL whose report went out with a possibly inherited title. */\n\tlet correctionArmedFor: string | null = null;\n\tlet fallbackTimer: unknown = null;\n\tlet settleTimer: unknown = null;\n\tlet stopped = false;\n\n\tconst clearTimers = () => {\n\t\tif (fallbackTimer !== null) cancel(fallbackTimer);\n\t\tif (settleTimer !== null) cancel(settleTimer);\n\t\tfallbackTimer = null;\n\t\tsettleTimer = null;\n\t};\n\n\tconst send = (page: TrackedPage) => {\n\t\tif (lastReported && lastReported.url === page.url && lastReported.title === page.title) return;\n\t\tlastReported = page;\n\t\tdeps.report(page);\n\t};\n\n\tconst settle = (source: \"title\" | \"fallback\") => {\n\t\tif (stopped || !pending) return;\n\t\tconst title = deps.getTitle();\n\t\t/* A head mutation that left the title as it was is not the commit we are\n\t\t waiting for; keep waiting, the bounded timer still stands. */\n\t\tif (source === \"title\" && title === pending.titleAtNavigate) return;\n\n\t\tconst { url, titleAtNavigate } = pending;\n\t\tpending = null;\n\t\tclearTimers();\n\t\tsend({ url, title });\n\t\t/* Reported on the clock with the title unchanged since the URL moved:\n\t\t either the route shares the title, or the framework is slow. Allow\n\t\t exactly one correction if the latter turns out to be true. */\n\t\tcorrectionArmedFor = source === \"fallback\" && title === titleAtNavigate ? url : null;\n\t};\n\n\tconst onTitleChange = () => {\n\t\tif (stopped) return;\n\t\tif (pending) {\n\t\t\tif (settleTimer !== null) cancel(settleTimer);\n\t\t\tsettleTimer = schedule(() => {\n\t\t\t\tsettleTimer = null;\n\t\t\t\tsettle(\"title\");\n\t\t\t}, settleMs);\n\t\t\treturn;\n\t\t}\n\t\tif (correctionArmedFor !== null && deps.getUrl() === correctionArmedFor) {\n\t\t\tconst title = deps.getTitle();\n\t\t\tif (lastReported && title !== lastReported.title) {\n\t\t\t\tcorrectionArmedFor = null;\n\t\t\t\tsend({ url: lastReported.url, title });\n\t\t\t}\n\t\t}\n\t};\n\n\tconst unobserve = deps.observeTitle(onTitleChange);\n\n\treturn {\n\t\tnavigate() {\n\t\t\tif (stopped) return;\n\t\t\tconst url = deps.getUrl();\n\t\t\t/* pushState followed by replaceState on the same address is common;\n\t\t\t the first navigation's wait keeps running. */\n\t\t\tif (pending?.url === url) return;\n\t\t\tclearTimers();\n\t\t\tcorrectionArmedFor = null;\n\t\t\tpending = { url, titleAtNavigate: deps.getTitle() };\n\t\t\tfallbackTimer = schedule(() => {\n\t\t\t\tfallbackTimer = null;\n\t\t\t\tsettle(\"fallback\");\n\t\t\t}, maxWaitMs);\n\t\t},\n\t\tstop() {\n\t\t\tstopped = true;\n\t\t\tclearTimers();\n\t\t\tpending = null;\n\t\t\tunobserve();\n\t\t},\n\t};\n}\n","\"use client\";\n\nimport {\n\ttype HelpwayMethods,\n\tWebSocketManager,\n\ttype WidgetClient,\n\tWidgetEventEmitter,\n\ttype WidgetStore,\n\ttype WidgetTheme,\n\tapplyTheme,\n\tcreateHelpwayAPI,\n\tcreatePageTracker,\n\tcreateWidgetClient,\n\tcreateWidgetStore,\n\tinitI18n,\n\tinstallCallable,\n\tsetLocale,\n\tsyncVisitorId,\n} from \"@helpway/widget-core\";\nimport {\n\ttype ReactNode,\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { type StoreApi, useStore } from \"zustand\";\n\n// ── Context ──────────────────────────────────────────────\n\nexport interface IdentifyData {\n\texternalId: string;\n\temail?: string;\n\tname?: string;\n\timage?: string;\n\tmetadata?: Record<string, unknown>;\n\t/**\n\t * Move this browser's visitor to the contact above even if it already\n\t * belongs to a different contact. Dangerous: it merges whatever history\n\t * this browser has into that contact. Off by default; without it the\n\t * server keeps the existing link and returns that contact (#193).\n\t */\n\treassign?: boolean;\n}\n\ninterface WidgetContextValue {\n\tclient: WidgetClient;\n\tstore: StoreApi<WidgetStore>;\n\tws: WebSocketManager;\n\tidentify: (data: IdentifyData) => Promise<void>;\n\tapi: HelpwayMethods;\n\temitter: WidgetEventEmitter;\n\thasBootstrapError: boolean;\n\twsDisconnected: boolean;\n\tretryBootstrap: () => void;\n\t/** Explicit language hint for `widget.createConversation`'s `sourceLocale`\n\t * — see `sourceLocaleRef` docstring in `SupportProvider`. `undefined`\n\t * when no explicit signal was ever given. */\n\tgetSourceLocale: () => string | undefined;\n}\n\nconst WidgetContext = createContext<WidgetContextValue | null>(null);\n\nexport function useWidgetContext(): WidgetContextValue {\n\tconst ctx = useContext(WidgetContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useWidgetContext must be used within <SupportProvider>\");\n\t}\n\treturn ctx;\n}\n\n/** Use a slice of the widget store with auto re-render */\nexport function useWidgetStore<T>(selector: (state: WidgetStore) => T): T {\n\tconst { store } = useWidgetContext();\n\treturn useStore(store, selector);\n}\n\n/** Hook to identify the current visitor (link to customer contact) */\nexport function useIdentify() {\n\tconst { identify } = useWidgetContext();\n\treturn identify;\n}\n\n/** Raw tRPC client — used by interactive components that need to call\n * mutations not exposed via the public HelpwayMethods (e.g. workflow\n * quick-reply taps). The client is `any`-typed by design (see\n * packages/widget-core/src/client.ts) so callers must spell mutation\n * paths explicitly. */\nexport function useWidgetClient(): WidgetClient {\n\tconst { client } = useWidgetContext();\n\treturn client;\n}\n\n// ── Provider ─────────────────────────────────────────────\n\ninterface SupportProviderProps {\n\tapiKey: string;\n\tapiUrl?: string;\n\tlocale?: string;\n\tinitialConversationId?: string;\n\tdeepLinkToken?: string;\n\tonReady?: (api: HelpwayMethods) => void;\n\tcustomLauncherSelector?: string;\n\tonOpen?: () => void;\n\tonClose?: () => void;\n\tonUnreadChange?: (count: number) => void;\n\t/**\n\t * Developer-side theme override. Most consumers should configure\n\t * appearance in the Helpway dashboard (see\n\t * https://helpway.ai/docs/customization) so changes apply without\n\t * a redeploy. Use this prop only when you need the widget to inherit\n\t * a host-app theme that the dashboard can't see (e.g. a tenant-\n\t * specific brand color resolved at runtime). Values here are written\n\t * as CSS custom properties on the widget host and override the\n\t * dashboard config for this mount only.\n\t */\n\ttheme?: WidgetTheme;\n\tchildren: ReactNode;\n}\n\n/**\n * Root provider for the Helpway widget.\n * Creates tRPC client, WebSocket connection, and state store.\n *\n * Visitor identity is managed via server-side cookies (hw_visitor).\n * No localStorage or client-side ID management needed.\n */\nexport function SupportProvider({\n\tapiKey,\n\tapiUrl,\n\tlocale,\n\tinitialConversationId,\n\tdeepLinkToken,\n\tonReady,\n\tcustomLauncherSelector,\n\tonOpen,\n\tonClose,\n\tonUnreadChange,\n\ttheme,\n\tchildren,\n}: SupportProviderProps) {\n\tconst initRef = useRef<{\n\t\tclient: WidgetClient;\n\t\tstore: StoreApi<WidgetStore>;\n\t\tws: WebSocketManager;\n\t\tidentify: (data: IdentifyData) => Promise<void>;\n\t\tapi: HelpwayMethods;\n\t\temitter: WidgetEventEmitter;\n\t} | null>(null);\n\tconst [hasBootstrapError, setHasBootstrapError] = useState(false);\n\tconst [wsDisconnected, setWsDisconnected] = useState(false);\n\tconst [bootstrapAttempt, setBootstrapAttempt] = useState(0);\n\n\t/**\n\t * Explicit language hint for `widget.createConversation` (helpway#48,\n\t * helpway#51 — `sourceLocale`). Populated ONLY from signals the host site\n\t * or its own backend actually vouched for: the `locale` prop and\n\t * `identify()`'s `metadata.locale`. Deliberately NEVER set from\n\t * `navigator.language` or the server's geo/Accept-Language-derived\n\t * `detectedLocale` (bootstrap) — those are exactly the guesses the\n\t * precedence chain treats as lower-priority fallbacks, so echoing them\n\t * back as an \"explicit\" hint would just re-introduce the EN/US skew this\n\t * fixes. A ref, not state — read once at send time, doesn't need to\n\t * trigger a re-render.\n\t */\n\tconst sourceLocaleRef = useRef<string | undefined>(locale);\n\tconst getSourceLocale = useCallback(() => sourceLocaleRef.current, []);\n\n\tif (!initRef.current) {\n\t\tconst resolvedApiUrl = apiUrl ?? inferApiUrl();\n\n\t\tconst client = createWidgetClient({\n\t\t\tapiUrl: resolvedApiUrl,\n\t\t\tapiKey,\n\t\t});\n\n\t\tconst store = createWidgetStore();\n\t\tconst emitter = new WidgetEventEmitter();\n\n\t\tconst ws = new WebSocketManager({\n\t\t\tapiUrl: resolvedApiUrl,\n\t\t\tvisitorId: \"\",\n\t\t\twebsiteId: \"\",\n\t\t\tapiKey,\n\t\t});\n\n\t\tconst identify = async (data: IdentifyData) => {\n\t\t\ttry {\n\t\t\t\tconst result = await client.widget.identify.mutate(data);\n\t\t\t\tif (result.contact) {\n\t\t\t\t\tstore.getState().updateVisitorContact({\n\t\t\t\t\t\tid: result.contact.id,\n\t\t\t\t\t\tname: result.contact.name ?? null,\n\t\t\t\t\t\temail: result.contact.email ?? null,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst metaLocale = data.metadata?.locale;\n\t\t\t\tif (typeof metaLocale === \"string\" && metaLocale.length > 0) {\n\t\t\t\t\tsetLocale(metaLocale);\n\t\t\t\t\t// identify() metadata is the host app's own record of this\n\t\t\t\t\t// visitor's language — an explicit signal, same tier as the\n\t\t\t\t\t// `locale` prop.\n\t\t\t\t\tsourceLocaleRef.current = metaLocale;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Helpway] identify failed:\", err);\n\t\t\t}\n\t\t};\n\n\t\tconst api = createHelpwayAPI({ store, emitter, identify, apiKey });\n\n\t\t// Lazy init, once. react-doctor flags this as a ref mutated during\n\t\t// render and it is wrong to \"fix\": the values are consumed on this\n\t\t// same render two lines down, so moving the assignment into an\n\t\t// effect leaves client/store undefined on first paint. This is the\n\t\t// shape React's own docs sanction for expensive one-time setup.\n\t\tinitRef.current = { client, store, ws, identify, api, emitter };\n\t}\n\n\tconst { client, store, ws, identify, api, emitter } = initRef.current;\n\n\tconst retryBootstrap = useCallback(() => {\n\t\tsetHasBootstrapError(false);\n\t\tsetBootstrapAttempt((n) => n + 1);\n\t}, []);\n\n\t// Bootstrap on mount (re-runs on retry)\n\tuseEffect(() => {\n\t\tlet cancelled = false;\n\n\t\tasync function bootstrap() {\n\t\t\ttry {\n\t\t\t\tconst data = await client.widget.bootstrap.query();\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\t// Initialize i18n BEFORE setReady to avoid flash of English text.\n\t\t\t\t// Priority: explicit `locale` prop → server-side detection\n\t\t\t\t// (Accept-Language + CF-IPCountry) → widget-core bundled default.\n\t\t\t\tconst resolvedLocale =\n\t\t\t\t\tlocale ?? (data as { detectedLocale?: string | null }).detectedLocale ?? undefined;\n\t\t\t\tawait initI18n({\n\t\t\t\t\tlocale: resolvedLocale,\n\t\t\t\t\tcdnBase: (data.agentConfig as { i18nCdnBase?: string } | null)?.i18nCdnBase ?? undefined,\n\t\t\t\t});\n\n\t\t\t\tstore.getState().setReady(data.visitor, data.website, data.agentConfig);\n\t\t\t\tsetHasBootstrapError(false);\n\n\t\t\t\t// Sync the server-signed visitor ID to localStorage — sent back as\n\t\t\t\t// X-Visitor-Id on every subsequent request (client.ts). Only the\n\t\t\t\t// SIGNED form (helpway#122 round 2) lets the API's write rate\n\t\t\t\t// limiter recognize this as a real visitor instead of falling to\n\t\t\t\t// the shared, stricter \"unsigned\" tier. `?? data.visitor.id` is a\n\t\t\t\t// defensive fallback for an older API build that doesn't send\n\t\t\t\t// `signedId` yet — never happens against a current deploy, but\n\t\t\t\t// costs nothing to keep the widget from throwing if one is mid-roll.\n\t\t\t\tif (data.visitor?.id) {\n\t\t\t\t\tsyncVisitorId(apiKey, data.visitor.signedId ?? data.visitor.id);\n\t\t\t\t}\n\n\t\t\t\tconst convData = await client.widget.listConversations.query();\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\tconst mapConversation = (c: {\n\t\t\t\t\tid: string;\n\t\t\t\t\ttitle: string | null;\n\t\t\t\t\tstatus: string;\n\t\t\t\t\tlastMessageText: string | null;\n\t\t\t\t\tlastMessageAt: string | null;\n\t\t\t\t\tlastMessageSenderType: string | null;\n\t\t\t\t\tlastMessageSenderName: string | null;\n\t\t\t\t\tlastMessageSenderImage: string | null;\n\t\t\t\t\tunreadCount?: number | null;\n\t\t\t\t}) => ({\n\t\t\t\t\tid: c.id,\n\t\t\t\t\ttitle: c.title,\n\t\t\t\t\tstatus: c.status,\n\t\t\t\t\tlastMessageText: c.lastMessageText,\n\t\t\t\t\tlastMessageAt: c.lastMessageAt,\n\t\t\t\t\tlastMessageSenderType: c.lastMessageSenderType,\n\t\t\t\t\tlastMessageSenderName: c.lastMessageSenderName,\n\t\t\t\t\tlastMessageSenderImage: c.lastMessageSenderImage,\n\t\t\t\t\t/* The server's count, not a zero.\n\n\t\t\t\t\t This was the literal `0`, which meant `useUnread()` answered 0 on\n\t\t\t\t\t every page load however many replies were waiting — the value\n\t\t\t\t\t described \"messages that arrived while this tab has been open\",\n\t\t\t\t\t not \"unread\". A badge shipped against the hook downstream never\n\t\t\t\t\t rendered once, with an unanswered agent message on screen.\n\n\t\t\t\t\t Still defaulted, because a widget on an older API build gets a\n\t\t\t\t\t payload without the field, and 0 is the honest answer there — the\n\t\t\t\t\t socket path raises it from there as messages land. */\n\t\t\t\t\tunreadCount: c.unreadCount ?? 0,\n\t\t\t\t});\n\n\t\t\t\tstore.getState().setConversations(convData.conversations.map(mapConversation));\n\n\t\t\t\t// Connect WebSocket BEFORE the proactive check so the visitor-channel\n\t\t\t\t// subscription is live by the time the workflow orchestrator emits\n\t\t\t\t// timelineItemCreated. Without this, the greeting message is broadcast\n\t\t\t\t// to a not-yet-subscribed client and the launcher preview bubble never\n\t\t\t\t// appears (only the unread badge increments via REST).\n\t\t\t\tif (data.website?.id && data.visitor?.id) {\n\t\t\t\t\tws.configure({ websiteId: data.website.id, visitorId: data.visitor.id });\n\t\t\t\t\tws.connect();\n\t\t\t\t}\n\n\t\t\t\tif (convData.conversations.length === 0 && !initialConversationId) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst proactive = await client.widget.proactiveCheck.mutate();\n\t\t\t\t\t\tif (cancelled || !proactive.triggered) {\n\t\t\t\t\t\t\t// nothing to do\n\t\t\t\t\t\t} else if (proactive.ephemeral) {\n\t\t\t\t\t\t\t// Render the greeting + (optional) quick replies entirely\n\t\t\t\t\t\t\t// client-side. No server-side conversation exists yet — we\n\t\t\t\t\t\t\t// materialize on the visitor's first reply.\n\t\t\t\t\t\t\thandleEphemeralProactive(store, proactive.ephemeral);\n\t\t\t\t\t\t} else if (proactive.conversationId) {\n\t\t\t\t\t\t\t// Fallback path for complex workflows that needed the\n\t\t\t\t\t\t\t// orchestrator up-front (delays, AI agent before any\n\t\t\t\t\t\t\t// visitor input, etc).\n\t\t\t\t\t\t\tconst nowIso = new Date().toISOString();\n\t\t\t\t\t\t\tstore.getState().addConversation({\n\t\t\t\t\t\t\t\tid: proactive.conversationId,\n\t\t\t\t\t\t\t\ttitle: null,\n\t\t\t\t\t\t\t\tstatus: \"open\",\n\t\t\t\t\t\t\t\tlastMessageText: proactive.lastMessageText ?? null,\n\t\t\t\t\t\t\t\tlastMessageAt: proactive.lastMessageAt ?? nowIso,\n\t\t\t\t\t\t\t\tlastMessageSenderType: proactive.lastMessageSenderType ?? null,\n\t\t\t\t\t\t\t\tlastMessageSenderName: null,\n\t\t\t\t\t\t\t\tlastMessageSenderImage: null,\n\t\t\t\t\t\t\t\tassigneeName: null,\n\t\t\t\t\t\t\t\tassigneeImage: null,\n\t\t\t\t\t\t\t\tunreadCount: 1,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (proactive.lastMessageText && !store.getState().isOpen) {\n\t\t\t\t\t\t\t\tstore.setState({\n\t\t\t\t\t\t\t\t\tincomingPreview: {\n\t\t\t\t\t\t\t\t\t\ttext: proactive.lastMessageText,\n\t\t\t\t\t\t\t\t\t\tconversationId: proactive.conversationId,\n\t\t\t\t\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// proactive check is best-effort\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* First page view goes through the same tracker as route changes, so\n\t\t\t\t a framework that writes <title> after hydration is waited for here\n\t\t\t\t too instead of being read mid-commit. */\n\t\t\t\tpageTracker?.navigate();\n\n\t\t\t\tif (initialConversationId && !cancelled) {\n\t\t\t\t\tif (deepLinkToken) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst redeemed = await client.widget.redeemDeepLink.mutate({ token: deepLinkToken });\n\t\t\t\t\t\t\tif (!cancelled && redeemed?.visitorId && redeemed.visitorId !== data.visitor?.id) {\n\t\t\t\t\t\t\t\t// Sync the signed form (helpway#122 round 2) — same reasoning\n\t\t\t\t\t\t\t\t// as the bootstrap sync above.\n\t\t\t\t\t\t\t\tsyncVisitorId(apiKey, redeemed.signedVisitorId ?? redeemed.visitorId);\n\t\t\t\t\t\t\t\tconst freshData = await client.widget.bootstrap.query();\n\t\t\t\t\t\t\t\tif (!cancelled) {\n\t\t\t\t\t\t\t\t\tstore\n\t\t\t\t\t\t\t\t\t\t.getState()\n\t\t\t\t\t\t\t\t\t\t.setReady(freshData.visitor, freshData.website, freshData.agentConfig);\n\t\t\t\t\t\t\t\t\tconst freshConvs = await client.widget.listConversations.query();\n\t\t\t\t\t\t\t\t\tif (!cancelled) {\n\t\t\t\t\t\t\t\t\t\tstore\n\t\t\t\t\t\t\t\t\t\t\t.getState()\n\t\t\t\t\t\t\t\t\t\t\t.setConversations(freshConvs.conversations.map(mapConversation));\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Token invalid/expired — still open widget but without identity restoration\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!cancelled) {\n\t\t\t\t\t\tstore.getState().setActiveConversation(initialConversationId);\n\t\t\t\t\t\tstore.getState().setOpen(true);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\temitter.emit(\"ready\");\n\t\t\t\tonReady?.(initRef.current!.api);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Helpway] Bootstrap failed:\", err);\n\t\t\t\tif (!cancelled) {\n\t\t\t\t\tstore.getState().setConnecting(false);\n\t\t\t\t\tsetHasBootstrapError(true);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// SPA route tracking — patches pushState/replaceState + listens for\n\t\t// popstate so updatePage fires whenever the visitor navigates without\n\t\t// a full reload. Server stores last 20 page views in visitor.pageHistory\n\t\t// for support agent context.\n\t\t//\n\t\t// The title is not read on a timer (#186): `pushState` moves the URL\n\t\t// synchronously, the host framework writes <title> from its own head\n\t\t// effect afterwards, and a fixed delay recorded each new URL with the\n\t\t// previous page's title. The tracker waits for the title to change, or\n\t\t// for a bounded fallback, before it reports — see widget-core/page-tracker.\n\t\tconst pageTracker =\n\t\t\ttypeof window === \"undefined\"\n\t\t\t\t? null\n\t\t\t\t: createPageTracker({\n\t\t\t\t\t\tgetUrl: () => window.location.href,\n\t\t\t\t\t\tgetTitle: () => document.title || window.location.pathname,\n\t\t\t\t\t\tobserveTitle: (onChange) => {\n\t\t\t\t\t\t\tif (typeof MutationObserver === \"undefined\") return () => {};\n\t\t\t\t\t\t\t/* The whole head, not the <title> node: frameworks replace the\n\t\t\t\t\t\t\t element rather than edit its text, and a new node would escape\n\t\t\t\t\t\t\t an observer pinned to the old one. */\n\t\t\t\t\t\t\tconst observer = new MutationObserver(onChange);\n\t\t\t\t\t\t\tobserver.observe(document.head ?? document.documentElement, {\n\t\t\t\t\t\t\t\tsubtree: true,\n\t\t\t\t\t\t\t\tchildList: true,\n\t\t\t\t\t\t\t\tcharacterData: true,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\treturn () => observer.disconnect();\n\t\t\t\t\t\t},\n\t\t\t\t\t\treport: (page) => {\n\t\t\t\t\t\t\tclient.widget.updatePage.mutate(page).catch(() => {});\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\tconst reportPage = () => {\n\t\t\tpageTracker?.navigate();\n\t\t};\n\n\t\tbootstrap();\n\n\t\tconst origPush = window.history.pushState.bind(window.history);\n\t\tconst origReplace = window.history.replaceState.bind(window.history);\n\t\twindow.history.pushState = function patchedPush(...args) {\n\t\t\torigPush(...args);\n\t\t\treportPage();\n\t\t};\n\t\twindow.history.replaceState = function patchedReplace(...args) {\n\t\t\torigReplace(...args);\n\t\t\treportPage();\n\t\t};\n\t\twindow.addEventListener(\"popstate\", reportPage);\n\n\t\t// Debounced markSeen — coalesces rapid events (AI may stream multiple\n\t\t// messages, plus the typing/processing events fire too).\n\t\tlet markSeenTimer: ReturnType<typeof setTimeout> | null = null;\n\t\tconst scheduleMarkSeen = (conversationId: string) => {\n\t\t\tif (markSeenTimer) clearTimeout(markSeenTimer);\n\t\t\tmarkSeenTimer = setTimeout(() => {\n\t\t\t\tclient.widget.markSeen.mutate({ conversationId }).catch(() => {});\n\t\t\t\tstore.getState().clearUnread(conversationId);\n\t\t\t}, 400);\n\t\t};\n\n\t\tconst unsub = ws.onEvent((event) => {\n\t\t\tstore.getState().handleRealtimeEvent(event);\n\n\t\t\tif (event.type === \"timelineItemCreated\") {\n\t\t\t\tconst item = event.item;\n\t\t\t\tconst isPublicIncoming = item?.visibility === \"public\" && !item.visitorId;\n\n\t\t\t\t// Emit messageReceived for public incoming messages\n\t\t\t\tif (isPublicIncoming && item?.text) {\n\t\t\t\t\temitter.emit(\"messageReceived\", {\n\t\t\t\t\t\tconversationId: event.conversationId,\n\t\t\t\t\t\ttext: item.text,\n\t\t\t\t\t\tsenderName: \"aiAgentId\" in item && item.aiAgentId ? \"AI\" : null,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (!isPublicIncoming) return;\n\t\t\t\tconst s = store.getState();\n\t\t\t\tconst isViewing = s.isOpen && s.activeConversationId === event.conversationId;\n\t\t\t\tif (isViewing) scheduleMarkSeen(event.conversationId);\n\t\t\t}\n\t\t});\n\n\t\t/* Monitor WebSocket connection state.\n\n\t\t A reconnect that heals in well under a second is not worth telling anyone\n\t\t about, and the old shape reported it anyway: a bare 3s poll of isConnected\n\t\t could catch a 400ms blip and then hold \"Reconnecting…\" on screen for the\n\t\t rest of its interval. That is how a self-healing state became a visible\n\t\t alarm — the socket was already back before the banner had finished\n\t\t animating in.\n\n\t\t Down has to persist to be reported; recovery is reported at once. The\n\t\t asymmetry is deliberate: being slow to announce trouble costs nothing,\n\t\t being slow to withdraw the claim is the bug. */\n\t\tconst DOWN_GRACE_MS = 2000;\n\t\tlet downSince: number | null = null;\n\t\tconst wsCheck = setInterval(() => {\n\t\t\tif (ws.isConnected) {\n\t\t\t\tdownSince = null;\n\t\t\t\tsetWsDisconnected(false);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (downSince === null) downSince = Date.now();\n\t\t\tsetWsDisconnected(Date.now() - downSince >= DOWN_GRACE_MS);\n\t\t}, 1000);\n\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t\tunsub();\n\t\t\tclearInterval(wsCheck);\n\t\t\tif (markSeenTimer) clearTimeout(markSeenTimer);\n\t\t\tpageTracker?.stop();\n\t\t\twindow.history.pushState = origPush;\n\t\t\twindow.history.replaceState = origReplace;\n\t\t\twindow.removeEventListener(\"popstate\", reportPage);\n\t\t\tws.disconnect();\n\t\t};\n\t}, [client, store, ws, bootstrapAttempt]);\n\n\t// Re-initialize translations when locale prop changes after bootstrap\n\tuseEffect(() => {\n\t\tif (locale != null) {\n\t\t\tsetLocale(locale);\n\t\t\tsourceLocaleRef.current = locale;\n\t\t}\n\t}, [locale]);\n\n\t// Wire up event callbacks: emit open/close events\n\tuseEffect(() => {\n\t\tconst unsub = store.subscribe((state, prev) => {\n\t\t\tif (state.isOpen && !prev.isOpen) {\n\t\t\t\temitter.emit(\"open\");\n\t\t\t\tonOpen?.();\n\t\t\t}\n\t\t\tif (!state.isOpen && prev.isOpen) {\n\t\t\t\temitter.emit(\"close\");\n\t\t\t\tonClose?.();\n\t\t\t}\n\t\t\tconst prevUnread = prev.conversations.reduce((s, c) => s + c.unreadCount, 0);\n\t\t\tconst nextUnread = state.conversations.reduce((s, c) => s + c.unreadCount, 0);\n\t\t\tif (nextUnread !== prevUnread) {\n\t\t\t\temitter.emit(\"unreadChange\", nextUnread);\n\t\t\t\tonUnreadChange?.(nextUnread);\n\t\t\t}\n\t\t});\n\t\treturn unsub;\n\t}, [store, emitter, onOpen, onClose, onUnreadChange]);\n\n\t// Custom launcher selector: attach click handler with MutationObserver fallback for SPAs\n\tuseEffect(() => {\n\t\tif (!customLauncherSelector) return;\n\t\tconst handler = (e: Event) => {\n\t\t\te.preventDefault();\n\t\t\tapi.toggle();\n\t\t};\n\n\t\tconst attach = () => {\n\t\t\tconst el = document.querySelector(customLauncherSelector);\n\t\t\tif (el) {\n\t\t\t\tel.addEventListener(\"click\", handler);\n\t\t\t\treturn el;\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\n\t\tlet el = attach();\n\t\tlet observer: MutationObserver | null = null;\n\n\t\tif (!el) {\n\t\t\tobserver = new MutationObserver(() => {\n\t\t\t\tel = attach();\n\t\t\t\tif (el) observer?.disconnect();\n\t\t\t});\n\t\t\tobserver.observe(document.body, { childList: true, subtree: true });\n\t\t}\n\n\t\treturn () => {\n\t\t\tel?.removeEventListener(\"click\", handler);\n\t\t\tobserver?.disconnect();\n\t\t};\n\t}, [customLauncherSelector, api]);\n\n\t// Sync window.Helpway with the current api instance on mount,\n\t// restore on unmount. Must live in an effect (not the init block)\n\t// so React StrictMode's double mount/unmount cycle doesn't leave\n\t// the global undefined: the effect re-runs on each mount and\n\t// re-installs the callable, while the init block only fires once\n\t// because initRef.current is preserved across remounts.\n\t//\n\t// IMPORTANT: window.Helpway is exposed as a CALLABLE function (Intercom-style)\n\t// so that `Helpway(\"identify\", payload)` works alongside `Helpway.identify(payload)`.\n\t// Earlier versions assigned the raw `api` object here, which clobbered the\n\t// callable installed by the widget-embed loader and made the documented\n\t// `Helpway(\"cmd\", ...)` form throw \"is not a function\" downstream.\n\t// Apply developer-side theme overrides. We target the host that the\n\t// widget script created (#helpway-widget) when running under the\n\t// embed loader; otherwise fall back to documentElement so the CSS\n\t// vars cascade into a Light-DOM React mount. See:\n\t// https://helpway.ai/docs/customization\n\tuseEffect(() => {\n\t\tif (!theme || typeof document === \"undefined\") return;\n\t\tconst target =\n\t\t\t(document.getElementById(\"helpway-widget\") as HTMLElement | null) ?? document.documentElement;\n\t\tapplyTheme(target, theme);\n\t}, [theme]);\n\n\tuseEffect(() => {\n\t\tif (typeof window === \"undefined\") return;\n\t\tconst callable = installCallable(api);\n\t\treturn () => {\n\t\t\tif (window.Helpway === callable) {\n\t\t\t\twindow.Helpway = undefined;\n\t\t\t}\n\t\t\temitter.removeAll();\n\t\t};\n\t}, [api, emitter]);\n\n\tconst ctxValue: WidgetContextValue = {\n\t\tclient,\n\t\tstore,\n\t\tws,\n\t\tidentify,\n\t\tapi,\n\t\temitter,\n\t\thasBootstrapError,\n\t\twsDisconnected,\n\t\tretryBootstrap,\n\t\tgetSourceLocale,\n\t};\n\n\treturn <WidgetContext.Provider value={ctxValue}>{children}</WidgetContext.Provider>;\n}\n\n// ── Helpers ──────────────────────────────────────────────\n\n/**\n * Resolve the API origin when the consumer doesn't pass `apiUrl` explicitly.\n *\n * Order of precedence:\n * 1. CDN script-tag origin — when the widget loads via\n * `<script src=\"https://cdn.helpway.ai/widget.js\" data-key=\"...\">` we\n * derive the origin from the script's URL so the bootstrap call hits\n * the API that owns the public key.\n * 2. Production default — `https://api.helpway.ai`. Matches the JSDoc\n * contract on the `apiUrl` prop.\n *\n * Earlier versions fell back to `window.location.origin` after the script\n * lookup, which broke any framework integration without the script tag\n * (Next App Router, Vite SPA, etc.) — bootstrap hit the consumer's own\n * server and 404'd. The `https://api.helpway.ai` fallback removes that\n * footgun.\n */\n/**\n * Synthetic conversation id prefix used for ephemeral proactive workflows.\n * The send-message flow checks for this prefix and routes to\n * `materializeFromProactive` instead of `sendMessage`/`createConversation`,\n * which is the moment we actually persist the conversation.\n */\nexport const EPHEMERAL_CONV_PREFIX = \"eph-\";\n\ninterface EphemeralProactivePayload {\n\tworkflowId: string;\n\tpathId: string;\n\tmessages: Array<{ stepId: string; text: string; sender: \"ai\" }>;\n\tquickReplies?: {\n\t\tstepId: string;\n\t\tprompt: string;\n\t\toptions: Array<{ id: string; label: string; goToPathId: string }>;\n\t};\n}\n\nfunction handleEphemeralProactive(\n\tstore: StoreApi<WidgetStore>,\n\tpayload: EphemeralProactivePayload,\n) {\n\tconst synthId = `${EPHEMERAL_CONV_PREFIX}${payload.workflowId}`;\n\tconst now = Date.now();\n\tconst lastMessage = payload.messages[payload.messages.length - 1];\n\tconst previewText = lastMessage?.text ?? \"\";\n\n\t// Inject the greeting (and quick replies) as if they came from the\n\t// server. Stagger timestamps so order is preserved if the visitor\n\t// scrolls through them later.\n\tconst items = payload.messages.map((m, i) => ({\n\t\tid: `${synthId}-msg-${m.stepId}`,\n\t\tconversationId: synthId,\n\t\ttype: \"message\" as const,\n\t\ttext: m.text,\n\t\tvisibility: \"public\" as const,\n\t\tuserId: null,\n\t\tvisitorId: null,\n\t\taiAgentId: null,\n\t\tcreatedAt: new Date(now - (payload.messages.length - i) * 100).toISOString(),\n\t\teditedAt: null,\n\t\tdeletedAt: null,\n\t}));\n\n\tif (payload.quickReplies) {\n\t\tconst qrFallback =\n\t\t\tpayload.quickReplies.prompt ||\n\t\t\tpayload.quickReplies.options.map((o) => `• ${o.label}`).join(\"\\n\");\n\t\titems.push({\n\t\t\tid: `${synthId}-qr-${payload.quickReplies.stepId}`,\n\t\t\tconversationId: synthId,\n\t\t\ttype: \"message\",\n\t\t\ttext: qrFallback,\n\t\t\tvisibility: \"public\",\n\t\t\tuserId: null,\n\t\t\tvisitorId: null,\n\t\t\taiAgentId: null,\n\t\t\tcreatedAt: new Date(now).toISOString(),\n\t\t\teditedAt: null,\n\t\t\tdeletedAt: null,\n\t\t\tmetadata: {\n\t\t\t\tkind: \"quick_replies\" as const,\n\t\t\t\tprompt: payload.quickReplies.prompt ?? null,\n\t\t\t\toptions: payload.quickReplies.options.map((o) => ({ id: o.id, label: o.label })),\n\t\t\t\tstepId: payload.quickReplies.stepId,\n\t\t\t},\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: metadata is widely typed\n\t\t} as any);\n\t}\n\n\tconst s = store.getState();\n\ts.addConversation({\n\t\tid: synthId,\n\t\ttitle: null,\n\t\tstatus: \"open\",\n\t\tlastMessageText: previewText,\n\t\tlastMessageAt: new Date(now).toISOString(),\n\t\tlastMessageSenderType: \"ai\",\n\t\tlastMessageSenderName: null,\n\t\tlastMessageSenderImage: null,\n\t\tassigneeName: null,\n\t\tassigneeImage: null,\n\t\tunreadCount: items.length,\n\t});\n\t// biome-ignore lint/suspicious/noExplicitAny: synthetic items match TimelineItem shape\n\ts.setMessages(synthId, items as any);\n\n\tif (!s.isOpen && previewText) {\n\t\tstore.setState({\n\t\t\tincomingPreview: {\n\t\t\t\ttext: previewText,\n\t\t\t\tconversationId: synthId,\n\t\t\t\ttimestamp: now,\n\t\t\t\tmessages: payload.messages.map((m) => ({ text: m.text })),\n\t\t\t\t...(payload.quickReplies\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tquickReplies: {\n\t\t\t\t\t\t\t\tstepId: payload.quickReplies.stepId,\n\t\t\t\t\t\t\t\tprompt: payload.quickReplies.prompt ?? null,\n\t\t\t\t\t\t\t\toptions: payload.quickReplies.options.map((o) => ({\n\t\t\t\t\t\t\t\t\tid: o.id,\n\t\t\t\t\t\t\t\t\tlabel: o.label,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t});\n\t}\n}\n\nfunction inferApiUrl(): string {\n\tif (typeof document !== \"undefined\") {\n\t\tconst script = document.querySelector(\"script[data-key][src]\");\n\t\tif (script) {\n\t\t\tconst src = script.getAttribute(\"src\");\n\t\t\tif (src) {\n\t\t\t\ttry {\n\t\t\t\t\tconst url = new URL(src);\n\t\t\t\t\treturn `${url.protocol}//${url.host}`;\n\t\t\t\t} catch {\n\t\t\t\t\t// Fall through to the production default.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn \"https://api.helpway.ai\";\n}\n","\"use client\";\n\nimport type { TimelineItem } from \"@helpway/types\";\nimport { formatRelativeTime, isAwaitingVisitorReply, t } from \"@helpway/widget-core\";\nimport type {\n\tConversationSummary,\n\tDockSuggestion,\n\tWidgetContentTab,\n\tWidgetPlacement,\n} from \"@helpway/widget-core\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\n/** Resolve a label that might be a translation key (widget.*) or raw text */\nfunction resolveLabel(label: string): string {\n\tif (!label.startsWith(\"widget.\")) return label;\n\tconst resolved = t(label);\n\t// If t() returned the key itself (no translation found), humanize it\n\tif (resolved === label)\n\t\treturn label\n\t\t\t.replace(\"widget.\", \"\")\n\t\t\t.replace(/_/g, \" \")\n\t\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n\treturn resolved;\n}\n\nimport { useAnnouncements } from \"../hooks/use-announcements\";\nimport type { UnseenAnnouncementEntry } from \"../hooks/use-announcements\";\nimport { useAwaitingReply } from \"../hooks/use-awaiting-reply\";\nimport { useComposer } from \"../hooks/use-composer\";\nimport { useConversations } from \"../hooks/use-conversations\";\nimport { conversationIdentity, useHeaderIdentity } from \"../hooks/use-header-identity\";\nimport { useI18n } from \"../hooks/use-i18n\";\nimport { usePresence } from \"../hooks/use-presence\";\nimport { useTimeline } from \"../hooks/use-timeline\";\nimport { useUnread } from \"../hooks/use-unread\";\nimport { useWidget } from \"../hooks/use-widget\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\nimport { DockedBar } from \"../shell/docked-bar\";\nimport { AnnouncementPreviews } from \"./announcement-previews\";\nimport { Composer } from \"./composer\";\nimport { ContentTabView } from \"./content/content-tab-view\";\nimport { ContentTabIconComponent } from \"./content/tab-icon\";\nimport { WidgetDebugOverlay } from \"./debug-overlay\";\nimport { ChevronRightIcon, DotsIcon, NewChatIcon } from \"./icons\";\nimport { HomeIcon, MessagesIcon, SendIcon, XIcon } from \"./icons\";\nimport { MessageBubble } from \"./message-bubble\";\nimport { MessageList } from \"./message-list\";\nimport { MessagePreview } from \"./message-preview\";\nimport { stripMarkdown } from \"./strip-markdown\";\n\nimport type { SubView, Tab } from \"./default-widget/types\";\n\nconst EMPTY_CONTENT_TABS: WidgetContentTab[] = [];\n\n/**\n * Factory-default admin strings. If the admin never customized these\n * values, the widget falls back to t() so visitors see their locale's\n * translation from the CDN bundle instead of frozen English.\n *\n * Keep in sync with packages/api seed defaults + widget-core/src/i18n.ts.\n */\n/* Sentinel, not display copy — it must keep matching the string the API seeds\n into the DB, or the untouched-default check below fails and every non-English\n visitor gets frozen English. The greeting that actually renders is\n t(\"widget.welcome_message\"), which is now one line; don't \"sync\" this to it. */\nconst DEFAULT_EN_WELCOME = \"Hi there 👋\\nHow can we help?\";\nconst DEFAULT_EN_SUBTITLE = \"Usually replies in minutes\";\n\n/**\n * Helpway brand mark — octagonal outer with stylized \"W\" inside. Used as\n * the widget's own fallback avatar when the customer hasn't configured a\n * custom avatar/preset and the host site didn't set a logo either. Keeps\n * unconfigured widgets looking intentional rather than generic.\n */\nfunction HelpwayMark({ className }: { className?: string }) {\n\treturn (\n\t\t<svg\n\t\t\tclassName={className}\n\t\t\twidth=\"100%\"\n\t\t\theight=\"100%\"\n\t\t\tviewBox=\"0 0 42 42\"\n\t\t\tfill=\"none\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<path\n\t\t\t\td=\"M28.7 0H12.8L0 12.8V28.7L12.8 41.5H28.7L41.5 28.7V12.8L28.7 0ZM15 28.9L6.80002 20.7L15 12.5C18.1 9.4 23.2 9.4 26.3 12.5L34.5 20.7L26.3 28.9C23.2 32 18.2 32 15 28.9Z\"\n\t\t\t\tfill=\"currentColor\"\n\t\t\t/>\n\t\t</svg>\n\t);\n}\n\n/**\n * WidgetLogo — chat-header avatar. Renders WHO is talking to the\n * visitor right now. Resolution chain:\n * 1. Active conversation's assigned support user (assigneeName +\n * assigneeImage from the widget API). When a human takes over a\n * conversation the visitor sees that human, not the AI agent.\n * 2. Agent uploaded image (agentConfig.avatarUrl)\n * 3. Agent icon preset (avatarPreset + brandColor)\n * 4. Website logo (website.logoUrl)\n * 5. Helpway brand mark (octagonal) as the true last-resort fallback\n *\n * The `forceAgent` escape hatch skips the assignee lookup — used by\n * surfaces that mean \"the agent\" specifically (welcome card, conversation\n * list rows where we want the persistent brand, etc.) rather than \"the\n * person currently helping you\".\n */\nexport function WidgetLogo({\n\tclassName,\n\tforceAgent = false,\n}: {\n\tclassName?: string;\n\tforceAgent?: boolean;\n}) {\n\tconst agentConfig = useWidgetStore((s) => s.agentConfig);\n\tconst logoUrl = useWidgetStore((s) => s.website?.logoUrl);\n\tconst activeId = useWidgetStore((s) => s.activeConversationId);\n\tconst assignee = useWidgetStore((s) => {\n\t\tif (forceAgent || !s.activeConversationId) return null;\n\t\tconst c = s.conversations.find((c) => c.id === s.activeConversationId);\n\t\treturn c?.assigneeName || c?.assigneeImage ? c : null;\n\t});\n\n\t// In the launcher bubble (forceAgent=true), uploaded images are\n\t// treated as brand logos — `contain` + padding so SVG/PNG marks\n\t// don't get cropped by the rounded bubble. In the chat-header\n\t// context, face-photo avatars keep `cover` behavior.\n\tconst logoClass = forceAgent ? \"hw-agent-img--logo\" : \"\";\n\n\t// Assigned human takes priority over the AI agent default — but only\n\t// when we actually have an active conversation we're rendering for.\n\tif (!forceAgent && activeId && assignee?.assigneeImage) {\n\t\treturn (\n\t\t\t<img\n\t\t\t\tsrc={assignee.assigneeImage}\n\t\t\t\talt={assignee.assigneeName ?? \"\"}\n\t\t\t\tclassName={`hw-agent-img ${className ?? \"\"}`}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// Agent uploaded image\n\tif (agentConfig?.avatarUrl) {\n\t\treturn (\n\t\t\t<img\n\t\t\t\tsrc={agentConfig.avatarUrl}\n\t\t\t\talt=\"\"\n\t\t\t\tclassName={`hw-agent-img ${logoClass} ${className ?? \"\"}`}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// Agent icon preset — use the same CSS variable as the welcome hero\n\t// so both surfaces stay color-synced. `--hw-primary` is fed by either\n\t// the inline style on `.hw-widget` (from agentConfig.brandColor) or\n\t// a `theme` prop override; reading the literal `agentConfig.brandColor`\n\t// here used to drift apart from the hero whenever the prop won.\n\tif (agentConfig?.avatarPreset) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={`hw-agent-icon ${className ?? \"\"}`}\n\t\t\t\tstyle={{\n\t\t\t\t\tbackgroundColor: \"var(--hw-primary)\",\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\tjustifyContent: \"center\",\n\t\t\t\t\tborderRadius: 8,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<AgentPresetIcon presetId={agentConfig.avatarPreset} />\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// Website logo — always a brand mark, never a face avatar. Apply\n\t// --logo class regardless of context so it stays uncropped in both\n\t// launcher bubble and chat-header circles.\n\tif (logoUrl) {\n\t\treturn (\n\t\t\t<img src={logoUrl} alt=\"\" className={`hw-agent-img hw-agent-img--logo ${className ?? \"\"}`} />\n\t\t);\n\t}\n\n\treturn <HelpwayMark className={className} />;\n}\n\n/**\n * LauncherIcon — what the visitor sees on the always-visible bubble\n * BEFORE opening the widget. Brand-stable, doesn't change per\n * conversation. Resolution chain:\n * 1. Custom launcher icon (agentConfig.launcherIconUrl) — admin upload\n * 2. Agent avatar (avatarUrl) — same image as the chat header default\n * 3. Agent icon preset\n * 4. Website logo\n * 5. Helpway brand mark\n */\nfunction LauncherIcon({ className }: { className?: string }) {\n\tconst agentConfig = useWidgetStore((s) => s.agentConfig);\n\tconst [imgLoaded, setImgLoaded] = useState(false);\n\tconst imgSrc = agentConfig?.launcherIconUrl ?? null;\n\n\tuseEffect(() => {\n\t\tif (!imgSrc) return;\n\t\tsetImgLoaded(false);\n\t\tconst img = new Image();\n\t\timg.src = imgSrc;\n\t\tif (img.complete) {\n\t\t\tsetImgLoaded(true);\n\t\t\treturn;\n\t\t}\n\t\timg.onload = () => setImgLoaded(true);\n\t\timg.onerror = () => setImgLoaded(true);\n\t}, [imgSrc]);\n\n\tif (imgSrc) {\n\t\treturn (\n\t\t\t<img\n\t\t\t\tsrc={imgSrc}\n\t\t\t\talt=\"\"\n\t\t\t\tclassName={`hw-agent-img hw-agent-img--logo ${className ?? \"\"}`}\n\t\t\t\tstyle={{ opacity: imgLoaded ? 1 : 0, transition: \"opacity 0.15s ease\" }}\n\t\t\t/>\n\t\t);\n\t}\n\treturn <WidgetLogo className={className} forceAgent />;\n}\n\n/**\n * Exact SVG paths extracted from @central-icons-react at build time.\n * Pixel-perfect match with the dashboard picker. Using static trusted\n * strings (NOT user input) rendered via innerHTML — safe because content\n * is hardcoded SVG from our own icon library, never from external sources.\n */\nconst PRESET_SVG: Record<string, string> = {\n\t// Helpway brand mark — octagonal chamfer with stylized \"W\" inside.\n\t// First entry so it's the default preset for new orgs.\n\thelpway:\n\t\t'<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M16.4 0H7.31L0 7.31V16.4L7.31 23.71H16.4L23.71 16.4V7.31L16.4 0ZM8.57 16.51L3.89 11.83L8.57 7.14C10.34 5.37 13.26 5.37 15.03 7.14L19.71 11.83L15.03 16.51C13.26 18.29 10.4 18.29 8.57 16.51Z\" fill=\"white\"/>',\n\tatom: '<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M9.67904 3.29155C10.7467 1.56948 13.2537 1.56948 14.3214 3.29155L15.1308 4.59707C15.2462 4.7833 15.3634 4.9684 15.4823 5.15233C15.7005 5.1305 15.9185 5.10662 16.1363 5.08068L17.6626 4.89893C19.6747 4.65934 21.2396 6.61723 20.5571 8.52637L20.0401 9.97255C19.9664 10.1786 19.8947 10.3854 19.825 10.5927C19.9779 10.7493 20.1323 10.9045 20.2882 11.0583L21.3821 12.1371C22.8256 13.5609 22.2668 16.0039 20.3491 16.6605L18.895 17.1584C18.6876 17.2294 18.4809 17.3023 18.275 17.3772C18.2478 17.5943 18.2226 17.8117 18.1995 18.0294L18.0372 19.5565C17.823 21.572 15.5635 22.6577 13.8546 21.5695L12.5584 20.7442C12.3734 20.6264 12.1873 20.5103 12.0002 20.3961C11.8131 20.5103 11.627 20.6264 11.442 20.7442L10.1458 21.5695C8.4369 22.6577 6.17739 21.572 5.96321 19.5565L5.80094 18.0294C5.7778 17.8117 5.75263 17.5943 5.72541 17.3772C5.51949 17.3023 5.31282 17.2294 5.10542 17.1584L3.65133 16.6605C1.7336 16.0039 1.17475 13.5609 2.61829 12.1371L3.71216 11.0583C3.86807 10.9045 4.0225 10.7493 4.17541 10.5927C4.10567 10.3854 4.03395 10.1786 3.96028 9.97255L3.44329 8.52637C2.7608 6.61723 4.32567 4.65934 6.33777 4.89893L7.86408 5.08068C8.08191 5.10662 8.29993 5.1305 8.5181 5.15233C8.63698 4.9684 8.75417 4.7833 8.86963 4.59707L9.67904 3.29155ZM7.61407 6.4827L6.16966 6.31071C5.20357 6.19567 4.45578 7.13505 4.78207 8.04778L5.2716 9.41715C6.10452 8.48167 6.88648 7.5021 7.61407 6.4827ZM5.78854 10.961C7.04552 9.61105 8.19784 8.16742 9.23549 6.64268C11.076 6.78287 12.9244 6.78287 14.7649 6.64268C15.8026 8.16743 16.9549 9.61105 18.2119 10.961C17.6657 12.722 17.2545 14.522 16.9818 16.3454C15.2628 17.0169 13.5974 17.8181 12.0002 18.7422C10.403 17.8181 8.73761 17.0169 7.01863 16.3454C6.74592 14.522 6.3347 12.722 5.78854 10.961ZM4.65269 12.1275L3.61666 13.1494C2.92581 13.8308 3.19234 15.0006 4.11188 15.3154L5.48873 15.7868C5.27593 14.553 4.99684 13.3315 4.65269 12.1275ZM7.22343 17.9611L7.377 19.4062C7.47946 20.3704 8.56185 20.8926 9.38218 20.3703L10.6083 19.5895C9.51004 18.9865 8.38012 18.4429 7.22343 17.9611ZM13.3921 19.5895L14.6182 20.3703C15.4385 20.8926 16.5209 20.3704 16.6234 19.4062L16.777 17.9611C15.6203 18.4429 14.4903 18.9865 13.3921 19.5895ZM18.5117 15.7868L19.8885 15.3154C20.8081 15.0006 21.0746 13.8308 20.3837 13.1494L19.3477 12.1275C19.0035 13.3315 18.7245 14.553 18.5117 15.7868ZM18.7288 9.41715L19.2183 8.04778C19.5446 7.13505 18.7968 6.19567 17.8307 6.31071L16.3863 6.4827C17.1139 7.5021 17.8959 8.48167 18.7288 9.41715ZM13.8786 5.2756C12.6272 5.3429 11.3731 5.3429 10.1218 5.2756L10.8874 4.04072C11.3991 3.21542 12.6013 3.21542 13.113 4.04072L13.8786 5.2756Z\" fill=\"white\"/>',\n\tbrain:\n\t\t'<path d=\"M15 10C13.3431 10 12 8.65685 12 7\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9 14C10.6569 14 12 15.3431 12 17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 3.53516L12 20.2422\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M21 14.5C21 15.9633 20.102 17.2168 18.8271 17.7396C18.2888 19.6221 16.5553 21 14.5 21C13.5749 21 12.7151 20.7209 12 20.2422C11.285 20.7209 10.4251 21 9.5 21C7.44468 21 5.71119 19.6221 5.17291 17.7396C3.89797 17.2168 3 15.9633 3 14.5C3 13.5207 3.40223 12.6353 4.05051 12C3.40223 11.3647 3 10.4793 3 9.5C3 7.69511 4.36618 6.20931 6.12085 6.0203C6.55779 4.28478 8.12886 3 10 3C10.7286 3 11.4117 3.19479 12 3.53513C12.5883 3.19479 13.2714 3 14 3C15.8711 3 17.4422 4.28478 17.8792 6.0203C19.6338 6.20931 21 7.69511 21 9.5C21 10.4793 20.5978 11.3647 19.9495 12C20.5978 12.6353 21 13.5207 21 14.5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\trobot:\n\t\t'<path d=\"M12 4H7C5.89543 4 5 4.89543 5 6V11C5 12.1046 5.89543 13 7 13H17C18.1046 13 19 12.1046 19 11V6C19 4.89543 18.1046 4 17 4H12ZM12 4V2M6 15L4 17M6 15C6 18.3137 8.68629 21 12 21C15.3137 21 18 18.3137 18 15M6 15V13M18 15L20 17M18 15V13M9 8V9M15 8V9\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tsparkle:\n\t\t'<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M21 12.5C14.75 12.5 12 15.4028 12 22C12 15.4028 9.25 12.5 3 12.5C9.25 12.5 12 9.59722 12 3C12 9.59722 14.75 12.5 21 12.5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linejoin=\"round\"/>',\n\tbolt: '<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M13.1981 20.0571C11.7326 20.0571 10.2936 19.5252 9.46756 18.3817L9.1762 19.7304L3.79688 22.5824L4.3776 19.7304L8.2951 2H13.0916L11.7059 8.24953C12.8251 7.02621 13.8643 6.57412 15.1967 6.57412C18.0746 6.57412 19.9931 8.46227 19.9931 11.9194C19.9931 15.483 17.7815 20.0571 13.1981 20.0571ZM15.0368 12.9301C15.0368 14.5788 13.8643 15.8287 12.3455 15.8287C11.4927 15.8287 10.72 15.5096 10.2137 14.9511L10.9598 11.6802C11.5194 11.1216 12.1589 10.8025 12.905 10.8025C14.0509 10.8025 15.0368 11.6536 15.0368 12.9301Z\" fill=\"white\"/>',\n\tagent:\n\t\t'<path d=\"M12 8.5V12M12 12H8C6.89543 12 6 12.8954 6 14V15.5M12 12H16C17.1046 12 18 12.8954 18 14V15.5\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><circle cx=\"12\" cy=\"6\" r=\"2.5\" stroke=\"white\" stroke-width=\"2\"/><circle cx=\"6\" cy=\"18\" r=\"2.5\" stroke=\"white\" stroke-width=\"2\"/><circle cx=\"18\" cy=\"18\" r=\"2.5\" stroke=\"white\" stroke-width=\"2\"/>',\n\tbubble:\n\t\t'<path d=\"M4.00195 6.00003C4.00195 4.89546 4.89738 4.00003 6.00195 4.00002L18.0019 4C19.1065 4 20.002 4.89543 20.002 6V16.0358C20.002 17.1403 19.1065 18.0358 18.002 18.0358L15.3757 18.0358C15.1427 18.0358 14.9171 18.1171 14.7377 18.2657L11.9977 20.5358L9.29398 18.2694C9.11393 18.1185 8.8865 18.0358 8.65157 18.0358H6.00195C4.89738 18.0358 4.00195 17.1403 4.00195 16.0358V6.00003Z\" fill=\"white\"/><path d=\"M13.2395 9.43518L12.5426 7.62334C12.4561 7.39842 12.24 7.25 11.999 7.25C11.758 7.25 11.5419 7.39842 11.4554 7.62334L10.7586 9.43518C10.657 9.69927 10.4483 9.90797 10.1842 10.0095L8.37236 10.7064C8.14744 10.7929 7.99902 11.009 7.99902 11.25C7.99902 11.491 8.14744 11.7071 8.37236 11.7936L10.1842 12.4905C10.4483 12.592 10.657 12.8007 10.7586 13.0648L11.4554 14.8767C11.5419 15.1016 11.758 15.25 11.999 15.25C12.24 15.25 12.4561 15.1016 12.5426 14.8767L13.2395 13.0648C13.3411 12.8007 13.5498 12.592 13.8138 12.4905L15.6257 11.7936C15.8506 11.7071 15.999 11.491 15.999 11.25C15.999 11.009 15.8506 10.7929 15.6257 10.7064L13.8138 10.0095C13.5498 9.90797 13.3411 9.69927 13.2395 9.43518Z\" fill=\"white\"/>',\n\tlightbulb:\n\t\t'<path d=\"M10 21H14M15.6076 15C17.6404 13.7751 19 11.5463 19 9C19 5.13401 15.866 2 12 2C8.13401 2 5 5.13401 5 9C5 11.5463 6.35958 13.7751 8.39241 15M15.6076 15C15.4111 15.1184 15.2084 15.2274 15 15.3264V17C15 17.5523 14.5523 18 14 18H10C9.44772 18 9 17.5523 9 17V15.3264C8.7916 15.2274 8.58886 15.1184 8.39241 15M15.6076 15H8.39241\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\twand: '<path d=\"M11.3908 12.6089L4 19.9996\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M18.3943 5.2792C18.5999 5.1944 18.8056 5.40008 18.7208 5.60565L17.1697 9.36581C17.1339 9.45248 17.1497 9.55186 17.2105 9.62323L19.8476 12.72C19.9918 12.8894 19.8597 13.1485 19.638 13.1314L15.5826 12.8182C15.4891 12.811 15.3994 12.8566 15.3503 12.9365L13.22 16.4015C13.1035 16.591 12.8163 16.5455 12.764 16.3293L11.8087 12.3756C11.7867 12.2844 11.7156 12.2133 11.6244 12.1913L7.67069 11.236C7.45453 11.1837 7.40903 10.8964 7.59847 10.78L11.0635 8.64965C11.1434 8.60055 11.189 8.51089 11.1818 8.41743L10.8686 4.36198C10.8515 4.14027 11.1106 4.00822 11.2799 4.15239L14.3768 6.78952C14.4481 6.8503 14.5475 6.86604 14.6342 6.83029L18.3943 5.2792Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tchip: '<path d=\"M8 5.5V4M12 5.5V4M16 5.5V4M8 20V18.5M12 20V18.5M16 20V18.5M8.75 15H15.25C15.6642 15 16 14.6642 16 14.25V9.75C16 9.33579 15.6642 9 15.25 9H8.75C8.33579 9 8 9.33579 8 9.75V14.25C8 14.6642 8.33579 15 8.75 15ZM6 20H18C19.1046 20 20 19.1046 20 18V6C20 4.89543 19.1046 4 18 4H6C4.89543 4 4 4.89543 4 6V18C4 19.1046 4.89543 20 6 20Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tcode: '<path d=\"M10 9.5L8.20711 11.2929C7.81658 11.6834 7.81658 12.3166 8.20711 12.7071L10 14.5M14 9.5L15.7929 11.2929C16.1834 11.6834 16.1834 12.3166 15.7929 12.7071L14 14.5M6 20H18C19.1046 20 20 19.1046 20 18V6C20 4.89543 19.1046 4 18 4H6C4.89543 4 4 4.89543 4 6V18C4 19.1046 4.89543 20 6 20Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tlightning:\n\t\t'<path d=\"M4.11593 12.2764L8.61593 3.27639C8.70063 3.107 8.87376 3 9.06315 3H17.121C17.5097 3 17.7497 3.42399 17.5498 3.75725L15.4585 7.24275C15.2585 7.57601 15.4986 8 15.8872 8H20.6909C21.1505 8 21.3666 8.56776 21.0235 8.87338L7.38117 21.0236C7.00034 21.3628 6.41568 20.981 6.57301 20.4959L8.79194 13.6543C8.8967 13.3312 8.6559 13 8.31633 13H4.56314C4.19145 13 3.94971 12.6088 4.11593 12.2764Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tvibe: '<path d=\"M18.9847 2.4329C18.9568 2.18651 18.7485 2.00025 18.5005 2C18.2525 1.99975 18.0438 2.18557 18.0154 2.43191C17.838 3.96993 16.9699 4.83801 15.4319 5.01541C15.1856 5.04382 14.9997 5.25253 15 5.5005C15.0003 5.74847 15.1865 5.9568 15.4329 5.9847C16.9491 6.15645 17.8774 7.01617 18.0141 8.55536C18.0365 8.80725 18.2477 9.00028 18.5005 9C18.7534 8.99971 18.9642 8.80621 18.986 8.55426C19.1173 7.03683 20.0368 6.11734 21.5543 5.98599C21.8062 5.96418 21.9997 5.75344 22 5.50055C22.0003 5.24766 21.8073 5.03648 21.5554 5.01411C20.0162 4.87738 19.1564 3.94911 18.9847 2.4329Z\" fill=\"white\"/><path d=\"M2 20C2 16.6863 4.68629 14 8 14H8.5\" fill=\"white\"/><path d=\"M11 20L12.6892 14.0879C12.8732 13.444 13.4617 13 14.1315 13H20.5417C21.2725 13 21.8001 13.6995 21.5994 14.4022L20.2072 19.2747C20.0846 19.704 19.6922 20 19.2457 20H11ZM11 20H7\" fill=\"white\"/><circle cx=\"8.75\" cy=\"7.5\" r=\"3.5\" stroke=\"white\" stroke-width=\"2\"/>',\n\tnetwork:\n\t\t'<path d=\"M12 6.8501L16 7.2501M17.75 10.0001L16.55 14.0001M13.5 14.3572L12 12.0001L10.4091 9.5001M6.25 14.0001L7.45 10.0001M8 16.7501L12 17.1501\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><circle cx=\"18.5\" cy=\"7.5\" r=\"2.5\" stroke=\"white\" stroke-width=\"2\"/><circle cx=\"5.5\" cy=\"16.5\" r=\"2.5\" stroke=\"white\" stroke-width=\"2\"/><circle cx=\"8.5\" cy=\"6.5\" r=\"3.5\" stroke=\"white\" stroke-width=\"2\"/><circle cx=\"15.5\" cy=\"17.5\" r=\"3.5\" stroke=\"white\" stroke-width=\"2\"/>',\n\tconsole:\n\t\t'<path d=\"M7.5 8L9.25 9.75L7.5 11.5M12 11.5H14M6 20H18C19.1046 20 20 19.1046 20 18V6C20 4.89543 19.1046 4 18 4H6C4.89543 4 4 4.89543 4 6V18C4 19.1046 4.89543 20 6 20Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tprompt:\n\t\t'<path d=\"M6 5H5C3.89543 5 3 5.89543 3 7V8\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M18 5H19C20.1046 5 21 5.89543 21 7V8\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M21 16V17C21 18.1046 20.1046 19 19 19H18\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M6 19H5C3.89543 19 3 18.1046 3 17V16\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M8 10H16\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M8 14H14\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tglobe:\n\t\t'<path d=\"M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M21 12H3\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 21C10.067 21 8.5 16.9706 8.5 12C8.5 7.02944 10.067 3 12 3C13.933 3 15.5 7.02944 15.5 12C15.5 16.9706 13.933 21 12 21Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\ttarget:\n\t\t'<path d=\"M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M17 12C17 14.7614 14.7614 17 12 17C9.23858 17 7 14.7614 7 12C7 9.23858 9.23858 7 12 7C14.7614 7 17 9.23858 17 12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M13 12C13 12.5523 12.5523 13 12 13C11.4477 13 11 12.5523 11 12C11 11.4477 11.4477 11 12 11C12.5523 11 13 11.4477 13 12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tdiamond:\n\t\t'<path d=\"M8.28256 4C7.77978 4 7.29545 4.18937 6.926 4.53039L2.53016 8.58809C1.69548 9.35857 1.66929 10.6687 2.47251 11.4719L10.5864 19.5858C11.3674 20.3668 12.6338 20.3668 13.4148 19.5858L21.5287 11.4719C22.3319 10.6687 22.3057 9.35857 21.471 8.58809L17.0752 4.53039C16.7057 4.18937 16.2214 4 15.7186 4H8.28256Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9.5 8L7.5 10L9.5 12\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tstar: '<path d=\"M11.5288 2.29524C11.7179 1.90159 12.2821 1.90159 12.4712 2.29524L14.9458 7.44648C15.0219 7.60491 15.1735 7.71434 15.3487 7.73728L21.0456 8.4832C21.4809 8.5402 21.6552 9.07312 21.3368 9.37342L17.1693 13.303C17.0412 13.4238 16.9832 13.6009 17.0154 13.7735L18.0616 19.3857C18.1416 19.8146 17.6852 20.144 17.2993 19.9359L12.249 17.2133C12.0937 17.1296 11.9063 17.1296 11.751 17.2133L6.70073 19.9359C6.3148 20.144 5.85841 19.8146 5.93837 19.3857L6.98459 13.7735C7.01677 13.6009 6.95885 13.4238 6.83068 13.303L2.66324 9.37342C2.34476 9.07312 2.51909 8.5402 2.95444 8.4832L8.65127 7.73728C8.82648 7.71434 8.97811 7.60491 9.05422 7.44648L11.5288 2.29524Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\theart:\n\t\t'<path d=\"M21 10C21 15.75 12.75 20 12 20C11.25 20 3 15.75 3 10C3 6 5.5 4 8 4C10.5 4 12 5.5 12 5.5C12 5.5 13.5 4 16 4C18.5 4 21 6 21 10Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tshield:\n\t\t'<path d=\"M20 7.17737C20 6.32338 19.4578 5.56361 18.6502 5.286L12.6502 3.2235C12.2288 3.07866 11.7712 3.07866 11.3498 3.22349L5.34984 5.286C4.54224 5.56361 4 6.32338 4 7.17737V11.9123C4 16.8848 8 19 12 21.1579C16 19 20 16.8848 20 11.9123V7.17737Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\trocket:\n\t\t'<path d=\"M3 21H5C6.10457 21 7 20.1046 7 19C7 17.8954 6.10457 17 5 17C3.89543 17 3 17.8954 3 19V21Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M7.00098 13H4.76717C3.98987 13 3.50976 12.152 3.90968 11.4855L5.41837 8.97101C5.77982 8.3686 6.43083 8 7.13336 8H11.251C13.7671 5.25513 16.4925 3.3474 20.0017 3.04278C20.5519 2.99502 21.006 3.44906 20.9582 3.99927C20.6536 7.50845 18.7459 10.2339 16.001 12.75V16.8676C16.001 17.5701 15.6324 18.2212 15.03 18.5826L12.5155 20.0913C11.849 20.4912 11.001 20.0111 11.001 19.2338V17L7.00098 13Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M7 13L11.25 8\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M16 12.75L11 17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tcrown:\n\t\t'<path d=\"M4.16831 17.4079L2 7L8 10L12 4L16 10L22 7L19.8317 17.4079C19.6385 18.3353 18.8211 19 17.8737 19H6.12628C5.17892 19 4.36153 18.3353 4.16831 17.4079Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\ttrophy:\n\t\t'<path d=\"M12.0039 17V14\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M18 5H19C20.1046 5 21 5.89543 21 7C21 8.65685 19.6569 10 18 10\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M6 5C6 3.89543 6.89543 3 8 3H16C17.1046 3 18 3.89543 18 5V8C18 11.3137 15.3137 14 12 14C8.68629 14 6 11.3137 6 8V5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M7 19C7 17.8954 7.89543 17 9 17H15C16.1046 17 17 17.8954 17 19C17 20.1046 16.1046 21 15 21H9C7.89543 21 7 20.1046 7 19Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M6 5H5C3.89543 5 3 5.89543 3 7C3 8.65685 4.34315 10 6 10\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tcompass:\n\t\t'<path d=\"M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M14.6558 8.73023L10.5513 9.84965C10.2097 9.94281 9.94281 10.2097 9.84965 10.5513L8.73023 14.6558C8.62843 15.0291 8.97092 15.3716 9.34417 15.2698L13.4487 14.1504C13.7903 14.0572 14.0572 13.7903 14.1504 13.4487L15.2698 9.34417C15.3716 8.97092 15.0291 8.62843 14.6558 8.73023Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tfire: '<path d=\"M19.5 13.8122C19.5 23.3907 4.5 23.4012 4.5 13.8122C4.5 6.61352 12 2.5 12 2.5C12 2.5 19.5 6.61352 19.5 13.8122Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M15.5 17.4061C15.5 22.1954 8.5 22.2006 8.5 17.4061C8.5 13.8068 12 11.75 12 11.75C12 11.75 15.5 13.8068 15.5 17.4061Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tkey: '<path d=\"M20.8002 9.8753L20.0194 10.5L20.0194 10.5L20.8002 9.8753ZM22.0002 11.3753L21.2194 12V12L22.0002 11.3753ZM22.0002 12.6247L21.2194 12V12L22.0002 12.6247ZM20.8002 14.1247L20.0194 13.5L20.0194 13.5L20.8002 14.1247ZM18 14.5L17.5528 15.3944C17.6916 15.4639 17.8448 15.5 18 15.5V14.5ZM16 13.5L16.4472 12.6056C16.1657 12.4648 15.8343 12.4648 15.5528 12.6056L16 13.5ZM14 14.5V15.5C14.1552 15.5 14.3084 15.4639 14.4472 15.3944L14 14.5ZM11.0141 9.01843L11.8165 8.42152L11.8165 8.42152L11.0141 9.01843ZM11.0141 14.9816L10.2118 14.3847V14.3847L11.0141 14.9816ZM6.5 12C6.5 11.7239 6.72386 11.5 7 11.5V13.5C7.82843 13.5 8.5 12.8284 8.5 12H6.5ZM7 11.5C7.27614 11.5 7.5 11.7239 7.5 12H5.5C5.5 12.8284 6.17157 13.5 7 13.5V11.5ZM7.5 12C7.5 12.2761 7.27614 12.5 7 12.5V10.5C6.17157 10.5 5.5 11.1716 5.5 12H7.5ZM7 12.5C6.72386 12.5 6.5 12.2761 6.5 12H8.5C8.5 11.1716 7.82843 10.5 7 10.5V12.5ZM6.5 13H7.5V11H6.5V13ZM7 16C4.79086 16 3 14.2091 3 12H1C1 15.3137 3.68629 18 7 18V16ZM3 12C3 9.79086 4.79086 8 7 8V6C3.68629 6 1 8.68629 1 12H3ZM20.0194 10.5L21.2194 12L22.7811 10.7506L21.5811 9.25061L20.0194 10.5ZM21.2194 12L20.0194 13.5L21.5811 14.7494L22.7811 13.2494L21.2194 12ZM20.0194 13.5H18V15.5H20.0194V13.5ZM18.4472 13.6056L16.4472 12.6056L15.5528 14.3944L17.5528 15.3944L18.4472 13.6056ZM15.5528 12.6056L13.5528 13.6056L14.4472 15.3944L16.4472 14.3944L15.5528 12.6056ZM11.9079 10.5H20.0194V8.5H11.9079V10.5ZM7 8C8.31459 8 9.48107 8.63311 10.2118 9.61533L11.8165 8.42152C10.7246 6.9539 8.97356 6 7 6V8ZM14 13.5H11.9079V15.5H14V13.5ZM10.2118 14.3847C9.48107 15.3669 8.31459 16 7 16V18C8.97356 18 10.7246 17.0461 11.8165 15.5785L10.2118 14.3847ZM11.9079 13.5C11.1751 13.5 10.5749 13.8967 10.2118 14.3847L11.8165 15.5785C11.8445 15.5408 11.8734 15.5183 11.8929 15.5074C11.9106 15.4976 11.9148 15.5 11.9079 15.5V13.5ZM20.0194 13.5L20.0194 13.5V15.5C20.6269 15.5 21.2016 15.2238 21.5811 14.7494L20.0194 13.5ZM11.9079 8.5C11.9148 8.5 11.9106 8.50239 11.8929 8.49258C11.8734 8.48172 11.8445 8.45923 11.8165 8.42152L10.2118 9.61533C10.5749 10.1033 11.1751 10.5 11.9079 10.5V8.5ZM21.2194 12V12L22.7811 13.2494C23.3655 12.519 23.3655 11.481 22.7811 10.7506L21.2194 12ZM21.5811 9.25061C21.2016 8.77618 20.6269 8.5 20.0194 8.5V10.5L20.0194 10.5L21.5811 9.25061Z\" fill=\"white\"/>',\n\tlock: '<path d=\"M5 12C5 10.8954 5.89543 10 7 10H17C18.1046 10 19 10.8954 19 12V19C19 20.1046 18.1046 21 17 21H7C5.89543 21 5 20.1046 5 19V12Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M16 9.5V7C16 4.79086 14.2091 3 12 3C9.79086 3 8 4.79086 8 7V9.5\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 14V17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tbookmark:\n\t\t'<path d=\"M19 19.9948V5C19 3.89543 18.1046 3 17 3H7C5.89543 3 5 3.89543 5 5V19.9948C5 20.8047 5.91243 21.2787 6.57503 20.813L10.8499 17.8083C11.54 17.3233 12.46 17.3233 13.1501 17.8083L17.425 20.813C18.0876 21.2787 19 20.8047 19 19.9948Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tstore:\n\t\t'<path d=\"M4 10V18C4 19.1046 4.89543 20 6 20H18C19.1046 20 20 19.1046 20 18V10\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M14.4996 4H9.49956L9.2133 8.00762C9.0978 9.62461 10.3785 11 11.9996 11C13.6207 11 14.9013 9.62461 14.7858 8.00763L14.4996 4Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9.50047 4H5.73506C4.73976 4 3.89592 4.73186 3.75516 5.71716L3.4699 7.71396C3.22214 9.44831 4.56792 11 6.31987 11C7.83025 11 9.08385 9.83276 9.19146 8.32621L9.50047 4Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M18.2654 4H14.5L14.809 8.32621C14.9166 9.83276 16.1702 11 17.6806 11C19.4326 11 20.7783 9.44831 20.5306 7.71396L20.2453 5.71716C20.1046 4.73186 19.2607 4 18.2654 4Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tbag: '<path d=\"M15.0001 8C15.0001 9.65685 13.6569 11 12.0001 11C10.3432 11 9.00008 9.65685 9.00008 8M4.88288 5.87524L4.13288 17.8752C4.06092 19.0266 4.97534 20 6.12899 20H17.8712C19.0248 20 19.9392 19.0266 19.8673 17.8752L19.1173 5.87524C19.0514 4.82117 18.1773 4 17.1212 4H6.87899C5.82286 4 4.94876 4.82117 4.88288 5.87524Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\t\"credit-card\":\n\t\t'<path d=\"M3 10V17C3 18.1046 3.89543 19 5 19H19C20.1046 19 21 18.1046 21 17V10M3 10V7C3 5.89543 3.89543 5 5 5H19C20.1046 5 21 5.89518 21 6.99975V10M3 10H21\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\treceipt:\n\t\t'<path d=\"M9 8H15M9 12H11M19 21V5C19 3.89543 18.1046 3 17 3H7C5.89543 3 5 3.89543 5 5V21L7.33333 19L9.66667 21L12 19L14.3333 21L16.6667 19L19 21Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tbank: '<path d=\"M11.1056 2.94723L3.68328 6.65838C3.26452 6.86776 3 7.29576 3 7.76395C3 8.44661 3.55341 9.00002 4.23607 9.00002H19.7639C20.4466 9.00002 21 8.44661 21 7.76395C21 7.29576 20.7355 6.86776 20.3167 6.65838L12.8944 2.94723C12.3314 2.6657 11.6686 2.6657 11.1056 2.94723Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M19.6126 20H4.38749C3.70493 20 3.22296 19.3313 3.4388 18.6838L3.54421 18.3675C3.81644 17.5509 4.58072 17 5.44158 17H18.5585C19.4194 17 20.1837 17.5509 20.4559 18.3675L20.5613 18.6838C20.7772 19.3313 20.2952 20 19.6126 20Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M19 9V17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M15 17V9\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5 9V17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9 17V9\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\twallet:\n\t\t'<path d=\"M3 8V7C3 5.89543 3.89543 5 5 5H19C20.1046 5 21 5.89543 21 7V8M3 8H21M3 8V11M21 8V11M21 11V17C21 18.1046 20.1046 19 19 19H5C3.89543 19 3 18.1046 3 17V11M21 11H15C15 12.1046 14.1046 13 13 13H11C9.89543 13 9 12.1046 9 11H3\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tpackage:\n\t\t'<path d=\"M9 4V7.5C9 8.32843 9.67157 9 10.5 9H13.5C14.3284 9 15 8.32843 15 7.5V4M14 16H16M4 6V18C4 19.1046 4.89543 20 6 20H18C19.1046 20 20 19.1046 20 18V6C20 4.89543 19.1046 4 18 4H6C4.89543 4 4 4.89543 4 6Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\ttruck:\n\t\t'<path d=\"M10 16.5C10 17.8807 8.88071 19 7.5 19C6.11929 19 5 17.8807 5 16.5C5 15.1193 6.11929 14 7.5 14C8.88071 14 10 15.1193 10 16.5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M19 16.5C19 17.8807 17.8807 19 16.5 19C15.1193 19 14 17.8807 14 16.5C14 15.1193 15.1193 14 16.5 14C17.8807 14 19 15.1193 19 16.5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M10 16H14\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9 14V7H6.07037C5.40166 7 4.7772 7.3342 4.40627 7.8906L3.3359 9.49615C3.11688 9.82469 3 10.2107 3 10.6056V14.2857C3 15.2325 3.76751 16 4.71429 16\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9 9V7C9 5.89543 9.89543 5 11 5H19C20.1046 5 21 5.89543 21 7V14C21 15.1046 20.1046 16 19 16\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tmegaphone:\n\t\t'<path d=\"M17.9961 14.0001C19.6529 14.0001 20.9961 12.657 20.9961 11.0001C20.9961 9.34325 19.6529 8.0001 17.9961 8.0001M12.8254 18.0001C12.4136 19.1653 11.3023 20.0001 9.99609 20.0001C8.33924 20.0001 6.99609 18.657 6.99609 17.0001V15.5001M6.99829 6.5001V15.5001M17.9961 5.73752V16.2627C17.9961 17.617 16.6784 18.5797 15.3882 18.1681L4.38819 14.6585C3.55899 14.394 2.99609 13.6235 2.99609 12.7532V9.24704C2.99609 8.37667 3.55899 7.60622 4.38819 7.34167L15.3882 3.83215C16.6784 3.42051 17.9961 4.38325 17.9961 5.73752Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\temail:\n\t\t'<path d=\"M20.782 6.09202L19.891 6.54601L19.891 6.54601L20.782 6.09202ZM19.908 5.21799L20.362 4.32698V4.32698L19.908 5.21799ZM4.09202 5.21799L3.63803 4.32698L3.63803 4.32698L4.09202 5.21799ZM3.21799 6.09202L2.32698 5.63803L2.32698 5.63803L3.21799 6.09202ZM3.21799 17.908L4.10899 17.454L4.10899 17.454L3.21799 17.908ZM4.09202 18.782L4.54601 17.891H4.54601L4.09202 18.782ZM19.908 18.782L20.362 19.673V19.673L19.908 18.782ZM20.782 17.908L19.891 17.454L19.891 17.454L20.782 17.908ZM21 8.2H20V15.8H21H22V8.2H21ZM21 8.2H22C22 7.65645 22.0008 7.18864 21.9694 6.80497C21.9371 6.40963 21.8658 6.01641 21.673 5.63803L20.782 6.09202L19.891 6.54601C19.9162 6.59545 19.9539 6.69617 19.9761 6.96784C19.9992 7.25117 20 7.62345 20 8.2H21ZM20.782 6.09202L21.673 5.63803C21.3854 5.07354 20.9265 4.6146 20.362 4.32698L19.908 5.21799L19.454 6.10899C19.6422 6.20487 19.7951 6.35785 19.891 6.54601L20.782 6.09202ZM17.8 5V6C18.3766 6 18.7488 6.00078 19.0322 6.02393C19.3038 6.04612 19.4045 6.0838 19.454 6.10899L19.908 5.21799L20.362 4.32698C19.9836 4.13419 19.5904 4.06287 19.195 4.03057C18.8114 3.99922 18.3436 4 17.8 4V5ZM6.2 5V6H17.8V5V4H6.2V5ZM6.2 5V4C5.65645 4 5.18864 3.99922 4.80497 4.03057C4.40963 4.06287 4.01641 4.13419 3.63803 4.32698L4.09202 5.21799L4.54601 6.10899C4.59545 6.0838 4.69617 6.04612 4.96784 6.02393C5.25117 6.00078 5.62345 6 6.2 6V5ZM3.21799 6.09202L4.10899 6.54601C4.20487 6.35785 4.35785 6.20487 4.54601 6.10899L4.09202 5.21799L3.63803 4.32698C3.07354 4.6146 2.6146 5.07354 2.32698 5.63803L3.21799 6.09202ZM3 8.2H4C4 7.62345 4.00078 7.25117 4.02393 6.96784C4.04612 6.69617 4.0838 6.59545 4.10899 6.54601L3.21799 6.09202L2.32698 5.63803C2.13419 6.01641 2.06287 6.40963 2.03057 6.80497C1.99922 7.18864 2 7.65645 2 8.2H3ZM3 15.8H4V8.2H3H2V15.8H3ZM3 15.8H2C2 16.3435 1.99922 16.8114 2.03057 17.195C2.06287 17.5904 2.13419 17.9836 2.32698 18.362L3.21799 17.908L4.10899 17.454C4.0838 17.4045 4.04612 17.3038 4.02393 17.0322C4.00078 16.7488 4 16.3765 4 15.8H3ZM4.09202 18.782L4.54601 17.891C4.35785 17.7951 4.20487 17.6421 4.10899 17.454L3.21799 17.908L2.32698 18.362C2.6146 18.9265 3.07354 19.3854 3.63803 19.673L4.09202 18.782ZM6.2 19V18C5.62345 18 5.25117 17.9992 4.96784 17.9761C4.69617 17.9539 4.59545 17.9162 4.54601 17.891L4.09202 18.782L3.63803 19.673C4.01641 19.8658 4.40963 19.9371 4.80497 19.9694C5.18864 20.0008 5.65645 20 6.2 20V19ZM17.8 19V18H6.2V19V20H17.8V19ZM17.8 19V20C18.3436 20 18.8114 20.0008 19.195 19.9694C19.5904 19.9371 19.9836 19.8658 20.362 19.673L19.908 18.782L19.454 17.891C19.4045 17.9162 19.3038 17.9539 19.0322 17.9761C18.7488 17.9992 18.3766 18 17.8 18V19ZM20.782 17.908L19.891 17.454C19.7951 17.6421 19.6422 17.7951 19.454 17.891L19.908 18.782L20.362 19.673C20.9265 19.3854 21.3854 18.9265 21.673 18.362L20.782 17.908ZM21 15.8H20C20 16.3765 19.9992 16.7488 19.9761 17.0322C19.9539 17.3038 19.9162 17.4045 19.891 17.454L20.782 17.908L21.673 18.362C21.8658 17.9836 21.9371 17.5904 21.9694 17.195C22.0008 16.8114 22 16.3435 22 15.8H21Z\" fill=\"white\"/><path d=\"M21 5.63635L13.2665 11.9638C12.5297 12.5666 11.4703 12.5666 10.7335 11.9638L3 5.63635\" fill=\"white\"/>',\n\tbell: '<path d=\"M4.69376 9.44981C5.15435 5.76511 8.28661 3 12 3C15.7134 3 18.8456 5.76511 19.3062 9.44981L19.969 14.7519C20.1182 15.9456 19.1874 17 17.9844 17H6.01555C4.81256 17 3.88178 15.9456 4.031 14.7519L4.69376 9.44981Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M16 17C16 19.2091 14.2091 21 12 21C9.79086 21 8 19.2091 8 17\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tpeople:\n\t\t'<path d=\"M15.5 6.5C15.5 8.433 13.933 10 12 10C10.067 10 8.5 8.433 8.5 6.5C8.5 4.567 10.067 3 12 3C13.933 3 15.5 4.567 15.5 6.5Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12.0011 13C8.60997 13 6.03711 15.0143 4.9836 17.8629C4.5748 18.9682 5.51944 20 6.69796 20H17.3043C18.4828 20 19.4274 18.9682 19.0186 17.8629C17.9651 15.0143 15.3923 13 12.0011 13Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tsupport:\n\t\t'<path d=\"M6 10H4.5C3.67157 10 3 10.6716 3 11.5V15C3 15.8284 3.67157 16.5 4.5 16.5H6V10Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M20 10H18.5V16.5H20C20.8284 16.5 21.5 15.8284 21.5 15V11.5C21.5 10.6716 20.8284 10 20 10Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M19.5 10V9.75C19.5 6.02208 16.2541 3 12.25 3C8.24594 3 5 6.02208 5 9.75V10\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 19V19.5C12 20.3284 12.6716 21 13.5 21H15.25C17.7353 21 19.75 18.9853 19.75 16.5\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\thandshake:\n\t\t'<path d=\"M11.8305 5.68856C9.57907 3.43715 5.92881 3.43715 3.6774 5.68856C1.57785 7.78811 1.40103 11.1544 3.42019 13.3313C5.71921 15.8101 8.14783 18.1408 10.7345 20.3519C11.4619 20.9737 12.5313 20.9737 13.2587 20.3519C15.8453 18.1408 18.2739 15.8101 20.573 13.3313C22.5921 11.1544 22.4153 7.78811 20.3158 5.68856C18.0644 3.43715 14.4141 3.43715 12.1627 5.68856L8.8146 9.03664C8.22881 9.62243 8.22881 10.5722 8.8146 11.158C9.98617 12.3295 11.8857 12.3295 13.0572 11.158L13.7643 10.4509C14.1549 10.0603 14.788 10.0603 15.1786 10.4509L18.7141 13.9864\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tpill: '<path d=\"M17.4541 10.0962C18.6109 8.31497 18.4083 5.90826 16.8462 4.34619C15.0513 2.55127 12.1411 2.55127 10.3462 4.34619L4.34619 10.3462C2.55127 12.1411 2.55127 15.0513 4.34619 16.8462C5.90826 18.4083 8.31497 18.6109 10.0962 17.4541\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M7.5 7.5L11 11\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M16.5 20.5L14.5 10.5\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><circle cx=\"15.5\" cy=\"15.5\" r=\"5.5\" stroke=\"white\" stroke-width=\"2\"/>',\n\t\"heart-beat\":\n\t\t'<path d=\"M16 12H14.5L13 14L10.5 10L9.25 12H8M12 5.76835C18.1619 -0.481837 28.7252 11.1257 12 20.5C-4.72523 11.1257 5.83803 -0.481838 12 5.76835Z\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n\tbook: '<path d=\"M9 6C8.44772 6 8 6.44772 8 7C8 7.55228 8.44772 8 9 8V6ZM15 8C15.5523 8 16 7.55228 16 7C16 6.44772 15.5523 6 15 6V8ZM9 10C8.44772 10 8 10.4477 8 11C8 11.5523 8.44772 12 9 12V10ZM12 12C12.5523 12 13 11.5523 13 11C13 10.4477 12.5523 10 12 10V12ZM7 4H17V2H7V4ZM18 5V19H20V5H18ZM17 20H7V22H17V20ZM6 19V5H4V19H6ZM7 20C6.44771 20 6 19.5523 6 19H4C4 20.6569 5.34315 22 7 22V20ZM18 19C18 19.5523 17.5523 20 17 20V22C18.6569 22 20 20.6569 20 19H18ZM17 4C17.5523 4 18 4.44772 18 5H20C20 3.34315 18.6569 2 17 2V4ZM7 2C5.34315 2 4 3.34315 4 5H6C6 4.44772 6.44772 4 7 4V2ZM18 12V15H20V12H18ZM17 16H7V18H17V16ZM7 22H10V20H7V22ZM7 16C5.34315 16 4 17.3431 4 19H6C6 18.4477 6.44772 18 7 18V16ZM18 15C18 15.5523 17.5523 16 17 16V18C18.6569 18 20 16.6569 20 15H18ZM9 8H15V6H9V8ZM9 12H12V10H9V12Z\" fill=\"white\"/>',\n\tgraduate:\n\t\t'<path d=\"M23 9L12 14L1 9L12 4L23 9ZM23 9V16M5 11V15.3025C5 16.0398 5.40565 16.7173 6.05556 17.0655L11.0556 19.744C11.6455 20.0601 12.3545 20.0601 12.9444 19.744L17.9444 17.0655C18.5944 16.7173 19 16.0398 19 15.3025V11\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>',\n};\n\n/**\n * Renders preset icon SVG — uses trusted static SVG content extracted from\n * @central-icons-react at build time. Content is hardcoded (not user input),\n * so innerHTML usage is safe from XSS.\n */\nfunction AgentPresetIcon({ presetId }: { presetId: string }) {\n\tconst svgContent = PRESET_SVG[presetId] ?? PRESET_SVG.sparkle;\n\treturn (\n\t\t// biome-ignore lint: trusted static SVG content from our icon library\n\t\t<svg\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tstyle={{ width: \"55%\", height: \"55%\" }}\n\t\t\tdangerouslySetInnerHTML={{ __html: svgContent ?? \"\" }}\n\t\t/>\n\t);\n}\n\n/**\n * What the header's dismiss control does depends on the shell.\n *\n * In the bubble shell the panel goes away and the launcher is all that is left, so\n * an × is the truth. Docked, the bar stays on the page and keeps the thread one\n * keystroke away — nothing is closed, the conversation folds back into the bar.\n * A chevron says that; an × promises a disappearance that does not happen.\n */\nfunction CloseGlyph({ docked }: { docked: boolean }) {\n\tif (!docked) return <XIcon size={20} />;\n\treturn (\n\t\t<svg\n\t\t\twidth=\"20\"\n\t\t\theight=\"20\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<path d=\"M6 9.5 12 15.5 18 9.5\" />\n\t\t</svg>\n\t);\n}\n\n/**\n * Unified support widget — Intercom-style with tab navigation.\n * Two tabs: Home + Messages. Sub-views: conversation + new conversation.\n */\nexport function DefaultWidget({\n\thideLauncher = false,\n\tplacement = \"bubble\",\n\tcolorScheme,\n\tdockSuggestions,\n}: {\n\thideLauncher?: boolean;\n\tplacement?: WidgetPlacement;\n\t/**\n\t * Pin the appearance instead of following the visitor's OS. An embedded\n\t * widget lives in someone else's page; matching that page beats matching\n\t * the machine it is being read on.\n\t */\n\tcolorScheme?: \"light\" | \"dark\" | \"system\";\n\t/**\n\t * Ways in offered above the docked bar before the visitor types.\n\t * A prop for now — this belongs on AgentConfig once the API returns\n\t * per-workspace (and eventually per-page) suggestions.\n\t */\n\tdockSuggestions?: readonly DockSuggestion[];\n} = {}) {\n\tconst { isReady, website, agentConfig } = useWidget();\n\tuseI18n();\n\tconst { client, store, hasBootstrapError, wsDisconnected, retryBootstrap } = useWidgetContext();\n\tconst { conversations, create, isCreating, setActiveConversation } = useConversations();\n\tconst activeId = useWidgetStore((s) => s.activeConversationId);\n\tconst isDismissed = useWidgetStore((s) => s.isDismissed);\n\tconst { totalUnread } = useUnread();\n\t/* Threads waiting on the visitor, which the unread count cannot see: once they\n\t open a thread the count goes to zero and the conversation is still theirs to\n\t answer. Counting human replies only — an AI auto-reply follows nearly every\n\t visitor message, so including those would light the launcher permanently. */\n\tconst awaitingReply = useAwaitingReply();\n\n\tconst contentTabs = useWidgetStore((s) => s.agentConfig?.contentTabs) ?? EMPTY_CONTENT_TABS;\n\tconst { announcementTabs, markEntrySeen, getUnseenEntries } = useAnnouncements();\n\tconst unseenAnnouncementCount = useWidgetStore((s) => s.unseenAnnouncementCount);\n\t/* Read as a boolean, not the object: the dock only needs to know whether a\n\t reply is occupying a slot, and selecting the object would re-render the whole\n\t widget on every keystroke of a streamed preview. */\n\tconst incomingPreview = useWidgetStore((s) => !!s.incomingPreview);\n\n\tconst visitorContact = useWidgetStore((s) => s.visitor?.contact);\n\n\t// DEV: email prompt debug\n\tif (process.env.NODE_ENV !== \"production\") {\n\t\tconsole.debug(\"[Widget]\", {\n\t\t\treqEmail: agentConfig?.requireVisitorEmail,\n\t\t\tcontact: visitorContact?.email ?? null,\n\t\t\tactiveId,\n\t\t});\n\t}\n\n\tconst storeIsOpen = useWidgetStore((s) => s.isOpen);\n\tconst [isClosing, setIsClosing] = useState(false);\n\tconst isOpen = storeIsOpen || isClosing;\n\tconst [activeTab, setActiveTab] = useState<Tab>(\"home\");\n\tconst [subView, setSubView] = useState<SubView>(null);\n\tconst [newText, setNewText] = useState(\"\");\n\tconst [contentDetailSlug, setContentDetailSlug] = useState<string | null>(null);\n\tconst [contentCategoryName, setContentCategoryName] = useState<string | null>(null);\n\n\t// Sync API-driven navigation: when store.activeConversationId changes externally\n\t// (via window.Helpway.openConversation), drive the local subView to match.\n\tconst prevActiveIdRef = useRef(activeId);\n\tuseEffect(() => {\n\t\tif (activeId && activeId !== prevActiveIdRef.current && subView !== \"conversation\") {\n\t\t\tsetSubView(\"conversation\");\n\t\t}\n\t\tprevActiveIdRef.current = activeId;\n\t}, [activeId, subView]);\n\n\t// Consume newConversationPrefill from global API (window.Helpway.newConversation)\n\tconst prefill = useWidgetStore((s) => s.newConversationPrefill);\n\tuseEffect(() => {\n\t\tif (prefill !== null) {\n\t\t\tif (prefill.length > 0) setNewText(prefill);\n\t\t\tsetSubView(\"new\");\n\t\t\tsetActiveTab(\"home\");\n\t\t\tstore.getState().setNewConversationPrefill(null);\n\t\t}\n\t}, [prefill, store]);\n\n\tconst closeTimerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n\t// Resolve welcome/subtitle here (used both by openNewConversation seed\n\t// and by the header). Hoisted above openNewConversation so the callback\n\t// captures a defined binding instead of hitting the TDZ at closure time.\n\tconst welcomeMsgRaw = agentConfig?.welcomeMessage;\n\tconst welcomeIsFactoryDefault = !welcomeMsgRaw || welcomeMsgRaw === DEFAULT_EN_WELCOME;\n\tconst welcomeMessage = welcomeMsgRaw?.startsWith(\"widget.\")\n\t\t? t(welcomeMsgRaw)\n\t\t: welcomeIsFactoryDefault\n\t\t\t? t(\"widget.welcome_message\")\n\t\t\t: welcomeMsgRaw;\n\n\tconst openConversation = useCallback(\n\t\t(id: string) => {\n\t\t\tsetActiveConversation(id);\n\t\t\tsetSubView(\"conversation\");\n\t\t},\n\t\t[setActiveConversation],\n\t);\n\n\tconst openNewConversation = useCallback(() => {\n\t\t// Seed a temp conversation + a stable welcome bubble and drop the user\n\t\t// straight into \"conversation\" view. This keeps the welcome bubble\n\t\t// mounted in the SAME React subtree across the first-send transition\n\t\t// (previously: \"new\" view → \"conversation\" view = unmount + remount =\n\t\t// CSS `hw-msg-appear` animation replays = the \"git-gel\" flash).\n\t\t//\n\t\t// useComposer notices the temp id and routes through createConversation\n\t\t// when the visitor sends their first message.\n\t\tconst agentId = agentConfig?.id;\n\t\tif (!agentId) {\n\t\t\t// No agent config yet — skip the seed and let the server decide.\n\t\t\t// The user can still compose; submit will call createConversation.\n\t\t\tsetSubView(\"new\");\n\t\t\treturn;\n\t\t}\n\t\tconst tempId = `temp-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n\t\tconst seedWelcome: TimelineItem = {\n\t\t\tid: `seed-welcome-${tempId}`,\n\t\t\tconversationId: tempId,\n\t\t\torganizationId: \"\",\n\t\t\ttype: \"message\",\n\t\t\tvisibility: \"public\",\n\t\t\ttext: welcomeMessage,\n\t\t\tparts: null,\n\t\t\tuserId: null,\n\t\t\tvisitorId: null,\n\t\t\taiAgentId: agentId,\n\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\teditedAt: null,\n\t\t\tdeletedAt: null,\n\t\t};\n\t\tstore.getState().setMessages(tempId, [seedWelcome]);\n\t\tsetActiveConversation(tempId);\n\t\tsetSubView(\"conversation\");\n\t}, [agentConfig?.id, store, setActiveConversation, welcomeMessage]);\n\n\t// Open straight into a conversation — never onto a home screen.\n\t// First-timers get the seeded welcome + a focused composer; returning\n\t// visitors resume their most recent thread. Every screen between the\n\t// launcher and the composer is a place people drop out, so there isn't\n\t// one: the tab bar only exists once you navigate back to a list.\n\t// Ref-guarded so this fires once per open, and never fights a caller\n\t// that already routed us somewhere (openConversation / prefill).\n\tconst didAutoOpenRef = useRef(false);\n\tuseEffect(() => {\n\t\tif (!isOpen) {\n\t\t\tdidAutoOpenRef.current = false;\n\t\t\treturn;\n\t\t}\n\t\tif (didAutoOpenRef.current || !isReady) return;\n\t\tdidAutoOpenRef.current = true;\n\t\tif (subView !== null) return;\n\t\tconst mostRecent = conversations[0];\n\t\tif (mostRecent) openConversation(mostRecent.id);\n\t\telse openNewConversation();\n\t}, [isOpen, isReady, subView, conversations, openConversation, openNewConversation]);\n\n\t// ── Docked shell ───────────────────────────────────────────────────\n\t// In `placement=\"docked\"` the bar IS the composer, so it needs its own\n\t// composer state — the panel's is hidden. Sending from a cold start\n\t// has to open a conversation first, and useComposer binds its\n\t// conversation id at call time, so the text waits in a ref for one\n\t// render rather than being sent against a stale id.\n\tconst dockComposer = useComposer(activeId);\n\tconst dockRef = useRef(dockComposer);\n\t// Synced after commit, never during render — the ref is only read from\n\t// callbacks and timeouts, which all run after this effect.\n\tuseEffect(() => {\n\t\tdockRef.current = dockComposer;\n\t});\n\tconst pendingDockText = useRef<string | null>(null);\n\n\t/* Folding the panel away leaves the conversation intact — activeConversationId\n\t and the thread both survive — so pressing the bar again should put the\n\t visitor back in it. Guarded on an existing real conversation: on a docs page\n\t a press that opens an empty panel over the article is noise, and sending is\n\t already the thing that opens one from cold. */\n\tconst reopenFromDock = useCallback(() => {\n\t\tconst state = store.getState();\n\t\tif (state.isOpen) return;\n\t\tconst resumable = state.conversations.some((conv) => !conv.id.startsWith(\"temp-\"));\n\t\tif (!resumable) return;\n\t\tstate.setOpen(true);\n\t}, [store]);\n\n\tconst submitFromDock = useCallback(\n\t\t(override?: string) => {\n\t\t\tconst text = (override ?? dockRef.current.text).trim();\n\t\t\t/* An attachment with no caption still has to reach the composer. This guard\n\t\t\t used to be `if (!text) return`, which swallowed the press: the composer's\n\t\t\t caption policy — the thing that produces a visible \"add a message\" error —\n\t\t\t never ran, so a visitor who picked a file and pressed send got a dead\n\t\t\t button and no reason. Empty text is now the composer's call to refuse,\n\t\t\t which it does out loud. */\n\t\t\tconst stagedAttachment = dockRef.current.attachments.some((a) => a.part !== null);\n\t\t\tif (!text && !stagedAttachment) return;\n\t\t\t// The docked shell has no launcher, so sending is the only thing\n\t\t\t// that can reveal the panel — without this the conversation is\n\t\t\t// created and answered while nothing is on screen. Read off the\n\t\t\t// store rather than the hook: the hook binding is declared\n\t\t\t// further down this component.\n\t\t\tstore.getState().setOpen(true);\n\t\t\tif (activeId) {\n\t\t\t\tdockRef.current.setText(\"\");\n\t\t\t\tvoid dockRef.current.submit({ text, conversationId: activeId });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Cold start: openNewConversation seeds the temp conversation through\n\t\t\t// the zustand store, which is synchronous — the id is readable on the\n\t\t\t// next line, before any render. Handing it to submit is what makes a\n\t\t\t// suggestion pill actually send. The previous version staged the text\n\t\t\t// in a ref and fired a 0ms timer, and when the pill lost that race the\n\t\t\t// panel opened onto an empty composer with the question dropped.\n\t\t\topenNewConversation();\n\t\t\tconst seededId = store.getState().activeConversationId;\n\t\t\tdockRef.current.setText(\"\");\n\t\t\tif (!seededId) {\n\t\t\t\t// No agent config yet, so openNewConversation could only route to\n\t\t\t\t// the \"new\" view — the text waits until an id exists.\n\t\t\t\tpendingDockText.current = text;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvoid dockRef.current.submit({ text, conversationId: seededId });\n\t\t},\n\t\t[activeId, openNewConversation, store],\n\t);\n\n\tuseEffect(() => {\n\t\tif (!activeId || pendingDockText.current == null) return;\n\t\tconst text = pendingDockText.current;\n\t\tpendingDockText.current = null;\n\t\tvoid dockRef.current.submit({ text, conversationId: activeId });\n\t}, [activeId]);\n\n\t// Conversation options. The header's only affordance was a close\n\t// button, so expanding the panel or starting over had no home.\n\tconst [menuOpen, setMenuOpen] = useState(false);\n\tuseEffect(() => {\n\t\tif (!menuOpen) return;\n\t\tconst close = () => setMenuOpen(false);\n\t\tconst onKey = (event: KeyboardEvent) => {\n\t\t\tif (event.key === \"Escape\") setMenuOpen(false);\n\t\t};\n\t\tdocument.addEventListener(\"click\", close);\n\t\tdocument.addEventListener(\"keydown\", onKey);\n\t\treturn () => {\n\t\t\tdocument.removeEventListener(\"click\", close);\n\t\t\tdocument.removeEventListener(\"keydown\", onKey);\n\t\t};\n\t}, [menuOpen]);\n\n\tconst goBack = useCallback(() => {\n\t\tif (subView === \"content-detail\") {\n\t\t\t// If inside a grouped tab, go back to category items, not all the way to categories\n\t\t\tconst tabId = activeTab.startsWith(\"content:\") ? activeTab.slice(8) : null;\n\t\t\tconst activeContentTab = tabId ? contentTabs.find((t) => t.id === tabId) : null;\n\t\t\tif (activeContentTab?.tabType === \"grouped\" && contentCategoryName) {\n\t\t\t\tsetSubView(\"content-category\");\n\t\t\t\tsetContentDetailSlug(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetSubView(null);\n\t\t\tsetContentDetailSlug(null);\n\t\t\treturn;\n\t\t}\n\t\tif (subView === \"content-category\") {\n\t\t\tsetSubView(null);\n\t\t\tsetContentCategoryName(null);\n\t\t\treturn;\n\t\t}\n\t\t// Race-immune mark-seen: when leaving a conversation, the visitor has\n\t\t// effectively \"seen\" everything currently in it — including any AI reply\n\t\t// that may have arrived via WS milliseconds before they tapped back.\n\t\t// Without this, the WS event arriving AFTER setActiveConversation(null)\n\t\t// finds isViewing=false and increments unreadCount.\n\t\t// Skip temp-* IDs (server doesn't know about them yet).\n\t\tconst leavingId = store.getState().activeConversationId;\n\t\tif (leavingId && !leavingId.startsWith(\"temp-\")) {\n\t\t\tstore.getState().clearUnread(leavingId);\n\t\t\tclient.widget.markSeen.mutate({ conversationId: leavingId }).catch(() => {});\n\t\t}\n\t\tsetActiveConversation(null);\n\t\tsetSubView(null);\n\t}, [setActiveConversation, subView, activeTab, contentTabs, contentCategoryName, client, store]);\n\n\tconst switchTab = useCallback(\n\t\t(tab: Tab) => {\n\t\t\t// Save current tab state\n\t\t\ttabStateRef.current[activeTab] = { subView, activeId };\n\t\t\t// Restore target tab state (if any)\n\t\t\tconst saved = tabStateRef.current[tab];\n\t\t\tsetActiveTab(tab);\n\t\t\tsetSubView(saved?.subView ?? null);\n\t\t\tif (saved?.activeId != null) {\n\t\t\t\tsetActiveConversation(saved.activeId);\n\t\t\t} else if (!saved) {\n\t\t\t\tsetActiveConversation(null);\n\t\t\t}\n\t\t},\n\t\t[activeTab, subView, activeId, setActiveConversation],\n\t);\n\n\t// Consume pendingContentDetail — set by anchored consumers (or any\n\t// external trigger) that want to deep-link the visitor into a\n\t// specific content entry's detail view instead of dropping them on\n\t// the home surface. Mirrors what the launcher's announcement onOpen\n\t// does internally: mark the entry seen, switch to the right content\n\t// tab, open its detail, then clear the pending state. Sits after\n\t// `switchTab` so the dep array can reference the stable useCallback.\n\tconst pendingContentDetail = useWidgetStore((s) => s.pendingContentDetail);\n\tuseEffect(() => {\n\t\tif (!pendingContentDetail) return;\n\t\tconst { slug, tabId } = pendingContentDetail;\n\t\tmarkEntrySeen(slug);\n\t\tswitchTab(`content:${tabId}`);\n\t\tsetContentDetailSlug(slug);\n\t\tsetSubView(\"content-detail\");\n\t\tstore.getState().setPendingContentDetail(null);\n\t}, [pendingContentDetail, markEntrySeen, switchTab, store]);\n\n\tconst setStoreOpen = useWidgetStore((s) => s.setOpen);\n\n\tconst handleBubbleClick = useCallback(() => {\n\t\tif (storeIsOpen) {\n\t\t\tconst leavingId = store.getState().activeConversationId;\n\t\t\tif (leavingId && !leavingId.startsWith(\"temp-\")) {\n\t\t\t\tstore.getState().clearUnread(leavingId);\n\t\t\t\tclient.widget.markSeen.mutate({ conversationId: leavingId }).catch(() => {});\n\t\t\t}\n\t\t\tsetIsClosing(true);\n\t\t\tcloseTimerRef.current = setTimeout(() => {\n\t\t\t\tsetIsClosing(false);\n\t\t\t\tsetStoreOpen(false);\n\t\t\t}, 200);\n\t\t} else {\n\t\t\tsetIsClosing(false);\n\t\t\tsetSubView(null);\n\t\t\tsetActiveTab(\"home\");\n\t\t\tsetStoreOpen(true);\n\t\t}\n\t}, [storeIsOpen, setStoreOpen, client, store]);\n\n\tconst handleClose = useCallback(() => {\n\t\tconst leavingId = store.getState().activeConversationId;\n\t\tif (leavingId && !leavingId.startsWith(\"temp-\")) {\n\t\t\tstore.getState().clearUnread(leavingId);\n\t\t\tclient.widget.markSeen.mutate({ conversationId: leavingId }).catch(() => {});\n\t\t}\n\t\tsetIsClosing(true);\n\t\tcloseTimerRef.current = setTimeout(() => {\n\t\t\tsetIsClosing(false);\n\t\t\tsetStoreOpen(false);\n\t\t}, 200);\n\t}, [setStoreOpen, client, store]);\n\n\tconst handleNewConversation = useCallback(async () => {\n\t\tconst trimmed = newText.trim();\n\t\tif (!trimmed || isCreating) return;\n\t\tconst conv = await create(trimmed);\n\t\tif (conv) {\n\t\t\tsetNewText(\"\");\n\t\t\tsetSubView(\"conversation\");\n\t\t}\n\t}, [newText, isCreating, create]);\n\n\tconst windowRef = useRef<HTMLDivElement>(null);\n\tconst bubbleRef = useRef<HTMLButtonElement>(null);\n\tconst tabStateRef = useRef<{ [tab: string]: { subView: SubView; activeId: string | null } }>({});\n\tconst touchStartY = useRef(0);\n\tconst touchDeltaY = useRef(0);\n\n\tconst handleTouchStart = useCallback((e: React.TouchEvent) => {\n\t\ttouchStartY.current = e.touches[0]?.clientY ?? 0;\n\t\ttouchDeltaY.current = 0;\n\t}, []);\n\n\tconst handleTouchMove = useCallback((e: React.TouchEvent) => {\n\t\tconst delta = (e.touches[0]?.clientY ?? 0) - touchStartY.current;\n\t\ttouchDeltaY.current = delta;\n\t\tif (delta > 0 && windowRef.current) {\n\t\t\twindowRef.current.style.transform = `translateY(${Math.min(delta, 200)}px)`;\n\t\t\twindowRef.current.style.opacity = `${Math.max(1 - delta / 400, 0.5)}`;\n\t\t}\n\t}, []);\n\n\tconst handleTouchEnd = useCallback(() => {\n\t\tif (windowRef.current) {\n\t\t\twindowRef.current.style.transform = \"\";\n\t\t\twindowRef.current.style.opacity = \"\";\n\t\t}\n\t\tif (touchDeltaY.current > 80) {\n\t\t\thandleClose();\n\t\t}\n\t}, [handleClose]);\n\n\t// iOS virtual keyboard — `height: 100%` in CSS refers to the LAYOUT\n\t// viewport, which doesn't shrink when the keyboard opens on iOS Safari.\n\t// The result: composer gets pushed below the visible area and visitors\n\t// can't see what they're typing. visualViewport.height is the one\n\t// reliable API that reflects post-keyboard space. We write it to a CSS\n\t// custom property the mobile @media block consumes.\n\tuseEffect(() => {\n\t\tif (!isOpen || !windowRef.current) return;\n\t\tconst vv = window.visualViewport;\n\t\tif (!vv) return;\n\t\tconst win = windowRef.current;\n\t\tconst applyHeight = () => {\n\t\t\twin.style.setProperty(\"--hw-visible-height\", `${vv.height}px`);\n\t\t};\n\t\tapplyHeight();\n\t\tvv.addEventListener(\"resize\", applyHeight);\n\t\tvv.addEventListener(\"scroll\", applyHeight);\n\t\treturn () => {\n\t\t\tvv.removeEventListener(\"resize\", applyHeight);\n\t\t\tvv.removeEventListener(\"scroll\", applyHeight);\n\t\t\twin.style.removeProperty(\"--hw-visible-height\");\n\t\t};\n\t}, [isOpen]);\n\n\t// Escape to close / back — listener attached to the widget window, NOT\n\t// document. Two reasons: (1) widget lives inside a shadow DOM; document\n\t// listeners fire for host-page key events too, which would close the\n\t// widget when a visitor presses ESC in the host site's own search box.\n\t// (2) WCAG 2.1 AA requires focus-scoped escape behavior for dialogs.\n\tuseEffect(() => {\n\t\tif (!isOpen || !windowRef.current) return;\n\t\tconst win = windowRef.current;\n\t\tconst handleKeyDown = (e: KeyboardEvent) => {\n\t\t\tif (e.key === \"Escape\") {\n\t\t\t\tif (subView) {\n\t\t\t\t\tgoBack();\n\t\t\t\t} else {\n\t\t\t\t\thandleClose();\n\t\t\t\t\tsetTimeout(() => bubbleRef.current?.focus(), 220);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\twin.addEventListener(\"keydown\", handleKeyDown);\n\t\treturn () => win.removeEventListener(\"keydown\", handleKeyDown);\n\t}, [isOpen, subView, handleClose, goBack]);\n\n\t// Focus trap — same rationale: listen on the widget window so only\n\t// keydowns inside the widget are trapped. `document.activeElement`\n\t// returns the shadow HOST when focus is inside a shadow root; to find\n\t// the actually-focused element we walk into the shadow root.\n\t//\n\t// Skipped entirely under `hideLauncher` (embedded/anchored consumers\n\t// like a sidebar Help item): in that mode the widget shares space\n\t// with the host's own inputs, so grabbing focus on open silently\n\t// steals the visitor's typing/paste context — Cmd+V after opening\n\t// the panel would land in our composer instead of whatever the host\n\t// had focused (paste hijack). Trapping Tab would also fight the\n\t// host's keyboard nav. Both belong to the modal launcher use case,\n\t// not to embedded consumption.\n\tuseEffect(() => {\n\t\tif (!isOpen || !windowRef.current || hideLauncher) return;\n\t\tconst win = windowRef.current;\n\t\tconst getFocusable = () =>\n\t\t\twin.querySelectorAll<HTMLElement>(\n\t\t\t\t'button:not([disabled]), [href], input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n\t\t\t);\n\t\tconst getActive = (): Element | null => {\n\t\t\t// Prefer the shadow root's activeElement so focus tracking works\n\t\t\t// even when the widget is mounted inside a closed/open shadow DOM.\n\t\t\tconst root = win.getRootNode();\n\t\t\tif (root instanceof ShadowRoot) return root.activeElement;\n\t\t\treturn document.activeElement;\n\t\t};\n\t\tconst handleTab = (e: KeyboardEvent) => {\n\t\t\tif (e.key !== \"Tab\") return;\n\t\t\tconst focusable = getFocusable();\n\t\t\tif (focusable.length === 0) return;\n\t\t\tconst first = focusable[0];\n\t\t\tconst last = focusable[focusable.length - 1];\n\t\t\tconst active = getActive();\n\t\t\tif (e.shiftKey && active === first) {\n\t\t\t\te.preventDefault();\n\t\t\t\tlast?.focus();\n\t\t\t} else if (!e.shiftKey && active === last) {\n\t\t\t\te.preventDefault();\n\t\t\t\tfirst?.focus();\n\t\t\t}\n\t\t};\n\t\twin.addEventListener(\"keydown\", handleTab);\n\t\t/* Docked keeps its focus where it was. The composer is the dock bar, which\n\t\t lives OUTSIDE this window — so pulling focus to the panel's first button\n\t\t took it off the field the visitor was mid-sentence in: type, press\n\t\t Enter, and the caret jumped to the header. In the bubble placement the\n\t\t composer IS inside the window, so focusing into it is the right move. */\n\t\tif (placement !== \"docked\") {\n\t\t\tconst focusable = getFocusable();\n\t\t\tif (focusable.length > 0) focusable[0]?.focus();\n\t\t}\n\t\treturn () => win.removeEventListener(\"keydown\", handleTab);\n\t}, [isOpen, hideLauncher, placement]);\n\n\tconst showTabBar = subView === null;\n\t/* Header identity lives in useHeaderIdentity so the per-bubble name label can\n\t compare against the same value instead of re-deriving its own. See the hook\n\t for what the two copies of this chain cost us. */\n\tconst { humanImage, hasTeamAgent, companyName, headerName } = useHeaderIdentity();\n\tconst subtitleMsg = agentConfig?.subtitleText;\n\tconst subtitleIsFactoryDefault = !subtitleMsg || subtitleMsg === DEFAULT_EN_SUBTITLE;\n\tconst subtitleText = subtitleMsg?.startsWith(\"widget.\")\n\t\t? t(subtitleMsg)\n\t\t: subtitleIsFactoryDefault\n\t\t\t? t(\"widget.subtitle_text\")\n\t\t\t: subtitleMsg;\n\tconst brandColor = agentConfig?.brandColor ?? \"#0a0a0a\";\n\tconst widgetPosition = agentConfig?.widgetPosition ?? \"bottom-right\";\n\tconst launcherStyle = agentConfig?.launcherStyle ?? \"icon\";\n\tconst bubbleStyle = agentConfig?.bubbleStyle ?? \"rounded\";\n\n\t// Smart default: when the org uploaded a logo as the agent avatar\n\t// (vs a face photo), tint the chat-header circle with the brand\n\t// color and switch the image to `contain` so the mark isn't cropped.\n\t// `--hw-agent-bg-default` is consumed by the styles.css fallback\n\t// chain — site-side `:root { --hw-agent-bg: ... }` still wins.\n\tconst hasUploadedAvatar = !!agentConfig?.avatarUrl;\n\n\treturn (\n\t\t<div\n\t\t\tclassName=\"hw-widget\"\n\t\t\tdata-hw-placement={placement}\n\t\t\t/* Lets the docked shell close the gap between the panel and the bar while a\n\t\t\t conversation is open: the two become one card with the composer at its\n\t\t\t foot, instead of a floating panel over a separate pill. */\n\t\t\tdata-hw-open={isOpen ? \"true\" : \"false\"}\n\t\t\tdata-theme={colorScheme === \"system\" ? undefined : colorScheme}\n\t\t\tdata-has-avatar={hasUploadedAvatar ? \"true\" : \"false\"}\n\t\t\tstyle={\n\t\t\t\t{\n\t\t\t\t\t\"--hw-primary\": brandColor,\n\t\t\t\t\t\"--hw-position-right\": widgetPosition === \"bottom-right\" ? \"20px\" : \"auto\",\n\t\t\t\t\t\"--hw-position-left\": widgetPosition === \"bottom-left\" ? \"20px\" : \"auto\",\n\t\t\t\t\t\"--hw-window-right\": widgetPosition === \"bottom-right\" ? \"0\" : \"auto\",\n\t\t\t\t\t\"--hw-window-left\": widgetPosition === \"bottom-left\" ? \"0\" : \"auto\",\n\t\t\t\t} as React.CSSProperties\n\t\t\t}\n\t\t>\n\t\t\t{placement === \"docked\" && isReady && (\n\t\t\t\t<DockedBar\n\t\t\t\t\tvalue={dockComposer.text}\n\t\t\t\t\tonChange={dockComposer.setText}\n\t\t\t\t\tonSubmit={() => submitFromDock()}\n\t\t\t\t\tdisabled={dockComposer.isSubmitting}\n\t\t\t\t\tsuggestions={activeId ? undefined : dockSuggestions}\n\t\t\t\t\tonSuggestion={(question) => submitFromDock(question)}\n\t\t\t\t\tattachments={dockComposer.attachments}\n\t\t\t\t\tonAddFiles={dockComposer.addFiles}\n\t\t\t\t\tonRemoveAttachment={dockComposer.removeAttachment}\n\t\t\t\t\tonReopen={reopenFromDock}\n\t\t\t\t\tsendError={dockComposer.sendError}\n\t\t\t\t\tonClearSendError={dockComposer.clearSendError}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{isOpen && !isReady && !hasBootstrapError && (\n\t\t\t\t<div className={`hw-window ${isClosing ? \"hw-window--closing\" : \"\"}`}>\n\t\t\t\t\t<div className=\"hw-skeleton-loading\">\n\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 120 }} />\n\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 200 }} />\n\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 160 }} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t{isOpen && hasBootstrapError && (\n\t\t\t\t<div className={`hw-window ${isClosing ? \"hw-window--closing\" : \"\"}`}>\n\t\t\t\t\t<div className=\"hw-bootstrap-error\">\n\t\t\t\t\t\t<div className=\"hw-bootstrap-error-text\">{t(\"widget.error_desc\")}</div>\n\t\t\t\t\t\t<button type=\"button\" className=\"hw-bootstrap-error-retry\" onClick={retryBootstrap}>\n\t\t\t\t\t\t\t{t(\"widget.retry\")}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t{isOpen && isReady && (\n\t\t\t\t<div\n\t\t\t\t\tref={windowRef}\n\t\t\t\t\tclassName={`hw-window ${isClosing ? \"hw-window--closing\" : \"\"} ${\n\t\t\t\t\t\tsubView === \"content-detail\" ? \"hw-window--reading\" : \"\"\n\t\t\t\t\t}`}\n\t\t\t\t\trole=\"dialog\"\n\t\t\t\t\taria-label={t(\"widget.aria_chat\")}\n\t\t\t\t\taria-modal=\"true\"\n\t\t\t\t\tonTouchStart={handleTouchStart}\n\t\t\t\t\tonTouchMove={handleTouchMove}\n\t\t\t\t\tonTouchEnd={handleTouchEnd}\n\t\t\t\t>\n\t\t\t\t\t{/* Drag handle for mobile swipe-down */}\n\t\t\t\t\t<div className=\"hw-drag-handle\">\n\t\t\t\t\t\t<div className=\"hw-drag-handle-pill\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t{/* WebSocket disconnect banner */}\n\t\t\t\t\t{wsDisconnected && (\n\t\t\t\t\t\t<div className=\"hw-disconnect\">\n\t\t\t\t\t\t\t<div className=\"hw-disconnect-spinner\" />\n\t\t\t\t\t\t\t{t(\"widget.reconnecting\")}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{/* ── Sub-view header: content-detail/content-category gets centered title ── */}\n\t\t\t\t\t{(subView === \"content-detail\" || subView === \"content-category\") &&\n\t\t\t\t\t\t(() => {\n\t\t\t\t\t\t\tconst tabId = activeTab.replace(\"content:\", \"\");\n\t\t\t\t\t\t\tconst contentTab = contentTabs.find((t) => t.id === tabId);\n\t\t\t\t\t\t\t// Show category name when viewing items within a category\n\t\t\t\t\t\t\tconst headerTitle =\n\t\t\t\t\t\t\t\tsubView === \"content-category\" && contentCategoryName\n\t\t\t\t\t\t\t\t\t? contentCategoryName\n\t\t\t\t\t\t\t\t\t: contentTab?.label\n\t\t\t\t\t\t\t\t\t\t? resolveLabel(contentTab.label)\n\t\t\t\t\t\t\t\t\t\t: t(\"widget.content\");\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div className=\"hw-header hw-header--centered\">\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"hw-header-back\"\n\t\t\t\t\t\t\t\t\t\tonClick={goBack}\n\t\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_back\")}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\t\t\tstrokeWidth={2}\n\t\t\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<path d=\"M15 18l-6-6 6-6\" />\n\t\t\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-title\">{headerTitle}</div>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"hw-header-close\"\n\t\t\t\t\t\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_close\")}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<CloseGlyph docked={placement === \"docked\"} />\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})()}\n\t\t\t\t\t{subView !== null && subView !== \"content-detail\" && subView !== \"content-category\" && (\n\t\t\t\t\t\t<div className=\"hw-header hw-header--sub\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"hw-header-back\"\n\t\t\t\t\t\t\t\tonClick={goBack}\n\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_back\")}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\tstrokeWidth={2}\n\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<path d=\"M15 18l-6-6 6-6\" />\n\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<div className=\"hw-header-identity\">\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tclassName={`hw-header-bot-icon${hasTeamAgent ? \" hw-header-bot-icon--team\" : \"\"}`}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{hasTeamAgent && humanImage ? (\n\t\t\t\t\t\t\t\t\t\t<img src={humanImage} alt={headerName} className=\"hw-header-agent-img\" />\n\t\t\t\t\t\t\t\t\t) : hasTeamAgent ? (\n\t\t\t\t\t\t\t\t\t\t<span className=\"hw-header-agent-initials\">\n\t\t\t\t\t\t\t\t\t\t\t{headerName\n\t\t\t\t\t\t\t\t\t\t\t\t.split(\" \")\n\t\t\t\t\t\t\t\t\t\t\t\t.map((w: string) => w[0])\n\t\t\t\t\t\t\t\t\t\t\t\t.join(\"\")\n\t\t\t\t\t\t\t\t\t\t\t\t.slice(0, 2)\n\t\t\t\t\t\t\t\t\t\t\t\t.toUpperCase()}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t<WidgetLogo />\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"hw-header-info\">\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-name\">{headerName}</div>\n\t\t\t\t\t\t\t\t\t{/* Keep the subtitle identical in both \"new\" and \"conversation\"\n\t\t\t\t\t\t\t\t\t sub-views — otherwise the header reads \"New conversation\"\n\t\t\t\t\t\t\t\t\t while composing and snaps to \"Usually replies in minutes\"\n\t\t\t\t\t\t\t\t\t the moment you send, which feels like the whole header\n\t\t\t\t\t\t\t\t\t rebuilt. */}\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-status\">{subtitleText}</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"hw-header-actions\">\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"hw-header-menu-btn\"\n\t\t\t\t\t\t\t\t\taria-haspopup=\"menu\"\n\t\t\t\t\t\t\t\t\taria-expanded={menuOpen}\n\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_options\")}\n\t\t\t\t\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t\t\t\t\tsetMenuOpen((open) => !open);\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<DotsIcon size={18} />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"hw-header-close\"\n\t\t\t\t\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_close\")}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<CloseGlyph docked={placement === \"docked\"} />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t{menuOpen && (\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-menu\" role=\"menu\">\n\t\t\t\t\t\t\t\t\t\t{/* The docked shell has no tab bar and no list screen, so a visitor\n\t\t\t\t\t\t\t\t\t\t with three threads had no way back to the other two — the menu\n\t\t\t\t\t\t\t\t\t\t offered starting a fourth. Their own conversations belong here,\n\t\t\t\t\t\t\t\t\t\t ahead of the button that makes new ones. */}\n\t\t\t\t\t\t\t\t\t\t{conversations.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"hw-header-menu-convs\">\n\t\t\t\t\t\t\t\t\t\t\t\t{conversations.slice(0, 3).map((conv) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={conv.id}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"hw-header-menu-conv\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata-active={conv.id === activeId ? \"true\" : undefined}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetMenuOpen(false);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\topenConversation(conv.id);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"hw-header-menu-conv-top\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"hw-header-menu-conv-name\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{conversationIdentity(conv).humanName ?? companyName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{conv.lastMessageAt && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"hw-header-menu-conv-time\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatRelativeTime(conv.lastMessageAt)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"hw-header-menu-conv-preview\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{conv.lastMessageText ?? t(\"widget.no_preview\")}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\t\tsetMenuOpen(false);\n\t\t\t\t\t\t\t\t\t\t\t\topenNewConversation();\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<NewChatIcon size={16} />\n\t\t\t\t\t\t\t\t\t\t\t{t(\"widget.new_conversation\")}\n\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* ── Home: hero header with gradient + sheet overlay ── */}\n\t\t\t\t\t{subView === null && activeTab === \"home\" && (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<div className=\"hw-hero\">\n\t\t\t\t\t\t\t\t<div className=\"hw-hero-top\">\n\t\t\t\t\t\t\t\t\t<div className=\"hw-hero-bot-icon\">\n\t\t\t\t\t\t\t\t\t\t<WidgetLogo />\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"hw-hero-close\"\n\t\t\t\t\t\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_close\")}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<CloseGlyph docked={placement === \"docked\"} />\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"hw-hero-greeting\">\n\t\t\t\t\t\t\t\t\t{welcomeMessage.split(\"\\n\").map((line, i) => (\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\t\t\t\t\tclassName={i === 0 ? \"hw-hero-greeting-name\" : \"hw-hero-greeting-question\"}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{i > 0 && <br />}\n\t\t\t\t\t\t\t\t\t\t\t{line}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"hw-hero-subtitle\">{subtitleText}</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t{/* Sheet — overlaps hero, Intercom-style white drawer */}\n\t\t\t\t\t\t\t<div className=\"hw-sheet\">\n\t\t\t\t\t\t\t\t<div className=\"hw-sheet-inner\">\n\t\t\t\t\t\t\t\t\t<button type=\"button\" className=\"hw-card\" onClick={openNewConversation}>\n\t\t\t\t\t\t\t\t\t\t<div className=\"hw-card-body\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"hw-card-title\">{t(\"widget.send_us_message\")}</div>\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"hw-card-meta\">{t(\"widget.reply_time\")}</div>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t<div className=\"hw-card-arrow\">\n\t\t\t\t\t\t\t\t\t\t\t<SendIcon />\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t{announcementTabs.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t<WhatsNewCard\n\t\t\t\t\t\t\t\t\t\t\tgetUnseenEntries={getUnseenEntries}\n\t\t\t\t\t\t\t\t\t\t\tannouncementTabs={announcementTabs}\n\t\t\t\t\t\t\t\t\t\t\tonViewAll={() => {\n\t\t\t\t\t\t\t\t\t\t\t\tswitchTab(`content:${announcementTabs[0]!.id}`);\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\tonSelect={(slug, tabId) => {\n\t\t\t\t\t\t\t\t\t\t\t\tswitchTab(`content:${tabId}`);\n\t\t\t\t\t\t\t\t\t\t\t\tsetContentDetailSlug(slug);\n\t\t\t\t\t\t\t\t\t\t\t\tsetSubView(\"content-detail\");\n\t\t\t\t\t\t\t\t\t\t\t\tmarkEntrySeen(slug);\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t<HomeView\n\t\t\t\t\t\t\t\t\t\tconversations={conversations}\n\t\t\t\t\t\t\t\t\t\tonSelect={openConversation}\n\t\t\t\t\t\t\t\t\t\tonMessagesClick={() => switchTab(\"messages\")}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* ── Messages tab header ── */}\n\t\t\t\t\t{subView === null && activeTab === \"messages\" && (\n\t\t\t\t\t\t<div className=\"hw-header hw-header--centered\">\n\t\t\t\t\t\t\t<div className=\"hw-header-spacer\" />\n\t\t\t\t\t\t\t<div className=\"hw-header-title\">{t(\"widget.messages\")}</div>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"hw-header-close\"\n\t\t\t\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_close\")}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<CloseGlyph docked={placement === \"docked\"} />\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* ── Content tab header (list view, not detail) ── */}\n\t\t\t\t\t{subView === null &&\n\t\t\t\t\t\tactiveTab.startsWith(\"content:\") &&\n\t\t\t\t\t\t(() => {\n\t\t\t\t\t\t\tconst tabId = activeTab.replace(\"content:\", \"\");\n\t\t\t\t\t\t\tconst contentTab = contentTabs.find((t) => t.id === tabId);\n\t\t\t\t\t\t\tif (!contentTab) return null;\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div className=\"hw-header hw-header--centered\">\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-spacer\" />\n\t\t\t\t\t\t\t\t\t<div className=\"hw-header-title\">{resolveLabel(contentTab.label)}</div>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"hw-header-close\"\n\t\t\t\t\t\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_close\")}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<CloseGlyph docked={placement === \"docked\"} />\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})()}\n\n\t\t\t\t\t{/* ── Content (non-home views) ── */}\n\t\t\t\t\t{(subView !== null || activeTab !== \"home\") && (\n\t\t\t\t\t\t<div className=\"hw-content\">\n\t\t\t\t\t\t\t{subView === null && activeTab === \"messages\" && (\n\t\t\t\t\t\t\t\t<MessagesView\n\t\t\t\t\t\t\t\t\tconversations={conversations}\n\t\t\t\t\t\t\t\t\tonSelect={openConversation}\n\t\t\t\t\t\t\t\t\tonNewClick={openNewConversation}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t{subView === \"new\" && (\n\t\t\t\t\t\t\t\t<NewConversationView\n\t\t\t\t\t\t\t\t\ttext={newText}\n\t\t\t\t\t\t\t\t\tonTextChange={setNewText}\n\t\t\t\t\t\t\t\t\tonSubmit={handleNewConversation}\n\t\t\t\t\t\t\t\t\tisSubmitting={isCreating}\n\t\t\t\t\t\t\t\t\twelcomeMessage={welcomeMessage}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t{subView === \"conversation\" && activeId && (\n\t\t\t\t\t\t\t\t<ConversationView conversationId={activeId} starters={dockSuggestions} />\n\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t{/* ── Content tab views ── */}\n\t\t\t\t\t\t\t{activeTab.startsWith(\"content:\") &&\n\t\t\t\t\t\t\t\t(() => {\n\t\t\t\t\t\t\t\t\tconst tabId = activeTab.replace(\"content:\", \"\");\n\t\t\t\t\t\t\t\t\tconst contentTab = contentTabs.find((t) => t.id === tabId);\n\t\t\t\t\t\t\t\t\tif (!contentTab) return null;\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<ContentTabView\n\t\t\t\t\t\t\t\t\t\t\ttab={contentTab}\n\t\t\t\t\t\t\t\t\t\t\tshowDetail={subView === \"content-detail\"}\n\t\t\t\t\t\t\t\t\t\t\tdetailSlug={contentDetailSlug}\n\t\t\t\t\t\t\t\t\t\t\tsubView={subView}\n\t\t\t\t\t\t\t\t\t\t\tonSelectEntry={(slug) => {\n\t\t\t\t\t\t\t\t\t\t\t\tsetContentDetailSlug(slug);\n\t\t\t\t\t\t\t\t\t\t\t\tsetSubView(\"content-detail\");\n\t\t\t\t\t\t\t\t\t\t\t\t// Mark seen on open, mirroring the home-tab and\n\t\t\t\t\t\t\t\t\t\t\t\t// deep-link paths. Without this, opening a changelog\n\t\t\t\t\t\t\t\t\t\t\t\t// entry from the content tab left the unseen badge\n\t\t\t\t\t\t\t\t\t\t\t\t// stuck until another path happened to clear it.\n\t\t\t\t\t\t\t\t\t\t\t\tmarkEntrySeen(slug);\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\tonSelectCategory={(cat) => {\n\t\t\t\t\t\t\t\t\t\t\t\tsetContentCategoryName(cat.title);\n\t\t\t\t\t\t\t\t\t\t\t\tsetSubView(\"content-category\");\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t})()}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* ── Tab Bar ── */}\n\t\t\t\t\t{showTabBar && (\n\t\t\t\t\t\t<TabBar\n\t\t\t\t\t\t\tactiveTab={activeTab}\n\t\t\t\t\t\t\tonTabChange={switchTab}\n\t\t\t\t\t\t\tunreadCount={totalUnread}\n\t\t\t\t\t\t\tcontentTabs={contentTabs}\n\t\t\t\t\t\t\tshowMessagesTab={agentConfig?.showMessagesTab ?? true}\n\t\t\t\t\t\t\tunseenAnnouncementCount={unseenAnnouncementCount}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* ── Footer ── */}\n\t\t\t\t\t<div className=\"hw-powered\">\n\t\t\t\t\t\t{t(\"widget.powered_by\")}{\" \"}\n\t\t\t\t\t\t<a href=\"https://helpway.ai\" target=\"_blank\" rel=\"noopener noreferrer\">\n\t\t\t\t\t\t\tHelpway\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Closed-state dock — one owner for the strip above the launcher.\n\n\t\t\t Both cards used to pin themselves to this exact spot independently,\n\t\t\t so a visitor with an unread reply AND unseen announced content got\n\t\t\t them stacked on top of each other, the lower one unreadable and\n\t\t\t unclickable. They are siblings in one flex column now; see\n\t\t\t `.hw-preview-dock` for why the order below is the priority order. */}\n\t\t\t{isReady && !isOpen && !isDismissed && !hideLauncher && (\n\t\t\t\t<div className=\"hw-preview-dock\">\n\t\t\t\t\t{/* Announcements sit above — content that can wait, and the first thing\n\t\t\t\t\t to give up a slot. Two cards is the whole budget for this strip:\n\t\t\t\t\t four of them need more viewport than a laptop has, and the ones that\n\t\t\t\t\t overflowed went off the top of the screen rather than queueing.\n\t\t\t\t\t A pending reply takes one slot, so announcements get the other. */}\n\t\t\t\t\t<AnnouncementPreviews\n\t\t\t\t\t\tmaxVisible={incomingPreview ? 1 : 2}\n\t\t\t\t\t\tavatar={<WidgetLogo />}\n\t\t\t\t\t\tonOpen={(slug, tabId) => {\n\t\t\t\t\t\t\tmarkEntrySeen(slug);\n\t\t\t\t\t\t\thandleBubbleClick();\n\t\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\t\tswitchTab(`content:${tabId}`);\n\t\t\t\t\t\t\t\tsetContentDetailSlug(slug);\n\t\t\t\t\t\t\t\tsetSubView(\"content-detail\");\n\t\t\t\t\t\t\t}, 50);\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\n\t\t\t\t\t{/* The reply sits nearest the launcher.\n\n\t\t\t\t\t No auto-dismiss. This card only ever carries a real incoming\n\t\t\t\t\t reply, and the old 8-second timer deleted it: a visitor who\n\t\t\t\t\t looked away for a moment lost the notification entirely — the\n\t\t\t\t\t unread count stayed, the words did not. It now waits for the\n\t\t\t\t\t visitor to open the thread or close the card, which is what a\n\t\t\t\t\t notification is supposed to do. */}\n\t\t\t\t\t<MessagePreview onOpen={handleBubbleClick} avatar={<WidgetLogo />} autoDismissMs={null} />\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Dev-only debug overlay — activates via ?hwdebug=1 or localStorage hw:debug=1 */}\n\t\t\t<WidgetDebugOverlay />\n\n\t\t\t{/* Bubble — hidden until bootstrap completes so visitors don't\n\t\t\t see a flash of the default Helpway brand mark + neutral\n\t\t\t color before the org's custom icon + brand color arrive.\n\t\t\t isReady flips true once and stays true, so the bubble\n\t\t\t remains visible across the rest of the session. */}\n\t\t\t{isReady && !isDismissed && (!hideLauncher || isOpen) && (\n\t\t\t\t<button\n\t\t\t\t\tref={bubbleRef}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName={[\n\t\t\t\t\t\t\"hw-bubble\",\n\t\t\t\t\t\t`hw-bubble--${bubbleStyle}`,\n\t\t\t\t\t\tlauncherStyle !== \"icon\" ? `hw-bubble--launcher-${launcherStyle}` : \"\",\n\t\t\t\t\t\tisOpen ? \"hw-bubble--open\" : \"\",\n\t\t\t\t\t\tagentConfig?.launcherIconUrl || agentConfig?.avatarUrl || website?.logoUrl\n\t\t\t\t\t\t\t? \"hw-bubble--avatar\"\n\t\t\t\t\t\t\t: \"\",\n\t\t\t\t\t]\n\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t.join(\" \")}\n\t\t\t\t\tonClick={handleBubbleClick}\n\t\t\t\t\taria-label={isOpen ? t(\"widget.aria_close_support\") : t(\"widget.aria_open\")}\n\t\t\t\t\taria-expanded={isOpen}\n\t\t\t\t\taria-haspopup=\"dialog\"\n\t\t\t\t>\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName={`hw-bubble-icon hw-bubble-icon--bot ${isOpen ? \"hw-bubble-icon--hidden\" : \"\"}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<LauncherIcon />\n\t\t\t\t\t</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName={`hw-bubble-icon hw-bubble-icon--close ${!isOpen ? \"hw-bubble-icon--hidden\" : \"\"}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<XIcon size={24} />\n\t\t\t\t\t</span>\n\t\t\t\t\t{launcherStyle !== \"icon\" && !isOpen && (\n\t\t\t\t\t\t<span className=\"hw-bubble-label\">\n\t\t\t\t\t\t\t{launcherStyle === \"help\" ? t(\"widget.help\") : companyName}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)}\n\t\t\t\t\t{!isOpen && (totalUnread > 0 || awaitingReply > 0 || unseenAnnouncementCount > 0) && (\n\t\t\t\t\t\t<div className=\"hw-bubble-badge\">\n\t\t\t\t\t\t\t{totalUnread > 0 ? totalUnread : \"\"}\n\t\t\t\t\t\t\t{/* A dot, not a number, for the awaiting case. The visitor has\n\t\t\t\t\t\t\t already read the reply — there is nothing new to count, only a\n\t\t\t\t\t\t\t thread still waiting on them, and printing a \"1\" for something\n\t\t\t\t\t\t\t they have seen is how a badge stops meaning anything. */}\n\t\t\t\t\t\t\t{totalUnread === 0 && (awaitingReply > 0 || unseenAnnouncementCount > 0) && (\n\t\t\t\t\t\t\t\t<span className=\"hw-bubble-badge-dot\" />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// ── Tab Bar ─────────────────────────────────────────────\n\nfunction TabBar({\n\tactiveTab,\n\tonTabChange,\n\tunreadCount,\n\tcontentTabs,\n\tshowMessagesTab = true,\n\tunseenAnnouncementCount = 0,\n}: {\n\tactiveTab: Tab;\n\tonTabChange: (tab: Tab) => void;\n\tunreadCount: number;\n\tcontentTabs: WidgetContentTab[];\n\tshowMessagesTab?: boolean;\n\tunseenAnnouncementCount?: number;\n}) {\n\treturn (\n\t\t<div className=\"hw-tabs\" role=\"tablist\">\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tclassName={`hw-tabs-item ${activeTab === \"home\" ? \"hw-tabs-item--active\" : \"\"}`}\n\t\t\t\tonClick={() => onTabChange(\"home\")}\n\t\t\t\trole=\"tab\"\n\t\t\t\taria-selected={activeTab === \"home\"}\n\t\t\t>\n\t\t\t\t<HomeIcon />\n\t\t\t\t<span>{t(\"widget.home\")}</span>\n\t\t\t</button>\n\t\t\t{showMessagesTab && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName={`hw-tabs-item ${activeTab === \"messages\" ? \"hw-tabs-item--active\" : \"\"}`}\n\t\t\t\t\tonClick={() => onTabChange(\"messages\")}\n\t\t\t\t\trole=\"tab\"\n\t\t\t\t\taria-selected={activeTab === \"messages\"}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"hw-tabs-icon-wrap\">\n\t\t\t\t\t\t<MessagesIcon />\n\t\t\t\t\t\t{unreadCount > 0 && (\n\t\t\t\t\t\t\t<span className=\"hw-tabs-badge\">{unreadCount > 99 ? \"99+\" : unreadCount}</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span>{t(\"widget.messages\")}</span>\n\t\t\t\t</button>\n\t\t\t)}\n\t\t\t{/* Dynamic content tabs from Better i18n Content CMS */}\n\t\t\t{contentTabs.map((tab) => (\n\t\t\t\t<button\n\t\t\t\t\tkey={tab.id}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName={`hw-tabs-item ${activeTab === `content:${tab.id}` ? \"hw-tabs-item--active\" : \"\"}`}\n\t\t\t\t\tonClick={() => onTabChange(`content:${tab.id}`)}\n\t\t\t\t\trole=\"tab\"\n\t\t\t\t\taria-selected={activeTab === `content:${tab.id}`}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"hw-tabs-icon-wrap\">\n\t\t\t\t\t\t<ContentTabIconComponent icon={tab.icon} />\n\t\t\t\t\t\t{tab.isAnnouncements && unseenAnnouncementCount > 0 && <span className=\"hw-tabs-dot\" />}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span>{resolveLabel(tab.label)}</span>\n\t\t\t\t</button>\n\t\t\t))}\n\t\t</div>\n\t);\n}\n\n// ── Home Tab ────────────────────────────────────────────\n\nfunction HomeView({\n\tconversations,\n\tonSelect,\n\tonMessagesClick,\n}: {\n\tconversations: ConversationSummary[];\n\tonSelect: (id: string) => void;\n\tonMessagesClick: () => void;\n}) {\n\tconst recent = conversations.slice(0, 3);\n\tif (recent.length === 0) return null;\n\n\treturn (\n\t\t<div className=\"hw-recent-card\">\n\t\t\t<div className=\"hw-recent-header\">{t(\"widget.recent_conversations\")}</div>\n\t\t\t{recent.map((conv, i) => (\n\t\t\t\t<ConversationRow\n\t\t\t\t\tkey={conv.id}\n\t\t\t\t\tconversation={conv}\n\t\t\t\t\tonSelect={onSelect}\n\t\t\t\t\tisLast={i === recent.length - 1}\n\t\t\t\t/>\n\t\t\t))}\n\t\t\t{conversations.length > 3 && (\n\t\t\t\t<button type=\"button\" className=\"hw-recent-see-all\" onClick={onMessagesClick}>\n\t\t\t\t\t{t(\"widget.see_all\")}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// ── Messages Tab ────────────────────────────────────────\n\nfunction MessagesView({\n\tconversations,\n\tonSelect,\n\tonNewClick,\n}: {\n\tconversations: ConversationSummary[];\n\tonSelect: (id: string) => void;\n\tonNewClick: () => void;\n}) {\n\tif (conversations.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"hw-empty-state\">\n\t\t\t\t<div className=\"hw-empty-icon-wrap\">\n\t\t\t\t\t<MessagesIcon />\n\t\t\t\t</div>\n\t\t\t\t<div className=\"hw-empty-title\">{t(\"widget.no_messages\")}</div>\n\t\t\t\t<div className=\"hw-empty-desc\">{t(\"widget.no_messages_desc\")}</div>\n\t\t\t\t<button type=\"button\" className=\"hw-empty-btn\" onClick={onNewClick}>\n\t\t\t\t\t{t(\"widget.start_conversation\")}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"hw-msgs-tab\">\n\t\t\t{conversations.map((conv) => (\n\t\t\t\t<ConversationCard key={conv.id} conversation={conv} onSelect={onSelect} />\n\t\t\t))}\n\t\t</div>\n\t);\n}\n\n// ── Shared conversation body (avatar + name + time + preview) ──\n\nfunction ConvCardBody({ conv }: { conv: ConversationSummary }) {\n\tconst agentName = useWidgetStore((s) => s.agentConfig?.name) ?? \"Support\";\n\t/* Assignment, not last-speaker. This row used to read `lastMessageSenderType\n\t === \"team\"`, which is only true while a teammate's own message is the newest\n\t thing in the thread. The moment the visitor replied, the row fell back to\n\t the AI's name — so a conversation a human had taken over was listed as\n\t \"Better AI\" underneath the visitor's own words, while the header two taps\n\t away named the human correctly. Both surfaces now ask\n\t `conversationIdentity()`. */\n\tconst { humanName, humanImage } = conversationIdentity(conv);\n\tconst isTeam = !!humanName;\n\tconst displayName = humanName ?? agentName;\n\tconst preview = conv.lastMessageText ?? t(\"widget.no_preview\");\n\treturn (\n\t\t<>\n\t\t\t<div className={`hw-conv-card-avatar${isTeam ? \" hw-conv-card-avatar--team\" : \"\"}`}>\n\t\t\t\t{isTeam ? (\n\t\t\t\t\thumanImage ? (\n\t\t\t\t\t\t<img src={humanImage} alt={displayName} className=\"hw-conv-card-avatar-img\" />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<span className=\"hw-conv-card-avatar-initials\">\n\t\t\t\t\t\t\t{displayName\n\t\t\t\t\t\t\t\t.split(\" \")\n\t\t\t\t\t\t\t\t.map((w) => w[0])\n\t\t\t\t\t\t\t\t.join(\"\")\n\t\t\t\t\t\t\t\t.slice(0, 2)\n\t\t\t\t\t\t\t\t.toUpperCase()}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)\n\t\t\t\t) : (\n\t\t\t\t\t<WidgetLogo />\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div className=\"hw-conv-card-content\">\n\t\t\t\t<div className=\"hw-conv-card-top\">\n\t\t\t\t\t<span className=\"hw-conv-card-name\">{displayName}</span>\n\t\t\t\t\t{conv.lastMessageAt && (\n\t\t\t\t\t\t<span className=\"hw-conv-card-time\">{formatRelativeTime(conv.lastMessageAt)}</span>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"hw-conv-card-preview\">{preview}</div>\n\t\t\t</div>\n\t\t</>\n\t);\n}\n\n// ── Conversation Card (Intercom-style, Messages tab) ─────\n\nfunction ConversationCard({\n\tconversation: conv,\n\tonSelect,\n}: {\n\tconversation: ConversationSummary;\n\tonSelect: (id: string) => void;\n}) {\n\tconst hasUnread = conv.unreadCount > 0;\n\t/* Only when there is no count to show. An unread badge already says \"something\n\t new is here\"; printing both a \"2\" and \"Awaiting your reply\" on one row says\n\t it twice and turns a state into decoration.\n\n\t The case this exists for is the one the badge cannot cover: the visitor\n\t OPENED the thread, so the count is zero, and still did not answer. That is\n\t where a support conversation dies — we replied, they saw it, nothing on\n\t screen ever mentions it again. */\n\tconst awaiting = !hasUnread && isAwaitingVisitorReply(conv);\n\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclassName={`hw-conv-card ${hasUnread ? \"hw-conv-card--unread\" : \"\"}`}\n\t\t\tonClick={() => onSelect(conv.id)}\n\t\t>\n\t\t\t<div className=\"hw-conv-card-row\">\n\t\t\t\t<ConvCardBody conv={conv} />\n\t\t\t</div>\n\t\t\t{hasUnread && <div className=\"hw-conv-card-badge\">{conv.unreadCount}</div>}\n\t\t\t{awaiting && <div className=\"hw-awaiting\">{t(\"widget.awaiting_your_reply\")}</div>}\n\t\t</button>\n\t);\n}\n\n// ── Conversation Row (inside Home tab grouped card) ───────\n\nfunction ConversationRow({\n\tconversation: conv,\n\tonSelect,\n\tisLast,\n}: {\n\tconversation: ConversationSummary;\n\tonSelect: (id: string) => void;\n\tisLast: boolean;\n}) {\n\tconst hasUnread = conv.unreadCount > 0;\n\tconst awaiting = !hasUnread && isAwaitingVisitorReply(conv);\n\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclassName={`hw-recent-row ${hasUnread ? \"hw-recent-row--unread\" : \"\"} ${isLast ? \"hw-recent-row--last\" : \"\"}`}\n\t\t\tonClick={() => onSelect(conv.id)}\n\t\t>\n\t\t\t<ConvCardBody conv={conv} />\n\t\t\t{hasUnread && <div className=\"hw-recent-row-badge\">{conv.unreadCount}</div>}\n\t\t\t{awaiting && <div className=\"hw-awaiting\">{t(\"widget.awaiting_your_reply\")}</div>}\n\t\t</button>\n\t);\n}\n\n// ── Inline Email Prompt (post-first-reply) ─────────────\n\nfunction InlineEmailPrompt({ conversationId }: { conversationId?: string }) {\n\tconst { client, store } = useWidgetContext();\n\tconst updateContact = useWidgetStore((s) => s.updateVisitorContact);\n\tconst [email, setEmail] = useState(\"\");\n\tconst [isSubmitting, setIsSubmitting] = useState(false);\n\tconst [isSuccess, setIsSuccess] = useState(false);\n\tconst [hasError, setHasError] = useState(false);\n\n\tconst handleSubmit = async () => {\n\t\tconst trimmed = email.trim();\n\t\tif (!trimmed || !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(trimmed)) {\n\t\t\tsetHasError(true);\n\t\t\treturn;\n\t\t}\n\t\tsetHasError(false);\n\n\t\tconst previousContact = store.getState().visitor?.contact ?? null;\n\t\tconst optimisticContactId = previousContact?.id ?? `optimistic-contact-${Date.now()}`;\n\t\tupdateContact({\n\t\t\tid: optimisticContactId,\n\t\t\tname: previousContact?.name ?? null,\n\t\t\temail: trimmed,\n\t\t});\n\t\tsetIsSuccess(true);\n\t\tsetIsSubmitting(true);\n\t\ttry {\n\t\t\tconst result = await client.widget.collectEmail.mutate({\n\t\t\t\temail: trimmed,\n\t\t\t\t...(conversationId ? { conversationId } : {}),\n\t\t\t});\n\t\t\tif (result.contact) {\n\t\t\t\tupdateContact({\n\t\t\t\t\tid: result.contact.id,\n\t\t\t\t\tname: result.contact.name,\n\t\t\t\t\temail: result.contact.email,\n\t\t\t\t});\n\t\t\t}\n\t\t\t// needsEmail will become false via optimistic contact update\n\t\t} catch {\n\t\t\tif (previousContact) {\n\t\t\t\tupdateContact(previousContact);\n\t\t\t} else {\n\t\t\t\tupdateContact({ id: \"\", name: null, email: null });\n\t\t\t}\n\t\t\tsetIsSuccess(false);\n\t\t} finally {\n\t\t\tsetIsSubmitting(false);\n\t\t}\n\t};\n\n\tif (isSuccess) {\n\t\treturn (\n\t\t\t<div className=\"hw-email-card hw-email-card--success\">\n\t\t\t\t<svg\n\t\t\t\t\twidth=\"15\"\n\t\t\t\t\theight=\"15\"\n\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"#22c55e\"\n\t\t\t\t\tstrokeWidth={2.5}\n\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t>\n\t\t\t\t\t<polyline points=\"20 6 9 17 4 12\" />\n\t\t\t\t</svg>\n\t\t\t\t{t(\"widget.email_saved\")}\n\t\t\t</div>\n\t\t);\n\t}\n\n\t/* Asking for an email is a one-field favour, and it was built like a form: an\n\t icon tile, two lines of header, a full-width input and a full-width button —\n\t four stacked blocks and about 150px of thread for one address. It is a\n\t labelled row now, with the submit inside the field, so it reads as part of\n\t the conversation rather than an interruption of it. */\n\treturn (\n\t\t<div className=\"hw-email-card\">\n\t\t\t<p className=\"hw-email-card-title\">{t(\"widget.email_title\")}</p>\n\t\t\t<p className=\"hw-email-card-subtitle\">{t(\"widget.email_subtitle\")}</p>\n\t\t\t<div className=\"hw-email-card-row\">\n\t\t\t\t<input\n\t\t\t\t\ttype=\"email\"\n\t\t\t\t\tclassName={`hw-email-card-input${hasError ? \" hw-email-card-input--error\" : \"\"}`}\n\t\t\t\t\tvalue={email}\n\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\tsetEmail(e.target.value);\n\t\t\t\t\t\tsetHasError(false);\n\t\t\t\t\t}}\n\t\t\t\t\tonKeyDown={(e) => {\n\t\t\t\t\t\tif (e.key === \"Enter\") handleSubmit();\n\t\t\t\t\t}}\n\t\t\t\t\tplaceholder={t(\"widget.email_placeholder\")}\n\t\t\t\t/>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"hw-email-card-submit\"\n\t\t\t\t\tonClick={handleSubmit}\n\t\t\t\t\tdisabled={isSubmitting || !email.trim()}\n\t\t\t\t\taria-label={t(\"widget.email_continue\")}\n\t\t\t\t>\n\t\t\t\t\t{isSubmitting ? (\n\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\twidth=\"14\"\n\t\t\t\t\t\t\theight=\"14\"\n\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\tstrokeWidth={2}\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<circle cx=\"12\" cy=\"12\" r=\"10\" strokeDasharray=\"32\" strokeDashoffset=\"32\">\n\t\t\t\t\t\t\t\t<animate\n\t\t\t\t\t\t\t\t\tattributeName=\"stroke-dashoffset\"\n\t\t\t\t\t\t\t\t\tvalues=\"32;0\"\n\t\t\t\t\t\t\t\t\tdur=\"1s\"\n\t\t\t\t\t\t\t\t\trepeatCount=\"indefinite\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</circle>\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\twidth=\"15\"\n\t\t\t\t\t\t\theight=\"15\"\n\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\tstrokeWidth={2.2}\n\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<path d=\"M5 12h13M12 5l7 7-7 7\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ── New Conversation ────────────────────────────────────\n\nfunction NewConversationView({\n\ttext,\n\tonTextChange,\n\tonSubmit,\n\tisSubmitting,\n\twelcomeMessage,\n}: {\n\ttext: string;\n\tonTextChange: (t: string) => void;\n\tonSubmit: () => void;\n\tisSubmitting: boolean;\n\twelcomeMessage: string;\n}) {\n\t// Stable timestamp so the bubble doesn't tick/re-render while the user types.\n\treturn (\n\t\t<div className=\"hw-new\">\n\t\t\t{/* Use the same MessageBubble that renders inside ConversationView so\n\t\t\t the welcome message looks IDENTICAL before and after the first send\n\t\t\t — same markdown rendering (line breaks preserved), same styles,\n\t\t\t same meta row. Without this the \"new\" view uses a raw string render\n\t\t\t and the user sees the bubble visually change the moment the\n\t\t\t conversation is created. */}\n\t\t\t<div className=\"hw-new-welcome\">\n\t\t\t\t<MessageBubble text={welcomeMessage} sender=\"ai\" parts={null} />\n\t\t\t</div>\n\t\t\t<Composer\n\t\t\t\ttext={text}\n\t\t\t\tonTextChange={onTextChange}\n\t\t\t\tonSubmit={onSubmit}\n\t\t\t\tisSubmitting={isSubmitting}\n\t\t\t\tplaceholder={t(\"widget.placeholder_new\")}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\n// ── Conversation View ───────────────────────────────────\n\nfunction ConversationView({\n\tconversationId,\n\tstarters,\n}: {\n\tconversationId: string;\n\t/** Offered under the greeting until the visitor has said something. */\n\tstarters?: readonly DockSuggestion[];\n}) {\n\tconst { items, isLoading, hasMore, loadMore } = useTimeline(conversationId);\n\tconst {\n\t\ttext,\n\t\tsetText,\n\t\tsubmit,\n\t\tisSubmitting,\n\t\tattachments,\n\t\taddFiles,\n\t\tremoveAttachment,\n\t\tsendError,\n\t\tclearSendError,\n\t\temailGateConvId,\n\t} = useComposer(conversationId);\n\tconst { isTyping, isAiProcessing, setTyping } = usePresence(conversationId);\n\tconst streamingText = useWidgetStore((s) => s.streamingText.get(conversationId) ?? \"\");\n\tconst agentConfig = useWidgetStore((s) => s.agentConfig);\n\tconst visitorContact = useWidgetStore((s) => s.visitor?.contact);\n\n\t// Only while the thread is still nothing but the seeded welcome. The\n\t// first rule here checked for a visitor message, which left the\n\t// suggestions sitting under \"<name> joined the conversation\" — a human\n\t// arriving is exactly the moment canned questions stop being helpful.\n\t// Any second item at all means something happened, so that is the test.\n\tconst showStarters = !!starters?.length && items.length <= 1;\n\n\t// Reaching a human is something the agent offers, not a control the\n\t// visitor has to find. Fin has none anywhere and gates the request\n\t// behind an email form; this is one tap and never gated. Shown once\n\t// the agent has actually said something, and dropped as soon as a\n\t// human is in the thread.\n\n\tconst isResolved = useWidgetStore((s) => {\n\t\tconst conv = s.conversations.find((c) => c.id === conversationId);\n\t\treturn conv?.status === \"resolved\";\n\t});\n\n\t// Email prompt gate (BETTER-227 — Intercom pattern).\n\t// Show ONLY after:\n\t// (1) visitor sent at least one real message (not the welcome bubble), AND\n\t// (2) AI has replied at least once (so the visitor has seen value from the widget)\n\t// Prevents the \"Get notified when we reply\" card from appearing on widget open\n\t// before the visitor has even typed. Matches Intercom's post-first-response flow.\n\tconst visitorMessageCount = items.filter(\n\t\t(it) => it.type === \"message\" && Boolean((it as { visitorId?: string | null }).visitorId),\n\t).length;\n\tconst hasAiReply = items.some(\n\t\t(it) => it.type === \"message\" && Boolean((it as { aiAgentId?: string | null }).aiAgentId),\n\t);\n\t// Email is satisfied if EITHER the contact has one (fully identified\n\t// visitor) OR the visitor itself has one (collected via the gate but\n\t// not yet linked to a Contact row). Without the visitor.email fallback,\n\t// the gate re-shows on every refresh until a Contact is created.\n\tconst visitorOwnEmail = useWidgetStore((s) => s.visitor?.email);\n\tconst hasEmail = !!visitorContact?.email || !!visitorOwnEmail;\n\tconst needsEmailPostReply =\n\t\t!!agentConfig?.requireVisitorEmail && !hasEmail && visitorMessageCount >= 2 && hasAiReply;\n\tconst needsEmail = needsEmailPostReply || !!emailGateConvId;\n\n\tif (isLoading && items.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"hw-messages\">\n\t\t\t\t<div className=\"hw-skeleton-messages\">\n\t\t\t\t\t{/* AI message skeleton */}\n\t\t\t\t\t<div className=\"hw-skeleton-msg\">\n\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-avatar\" />\n\t\t\t\t\t\t<div className=\"hw-skeleton-bubble\">\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 140 }} />\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 200 }} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t{/* Visitor message skeleton */}\n\t\t\t\t\t<div className=\"hw-skeleton-msg hw-skeleton-msg--right\">\n\t\t\t\t\t\t<div className=\"hw-skeleton-bubble\" style={{ alignItems: \"flex-end\" }}>\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 160 }} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t{/* AI reply skeleton */}\n\t\t\t\t\t<div className=\"hw-skeleton-msg\">\n\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-avatar\" />\n\t\t\t\t\t\t<div className=\"hw-skeleton-bubble\">\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 180 }} />\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 120 }} />\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: 80 }} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<MessageList\n\t\t\t\titems={items}\n\t\t\t\t/* Not while the email ask is on screen. The card already states what\n\t\t\t\t happens next — \"We'll email you when we respond\" — and a thinking\n\t\t\t\t indicator underneath it promises something different: that a reply is\n\t\t\t\t arriving right now. Two answers to \"what am I waiting for\", stacked.\n\t\t\t\t Whichever one is true, showing both is wrong, so the card wins while\n\t\t\t\t it is up; the moment the visitor submits, `needsEmail` clears and the\n\t\t\t\t indicator comes back if the AI really is working. */\n\t\t\t\tisTyping={isTyping && !needsEmail}\n\t\t\t\tisAiProcessing={isAiProcessing && !needsEmail}\n\t\t\t\tstreamingText={streamingText || undefined}\n\t\t\t\thasMore={hasMore}\n\t\t\t\tisLoadingMore={isLoading}\n\t\t\t\tonLoadMore={loadMore}\n\t\t\t\t/* No \"Talk to a human\" offer here any more. The pipeline escalates on its\n\t\t\t\t own the moment it cannot answer — that is what the escalate tool is\n\t\t\t\t for — so the button was a second, manual path to something that had\n\t\t\t\t already happened, and it sat under every answer including the ones\n\t\t\t\t that were fine. */\n\t\t\t\t/* The email ask belongs IN the thread. Pinned under the list it read as\n\t\t\t\t chrome — a form the panel had grown at the bottom, competing with the\n\t\t\t\t composer directly below it — when what it actually is is the agent\n\t\t\t\t asking one more question. Inside the scroller it arrives after the last\n\t\t\t\t message, scrolls with it, and the reader answers it the way they\n\t\t\t\t answered everything else. */\n\t\t\t\trenderAfterMessages={\n\t\t\t\t\tneedsEmail || showStarters ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t{needsEmail && <InlineEmailPrompt conversationId={emailGateConvId ?? undefined} />}\n\t\t\t\t\t\t\t{showStarters && (\n\t\t\t\t\t\t\t\t<div className=\"hw-starters\">\n\t\t\t\t\t\t\t\t\t{starters?.map((entry, index) => {\n\t\t\t\t\t\t\t\t\t\tconst question = typeof entry === \"string\" ? entry : entry.question;\n\t\t\t\t\t\t\t\t\t\tconst label = typeof entry === \"string\" ? null : entry.label;\n\t\t\t\t\t\t\t\t\t\t/* The label leads and the question explains it. Side by side\n\t\t\t\t\t\t\t\t they fought for the same line: labels are short words in\n\t\t\t\t\t\t\t\t some configs (\"Pricing\") and half-sentences in others\n\t\t\t\t\t\t\t\t (\"Pick a framework\"), and a fixed-width column had to be\n\t\t\t\t\t\t\t\t wrong for one of them. Stacked, both lengths read the same.\n\t\t\t\t\t\t\t\t With no label the question IS the line, so it moves up. */\n\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\tkey={question}\n\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"hw-starter\"\n\t\t\t\t\t\t\t\t\t\t\t\tstyle={{ animationDelay: `${90 + index * 70}ms` }}\n\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\tvoid submit({ text: question });\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"hw-starter-text\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"hw-starter-k\">{label ?? question}</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{label && <span className=\"hw-starter-q\">{question}</span>}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t<ChevronRightIcon size={14} />\n\t\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : undefined\n\t\t\t\t}\n\t\t\t/>\n\t\t\t{/* Resolved → show the CSAT banner ABOVE the composer, never INSTEAD\n\t\t\t of it. Keeping the composer mounted means a follow-up just\n\t\t\t works: the server reopens the thread (widget.sendMessage →\n\t\t\t status: open) so resolved is never a dead-end. */}\n\t\t\t{isResolved && <ResolvedBanner conversationId={conversationId} />}\n\t\t\t{sendError && (\n\t\t\t\t<div className=\"hw-send-error\">\n\t\t\t\t\t{sendError}\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"hw-send-error-retry\"\n\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\tclearSendError();\n\t\t\t\t\t\t\tsubmit();\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(\"widget.retry\")}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<Composer\n\t\t\t\ttext={text}\n\t\t\t\tonTextChange={setText}\n\t\t\t\tonSubmit={submit}\n\t\t\t\tonTyping={setTyping}\n\t\t\t\tisSubmitting={isSubmitting}\n\t\t\t\tattachments={attachments}\n\t\t\t\tonAddFiles={addFiles}\n\t\t\t\tonRemoveAttachment={removeAttachment}\n\t\t\t\tdisabled={needsEmail}\n\t\t\t/>\n\t\t</>\n\t);\n}\n\n// ── Resolved Banner with CSAT ───────────────────────────\n\nfunction ResolvedBanner({ conversationId }: { conversationId: string }) {\n\tconst { client } = useWidgetContext();\n\tconst [csatRating, setCsatRating] = useState<\"good\" | \"bad\" | null>(null);\n\tconst [csatSubmitted, setCsatSubmitted] = useState(false);\n\n\tconst handleCsat = (rating: \"good\" | \"bad\") => {\n\t\tsetCsatRating(rating);\n\t\tsetCsatSubmitted(true);\n\t\t// Send CSAT via API (fire and forget)\n\t\tclient.widget.sendCsat.mutate({ conversationId, rating }).catch(() => {});\n\t};\n\n\treturn (\n\t\t<div className=\"hw-resolved\">\n\t\t\t<div className=\"hw-resolved-text\">{t(\"widget.resolved_text\")}</div>\n\t\t\t{!csatSubmitted ? (\n\t\t\t\t<div className=\"hw-csat\">\n\t\t\t\t\t<div className=\"hw-csat-label\">{t(\"widget.csat_label\")}</div>\n\t\t\t\t\t<div className=\"hw-csat-buttons\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName={`hw-csat-btn ${csatRating === \"good\" ? \"hw-csat-btn--selected\" : \"\"}`}\n\t\t\t\t\t\t\tonClick={() => handleCsat(\"good\")}\n\t\t\t\t\t\t\taria-label={t(\"widget.aria_good\")}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t👍\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName={`hw-csat-btn ${csatRating === \"bad\" ? \"hw-csat-btn--selected\" : \"\"}`}\n\t\t\t\t\t\t\tonClick={() => handleCsat(\"bad\")}\n\t\t\t\t\t\t\taria-label={t(\"widget.aria_bad\")}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t👎\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t) : (\n\t\t\t\t<div className=\"hw-csat-thanks\">{t(\"widget.csat_thanks\")}</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// ── Message Preview Bubble ─────────────────────\n// MessagePreview moved to ./message-preview.tsx so `hideLauncher`\n// integrations can render the same proactive bubble next to their own\n// trigger. DefaultWidget composes it with the launcher placement +\n// <WidgetLogo /> avatar above.\n\n// ── Announcement Preview Bubble ─────────────────\n// AnnouncementPreviews + AnnouncementPreviewItem (and the stripMarkdown\n// helper) moved to ./announcement-previews.tsx + ./strip-markdown.ts so\n// `hideLauncher` integrations can render the same proactive cards next\n// to their own trigger. DefaultWidget composes the export above with\n// the launcher placement + <WidgetLogo /> avatar.\n\n// ── What's New Card (Home tab) ──────────────────\n\nfunction WhatsNewCard({\n\tgetUnseenEntries,\n\tannouncementTabs,\n\tonViewAll,\n\tonSelect,\n}: {\n\tgetUnseenEntries: () => UnseenAnnouncementEntry[];\n\tannouncementTabs: WidgetContentTab[];\n\tonViewAll: () => void;\n\tonSelect: (slug: string, tabId: string) => void;\n}) {\n\tconst unseen = getUnseenEntries();\n\tif (unseen.length === 0) return null;\n\n\tconst display = unseen.slice(0, 3);\n\tconst badgeFieldMap = new Map(announcementTabs.map((t) => [t.id, t.display?.badgeField]));\n\n\treturn (\n\t\t<div className=\"hw-whats-new\">\n\t\t\t<div className=\"hw-whats-new-header\">\n\t\t\t\t<span className=\"hw-whats-new-title\">{resolveLabel(\"widget.whats_new\")}</span>\n\t\t\t\t<button type=\"button\" className=\"hw-whats-new-view-all\" onClick={onViewAll}>\n\t\t\t\t\t{resolveLabel(\"widget.view_all\")} →\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<div className=\"hw-whats-new-list\">\n\t\t\t\t{display.map((entry) => {\n\t\t\t\t\tconst badgeField = badgeFieldMap.get(entry.tabId);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tkey={entry.slug}\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"hw-whats-new-item\"\n\t\t\t\t\t\t\tonClick={() => onSelect(entry.slug, entry.tabId)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{badgeField && entry.customFields[badgeField] && (\n\t\t\t\t\t\t\t\t<div className=\"hw-whats-new-item-top\">\n\t\t\t\t\t\t\t\t\t<span className=\"hw-whats-new-badge\">{entry.customFields[badgeField]}</span>\n\t\t\t\t\t\t\t\t\t{entry.publishedAt && (\n\t\t\t\t\t\t\t\t\t\t<span className=\"hw-whats-new-time\">\n\t\t\t\t\t\t\t\t\t\t\t{formatRelativeTime(entry.publishedAt)}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t<div className=\"hw-whats-new-item-title\">\n\t\t\t\t\t\t\t\t{entry.title}\n\t\t\t\t\t\t\t\t{!badgeField && entry.publishedAt && (\n\t\t\t\t\t\t\t\t\t<span className=\"hw-whats-new-time-inline\">\n\t\t\t\t\t\t\t\t\t\t{formatRelativeTime(entry.publishedAt)}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{entry.body &&\n\t\t\t\t\t\t\t\t(() => {\n\t\t\t\t\t\t\t\t\tconst clean = stripMarkdown(entry.body);\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<div className=\"hw-whats-new-item-body\">\n\t\t\t\t\t\t\t\t\t\t\t{clean.length > 80 ? `${clean.slice(0, 80)}…` : clean}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t})()}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","import { CONTENT_CACHE_TTL, getLocale } from \"@helpway/widget-core\";\nimport type { WidgetContentTab } from \"@helpway/widget-core\";\nimport { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\ninterface AnnouncementEntry {\n\tslug: string;\n\ttitle: string;\n\tbody: string | null;\n\tpublishedAt: string | null;\n\tcustomFields: Record<string, string | null>;\n}\n\nexport interface UnseenAnnouncementEntry extends AnnouncementEntry {\n\ttabId: string;\n}\n\n// ── Per-entry localStorage tracking ──\n\nfunction storageKey(websiteId: string, visitorId: string): string {\n\treturn `helpway:${websiteId}:${visitorId}:announcements:seen`;\n}\n\nfunction hasSeenKey(websiteId: string, visitorId: string): boolean {\n\ttry {\n\t\treturn localStorage.getItem(storageKey(websiteId, visitorId)) !== null;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction getSeenSlugs(websiteId: string, visitorId: string): Set<string> {\n\ttry {\n\t\tconst raw = localStorage.getItem(storageKey(websiteId, visitorId));\n\t\tif (!raw) return new Set();\n\t\treturn new Set(JSON.parse(raw) as string[]);\n\t} catch {\n\t\treturn new Set();\n\t}\n}\n\nfunction addSeenSlug(websiteId: string, visitorId: string, slug: string): void {\n\ttry {\n\t\tconst seen = getSeenSlugs(websiteId, visitorId);\n\t\tseen.add(slug);\n\t\tlocalStorage.setItem(storageKey(websiteId, visitorId), JSON.stringify([...seen]));\n\t} catch {\n\t\t// storage full or blocked\n\t}\n}\n\nfunction addSeenSlugs(websiteId: string, visitorId: string, slugs: string[]): void {\n\ttry {\n\t\tconst seen = getSeenSlugs(websiteId, visitorId);\n\t\tfor (const s of slugs) seen.add(s);\n\t\tlocalStorage.setItem(storageKey(websiteId, visitorId), JSON.stringify([...seen]));\n\t} catch {\n\t\t// storage full or blocked\n\t}\n}\n\nfunction filterUnseen(entries: AnnouncementEntry[], seen: Set<string>): AnnouncementEntry[] {\n\treturn entries.filter((e) => !seen.has(e.slug));\n}\n\nconst EMPTY_TABS: WidgetContentTab[] = [];\n\n/**\n * Per-entry announcement tracking across all tabs with isAnnouncements.\n *\n * Anonymous visitors (no contact) skip first-visit seeding — they always\n * see announcement previews. Identified visitors seed on first visit so\n * existing entries don't flood as unread.\n *\n * Multiple announcement tabs supported: previews stack, unseen count\n * aggregates, and each entry carries its tabId for correct navigation.\n */\nexport function useAnnouncements() {\n\tconst { client, store } = useWidgetContext();\n\tconst isReady = useWidgetStore((s) => s.isReady);\n\tconst websiteId = useWidgetStore((s) => s.website?.id) ?? null;\n\tconst visitorId = useWidgetStore((s) => s.visitor?.id) ?? null;\n\tconst isAnonymous = useWidgetStore((s) => !s.visitor?.contact);\n\tconst contentTabs = useWidgetStore((s) => s.agentConfig?.contentTabs) ?? EMPTY_TABS;\n\tconst announcementTabs = useMemo(\n\t\t() => contentTabs.filter((t) => t.isAnnouncements),\n\t\t[contentTabs],\n\t);\n\tconst checkedRef = useRef(false);\n\n\tuseEffect(() => {\n\t\tif (!isReady || !websiteId || !visitorId || announcementTabs.length === 0) return;\n\t\tif (checkedRef.current) return;\n\t\tcheckedRef.current = true;\n\n\t\tconst isFirstVisit = !hasSeenKey(websiteId, visitorId);\n\t\tlet pending = announcementTabs.length;\n\t\tlet totalUnseen = 0;\n\t\tconst allSlugs: string[] = [];\n\n\t\tfunction onTabDone(entries: AnnouncementEntry[], tab: WidgetContentTab) {\n\t\t\tallSlugs.push(...entries.map((e) => e.slug));\n\n\t\t\t// Identified user's first visit: defer unseen computation until\n\t\t\t// all tabs are collected so we can seed everything at once.\n\t\t\tif (!(isFirstVisit && !isAnonymous) && entries.length > 0) {\n\t\t\t\tconst seen = getSeenSlugs(websiteId!, visitorId!);\n\t\t\t\tconst unseen = filterUnseen(entries, seen);\n\t\t\t\ttotalUnseen += unseen.length;\n\n\t\t\t\tconst newest = unseen[0];\n\t\t\t\tif (newest && !store.getState().isOpen) {\n\t\t\t\t\tconst badgeField = tab.display?.badgeField;\n\t\t\t\t\tstore.getState().setAnnouncementPreview({\n\t\t\t\t\t\ttitle: newest.title,\n\t\t\t\t\t\tbody: newest.body,\n\t\t\t\t\t\tslug: newest.slug,\n\t\t\t\t\t\ttabId: tab.id,\n\t\t\t\t\t\tbadge: badgeField ? (newest.customFields[badgeField] ?? null) : null,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpending--;\n\t\t\tif (pending === 0) {\n\t\t\t\tif (isFirstVisit && !isAnonymous) {\n\t\t\t\t\t// Seed all entries across all tabs at once\n\t\t\t\t\tif (allSlugs.length > 0) {\n\t\t\t\t\t\taddSeenSlugs(websiteId!, visitorId!, allSlugs);\n\t\t\t\t\t}\n\t\t\t\t\tstore.getState().setUnseenAnnouncementCount(0);\n\t\t\t\t} else {\n\t\t\t\t\tstore.getState().setUnseenAnnouncementCount(totalUnseen);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const tab of announcementTabs) {\n\t\t\tconst cacheKey = `announcements:${tab.id}:${getLocale()}`;\n\t\t\tconst cached = store.getState().contentCache.get(cacheKey);\n\t\t\tif (cached && Date.now() - cached.ts < CONTENT_CACHE_TTL) {\n\t\t\t\tonTabDone(cached.data as AnnouncementEntry[], tab);\n\t\t\t} else {\n\t\t\t\tclient.widget.getContent\n\t\t\t\t\t.query({ tabId: tab.id, page: 1, limit: 5, language: getLocale() })\n\t\t\t\t\t.then((result: { items?: AnnouncementEntry[] }) => {\n\t\t\t\t\t\tconst entries = result.items ?? [];\n\t\t\t\t\t\tstore.getState().setContentCache(cacheKey, entries);\n\t\t\t\t\t\tonTabDone(entries, tab);\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tonTabDone([], tab);\n\t\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}, [isReady, websiteId, visitorId, isAnonymous, announcementTabs, client, store]);\n\n\tconst markEntrySeen = useCallback(\n\t\t(slug: string) => {\n\t\t\tif (!websiteId || !visitorId || announcementTabs.length === 0) return;\n\t\t\taddSeenSlug(websiteId, visitorId, slug);\n\n\t\t\t// Recompute total unseen count across all tabs\n\t\t\tconst seen = getSeenSlugs(websiteId, visitorId);\n\t\t\tlet total = 0;\n\t\t\tfor (const tab of announcementTabs) {\n\t\t\t\tconst cacheKey = `announcements:${tab.id}:${getLocale()}`;\n\t\t\t\tconst cached = store.getState().contentCache.get(cacheKey);\n\t\t\t\tif (cached) {\n\t\t\t\t\ttotal += filterUnseen(cached.data as AnnouncementEntry[], seen).length;\n\t\t\t\t}\n\t\t\t}\n\t\t\tstore.getState().setUnseenAnnouncementCount(total);\n\t\t\tstore.getState().dismissAnnouncementPreview(slug);\n\t\t},\n\t\t[websiteId, visitorId, announcementTabs, store],\n\t);\n\n\tconst markAllSeen = useCallback(() => {\n\t\tif (!websiteId || !visitorId || announcementTabs.length === 0) return;\n\t\tfor (const tab of announcementTabs) {\n\t\t\tconst cacheKey = `announcements:${tab.id}:${getLocale()}`;\n\t\t\tconst cached = store.getState().contentCache.get(cacheKey);\n\t\t\tif (cached) {\n\t\t\t\tconst entries = cached.data as AnnouncementEntry[];\n\t\t\t\taddSeenSlugs(websiteId, visitorId, entries.map((e) => e.slug));\n\t\t\t}\n\t\t}\n\t\tstore.getState().setUnseenAnnouncementCount(0);\n\t\tstore.getState().dismissAnnouncementPreview();\n\t}, [websiteId, visitorId, announcementTabs, store]);\n\n\tconst getUnseenEntries = useCallback((): UnseenAnnouncementEntry[] => {\n\t\tif (announcementTabs.length === 0 || !websiteId || !visitorId) return [];\n\t\tconst seen = getSeenSlugs(websiteId, visitorId);\n\t\tconst result: UnseenAnnouncementEntry[] = [];\n\t\tfor (const tab of announcementTabs) {\n\t\t\tconst cacheKey = `announcements:${tab.id}:${getLocale()}`;\n\t\t\tconst cached = store.getState().contentCache.get(cacheKey);\n\t\t\tif (cached) {\n\t\t\t\tfor (const entry of filterUnseen(cached.data as AnnouncementEntry[], seen)) {\n\t\t\t\t\tresult.push({ ...entry, tabId: tab.id });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}, [announcementTabs, websiteId, visitorId, store]);\n\n\treturn {\n\t\tannouncementTabs,\n\t\tmarkEntrySeen,\n\t\tmarkAllSeen,\n\t\tgetUnseenEntries,\n\t};\n}\n","\"use client\";\n\nimport { awaitingReplyCount } from \"@helpway/widget-core\";\nimport { useWidgetStore } from \"../provider\";\n\n/**\n * How many conversations are waiting on the visitor to reply.\n *\n * Exists because `useUnread()` answers a question consumers usually do not have.\n * A thread we answered two minutes ago and a thread the visitor closed\n * themselves look identical in the widget — same row, same weight, no marker —\n * and that is the moment a support thread dies: we reply, the visitor never\n * registers it, the conversation is abandoned with an unanswered message in it.\n *\n * Counts human replies, not AI ones. An auto-reply follows nearly every visitor\n * message, so including them leaves the indicator permanently lit for anyone who\n * has ever opened the widget, which teaches people to ignore it.\n *\n * Written by hand in a downstream dashboard before it existed here; a\n * `hideLauncher` integration badging its own trigger should not have to\n * reimplement the rule.\n *\n * ```tsx\n * const awaiting = useAwaitingReply();\n * // \"3 awaiting reply\" — label it, do not just show the number\n * ```\n */\nexport function useAwaitingReply(): number {\n\treturn useWidgetStore((s) => awaitingReplyCount(s.conversations));\n}\n","import type { TimelineItem } from \"@helpway/types\";\nimport { t } from \"@helpway/widget-core\";\nimport { useCallback, useState } from \"react\";\nimport { useWidgetContext } from \"../provider\";\n\n/**\n * The page the visitor is on, shaped for `sendMessage`.\n *\n * Returns nothing off the browser (SSR) or when the URL is unreadable, so the\n * field simply stays absent rather than sending an empty page the server would\n * have to defend against.\n */\nfunction currentPagePayload(): { page?: { url: string; title: string } } {\n\tif (typeof window === \"undefined\") return {};\n\tconst url = window.location.href;\n\tif (!url) return {};\n\treturn { page: { url, title: document.title || window.location.pathname } };\n}\n\nexport interface PendingAttachment {\n\tid: string;\n\tfile: File;\n\tpreviewUrl: string | null; // blob URL for images\n\tisUploading: boolean;\n\terror: string | null;\n\t/** Resolved after upload — the part to include in sendMessage */\n\tpart:\n\t\t| { type: \"image\"; url: string; mimeType: string }\n\t\t| { type: \"file\"; url: string; fileName: string; fileSize: number; mimeType: string }\n\t\t| null;\n}\n\nconst MAX_ATTACHMENTS = 10;\nconst MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB\n\n/**\n * Composer state — text input + attachments + submit for a conversation.\n */\n/**\n * What the file picker will offer. Lives with the attachment hook rather than in\n * the composer that renders the picker: the docked bar has a picker of its own,\n * and two lists of accepted types drift the moment one of them gains a format.\n */\nexport const ACCEPTED_TYPES = [\n\t\"image/png\",\n\t\"image/jpeg\",\n\t\"image/gif\",\n\t\"image/webp\",\n\t\"image/svg+xml\",\n\t\"application/pdf\",\n\t\"text/plain\",\n\t\"text/csv\",\n\t\"application/zip\",\n\t\"application/msword\",\n\t\"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n\t\"application/vnd.ms-excel\",\n\t\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n].join(\",\");\n\nexport function useComposer(boundConversationId: string | null) {\n\tconst { client, ws, store, getSourceLocale } = useWidgetContext();\n\t// Alias so every callback below keeps reading `conversationId` while\n\t// `submit` is free to shadow it with a caller-supplied id (see there).\n\tconst conversationId = boundConversationId;\n\tconst [text, setText] = useState(\"\");\n\tconst [isSubmitting, setIsSubmitting] = useState(false);\n\tconst [attachments, setAttachments] = useState<PendingAttachment[]>([]);\n\tconst [sendError, setSendError] = useState<string | null>(null);\n\tconst [emailGateConvId, setEmailGateConvId] = useState<string | null>(null);\n\n\tconst addFiles = useCallback(\n\t\tasync (files: File[]) => {\n\t\t\tif (!conversationId) return;\n\n\t\t\tconst remaining = MAX_ATTACHMENTS - attachments.length;\n\t\t\tconst toAdd = files.slice(0, remaining);\n\t\t\tif (toAdd.length === 0) return;\n\n\t\t\t// Create pending entries\n\t\t\tconst pending: PendingAttachment[] = toAdd.map((file) => ({\n\t\t\t\tid: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n\t\t\t\tfile,\n\t\t\t\tpreviewUrl: file.type.startsWith(\"image/\") ? URL.createObjectURL(file) : null,\n\t\t\t\tisUploading: true,\n\t\t\t\terror: null,\n\t\t\t\tpart: null,\n\t\t\t}));\n\n\t\t\tsetAttachments((prev) => [...prev, ...pending]);\n\n\t\t\t// Upload each file\n\t\t\tfor (const item of pending) {\n\t\t\t\ttry {\n\t\t\t\t\tif (item.file.size > MAX_FILE_SIZE) {\n\t\t\t\t\t\tthrow new Error(t(\"widget.file_too_large\"));\n\t\t\t\t\t}\n\n\t\t\t\t\t// Read file as base64\n\t\t\t\t\tconst base64 = await fileToBase64(item.file);\n\n\t\t\t\t\t// For temp conversations (before first send) skip the\n\t\t\t\t\t// conversationId — server scopes the R2 key to the visitor\n\t\t\t\t\t// and the file is attached to the timeline item by\n\t\t\t\t\t// createConversation when submit fires.\n\t\t\t\t\tconst convIdForUpload = conversationId.startsWith(\"temp-\") ? undefined : conversationId;\n\t\t\t\t\tconst result = await client.widget.uploadAttachment.mutate({\n\t\t\t\t\t\t...(convIdForUpload ? { conversationId: convIdForUpload } : {}),\n\t\t\t\t\t\tbase64,\n\t\t\t\t\t\tmimeType: item.file.type || \"application/octet-stream\",\n\t\t\t\t\t\tfileName: item.file.name,\n\t\t\t\t\t});\n\n\t\t\t\t\tsetAttachments((prev) =>\n\t\t\t\t\t\tprev.map((a) =>\n\t\t\t\t\t\t\ta.id === item.id ? { ...a, isUploading: false, part: result.part } : a,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Upload failed\";\n\t\t\t\t\tsetAttachments((prev) =>\n\t\t\t\t\t\tprev.map((a) => (a.id === item.id ? { ...a, isUploading: false, error: message } : a)),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[conversationId, attachments.length, client],\n\t);\n\n\tconst removeAttachment = useCallback((id: string) => {\n\t\tsetAttachments((prev) => {\n\t\t\tconst item = prev.find((a) => a.id === id);\n\t\t\tif (item?.previewUrl) URL.revokeObjectURL(item.previewUrl);\n\t\t\treturn prev.filter((a) => a.id !== id);\n\t\t});\n\t}, []);\n\n\t/**\n\t * `override` exists because the caller sometimes knows the text and the\n\t * conversation before this closure does: a suggestion pill sends a question\n\t * the composer state has never held, and the docked shell creates the\n\t * conversation in the same click that sends its first message. Passing both\n\t * in replaces the old setText → wait-a-tick → submit dance, which dropped\n\t * the message whenever the re-render didn't land before the timer.\n\t */\n\tconst submit = useCallback(\n\t\tasync (override?: { text?: string; conversationId?: string }) => {\n\t\t\tconst conversationId = override?.conversationId ?? boundConversationId;\n\t\t\tconst source = override?.text ?? text;\n\t\t\tconst trimmed = source.trim();\n\t\t\tconst readyParts = attachments.filter((a) => a.part !== null).map((a) => a.part!);\n\t\t\tconst hasText = trimmed.length > 0;\n\t\t\tconst hasAttachments = readyParts.length > 0;\n\n\t\t\tif (!conversationId || isSubmitting) return;\n\n\t\t\t// Policy 2026-04-19: every outgoing message must have a text body.\n\t\t\t// An attachment on its own renders as an empty bubble in the\n\t\t\t// dashboard and leaves the AI with no caption to reason about.\n\t\t\t// Surface a soft inline error instead of silently no-op'ing so\n\t\t\t// the visitor understands *why* the send didn't go through.\n\t\t\tif (!hasText) {\n\t\t\t\tif (hasAttachments) {\n\t\t\t\t\tsetSendError(t(\"widget.caption_required\"));\n\t\t\t\t\tsetTimeout(() => setSendError(null), 4000);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Don't send while uploads are in progress\n\t\t\tconst stillUploading = attachments.some((a) => a.isUploading);\n\t\t\tif (stillUploading) return;\n\n\t\t\t// ── OPTIMISTIC: message appears in the widget INSTANTLY ──\n\t\t\t// The user sees their message the moment they hit send; the mutation\n\t\t\t// runs in the background. On success we swap the optimistic placeholder\n\t\t\t// for the server-confirmed item (preserving scroll + bubble position).\n\t\t\t// On failure we remove the placeholder and restore the composer text.\n\t\t\tconst optimisticId = `optimistic-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n\t\t\tconst now = new Date().toISOString();\n\t\t\tconst currentVisitorId = store.getState().visitor?.id ?? null;\n\t\t\tconst optimisticItem: TimelineItem = {\n\t\t\t\tid: optimisticId,\n\t\t\t\tconversationId,\n\t\t\t\torganizationId: \"\",\n\t\t\t\ttype: \"message\",\n\t\t\t\tvisibility: \"public\",\n\t\t\t\ttext: hasText ? trimmed : null,\n\t\t\t\tparts:\n\t\t\t\t\thasText || hasAttachments\n\t\t\t\t\t\t? ([\n\t\t\t\t\t\t\t\t...(hasText ? [{ type: \"text\" as const, text: trimmed }] : []),\n\t\t\t\t\t\t\t\t...readyParts,\n\t\t\t\t\t\t\t] as TimelineItem[\"parts\"])\n\t\t\t\t\t\t: null,\n\t\t\t\tuserId: null,\n\t\t\t\tvisitorId: currentVisitorId,\n\t\t\t\taiAgentId: null,\n\t\t\t\tcreatedAt: now,\n\t\t\t\teditedAt: null,\n\t\t\t\tdeletedAt: null,\n\t\t\t};\n\n\t\t\t// Flush UI immediately\n\t\t\tconst attachmentsSnapshot = attachments;\n\t\t\tconst textSnapshot = source;\n\t\t\tstore.getState().addMessage(conversationId, optimisticItem);\n\t\t\t/* Show that something is coming NOW, not when the server gets around to\n\t\t\t saying so. The thinking dots used to wait for aiProcessingProgress, which\n\t\t\t the pipeline emits only after the queue picks the job up — so the visitor\n\t\t\t pressed send and watched an empty panel for as long as that took. The\n\t\t\t visitor's own message is proof enough that a reply is on its way.\n\n\t\t\t This comment used to claim that \"every path that ends the reply already\n\t\t\t clears this\", and list them. It was wrong, and the way it was wrong is\n\t\t\t the lesson: the server had six exits that cleared nothing — four guards\n\t\t\t in runAiPipeline, two in the queue consumer — and an enumerated list in\n\t\t\t a comment cannot notice when a seventh is added. An invariant that is\n\t\t\t documented rather than enforced decays silently, and the only place it\n\t\t\t showed was a visitor's screen.\n\n\t\t\t `setAiProcessing` now arms its own ceiling (see AI_INDICATOR_MAX_MS in\n\t\t\t widget-core/store.ts), so raising it here cannot outlive the answer no\n\t\t\t matter what the server does or fails to do. */\n\t\t\tstore.getState().setAiProcessing(conversationId, true);\n\t\t\tsetText(\"\");\n\t\t\tsetAttachments([]);\n\t\t\tws.sendTyping(conversationId, false);\n\t\t\tsetIsSubmitting(true);\n\t\t\ttry {\n\t\t\t\t// Temp conversation IDs (seeded by openNewConversation) don't exist on\n\t\t\t\t// the server yet. On the first send we have to call createConversation\n\t\t\t\t// instead — the API allocates the real ID and returns the visitor item.\n\t\t\t\t// The welcome item from the response is DROPPED because the widget is\n\t\t\t\t// already showing a seed welcome bubble; keeping the same bubble\n\t\t\t\t// instance across this transition is what prevents the \"git-gel\" flash.\n\t\t\t\tconst isTempConversation = conversationId.startsWith(\"temp-\");\n\t\t\t\t// Ephemeral proactive conversation — only exists in the widget\n\t\t\t\t// store, server hasn't seen it yet. First reply triggers\n\t\t\t\t// materialization (creates conversation + writes greeting +\n\t\t\t\t// visitor message in one go).\n\t\t\t\tconst isEphemeralConversation = conversationId.startsWith(\"eph-\");\n\t\t\t\tif (isEphemeralConversation) {\n\t\t\t\t\tconst workflowId = conversationId.slice(\"eph-\".length);\n\t\t\t\t\tconst result = await client.widget.materializeFromProactive.mutate({\n\t\t\t\t\t\tworkflowId,\n\t\t\t\t\t\t...(hasText ? { text: trimmed } : {}),\n\t\t\t\t\t});\n\t\t\t\t\t// Pull the real conversation onto the synthetic id so all the\n\t\t\t\t\t// in-flight optimistic state (visitor bubble, scroll position,\n\t\t\t\t\t// active id) carries over without a flash.\n\t\t\t\t\tstore.getState().remapConversationId(conversationId, result.conversationId);\n\t\t\t\t\t// Hydrate canonical timeline from server — replaces synthetic\n\t\t\t\t\t// greeting ids with real ULIDs and surfaces the persisted\n\t\t\t\t\t// visitor message. We keep the optimistic placeholder in the\n\t\t\t\t\t// store so the visitor sees their bubble immediately; the\n\t\t\t\t\t// canonical setMessages dedupes by id, but our optimistic id\n\t\t\t\t\t// won't collide so it'll be shadowed cleanly.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst timeline = await client.widget.getTimeline.query({\n\t\t\t\t\t\t\tconversationId: result.conversationId,\n\t\t\t\t\t\t\tlimit: 50,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (timeline?.items) {\n\t\t\t\t\t\t\tstore.getState().setMessages(result.conversationId, timeline.items as TimelineItem[]);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Best-effort: optimistic state is still on screen, next\n\t\t\t\t\t\t// WS event or refresh will hydrate.\n\t\t\t\t\t}\n\t\t\t\t} else if (isTempConversation) {\n\t\t\t\t\tconst sourceLocale = getSourceLocale();\n\t\t\t\t\tconst result = await client.widget.createConversation.mutate({\n\t\t\t\t\t\t...(hasText ? { text: trimmed } : {}),\n\t\t\t\t\t\t...(hasAttachments ? { parts: readyParts } : {}),\n\t\t\t\t\t\t/* The first message is the one that most needs this — someone\n\t\t\t\t\t\t lands on a page and immediately asks what it is. */\n\t\t\t\t\t\t...currentPagePayload(),\n\t\t\t\t\t\t...(sourceLocale ? { sourceLocale } : {}),\n\t\t\t\t\t});\n\t\t\t\t\tconst conv = result.conversation;\n\t\t\t\t\t// Move the temp conversation's messages (seed welcome + optimistic\n\t\t\t\t\t// visitor) onto the server-assigned id. remapConversationId merges\n\t\t\t\t\t// with any existing items under the real id (WS races are fine).\n\t\t\t\t\tstore.getState().remapConversationId(conversationId, conv.id);\n\t\t\t\t\tif (result.item) {\n\t\t\t\t\t\tstore.getState().replaceMessage(conv.id, optimisticId, result.item as TimelineItem);\n\t\t\t\t\t}\n\t\t\t\t\tif (result.requireEmail) {\n\t\t\t\t\t\tsetEmailGateConvId(conv.id);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst result = await client.widget.sendMessage.mutate({\n\t\t\t\t\t\tconversationId,\n\t\t\t\t\t\t...(hasText ? { text: trimmed } : {}),\n\t\t\t\t\t\t...(hasAttachments ? { parts: readyParts } : {}),\n\t\t\t\t\t\t/* Carry the page with the question. The provider reports it on\n\t\t\t\t\t\t bootstrap too, but that call is fire-and-forget — a visitor who\n\t\t\t\t\t\t lands and immediately asks \"what is this page about\" beat it,\n\t\t\t\t\t\t and the agent answered with no idea where they were. */\n\t\t\t\t\t\t...currentPagePayload(),\n\t\t\t\t\t});\n\n\t\t\t\t\t// Replace optimistic placeholder with server-confirmed item.\n\t\t\t\t\t// If the WS echo already landed with the real id, replaceMessage\n\t\t\t\t\t// just drops the placeholder (race-safe, see store implementation).\n\t\t\t\t\tstore\n\t\t\t\t\t\t.getState()\n\t\t\t\t\t\t.replaceMessage(conversationId, optimisticId, result.item as TimelineItem);\n\t\t\t\t}\n\n\t\t\t\t// Clean up blob URLs for uploaded attachments\n\t\t\t\tfor (const a of attachmentsSnapshot) {\n\t\t\t\t\tif (a.previewUrl) URL.revokeObjectURL(a.previewUrl);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useComposer] Send failed:\", err);\n\t\t\t\t// Roll back: remove placeholder, restore text + attachments so user can retry\n\t\t\t\tstore.getState().removeMessage(conversationId, optimisticId);\n\t\t\t\t// Nothing is coming — take the dots back down with the message.\n\t\t\t\tstore.getState().setAiProcessing(conversationId, false);\n\t\t\t\tsetText(textSnapshot);\n\t\t\t\tsetAttachments(attachmentsSnapshot);\n\t\t\t\tsetSendError(err instanceof Error ? err.message : t(\"widget.send_error\"));\n\t\t\t\t// Auto-clear after 5 seconds\n\t\t\t\tsetTimeout(() => setSendError(null), 5000);\n\t\t\t} finally {\n\t\t\t\tsetIsSubmitting(false);\n\t\t\t}\n\t\t},\n\t\t[text, attachments, boundConversationId, isSubmitting, client, ws, store, getSourceLocale],\n\t);\n\n\tconst clearSendError = useCallback(() => setSendError(null), []);\n\n\treturn {\n\t\ttext,\n\t\tsetText,\n\t\tsubmit,\n\t\tisSubmitting,\n\t\tattachments,\n\t\taddFiles,\n\t\tremoveAttachment,\n\t\tsendError,\n\t\tclearSendError,\n\t\temailGateConvId,\n\t};\n}\n\n// ── Helpers ─────────────────────────────────────\n\nfunction fileToBase64(file: File): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst reader = new FileReader();\n\t\treader.onload = () => {\n\t\t\t// result is \"data:<mime>;base64,<data>\" — strip the prefix\n\t\t\tconst result = reader.result as string;\n\t\t\tconst base64 = result.split(\",\")[1];\n\t\t\tif (!base64) return reject(new Error(\"Failed to encode file\"));\n\t\t\tresolve(base64);\n\t\t};\n\t\treader.onerror = () => reject(new Error(\"Failed to read file\"));\n\t\treader.readAsDataURL(file);\n\t});\n}\n","import type { TimelineItem } from \"@helpway/types\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\n/**\n * Conversation list + create new conversation.\n */\nexport function useConversations() {\n\tconst { client, store, getSourceLocale } = useWidgetContext();\n\tconst conversations = useWidgetStore((s) => s.conversations);\n\tconst setActiveConversation = useWidgetStore((s) => s.setActiveConversation);\n\tconst [isCreating, setIsCreating] = useState(false);\n\n\tconst clientRef = useRef(client);\n\tconst storeRef = useRef(store);\n\tconst getSourceLocaleRef = useRef(getSourceLocale);\n\n\t// Synced after commit, never during render. Every read of these refs\n\t// happens inside an effect or an async callback, all of which run after\n\t// this one, so the value is always current by the time it is used.\n\tuseEffect(() => {\n\t\tclientRef.current = client;\n\t\tstoreRef.current = store;\n\t\tgetSourceLocaleRef.current = getSourceLocale;\n\t});\n\n\tconst create = useCallback(async (text: string) => {\n\t\tsetIsCreating(true);\n\n\t\t// OPTIMISTIC: show the visitor's message + open the conversation view\n\t\t// BEFORE the server roundtrip completes. The conversation gets a temp\n\t\t// id (`temp-<random>`) that's remapped to the server id on success.\n\t\t// Welcome message + any AI reply flow in via the same path the API\n\t\t// returns them — either by replacing the temp conv or via WS.\n\t\tconst tempConversationId = `temp-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n\t\tconst now = new Date().toISOString();\n\t\tconst optimisticMessageId = `optimistic-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n\t\tconst currentVisitorId = storeRef.current.getState().visitor?.id ?? null;\n\n\t\tconst optimisticMsg: TimelineItem = {\n\t\t\tid: optimisticMessageId,\n\t\t\tconversationId: tempConversationId,\n\t\t\torganizationId: \"\",\n\t\t\ttype: \"message\",\n\t\t\tvisibility: \"public\",\n\t\t\ttext,\n\t\t\tparts: null,\n\t\t\tuserId: null,\n\t\t\tvisitorId: currentVisitorId,\n\t\t\taiAgentId: null,\n\t\t\tcreatedAt: now,\n\t\t\teditedAt: null,\n\t\t\tdeletedAt: null,\n\t\t};\n\n\t\t// Flush UI immediately: fake conversation + message + switch view\n\t\tconst store = storeRef.current.getState();\n\t\tstore.addConversation({\n\t\t\tid: tempConversationId,\n\t\t\ttitle: null,\n\t\t\tstatus: \"open\",\n\t\t\tlastMessageText: text,\n\t\t\tlastMessageAt: now,\n\t\t\tlastMessageSenderType: \"visitor\",\n\t\t\tlastMessageSenderName: null,\n\t\t\tlastMessageSenderImage: null,\n\t\t\tassigneeName: null,\n\t\t\tassigneeImage: null,\n\t\t\tunreadCount: 0,\n\t\t});\n\t\tstore.setMessages(tempConversationId, [optimisticMsg]);\n\t\tstore.setActiveConversation(tempConversationId);\n\n\t\ttry {\n\t\t\tconst sourceLocale = getSourceLocaleRef.current();\n\t\t\tconst result = await clientRef.current.widget.createConversation.mutate({\n\t\t\t\ttext,\n\t\t\t\t...(sourceLocale ? { sourceLocale } : {}),\n\t\t\t});\n\t\t\tconst conv = result.conversation;\n\n\t\t\t// Remap temp ID → real ID (rewrites conversations list + messages map + active ref).\n\t\t\t// The optimistic message's id becomes stale (conversationId changed) — replaceMessage\n\t\t\t// with the server-confirmed item.\n\t\t\tstoreRef.current.getState().remapConversationId(tempConversationId, conv.id);\n\t\t\tif (result.item) {\n\t\t\t\tstoreRef.current\n\t\t\t\t\t.getState()\n\t\t\t\t\t.replaceMessage(conv.id, optimisticMessageId, result.item as TimelineItem);\n\t\t\t}\n\t\t\t// Insert welcome message if the agent sent one.\n\t\t\t// The welcome is ALWAYS the very first item in a new conversation, so\n\t\t\t// we place it at index 0 deterministically — never trust createdAt sort,\n\t\t\t// because client-clock (optimistic visitor) vs server-clock (welcome)\n\t\t\t// can be off by enough to re-order the pair. Dedup by id so a WS echo\n\t\t\t// doesn't double-insert.\n\t\t\tif (result.welcomeItem) {\n\t\t\t\tconst welcome = result.welcomeItem as TimelineItem;\n\t\t\t\tconst existing = storeRef.current.getState().messages.get(conv.id) ?? [];\n\t\t\t\tconst withoutWelcome = existing.filter((m) => m.id !== welcome.id);\n\t\t\t\tstoreRef.current.getState().setMessages(conv.id, [welcome, ...withoutWelcome]);\n\t\t\t}\n\t\t\treturn conv;\n\t\t} catch (err) {\n\t\t\t// Roll back: remove the fake conversation + message; let the caller surface the error\n\t\t\tstoreRef.current.getState().removeMessage(tempConversationId, optimisticMessageId);\n\t\t\tconst convs = storeRef.current\n\t\t\t\t.getState()\n\t\t\t\t.conversations.filter((c) => c.id !== tempConversationId);\n\t\t\tstoreRef.current.setState({ conversations: convs, activeConversationId: null });\n\t\t\tthrow err;\n\t\t} finally {\n\t\t\tsetIsCreating(false);\n\t\t}\n\t}, []);\n\n\treturn { conversations, create, isCreating, setActiveConversation };\n}\n","import type { ConversationSummary } from \"@helpway/widget-core\";\nimport { useWidgetStore } from \"../provider\";\n\n/**\n * Who a conversation belongs to, human-side — name and photo decided together.\n *\n * Resolution order:\n * 1. the assigned support user — sticky once a human takes over, even before\n * they have typed anything\n * 2. the last team-side sender — a teammate jumped in without a formal\n * assignment. A bare `lastMessageSenderName` will not do on its own: it is\n * also set for visitor messages, hence the sender-type guard.\n * 3. neither — nobody human is on this thread\n *\n * Pure and per-conversation, because two surfaces need the same answer about\n * different conversations: the header asks about the open one, the conversation\n * list asks about every row. They used to answer it differently — the list only\n * ever looked at who sent the last message — so a thread assigned to a teammate\n * showed that person in the header and the AI's name in the list, because the\n * last message was the visitor's own. Same question, one answer.\n */\nexport function conversationIdentity(conv: ConversationSummary | null | undefined): {\n\thumanName: string | null;\n\thumanImage: string | null;\n} {\n\tconst teamSender =\n\t\tconv?.lastMessageSenderType === \"team\" && conv?.lastMessageSenderName ? conv : null;\n\treturn {\n\t\thumanName: conv?.assigneeName ?? teamSender?.lastMessageSenderName ?? null,\n\t\thumanImage: conv?.assigneeImage ?? teamSender?.lastMessageSenderImage ?? null,\n\t};\n}\n\n/**\n * Who the chat header is currently naming, and with which photo.\n *\n * This existed twice: once in `default-widget.tsx` (the chain the header\n * actually renders) and once in `message-list.tsx` (the chain the per-bubble\n * name label compared itself against, to avoid repeating a name the header\n * already shows). The two chains had drifted — the list's copy was missing the\n * `lastMessageSenderName` step — so every one of a teammate's messages printed\n * his name above the bubble AND under it, three times over, next to his name in\n * the header. A suppression rule that reads a different value than the thing it\n * is suppressing against cannot work, so the value now has one home.\n */\nexport function useHeaderIdentity() {\n\tconst activeConvSummary = useWidgetStore((s) => {\n\t\tconst id = s.activeConversationId;\n\t\treturn id ? s.conversations.find((c) => c.id === id) : null;\n\t});\n\tconst agentConfigName = useWidgetStore((s) => s.agentConfig?.name);\n\tconst websiteName = useWidgetStore((s) => s.website?.name);\n\n\tconst { humanName, humanImage } = conversationIdentity(activeConvSummary);\n\tconst companyName = agentConfigName ?? websiteName ?? \"Support\";\n\n\treturn {\n\t\thumanName,\n\t\thumanImage,\n\t\thasTeamAgent: !!humanName,\n\t\t/** Fallback identity when no human is on the thread — also how the AI signs its answers. */\n\t\tcompanyName,\n\t\t/** Exactly what the header prints. Compare per-bubble name labels against this. */\n\t\theaderName: humanName ?? companyName,\n\t};\n}\n","import { useEffect, useState } from \"react\";\nimport { onLocaleChange, getI18nRevision } from \"@helpway/widget-core\";\n\n/**\n * React hook that triggers re-render when widget translations load or locale changes.\n * Place this in the top-level widget component so all children get fresh t() values.\n *\n * Returns the current i18n revision number (for debugging).\n */\nexport function useI18n(): number {\n\tconst [rev, setRev] = useState(() => getI18nRevision());\n\n\tuseEffect(() => {\n\t\t// Subscribe to locale/translation changes\n\t\treturn onLocaleChange(() => {\n\t\t\tsetRev(getI18nRevision());\n\t\t});\n\t}, []);\n\n\treturn rev;\n}\n","import { useCallback, useRef } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\n/**\n * Typing presence — show \"is typing\" + send own typing status.\n *\n * Debounced: only sends WS event when typing state *changes*.\n * While typing, auto-stops after 3 seconds of inactivity.\n *\n * Usage:\n * ```tsx\n * const { isTyping, setTyping } = usePresence(conversationId)\n * ```\n */\nexport function usePresence(conversationId: string | null) {\n\tconst { ws } = useWidgetContext();\n\tconst isTyping = useWidgetStore((s) =>\n\t\tconversationId ? (s.typingUsers.get(conversationId) ?? false) : false,\n\t);\n\tconst isAiProcessing = useWidgetStore((s) =>\n\t\tconversationId ? (s.aiProcessing.get(conversationId) ?? false) : false,\n\t);\n\tconst typingTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\tconst isSendingTyping = useRef(false);\n\n\tconst setTyping = useCallback(\n\t\t(typing: boolean) => {\n\t\t\tif (!conversationId) return;\n\n\t\t\t// Clear any pending auto-stop\n\t\t\tif (typingTimer.current) clearTimeout(typingTimer.current);\n\n\t\t\tif (typing) {\n\t\t\t\t// Only send \"typing: true\" if we haven't already\n\t\t\t\tif (!isSendingTyping.current) {\n\t\t\t\t\tisSendingTyping.current = true;\n\t\t\t\t\tws.sendTyping(conversationId, true);\n\t\t\t\t}\n\t\t\t\t// Auto-stop after 3 seconds of inactivity\n\t\t\t\ttypingTimer.current = setTimeout(() => {\n\t\t\t\t\tisSendingTyping.current = false;\n\t\t\t\t\tws.sendTyping(conversationId, false);\n\t\t\t\t}, 3000);\n\t\t\t} else {\n\t\t\t\t// Immediately send stop\n\t\t\t\tif (isSendingTyping.current) {\n\t\t\t\t\tisSendingTyping.current = false;\n\t\t\t\t\tws.sendTyping(conversationId, false);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[conversationId, ws],\n\t);\n\n\treturn { isTyping, isAiProcessing, setTyping };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\nimport type { TimelineItem } from \"@helpway/types\";\n\nconst EMPTY_ITEMS: TimelineItem[] = [];\n\n/**\n * Timeline items for a conversation + real-time updates.\n */\nexport function useTimeline(conversationId: string | null) {\n\tconst { client, store } = useWidgetContext();\n\tconst messages = useWidgetStore((s) =>\n\t\tconversationId ? s.messages.get(conversationId) ?? EMPTY_ITEMS : EMPTY_ITEMS,\n\t);\n\tconst [isLoading, setIsLoading] = useState(false);\n\tconst [hasMore, setHasMore] = useState(false);\n\tconst cursorRef = useRef<string | undefined>(undefined);\n\n\t// Stable refs to avoid effect re-triggers\n\tconst clientRef = useRef(client);\n\tconst storeRef = useRef(store);\n\n\t// Synced after commit, never during render. Every read of these refs\n\t// happens inside an effect or an async callback, all of which run after\n\t// this one, so the value is always current by the time it is used.\n\tuseEffect(() => {\n\t\tclientRef.current = client;\n\t\tstoreRef.current = store;\n\t});\n\n\t// Load initial timeline when conversation changes\n\tuseEffect(() => {\n\t\tif (!conversationId) return;\n\n\t\t// Skip server fetch for optimistic temp IDs — they don't exist server-side.\n\t\t// useConversations.create() owns the seed for these; once remap fires this\n\t\t// effect re-runs with the real id and the fetch happens then.\n\t\tif (conversationId.startsWith(\"temp-\")) return;\n\n\t\tlet cancelled = false;\n\n\t\t// If createConversation already seeded the messages store (welcome + first\n\t\t// visitor message), the server has nothing new to tell us — skip the fetch.\n\t\t// Overwriting the seed with the server payload causes a full array-identity\n\t\t// flip, a brief key-swap for the optimistic→server id transition, and\n\t\t// restarts CSS enter animations — the \"mesajlar gidip tekrar geliyor\" flash.\n\t\t// New items still flow in via WS.addMessage, which dedupes by id.\n\t\tconst existingMessages = storeRef.current.getState().messages.get(conversationId);\n\t\tconst hasSeed = !!existingMessages && existingMessages.length > 0;\n\t\tif (hasSeed) {\n\t\t\tstoreRef.current.getState().clearUnread(conversationId);\n\t\t\tclientRef.current.widget.markSeen\n\t\t\t\t.mutate({ conversationId })\n\t\t\t\t.catch(() => {});\n\t\t\treturn () => {\n\t\t\t\tcancelled = true;\n\t\t\t};\n\t\t}\n\n\t\tsetIsLoading(true);\n\t\tasync function load() {\n\t\t\ttry {\n\t\t\t\tconst data = await clientRef.current.widget.getTimeline.query({\n\t\t\t\t\tconversationId: conversationId!,\n\t\t\t\t\tlimit: 50,\n\t\t\t\t});\n\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\t// Only overwrite if API returned items — don't wipe seed messages with empty response\n\t\t\t\tif (data.items.length > 0) {\n\t\t\t\t\tstoreRef.current.getState().setMessages(conversationId!, data.items as TimelineItem[]);\n\t\t\t\t}\n\t\t\t\tsetHasMore(data.hasMore);\n\t\t\t\tcursorRef.current = data.nextCursor ?? undefined;\n\n\t\t\t\t// Mark as seen + clear local unread count\n\t\t\t\tstoreRef.current.getState().clearUnread(conversationId!);\n\t\t\t\tclientRef.current.widget.markSeen.mutate({ conversationId: conversationId! }).catch(() => {});\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useTimeline] Failed to load:\", err);\n\t\t\t} finally {\n\t\t\t\tif (!cancelled) setIsLoading(false);\n\t\t\t}\n\t\t}\n\n\t\tload();\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, [conversationId]); // Only re-run when conversationId changes\n\n\tconst loadMore = useCallback(async () => {\n\t\tif (!conversationId || !hasMore || isLoading) return;\n\n\t\tsetIsLoading(true);\n\t\ttry {\n\t\t\tconst data = await clientRef.current.widget.getTimeline.query({\n\t\t\t\tconversationId,\n\t\t\t\tcursor: cursorRef.current,\n\t\t\t\tlimit: 50,\n\t\t\t});\n\n\t\t\tconst existing = storeRef.current.getState().messages.get(conversationId) ?? [];\n\t\t\tstoreRef.current.getState().setMessages(conversationId, [...data.items as TimelineItem[], ...existing]);\n\t\t\tsetHasMore(data.hasMore);\n\t\t\tcursorRef.current = data.nextCursor ?? undefined;\n\t\t} finally {\n\t\t\tsetIsLoading(false);\n\t\t}\n\t}, [conversationId, hasMore, isLoading]);\n\n\treturn { items: messages, isLoading, hasMore, loadMore };\n}\n","import { useWidgetStore } from \"../provider\";\n\n/**\n * Total unread count across all conversations.\n *\n * Usage:\n * ```tsx\n * const { totalUnread } = useUnread()\n * ```\n */\nexport function useUnread() {\n\tconst totalUnread = useWidgetStore((s) =>\n\t\ts.conversations.reduce((sum, c) => sum + c.unreadCount, 0),\n\t);\n\n\treturn { totalUnread };\n}\n","import { useWidgetContext, useWidgetStore } from \"../provider\";\n\n/**\n * Core widget state — connection status, visitor identity, website info.\n *\n * Usage:\n * ```tsx\n * const { isReady, visitor, website, identify } = useWidget()\n * ```\n */\nexport function useWidget() {\n\tconst { client } = useWidgetContext();\n\tconst isReady = useWidgetStore((s) => s.isReady);\n\tconst isConnecting = useWidgetStore((s) => s.isConnecting);\n\tconst visitor = useWidgetStore((s) => s.visitor);\n\tconst website = useWidgetStore((s) => s.website);\n\tconst agentConfig = useWidgetStore((s) => s.agentConfig);\n\n\tasync function identify(data: {\n\t\texternalId: string;\n\t\temail?: string;\n\t\tname?: string;\n\t\timage?: string;\n\t\tmetadata?: Record<string, unknown>;\n\t\t/**\n\t\t * Move this browser's visitor to the contact above even if it already\n\t\t * belongs to a different contact. Dangerous: it merges whatever history\n\t\t * this browser has into that contact. Off by default; without it the\n\t\t * server keeps the existing link and returns that contact (#193).\n\t\t */\n\t\treassign?: boolean;\n\t}) {\n\t\treturn client.widget.identify.mutate(data);\n\t}\n\n\treturn { isReady, isConnecting, visitor, website, agentConfig, identify };\n}\n","import { t } from \"@helpway/widget-core\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport type { DockSuggestion } from \"@helpway/widget-core\";\n\nimport { ACCEPTED_TYPES, type PendingAttachment } from \"../hooks/use-composer\";\nimport { PreviewThumb } from \"../themed/composer\";\nimport { ArrowUpIcon, PaperclipIcon } from \"../themed/icons\";\n\n/**\n * The composer bar for `placement=\"docked\"`.\n *\n * Unlike the bubble shell, the bar is persistent chrome and it IS the\n * composer — the conversation panel above it renders without one. That\n * is why this lives in `shell/` rather than inside the conversation:\n * moving the widget must never change the conversation UI.\n *\n * It shares the panel's measure so bar and panel read as one column, and\n * it grows with its content instead of scrolling a one-line field.\n */\nexport interface DockedBarProps {\n\tvalue: string;\n\tonChange: (next: string) => void;\n\tonSubmit: () => void;\n\tdisabled?: boolean;\n\t/**\n\t * Ways in offered before the visitor has typed anything. Rendered as\n\t * pills floating above the bar, over the page — there is no panel to\n\t * put them in yet, and a panel would read as demanding attention\n\t * where pills read as offering.\n\t */\n\tsuggestions?: readonly DockSuggestion[];\n\tonSuggestion?: (question: string) => void;\n\tplaceholder?: string;\n\t/**\n\t * Attachment plumbing, same three pieces the bubble composer gets from\n\t * `useComposer`. The docked bar IS the composer, so leaving these out\n\t * meant the docked shell was the one place a visitor could not send a\n\t * screenshot — the single most common thing a support thread needs.\n\t */\n\tattachments?: PendingAttachment[];\n\tonAddFiles?: (files: File[]) => void;\n\tonRemoveAttachment?: (id: string) => void;\n\t/**\n\t * Reaching for the bar again after folding the panel away. The thread is still\n\t * there — the visitor closed a panel, not a conversation — so touching the\n\t * composer brings it back where they left it. Only wired to a pointer press:\n\t * on `focus` it would also fire for someone tabbing through the page, and a\n\t * panel that appears over the article you are reading because you pressed Tab\n\t * is worse than one that never reappears.\n\t */\n\tonReopen?: () => void;\n\t/**\n\t * Why a send did not happen. The composer refuses an attachment with no caption\n\t * on purpose and sets this instead of failing silently — but in the docked shell\n\t * there was nothing rendering it, so the refusal WAS silent: the file sat in the\n\t * bar, the button did nothing, and no reason was ever given.\n\t */\n\tsendError?: string | null;\n\tonClearSendError?: () => void;\n}\n\n/**\n * The pills float over the host page, so on a content-heavy page they sit on top of\n * whatever is behind them — a code block, a table row. Offering them is right; being\n * unable to put them away is not.\n *\n * One control clears the whole offer rather than one × per pill. The pills are a single\n * gesture from the agent (\"here are ways in\"), so declining them is a single gesture\n * back; asking the visitor to refuse three times to see the page under them is the\n * problem restated, not solved.\n *\n * The dismissal is keyed by the offer's own questions, not a bare boolean: local state,\n * so it returns on the next page load, but if the host swaps in a different set of\n * suggestions that IS a new offer and gets shown.\n */\nfunction useDismissableOffer(suggestions: readonly DockSuggestion[] | undefined) {\n\tconst [dismissedKey, setDismissedKey] = useState<string | null>(null);\n\tconst questions = (suggestions ?? []).map((entry) =>\n\t\ttypeof entry === \"string\" ? entry : entry.question,\n\t);\n\tconst key = questions.join(\"|\");\n\treturn {\n\t\tquestions: dismissedKey === key ? [] : questions,\n\t\tdismiss: () => setDismissedKey(key),\n\t};\n}\n\n/* ── Dictation ─────────────────────────────────────────────────────────────\n The reference composer we are matching offers a mic beside the clip, and on\n a docked bar — often the only input on a docs page — speaking a question is\n faster than typing it. Wired to the platform's own recognizer rather than an\n upload-and-transcribe round trip: no audio leaves the page, and there is no\n server cost to a visitor who trails off mid-sentence.\n\n Typed against a minimal surface instead of `any`: we touch six members, and\n the vendor-prefixed constructor is still the only one Safari exposes. The\n button renders only where the constructor exists, so it is never a control\n that looks live and does nothing. */\ninterface SpeechAlternative {\n\ttranscript: string;\n}\ninterface SpeechResult {\n\treadonly length: number;\n\tisFinal: boolean;\n\t[index: number]: SpeechAlternative;\n}\ninterface SpeechResultList {\n\treadonly length: number;\n\t[index: number]: SpeechResult;\n}\ninterface SpeechEvent {\n\tresultIndex: number;\n\tresults: SpeechResultList;\n}\ninterface Recognition {\n\tlang: string;\n\tcontinuous: boolean;\n\tinterimResults: boolean;\n\tstart(): void;\n\tstop(): void;\n\tonresult: ((event: SpeechEvent) => void) | null;\n\tonend: (() => void) | null;\n\tonerror: (() => void) | null;\n}\ntype RecognitionCtor = new () => Recognition;\n\nfunction recognitionCtor(): RecognitionCtor | null {\n\tif (typeof window === \"undefined\") return null;\n\tconst scope = window as unknown as {\n\t\tSpeechRecognition?: RecognitionCtor;\n\t\twebkitSpeechRecognition?: RecognitionCtor;\n\t};\n\treturn scope.SpeechRecognition ?? scope.webkitSpeechRecognition ?? null;\n}\n\n/**\n * Dictation as an append, not a replace: the visitor may have typed half a\n * sentence before reaching for the mic, and eating it would be worse than not\n * offering the mic at all. Interim results are ignored — a field that rewrites\n * itself while you speak is unreadable — so only settled phrases land.\n */\nfunction useDictation(onText: (chunk: string) => void) {\n\tconst [listening, setListening] = useState(false);\n\tconst recRef = useRef<Recognition | null>(null);\n\t/* The recognizer outlives the render that started it, so the callback is read\n\t through a ref — synced in an effect rather than assigned during render, which\n\t would be a write to shared state in the render phase. */\n\tconst onTextRef = useRef(onText);\n\tuseEffect(() => {\n\t\tonTextRef.current = onText;\n\t}, [onText]);\n\n\t// Support is a property of the browser, so it is resolved once rather than\n\t// on every render, and it decides whether the button exists at all.\n\tconst [supported] = useState(() => recognitionCtor() !== null);\n\n\t// A recognizer left running after unmount keeps the mic indicator lit in the\n\t// tab strip long after the widget is gone.\n\tuseEffect(\n\t\t() => () => {\n\t\t\trecRef.current?.stop();\n\t\t\trecRef.current = null;\n\t\t},\n\t\t[],\n\t);\n\n\tconst toggle = useCallback(() => {\n\t\tif (recRef.current) {\n\t\t\trecRef.current.stop();\n\t\t\treturn;\n\t\t}\n\t\tconst Ctor = recognitionCtor();\n\t\tif (!Ctor) return;\n\t\tconst rec = new Ctor();\n\t\trec.lang = typeof document !== \"undefined\" ? document.documentElement.lang || \"en\" : \"en\";\n\t\trec.continuous = false;\n\t\trec.interimResults = false;\n\t\trec.onresult = (event) => {\n\t\t\tfor (let i = event.resultIndex; i < event.results.length; i++) {\n\t\t\t\tconst result = event.results[i];\n\t\t\t\tif (!result?.isFinal) continue;\n\t\t\t\tconst said = result[0]?.transcript?.trim();\n\t\t\t\tif (said) onTextRef.current(said);\n\t\t\t}\n\t\t};\n\t\tconst finish = () => {\n\t\t\trecRef.current = null;\n\t\t\tsetListening(false);\n\t\t};\n\t\trec.onend = finish;\n\t\trec.onerror = finish;\n\t\trecRef.current = rec;\n\t\tsetListening(true);\n\t\trec.start();\n\t}, []);\n\n\t/* Stopping has to be callable from outside the button, because the button is not\n\t the only thing that ends a dictation — see the blur handler. */\n\tconst stop = useCallback(() => {\n\t\trecRef.current?.stop();\n\t}, []);\n\n\treturn { supported, listening, toggle, stop };\n}\n\n/** Matches --hw-bar-max-height in styles.css. */\nconst MAX_HEIGHT = 148;\n/** Above this the field is no longer one line, so the pill squares off. */\nconst GROWN_AT = 40;\n\n/** Paste and drop both hand us a DataTransfer; only files are interesting. */\nfunction filesFrom(data: DataTransfer | null): File[] {\n\tif (!data?.files) return [];\n\tconst out: File[] = [];\n\tfor (let i = 0; i < data.files.length; i++) {\n\t\tconst file = data.files[i];\n\t\tif (file) out.push(file);\n\t}\n\treturn out;\n}\n\nexport function DockedBar({\n\tvalue,\n\tonChange,\n\tonSubmit,\n\tdisabled = false,\n\tsuggestions,\n\tonSuggestion,\n\tplaceholder,\n\tattachments,\n\tonAddFiles,\n\tonRemoveAttachment,\n\tonReopen,\n\tsendError,\n\tonClearSendError,\n}: DockedBarProps) {\n\tconst [focused, setFocused] = useState(false);\n\tconst inputRef = useRef<HTMLTextAreaElement>(null);\n\tconst boxRef = useRef<HTMLDivElement>(null);\n\tconst fileInputRef = useRef<HTMLInputElement>(null);\n\tconst { questions: visibleQuestions, dismiss: dismissOffer } = useDismissableOffer(suggestions);\n\n\t/* Dictation writes into the same field as the keyboard, appended with a space\n\t so two dictated phrases don't fuse into one word. */\n\tconst dictation = useDictation((chunk) => {\n\t\tconst current = inputRef.current?.value ?? value;\n\t\tonChange(current ? `${current.replace(/\\s+$/, \"\")} ${chunk}` : chunk);\n\t\tinputRef.current?.focus();\n\t});\n\n\t// Height is derived from content on every change rather than held in\n\t// state — a render pass per keystroke to store a number the DOM\n\t// already knows is wasted work.\n\tconst grow = useCallback(() => {\n\t\tconst el = inputRef.current;\n\t\tconst box = boxRef.current;\n\t\tif (!el || !box) return;\n\t\tel.style.height = \"auto\";\n\t\tconst next = Math.min(MAX_HEIGHT, el.scrollHeight);\n\t\tel.style.height = `${next}px`;\n\t\tbox.dataset.grown = next > GROWN_AT ? \"true\" : \"false\";\n\t}, []);\n\n\t// Re-measure when the value is cleared from outside (submit, reset).\n\tuseEffect(grow, [grow, value]);\n\n\tconst handleKeyDown = useCallback(\n\t\t(event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n\t\t\tif (event.key !== \"Enter\" || event.shiftKey) return;\n\t\t\tevent.preventDefault();\n\t\t\tif (!value.trim() || disabled) return;\n\t\t\tonSubmit();\n\t\t},\n\t\t[value, disabled, onSubmit],\n\t);\n\n\t/* A screenshot pasted straight into the field is how most support threads start,\n\t so paste is handled here and not only behind the clip. */\n\tconst handlePaste = useCallback(\n\t\t(event: React.ClipboardEvent<HTMLTextAreaElement>) => {\n\t\t\tif (!onAddFiles) return;\n\t\t\tconst files = filesFrom(event.clipboardData);\n\t\t\tif (!files.length) return;\n\t\t\tevent.preventDefault();\n\t\t\tonAddFiles(files);\n\t\t},\n\t\t[onAddFiles],\n\t);\n\n\t/* Shown when the composer has the visitor's attention, not on arrival.\n\t Three pills stacked above the bar take roughly 240px of viewport, and they float\n\t over the page — so on every content page they landed on whatever was behind them:\n\t a card, a callout's body text, the one code line an install section exists to\n\t show. The visitor had asked for none of it. Offering ways in is right; doing it\n\t over the thing they came to read is not. Focus anywhere in the dock is the signal\n\t that they are looking at it rather than at the article. */\n\tconst showSuggestions = focused && !!visibleQuestions.length && !value.trim();\n\n\t/* Focus tracked on the whole dock rather than the textarea, so clicking a pill —\n\t which moves focus out of the field — does not unmount the pill under the pointer\n\t before the click lands. `relatedTarget` outside the dock is a real exit. */\n\tconst onDockBlur = (event: React.FocusEvent<HTMLDivElement>) => {\n\t\tconst next = event.relatedTarget as Node | null;\n\t\tif (next && event.currentTarget.contains(next)) return;\n\t\tsetFocused(false);\n\t\t/* And stop listening. The unmount cleanup was the wrong hook for this: the bar\n\t\t is persistent chrome, so folding the panel away — or clicking back into the\n\t\t article — never unmounts it, and a recognizer started here kept the browser's\n\t\t mic indicator lit long after the visitor thought they had closed the chat.\n\t\t Focus is the honest signal: dictation belongs to the composer being used. */\n\t\tdictation.stop();\n\t};\n\n\t/* Same rule as the bubble composer: an attachment that is still uploading is not\n\t sendable yet, and text alone or a settled attachment both are. */\n\tconst uploading = attachments?.some((a) => a.isUploading) ?? false;\n\tconst hasAttachment = attachments?.some((a) => a.part !== null) ?? false;\n\tconst canSend = (!!value.trim() || hasAttachment) && !uploading && !disabled;\n\n\treturn (\n\t\t<div className=\"hw-dock\" onFocus={() => setFocused(true)} onBlur={onDockBlur}>\n\t\t\t{showSuggestions && (\n\t\t\t\t<div className=\"hw-dock-suggestions\">\n\t\t\t\t\t{visibleQuestions.map((question, index) => (\n\t\t\t\t\t\t/* The pill stays a button and the dismiss is a sibling, not a nested\n\t\t\t\t\t\t button — a button inside a button is invalid and the inner click\n\t\t\t\t\t\t would still fire the outer one. Only the first row carries the ×,\n\t\t\t\t\t\t since it closes the whole offer. */\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tkey={question}\n\t\t\t\t\t\t\tclassName=\"hw-dock-pill-row\"\n\t\t\t\t\t\t\tstyle={{ animationDelay: `${120 + index * 90}ms` }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"hw-dock-pill\"\n\t\t\t\t\t\t\t\tonClick={() => onSuggestion?.(question)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{question}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t{index === 0 && (\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"hw-dock-pill-dismiss\"\n\t\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_dismiss\")}\n\t\t\t\t\t\t\t\t\tonClick={dismissOffer}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\t\tstrokeWidth=\"2.5\"\n\t\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<path d=\"M18 6 6 18M6 6l12 12\" />\n\t\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{sendError && (\n\t\t\t\t<div className=\"hw-dock-error\" role=\"alert\">\n\t\t\t\t\t{sendError}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\tclassName=\"hw-dock-bar\"\n\t\t\t\tref={boxRef}\n\t\t\t\tdata-grown=\"false\"\n\t\t\t\tonMouseDown={onReopen}\n\t\t\t\tonTouchStart={onReopen}\n\t\t\t>\n\t\t\t\t{/* Above the field rather than beside it: a thumbnail in the row would\n\t\t\t\t shove the caption into a sliver on the one bar width we control. */}\n\t\t\t\t{!!attachments?.length && (\n\t\t\t\t\t<div className=\"hw-dock-previews\">\n\t\t\t\t\t\t{attachments.map((a) => (\n\t\t\t\t\t\t\t<PreviewThumb\n\t\t\t\t\t\t\t\tkey={a.id}\n\t\t\t\t\t\t\t\tattachment={a}\n\t\t\t\t\t\t\t\tonRemove={onRemoveAttachment ? () => onRemoveAttachment(a.id) : undefined}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t{/* Never disabled while a send is in flight. The browser blurs a\n\t\t\t\t disabled element, so locking the field for the ~200ms round trip\n\t\t\t\t threw the caret out of it — the visitor pressed Enter and lost\n\t\t\t\t the field they were typing in. `canSend` and the Enter handler\n\t\t\t\t already refuse a second submit, which is the part that actually\n\t\t\t\t needed guarding. */}\n\t\t\t\t<textarea\n\t\t\t\t\tref={inputRef}\n\t\t\t\t\tclassName=\"hw-dock-input\"\n\t\t\t\t\trows={1}\n\t\t\t\t\tvalue={value}\n\t\t\t\t\tplaceholder={placeholder ?? t(\"widget.placeholder_new\")}\n\t\t\t\t\taria-label={t(\"widget.placeholder_new\")}\n\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\tonChange(event.target.value);\n\t\t\t\t\t\tif (sendError) onClearSendError?.();\n\t\t\t\t\t\tgrow();\n\t\t\t\t\t}}\n\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\tonPaste={handlePaste}\n\t\t\t\t/>\n\t\t\t\t<div className=\"hw-dock-actions\">\n\t\t\t\t\t{dictation.supported && (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"hw-dock-tool\"\n\t\t\t\t\t\t\tdata-active={dictation.listening ? \"true\" : undefined}\n\t\t\t\t\t\t\taria-label={t(\"widget.aria_dictate\")}\n\t\t\t\t\t\t\taria-pressed={dictation.listening}\n\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t\tonClick={dictation.toggle}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<MicGlyph />\n\t\t\t\t\t\t</button>\n\t\t\t\t\t)}\n\t\t\t\t\t{onAddFiles && (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"hw-dock-tool\"\n\t\t\t\t\t\t\t\taria-label={t(\"widget.aria_attach\")}\n\t\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t\t\tonClick={() => fileInputRef.current?.click()}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<PaperclipIcon size={17} />\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\tref={fileInputRef}\n\t\t\t\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t\t\t\taccept={ACCEPTED_TYPES}\n\t\t\t\t\t\t\t\tmultiple\n\t\t\t\t\t\t\t\thidden\n\t\t\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\t\t\tif (!event.target.files) return;\n\t\t\t\t\t\t\t\t\tonAddFiles(Array.from(event.target.files));\n\t\t\t\t\t\t\t\t\t// Reset so picking the same file twice still fires a change.\n\t\t\t\t\t\t\t\t\tevent.target.value = \"\";\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</>\n\t\t\t\t\t)}\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"hw-dock-send\"\n\t\t\t\t\t\taria-label={t(\"widget.aria_send\")}\n\t\t\t\t\t\tdisabled={!canSend}\n\t\t\t\t\t\tonClick={onSubmit}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ArrowUpIcon size={16} />\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n/** Local glyph — the shipped icon snapshot has no mic, and one path is cheaper\n than another entry in the generated set. */\nfunction MicGlyph() {\n\treturn (\n\t\t<svg\n\t\t\twidth=\"17\"\n\t\t\theight=\"17\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<path d=\"M12 3.5a3 3 0 0 1 3 3v4.5a3 3 0 0 1-6 0V6.5a3 3 0 0 1 3-3Z\" />\n\t\t\t<path d=\"M5.5 11v.5a6.5 6.5 0 0 0 13 0V11\" />\n\t\t\t<path d=\"M12 18v3\" />\n\t\t</svg>\n\t);\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport { t } from \"@helpway/widget-core\";\nimport { ACCEPTED_TYPES, type PendingAttachment } from \"../hooks/use-composer\";\nimport { SendIcon, PaperclipIcon, XIcon } from \"./icons\";\n\nconst MAX_CHARS = 5000;\nconst CHAR_WARN_THRESHOLD = 4800;\n\n\ninterface ComposerProps {\n\ttext: string;\n\tonTextChange: (text: string) => void;\n\tonSubmit: () => void;\n\tonTyping?: (isTyping: boolean) => void;\n\tisSubmitting?: boolean;\n\tplaceholder?: string;\n\t/** Compact mode — single-line input without footer row */\n\tcompact?: boolean;\n\t/** Pending attachments to preview */\n\tattachments?: PendingAttachment[];\n\t/** Called when files are added (paste, drop, or file picker) */\n\tonAddFiles?: (files: File[]) => void;\n\t/** Called to remove a pending attachment */\n\tonRemoveAttachment?: (id: string) => void;\n\t/** Disable entire composer (e.g. email required before sending) */\n\tdisabled?: boolean;\n}\n\n/** Widget composer — auto-resize, Enter-to-send, paste/drop attachments */\nexport function Composer({\n\ttext,\n\tonTextChange,\n\tonSubmit,\n\tonTyping,\n\tisSubmitting,\n\tplaceholder,\n\tcompact,\n\tattachments,\n\tonAddFiles,\n\tonRemoveAttachment,\n\tdisabled,\n}: ComposerProps) {\n\tconst ref = useRef<HTMLTextAreaElement>(null);\n\tconst fileInputRef = useRef<HTMLInputElement>(null);\n\n\t// Feature-detect once per mount. CSS.supports is cheap but doing it\n\t// inside handleChange would run on every keystroke.\n\tconst supportsFieldSizing = useRef(\n\t\ttypeof CSS !== \"undefined\" && CSS.supports?.(\"field-sizing\", \"content\"),\n\t);\n\n\tconst handleKeyDown = useCallback(\n\t\t(e: React.KeyboardEvent) => {\n\t\t\tif (e.key === \"Enter\" && !e.shiftKey) {\n\t\t\t\te.preventDefault();\n\t\t\t\tonSubmit();\n\t\t\t}\n\t\t},\n\t\t[onSubmit],\n\t);\n\n\tconst handleChange = useCallback(\n\t\t(e: React.ChangeEvent<HTMLTextAreaElement>) => {\n\t\t\tconst value = e.target.value;\n\t\t\tif (value.length > MAX_CHARS) return; // Hard cap\n\t\t\tonTextChange(value);\n\t\t\tonTyping?.(value.length > 0);\n\n\t\t\t// Auto-resize fallback for engines without `field-sizing: content`\n\t\t\t// (Safari <17.4, Firefox <132, Chrome <123). Modern browsers handle\n\t\t\t// the resize in CSS — running this on every keystroke would force\n\t\t\t// a redundant reflow and briefly snap the textarea to min-height\n\t\t\t// before the new height is applied. Kept in sync with the 220px\n\t\t\t// max-height on .hw-composer-input.\n\t\t\tif (!supportsFieldSizing.current) {\n\t\t\t\tconst el = ref.current;\n\t\t\t\tif (el) {\n\t\t\t\t\tel.style.height = \"auto\";\n\t\t\t\t\tel.style.height = `${Math.min(el.scrollHeight, 220)}px`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[onTextChange, onTyping],\n\t);\n\n\t// ── Clipboard paste ──────────────────────────\n\tconst handlePaste = useCallback(\n\t\t(e: React.ClipboardEvent) => {\n\t\t\tif (!onAddFiles) return;\n\t\t\tconst files = extractFiles(e.clipboardData);\n\t\t\tif (files.length > 0) {\n\t\t\t\te.preventDefault();\n\t\t\t\tonAddFiles(files);\n\t\t\t}\n\t\t},\n\t\t[onAddFiles],\n\t);\n\n\t// ── Drag & drop ──────────────────────────────\n\tconst [isDragging, setIsDragging] = useState(false);\n\tconst dragCountRef = useRef(0);\n\n\tconst handleDragEnter = useCallback((e: React.DragEvent) => {\n\t\te.preventDefault();\n\t\tdragCountRef.current++;\n\t\tif (dragCountRef.current === 1) setIsDragging(true);\n\t}, []);\n\n\tconst handleDragLeave = useCallback((e: React.DragEvent) => {\n\t\te.preventDefault();\n\t\tdragCountRef.current--;\n\t\tif (dragCountRef.current === 0) setIsDragging(false);\n\t}, []);\n\n\tconst handleDragOver = useCallback((e: React.DragEvent) => {\n\t\te.preventDefault();\n\t\te.dataTransfer.dropEffect = \"copy\";\n\t}, []);\n\n\tconst handleDrop = useCallback(\n\t\t(e: React.DragEvent) => {\n\t\t\te.preventDefault();\n\t\t\tdragCountRef.current = 0;\n\t\t\tsetIsDragging(false);\n\t\t\tif (!onAddFiles) return;\n\t\t\tconst files = extractFiles(e.dataTransfer);\n\t\t\tif (files.length > 0) onAddFiles(files);\n\t\t},\n\t\t[onAddFiles],\n\t);\n\n\t// ── File picker ──────────────────────────────\n\tconst handleFileClick = useCallback(() => {\n\t\tfileInputRef.current?.click();\n\t}, []);\n\n\tconst handleFileChange = useCallback(\n\t\t(e: React.ChangeEvent<HTMLInputElement>) => {\n\t\t\tif (!onAddFiles || !e.target.files) return;\n\t\t\tonAddFiles(Array.from(e.target.files));\n\t\t\te.target.value = \"\"; // reset so same file can be picked again\n\t\t},\n\t\t[onAddFiles],\n\t);\n\n\tconst hasText = text.trim().length > 0;\n\tconst hasAttachments = attachments && attachments.some((a) => a.part !== null);\n\tconst stillUploading = attachments?.some((a) => a.isUploading) ?? false;\n\t// Button stays clickable whenever there's *something* to send — the\n\t// actual text-required guard lives in `useComposer.submit` and\n\t// surfaces as an inline error if the visitor tries to send an\n\t// attachment without a caption. Feels less sticky than a disabled\n\t// arrow the user can't interpret.\n\tconst canSend = (hasText || hasAttachments) && !stillUploading;\n\tconst showCharCount = text.length >= CHAR_WARN_THRESHOLD;\n\tconst isOverLimit = text.length > MAX_CHARS;\n\n\treturn (\n\t\t<div\n\t\t\tclassName={`hw-composer ${compact ? \"hw-composer--compact\" : \"\"} ${isDragging ? \"hw-composer--dragging\" : \"\"}`}\n\t\t\tonDragEnter={handleDragEnter}\n\t\t\tonDragLeave={handleDragLeave}\n\t\t\tonDragOver={handleDragOver}\n\t\t\tonDrop={handleDrop}\n\t\t>\n\t\t\t<div className=\"hw-composer-box\" style={{ position: \"relative\" }}>\n\t\t\t\t{/* Drag overlay */}\n\t\t\t\t{isDragging && (\n\t\t\t\t\t<div className=\"hw-composer-drop-overlay\">\n\t\t\t\t\t\t<span className=\"hw-composer-drop-text\">{t(\"widget.drop_files\")}</span>\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t{/* Attachment previews */}\n\t\t\t\t{attachments && attachments.length > 0 && (\n\t\t\t\t\t<div className=\"hw-composer-previews\">\n\t\t\t\t\t\t{attachments.map((a) => (\n\t\t\t\t\t\t\t<PreviewThumb\n\t\t\t\t\t\t\t\tkey={a.id}\n\t\t\t\t\t\t\t\tattachment={a}\n\t\t\t\t\t\t\t\tonRemove={onRemoveAttachment ? () => onRemoveAttachment(a.id) : undefined}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t<textarea\n\t\t\t\t\tref={ref}\n\t\t\t\t\tclassName=\"hw-composer-input\"\n\t\t\t\t\tvalue={text}\n\t\t\t\t\tonChange={handleChange}\n\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\tonPaste={handlePaste}\n\t\t\t\t\tplaceholder={placeholder ?? t(\"widget.placeholder\")}\n\t\t\t\t\trows={1}\n\t\t\t\t\tdisabled={disabled || isSubmitting}\n\t\t\t\t\taria-label={t(\"widget.aria_input\")}\n\t\t\t\t/>\n\t\t\t\t<div className=\"hw-composer-toolbar\">\n\t\t\t\t\t<div className=\"hw-composer-toolbar-left\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"hw-composer-attach\"\n\t\t\t\t\t\t\tonClick={handleFileClick}\n\t\t\t\t\t\t\tdisabled={disabled || isSubmitting}\n\t\t\t\t\t\t\taria-label={t(\"widget.aria_attach\")}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<PaperclipIcon />\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\tref={fileInputRef}\n\t\t\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t\t\taccept={ACCEPTED_TYPES}\n\t\t\t\t\t\t\tmultiple\n\t\t\t\t\t\t\thidden\n\t\t\t\t\t\t\tonChange={handleFileChange}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{showCharCount && (\n\t\t\t\t\t\t\t<span className={`hw-composer-charcount ${isOverLimit ? \"hw-composer-charcount--over\" : \"\"}`}>\n\t\t\t\t\t\t\t\t{MAX_CHARS - text.length}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName={`hw-composer-send ${canSend && !isOverLimit && !disabled ? \"hw-composer-send--active\" : \"hw-composer-send--inactive\"}`}\n\t\t\t\t\t\tonClick={() => onSubmit()}\n\t\t\t\t\t\tdisabled={disabled || !canSend || isSubmitting || isOverLimit}\n\t\t\t\t\t\taria-label={t(\"widget.aria_send\")}\n\t\t\t\t\t>\n\t\t\t\t\t\t<SendIcon />\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ── Preview thumbnail with hover ─────────────────\n\n/**\n * The thumbnail for a file staged in the composer.\n *\n * Deliberately has no hover popover. Sent attachments get one — peeking at an\n * image someone else posted is worth a 260px card. Here the visitor picked the\n * file a second ago; the card only threw a white rectangle across the page they\n * were reading, anchored to a 48px square they were about to type past.\n */\nexport function PreviewThumb({ attachment: a, onRemove }: { attachment: PendingAttachment; onRemove?: () => void }) {\n\treturn (\n\t\t<div className={`hw-composer-preview ${a.error ? \"hw-composer-preview--error\" : \"\"}`}>\n\t\t\t{a.previewUrl ? (\n\t\t\t\t<img src={a.previewUrl} alt={a.file.name} className=\"hw-composer-preview-img\" />\n\t\t\t) : (\n\t\t\t\t<div className=\"hw-composer-preview-file\">\n\t\t\t\t\t<span className=\"hw-composer-preview-ext\">\n\t\t\t\t\t\t{a.file.name.split(\".\").pop()?.toUpperCase() ?? \"FILE\"}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t{a.isUploading && <div className=\"hw-composer-preview-loader\" />}\n\t\t\t{a.error && <div className=\"hw-composer-preview-badge\" title={a.error}>!</div>}\n\t\t\t{onRemove && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"hw-composer-preview-remove\"\n\t\t\t\t\tonClick={onRemove}\n\t\t\t\t\taria-label={t(\"widget.aria_remove\")}\n\t\t\t\t>\n\t\t\t\t\t<XIcon />\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// ── Helpers ──────────────────────────────────────\n\nfunction extractFiles(data: DataTransfer): File[] {\n\tconst files: File[] = [];\n\tif (data.files) {\n\t\tfor (let i = 0; i < data.files.length; i++) {\n\t\t\tconst file = data.files[i];\n\t\t\tif (file) files.push(file);\n\t\t}\n\t}\n\treturn files;\n}\n","// AUTO-GENERATED — DO NOT EDIT.\n// Run `bun scripts/sync-icons.ts` to regenerate from\n// @central-icons-react/round-outlined-radius-2-stroke-2 (devDep, not shipped).\n//\n// To add or rename an icon: edit MANIFEST in scripts/sync-icons.ts, re-run.\n\nimport type { SVGProps } from \"react\";\n\ntype IconProps = SVGProps<SVGSVGElement> & { size?: number | string };\n\n// IconBubble2\nexport function MessageIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M5.00195 4H19.002C20.1065 4 21.002 4.89543 21.002 6V16C21.002 17.1046 20.1065 18 19.002 18H12.002L7.00195 21V18H5.00195C3.89738 18 3.00195 17.1046 3.00195 16V6C3.00195 4.89543 3.89738 4 5.00195 4Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"square\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconCrossMedium\nexport function XIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M6.5 6.5L17.5 17.5M17.5 6.5L6.5 17.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconArrowLeft\nexport function ArrowLeftIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M10 6L4 12L10 18\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t\t<path d=\"M5 12H20\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconChevronRight\nexport function ChevronRightIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M9 4L15.5858 10.5858C16.3668 11.3668 16.3668 12.6331 15.5858 13.4142L9 20\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconSparklesSoft\nexport function SparklesIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M19 13C14.0987 13.4243 11.4243 16.0987 11 21C10.5578 16.0225 7.89737 13.5547 3 13C7.97478 12.4262 10.4262 9.97478 11 5C11.5547 9.89737 14.0225 12.5578 19 13Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t\t<path d=\"M18.8864 2.34512C18.8642 2.14869 18.6981 2.0002 18.5004 2C18.3027 1.9998 18.1363 2.14794 18.1137 2.34433C18.0082 3.25861 17.7367 3.88584 17.3113 4.31127C16.8858 4.7367 16.2586 5.00822 15.3443 5.11367C15.1479 5.13632 14.9998 5.30271 15 5.5004C15.0002 5.69809 15.1487 5.86417 15.3451 5.88642C16.2439 5.98823 16.8855 6.25969 17.3217 6.68804C17.7556 7.11407 18.0322 7.74041 18.1126 8.64552C18.1305 8.84634 18.2988 9.00023 18.5004 9C18.702 8.99977 18.8701 8.84551 18.8874 8.64465C18.9645 7.75483 19.2409 7.11438 19.6776 6.67764C20.1144 6.24091 20.7548 5.96446 21.6446 5.88744C21.8455 5.87005 21.9998 5.70205 22 5.50044C22.0002 5.29883 21.8463 5.13048 21.6455 5.11264C20.7404 5.03224 20.1141 4.75557 19.688 4.3217C19.2597 3.88545 18.9882 3.24394 18.8864 2.34512Z\" fill=\"currentColor\" />\n\t\t</svg>\n\t);\n}\n\n// IconPaperPlaneTopRight\nexport function SendIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M9.61946 10.8613L20.9997 4.55422M9.04735 10.9043L4.10061 5.68812C3.49632 5.05091 3.94803 4 4.82621 4H20.2513C21.0247 4 21.5054 4.84039 21.1132 5.50702L13.1902 18.9762C12.7433 19.7358 11.6035 19.5879 11.3654 18.7393L9.28458 11.3223C9.24066 11.1658 9.15923 11.0223 9.04735 10.9043Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconPaperclip1\nexport function PaperclipIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M6 11V15C6 18.3137 8.68629 21 12 21C15.3137 21 18 18.3137 18 15V7C18 4.79086 16.2091 3 14 3C11.7909 3 10 4.79086 10 7V15C10 16.1046 10.8954 17 12 17C13.1046 17 14 16.1046 14 15V7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconArrowUp\nexport function ArrowUpIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M12 5V20\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t\t<path d=\"M6 10L12 4L18 10\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconHome\nexport function HomeIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M4 9.77313C4 9.2136 4 8.93383 4.07063 8.67517C4.1332 8.446 4.23609 8.22982 4.3745 8.03675C4.53071 7.81882 4.74784 7.6424 5.1821 7.28957L9.9821 3.38956C10.7014 2.80513 11.0611 2.51291 11.4609 2.40099C11.8135 2.30229 12.1865 2.30229 12.5391 2.40099C12.9389 2.51291 13.2986 2.80513 14.0179 3.38957L18.8179 7.28957C19.2522 7.6424 19.4693 7.81882 19.6255 8.03675C19.7639 8.22982 19.8668 8.446 19.9294 8.67517C20 8.93383 20 9.2136 20 9.77313V16.8C20 17.9201 20 18.4802 19.782 18.908C19.5903 19.2843 19.2843 19.5903 18.908 19.782C18.4802 20 17.9201 20 16.8 20H7.2C6.07989 20 5.51984 20 5.09202 19.782C4.71569 19.5903 4.40973 19.2843 4.21799 18.908C4 18.4802 4 17.9201 4 16.8V9.77313Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconBubbleDots\nexport function MessagesIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M4.00195 6.00003C4.00195 4.89546 4.89738 4.00003 6.00195 4.00002L18.0019 4C19.1065 4 20.002 4.89543 20.002 6V16.0358C20.002 17.1403 19.1065 18.0358 18.002 18.0358L15.3757 18.0358C15.1427 18.0358 14.9171 18.1171 14.7377 18.2657L11.9977 20.5358L9.29398 18.2694C9.11393 18.1185 8.8865 18.0358 8.65157 18.0358H6.00195C4.89738 18.0358 4.00195 17.1403 4.00195 16.0358V6.00003Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinejoin=\"round\" />\n\t\t\t<path d=\"M6.875 11.25C6.875 11.7332 7.26675 12.125 7.75 12.125C8.23325 12.125 8.625 11.7332 8.625 11.25C8.625 10.7668 8.23325 10.375 7.75 10.375C7.26675 10.375 6.875 10.7668 6.875 11.25ZM11.125 11.25C11.125 11.7332 11.5168 12.125 12 12.125C12.4832 12.125 12.875 11.7332 12.875 11.25C12.875 10.7668 12.4832 10.375 12 10.375C11.5168 10.375 11.125 10.7668 11.125 11.25ZM15.375 11.25C15.375 11.7332 15.7668 12.125 16.25 12.125C16.7332 12.125 17.125 11.7332 17.125 11.25C17.125 10.7668 16.7332 10.375 16.25 10.375C15.7668 10.375 15.375 10.7668 15.375 11.25Z\" fill=\"currentColor\" stroke=\"currentColor\" strokeWidth=\"0.75\" strokeLinecap=\"square\" />\n\t\t</svg>\n\t);\n}\n\n// IconMagnifyingGlass\nexport function SearchIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M11 18C14.866 18 18 14.866 18 11C18 7.13401 14.866 4 11 4C7.13401 4 4 7.13401 4 11C4 14.866 7.13401 18 11 18Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n\t\t\t<path d=\"M20 20L16.05 16.05\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconBubblePlus\nexport function NewChatIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M11.9998 8L11.9998 11M11.9998 11V14M11.9998 11H8.99976M11.9998 11H14.9998M11.9977 20.5358L14.7377 18.2657C14.9171 18.1171 15.1427 18.0358 15.3757 18.0358L18.002 18.0358C19.1065 18.0357 20.002 17.1403 20.002 16.0358V6C20.002 4.89543 19.1065 4 18.0019 4L6.00195 4.00002C4.89738 4.00002 4.00195 4.89545 4.00195 6.00002V16.0358C4.00195 17.1403 4.89738 18.0358 6.00195 18.0358H8.65157C8.8865 18.0358 9.11393 18.1185 9.29398 18.2694L11.9977 20.5358Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconAppleIntelligence\nexport function BotIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path fillRule=\"evenodd\" clipRule=\"evenodd\" d=\"M9.67904 3.29155C10.7467 1.56948 13.2537 1.56948 14.3214 3.29155L15.1308 4.59707C15.2462 4.7833 15.3634 4.9684 15.4823 5.15233C15.7005 5.1305 15.9185 5.10662 16.1363 5.08068L17.6626 4.89893C19.6747 4.65934 21.2396 6.61723 20.5571 8.52637L20.0401 9.97255C19.9664 10.1786 19.8947 10.3854 19.825 10.5927C19.9779 10.7493 20.1323 10.9045 20.2882 11.0583L21.3821 12.1371C22.8256 13.5609 22.2668 16.0039 20.3491 16.6605L18.895 17.1584C18.6876 17.2294 18.4809 17.3023 18.275 17.3772C18.2478 17.5943 18.2226 17.8117 18.1995 18.0294L18.0372 19.5565C17.823 21.572 15.5635 22.6577 13.8546 21.5695L12.5584 20.7442C12.3734 20.6264 12.1873 20.5103 12.0002 20.3961C11.8131 20.5103 11.627 20.6264 11.442 20.7442L10.1458 21.5695C8.4369 22.6577 6.17739 21.572 5.96321 19.5565L5.80094 18.0294C5.7778 17.8117 5.75263 17.5943 5.72541 17.3772C5.51949 17.3023 5.31282 17.2294 5.10542 17.1584L3.65133 16.6605C1.7336 16.0039 1.17475 13.5609 2.61829 12.1371L3.71216 11.0583C3.86807 10.9045 4.0225 10.7493 4.17541 10.5927C4.10567 10.3854 4.03395 10.1786 3.96028 9.97255L3.44329 8.52637C2.7608 6.61723 4.32567 4.65934 6.33777 4.89893L7.86408 5.08068C8.08191 5.10662 8.29993 5.1305 8.5181 5.15233C8.63698 4.9684 8.75417 4.7833 8.86963 4.59707L9.67904 3.29155ZM7.61407 6.4827L6.16966 6.31071C5.20357 6.19567 4.45578 7.13505 4.78207 8.04778L5.2716 9.41715C6.10452 8.48167 6.88648 7.5021 7.61407 6.4827ZM5.78854 10.961C7.04552 9.61105 8.19784 8.16742 9.23549 6.64268C11.076 6.78287 12.9244 6.78287 14.7649 6.64268C15.8026 8.16743 16.9549 9.61105 18.2119 10.961C17.6657 12.722 17.2545 14.522 16.9818 16.3454C15.2628 17.0169 13.5974 17.8181 12.0002 18.7422C10.403 17.8181 8.73761 17.0169 7.01863 16.3454C6.74592 14.522 6.3347 12.722 5.78854 10.961ZM4.65269 12.1275L3.61666 13.1494C2.92581 13.8308 3.19234 15.0006 4.11188 15.3154L5.48873 15.7868C5.27593 14.553 4.99684 13.3315 4.65269 12.1275ZM7.22343 17.9611L7.377 19.4062C7.47946 20.3704 8.56185 20.8926 9.38218 20.3703L10.6083 19.5895C9.51004 18.9865 8.38012 18.4429 7.22343 17.9611ZM13.3921 19.5895L14.6182 20.3703C15.4385 20.8926 16.5209 20.3704 16.6234 19.4062L16.777 17.9611C15.6203 18.4429 14.4903 18.9865 13.3921 19.5895ZM18.5117 15.7868L19.8885 15.3154C20.8081 15.0006 21.0746 13.8308 20.3837 13.1494L19.3477 12.1275C19.0035 13.3315 18.7245 14.553 18.5117 15.7868ZM18.7288 9.41715L19.2183 8.04778C19.5446 7.13505 18.7968 6.19567 17.8307 6.31071L16.3863 6.4827C17.1139 7.5021 17.8959 8.48167 18.7288 9.41715ZM13.8786 5.2756C12.6272 5.3429 11.3731 5.3429 10.1218 5.2756L10.8874 4.04072C11.3991 3.21542 12.6013 3.21542 13.113 4.04072L13.8786 5.2756Z\" fill=\"currentColor\" />\n\t\t</svg>\n\t);\n}\n\n// IconBook\nexport function BookIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M9 6C8.44772 6 8 6.44772 8 7C8 7.55228 8.44772 8 9 8V6ZM15 8C15.5523 8 16 7.55228 16 7C16 6.44772 15.5523 6 15 6V8ZM9 10C8.44772 10 8 10.4477 8 11C8 11.5523 8.44772 12 9 12V10ZM12 12C12.5523 12 13 11.5523 13 11C13 10.4477 12.5523 10 12 10V12ZM7 4H17V2H7V4ZM18 5V19H20V5H18ZM17 20H7V22H17V20ZM6 19V5H4V19H6ZM7 20C6.44771 20 6 19.5523 6 19H4C4 20.6569 5.34315 22 7 22V20ZM18 19C18 19.5523 17.5523 20 17 20V22C18.6569 22 20 20.6569 20 19H18ZM17 4C17.5523 4 18 4.44772 18 5H20C20 3.34315 18.6569 2 17 2V4ZM7 2C5.34315 2 4 3.34315 4 5H6C6 4.44772 6.44772 4 7 4V2ZM18 12V15H20V12H18ZM17 16H7V18H17V16ZM7 22H10V20H7V22ZM7 16C5.34315 16 4 17.3431 4 19H6C6 18.4477 6.44772 18 7 18V16ZM18 15C18 15.5523 17.5523 16 17 16V18C18.6569 18 20 16.6569 20 15H18ZM9 8H15V6H9V8ZM9 12H12V10H9V12Z\" fill=\"currentColor\" />\n\t\t</svg>\n\t);\n}\n\n// IconMegaphone\nexport function MegaphoneIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M17.9961 14.0001C19.6529 14.0001 20.9961 12.657 20.9961 11.0001C20.9961 9.34325 19.6529 8.0001 17.9961 8.0001M12.8254 18.0001C12.4136 19.1653 11.3023 20.0001 9.99609 20.0001C8.33924 20.0001 6.99609 18.657 6.99609 17.0001V15.5001M6.99829 6.5001V15.5001M17.9961 5.73752V16.2627C17.9961 17.617 16.6784 18.5797 15.3882 18.1681L4.38819 14.6585C3.55899 14.394 2.99609 13.6235 2.99609 12.7532V9.24704C2.99609 8.37667 3.55899 7.60622 4.38819 7.34167L15.3882 3.83215C16.6784 3.42051 17.9961 4.38325 17.9961 5.73752Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconLightBulb\nexport function LightbulbIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M10 21H14M15.6076 15C17.6404 13.7751 19 11.5463 19 9C19 5.13401 15.866 2 12 2C8.13401 2 5 5.13401 5 9C5 11.5463 6.35958 13.7751 8.39241 15M15.6076 15C15.4111 15.1184 15.2084 15.2274 15 15.3264V17C15 17.5523 14.5523 18 14 18H10C9.44772 18 9 17.5523 9 17V15.3264C8.7916 15.2274 8.58886 15.1184 8.39241 15M15.6076 15H8.39241\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconCircleQuestionmark\nexport function HelpCircleIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t\t<path d=\"M12 16V16.01\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n\t\t\t<path d=\"M12 13C12 11.3608 14 11.9319 14 10C14 8.89543 13.1046 8 12 8C11.2597 8 10.6134 8.4022 10.2676 9\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconNewspaper\nexport function NewspaperIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M16 12V6C16 4.89543 15.1046 4 14 4H5C3.89543 4 3 4.89543 3 6V17.5C3 18.8807 4.11929 20 5.5 20H18.5M16 12V17.5C16 18.8807 17.1193 20 18.5 20M16 12H19C20.1046 12 21 12.8954 21 14V17.5C21 18.8807 19.8807 20 18.5 20M7 16H12M7 8H12V12H7V8Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n// IconStar\nexport function StarIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={typeof size === \"number\" ? `${size}px` : size}\n\t\t\theight={typeof size === \"number\" ? `${size}px` : size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden={true}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path d=\"M11.5288 2.29524C11.7179 1.90159 12.2821 1.90159 12.4712 2.29524L14.9458 7.44648C15.0219 7.60491 15.1735 7.71434 15.3487 7.73728L21.0456 8.4832C21.4809 8.5402 21.6552 9.07312 21.3368 9.37342L17.1693 13.303C17.0412 13.4238 16.9832 13.6009 17.0154 13.7735L18.0616 19.3857C18.1416 19.8146 17.6852 20.144 17.2993 19.9359L12.249 17.2133C12.0937 17.1296 11.9063 17.1296 11.751 17.2133L6.70073 19.9359C6.3148 20.144 5.85841 19.8146 5.93837 19.3857L6.98459 13.7735C7.01677 13.6009 6.95885 13.4238 6.83068 13.303L2.66324 9.37342C2.34476 9.07312 2.51909 8.5402 2.95444 8.4832L8.65127 7.73728C8.82648 7.71434 8.97811 7.60491 9.05422 7.44648L11.5288 2.29524Z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n\t\t</svg>\n\t);\n}\n\n/**\n * Conversation options. Not in the Central Icons snapshot — three dots on\n * the same 24 grid, filled to match the set's solid glyphs.\n */\nexport function DotsIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={size}\n\t\t\theight={size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\taria-hidden=\"true\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<circle cx=\"5\" cy=\"12\" r=\"1.7\" fill=\"currentColor\" />\n\t\t\t<circle cx=\"12\" cy=\"12\" r=\"1.7\" fill=\"currentColor\" />\n\t\t\t<circle cx=\"19\" cy=\"12\" r=\"1.7\" fill=\"currentColor\" />\n\t\t</svg>\n\t);\n}\n\n/** A person, for the hand-off-to-a-human offer. Same 24 grid as the set. */\nexport function PersonIcon({ size = 24, ...props }: IconProps) {\n\treturn (\n\t\t<svg\n\t\t\twidth={size}\n\t\t\theight={size}\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\taria-hidden=\"true\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path\n\t\t\t\td=\"M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2\"\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t/>\n\t\t\t<circle cx=\"12\" cy=\"7\" r=\"4\" stroke=\"currentColor\" strokeWidth=\"2\" />\n\t\t</svg>\n\t);\n}\n","\"use client\";\n\nimport { splitAnnouncementStack, t, truncatePreviewBody } from \"@helpway/widget-core\";\nimport type { MouseEvent, ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport { useWidgetStore } from \"../provider\";\nimport { XIcon } from \"./icons\";\nimport { stripMarkdown } from \"./strip-markdown\";\n\n/** Placement of the announcement stack — mirrors `MessagePreviewPlacement`. */\nexport type AnnouncementPreviewsPlacement = \"launcher\" | \"anchored\";\n\n/** Shape of a single announcement entry as it lives in the widget store. */\nexport interface AnnouncementPreviewEntry {\n\ttitle: string;\n\tbody: string | null;\n\tslug: string;\n\ttabId: string;\n\tbadge: string | null;\n}\n\nexport interface AnnouncementPreviewsProps {\n\t/** Called when the visitor taps an announcement card. Receives the\n\t * entry's slug + the parent tab id. The consumer decides what to\n\t * do — at minimum `setOpen(true)`, optionally deep-link into the\n\t * matching content tab + detail. */\n\tonOpen: (slug: string, tabId: string) => void;\n\t/** The avatar node shown in each card's header. Injected so the\n\t * component is decoupled from avatar resolution; pass\n\t * `<WidgetLogo />` for the SDK default. */\n\tavatar: ReactNode;\n\t/**\n\t * Outer positioning mode. `\"launcher\"` (default) keeps the stack\n\t * pinned above the floating bubble; `\"anchored\"` drops that and\n\t * lets the consumer's positioned wrapper place the stack — and\n\t * each card stretches to the wrapper width instead of the launcher\n\t * 300px (via the same `.hw-preview--anchored` modifier the\n\t * message preview uses).\n\t */\n\tplacement?: AnnouncementPreviewsPlacement;\n\t/**\n\t * Optional caption rendered as a separated footer beneath each\n\t * card (e.g. a \"via X\" provenance line). Omitted on the launcher\n\t * so its visual stays byte-identical to the original.\n\t */\n\tfooter?: ReactNode;\n\t/**\n\t * How many cards to render before collapsing the rest into a single\n\t * \"+N more updates\" row.\n\t *\n\t * Unlimited by default, which is what every existing consumer already gets.\n\t * The launcher passes a real number because the strip above it is shared with\n\t * the incoming-reply card and the two together ran off the top of the screen:\n\t * four cards need more than 600px of viewport, and the topmost ones were\n\t * simply gone. Clipping is a priority statement, not a size fix — a reply is a\n\t * conversation waiting on the visitor, an announcement is content that can\n\t * wait, so the announcements are what gets collapsed.\n\t */\n\tmaxVisible?: number;\n}\n\n/**\n * `<AnnouncementPreviews>` — proactive \"new content\" cards shown when\n * the widget panel is closed and the visitor hasn't seen the latest\n * entries from a \"Promote new content\" tab yet. Stacks multiple\n * entries vertically.\n *\n * Extracted from the default widget so `hideLauncher` integrations can\n * surface the *exact same* cards next to their own UI instead of the\n * floating launcher. Visual/markup is byte-identical to the launcher\n * version — only the outer positioning is parameterised via\n * `placement`. Announcements never auto-dismiss (visitors need time to\n * read); they're cleared by tapping the card or the ✕.\n *\n * Must be rendered inside `<SupportProvider>`.\n */\nexport function AnnouncementPreviews({\n\tonOpen,\n\tavatar,\n\tplacement = \"launcher\",\n\tfooter,\n\tmaxVisible = Number.POSITIVE_INFINITY,\n}: AnnouncementPreviewsProps) {\n\tconst previews = useWidgetStore((s) => s.announcementPreviews);\n\tconst dismissPreview = useWidgetStore((s) => s.dismissAnnouncementPreview);\n\tconst agentName = useWidgetStore((s) => s.agentConfig?.name) ?? \"Support\";\n\n\tif (previews.length === 0) return null;\n\n\tconst stackPlacementClass = placement === \"anchored\" ? \"hw-preview-stack--anchored \" : \"\";\n\n\t/* Newest first is already the store's order (setAnnouncementPreview prepends),\n\t so the visible slice is the top of the list and the overflow is the tail. */\n\tconst { visible, hidden } = splitAnnouncementStack(previews, maxVisible);\n\t/* The row opens the next unread one rather than \"all of them\": marking every\n\t hidden entry seen on one tap would silently consume announcements the visitor\n\t never read. */\n\tconst next = hidden[0];\n\n\treturn (\n\t\t<div className={`hw-preview-stack ${stackPlacementClass}`.trim()}>\n\t\t\t{visible.map((preview) => (\n\t\t\t\t<AnnouncementPreviewItem\n\t\t\t\t\tkey={preview.slug}\n\t\t\t\t\tpreview={preview}\n\t\t\t\t\tagentName={agentName}\n\t\t\t\t\tavatar={avatar}\n\t\t\t\t\tplacement={placement}\n\t\t\t\t\tfooter={footer}\n\t\t\t\t\tonOpen={onOpen}\n\t\t\t\t\tonDismiss={(slug) => dismissPreview(slug)}\n\t\t\t\t/>\n\t\t\t))}\n\t\t\t{next && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"hw-preview-more\"\n\t\t\t\t\tonClick={() => onOpen(next.slug, next.tabId)}\n\t\t\t\t>\n\t\t\t\t\t{hidden.length === 1\n\t\t\t\t\t\t? t(\"widget.more_announcements_one\")\n\t\t\t\t\t\t: t(\"widget.more_announcements\", { count: hidden.length })}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction AnnouncementPreviewItem({\n\tpreview,\n\tagentName,\n\tavatar,\n\tplacement,\n\tfooter,\n\tonOpen,\n\tonDismiss,\n}: {\n\tpreview: AnnouncementPreviewEntry;\n\tagentName: string;\n\tavatar: ReactNode;\n\tplacement: AnnouncementPreviewsPlacement;\n\tfooter?: ReactNode;\n\tonOpen: (slug: string, tabId: string) => void;\n\tonDismiss: (slug: string) => void;\n}) {\n\tconst [closing, setClosing] = useState(false);\n\n\tconst handleClose = (e: MouseEvent) => {\n\t\te.stopPropagation();\n\t\tsetClosing(true);\n\t\tsetTimeout(() => {\n\t\t\tonDismiss(preview.slug);\n\t\t\tsetClosing(false);\n\t\t}, 200);\n\t};\n\n\tconst placementClass = placement === \"anchored\" ? \"hw-preview--anchored \" : \"\";\n\n\treturn (\n\t\t<div\n\t\t\tclassName={`hw-preview hw-preview--announcement ${placementClass}${closing ? \"hw-preview--closing\" : \"\"}`.trim()}\n\t\t\tonClick={() => onOpen(preview.slug, preview.tabId)}\n\t\t\trole=\"button\"\n\t\t\ttabIndex={0}\n\t\t>\n\t\t\t<div className=\"hw-preview-header\">\n\t\t\t\t<div className=\"hw-preview-avatar\">{avatar}</div>\n\t\t\t\t<div className=\"hw-preview-name\">{agentName}</div>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"hw-preview-close\"\n\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\taria-label={t(\"widget.aria_dismiss\")}\n\t\t\t\t>\n\t\t\t\t\t<XIcon size={20} />\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<div className=\"hw-preview-body hw-preview-body--title\">{preview.title}</div>\n\t\t\t{preview.body &&\n\t\t\t\t(() => {\n\t\t\t\t\tconst clean = stripMarkdown(preview.body);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div className=\"hw-preview-body hw-preview-body--desc\">\n\t\t\t\t\t\t\t{truncatePreviewBody(clean)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t);\n\t\t\t\t})()}\n\t\t\t{preview.badge && <div className=\"hw-announcement-badge\">{preview.badge}</div>}\n\t\t\t{footer != null && footer !== false && <div className=\"hw-preview-footer\">{footer}</div>}\n\t\t</div>\n\t);\n}\n","/**\n * Strip the most common Markdown affordances so a body excerpt reads as\n * plain text inside a preview bubble. Intentionally minimal — covers\n * headings, bold/italic, lists, links, inline code, and newlines. Not\n * a full Markdown renderer; meant for short truncated descriptions\n * where the rendered styling would clash with the surrounding chrome.\n */\nexport function stripMarkdown(text: string): string {\n\treturn text\n\t\t.replace(/^#{1,6}\\s+/gm, \"\")\n\t\t.replace(/\\*\\*(.+?)\\*\\*/g, \"$1\")\n\t\t.replace(/\\*(.+?)\\*/g, \"$1\")\n\t\t.replace(/^[-*+]\\s+/gm, \"\")\n\t\t.replace(/\\[(.+?)\\]\\(.+?\\)/g, \"$1\")\n\t\t.replace(/`(.+?)`/g, \"$1\")\n\t\t.replace(/\\n{2,}/g, \" \")\n\t\t.replace(/\\n/g, \" \")\n\t\t.trim();\n}\n","import { resolveLabel, t } from \"@helpway/widget-core\";\nimport type { WidgetContentTab } from \"@helpway/widget-core\";\nimport { useCallback, useEffect } from \"react\";\nimport { useContentTab } from \"../../hooks/use-content-tab\";\nimport type { ContentEntryItem } from \"../../hooks/use-content-tab\";\nimport { ContentDetailView } from \"./content-detail-view\";\nimport { ContentListView } from \"./content-list-view\";\nimport { GroupedContentTabView } from \"./grouped-content-tab-view\";\n\n/**\n * Content tab dispatcher:\n * - \"flat\" (default) → simple list → detail\n * - \"grouped\" → categories → items → detail\n */\nexport function ContentTabView({\n\ttab,\n\tshowDetail,\n\tdetailSlug,\n\tsubView,\n\tonSelectEntry,\n\tonSelectCategory,\n}: {\n\ttab: WidgetContentTab;\n\tshowDetail: boolean;\n\tdetailSlug: string | null;\n\tsubView?: string | null;\n\tonSelectEntry: (slug: string) => void;\n\tonSelectCategory?: (category: ContentEntryItem) => void;\n}) {\n\t// ── Grouped tab ──\n\tif (tab.tabType === \"grouped\" && tab.itemsModelSlug) {\n\t\treturn (\n\t\t\t<GroupedContentTabView\n\t\t\t\ttab={tab}\n\t\t\t\tsubView={subView ?? null}\n\t\t\t\tdetailSlug={detailSlug}\n\t\t\t\tonSelectCategory={onSelectCategory ?? (() => {})}\n\t\t\t\tonSelectEntry={onSelectEntry}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// ── Flat tab (default) ──\n\treturn (\n\t\t<FlatContentTabView\n\t\t\ttab={tab}\n\t\t\tshowDetail={showDetail}\n\t\t\tdetailSlug={detailSlug}\n\t\t\tonSelectEntry={onSelectEntry}\n\t\t/>\n\t);\n}\n\n// ── Flat (original behavior) ─────────────────────────────\n\nfunction FlatContentTabView({\n\ttab,\n\tshowDetail,\n\tdetailSlug,\n\tonSelectEntry,\n}: {\n\ttab: WidgetContentTab;\n\tshowDetail: boolean;\n\tdetailSlug: string | null;\n\tonSelectEntry: (slug: string) => void;\n}) {\n\tconst {\n\t\tentries,\n\t\tdetail,\n\t\tisLoading,\n\t\tisLoadingDetail,\n\t\thasMore,\n\t\tfetchEntries,\n\t\tloadMore,\n\t\tfetchDetail,\n\t} = useContentTab(tab.id);\n\n\tuseEffect(() => {\n\t\tif (detailSlug) fetchDetail(detailSlug);\n\t}, [detailSlug, fetchDetail]);\n\n\tconst handleSearch = useCallback(\n\t\t(query: string) => {\n\t\t\tfetchEntries({ page: 1, search: query || undefined, reset: true });\n\t\t},\n\t\t[fetchEntries],\n\t);\n\n\tif (showDetail && detailSlug) {\n\t\treturn <ContentDetailView entry={detail} isLoading={isLoadingDetail} />;\n\t}\n\n\treturn (\n\t\t<ContentListView\n\t\t\tentries={entries}\n\t\t\tisLoading={isLoading}\n\t\t\thasMore={hasMore}\n\t\t\tonSelect={onSelectEntry}\n\t\t\tonLoadMore={loadMore}\n\t\t\tonSearch={handleSearch}\n\t\t\tsearchPlaceholder={`${t(\"widget.search\")} ${resolveLabel(tab.label).toLowerCase()}...`}\n\t\t\tdisplay={tab.display}\n\t\t/>\n\t);\n}\n","import type { WidgetContentTab } from \"@helpway/widget-core\";\nimport { CONTENT_CACHE_TTL, getLocale } from \"@helpway/widget-core\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\ninterface ContentEntryItem {\n\tslug: string;\n\ttitle: string;\n\tbody: string | null;\n\tpublishedAt: string | null;\n\tcustomFields: Record<string, string | null>;\n}\n\ninterface ContentEntryDetail {\n\tslug: string;\n\ttitle: string;\n\tbody: string | null;\n\tbodyHtml: string | null;\n\tpublishedAt: string | null;\n\tsourceLanguage: string;\n\tavailableLanguages: string[];\n\tcustomFields: Record<string, string | null>;\n}\n\nconst EMPTY_TABS: WidgetContentTab[] = [];\n\n// ── Cache key helpers ──\n\nfunction listKey(tabId: string, lang: string) {\n\treturn `flat:${tabId}:${lang}:list`;\n}\n\nfunction detailKey(tabId: string, lang: string, slug: string) {\n\treturn `flat:${tabId}:${lang}:detail:${slug}`;\n}\n\ninterface CachedList {\n\titems: ContentEntryItem[];\n\ttotal: number;\n\thasMore: boolean;\n\tpage: number;\n}\n\nfunction readCache<T>(cache: Map<string, { data: unknown; ts: number }>, key: string): T | null {\n\tconst entry = cache.get(key);\n\tif (!entry) return null;\n\tif (Date.now() - entry.ts > CONTENT_CACHE_TTL) return null;\n\treturn entry.data as T;\n}\n\n/**\n * Hook for fetching content from a dynamic content tab.\n * Content is cached in the Zustand store so tab switches don't re-fetch.\n */\nexport function useContentTab(tabId: string) {\n\tconst { client, store } = useWidgetContext();\n\tconst contentTabs = useWidgetStore((s) => s.agentConfig?.contentTabs) ?? EMPTY_TABS;\n\tconst tab = contentTabs.find((t) => t.id === tabId) ?? null;\n\n\tconst lang = getLocale();\n\tconst cache = store.getState().contentCache;\n\n\tconst [entries, setEntries] = useState<ContentEntryItem[]>(\n\t\t() => readCache<CachedList>(cache, listKey(tabId, lang))?.items ?? [],\n\t);\n\tconst [detail, setDetail] = useState<ContentEntryDetail | null>(null);\n\tconst [isLoading, setIsLoading] = useState(false);\n\tconst [isLoadingDetail, setIsLoadingDetail] = useState(false);\n\tconst [hasMore, setHasMore] = useState(\n\t\t() => readCache<CachedList>(cache, listKey(tabId, lang))?.hasMore ?? false,\n\t);\n\tconst [total, setTotal] = useState(\n\t\t() => readCache<CachedList>(cache, listKey(tabId, lang))?.total ?? 0,\n\t);\n\tconst [page, setPage] = useState(\n\t\t() => readCache<CachedList>(cache, listKey(tabId, lang))?.page ?? 1,\n\t);\n\n\tconst fetchEntries = useCallback(\n\t\tasync (opts?: { page?: number; search?: string; reset?: boolean }) => {\n\t\t\tif (!tab) return;\n\t\t\tconst p = opts?.page ?? 1;\n\t\t\tconst reset = opts?.reset ?? p === 1;\n\n\t\t\tsetIsLoading(true);\n\t\t\ttry {\n\t\t\t\tconst result = await client.widget.getContent.query({\n\t\t\t\t\ttabId,\n\t\t\t\t\tpage: p,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t\tsearch: opts?.search,\n\t\t\t\t\tlanguage: getLocale(),\n\t\t\t\t});\n\n\t\t\t\tif (result.items) {\n\t\t\t\t\tsetEntries((prev) => {\n\t\t\t\t\t\tconst nextItems = reset ? result.items! : [...prev, ...result.items!];\n\t\t\t\t\t\tif (!opts?.search) {\n\t\t\t\t\t\t\tstore.getState().setContentCache(listKey(tabId, getLocale()), {\n\t\t\t\t\t\t\t\titems: nextItems,\n\t\t\t\t\t\t\t\ttotal: result.total,\n\t\t\t\t\t\t\t\thasMore: result.hasMore,\n\t\t\t\t\t\t\t\tpage: p,\n\t\t\t\t\t\t\t} satisfies CachedList);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nextItems;\n\t\t\t\t\t});\n\t\t\t\t\tsetHasMore(result.hasMore);\n\t\t\t\t\tsetTotal(result.total);\n\t\t\t\t\tsetPage(p);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useContentTab] fetch error:\", err);\n\t\t\t} finally {\n\t\t\t\tsetIsLoading(false);\n\t\t\t}\n\t\t},\n\t\t[client, tabId, tab, store],\n\t);\n\n\tconst loadMore = useCallback(() => {\n\t\tif (!hasMore || isLoading) return;\n\t\tfetchEntries({ page: page + 1 });\n\t}, [fetchEntries, hasMore, isLoading, page]);\n\n\tconst fetchDetail = useCallback(\n\t\tasync (slug: string) => {\n\t\t\tif (!tab) return;\n\n\t\t\t// Check detail cache\n\t\t\tconst cached = readCache<ContentEntryDetail>(\n\t\t\t\tstore.getState().contentCache,\n\t\t\t\tdetailKey(tabId, getLocale(), slug),\n\t\t\t);\n\t\t\tif (cached) {\n\t\t\t\tsetDetail(cached);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetIsLoadingDetail(true);\n\t\t\ttry {\n\t\t\t\tconst result = await client.widget.getContent.query({\n\t\t\t\t\ttabId,\n\t\t\t\t\tslug,\n\t\t\t\t\tlanguage: getLocale(),\n\t\t\t\t});\n\t\t\t\tif (result.entry) {\n\t\t\t\t\tconst entry = result.entry as ContentEntryDetail;\n\t\t\t\t\tsetDetail(entry);\n\t\t\t\t\tstore.getState().setContentCache(\n\t\t\t\t\t\tdetailKey(tabId, getLocale(), slug),\n\t\t\t\t\t\tentry,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useContentTab] detail error:\", err);\n\t\t\t} finally {\n\t\t\t\tsetIsLoadingDetail(false);\n\t\t\t}\n\t\t},\n\t\t[client, tabId, tab, store],\n\t);\n\n\tconst clearDetail = useCallback(() => {\n\t\tsetDetail(null);\n\t}, []);\n\n\t// Initial fetch — only if cache was empty\n\tuseEffect(() => {\n\t\tif (tab && entries.length === 0) {\n\t\t\tfetchEntries({ page: 1, reset: true });\n\t\t}\n\t}, [tab]); // eslint-disable-line react-hooks/exhaustive-deps\n\n\treturn {\n\t\ttab,\n\t\tentries,\n\t\tdetail,\n\t\tisLoading,\n\t\tisLoadingDetail,\n\t\thasMore,\n\t\ttotal,\n\t\tfetchEntries,\n\t\tloadMore,\n\t\tfetchDetail,\n\t\tclearDetail,\n\t};\n}\n\nexport type { ContentEntryItem, ContentEntryDetail, WidgetContentTab };\n","import { useEffect, useRef } from \"react\";\n\nconst COPY_ICON = `<svg class=\"hw-code-copy-icon\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"><path d=\"M15 9V4.25C15 3.55964 14.4404 3 13.75 3H4.25C3.55964 3 3 3.55964 3 4.25V13.75C3 14.4404 3.55964 15 4.25 15H9M10.25 9H19.75C20.4404 9 21 9.55964 21 10.25V19.75C21 20.4404 20.4404 21 19.75 21H10.25C9.55964 21 9 20.4404 9 19.75V10.25C9 9.55964 9.55964 9 10.25 9Z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`;\n\nconst CHECK_ICON = `<svg class=\"hw-code-check-icon\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"><path d=\"M8 13L11 16L16 8\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`;\n\nfunction inferCodeLanguage(code: string, lang?: string): string {\n\tif (lang) return lang;\n\tconst trimmed = code.trim();\n\tif (/^(npm|pnpm|yarn|bun|npx|curl|cd|mkdir|cp|mv|rm|export)\\b/m.test(trimmed)) return \"bash\";\n\tif (/\\b(import|export)\\b/.test(trimmed) && /<[A-Z_a-z][\\w.:-]*(\\s|>)/.test(trimmed)) return \"tsx\";\n\tif (/\\b(import|export|const|let|function|type|interface)\\b/.test(trimmed)) return \"ts\";\n\tif (/^\\s*[{[]/.test(trimmed)) return \"json\";\n\treturn \"code\";\n}\n\nexport function handleCodeBlockClick(e: Event, root: HTMLElement): void {\n\tconst target = e.target as HTMLElement | null;\n\tconst btn = target?.closest<HTMLButtonElement>(\".hw-code-copy\");\n\tif (!btn || !root.contains(btn)) return;\n\tconst block = btn.closest(\".hw-code\");\n\tconst code = block?.querySelector(\"pre code\");\n\tconst text = code?.textContent ?? \"\";\n\tif (!text) return;\n\tvoid navigator.clipboard?.writeText(text).then(\n\t\t() => flashCopied(btn),\n\t\t() => flashCopied(btn, true),\n\t);\n}\n\n/**\n * Lightweight Markdown → HTML renderer.\n * Zero dependencies. Handles common patterns:\n * headings, bold, italic, code, links, lists, blockquotes, images, hr.\n *\n * Security note: Content is served from Better i18n Content CMS which only\n * accepts authenticated writes (secret API key). The CMS sanitizes content\n * server-side. Additionally, our renderMarkdown escapes HTML entities before\n * processing markdown syntax, preventing injection of raw HTML tags.\n */\nexport function renderMarkdown(md: string): string {\n\t// Stash fenced code blocks BEFORE any other pass. Fence content must be\n\t// preserved verbatim: no bold, no autolink, no newline→<br> — otherwise\n\t// a curl command or JSON sample gets shredded. We also escape HTML inside\n\t// the block (the global escape below runs only on the remaining markdown).\n\tconst codeBlocks: string[] = [];\n\tconst codeBlockPlaceholder = (i: number) => `\\u0000CODEBLOCK${i}\\u0000`;\n\tconst body = md.replace(\n\t\t// Eat ALL newlines around the fence (zero-or-more both sides). The\n\t\t// replacement re-emits its own `\\n\\n` pair so the paragraph splitter\n\t\t// cleanly bookends the fence. Without this, `before\\n\\n` + `\\n\\n` from\n\t\t// us = 3 newlines, the extra one becomes <br /> and lands inside a <p>.\n\t\t/\\n*```(\\w+)?\\n?([\\s\\S]*?)```\\n*/g,\n\t\t(_match, lang: string | undefined, code: string) => {\n\t\t\tconst escaped = code.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n\t\t\tconst langLabel = inferCodeLanguage(code, lang);\n\t\t\tconst className = langLabel !== \"code\" ? ` class=\"language-${langLabel}\"` : \"\";\n\t\t\t// Render every fenced block with a header bar (language label + copy\n\t\t\t// button) so it reads like a proper code card, not a bare <pre>.\n\t\t\t// The actual copy action is wired up in MarkdownContent via event\n\t\t\t// delegation — we only need the markup + a stable attribute to key\n\t\t\t// off of.\n\t\t\tconst trimmed = escaped.replace(/\\n$/, \"\");\n\t\t\tcodeBlocks.push(\n\t\t\t\t`<div class=\"hw-code\" data-hw-code=\"1\"><div class=\"hw-code-header\"><span class=\"hw-code-lang\">${langLabel}</span><div class=\"hw-code-actions\"><button type=\"button\" class=\"hw-code-action hw-code-copy\" aria-label=\"Copy code\" title=\"Copy code\">${COPY_ICON}${CHECK_ICON}<span class=\"hw-code-copy-label\">Copy</span></button></div></div><pre><code${className}>${trimmed}</code></pre></div>`,\n\t\t\t);\n\t\t\t// Sandwich the placeholder in blank lines so the paragraph splitter\n\t\t\t// treats it as its own block. Otherwise a fence that follows a\n\t\t\t// paragraph without a separating blank line ends up inside a <p>\n\t\t\t// (invalid HTML, collapses the <pre>).\n\t\t\treturn `\\n\\n${codeBlockPlaceholder(codeBlocks.length - 1)}\\n\\n`;\n\t\t},\n\t);\n\n\tlet html = body\n\t\t// Escape HTML entities FIRST — prevents XSS from raw HTML in markdown\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t// Headings (### h3, ## h2, # h1)\n\t\t.replace(/^### (.+)$/gm, \"<h3>$1</h3>\")\n\t\t.replace(/^## (.+)$/gm, \"<h2>$1</h2>\")\n\t\t.replace(/^# (.+)$/gm, \"<h1>$1</h1>\")\n\t\t// Horizontal rule\n\t\t.replace(/^---$/gm, \"<hr />\")\n\t\t// Bold + italic\n\t\t.replace(/\\*\\*\\*(.+?)\\*\\*\\*/g, \"<strong><em>$1</em></strong>\")\n\t\t// Bold\n\t\t.replace(/\\*\\*(.+?)\\*\\*/g, \"<strong>$1</strong>\")\n\t\t// Italic\n\t\t.replace(/\\*(.+?)\\*/g, \"<em>$1</em>\")\n\t\t// Inline code\n\t\t.replace(/`([^`]+)`/g, \"<code>$1</code>\")\n\t\t// Images\n\t\t.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, '<img src=\"$2\" alt=\"$1\" />')\n\t\t// Links (markdown format)\n\t\t.replace(\n\t\t\t/\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n\t\t\t'<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>',\n\t\t)\n\t\t// Auto-link bare URLs (not already inside an href or markdown link)\n\t\t.replace(\n\t\t\t/(?<!\")(?<!=)(https?:\\/\\/[^\\s<)]+)/g,\n\t\t\t'<a href=\"$1\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>',\n\t\t)\n\t\t// Blockquotes\n\t\t.replace(/^&gt; (.+)$/gm, \"<blockquote>$1</blockquote>\")\n\t\t// Unordered lists\n\t\t.replace(/^[*-] (.+)$/gm, \"<li>$1</li>\")\n\t\t// Ordered lists — temp <oli> tag so the <ul> wrapper below can't claim\n\t\t// them; renamed to <li> when wrapped in <ol>.\n\t\t.replace(/^\\d+\\. (.+)$/gm, \"<oli>$1</oli>\");\n\n\t// Tables — must run while real newlines still exist (before the <br> pass).\n\t// Runs AFTER the inline passes so bold/links inside cells are already HTML.\n\t// Stashed as placeholders like code blocks so the paragraph splitter can't\n\t// chop a <table> in half.\n\tconst tables: string[] = [];\n\tconst tablePlaceholder = (i: number) => `\\u0000TABLE${i}\\u0000`;\n\thtml = html.replace(\n\t\t// header row | separator row (only - : | spaces) | 1+ body rows\n\t\t/^(\\|.+\\|)[ \\t]*\\n\\|[ \\t:|-]+\\|[ \\t]*\\n((?:\\|.+\\|[ \\t]*(?:\\n|$))+)/gm,\n\t\t(_match, headerLine: string, bodyLines: string) => {\n\t\t\tconst cells = (line: string) =>\n\t\t\t\tline.trim().replace(/^\\||\\|$/g, \"\").split(\"|\").map((c) => c.trim());\n\t\t\tconst head = cells(headerLine)\n\t\t\t\t.map((c) => `<th>${c}</th>`)\n\t\t\t\t.join(\"\");\n\t\t\tconst rows = bodyLines\n\t\t\t\t.trim()\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((line) => `<tr>${cells(line).map((c) => `<td>${c}</td>`).join(\"\")}</tr>`)\n\t\t\t\t.join(\"\");\n\t\t\ttables.push(\n\t\t\t\t`<div class=\"hw-table-wrap\"><table class=\"hw-table\"><thead><tr>${head}</tr></thead><tbody>${rows}</tbody></table></div>`,\n\t\t\t);\n\t\t\treturn `\\n\\n${tablePlaceholder(tables.length - 1)}\\n\\n`;\n\t\t},\n\t);\n\n\t// Wrap consecutive list items BEFORE newlines become <br /> — the old\n\t// post-<br> wrap could only ever see one <li> at a time, producing a\n\t// separate <ul> per item with stray <br />s in between.\n\thtml = html\n\t\t.replace(/((?:<li>.*<\\/li>\\n?)+)/g, (m) => `<ul>${m.replace(/\\n/g, \"\")}</ul>\\n`)\n\t\t.replace(\n\t\t\t/((?:<oli>.*<\\/oli>\\n?)+)/g,\n\t\t\t(m) => `<ol>${m.replace(/\\n/g, \"\").replace(/<(\\/?)oli>/g, \"<$1li>\")}</ol>\\n`,\n\t\t);\n\n\thtml = html\n\t\t// Paragraphs (double newline)\n\t\t.replace(/\\n\\n/g, \"</p><p>\")\n\t\t// Single newlines → br\n\t\t.replace(/\\n/g, \"<br />\");\n\n\t// Lists glued to surrounding text by a single newline pick up a stray\n\t// <br /> neighbor — drop it so spacing comes from CSS, not phantom breaks.\n\t// Same for a <br /> opening a paragraph (left over from placeholder seams).\n\thtml = html\n\t\t.replace(/<br \\/>(\\s*<(?:ul|ol)>)/g, \"$1\")\n\t\t.replace(/(<\\/(?:ul|ol)>\\s*)<br \\/>/g, \"$1\")\n\t\t.replace(/<p><br \\/>/g, \"<p>\");\n\n\t// Wrap in paragraph if not starting with a block element\n\tif (\n\t\t!html.startsWith(\"<h\") &&\n\t\t!html.startsWith(\"<ul\") &&\n\t\t!html.startsWith(\"<ol\") &&\n\t\t!html.startsWith(\"<blockquote\") &&\n\t\t!html.startsWith(\"<hr\")\n\t) {\n\t\thtml = `<p>${html}</p>`;\n\t}\n\n\t// Re-inject tables (same placeholder mechanics as code blocks below).\n\tif (tables.length > 0) {\n\t\t// biome-ignore lint/suspicious/noControlCharactersInRegex: placeholders use NUL sentinels intentionally.\n\t\thtml = html.replace(/\\u0000TABLE(\\d+)\\u0000/g, (_m, idx: string) => {\n\t\t\tconst i = Number.parseInt(idx, 10);\n\t\t\treturn tables[i] ?? \"\";\n\t\t});\n\t\t// Unwrap a <p> that ended up directly around a table (no blank-line\n\t\t// separator in the source) — invalid nesting collapses the layout.\n\t\thtml = html.replace(/<p>(\\s*<div class=\"hw-table-wrap\"[\\s\\S]*?<\\/div>\\s*)<\\/p>/g, \"$1\");\n\t}\n\n\t// A list that landed inside a <p> (single blank line before it) is invalid\n\t// nesting — unwrap like the code-block case below.\n\thtml = html.replace(/<p>(\\s*<(?:ul|ol)>[\\s\\S]*?<\\/(?:ul|ol)>\\s*)<\\/p>/g, \"$1\");\n\n\t// Re-inject code blocks now that surrounding paragraphs / <br> passes are\n\t// done. Placeholders used NUL sentinels so they can't collide with user\n\t// content or be accidentally wrapped by the block-element heuristics above.\n\tif (codeBlocks.length > 0) {\n\t\t// biome-ignore lint/suspicious/noControlCharactersInRegex: placeholders use NUL sentinels intentionally.\n\t\thtml = html.replace(/\\u0000CODEBLOCK(\\d+)\\u0000/g, (_m, idx: string) => {\n\t\t\tconst i = Number.parseInt(idx, 10);\n\t\t\treturn codeBlocks[i] ?? \"\";\n\t\t});\n\t\t// A code block that landed inside a <p> (because the preceding line had no\n\t\t// blank-line separator) becomes invalid nesting (<p><div><pre>). Unwrap\n\t\t// the outer <p> so the block stands on its own.\n\t\thtml = html.replace(/<p>(\\s*<div class=\"hw-code\"[\\s\\S]*?<\\/div>\\s*)<\\/p>/g, \"$1\");\n\t}\n\n\treturn html;\n}\n\n/**\n * Convert bare URLs in plain text to clickable links.\n * Used for visitor/team messages (not full markdown).\n * HTML-escaped for safety.\n */\nexport function linkifyText(text: string): string {\n\treturn text\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t.replace(\n\t\t\t/(https?:\\/\\/[^\\s<]+)/g,\n\t\t\t'<a href=\"$1\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>',\n\t\t)\n\t\t.replace(/\\n/g, \"<br />\");\n}\n\n/**\n * Renders markdown or pre-rendered HTML content.\n * Prefers bodyHtml (server-sanitized by CMS) when available,\n * falls back to client-side markdown rendering (HTML-escaped).\n */\nexport function MarkdownContent({\n\tbodyHtml,\n\tbodyMarkdown,\n\tclassName,\n}: {\n\tbodyHtml?: string | null;\n\tbodyMarkdown?: string | null;\n\tclassName?: string;\n}) {\n\tconst rootRef = useRef<HTMLDivElement>(null);\n\tconst html = bodyHtml ?? (bodyMarkdown ? renderMarkdown(bodyMarkdown) : \"\");\n\n\t// Strip whitespace-only block elements after the HTML lands in the DOM.\n\t// PlateJS/Slate/ProseMirror CMS bodies emit <p>&nbsp;</p> or <div> </div>\n\t// to represent visual line breaks. CSS `:empty` doesn't match these (the\n\t// nbsp/space is a text node) and CSS has no text-content selector, so we\n\t// clean them up here. Runs once per html change.\n\tuseEffect(() => {\n\t\tconst root = rootRef.current;\n\t\tif (!root) return;\n\n\t\tconst isWhitespaceOnly = (el: Element): boolean => {\n\t\t\t// No element children OR only <br> children, AND text is whitespace/empty\n\t\t\tconst hasNonBrChild = Array.from(el.children).some(\n\t\t\t\t(c) => c.tagName !== \"BR\",\n\t\t\t);\n\t\t\tif (hasNonBrChild) return false;\n\t\t\tconst text = el.textContent ?? \"\";\n\t\t\treturn text.replace(/[\\s ]/g, \"\") === \"\";\n\t\t};\n\n\t\tconst removeEmpties = () => {\n\t\t\tconst candidates = root.querySelectorAll(\"p, div\");\n\t\t\tcandidates.forEach((el) => {\n\t\t\t\tif (isWhitespaceOnly(el)) el.remove();\n\t\t\t});\n\t\t};\n\t\tremoveEmpties();\n\t}, [html]);\n\n\t// Event-delegated copy handler for any `.hw-code-copy` button inside the\n\t// rendered tree. Using delegation instead of rendering each code block as\n\t// a React component keeps the markdown → HTML path zero-dep.\n\tuseEffect(() => {\n\t\tconst root = rootRef.current;\n\t\tif (!root) return;\n\t\tconst handler = (e: Event) => {\n\t\t\thandleCodeBlockClick(e, root);\n\t\t};\n\t\troot.addEventListener(\"click\", handler);\n\t\treturn () => {\n\t\t\troot.removeEventListener(\"click\", handler);\n\t\t};\n\t}, []);\n\n\tif (!html) return null;\n\n\treturn (\n\t\t<div\n\t\t\tref={rootRef}\n\t\t\tclassName={`hw-markdown ${className ?? \"\"}`}\n\t\t\t// Content is from authenticated CMS (server-sanitized bodyHtml)\n\t\t\t// or client-side rendered with HTML entity escaping (renderMarkdown).\n\t\t\t// biome-ignore lint/security/noDangerouslySetInnerHtml: trusted CMS content\n\t\t\tdangerouslySetInnerHTML={{ __html: html }}\n\t\t/>\n\t);\n}\n\nfunction flashCopied(btn: HTMLButtonElement, failed = false) {\n\tconst label = btn.querySelector(\".hw-code-copy-label\");\n\tif (!label) return;\n\tconst original = label.textContent ?? \"Copy\";\n\tlabel.textContent = failed ? \"Failed\" : \"Copied\";\n\tbtn.classList.add(failed ? \"hw-code-copy--failed\" : \"hw-code-copy--copied\");\n\tsetTimeout(() => {\n\t\tlabel.textContent = original;\n\t\tbtn.classList.remove(\"hw-code-copy--copied\", \"hw-code-copy--failed\");\n\t}, 1500);\n}\n\n/**\n * Close dangling markdown delimiters in a partial (still-streaming) message\n * so renderMarkdown doesn't show raw syntax mid-stream: an unclosed ```fence\n * renders as literal backticks, an odd ** shows asterisks. The final message\n * replaces this bubble entirely, so the patch only ever affects transient UI.\n */\nexport function closeDanglingMarkdown(partial: string): string {\n\tlet out = partial;\n\tconst fences = (out.match(/```/g) ?? []).length;\n\tif (fences % 2 === 1) out += \"\\n```\";\n\t// Inline code / bold counted on the remainder outside fences is overkill\n\t// for a transient frame — a simple global parity check is good enough.\n\tconst bold = (out.match(/\\*\\*/g) ?? []).length;\n\tif (bold % 2 === 1) out += \"**\";\n\treturn out;\n}\n","import { formatRelativeTime } from \"@helpway/widget-core\";\nimport type { ContentEntryDetail } from \"../../hooks/use-content-tab\";\nimport { MarkdownContent } from \"./simple-markdown\";\n\nexport function ContentDetailView({\n\tentry,\n\tisLoading,\n}: {\n\tentry: ContentEntryDetail | null;\n\tisLoading: boolean;\n}) {\n\tif (isLoading || !entry) {\n\t\treturn <ArticleSkeleton />;\n\t}\n\n\tconst badge = entry.customFields.version ?? entry.customFields.priority ?? entry.customFields.type ?? null;\n\n\treturn (\n\t\t<div className=\"hw-content-detail\">\n\t\t\t<div className=\"hw-content-detail-header\">\n\t\t\t\t<h1 className=\"hw-content-detail-title\">{entry.title}</h1>\n\t\t\t\t{(badge || entry.publishedAt) && (\n\t\t\t\t\t<div className=\"hw-content-detail-meta\">\n\t\t\t\t\t\t{badge && <span className=\"hw-content-entry-badge\">{badge}</span>}\n\t\t\t\t\t\t{entry.publishedAt && (\n\t\t\t\t\t\t\t<span className=\"hw-content-detail-date\">\n\t\t\t\t\t\t\t\t{formatRelativeTime(entry.publishedAt)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t{(entry.body || entry.bodyHtml) && (\n\t\t\t\t<div className=\"hw-content-detail-body\">\n\t\t\t\t\t<MarkdownContent bodyHtml={entry.bodyHtml} bodyMarkdown={entry.body} />\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n/**\n * Article-shaped skeleton.\n *\n * Uses the real .hw-content-detail / .hw-content-detail-header / .hw-content-detail-body / .hw-markdown\n * wrapper classes so all padding, font metrics, and adjacency-spacing rules\n * apply identically to the skeleton — guaranteeing the content lands without\n * any reflow when it arrives.\n *\n * Layout maps 1:1 to the rendered changelog:\n * <h1>Title</h1>\n * <div class=\"meta\"> badge + date </div>\n * <h2>Section</h2>\n * <ul><li>Bullet 1, 2 lines</li></ul>\n * <ul><li>Bullet 2, 2 lines</li></ul>\n * ...\n */\nfunction ArticleSkeleton() {\n\tconst sections: { headerWidth: string; items: { l1: string; l2: string }[] }[] = [\n\t\t{\n\t\t\theaderWidth: \"30%\",\n\t\t\titems: [\n\t\t\t\t{ l1: \"98%\", l2: \"62%\" },\n\t\t\t\t{ l1: \"94%\", l2: \"48%\" },\n\t\t\t\t{ l1: \"96%\", l2: \"70%\" },\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\theaderWidth: \"26%\",\n\t\t\titems: [\n\t\t\t\t{ l1: \"92%\", l2: \"55%\" },\n\t\t\t\t{ l1: \"88%\", l2: \"40%\" },\n\t\t\t],\n\t\t},\n\t];\n\n\treturn (\n\t\t<div className=\"hw-content-detail\">\n\t\t\t<div className=\"hw-content-detail-header\">\n\t\t\t\t<h1 className=\"hw-content-detail-title\">\n\t\t\t\t\t<span className=\"hw-skeleton hw-skeleton-title\" />\n\t\t\t\t</h1>\n\t\t\t\t<div className=\"hw-content-detail-meta\">\n\t\t\t\t\t<span className=\"hw-skeleton hw-skeleton-badge\" />\n\t\t\t\t\t<span className=\"hw-skeleton hw-skeleton-date\" />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div className=\"hw-content-detail-body\">\n\t\t\t\t<div className=\"hw-markdown\">\n\t\t\t\t\t{sections.map((s, i) => (\n\t\t\t\t\t\t<SkeletonSection\n\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\theaderWidth={s.headerWidth}\n\t\t\t\t\t\t\titems={s.items}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction SkeletonSection({\n\theaderWidth,\n\titems,\n}: {\n\theaderWidth: string;\n\titems: { l1: string; l2: string }[];\n}) {\n\treturn (\n\t\t<>\n\t\t\t<h2>\n\t\t\t\t<span\n\t\t\t\t\tclassName=\"hw-skeleton hw-skeleton-h2\"\n\t\t\t\t\tstyle={{ display: \"block\", width: headerWidth }}\n\t\t\t\t/>\n\t\t\t</h2>\n\t\t\t{items.map((item, j) => (\n\t\t\t\t<ul key={j}>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<div className=\"hw-skeleton-bullet-lines\">\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName=\"hw-skeleton hw-skeleton-bullet-line\"\n\t\t\t\t\t\t\t\tstyle={{ display: \"block\", width: item.l1 }}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName=\"hw-skeleton hw-skeleton-bullet-line\"\n\t\t\t\t\t\t\t\tstyle={{ display: \"block\", width: item.l2, marginTop: 8 }}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t))}\n\t\t</>\n\t);\n}\n","import { formatRelativeTime, t } from \"@helpway/widget-core\";\nimport type { ContentTabDisplay } from \"@helpway/types\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { ContentEntryItem } from \"../../hooks/use-content-tab\";\n\n/**\n * Content entry list — Intercom-style clean card layout.\n * Search bar at top, card entries with title + description + chevron.\n */\nexport function ContentListView({\n\tentries,\n\tisLoading,\n\thasMore,\n\tonSelect,\n\tonLoadMore,\n\tonSearch,\n\tsearchPlaceholder,\n\tdisplay,\n}: {\n\tentries: ContentEntryItem[];\n\tisLoading: boolean;\n\thasMore: boolean;\n\tonSelect: (slug: string) => void;\n\tonLoadMore: () => void;\n\tonSearch?: (query: string) => void;\n\tsearchPlaceholder?: string;\n\tdisplay?: ContentTabDisplay;\n}) {\n\tconst [searchText, setSearchText] = useState(\"\");\n\tconst debounceRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n\tconst handleSearch = useCallback(\n\t\t(value: string) => {\n\t\t\tsetSearchText(value);\n\t\t\tif (!onSearch) return;\n\t\t\tclearTimeout(debounceRef.current);\n\t\t\tdebounceRef.current = setTimeout(() => {\n\t\t\t\tonSearch(value.trim());\n\t\t\t}, 300);\n\t\t},\n\t\t[onSearch],\n\t);\n\n\treturn (\n\t\t<div className=\"hw-content-list\">\n\t\t\t{/* Search */}\n\t\t\t{onSearch && (\n\t\t\t\t<div className=\"hw-content-search\">\n\t\t\t\t\t<div className=\"hw-content-search-box\">\n\t\t\t\t\t\t<svg className=\"hw-content-search-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n\t\t\t\t\t\t\t<circle cx=\"11\" cy=\"11\" r=\"8\" />\n\t\t\t\t\t\t\t<line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\tclassName=\"hw-content-search-input\"\n\t\t\t\t\t\t\tplaceholder={searchPlaceholder ?? t(\"widget.search\")}\n\t\t\t\t\t\t\tvalue={searchText}\n\t\t\t\t\t\t\tonChange={(e) => handleSearch(e.target.value)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Loading */}\n\t\t\t{isLoading && entries.length === 0 && (\n\t\t\t\t<div className=\"hw-skeleton-content\">\n\t\t\t\t\t{[1, 2, 3].map((i) => (\n\t\t\t\t\t\t<div key={i} className=\"hw-skeleton-content-item\">\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: \"70%\", height: 14 }} />\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: \"90%\", height: 12 }} />\n\t\t\t\t\t\t\t<div className=\"hw-skeleton hw-skeleton-line\" style={{ width: \"40%\", height: 10 }} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Empty */}\n\t\t\t{!isLoading && entries.length === 0 && (\n\t\t\t\t<div className=\"hw-content-empty\">\n\t\t\t\t\t<div className=\"hw-content-empty-title\">\n\t\t\t\t\t\t{searchText ? t(\"widget.no_results\") : t(\"widget.nothing_yet\")}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"hw-content-empty-desc\">\n\t\t\t\t\t\t{searchText ? t(\"widget.try_different\") : t(\"widget.check_back\")}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Entries */}\n\t\t\t{entries.length > 0 && (\n\t\t\t\t<div className=\"hw-content-entries\">\n\t\t\t\t\t{entries.map((entry) => (\n\t\t\t\t\t\t<ContentEntryCard key={entry.slug} entry={entry} onSelect={onSelect} display={display} />\n\t\t\t\t\t))}\n\t\t\t\t\t{hasMore && (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"hw-content-load-more\"\n\t\t\t\t\t\t\tonClick={onLoadMore}\n\t\t\t\t\t\t\tdisabled={isLoading}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{isLoading ? t(\"widget.loading\") : t(\"widget.load_more\")}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// ── Entry Card — Intercom-style ──────────────────────────\n\nfunction truncateText(text: string | null, maxLen = 80): string {\n\tif (!text) return \"\";\n\tconst clean = text.replace(/[#*_`>\\[\\]!()-]/g, \"\").trim();\n\treturn clean.length > maxLen ? `${clean.slice(0, maxLen)}...` : clean;\n}\n\nfunction ContentEntryCard({\n\tentry,\n\tonSelect,\n\tdisplay,\n}: {\n\tentry: ContentEntryItem;\n\tonSelect: (slug: string) => void;\n\tdisplay?: ContentTabDisplay;\n}) {\n\tconst { customFields } = entry;\n\n\t// Use display mapping if configured, otherwise auto-detect from common field names\n\tconst badge = display?.badgeField\n\t\t? customFields[display.badgeField] ?? null\n\t\t: customFields.version ?? customFields.priority ?? customFields.type ?? null;\n\n\tconst subtitleValue = display?.subtitleField\n\t\t? (display.subtitleField === \"body\" ? entry.body : customFields[display.subtitleField]) ?? null\n\t\t: customFields.excerpt ?? customFields.summary ?? customFields.description ?? null;\n\n\tconst preview = subtitleValue ? truncateText(subtitleValue) : truncateText(entry.body);\n\n\treturn (\n\t\t<button type=\"button\" className=\"hw-content-entry\" onClick={() => onSelect(entry.slug)}>\n\t\t\t<div className=\"hw-content-entry-main\">\n\t\t\t\t<div className=\"hw-content-entry-text\">\n\t\t\t\t\t<span className=\"hw-content-entry-title\">{entry.title}</span>\n\t\t\t\t\t{preview && (\n\t\t\t\t\t\t<span className=\"hw-content-entry-desc\">{preview}</span>\n\t\t\t\t\t)}\n\t\t\t\t\t{(badge || entry.publishedAt) && (\n\t\t\t\t\t\t<div className=\"hw-content-entry-meta\">\n\t\t\t\t\t\t\t{badge && <span className=\"hw-content-entry-badge\">{badge}</span>}\n\t\t\t\t\t\t\t{entry.publishedAt && (\n\t\t\t\t\t\t\t\t<span className=\"hw-content-entry-date\">{formatRelativeTime(entry.publishedAt)}</span>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<svg className=\"hw-content-entry-chevron\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n\t\t\t\t\t<polyline points=\"9 18 15 12 9 6\" />\n\t\t\t\t</svg>\n\t\t\t</div>\n\t\t</button>\n\t);\n}\n","import type { WidgetContentTab } from \"@helpway/widget-core\";\nimport { t } from \"@helpway/widget-core\";\nimport { useEffect, useRef } from \"react\";\nimport { useGroupedContentTab } from \"../../hooks/use-grouped-content-tab\";\nimport type { ContentEntryItem } from \"../../hooks/use-content-tab\";\nimport { ContentDetailView } from \"./content-detail-view\";\nimport { ContentListView } from \"./content-list-view\";\n\n/**\n * Grouped content tab — category → items → detail drill-down.\n *\n * Three views managed by parent (DefaultWidget):\n * - subView = null → show categories\n * - subView = \"content-category\" → show items for activeCategory\n * - subView = \"content-detail\" → show item detail\n */\nexport function GroupedContentTabView({\n\ttab,\n\tsubView,\n\tdetailSlug,\n\tonSelectCategory,\n\tonSelectEntry,\n}: {\n\ttab: WidgetContentTab;\n\tsubView: string | null;\n\tdetailSlug: string | null;\n\tonSelectCategory: (category: ContentEntryItem) => void;\n\tonSelectEntry: (slug: string) => void;\n}) {\n\tconst {\n\t\tcategories,\n\t\tisCategoriesLoading,\n\t\titems,\n\t\tisItemsLoading,\n\t\titemsHasMore,\n\t\tactiveCategory,\n\t\tdetail,\n\t\tisLoadingDetail,\n\t\tinitFetch,\n\t\tselectCategory,\n\t\tsearchCategories,\n\t\tloadMoreItems,\n\t\tsearchItems,\n\t\tfetchDetail,\n\t\tclearCategory,\n\t} = useGroupedContentTab(tab.id);\n\n\t// Init fetch categories on mount\n\tuseEffect(() => {\n\t\tinitFetch();\n\t}, [initFetch]);\n\n\t// Fetch detail when slug changes\n\tuseEffect(() => {\n\t\tif (detailSlug && subView === \"content-detail\") {\n\t\t\tfetchDetail(detailSlug);\n\t\t}\n\t}, [detailSlug, subView, fetchDetail]);\n\n\t// Clean up hook state when navigating back to category list\n\tconst prevSubView = useRef(subView);\n\tuseEffect(() => {\n\t\tif (prevSubView.current === \"content-category\" && subView === null) {\n\t\t\tclearCategory();\n\t\t}\n\t\tprevSubView.current = subView;\n\t}, [subView, clearCategory]);\n\n\t// ── Detail view ──\n\tif (subView === \"content-detail\" && detailSlug) {\n\t\treturn <ContentDetailView entry={detail} isLoading={isLoadingDetail} />;\n\t}\n\n\t// ── Items list (within a category) ──\n\tif (subView === \"content-category\" && activeCategory) {\n\t\treturn (\n\t\t\t<ContentListView\n\t\t\t\tentries={items}\n\t\t\t\tisLoading={isItemsLoading}\n\t\t\t\thasMore={itemsHasMore}\n\t\t\t\tonSelect={onSelectEntry}\n\t\t\t\tonLoadMore={loadMoreItems}\n\t\t\t\tonSearch={searchItems}\n\t\t\t\tsearchPlaceholder={t(\"widget.search\")}\n\t\t\t\tdisplay={tab.display}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// ── Categories list (with search) ──\n\treturn (\n\t\t<ContentListView\n\t\t\tentries={categories}\n\t\t\tisLoading={isCategoriesLoading}\n\t\t\thasMore={false}\n\t\t\tonSelect={(slug) => {\n\t\t\t\tconst cat = categories.find((c) => c.slug === slug);\n\t\t\t\tif (cat) {\n\t\t\t\t\tselectCategory(cat);\n\t\t\t\t\tonSelectCategory(cat);\n\t\t\t\t}\n\t\t\t}}\n\t\t\tonLoadMore={() => {}}\n\t\t\tonSearch={searchCategories}\n\t\t\tsearchPlaceholder={t(\"widget.search\")}\n\t\t/>\n\t);\n}\n","import type { WidgetContentTab } from \"@helpway/widget-core\";\nimport { CONTENT_CACHE_TTL, getLocale } from \"@helpway/widget-core\";\nimport { useCallback, useRef, useState } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\nimport type { ContentEntryItem, ContentEntryDetail } from \"./use-content-tab\";\n\nconst EMPTY_TABS: WidgetContentTab[] = [];\n\n// ── Cache key helpers ──\n\nfunction categoriesKey(tabId: string, lang: string) {\n\treturn `grouped:${tabId}:${lang}:categories`;\n}\n\nfunction itemsKey(tabId: string, lang: string, groupSlug: string) {\n\treturn `grouped:${tabId}:${lang}:items:${groupSlug}`;\n}\n\nfunction detailKey(tabId: string, lang: string, slug: string) {\n\treturn `grouped:${tabId}:${lang}:detail:${slug}`;\n}\n\ninterface CachedItems {\n\titems: ContentEntryItem[];\n\thasMore: boolean;\n\tpage: number;\n}\n\nfunction readCache<T>(cache: Map<string, { data: unknown; ts: number }>, key: string): T | null {\n\tconst entry = cache.get(key);\n\tif (!entry) return null;\n\tif (Date.now() - entry.ts > CONTENT_CACHE_TTL) return null;\n\treturn entry.data as T;\n}\n\n/**\n * Hook for grouped content tabs (category → items drill-down).\n * Content is cached in the Zustand store so tab switches don't re-fetch.\n */\nexport function useGroupedContentTab(tabId: string) {\n\tconst { client, store } = useWidgetContext();\n\tconst contentTabs = useWidgetStore((s) => s.agentConfig?.contentTabs) ?? EMPTY_TABS;\n\tconst tab = contentTabs.find((t) => t.id === tabId) ?? null;\n\n\tconst lang = getLocale();\n\tconst cache = store.getState().contentCache;\n\n\t// ── Categories (top level) ──\n\tconst cachedCategories = readCache<ContentEntryItem[]>(cache, categoriesKey(tabId, lang));\n\tconst [categories, setCategories] = useState<ContentEntryItem[]>(cachedCategories ?? []);\n\tconst [isCategoriesLoading, setIsCategoriesLoading] = useState(false);\n\n\t// ── Items (within a category) ──\n\tconst [items, setItems] = useState<ContentEntryItem[]>([]);\n\tconst [isItemsLoading, setIsItemsLoading] = useState(false);\n\tconst [itemsHasMore, setItemsHasMore] = useState(false);\n\tconst itemsPageRef = useRef(1);\n\n\t// ── Detail (single item) ──\n\tconst [detail, setDetail] = useState<ContentEntryDetail | null>(null);\n\tconst [isLoadingDetail, setIsLoadingDetail] = useState(false);\n\n\t// ── Active category ──\n\tconst [activeCategory, setActiveCategory] = useState<ContentEntryItem | null>(null);\n\n\t// ── All categories (unfiltered, for client-side search) ──\n\tconst allCategoriesRef = useRef<ContentEntryItem[]>(cachedCategories ?? []);\n\n\t// ── Fetch categories ──\n\tconst fetchCategories = useCallback(async () => {\n\t\tif (!tab) return;\n\t\tsetIsCategoriesLoading(true);\n\t\ttry {\n\t\t\tconst result = await client.widget.getContent.query({\n\t\t\t\ttabId,\n\t\t\t\tpage: 1,\n\t\t\t\tlimit: 50,\n\t\t\t\tlanguage: getLocale(),\n\t\t\t});\n\t\t\tif (result.items) {\n\t\t\t\tallCategoriesRef.current = result.items;\n\t\t\t\tsetCategories(result.items);\n\t\t\t\tstore.getState().setContentCache(categoriesKey(tabId, getLocale()), result.items);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconsole.error(\"[useGroupedContentTab] categories error:\", err);\n\t\t} finally {\n\t\t\tsetIsCategoriesLoading(false);\n\t\t}\n\t}, [client, tabId, tab, store]);\n\n\t// Init — only fetch if cache was empty\n\tconst initFetch = useCallback(() => {\n\t\tif (tab && categories.length === 0) {\n\t\t\tfetchCategories();\n\t\t}\n\t}, [fetchCategories, tab, categories.length]);\n\n\t// ── Fetch items for a category ──\n\tconst fetchItems = useCallback(\n\t\tasync (opts?: { page?: number; search?: string; reset?: boolean; groupSlug?: string }) => {\n\t\t\tif (!tab?.itemsModelSlug) return;\n\t\t\tconst p = opts?.page ?? 1;\n\t\t\tconst reset = opts?.reset ?? p === 1;\n\n\t\t\tsetIsItemsLoading(true);\n\t\t\ttry {\n\t\t\t\tconst result = await client.widget.getContent.query({\n\t\t\t\t\ttabId,\n\t\t\t\t\tpage: p,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t\tsearch: opts?.search,\n\t\t\t\t\tgroupSlug: opts?.groupSlug,\n\t\t\t\t\titemsModel: tab.itemsModelSlug,\n\t\t\t\t\tlanguage: getLocale(),\n\t\t\t\t});\n\t\t\t\tif (result.items) {\n\t\t\t\t\tsetItems((prev) => {\n\t\t\t\t\t\tconst nextItems = reset ? result.items! : [...prev, ...result.items!];\n\t\t\t\t\t\tif (!opts?.search && opts?.groupSlug) {\n\t\t\t\t\t\t\tstore.getState().setContentCache(\n\t\t\t\t\t\t\t\titemsKey(tabId, getLocale(), opts.groupSlug),\n\t\t\t\t\t\t\t\t{ items: nextItems, hasMore: result.hasMore, page: p } satisfies CachedItems,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nextItems;\n\t\t\t\t\t});\n\t\t\t\t\tsetItemsHasMore(result.hasMore);\n\t\t\t\t\titemsPageRef.current = p;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useGroupedContentTab] items error:\", err);\n\t\t\t} finally {\n\t\t\t\tsetIsItemsLoading(false);\n\t\t\t}\n\t\t},\n\t\t[client, tabId, tab, store],\n\t);\n\n\t// ── Select a category → load items from cache or fetch ──\n\tconst selectCategory = useCallback(\n\t\t(category: ContentEntryItem) => {\n\t\t\tsetActiveCategory(category);\n\t\t\tsetDetail(null);\n\n\t\t\tconst cached = readCache<CachedItems>(\n\t\t\t\tstore.getState().contentCache,\n\t\t\t\titemsKey(tabId, getLocale(), category.slug),\n\t\t\t);\n\t\t\tif (cached) {\n\t\t\t\tsetItems(cached.items);\n\t\t\t\tsetItemsHasMore(cached.hasMore);\n\t\t\t\titemsPageRef.current = cached.page;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetItems([]);\n\t\t\tfetchItems({ page: 1, reset: true, groupSlug: category.slug });\n\t\t},\n\t\t[fetchItems, store, tabId],\n\t);\n\n\t// ── Load more items ──\n\tconst loadMoreItems = useCallback(() => {\n\t\tif (!itemsHasMore || isItemsLoading || !activeCategory) return;\n\t\tfetchItems({\n\t\t\tpage: itemsPageRef.current + 1,\n\t\t\tgroupSlug: activeCategory.slug,\n\t\t});\n\t}, [fetchItems, itemsHasMore, isItemsLoading, activeCategory]);\n\n\t// ── Search items (cross-category) ──\n\tconst searchItems = useCallback(\n\t\t(query: string) => {\n\t\t\tsetItems([]);\n\t\t\tfetchItems({\n\t\t\t\tpage: 1,\n\t\t\t\treset: true,\n\t\t\t\tsearch: query || undefined,\n\t\t\t\tgroupSlug: query ? undefined : activeCategory?.slug,\n\t\t\t});\n\t\t},\n\t\t[fetchItems, activeCategory],\n\t);\n\n\t// ── Fetch item detail ──\n\tconst fetchDetail = useCallback(\n\t\tasync (slug: string) => {\n\t\t\tif (!tab?.itemsModelSlug) return;\n\n\t\t\tconst cached = readCache<ContentEntryDetail>(\n\t\t\t\tstore.getState().contentCache,\n\t\t\t\tdetailKey(tabId, getLocale(), slug),\n\t\t\t);\n\t\t\tif (cached) {\n\t\t\t\tsetDetail(cached);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetIsLoadingDetail(true);\n\t\t\ttry {\n\t\t\t\tconst result = await client.widget.getContent.query({\n\t\t\t\t\ttabId,\n\t\t\t\t\tslug,\n\t\t\t\t\titemsModel: tab.itemsModelSlug,\n\t\t\t\t\tlanguage: getLocale(),\n\t\t\t\t});\n\t\t\t\tif (result.entry) {\n\t\t\t\t\tconst entry = result.entry as ContentEntryDetail;\n\t\t\t\t\tsetDetail(entry);\n\t\t\t\t\tstore.getState().setContentCache(\n\t\t\t\t\t\tdetailKey(tabId, getLocale(), slug),\n\t\t\t\t\t\tentry,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[useGroupedContentTab] detail error:\", err);\n\t\t\t} finally {\n\t\t\t\tsetIsLoadingDetail(false);\n\t\t\t}\n\t\t},\n\t\t[client, tabId, tab, store],\n\t);\n\n\t// ── Search categories (client-side, instant) ──\n\tconst searchCategories = useCallback(\n\t\t(query: string) => {\n\t\t\tif (!query.trim()) {\n\t\t\t\tsetCategories(allCategoriesRef.current);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst q = query.toLowerCase();\n\t\t\tsetCategories(\n\t\t\t\tallCategoriesRef.current.filter((cat) =>\n\t\t\t\t\tcat.title.toLowerCase().includes(q) ||\n\t\t\t\t\t(cat.customFields.description ?? \"\").toLowerCase().includes(q),\n\t\t\t\t),\n\t\t\t);\n\t\t},\n\t\t[],\n\t);\n\n\tconst clearDetail = useCallback(() => {\n\t\tsetDetail(null);\n\t}, []);\n\n\tconst clearCategory = useCallback(() => {\n\t\tsetActiveCategory(null);\n\t\tsetItems([]);\n\t\tsetDetail(null);\n\t}, []);\n\n\treturn {\n\t\ttab,\n\t\tcategories,\n\t\tisCategoriesLoading,\n\t\titems,\n\t\tisItemsLoading,\n\t\titemsHasMore,\n\t\tactiveCategory,\n\t\tdetail,\n\t\tisLoadingDetail,\n\t\tinitFetch,\n\t\tselectCategory,\n\t\tsearchCategories,\n\t\tloadMoreItems,\n\t\tsearchItems,\n\t\tfetchDetail,\n\t\tclearDetail,\n\t\tclearCategory,\n\t};\n}\n","import {\n\tBookIcon,\n\tHelpCircleIcon,\n\tLightbulbIcon,\n\tMegaphoneIcon,\n\tNewspaperIcon,\n\tStarIcon,\n} from \"../icons\";\n\n/**\n * Maps icon string keys to Central Icons components.\n * Dashboard lets users pick from this set when configuring a content tab.\n * Falls back to BookIcon for unknown keys.\n */\nconst ICON_MAP: Record<string, React.FC> = {\n\tbook: BookIcon,\n\tmegaphone: MegaphoneIcon,\n\tlightbulb: LightbulbIcon,\n\t\"help-circle\": HelpCircleIcon,\n\tnewspaper: NewspaperIcon,\n\tstar: StarIcon,\n};\n\nexport function ContentTabIconComponent({ icon }: { icon: string }) {\n\tconst Icon = ICON_MAP[icon] ?? BookIcon;\n\treturn <Icon />;\n}\n","import type { TimelineItem } from \"@helpway/types\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useWidgetContext, useWidgetStore } from \"../provider\";\n\ninterface DebugEvent {\n\tid: string;\n\tt: number;\n\tkind: \"trpc\" | \"ws\" | \"store\" | \"error\";\n\tlabel: string;\n\tdetail?: string;\n}\n\nconst MAX_EVENTS = 60;\n\nfunction isDebugEnabled(): boolean {\n\tif (typeof window === \"undefined\") return false;\n\tif (typeof window.localStorage !== \"undefined\" && window.localStorage.getItem(\"hw:debug\") === \"1\") {\n\t\treturn true;\n\t}\n\tconst search = window.location?.search ?? \"\";\n\treturn search.includes(\"hwdebug=1\") || search.includes(\"debug=hw\");\n}\n\nfunction senderOf(item: TimelineItem): string {\n\tif (item.visitorId) return \"visitor\";\n\tif (item.aiAgentId) return \"ai\";\n\tif (item.userId) return \"team\";\n\treturn item.type;\n}\n\nexport function WidgetDebugOverlay() {\n\tconst [enabled, setEnabled] = useState(false);\n\tconst [open, setOpen] = useState(true);\n\tconst [events, setEvents] = useState<DebugEvent[]>([]);\n\tconst eventsRef = useRef<DebugEvent[]>([]);\n\n\t// Subscribe to each field individually — returning a fresh object from a\n\t// selector triggers an infinite re-render loop with zustand because each\n\t// render produces a new object reference.\n\tconst activeId = useWidgetStore((s) => s.activeConversationId);\n\tconst messagesMap = useWidgetStore((s) => s.messages);\n\tconst typingUsers = useWidgetStore((s) => s.typingUsers);\n\tconst aiProcessingMap = useWidgetStore((s) => s.aiProcessing);\n\tconst { store } = useWidgetContext();\n\n\tuseEffect(() => {\n\t\tsetEnabled(isDebugEnabled());\n\t}, []);\n\n\tconst pushEvent = useMemo(\n\t\t() => (ev: Omit<DebugEvent, \"id\" | \"t\">) => {\n\t\t\tconst e: DebugEvent = {\n\t\t\t\t...ev,\n\t\t\t\tid: `${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n\t\t\t\tt: Date.now(),\n\t\t\t};\n\t\t\teventsRef.current = [e, ...eventsRef.current].slice(0, MAX_EVENTS);\n\t\t\tsetEvents(eventsRef.current);\n\t\t},\n\t\t[],\n\t);\n\n\t// Intercept fetch to log tRPC calls — works with any tRPC proxy shape\n\t// because we observe at the network boundary, not the client object.\n\tuseEffect(() => {\n\t\tif (!enabled) return;\n\t\tif (typeof window === \"undefined\" || typeof window.fetch !== \"function\") return;\n\t\tconst originalFetch = window.fetch.bind(window);\n\t\tconst patched = (async (input: RequestInfo | URL, init?: RequestInit) => {\n\t\t\tconst url = typeof input === \"string\" ? input : input instanceof URL ? input.toString() : input.url;\n\t\t\tconst isTrpc = url.includes(\"/trpc/\");\n\t\t\tif (isTrpc) {\n\t\t\t\tconst method = init?.method ?? (typeof input !== \"string\" && !(input instanceof URL) ? input.method : \"GET\");\n\t\t\t\tconst label = url.split(\"/trpc/\")[1]?.split(\"?\")[0] ?? url;\n\t\t\t\tpushEvent({ kind: \"trpc\", label: `→ ${method} ${label}`, detail: shortJson(init?.body) });\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst res = await originalFetch(input, init);\n\t\t\t\tif (isTrpc) {\n\t\t\t\t\tconst label = url.split(\"/trpc/\")[1]?.split(\"?\")[0] ?? url;\n\t\t\t\t\tpushEvent({ kind: \"trpc\", label: `← ${res.status} ${label}` });\n\t\t\t\t}\n\t\t\t\treturn res;\n\t\t\t} catch (err) {\n\t\t\t\tif (isTrpc) {\n\t\t\t\t\tconst label = url.split(\"/trpc/\")[1]?.split(\"?\")[0] ?? url;\n\t\t\t\t\tpushEvent({ kind: \"error\", label: `✘ ${label}`, detail: err instanceof Error ? err.message : String(err) });\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t}) as unknown as typeof window.fetch;\n\t\twindow.fetch = patched;\n\t\treturn () => {\n\t\t\twindow.fetch = originalFetch;\n\t\t};\n\t}, [enabled, pushEvent]);\n\n\t// Tap WebSocket events by wrapping the store's handleRealtimeEvent\n\tuseEffect(() => {\n\t\tif (!enabled) return;\n\t\tconst original = store.getState().handleRealtimeEvent;\n\t\tstore.setState({\n\t\t\thandleRealtimeEvent: (ev) => {\n\t\t\t\tpushEvent({ kind: \"ws\", label: ev.type, detail: shortJson(ev) });\n\t\t\t\toriginal(ev);\n\t\t\t},\n\t\t});\n\t\treturn () => {\n\t\t\tstore.setState({ handleRealtimeEvent: original });\n\t\t};\n\t}, [enabled, store, pushEvent]);\n\n\t// Emit a marker when messages array changes for the active conversation\n\tconst activeMessages = activeId ? messagesMap.get(activeId) ?? [] : [];\n\tconst lastMsgSignature = useMemo(\n\t\t() => activeMessages.map((m) => `${m.id}:${senderOf(m)}:${m.createdAt}`).join(\"|\"),\n\t\t[activeMessages],\n\t);\n\tconst prevSigRef = useRef(lastMsgSignature);\n\tuseEffect(() => {\n\t\tif (!enabled) return;\n\t\tif (prevSigRef.current !== lastMsgSignature) {\n\t\t\tprevSigRef.current = lastMsgSignature;\n\t\t\tpushEvent({\n\t\t\t\tkind: \"store\",\n\t\t\t\tlabel: `messages[${activeMessages.length}]`,\n\t\t\t\tdetail: activeMessages\n\t\t\t\t\t.map((m, i) => `${i}:${senderOf(m)}=${(m.text ?? \"\").slice(0, 24)}`)\n\t\t\t\t\t.join(\" | \"),\n\t\t\t});\n\t\t}\n\t}, [lastMsgSignature, activeMessages, enabled, pushEvent]);\n\n\tif (!enabled) return null;\n\n\tconst isTyping = activeId ? typingUsers.get(activeId) : false;\n\tconst isAi = activeId ? aiProcessingMap.get(activeId) : false;\n\n\treturn (\n\t\t<div style={styles.wrap}>\n\t\t\t<div style={styles.header}>\n\t\t\t\t<strong>hw debug</strong>\n\t\t\t\t<span style={styles.meta}>\n\t\t\t\t\t{\" \"}· conv {activeId ? activeId.slice(0, 10) : \"—\"} · items {activeMessages.length} · typing {isTyping ? \"Y\" : \"n\"} · ai {isAi ? \"Y\" : \"n\"}\n\t\t\t\t</span>\n\t\t\t\t<button type=\"button\" style={styles.btn} onClick={() => setOpen((v) => !v)}>{open ? \"hide\" : \"show\"}</button>\n\t\t\t\t<button type=\"button\" style={styles.btn} onClick={() => { eventsRef.current = []; setEvents([]); }}>clear</button>\n\t\t\t</div>\n\t\t\t{open && (\n\t\t\t\t<div style={styles.body}>\n\t\t\t\t\t<div style={styles.section}>\n\t\t\t\t\t\t<div style={styles.sectionTitle}>messages (active)</div>\n\t\t\t\t\t\t{activeMessages.length === 0 ? (\n\t\t\t\t\t\t\t<div style={styles.empty}>empty</div>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tactiveMessages.map((m, i) => (\n\t\t\t\t\t\t\t\t<div key={m.id} style={styles.row}>\n\t\t\t\t\t\t\t\t\t<span style={{ ...styles.badge, background: colorFor(senderOf(m)) }}>{i}</span>\n\t\t\t\t\t\t\t\t\t<span style={styles.sender}>{senderOf(m)}</span>\n\t\t\t\t\t\t\t\t\t<span style={styles.ts}>{m.createdAt.slice(11, 23)}</span>\n\t\t\t\t\t\t\t\t\t<span style={styles.text}>{(m.text ?? \"\").slice(0, 60)}</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style={styles.section}>\n\t\t\t\t\t\t<div style={styles.sectionTitle}>events</div>\n\t\t\t\t\t\t{events.length === 0 ? (\n\t\t\t\t\t\t\t<div style={styles.empty}>no events yet — send a message</div>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tevents.map((e) => (\n\t\t\t\t\t\t\t\t<div key={e.id} style={styles.row}>\n\t\t\t\t\t\t\t\t\t<span style={{ ...styles.badge, background: kindColor(e.kind) }}>{e.kind}</span>\n\t\t\t\t\t\t\t\t\t<span style={styles.ts}>{new Date(e.t).toISOString().slice(11, 23)}</span>\n\t\t\t\t\t\t\t\t\t<span style={styles.evLabel}>{e.label}</span>\n\t\t\t\t\t\t\t\t\t{e.detail && <span style={styles.detail}>{e.detail}</span>}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction shortJson(v: unknown): string {\n\tif (v === undefined) return \"\";\n\ttry {\n\t\tconst s = JSON.stringify(v);\n\t\tif (!s) return \"\";\n\t\treturn s.length > 180 ? `${s.slice(0, 177)}…` : s;\n\t} catch {\n\t\treturn String(v);\n\t}\n}\n\nfunction colorFor(sender: string): string {\n\tswitch (sender) {\n\t\tcase \"visitor\":\n\t\t\treturn \"#1d4ed8\";\n\t\tcase \"ai\":\n\t\t\treturn \"#7c3aed\";\n\t\tcase \"team\":\n\t\t\treturn \"#16a34a\";\n\t\tdefault:\n\t\t\treturn \"#6b7280\";\n\t}\n}\n\nfunction kindColor(kind: DebugEvent[\"kind\"]): string {\n\tswitch (kind) {\n\t\tcase \"trpc\":\n\t\t\treturn \"#0ea5e9\";\n\t\tcase \"ws\":\n\t\t\treturn \"#f97316\";\n\t\tcase \"store\":\n\t\t\treturn \"#64748b\";\n\t\tcase \"error\":\n\t\t\treturn \"#dc2626\";\n\t}\n}\n\nconst styles: Record<string, React.CSSProperties> = {\n\twrap: {\n\t\tposition: \"fixed\",\n\t\tright: 12,\n\t\tbottom: 12,\n\t\tzIndex: 2147483000,\n\t\twidth: 420,\n\t\tmaxHeight: \"70vh\",\n\t\tbackground: \"rgba(9,9,11,0.94)\",\n\t\tcolor: \"#e5e7eb\",\n\t\tborderRadius: 10,\n\t\tfontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n\t\tfontSize: 11,\n\t\tboxShadow: \"0 12px 30px rgba(0,0,0,0.35)\",\n\t\toverflow: \"hidden\",\n\t\tpointerEvents: \"auto\",\n\t},\n\theader: {\n\t\tdisplay: \"flex\",\n\t\talignItems: \"center\",\n\t\tgap: 6,\n\t\tpadding: \"6px 10px\",\n\t\tbackground: \"#18181b\",\n\t\tborderBottom: \"1px solid #27272a\",\n\t},\n\tmeta: { flex: 1, color: \"#a1a1aa\", fontSize: 10 },\n\tbtn: {\n\t\tbackground: \"#27272a\",\n\t\tcolor: \"#e4e4e7\",\n\t\tborder: \"1px solid #3f3f46\",\n\t\tborderRadius: 4,\n\t\tpadding: \"2px 8px\",\n\t\tcursor: \"pointer\",\n\t\tfontSize: 10,\n\t},\n\tbody: { display: \"flex\", flexDirection: \"column\", maxHeight: \"calc(70vh - 32px)\", overflow: \"auto\" },\n\tsection: { borderBottom: \"1px solid #27272a\", padding: \"6px 10px\" },\n\tsectionTitle: { color: \"#a1a1aa\", fontSize: 10, textTransform: \"uppercase\", letterSpacing: 0.6, marginBottom: 4 },\n\trow: {\n\t\tdisplay: \"grid\",\n\t\tgridTemplateColumns: \"32px 56px 72px 1fr\",\n\t\tgap: 6,\n\t\talignItems: \"baseline\",\n\t\tpadding: \"2px 0\",\n\t\tborderTop: \"1px dashed #27272a\",\n\t},\n\tbadge: {\n\t\tdisplay: \"inline-block\",\n\t\tborderRadius: 3,\n\t\tpadding: \"1px 4px\",\n\t\tcolor: \"white\",\n\t\tfontSize: 9,\n\t\ttextAlign: \"center\",\n\t},\n\tsender: { color: \"#d4d4d8\" },\n\tts: { color: \"#71717a\", fontSize: 10 },\n\ttext: { color: \"#e4e4e7\", whiteSpace: \"nowrap\", overflow: \"hidden\", textOverflow: \"ellipsis\" },\n\tevLabel: { color: \"#e4e4e7\" },\n\tdetail: { gridColumn: \"1 / -1\", color: \"#a1a1aa\", fontSize: 10, whiteSpace: \"pre-wrap\", wordBreak: \"break-all\" },\n\tempty: { color: \"#52525b\", fontStyle: \"italic\", fontSize: 10 },\n};\n","import type { LinkPreviewPart, TimelineItemMetadata, TimelineItemPart } from \"@helpway/types\";\nimport { t } from \"@helpway/widget-core\";\nimport { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { closeDanglingMarkdown, handleCodeBlockClick, linkifyText, renderMarkdown } from \"./content/simple-markdown\";\n\ninterface MessageBubbleProps {\n\ttext: string;\n\tsender: \"visitor\" | \"team\" | \"ai\";\n\t/**\n\t * Explicit label for the meta row, overriding the sender's role. The widget's\n\t * own timeline never passes this — it labels by role — but a caller embedding\n\t * a single bubble may need to name someone.\n\t */\n\tsenderName?: string;\n\tparts?: TimelineItemPart[] | null;\n\ttimestamp?: string;\n\t/**\n\t * Whether this message closes a run from the same sender — the point where\n\t * the author's name belongs. Kept separate from `timestamp` so a clock label\n\t * that would only repeat the one above it can be dropped without taking the\n\t * signature with it.\n\t */\n\tshowAuthor?: boolean;\n\t/** Variant payload for interactive messages (quick replies, …). */\n\tmetadata?: TimelineItemMetadata | null;\n\t/** Called when the visitor taps a quick-reply option. */\n\tonQuickReplyTap?: (optionId: string, stepId: string) => void;\n\t/**\n\t * This bubble is a stream still arriving. Closes dangling markdown so an\n\t * unfinished ```fence does not flash as literal backticks, and shows the\n\t * caret.\n\t *\n\t * The stream is rendered through THIS component, not a hand-rolled copy of\n\t * its markup, so that the streamed bubble and the message that replaces it are\n\t * the same element type under the same key — React then reuses the DOM node\n\t * instead of tearing it down and mounting a replacement, which is what made\n\t * the answer visibly render a second time the moment it finished.\n\t */\n\tstreaming?: boolean;\n}\n\n/** Single message bubble — Intercom-style, renders text + image/file parts */\nexport function MessageBubble({\n\ttext,\n\tsender,\n\tsenderName,\n\tparts,\n\ttimestamp,\n\tshowAuthor,\n\tmetadata,\n\tonQuickReplyTap,\n\tstreaming,\n}: MessageBubbleProps) {\n\tconst senderClass = `hw-msg--${sender}`;\n\tconst bubbleRef = useRef<HTMLDivElement>(null);\n\n\tconst imageParts =\n\t\tparts?.filter((p): p is Extract<TimelineItemPart, { type: \"image\" }> => p.type === \"image\") ??\n\t\t[];\n\tconst fileParts =\n\t\tparts?.filter((p): p is Extract<TimelineItemPart, { type: \"file\" }> => p.type === \"file\") ?? [];\n\tconst linkPreviews =\n\t\tparts?.filter(\n\t\t\t(p): p is Extract<TimelineItemPart, { type: \"link-preview\" }> => p.type === \"link-preview\",\n\t\t) ?? [];\n\t// Where the answer came from. Shown as a short numbered list under the\n\t// message rather than a footnote block, so the visitor can check the\n\t// claim without leaving the thread.\n\tconst sources =\n\t\tparts?.filter(\n\t\t\t(p): p is Extract<TimelineItemPart, { type: \"source\" }> => p.type === \"source\",\n\t\t) ?? [];\n\tconst hasText = text.length > 0;\n\n\tuseEffect(() => {\n\t\tconst bubble = bubbleRef.current;\n\t\tif (!bubble || (sender !== \"ai\" && sender !== \"team\")) return;\n\t\tconst handleClick = (event: Event) => {\n\t\t\thandleCodeBlockClick(event, bubble);\n\t\t};\n\t\tbubble.addEventListener(\"click\", handleClick);\n\t\treturn () => {\n\t\t\tbubble.removeEventListener(\"click\", handleClick);\n\t\t};\n\t}, [sender]);\n\n\n\treturn (\n\t\t<div className={`hw-msg ${senderClass}`}>\n\t\t\t<div className=\"hw-msg-body\">\n\t\t\t\t{/* Image attachments */}\n\t\t\t\t{imageParts.length > 0 && (\n\t\t\t\t\t<div className=\"hw-msg-images\">\n\t\t\t\t\t\t{imageParts.map((img, i) => (\n\t\t\t\t\t\t\t<PreviewableThumbnail key={i} src={img.url} />\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t{/* Text bubble.\n\t\t\t\t - AI + team messages → renderMarkdown (team composer uses Tiptap → markdown output).\n\t\t\t\t - Visitor messages → linkifyText (widget composer is plain text).\n\t\t\t\t renderMarkdown escapes HTML entities first (&, <, >), so raw HTML cannot be injected.\n\t\t\t\t See packages/widget-react/src/themed/content/simple-markdown.ts for the safety guarantee. */}\n\t\t\t\t{hasText && (\n\t\t\t\t\t<div className=\"hw-msg-bubble\" ref={bubbleRef}>\n\t\t\t\t\t\t{sender === \"ai\" || sender === \"team\" ? (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t\t\t\t\t\t__html: renderMarkdown(streaming ? closeDanglingMarkdown(text) : text),\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<span dangerouslySetInnerHTML={{ __html: linkifyText(text) }} />\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{streaming && <span className=\"hw-streaming-cursor\" />}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t{/* File attachments */}\n\t\t\t\t{fileParts.length > 0 && (\n\t\t\t\t\t<div className=\"hw-msg-files\">\n\t\t\t\t\t\t{fileParts.map((file, i) => (\n\t\t\t\t\t\t\t<FileCard key={i} file={file} />\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t{/* Link preview cards */}\n\t\t\t\t{linkPreviews.length > 0 && (\n\t\t\t\t\t<div className=\"hw-msg-links\">\n\t\t\t\t\t\t{linkPreviews.map((lp, i) => (\n\t\t\t\t\t\t\t<LinkPreviewCard key={i} preview={lp} />\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t{/* Sources for the answer above */}\n\t\t\t\t{sources.length > 0 && (\n\t\t\t\t\t<div className=\"hw-sources\">\n\t\t\t\t\t\t{sources.map((src, i) =>\n\t\t\t\t\t\t\tsrc.sourceUrl ? (\n\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\tkey={src.knowledgeId}\n\t\t\t\t\t\t\t\t\thref={src.sourceUrl}\n\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\tclassName=\"hw-source\"\n\t\t\t\t\t\t\t\t\tonClick={(e) => e.stopPropagation()}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span className=\"hw-source-n\">{i + 1}</span>\n\t\t\t\t\t\t\t\t\t<span className=\"hw-source-title\">{src.title}</span>\n\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<div key={src.knowledgeId} className=\"hw-source\">\n\t\t\t\t\t\t\t\t\t<span className=\"hw-source-n\">{i + 1}</span>\n\t\t\t\t\t\t\t\t\t<span className=\"hw-source-title\">{src.title}</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\n\t\t\t\t{/* Quick reply buttons — workflow is paused awaiting visitor input.\n\t\t\t\t Disabled when metadata.cancelled is set (visitor typed instead). */}\n\t\t\t\t{metadata?.kind === \"quick_replies\" && (\n\t\t\t\t\t<QuickReplyButtons metadata={metadata} onTap={onQuickReplyTap} />\n\t\t\t\t)}\n\n\t\t\t\t{/* Clock only, last message of a run.\n\n\t\t\t\t This row has now been wrong three ways, and the third is worth\n\t\t\t\t recording so it does not come back. Printing the sender's NAME\n\t\t\t\t repeated whoever the header already showed. Printing nothing left the\n\t\t\t\t clock alone under a paragraph, reading as debris. Printing the ROLE —\n\t\t\t\t \"AI agent\" — was the answer to a question the reader had already\n\t\t\t\t answered: they opened a chat widget whose header carries the agent's\n\t\t\t\t name and avatar, so being told an agent replied is not news either.\n\t\t\t\t Tested on a real thread it reads as a label with nothing to label.\n\n\t\t\t\t So the row carries the one thing that is genuinely not on screen\n\t\t\t\t anywhere else: when the message arrived. And since a repeated clock\n\t\t\t\t is dropped upstream, most runs end with no row at all — which is the\n\t\t\t\t correct amount of chrome under an answer.\n\n\t\t\t\t `senderName` still overrides, for a caller rendering one bubble\n\t\t\t\t outside the timeline; the timeline itself never passes it. */}\n\t\t\t\t{(() => {\n\t\t\t\t\tconst isVisitor = sender === \"visitor\";\n\t\t\t\t\tconst lead = isVisitor ? null : (senderName ?? null);\n\t\t\t\t\tconst withLead = (showAuthor ?? !!timestamp) && !!lead;\n\t\t\t\t\tif (!withLead && !timestamp) return null;\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div className=\"hw-msg-meta\">\n\t\t\t\t\t\t\t{withLead && <span className=\"hw-msg-author\">{lead}</span>}\n\t\t\t\t\t\t\t{withLead && timestamp && <span className=\"hw-msg-meta-sep\">·</span>}\n\t\t\t\t\t\t\t{timestamp && <span className=\"hw-msg-time\">{timestamp}</span>}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t);\n\t\t\t\t})()}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ── Quick reply buttons (interactive workflow) ────────\n\nfunction QuickReplyButtons({\n\tmetadata,\n\tonTap,\n}: {\n\tmetadata: Extract<TimelineItemMetadata, { kind: \"quick_replies\" }>;\n\tonTap?: (optionId: string, stepId: string) => void;\n}) {\n\tconst [tappedId, setTappedId] = useState<string | null>(null);\n\tconst isLocked = metadata.cancelled || tappedId !== null;\n\n\tconst handleTap = (optionId: string) => {\n\t\tif (isLocked) return;\n\t\tsetTappedId(optionId);\n\t\tonTap?.(optionId, metadata.stepId);\n\t};\n\n\treturn (\n\t\t<div\n\t\t\tclassName=\"hw-quick-replies\"\n\t\t\tdata-cancelled={metadata.cancelled ? \"true\" : undefined}\n\t\t>\n\t\t\t{metadata.options.map((opt) => {\n\t\t\t\tconst isTapped = tappedId === opt.id;\n\t\t\t\treturn (\n\t\t\t\t\t<button\n\t\t\t\t\t\tkey={opt.id}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"hw-quick-reply-btn\"\n\t\t\t\t\t\tdata-tapped={isTapped ? \"true\" : undefined}\n\t\t\t\t\t\tdisabled={isLocked}\n\t\t\t\t\t\tonClick={() => handleTap(opt.id)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{opt.label}\n\t\t\t\t\t</button>\n\t\t\t\t);\n\t\t\t})}\n\t\t</div>\n\t);\n}\n\n// ── Previewable thumbnail (image) ────────────────\n\nfunction PreviewableThumbnail({ src }: { src: string }) {\n\tconst [hover, setHover] = useState(false);\n\tconst ref = useRef<HTMLAnchorElement>(null);\n\n\treturn (\n\t\t<>\n\t\t\t<a\n\t\t\t\tref={ref}\n\t\t\t\thref={src}\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tclassName=\"hw-msg-image-link\"\n\t\t\t\taria-label={t(\"widget.aria_open_image\")}\n\t\t\t\tonMouseEnter={() => setHover(true)}\n\t\t\t\tonMouseLeave={() => setHover(false)}\n\t\t\t>\n\t\t\t\t{/* alt=\"\" is right — the image is decorative inside a labelled\n\t\t\t\t link — but that leaves the anchor itself nameless, so the\n\t\t\t\t label goes on the anchor. */}\n\t\t\t\t<img src={src} alt=\"\" className=\"hw-msg-image\" loading=\"lazy\" />\n\t\t\t</a>\n\t\t\t{hover && <AnchoredPreview src={src} anchorRef={ref} href={src} />}\n\t\t</>\n\t);\n}\n\n// ── File card with hover preview for previewable types ───\n\nconst PREVIEWABLE_EXTS = new Set([\"pdf\", \"csv\", \"png\", \"jpg\", \"jpeg\", \"gif\", \"webp\", \"svg\"]);\n\nfunction FileCard({ file }: { file: Extract<TimelineItemPart, { type: \"file\" }> }) {\n\tconst [hover, setHover] = useState(false);\n\tconst ref = useRef<HTMLAnchorElement>(null);\n\tconst ext = file.fileName.split(\".\").pop()?.toLowerCase() ?? \"\";\n\tconst isPreviewable = PREVIEWABLE_EXTS.has(ext);\n\tconst isImage = file.mimeType.startsWith(\"image/\");\n\n\treturn (\n\t\t<>\n\t\t\t<a\n\t\t\t\tref={ref}\n\t\t\t\thref={file.url}\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tclassName=\"hw-msg-file\"\n\t\t\t\tonMouseEnter={() => isPreviewable && setHover(true)}\n\t\t\t\tonMouseLeave={() => setHover(false)}\n\t\t\t>\n\t\t\t\t<span className=\"hw-msg-file-icon\">\n\t\t\t\t\t<FileTypeIcon ext={ext} />\n\t\t\t\t</span>\n\t\t\t\t<span className=\"hw-msg-file-info\">\n\t\t\t\t\t<span className=\"hw-msg-file-name\">{file.fileName}</span>\n\t\t\t\t\t<span className=\"hw-msg-file-size\">{formatFileSize(file.fileSize)}</span>\n\t\t\t\t</span>\n\t\t\t</a>\n\t\t\t{hover &&\n\t\t\t\tisPreviewable &&\n\t\t\t\t(isImage ? (\n\t\t\t\t\t<AnchoredPreview src={file.url} anchorRef={ref} href={file.url} />\n\t\t\t\t) : (\n\t\t\t\t\t<AnchoredDocPreview fileName={file.fileName} ext={ext} anchorRef={ref} href={file.url} />\n\t\t\t\t))}\n\t\t</>\n\t);\n}\n\n// ── Anchored preview — card popover above the element ──\n\nexport function AnchoredPreview({\n\tsrc,\n\tanchorRef,\n\thref,\n\tonOpen,\n}: {\n\tsrc: string;\n\tanchorRef: React.RefObject<HTMLElement | null>;\n\thref?: string;\n\tonOpen?: () => void;\n}) {\n\tconst [style, setStyle] = useState<React.CSSProperties>({ opacity: 0 });\n\tconst [portalTarget, setPortalTarget] = useState<Element | DocumentFragment | null>(null);\n\n\tuseLayoutEffect(() => {\n\t\tconst anchor = anchorRef.current;\n\t\tif (!anchor) return;\n\n\t\tconst rect = anchor.getBoundingClientRect();\n\t\tconst pw = 260;\n\t\tconst gap = 8;\n\t\tconst vw = window.innerWidth;\n\n\t\tlet left = rect.left + rect.width / 2 - pw / 2;\n\t\tif (left < 8) left = 8;\n\t\tif (left + pw > vw - 8) left = vw - pw - 8;\n\n\t\tconst estimatedH = 200;\n\t\tlet top = rect.top - estimatedH - gap;\n\t\tif (top < 8) top = rect.bottom + gap;\n\n\t\tsetStyle({ left, top, width: pw, opacity: 1 });\n\t\t// Portal into the same root as the anchor so shadow-DOM widgets keep\n\t\t// --hw-* CSS token inheritance and the preview participates in the\n\t\t// widget's z-index stack. Falls back to document.body when the widget\n\t\t// isn't shadow-encapsulated.\n\t\tconst root = anchor.getRootNode();\n\t\tsetPortalTarget(root instanceof ShadowRoot ? root : document.body);\n\t}, [anchorRef]);\n\n\tconst handleClick = () => {\n\t\tif (onOpen) onOpen();\n\t\t// noopener: without it the opened page gets a handle on window.opener\n\t\t// and can navigate the host page out from under the visitor.\n\t\telse if (href) window.open(href, \"_blank\", \"noopener,noreferrer\");\n\t};\n\n\tif (!portalTarget) return null;\n\n\treturn createPortal(\n\t\t<div className=\"hw-hover-preview\" style={style} onClick={handleClick}>\n\t\t\t<img src={src} alt=\"\" className=\"hw-hover-preview-img\" />\n\t\t</div>,\n\t\tportalTarget,\n\t);\n}\n\n// ── Document preview popover (PDF, CSV) ──────────\n\nfunction AnchoredDocPreview({\n\tfileName,\n\text,\n\tanchorRef,\n\thref,\n}: {\n\tfileName: string;\n\text: string;\n\tanchorRef: React.RefObject<HTMLElement | null>;\n\thref: string;\n}) {\n\tconst [style, setStyle] = useState<React.CSSProperties>({ opacity: 0 });\n\tconst [portalTarget, setPortalTarget] = useState<Element | DocumentFragment | null>(null);\n\n\tuseLayoutEffect(() => {\n\t\tconst anchor = anchorRef.current;\n\t\tif (!anchor) return;\n\n\t\tconst rect = anchor.getBoundingClientRect();\n\t\tconst pw = 220;\n\t\tconst ph = 80;\n\t\tconst gap = 8;\n\t\tconst vw = window.innerWidth;\n\n\t\tlet left = rect.left + rect.width / 2 - pw / 2;\n\t\tif (left < 8) left = 8;\n\t\tif (left + pw > vw - 8) left = vw - pw - 8;\n\n\t\tlet top = rect.top - ph - gap;\n\t\tif (top < 8) top = rect.bottom + gap;\n\n\t\tsetStyle({ left, top, width: pw, opacity: 1 });\n\t\tconst root = anchor.getRootNode();\n\t\tsetPortalTarget(root instanceof ShadowRoot ? root : document.body);\n\t}, [anchorRef]);\n\n\tif (!portalTarget) return null;\n\n\treturn createPortal(\n\t\t<div\n\t\t\tclassName=\"hw-hover-preview hw-hover-preview--doc\"\n\t\t\tstyle={style}\n\t\t\tonClick={() => window.open(href, \"_blank\", \"noopener,noreferrer\")}\n\t\t>\n\t\t\t<div className=\"hw-hover-preview-doc-icon\">\n\t\t\t\t<FileTypeIcon ext={ext} />\n\t\t\t</div>\n\t\t\t<div className=\"hw-hover-preview-doc-info\">\n\t\t\t\t<span className=\"hw-hover-preview-doc-name\">{fileName}</span>\n\t\t\t\t<span className=\"hw-hover-preview-doc-hint\">{t(\"widget.click_to_open\")}</span>\n\t\t\t</div>\n\t\t</div>,\n\t\tportalTarget,\n\t);\n}\n\n// ── Helpers ──────────────────────────────────────\n\nfunction formatFileSize(bytes: number): string {\n\tif (bytes < 1024) return `${bytes} B`;\n\tif (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} KB`;\n\treturn `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n// Module scope: the palette never varies, so rebuilding it per render was\n// allocation for nothing.\nconst FILE_TYPE_COLORS: Record<string, string> = {\n\tpdf: \"#ef4444\",\n\tcsv: \"#22c55e\",\n\tdoc: \"#3b82f6\",\n\tdocx: \"#3b82f6\",\n\txls: \"#22c55e\",\n\txlsx: \"#22c55e\",\n\ttxt: \"#6b7280\",\n\tzip: \"#f59e0b\",\n};\n\nfunction FileTypeIcon({ ext }: { ext: string }) {\n\tconst color = FILE_TYPE_COLORS[ext] ?? \"currentColor\";\n\n\treturn (\n\t\t<svg\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke={color}\n\t\t\tstrokeWidth={1.5}\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t>\n\t\t\t<path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n\t\t\t<polyline points=\"14 2 14 8 20 8\" />\n\t\t\t{ext === \"pdf\" && (\n\t\t\t\t<text x=\"8\" y=\"18\" fontSize=\"6\" fill={color} stroke=\"none\" fontWeight=\"700\">\n\t\t\t\t\tPDF\n\t\t\t\t</text>\n\t\t\t)}\n\t\t\t{ext === \"csv\" && (\n\t\t\t\t<text x=\"7\" y=\"18\" fontSize=\"6\" fill={color} stroke=\"none\" fontWeight=\"700\">\n\t\t\t\t\tCSV\n\t\t\t\t</text>\n\t\t\t)}\n\t\t</svg>\n\t);\n}\n\n// ── Link preview card (Intercom-style) ──────────────\n\nfunction LinkPreviewCard({ preview }: { preview: LinkPreviewPart }) {\n\tconst hostname = (() => {\n\t\ttry { return new URL(preview.url).hostname; } catch { return preview.url; }\n\t})();\n\treturn (\n\t\t<a\n\t\t\thref={preview.url}\n\t\t\ttarget=\"_blank\"\n\t\t\trel=\"noopener noreferrer\"\n\t\t\tclassName=\"hw-link-preview\"\n\t\t\tonClick={(e) => e.stopPropagation()}\n\t\t>\n\t\t\t{preview.imageUrl && (\n\t\t\t\t<img\n\t\t\t\t\tsrc={preview.imageUrl}\n\t\t\t\t\talt=\"\"\n\t\t\t\t\tclassName=\"hw-link-preview-img\"\n\t\t\t\t\tloading=\"lazy\"\n\t\t\t\t\tonError={(e) => { (e.target as HTMLImageElement).style.display = \"none\"; }}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<div className=\"hw-link-preview-body\">\n\t\t\t\t{preview.favicon && (\n\t\t\t\t\t<img\n\t\t\t\t\t\tsrc={preview.favicon}\n\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\tclassName=\"hw-link-preview-favicon\"\n\t\t\t\t\t\twidth={16}\n\t\t\t\t\t\theight={16}\n\t\t\t\t\t\tonError={(e) => { (e.target as HTMLImageElement).style.display = \"none\"; }}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t{preview.title && <div className=\"hw-link-preview-title\">{preview.title}</div>}\n\t\t\t\t{preview.description && (\n\t\t\t\t\t<div className=\"hw-link-preview-desc\">{preview.description.slice(0, 120)}</div>\n\t\t\t\t)}\n\t\t\t\t<div className=\"hw-link-preview-url\">{hostname}</div>\n\t\t\t</div>\n\t\t</a>\n\t);\n}\n","\"use client\";\n\nimport type { TimelineItem, TimelineItemMetadata, TimelineItemPart } from \"@helpway/types\";\nimport {\n\tgetInitials,\n\tgetLocale,\n\tparseTimelineItemMetadata,\n\tstreamingKeyFor,\n\tt,\n} from \"@helpway/widget-core\";\nimport React, { useEffect, useRef } from \"react\";\nimport { useWidgetClient, useWidgetStore } from \"../provider\";\nimport { MessageBubble } from \"./message-bubble\";\n\nfunction parseParts(raw: TimelineItemPart[] | string | null): TimelineItemPart[] | null {\n\tif (!raw) return null;\n\tif (Array.isArray(raw)) return raw;\n\ttry {\n\t\tconst parsed = JSON.parse(raw);\n\t\treturn Array.isArray(parsed) ? parsed : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/* Intl formatters are cached, not constructed per render.\n\n `toLocaleDateString` builds a fresh `Intl.DateTimeFormat` on every call, and\n this list calls it once per item plus twice for the today/yesterday keys — so\n a 40-message thread paid for 42 formatter constructions per render, the most\n expensive thing in a component that re-renders on every streamed chunk.\n\n `en-CA` is not a display locale here: it is the shortest way to get a stable\n local-time YYYY-MM-DD bucket key. The display formatter is keyed by locale\n because `getLocale()` changes at runtime when the host app switches language. */\nconst DATE_KEY_FMT = new Intl.DateTimeFormat(\"en-CA\");\n\nconst displayFmtCache = new Map<string, Intl.DateTimeFormat>();\nfunction displayDateFormatter(locale: string): Intl.DateTimeFormat {\n\tconst hit = displayFmtCache.get(locale);\n\tif (hit) return hit;\n\tconst fmt = new Intl.DateTimeFormat(locale, {\n\t\tweekday: \"long\",\n\t\tmonth: \"short\",\n\t\tday: \"numeric\",\n\t});\n\tdisplayFmtCache.set(locale, fmt);\n\treturn fmt;\n}\n\ninterface MessageListProps {\n\titems: TimelineItem[];\n\tisTyping?: boolean;\n\tisAiProcessing?: boolean;\n\tstreamingText?: string;\n\thasMore?: boolean;\n\tisLoadingMore?: boolean;\n\tonLoadMore?: () => void;\n\t/** Slot rendered after all messages but before typing indicators (e.g. email prompt) */\n\trenderAfterMessages?: React.ReactNode;\n}\n\n/** Timeline with date separators, typing indicator, infinite scroll, and AI processing state */\nexport function MessageList({\n\titems,\n\tisTyping,\n\tisAiProcessing,\n\tstreamingText,\n\thasMore,\n\tisLoadingMore,\n\tonLoadMore,\n\trenderAfterMessages,\n}: MessageListProps) {\n\tconst bottomRef = useRef<HTMLDivElement>(null);\n\tconst topRef = useRef<HTMLDivElement>(null);\n\tconst containerRef = useRef<HTMLDivElement>(null);\n\tconst prevItemCountRef = useRef(items.length);\n\tconst isInitialLoadRef = useRef(true);\n\t/** Whether a streamed bubble was on screen at the previous render. */\n\tconst hadStreamRef = useRef(false);\n\t/* No sender-name plumbing here any more. The timeline labels a message by the\n\t sender's ROLE, which MessageBubble derives on its own, so this file no longer\n\t needs to know who the header is naming or what the AI is called — and the\n\t name-vs-header comparison that used to live here, with its own drifting copy\n\t of the header's resolution chain, is gone with it. useHeaderIdentity still\n\t exists for the header itself, in default-widget. */\n\tconst client = useWidgetClient();\n\tconst activeConversationId = useWidgetStore((s) => s.activeConversationId);\n\n\tconst handleQuickReplyTap = React.useCallback(\n\t\t(optionId: string, stepId: string) => {\n\t\t\tif (!activeConversationId) return;\n\t\t\t// Fire-and-forget — orchestrator runs the resume in the background\n\t\t\t// and emits new messages over WebSocket. Failure is swallowed so\n\t\t\t// the visitor never sees a tRPC error toast for this UX action.\n\t\t\tclient.widget.workflowReply\n\t\t\t\t.mutate({ conversationId: activeConversationId, stepId, optionId })\n\t\t\t\t.catch((err: unknown) => {\n\t\t\t\t\tconsole.warn(\"[helpway] workflowReply failed:\", err);\n\t\t\t\t});\n\t\t},\n\t\t[client, activeConversationId],\n\t);\n\n\t// Auto-scroll to bottom on new messages (but NOT when loading older ones at top)\n\tuseEffect(() => {\n\t\tconst prevCount = prevItemCountRef.current;\n\t\tconst newCount = items.length;\n\t\tprevItemCountRef.current = newCount;\n\n\t\t// Initial load or new messages added at the end → scroll to bottom\n\t\tif (isInitialLoadRef.current || newCount > prevCount) {\n\t\t\t// Only scroll if the new items were appended (not prepended)\n\t\t\tconst lastItem = items[items.length - 1];\n\t\t\tconst prevLastItem = prevCount > 0 ? items[prevCount - 1] : null;\n\n\t\t\tif (isInitialLoadRef.current || !prevLastItem || lastItem?.id !== prevLastItem?.id) {\n\t\t\t\t/* A message that replaces a stream is not new content arriving — it is\n\t\t\t\t the same text, already at the bottom, changing which component owns\n\t\t\t\t it. Animating to a position the reader is already at is the small\n\t\t\t\t slide they notice at the end of every answer. Jump instead. */\n\t\t\t\tconst replacedAStream = hadStreamRef.current;\n\t\t\t\tbottomRef.current?.scrollIntoView({\n\t\t\t\t\tbehavior: isInitialLoadRef.current || replacedAStream ? \"instant\" : \"smooth\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tisInitialLoadRef.current = false;\n\t\t}\n\t}, [items]);\n\n\t/* Follow the answer as it is written.\n\t\n\t The scroll effect above only fires when `items` changes, so nothing moved\n\t while a stream grew: the text ran past the bottom of the panel and the\n\t reader watched a sentence get cut off mid-word until the message finally\n\t landed. Streaming grows the same node continuously, which is not an items\n\t change, so it needs its own follow.\n\t\n\t \"instant\", not \"smooth\": this runs on every chunk, and a smooth scroll\n\t restarted a few times a second fights itself and never arrives.\n\t\n\t Also the read the items effect depends on — whether the render it is\n\t reacting to came out of a stream finishing. */\n\tuseEffect(() => {\n\t\tif (streamingText) {\n\t\t\tbottomRef.current?.scrollIntoView({ behavior: \"instant\" as ScrollBehavior });\n\t\t}\n\t\thadStreamRef.current = !!streamingText;\n\t}, [streamingText]);\n\n\t// Scroll to bottom when typing/AI indicators appear\n\tuseEffect(() => {\n\t\tif (isTyping || isAiProcessing) {\n\t\t\tbottomRef.current?.scrollIntoView({ behavior: \"smooth\" });\n\t\t}\n\t}, [isTyping, isAiProcessing]);\n\n\t// Infinite scroll — IntersectionObserver on the top sentinel\n\tuseEffect(() => {\n\t\tif (!hasMore || !onLoadMore || !topRef.current) return;\n\n\t\tconst observer = new IntersectionObserver(\n\t\t\t(entries) => {\n\t\t\t\tif (entries[0]?.isIntersecting && !isLoadingMore) {\n\t\t\t\t\t// Save scroll position before loading\n\t\t\t\t\tconst container = containerRef.current;\n\t\t\t\t\tconst prevScrollHeight = container?.scrollHeight ?? 0;\n\t\t\t\t\tconst prevScrollTop = container?.scrollTop ?? 0;\n\n\t\t\t\t\tonLoadMore();\n\n\t\t\t\t\t// Restore scroll position after DOM update (next frame)\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tif (container) {\n\t\t\t\t\t\t\tconst newScrollHeight = container.scrollHeight;\n\t\t\t\t\t\t\tcontainer.scrollTop = prevScrollTop + (newScrollHeight - prevScrollHeight);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ root: containerRef.current, threshold: 0.1 },\n\t\t);\n\n\t\tobserver.observe(topRef.current);\n\t\treturn () => observer.disconnect();\n\t}, [hasMore, onLoadMore, isLoadingMore]);\n\n\tif (items.length === 0) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName=\"hw-messages\"\n\t\t\t\trole=\"log\"\n\t\t\t\taria-label={t(\"widget.aria_messages\")}\n\t\t\t\taria-live=\"polite\"\n\t\t\t>\n\t\t\t\t<div className=\"hw-empty\">\n\t\t\t\t\t<div className=\"hw-empty-icon\">\n\t\t\t\t\t\t<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.5}>\n\t\t\t\t\t\t\t<path d=\"M7.9 20A9 9 0 1 0 4 16.1L2 22Z\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"hw-empty-text\">{t(\"widget.start_a_conversation\")}</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\tlet lastDateKey = \"\";\n\t// Stable \"today\" key (YYYY-MM-DD in local time) for separator gating.\n\t// We HIDE the separator for today entirely — matches Intercom/WhatsApp:\n\t// the date is implicit when \"now\", and showing it on every fresh\n\t// conversation creates a jarring vertical jump as the view fills in.\n\tconst todayKey = DATE_KEY_FMT.format(new Date());\n\tconst yesterday = new Date();\n\tyesterday.setDate(yesterday.getDate() - 1);\n\tconst yesterdayKey = DATE_KEY_FMT.format(yesterday);\n\n\treturn (\n\t\t<div\n\t\t\tref={containerRef}\n\t\t\tclassName=\"hw-messages\"\n\t\t\trole=\"log\"\n\t\t\taria-label={t(\"widget.aria_messages\")}\n\t\t\taria-live=\"polite\"\n\t\t>\n\t\t\t{/* Top sentinel for infinite scroll */}\n\t\t\t<div ref={topRef} className=\"hw-load-more-trigger\">\n\t\t\t\t{isLoadingMore && (\n\t\t\t\t\t<div className=\"hw-load-more-spinner\">\n\t\t\t\t\t\t<div />\n\t\t\t\t\t\t<div />\n\t\t\t\t\t\t<div />\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t{[\n\t\t\t\t...items.map((item) => {\n\t\t\t\t\tif (item.type === \"event\") {\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<EventCard\n\t\t\t\t\t\t\t\tkey={(item as unknown as { _stableKey?: string })._stableKey ?? item.id}\n\t\t\t\t\t\t\t\ttext={item.text ?? \"\"}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Date separator — bucket by local YYYY-MM-DD; skip rendering\n\t\t\t\t\t// when the bucket is \"today\" so today's chats stay flush at the top.\n\t\t\t\t\tconst itemDate = new Date(item.createdAt);\n\t\t\t\t\tconst dateKey = DATE_KEY_FMT.format(itemDate);\n\t\t\t\t\tconst isNewBucket = dateKey !== lastDateKey;\n\t\t\t\t\tif (isNewBucket) lastDateKey = dateKey;\n\t\t\t\t\tconst showDateSep = isNewBucket && dateKey !== todayKey;\n\t\t\t\t\tconst dateLabel =\n\t\t\t\t\t\tdateKey === yesterdayKey\n\t\t\t\t\t\t\t? t(\"widget.yesterday\")\n\t\t\t\t\t\t\t: displayDateFormatter(getLocale()).format(itemDate);\n\n\t\t\t\t\t// Determine sender\n\t\t\t\t\tconst sender = item.visitorId ? \"visitor\" : item.aiAgentId ? \"ai\" : \"team\";\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<React.Fragment\n\t\t\t\t\t\t\tkey={(item as unknown as { _stableKey?: string })._stableKey ?? item.id}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{showDateSep && (\n\t\t\t\t\t\t\t\t<div className=\"hw-date-sep\">\n\t\t\t\t\t\t\t\t\t<div className=\"hw-date-sep-line\" />\n\t\t\t\t\t\t\t\t\t<div className=\"hw-date-sep-text\">{dateLabel}</div>\n\t\t\t\t\t\t\t\t\t<div className=\"hw-date-sep-line\" />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t<MessageBubble\n\t\t\t\t\t\t\t\ttext={item.text ?? \"\"}\n\t\t\t\t\t\t\t\tsender={sender}\n\t\t\t\t\t\t\t\tparts={parseParts(item.parts)}\n\t\t\t\t\t\t\t\tmetadata={parseTimelineItemMetadata(\n\t\t\t\t\t\t\t\t\t(item as TimelineItem & { metadata?: TimelineItemMetadata | string | null })\n\t\t\t\t\t\t\t\t\t\t.metadata,\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tonQuickReplyTap={handleQuickReplyTap}\n\t\t\t\t\t\t\t\t/* No clock under a bubble, on either side. The day divider says\n\t\t\t\t\t\t\t which day; inside a day the minute a message landed is not\n\t\t\t\t\t\t\t something anyone came here to read, and printed under every run\n\t\t\t\t\t\t\t it was the last piece of chrome competing with the answer. Fin\n\t\t\t\t\t\t\t keeps relative time in the conversation LIST, where it helps you\n\t\t\t\t\t\t\t pick a thread, and out of the thread itself.\n\t\t\t\t\t\t\t MessageBubble still renders a meta row when a caller passes\n\t\t\t\t\t\t\t `timestamp` or `senderName`; the timeline passes neither. */\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</React.Fragment>\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\t\t/* The stream is the LAST ENTRY OF THIS SAME ARRAY, in the same\n\t\t\t\t React.Fragment wrapper, under the key the finished message arrives\n\t\t\t\t with (streamingKeyFor + addMessage). All three have to match or React\n\t\t\t\t cannot see the two as one thing:\n\n\t\t\t\t - same array, or they are different child slots\n\t\t\t\t - same key, or they are different children\n\t\t\t\t - same element type, or the key match is discarded anyway\n\n\t\t\t\t It had the key but not the other two: it sat after {items.map(...)}\n\t\t\t\t as its own slot, and it was a bare MessageBubble against the map's\n\t\t\t\t React.Fragment. So React tore it down and mounted the real bubble in\n\t\t\t\t its place, .hw-msg replayed hw-msg-appear (styles.css:1326), and the\n\t\t\t\t answer visibly animated in a second time just as it finished. */\n\t\t\t\t...(streamingText && activeConversationId\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t<React.Fragment key={streamingKeyFor(activeConversationId)}>\n\t\t\t\t\t\t\t\t{/* This null is load-bearing. React reconciles a Fragment's STATIC\n\t\t\t\t\t\t\t\t children by position, and the mapped entry's first child is\n\t\t\t\t\t\t\t\t `{showDateSep && <div className=\"hw-date-sep\">…}` — which\n\t\t\t\t\t\t\t\t evaluates to false for the last message but still occupies\n\t\t\t\t\t\t\t\t index 0. Without a placeholder here the bubble would sit at\n\t\t\t\t\t\t\t\t index 0 in the stream and index 1 in the message that replaces\n\t\t\t\t\t\t\t\t it, so React would remount it and hw-msg-appear would replay:\n\t\t\t\t\t\t\t\t the whole point of matching the key, undone by an off-by-one\n\t\t\t\t\t\t\t\t in the children array. */}\n\t\t\t\t\t\t\t\t{null}\n\t\t\t\t\t\t\t\t<MessageBubble text={streamingText} sender=\"ai\" parts={null} streaming />\n\t\t\t\t\t\t\t</React.Fragment>,\n\t\t\t\t\t\t]\n\t\t\t\t\t: []),\n\t\t\t]}\n\n\t\t\t{/* Slot for inline content after messages (e.g. email prompt) */}\n\t\t\t{renderAfterMessages}\n\n\t\t\t{/* ONE waiting indicator, for both reasons someone might be waiting.\n\n\t\t\t There were two, with byte-identical markup and mutually exclusive\n\t\t\t conditions — one for the AI, one for a teammate typing. So when the\n\t\t\t flags crossed, which they do on a normal reply (aiProcessingProgress\n\t\t\t sets both, aiStreamChunk clears both), React unmounted one element and\n\t\t\t mounted the other, and the dots restarted their bounce from frame zero.\n\t\t\t A reader cannot tell a restarted animation from a second wait\n\t\t\t beginning — which is exactly what it looked like.\n\n\t\t\t One node, one condition, so the flags can cross without the animation\n\t\t\t ever noticing. Streaming suppresses it: once text is arriving, the text\n\t\t\t IS the progress indicator.\n\n\t\t\t No name above the dots either: the answer that follows carries its own\n\t\t\t signature, and repeating it here printed the agent twice for one reply. */}\n\t\t\t{(isAiProcessing || isTyping) && !streamingText && (\n\t\t\t\t<div className=\"hw-typing\">\n\t\t\t\t\t<div className=\"hw-typing-dots\">\n\t\t\t\t\t\t<div className=\"hw-typing-dot\" />\n\t\t\t\t\t\t<div className=\"hw-typing-dot\" />\n\t\t\t\t\t\t<div className=\"hw-typing-dot\" />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t<div ref={bottomRef} />\n\t\t</div>\n\t);\n}\n\n// ── Event Card ────────────────────────────────────────\n\ninterface EventData {\n\taction: string;\n\tname: string;\n\timage?: string | null;\n}\n\nfunction parseEventData(text: string): EventData | null {\n\tif (!text.startsWith(\"{\")) return null;\n\ttry {\n\t\tconst data = JSON.parse(text);\n\t\tif (data.action && data.name) return data as EventData;\n\t} catch {\n\t\t/* plain text fallback */\n\t}\n\treturn null;\n}\n\nfunction EventCard({ text }: { text: string }) {\n\tconst data = parseEventData(text);\n\n\t// Structured event — rich card with avatar\n\tif (data) {\n\t\tconst message = data.action === \"joined\" ? t(\"widget.joined\") : t(\"widget.left\");\n\n\t\treturn (\n\t\t\t<div className=\"hw-event hw-event--card\">\n\t\t\t\t<div className=\"hw-event-avatar\">\n\t\t\t\t\t{data.image ? (\n\t\t\t\t\t\t<img src={data.image} alt=\"\" className=\"hw-event-avatar-img\" />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<span>{getInitials(data.name)}</span>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"hw-event-body\">\n\t\t\t\t\t<span className=\"hw-event-name\">{data.name}</span>{\" \"}\n\t\t\t\t\t<span className=\"hw-event-action\">{message}</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// Plain text event (resolve, reopen, etc.)\n\treturn (\n\t\t<div className=\"hw-event\">\n\t\t\t<div className=\"hw-event-text\">{text}</div>\n\t\t</div>\n\t);\n}\n","\"use client\";\n\nimport { t } from \"@helpway/widget-core\";\nimport { truncatePreviewBody } from \"@helpway/widget-core\";\nimport type { MouseEvent, ReactNode } from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { EPHEMERAL_CONV_PREFIX, useWidgetClient, useWidgetStore } from \"../provider\";\nimport { XIcon } from \"./icons\";\n\n/** Where the preview is anchored — controls only the outer positioning. */\nexport type MessagePreviewPlacement = \"launcher\" | \"anchored\";\n\nexport interface MessagePreviewProps {\n\t/** Called when the visitor taps the preview (or a quick reply). The\n\t * active conversation is already switched to the one that pinged —\n\t * the consumer just has to reveal the chat surface. */\n\tonOpen: () => void;\n\t/**\n\t * The avatar node shown in the header. Injected by the consumer so\n\t * this component stays decoupled from avatar resolution — the default\n\t * widget passes `<WidgetLogo />`; a custom surface can pass its own.\n\t */\n\tavatar: ReactNode;\n\t/**\n\t * Outer positioning mode. `\"launcher\"` (default) keeps the original\n\t * absolute placement above the floating bubble — DefaultWidget relies\n\t * on this, so the default is unchanged. `\"anchored\"` drops the\n\t * absolute/bottom/right rules (via `hw-preview--anchored`) so a\n\t * consumer can pin it to their own trigger (e.g. a sidebar item).\n\t */\n\tplacement?: MessagePreviewPlacement;\n\t/**\n\t * Auto-dismiss delay in ms. Default `8000` (the launcher behaviour).\n\t * Pass `null` (or `0`) to keep the preview until the visitor acts on\n\t * it — useful for an anchored surface where it isn't competing with\n\t * page content for attention. Quick-reply previews never auto-dismiss\n\t * regardless, since the visitor needs time to choose.\n\t */\n\tautoDismissMs?: number | null;\n\t/**\n\t * Optional caption rendered as a separated footer beneath the message\n\t * (e.g. a source label like \"via Helpway\"). Omitted for the launcher\n\t * so its visual stays byte-identical to the original.\n\t */\n\tfooter?: ReactNode;\n}\n\n/**\n * `<MessagePreview>` — the proactive incoming-message bubble shown while\n * the chat surface is closed. Reads `incomingPreview` from the widget\n * store, auto-dismisses after 8s (unless quick replies are present), and\n * on tap switches to the pinging conversation before calling `onOpen`.\n *\n * Extracted from the default widget so `hideLauncher` integrations can\n * surface the *exact same* preview next to their own UI instead of the\n * floating launcher. Visual/markup is byte-identical to the launcher\n * version — only the outer positioning is parameterised via `placement`.\n *\n * Must be rendered inside `<SupportProvider>`.\n */\nexport function MessagePreview({\n\tonOpen,\n\tavatar,\n\tplacement = \"launcher\",\n\tautoDismissMs = 8000,\n\tfooter,\n}: MessagePreviewProps) {\n\tconst preview = useWidgetStore((s) => s.incomingPreview);\n\tconst dismissPreview = useWidgetStore((s) => s.dismissPreview);\n\tconst setActiveConversation = useWidgetStore((s) => s.setActiveConversation);\n\tconst agentName = useWidgetStore((s) => s.agentConfig?.name) ?? \"Support\";\n\tconst client = useWidgetClient();\n\t/* A human who replies signs with their own name. The card used to print the\n\t agent's name over every message, so a teammate's answer arrived as if the\n\t AI had written it — the one moment the visitor most needs to know a person\n\t picked this up. The AI keeps the agent name because for it that IS the\n\t sender. */\n\tconst senderName = preview?.senderName || agentName;\n\tconst senderImage = preview?.senderImage || null;\n\tconst [closing, setClosing] = useState(false);\n\n\t// Auto-dismiss after `autoDismissMs` (skip when quick replies are\n\t// present — visitor needs time to read and decide — or when the\n\t// consumer opted out with null/0 for a persistent anchored surface).\n\tuseEffect(() => {\n\t\tif (!preview || preview.quickReplies) return;\n\t\tif (autoDismissMs == null || autoDismissMs <= 0) return;\n\t\tconst timer = setTimeout(() => {\n\t\t\tsetClosing(true);\n\t\t\tsetTimeout(() => dismissPreview(), 200);\n\t\t}, autoDismissMs);\n\t\treturn () => clearTimeout(timer);\n\t}, [preview, dismissPreview, autoDismissMs]);\n\n\tif (!preview) return null;\n\n\tconst handleClose = (e: MouseEvent) => {\n\t\te.stopPropagation();\n\t\tsetClosing(true);\n\t\tsetTimeout(() => {\n\t\t\tdismissPreview();\n\t\t\tsetClosing(false);\n\t\t}, 200);\n\t};\n\n\tconst handleClick = () => {\n\t\t// Bubble click is an explicit \"I want to read this\" — open the\n\t\t// widget AND jump straight to the conversation that pinged. Without\n\t\t// the setActiveConversation, the visitor lands on the home screen\n\t\t// and has to find the unread row themselves.\n\t\tconst targetConvId = preview.conversationId;\n\t\tdismissPreview();\n\t\tsetActiveConversation(targetConvId);\n\t\tonOpen();\n\t};\n\n\t/* Blank bodies are dropped rather than rendered empty. A quick-replies step\n\t with no prompt has nothing to say above its own buttons, and an empty\n\t `.hw-preview-body` is not nothing on screen — it is a padded row of dead\n\t space between the header and the options. */\n\t/* Tapping an option on the card answers the run, then opens the thread so the\n\t visitor watches it continue. Answering from the card is the whole point of\n\t putting buttons there — a control that only opens the widget, leaving the\n\t same buttons to be tapped again inside, is a link wearing a button's\n\t clothes, and it costs the visitor the tap that made them choose.\n\n\t Two exceptions, both real:\n\t - An ephemeral conversation has no server row yet (`eph-` prefix); its\n\t reply has to materialize through the in-widget flow, so here the card\n\t opens and hands the choice over intact.\n\t - Failure is swallowed. The mutation is idempotent server-side, the thread\n\t is opening either way, and an error toast on top of a notification card\n\t tells the visitor about a retry they cannot perform. */\n\tconst submitQuickReply = (optionId: string) => {\n\t\tconst convId = preview.conversationId;\n\t\tconst stepId = preview.quickReplies?.stepId;\n\t\tif (stepId && !convId.startsWith(EPHEMERAL_CONV_PREFIX)) {\n\t\t\tclient.widget.workflowReply\n\t\t\t\t.mutate({ conversationId: convId, stepId, optionId })\n\t\t\t\t.catch((err: unknown) => {\n\t\t\t\t\tconsole.warn(\"[helpway] workflowReply from preview failed:\", err);\n\t\t\t\t});\n\t\t}\n\t\tdismissPreview();\n\t\tsetActiveConversation(convId);\n\t\tonOpen();\n\t};\n\n\tconst messages = (preview.messages?.length ? preview.messages : [{ text: preview.text }]).filter(\n\t\t(m) => m.text.trim().length > 0,\n\t);\n\t/* Narrowed once, so the three `preview.quickReplies!` assertions below are\n\t gone with it. An assertion repeated three times is three chances for the\n\t next edit to move one of them outside the guard. */\n\tconst qr =\n\t\tpreview.quickReplies && preview.quickReplies.options.length > 0 ? preview.quickReplies : null;\n\n\tconst placementClass = placement === \"anchored\" ? \"hw-preview--anchored \" : \"\";\n\n\treturn (\n\t\t<div\n\t\t\tclassName={`hw-preview ${placementClass}${closing ? \"hw-preview--closing\" : \"\"}`}\n\t\t\tonClick={handleClick}\n\t\t\t/* The card advertised itself as a button and answered no key: focusable\n\t\t\t via `tabIndex`, labelled `role=\"button\"`, and with nothing bound — so a\n\t\t\t keyboard user could reach the notification and had no way to open it.\n\t\t\t Space is included because a role=\"button\" is expected to take it, and\n\t\t\t its default page-scroll has to be suppressed to not scroll the host\n\t\t\t page underneath. */\n\t\t\tonKeyDown={(e) => {\n\t\t\t\tif (e.key !== \"Enter\" && e.key !== \" \") return;\n\t\t\t\tif (e.target !== e.currentTarget) return;\n\t\t\t\te.preventDefault();\n\t\t\t\thandleClick();\n\t\t\t}}\n\t\t\trole=\"button\"\n\t\t\ttabIndex={0}\n\t\t>\n\t\t\t<div className=\"hw-preview-header\">\n\t\t\t\t<div className=\"hw-preview-avatar\">\n\t\t\t\t\t{senderImage ? <img src={senderImage} alt=\"\" /> : avatar}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"hw-preview-name\">{senderName}</div>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"hw-preview-close\"\n\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\taria-label={t(\"widget.aria_dismiss\")}\n\t\t\t\t>\n\t\t\t\t\t<XIcon size={20} />\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t{messages.map((m) => (\n\t\t\t\t/* Keyed by content, not index: the card's bodies are the sender's own\n\t\t\t\t consecutive messages, so two identical ones would already be a bug\n\t\t\t\t upstream, and an index key hands React the wrong bubble to reuse the\n\t\t\t\t moment a new message lands mid-animation. */\n\t\t\t\t<div key={m.text} className=\"hw-preview-body\">\n\t\t\t\t\t{truncatePreviewBody(m.text)}\n\t\t\t\t</div>\n\t\t\t))}\n\n\t\t\t{qr && (\n\t\t\t\t<>\n\t\t\t\t\t{qr.prompt && <div className=\"hw-preview-body\">{qr.prompt}</div>}\n\t\t\t\t\t{/* Same classes the in-bubble list uses. There were two implementations\n\t\t\t\t\t of this control and they had drifted: the preview's copy sat on a\n\t\t\t\t\t transparent ground with a plain border, coloured by --hw-brand, and\n\t\t\t\t\t hovered on `var(--hw-hover, …)` — a token that does not exist\n\t\t\t\t\t anywhere in this stylesheet, so its hover was a hardcoded grey that\n\t\t\t\t\t ignored dark mode and the glass card entirely. One definition now,\n\t\t\t\t\t so the two cannot disagree about what a quick reply looks like. */}\n\t\t\t\t\t<div className=\"hw-preview-quick-replies hw-quick-replies\">\n\t\t\t\t\t\t{qr.options.map((opt) => (\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tkey={opt.id}\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"hw-quick-reply-btn\"\n\t\t\t\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\t\t\t\tsubmitQuickReply(opt.id);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{opt.label}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</>\n\t\t\t)}\n\n\t\t\t{footer != null && footer !== false && <div className=\"hw-preview-footer\">{footer}</div>}\n\t\t</div>\n\t);\n}\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\":host {\\n all: initial;\\n font-family:\\n -apple-system,\\n BlinkMacSystemFont,\\n \\\"Segoe UI\\\",\\n Roboto,\\n \\\"Helvetica Neue\\\",\\n Arial,\\n sans-serif;\\n font-size: 14px;\\n line-height: 1.5;\\n color: #1a1a1a;\\n -webkit-font-smoothing: antialiased;\\n -moz-osx-font-smoothing: grayscale;\\n}\\n.hw-widget {\\n font-family:\\n -apple-system,\\n BlinkMacSystemFont,\\n \\\"Segoe UI\\\",\\n Roboto,\\n \\\"Helvetica Neue\\\",\\n Arial,\\n sans-serif;\\n font-size: 14px;\\n line-height: 1.5;\\n color: #1a1a1a;\\n -webkit-font-smoothing: antialiased;\\n -moz-osx-font-smoothing: grayscale;\\n}\\n.hw-widget *,\\n.hw-widget *::before,\\n.hw-widget *::after {\\n box-sizing: border-box;\\n margin: 0;\\n padding: 0;\\n}\\n:where(.hw-widget) {\\n --hw-primary: #171717;\\n --hw-primary-hover: #2a2a2a;\\n --hw-brand: #171717;\\n --hw-on-brand: #ffffff;\\n --hw-focus-border: #9ca3af;\\n --hw-focus-ring: rgba(0, 0, 0, 0.06);\\n --hw-accent: #6366f1;\\n --hw-bg: #ffffff;\\n --hw-bg-subtle: #fafaf9;\\n --hw-bg-hover: #f5f5f4;\\n --hw-border: #ebe9e5;\\n --hw-border-md: #e5e5e5;\\n --hw-text: #1c1b19;\\n --hw-text-1: #111;\\n --hw-text-2: #666;\\n --hw-text-3: #8a847c;\\n --hw-text-4: #a8a29a;\\n --hw-radius: 20px;\\n --hw-visitor-bubble-bg: #f5f5f4;\\n --hw-visitor-bubble-text: #1a1a1a;\\n --hw-font:\\n -apple-system,\\n BlinkMacSystemFont,\\n \\\"Segoe UI\\\",\\n Roboto,\\n \\\"Helvetica Neue\\\",\\n Arial,\\n sans-serif;\\n}\\n.hw-agent-img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n}\\n.hw-agent-icon {\\n width: 100%;\\n height: 100%;\\n border-radius: inherit;\\n}\\n.hw-widget :focus-visible {\\n outline: 2px solid var(--hw-primary);\\n outline-offset: 2px;\\n}\\n.hw-widget :focus:not(:focus-visible) {\\n outline: none;\\n}\\n.hw-widget {\\n position: fixed;\\n bottom: 20px;\\n right: var(--hw-position-right, 20px);\\n left: var(--hw-position-left, auto);\\n z-index: 999999;\\n font-family: var(--hw-font);\\n}\\n@keyframes hw-bubble-enter {\\n from {\\n opacity: 0;\\n transform: scale(0.6);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n.hw-bubble {\\n width: 48px;\\n height: 48px;\\n border-radius: 14px;\\n background: var(--hw-primary);\\n color: white;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\\n transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease;\\n position: relative;\\n overflow: visible;\\n animation: hw-bubble-enter 0.25s cubic-bezier(0.34, 1.56, 0.64, 1) both;\\n}\\n.hw-bubble--rounded {\\n border-radius: 14px;\\n}\\n.hw-bubble--square {\\n border-radius: 8px;\\n}\\n.hw-bubble--pill {\\n border-radius: 24px;\\n}\\n.hw-bubble--launcher-bubble,\\n.hw-bubble--launcher-help {\\n width: auto;\\n padding: 0 16px 0 12px;\\n gap: 8px;\\n border-radius: 24px;\\n}\\n.hw-bubble--launcher-bubble.hw-bubble--square,\\n.hw-bubble--launcher-help.hw-bubble--square {\\n border-radius: 8px;\\n}\\n.hw-bubble--launcher-bubble.hw-bubble--rounded,\\n.hw-bubble--launcher-help.hw-bubble--rounded {\\n border-radius: 14px;\\n}\\n.hw-bubble-label {\\n font-size: 14px;\\n font-weight: 600;\\n white-space: nowrap;\\n line-height: 1;\\n position: static;\\n opacity: 1;\\n transform: none;\\n}\\n.hw-bubble--launcher-bubble .hw-bubble-icon,\\n.hw-bubble--launcher-help .hw-bubble-icon {\\n position: static;\\n}\\n.hw-bubble:hover {\\n transform: scale(1.05);\\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);\\n}\\n.hw-bubble:active {\\n transform: scale(0.95);\\n}\\n.hw-bubble--open {\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\\n}\\n.hw-bubble:focus-visible {\\n outline: 2px solid white;\\n outline-offset: 2px;\\n}\\n.hw-bubble-icon {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n position: absolute;\\n transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.2s ease;\\n}\\n.hw-bubble-icon svg {\\n width: 22px;\\n height: 22px;\\n}\\n.hw-bubble-icon--hidden {\\n transform: scale(0.3) rotate(90deg);\\n opacity: 0;\\n}\\n.hw-bubble-icon--bot {\\n}\\n.hw-bubble--avatar .hw-bubble-icon--bot {\\n width: 100%;\\n height: 100%;\\n}\\n.hw-bubble--avatar .hw-bubble-icon--bot .hw-agent-img {\\n width: 100%;\\n height: 100%;\\n border-radius: 0;\\n}\\n.hw-agent-img.hw-agent-img--logo {\\n object-fit: contain;\\n padding: 10px;\\n box-sizing: border-box;\\n}\\n.hw-bubble--avatar .hw-bubble-icon--bot .hw-agent-img.hw-agent-img--logo {\\n padding: 10px;\\n box-sizing: border-box;\\n object-fit: contain;\\n}\\n.hw-bubble-icon--close svg {\\n width: 22px;\\n height: 22px;\\n}\\n.hw-bubble-badge {\\n position: absolute;\\n top: -4px;\\n right: -4px;\\n min-width: 20px;\\n height: 20px;\\n border-radius: 10px;\\n background: var(--hw-primary);\\n color: white;\\n font-size: 11px;\\n font-weight: 700;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 0 5px;\\n border: 2px solid white;\\n animation: hw-badge-pop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\\n}\\n@keyframes hw-badge-pop {\\n from {\\n transform: scale(0);\\n }\\n to {\\n transform: scale(1);\\n }\\n}\\n.hw-bubble-badge::after {\\n content: \\\"\\\";\\n position: absolute;\\n inset: -2px;\\n border-radius: inherit;\\n background: var(--hw-primary);\\n opacity: 0;\\n animation: hw-badge-pulse 2s ease-out infinite;\\n}\\n@keyframes hw-badge-pulse {\\n 0% {\\n opacity: 0.5;\\n transform: scale(1);\\n }\\n 100% {\\n opacity: 0;\\n transform: scale(1.8);\\n }\\n}\\n.hw-window {\\n position: absolute;\\n bottom: 72px;\\n right: var(--hw-window-right, 0);\\n left: var(--hw-window-left, auto);\\n width: 440px;\\n height: 640px;\\n background: var(--hw-bg-subtle);\\n color: var(--hw-text);\\n border-radius: var(--hw-radius);\\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.04);\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n animation: hw-window-open 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);\\n transition: width 280ms cubic-bezier(0.4, 0, 0.2, 1), height 280ms cubic-bezier(0.4, 0, 0.2, 1);\\n}\\n.hw-window--reading {\\n width: min(720px, calc(100vw - 40px));\\n height: min(800px, calc(100vh - 112px));\\n}\\n@keyframes hw-window-open {\\n from {\\n opacity: 0;\\n transform: translateY(12px) scale(0.96);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0) scale(1);\\n }\\n}\\n.hw-window--closing {\\n animation: hw-window-close 0.2s ease forwards;\\n}\\n@keyframes hw-window-close {\\n from {\\n opacity: 1;\\n transform: translateY(0) scale(1);\\n }\\n to {\\n opacity: 0;\\n transform: translateY(8px) scale(0.98);\\n }\\n}\\n.hw-content {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n min-height: 0;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-window,\\n .hw-window--closing,\\n .hw-content,\\n .hw-msg,\\n .hw-bubble,\\n .hw-bubble-icon,\\n .hw-bubble-badge,\\n .hw-bubble-badge::after,\\n .hw-typing-dot,\\n .hw-loading-dot {\\n animation-duration: 0.01ms !important;\\n transition-duration: 0.01ms !important;\\n }\\n}\\n.hw-hero {\\n flex-shrink: 0;\\n background:\\n linear-gradient(\\n 160deg,\\n color-mix(in srgb, var(--hw-primary) 60%, black) 0%,\\n var(--hw-primary) 50%,\\n color-mix(in srgb, var(--hw-primary) 40%, black) 100%);\\n color: white;\\n padding: 20px 22px 40px;\\n}\\n.hw-hero-top {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n margin-bottom: 16px;\\n}\\n.hw-hero-close {\\n width: 30px;\\n height: 30px;\\n border-radius: 50%;\\n border: none;\\n background: rgba(255, 255, 255, 0.1);\\n color: rgba(255, 255, 255, 0.6);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n transition: background 0.15s, color 0.15s;\\n}\\n.hw-hero-close:hover {\\n background: rgba(255, 255, 255, 0.2);\\n color: white;\\n}\\n.hw-hero-close:active {\\n transform: scale(0.92);\\n transition:\\n transform 0.14s cubic-bezier(0.23, 1, 0.32, 1),\\n background 0.15s,\\n color 0.15s;\\n}\\n.hw-hero-close svg {\\n width: 20px;\\n height: 20px;\\n}\\n.hw-hero-bot-icon {\\n width: 36px;\\n height: 36px;\\n flex-shrink: 0;\\n color: white;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 10px;\\n}\\n.hw-hero-bot-icon svg {\\n width: 32px;\\n height: 32px;\\n}\\n.hw-hero-bot-icon .hw-agent-img,\\n.hw-hero-bot-icon .hw-agent-icon {\\n border-radius: inherit;\\n overflow: hidden;\\n object-fit: contain;\\n}\\n.hw-hero-greeting {\\n font-size: 26px;\\n font-weight: 700;\\n line-height: 1.15;\\n margin-bottom: 6px;\\n}\\n.hw-hero-greeting-name {\\n font-weight: 300;\\n}\\n.hw-hero-greeting-question {\\n font-weight: 700;\\n}\\n.hw-hero-subtitle {\\n font-size: 15px;\\n color: rgba(255, 255, 255, 0.5);\\n line-height: 1.35;\\n}\\n.hw-sheet {\\n flex: 1;\\n overflow-y: auto;\\n min-height: 0;\\n background: #ffffff;\\n border-radius: 20px 20px 0 0;\\n margin-top: -24px;\\n box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.08);\\n position: relative;\\n z-index: 1;\\n}\\n.hw-sheet-inner {\\n padding: 20px 16px;\\n display: flex;\\n flex-direction: column;\\n gap: 12px;\\n}\\n.hw-header {\\n display: flex;\\n align-items: center;\\n padding: 14px 12px 14px 16px;\\n background: var(--hw-primary);\\n color: white;\\n flex-shrink: 0;\\n gap: 10px;\\n}\\n.hw-header--sub {\\n justify-content: space-between;\\n background: transparent;\\n color: var(--hw-text);\\n border-bottom: 0;\\n}\\n.hw-header-back {\\n width: 28px;\\n height: 28px;\\n border-radius: 8px;\\n border: none;\\n background: transparent;\\n color: var(--hw-text-3);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n transition: color 0.15s, background 0.15s;\\n flex-shrink: 0;\\n}\\n.hw-header-back svg {\\n width: 18px;\\n height: 18px;\\n}\\n.hw-header-back:hover {\\n color: var(--hw-text);\\n background: var(--hw-bg-subtle);\\n}\\n.hw-header-identity {\\n display: flex;\\n align-items: center;\\n gap: 10px;\\n flex: 1;\\n min-width: 0;\\n}\\n.hw-header-bot-icon {\\n width: 32px;\\n height: 32px;\\n flex-shrink: 0;\\n color: var(--hw-text);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 9px;\\n background: var(--hw-agent-bg, var(--hw-agent-bg-default, transparent));\\n}\\n.hw-header-bot-icon svg {\\n width: 24px;\\n height: 24px;\\n}\\n.hw-header-bot-icon--team {\\n background: var(--hw-brand, #0a0a0a);\\n color: var(--hw-on-brand, #fff);\\n}\\n.hw-header-agent-img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n border-radius: inherit;\\n}\\n.hw-header-bot-icon .hw-agent-img,\\n.hw-header-bot-icon .hw-agent-icon {\\n border-radius: inherit;\\n overflow: hidden;\\n}\\n.hw-header-bot-icon .hw-agent-img {\\n object-fit: var(--hw-agent-fit, var(--hw-agent-fit-default, cover));\\n padding: var(--hw-agent-pad, var(--hw-agent-pad-default, 0));\\n box-sizing: border-box;\\n}\\n.hw-widget[data-has-avatar=true] {\\n --hw-agent-bg-default: var(--hw-primary);\\n --hw-agent-fit-default: contain;\\n --hw-agent-pad-default: 6px;\\n}\\n.hw-header-agent-initials {\\n font-size: 11px;\\n font-weight: 600;\\n line-height: 1;\\n}\\n.hw-header-info {\\n flex: 1;\\n min-width: 0;\\n}\\n.hw-header-name {\\n font-size: 15px;\\n font-weight: 600;\\n line-height: 1.3;\\n}\\n.hw-header-status {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n line-height: 1.3;\\n}\\n.hw-header-close {\\n width: 28px;\\n height: 28px;\\n border-radius: 8px;\\n border: none;\\n background: transparent;\\n color: var(--hw-text-3);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n transition:\\n background-color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\\n flex-shrink: 0;\\n}\\n.hw-header-close svg {\\n width: 20px;\\n height: 20px;\\n}\\n.hw-header-close:hover {\\n background: var(--hw-bg-subtle);\\n color: var(--hw-text);\\n}\\n.hw-header-close:active {\\n transform: scale(0.92);\\n}\\n.hw-header--centered {\\n justify-content: space-between;\\n background: transparent;\\n color: var(--hw-text);\\n border-bottom: 0;\\n}\\n.hw-header--centered .hw-header-title {\\n position: absolute;\\n left: 50%;\\n transform: translateX(-50%);\\n max-width: calc(100% - 88px);\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n text-align: center;\\n}\\n.hw-header-spacer {\\n width: 28px;\\n flex-shrink: 0;\\n}\\n.hw-header--messages {\\n justify-content: space-between;\\n background: transparent;\\n color: var(--hw-text);\\n border-bottom: 0;\\n}\\n.hw-header-title {\\n font-size: 16px;\\n font-weight: 600;\\n}\\n.hw-header-actions {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n}\\n.hw-header-action {\\n width: 28px;\\n height: 28px;\\n border-radius: 8px;\\n border: none;\\n background: transparent;\\n color: var(--hw-text-3);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n transition:\\n background-color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\\n}\\n.hw-header-action svg {\\n width: 16px;\\n height: 16px;\\n}\\n.hw-header-action:hover {\\n background: var(--hw-bg-subtle);\\n color: var(--hw-text);\\n}\\n.hw-header-action:active {\\n transform: scale(0.94);\\n}\\n.hw-card {\\n display: flex;\\n align-items: center;\\n gap: 12px;\\n width: 100%;\\n padding: 14px 16px;\\n border-radius: 14px;\\n background: var(--hw-bg);\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.03);\\n cursor: pointer;\\n transition: box-shadow 180ms cubic-bezier(0.23, 1, 0.32, 1), transform 180ms cubic-bezier(0.23, 1, 0.32, 1);\\n text-align: left;\\n color: var(--hw-text);\\n font-family: inherit;\\n}\\n.hw-card:hover {\\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08), 0 0 0 1px rgba(0, 0, 0, 0.05);\\n transform: translateY(-1px);\\n}\\n.hw-card:active {\\n transform: translateY(0) scale(0.99);\\n transition-duration: 120ms;\\n}\\n.hw-card-body {\\n flex: 1;\\n min-width: 0;\\n}\\n.hw-card-title {\\n font-size: 14px;\\n font-weight: 600;\\n line-height: 1.3;\\n color: var(--hw-text);\\n}\\n.hw-card-meta {\\n font-size: 12px;\\n color: var(--hw-text-3);\\n line-height: 1.3;\\n margin-top: 1px;\\n}\\n.hw-card-arrow {\\n width: 32px;\\n height: 32px;\\n border-radius: 50%;\\n background: var(--hw-primary);\\n color: white;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n flex-shrink: 0;\\n}\\n.hw-card-arrow svg {\\n width: 14px;\\n height: 14px;\\n}\\n.hw-msgs-tab {\\n flex: 1;\\n overflow-y: auto;\\n padding: 12px 16px;\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n}\\n.hw-recent-card {\\n border-radius: 14px;\\n background: var(--hw-bg);\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.03);\\n overflow: hidden;\\n}\\n.hw-recent-header {\\n font-size: 12px;\\n font-weight: 600;\\n color: var(--hw-text-2);\\n padding: 12px 14px 0;\\n}\\n.hw-recent-row {\\n display: flex;\\n align-items: center;\\n gap: 10px;\\n width: 100%;\\n padding: 10px 14px;\\n border: none;\\n border-bottom: 1px solid var(--hw-border);\\n background: none;\\n cursor: pointer;\\n text-align: left;\\n font-family: inherit;\\n color: var(--hw-text);\\n transition: background-color 140ms cubic-bezier(0.23, 1, 0.32, 1), transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\\n position: relative;\\n}\\n.hw-recent-row:hover {\\n background: rgba(0, 0, 0, 0.03);\\n}\\n.hw-recent-row:active {\\n transform: scale(0.995);\\n}\\n.hw-recent-row--last {\\n border-bottom: none;\\n}\\n.hw-recent-row .hw-conv-card-avatar {\\n width: 32px;\\n height: 32px;\\n border-radius: 8px;\\n}\\n.hw-recent-row .hw-conv-card-avatar svg {\\n width: 18px;\\n height: 18px;\\n}\\n.hw-recent-row .hw-conv-card-name {\\n font-size: 13px;\\n}\\n.hw-recent-row .hw-conv-card-preview {\\n font-size: 12px;\\n}\\n.hw-recent-row--unread .hw-conv-card-name {\\n color: var(--hw-text);\\n}\\n.hw-recent-row--unread .hw-conv-card-time {\\n color: var(--hw-primary);\\n font-weight: 500;\\n}\\n.hw-recent-row-badge {\\n min-width: 18px;\\n height: 18px;\\n border-radius: 9px;\\n background: var(--hw-primary);\\n color: white;\\n font-size: 11px;\\n font-weight: 600;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 0 5px;\\n flex-shrink: 0;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-recent-see-all {\\n display: block;\\n width: 100%;\\n padding: 10px 14px;\\n text-align: center;\\n font-size: 13px;\\n font-weight: 500;\\n color: var(--hw-text);\\n background: none;\\n border: none;\\n border-top: 1px solid var(--hw-border);\\n cursor: pointer;\\n font-family: inherit;\\n transition: background 0.1s;\\n}\\n.hw-recent-see-all:hover {\\n background: rgba(0, 0, 0, 0.02);\\n}\\n.hw-conv-card {\\n position: relative;\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n width: 100%;\\n padding: 14px 16px;\\n border-radius: 14px;\\n background: var(--hw-bg);\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.03);\\n cursor: pointer;\\n transition: box-shadow 0.15s, transform 0.1s;\\n text-align: left;\\n font-family: inherit;\\n color: var(--hw-text);\\n}\\n.hw-conv-card:hover {\\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.04);\\n}\\n.hw-conv-card:active {\\n transform: scale(0.99);\\n}\\n.hw-conv-card-row {\\n display: flex;\\n align-items: center;\\n gap: 12px;\\n}\\n.hw-conv-card-avatar {\\n width: 36px;\\n height: 36px;\\n border-radius: 10px;\\n background: var(--hw-agent-bg, var(--hw-agent-bg-default, var(--hw-bg-subtle)));\\n color: var(--hw-text-3);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n flex-shrink: 0;\\n overflow: hidden;\\n}\\n.hw-conv-card-avatar svg {\\n width: 20px;\\n height: 20px;\\n}\\n.hw-conv-card-avatar-img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n}\\n.hw-conv-card-avatar .hw-agent-img {\\n object-fit: var(--hw-agent-fit, var(--hw-agent-fit-default, cover));\\n padding: var(--hw-agent-pad, var(--hw-agent-pad-default, 0));\\n box-sizing: border-box;\\n}\\n.hw-conv-card-avatar--team {\\n background: var(--hw-brand, #0a0a0a);\\n color: var(--hw-on-brand, #fff);\\n}\\n.hw-conv-card-avatar-initials {\\n font-size: 12px;\\n font-weight: 600;\\n line-height: 1;\\n letter-spacing: 0.02em;\\n}\\n.hw-conv-card-content {\\n flex: 1;\\n min-width: 0;\\n}\\n.hw-conv-card-top {\\n display: flex;\\n align-items: baseline;\\n gap: 8px;\\n}\\n.hw-conv-card-name {\\n flex: 1;\\n font-size: 14px;\\n font-weight: 600;\\n color: var(--hw-text);\\n}\\n.hw-conv-card-time {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n flex-shrink: 0;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-conv-card-preview {\\n font-size: 13px;\\n color: var(--hw-text-2);\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n line-height: 1.4;\\n margin-top: 1px;\\n}\\n.hw-conv-card--unread .hw-conv-card-name {\\n color: var(--hw-text);\\n}\\n.hw-conv-card--unread .hw-conv-card-time {\\n color: var(--hw-primary);\\n font-weight: 500;\\n}\\n.hw-conv-card-badge {\\n position: absolute;\\n top: 12px;\\n right: 12px;\\n min-width: 18px;\\n height: 18px;\\n border-radius: 9px;\\n background: var(--hw-primary);\\n color: white;\\n font-size: 11px;\\n font-weight: 600;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 0 5px;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-empty-state {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n padding: 32px;\\n text-align: center;\\n}\\n.hw-empty-icon-wrap {\\n width: 48px;\\n height: 48px;\\n border-radius: 50%;\\n background: var(--hw-bg-subtle);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n margin-bottom: 16px;\\n color: var(--hw-text-3);\\n}\\n.hw-empty-icon-wrap svg {\\n width: 24px;\\n height: 24px;\\n}\\n.hw-empty-title {\\n font-size: 15px;\\n font-weight: 600;\\n color: var(--hw-text);\\n margin-bottom: 4px;\\n}\\n.hw-empty-desc {\\n font-size: 13px;\\n color: var(--hw-text-3);\\n margin-bottom: 20px;\\n}\\n.hw-empty-btn {\\n padding: 8px 20px;\\n border-radius: 10px;\\n background: var(--hw-primary);\\n color: white;\\n border: none;\\n font-size: 13px;\\n font-weight: 500;\\n cursor: pointer;\\n font-family: inherit;\\n transition: background 0.15s;\\n}\\n.hw-empty-btn:hover {\\n background: var(--hw-primary-hover);\\n}\\n.hw-tabs {\\n display: flex;\\n border-top: 1px solid var(--hw-border);\\n flex-shrink: 0;\\n background: var(--hw-bg-subtle);\\n}\\n.hw-tabs-item {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 2px;\\n padding: 8px 0;\\n border: none;\\n background: none;\\n cursor: pointer;\\n font-family: inherit;\\n font-size: 11px;\\n font-weight: 500;\\n color: var(--hw-text-3);\\n transition: color 0.15s;\\n}\\n.hw-tabs-item svg {\\n width: 22px;\\n height: 22px;\\n overflow: visible;\\n}\\n.hw-tabs-item--active {\\n color: var(--hw-text);\\n}\\n.hw-tabs-item:hover {\\n color: var(--hw-text-2);\\n}\\n.hw-tabs-item:active {\\n transform: scale(0.94);\\n transition: transform 0.14s cubic-bezier(0.23, 1, 0.32, 1), color 0.15s;\\n}\\n.hw-tabs-icon-wrap {\\n position: relative;\\n display: inline-flex;\\n}\\n.hw-tabs-badge {\\n position: absolute;\\n top: -6px;\\n right: -10px;\\n min-width: 16px;\\n height: 16px;\\n border-radius: 8px;\\n background: var(--hw-primary);\\n color: white;\\n font-size: 10px;\\n font-weight: 700;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 0 4px;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-messages {\\n flex: 1;\\n overflow-y: auto;\\n overflow-x: hidden;\\n padding: 16px 14px 8px;\\n background: var(--hw-bg-subtle);\\n display: flex;\\n flex-direction: column;\\n gap: 14px;\\n overscroll-behavior: contain;\\n min-width: 0;\\n scrollbar-color: rgba(0, 0, 0, 0.2) transparent;\\n scrollbar-width: thin;\\n}\\n.hw-messages::-webkit-scrollbar {\\n width: 10px;\\n height: 10px;\\n}\\n.hw-messages::-webkit-scrollbar-track {\\n background: transparent;\\n}\\n.hw-messages::-webkit-scrollbar-thumb {\\n background: rgba(0, 0, 0, 0.16);\\n background-clip: content-box;\\n border: 3px solid transparent;\\n border-radius: 999px;\\n}\\n.hw-messages::-webkit-scrollbar-thumb:hover {\\n background: rgba(0, 0, 0, 0.28);\\n background-clip: content-box;\\n}\\n.hw-widget[data-theme=dark] .hw-messages {\\n scrollbar-color: rgba(255, 255, 255, 0.26) transparent;\\n}\\n.hw-widget[data-theme=dark] .hw-messages::-webkit-scrollbar-thumb {\\n background: rgba(255, 255, 255, 0.2);\\n background-clip: content-box;\\n}\\n.hw-widget[data-theme=dark] .hw-messages::-webkit-scrollbar-thumb:hover {\\n background: rgba(255, 255, 255, 0.32);\\n background-clip: content-box;\\n}\\n.hw-empty {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n padding: 32px;\\n color: var(--hw-text-3);\\n text-align: center;\\n}\\n.hw-empty-icon {\\n width: 40px;\\n height: 40px;\\n margin-bottom: 12px;\\n opacity: 0.3;\\n}\\n.hw-empty-text {\\n font-size: 13px;\\n}\\n.hw-date-sep {\\n display: flex;\\n align-items: center;\\n gap: 12px;\\n padding: 12px 0;\\n}\\n.hw-date-sep-line {\\n flex: 1;\\n height: 1px;\\n background: var(--hw-border-md);\\n}\\n.hw-date-sep-text {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n font-weight: 500;\\n white-space: nowrap;\\n}\\n.hw-msg {\\n display: flex;\\n padding: 4px 0;\\n max-width: 75%;\\n min-width: 0;\\n animation: hw-msg-appear 0.25s ease-out;\\n}\\n@keyframes hw-msg-appear {\\n from {\\n opacity: 0;\\n transform: translateY(6px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n.hw-msg--visitor {\\n align-self: flex-end;\\n}\\n.hw-msg--team,\\n.hw-msg--ai {\\n align-self: flex-start;\\n}\\n.hw-msg--ai {\\n width: 100%;\\n max-width: 100%;\\n}\\n.hw-msg-body {\\n display: flex;\\n flex-direction: column;\\n min-width: 0;\\n max-width: 100%;\\n}\\n.hw-msg-bubble {\\n padding: 10px 14px;\\n border-radius: 16px;\\n font-size: 14px;\\n line-height: 1.45;\\n white-space: pre-wrap;\\n word-break: break-word;\\n overflow-wrap: anywhere;\\n max-width: 100%;\\n}\\n.hw-msg--visitor .hw-msg-bubble {\\n background: var(--hw-primary);\\n color: white;\\n border-bottom-right-radius: 4px;\\n}\\n.hw-msg--team .hw-msg-bubble {\\n background: var(--hw-visitor-bubble-bg);\\n color: var(--hw-visitor-bubble-text);\\n border-bottom-left-radius: 4px;\\n}\\n.hw-msg--ai .hw-msg-bubble {\\n background: var(--hw-visitor-bubble-bg);\\n color: var(--hw-text);\\n border-bottom-left-radius: 4px;\\n white-space: normal;\\n max-width: min(100%, 640px);\\n}\\n.hw-msg--ai .hw-msg-body {\\n width: 100%;\\n}\\n.hw-msg--ai .hw-msg-bubble:has(.hw-code),\\n.hw-msg--ai .hw-msg-bubble:has(pre) {\\n width: 100%;\\n}\\n.hw-quick-replies {\\n display: flex;\\n flex-wrap: wrap;\\n gap: 6px;\\n margin-top: 8px;\\n}\\n.hw-quick-reply-btn {\\n font: inherit;\\n font-size: 13px;\\n font-weight: 500;\\n padding: 6px 14px;\\n border-radius: 18px;\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n background: var(--hw-bg, #fff);\\n color: var(--hw-text-1, #1a1a1a);\\n cursor: pointer;\\n transition:\\n background 120ms ease,\\n border-color 120ms ease,\\n box-shadow 120ms ease,\\n transform 80ms ease;\\n line-height: 1.3;\\n}\\n.hw-quick-reply-btn:hover:not(:disabled) {\\n border-color: var(--hw-primary);\\n background: color-mix(in srgb, var(--hw-primary) 8%, transparent);\\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);\\n}\\n.hw-quick-reply-btn:active:not(:disabled) {\\n transform: scale(0.97);\\n}\\n.hw-quick-reply-btn:disabled {\\n cursor: default;\\n opacity: 0.4;\\n}\\n.hw-quick-reply-btn[data-tapped=true] {\\n background: var(--hw-primary);\\n color: white;\\n border-color: var(--hw-primary);\\n opacity: 1;\\n}\\n.hw-quick-replies[data-cancelled=true] .hw-quick-reply-btn {\\n border-color: var(--hw-border);\\n color: var(--hw-text-3);\\n}\\n.hw-msg--ai .hw-code {\\n width: 100%;\\n box-sizing: border-box;\\n}\\n.hw-msg-meta {\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n font-size: 11px;\\n color: var(--hw-text-2);\\n margin-top: 2px;\\n padding: 0 4px;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-msg-time {\\n white-space: nowrap;\\n}\\n.hw-msg--visitor .hw-msg-meta {\\n text-align: right;\\n}\\n.hw-msg--team .hw-msg-body,\\n.hw-msg--ai .hw-msg-body {\\n align-items: flex-start;\\n}\\n.hw-msg--visitor .hw-msg-body {\\n align-items: flex-end;\\n}\\n.hw-typing {\\n display: flex;\\n flex-direction: column;\\n gap: 3px;\\n padding: 8px 0;\\n width: fit-content;\\n animation: hw-msg-appear 0.25s ease-out;\\n}\\n.hw-typing-dots {\\n display: flex;\\n gap: 3px;\\n padding: 6px 2px;\\n width: fit-content;\\n}\\n.hw-typing-dot {\\n width: 6px;\\n height: 6px;\\n border-radius: 50%;\\n background: var(--hw-text-3);\\n animation: hw-typing-bounce 1.4s infinite;\\n}\\n.hw-typing-dot:nth-child(2) {\\n animation-delay: 0.2s;\\n}\\n.hw-typing-dot:nth-child(3) {\\n animation-delay: 0.4s;\\n}\\n@keyframes hw-typing-bounce {\\n 0%, 60%, 100% {\\n transform: translateY(0);\\n }\\n 30% {\\n transform: translateY(-4px);\\n }\\n}\\n.hw-streaming-cursor {\\n display: inline-block;\\n width: 2px;\\n height: 1em;\\n background: currentColor;\\n opacity: 0.6;\\n margin-left: 1px;\\n vertical-align: text-bottom;\\n animation: hw-cursor-blink 0.8s step-end infinite;\\n}\\n@keyframes hw-cursor-blink {\\n 50% {\\n opacity: 0;\\n }\\n}\\n.hw-link-preview {\\n display: flex;\\n flex-direction: column;\\n gap: 0;\\n border: 1px solid var(--hw-border, rgba(0, 0, 0, 0.08));\\n border-radius: 10px;\\n overflow: hidden;\\n text-decoration: none;\\n color: inherit;\\n margin-top: 6px;\\n transition: background 0.15s;\\n}\\n.hw-link-preview:hover {\\n background: var(--hw-bg-hover, rgba(0, 0, 0, 0.02));\\n}\\n.hw-link-preview-img {\\n width: 100%;\\n height: 56px;\\n flex: 0 0 56px;\\n object-fit: cover;\\n object-position: top;\\n border-radius: 0;\\n}\\n.hw-link-preview-body {\\n padding: 8px 10px;\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n min-width: 0;\\n justify-content: center;\\n}\\n.hw-link-preview-favicon {\\n width: 16px;\\n height: 16px;\\n border-radius: 2px;\\n}\\n.hw-link-preview-title {\\n font-size: 12.5px;\\n font-weight: 600;\\n line-height: 1.3;\\n color: var(--hw-text, #1a1a1a);\\n display: -webkit-box;\\n -webkit-line-clamp: 2;\\n -webkit-box-orient: vertical;\\n overflow: hidden;\\n}\\n.hw-link-preview-desc {\\n font-size: 11.5px;\\n line-height: 1.4;\\n color: var(--hw-text-2, #6b7280);\\n display: -webkit-box;\\n -webkit-line-clamp: 2;\\n -webkit-box-orient: vertical;\\n overflow: hidden;\\n}\\n.hw-link-preview-url {\\n font-size: 11px;\\n color: var(--hw-text-2);\\n}\\n.hw-msg-links {\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n max-width: 240px;\\n}\\n.hw-loading {\\n flex: 1;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.hw-loading-dots {\\n display: flex;\\n gap: 4px;\\n}\\n.hw-loading-dot {\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: var(--hw-text-4);\\n animation: hw-loading-pulse 1.4s infinite;\\n}\\n.hw-loading-dot:nth-child(2) {\\n animation-delay: 0.2s;\\n}\\n.hw-loading-dot:nth-child(3) {\\n animation-delay: 0.4s;\\n}\\n@keyframes hw-loading-pulse {\\n 0%, 60%, 100% {\\n opacity: 0.3;\\n transform: scale(0.8);\\n }\\n 30% {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n@keyframes hw-skeleton-shimmer {\\n 0% {\\n background-position: -200px 0;\\n }\\n 100% {\\n background-position: calc(200px + 100%) 0;\\n }\\n}\\n.hw-skeleton {\\n background:\\n linear-gradient(\\n 90deg,\\n var(--hw-bg-subtle) 25%,\\n rgba(0, 0, 0, 0.04) 50%,\\n var(--hw-bg-subtle) 75%);\\n background-size: 200px 100%;\\n animation: hw-skeleton-shimmer 1.5s ease-in-out infinite;\\n border-radius: 6px;\\n}\\n.hw-skeleton-messages {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n padding: 16px;\\n gap: 16px;\\n}\\n.hw-skeleton-msg {\\n display: flex;\\n gap: 10px;\\n align-items: flex-start;\\n}\\n.hw-skeleton-msg--right {\\n flex-direction: row-reverse;\\n}\\n.hw-skeleton-avatar {\\n width: 28px;\\n height: 28px;\\n border-radius: 8px;\\n flex-shrink: 0;\\n}\\n.hw-skeleton-bubble {\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n}\\n.hw-skeleton-line {\\n height: 12px;\\n border-radius: 6px;\\n}\\n.hw-skeleton-convs {\\n display: flex;\\n flex-direction: column;\\n padding: 8px 0;\\n}\\n.hw-skeleton-conv {\\n display: flex;\\n gap: 10px;\\n align-items: center;\\n padding: 10px 16px;\\n}\\n.hw-skeleton-conv-avatar {\\n width: 36px;\\n height: 36px;\\n border-radius: 8px;\\n flex-shrink: 0;\\n}\\n.hw-skeleton-conv-lines {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n}\\n.hw-skeleton-content {\\n display: flex;\\n flex-direction: column;\\n padding: 12px 16px;\\n gap: 12px;\\n}\\n.hw-skeleton-content-item {\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n padding: 12px;\\n border-radius: 10px;\\n background: var(--hw-bg);\\n}\\n.hw-skeleton-title {\\n height: 22px;\\n width: 65%;\\n border-radius: 6px;\\n}\\n.hw-skeleton-badge {\\n width: 42px;\\n height: 18px;\\n border-radius: 9px;\\n}\\n.hw-skeleton-date {\\n width: 60px;\\n height: 12px;\\n border-radius: 6px;\\n}\\n.hw-skeleton-h2 {\\n height: 16px;\\n border-radius: 6px;\\n}\\n.hw-skeleton-bullet {\\n padding-left: 20px;\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n}\\n.hw-skeleton-bullet-line {\\n height: 14px;\\n border-radius: 7px;\\n}\\n.hw-email-card {\\n max-width: min(100%, 340px);\\n margin: 0;\\n padding: 0;\\n border: 0;\\n border-radius: 0;\\n background: none;\\n box-shadow: none;\\n animation: hw-email-slide-in 0.25s ease-out;\\n}\\n@keyframes hw-email-slide-in {\\n from {\\n opacity: 0;\\n transform: translateY(8px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n.hw-email-card-title {\\n font-size: 14px;\\n font-weight: 550;\\n color: var(--hw-text, #1a1a1a);\\n line-height: 1.3;\\n margin: 0 0 2px;\\n}\\n.hw-email-card-subtitle {\\n font-size: 12px;\\n color: var(--hw-text-2, #888);\\n line-height: 1.4;\\n margin: 0;\\n}\\n.hw-email-card-row {\\n max-width: 300px;\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n margin-top: 9px;\\n padding: 3px 3px 3px 12px;\\n border-radius: 999px;\\n border: 1px solid var(--hw-border, rgba(0,0,0,0.1));\\n background: var(--hw-bg-subtle, #fafafa);\\n transition: border-color 0.15s, box-shadow 0.15s;\\n}\\n.hw-email-card-row:focus-within {\\n border-color: var(--hw-focus-border, rgba(0,0,0,0.2));\\n box-shadow: 0 0 0 2px var(--hw-focus-ring, rgba(0,0,0,0.06));\\n}\\n.hw-email-card-input {\\n flex: 1;\\n min-width: 0;\\n padding: 6px 0;\\n border: 0;\\n background: transparent;\\n color: var(--hw-text, #1a1a1a);\\n font: inherit;\\n font-size: 13px;\\n outline: none;\\n}\\n.hw-email-card-input::placeholder {\\n color: var(--hw-text-3, #999);\\n}\\n.hw-email-card-row:has(.hw-email-card-input--error) {\\n border-color: #ef4444;\\n}\\n.hw-email-card-submit {\\n flex: none;\\n display: grid;\\n place-items: center;\\n width: 28px;\\n height: 28px;\\n border: none;\\n border-radius: 50%;\\n background: var(--hw-brand, #0a0a0a);\\n color: var(--hw-on-brand, #fff);\\n cursor: pointer;\\n transition: opacity 0.15s, transform 0.15s;\\n}\\n.hw-email-card-submit:hover:not(:disabled) {\\n transform: scale(1.06);\\n}\\n.hw-email-card-submit:disabled {\\n opacity: 0.45;\\n cursor: default;\\n}\\n.hw-email-card--success {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n padding: 2px 0;\\n font-size: 13px;\\n color: var(--hw-text-2, #888);\\n animation: hw-email-slide-in 0.2s ease-out;\\n}\\n.hw-email-card--success svg {\\n flex-shrink: 0;\\n}\\n.hw-composer {\\n display: flex;\\n flex-direction: column;\\n padding: 12px 16px;\\n background: transparent;\\n flex-shrink: 0;\\n}\\n.hw-composer--compact {\\n padding: 8px 12px;\\n}\\n.hw-composer-box {\\n display: flex;\\n flex-direction: column;\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n border-radius: 16px;\\n overflow: hidden;\\n transition: border-color 0.2s;\\n background: var(--hw-bg);\\n}\\n.hw-composer-box:focus-within {\\n border-color: var(--hw-focus-border);\\n box-shadow: 0 0 0 3px var(--hw-focus-ring);\\n}\\n.hw-composer-input {\\n resize: none;\\n border: none;\\n padding: 12px 16px 4px;\\n font-size: 14px;\\n font-family: inherit;\\n line-height: 1.4;\\n outline: none;\\n min-height: 40px;\\n max-height: 220px;\\n background: transparent;\\n color: var(--hw-text);\\n field-sizing: content;\\n}\\n.hw-composer-input:focus {\\n outline: none;\\n}\\n.hw-composer-input:focus-visible {\\n outline: none;\\n}\\n.hw-composer-input::placeholder {\\n color: var(--hw-text-4);\\n}\\n.hw-composer-toolbar {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 4px 10px 10px;\\n}\\n.hw-composer-toolbar-left {\\n display: flex;\\n align-items: center;\\n gap: 4px;\\n}\\n.hw-composer-send {\\n width: 32px;\\n height: 32px;\\n border-radius: 50%;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n flex-shrink: 0;\\n transition:\\n background-color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n color 140ms cubic-bezier(0.23, 1, 0.32, 1),\\n transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\\n}\\n.hw-composer-send:active:not(:disabled) {\\n transform: scale(0.9);\\n}\\n.hw-composer-send--active {\\n background: var(--hw-primary);\\n color: white;\\n}\\n.hw-composer-send--inactive {\\n background: var(--hw-border);\\n color: var(--hw-text-4);\\n cursor: default;\\n}\\n.hw-composer-send svg {\\n width: 14px;\\n height: 14px;\\n}\\n.hw-composer-charcount {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n font-variant-numeric: tabular-nums;\\n opacity: 1;\\n transform: translateY(0);\\n transition:\\n color 180ms cubic-bezier(0.23, 1, 0.32, 1),\\n opacity 180ms cubic-bezier(0.23, 1, 0.32, 1),\\n transform 180ms cubic-bezier(0.23, 1, 0.32, 1);\\n}\\n@starting-style {\\n .hw-composer-charcount {\\n opacity: 0;\\n transform: translateY(3px);\\n }\\n}\\n.hw-composer-charcount--over {\\n color: #ef4444;\\n font-weight: 600;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-composer-charcount {\\n transform: none;\\n transition: color 160ms ease, opacity 160ms ease;\\n }\\n @starting-style {\\n .hw-composer-charcount {\\n transform: none;\\n }\\n }\\n}\\n.hw-composer-previews {\\n display: flex;\\n gap: 6px;\\n padding: 8px 10px 0;\\n overflow-x: auto;\\n scrollbar-width: none;\\n}\\n.hw-composer-previews::-webkit-scrollbar {\\n display: none;\\n}\\n.hw-composer-preview {\\n position: relative;\\n width: 48px;\\n height: 48px;\\n border-radius: 8px;\\n overflow: hidden;\\n flex-shrink: 0;\\n background: var(--hw-border);\\n cursor: pointer;\\n}\\n.hw-composer-preview--error {\\n outline: 2px solid #ef4444;\\n outline-offset: -2px;\\n}\\n.hw-composer-preview-img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n}\\n.hw-composer-preview-file {\\n width: 100%;\\n height: 100%;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n background: var(--hw-bg-subtle);\\n}\\n.hw-composer-preview-ext {\\n font-size: 10px;\\n font-weight: 700;\\n color: var(--hw-text-3);\\n text-transform: uppercase;\\n}\\n.hw-composer-preview-loader {\\n position: absolute;\\n inset: 0;\\n background: rgba(0, 0, 0, 0.35);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.hw-composer-preview-loader::after {\\n content: \\\"\\\";\\n width: 16px;\\n height: 16px;\\n border: 2px solid rgba(255, 255, 255, 0.3);\\n border-top-color: white;\\n border-radius: 50%;\\n animation: hw-spin 0.6s linear infinite;\\n}\\n@keyframes hw-spin {\\n to {\\n transform: rotate(360deg);\\n }\\n}\\n.hw-composer-preview-badge {\\n position: absolute;\\n top: 2px;\\n right: 2px;\\n width: 16px;\\n height: 16px;\\n border-radius: 50%;\\n background: #ef4444;\\n color: white;\\n font-size: 10px;\\n font-weight: 700;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.hw-composer-preview-remove {\\n position: absolute;\\n top: 2px;\\n right: 2px;\\n width: 18px;\\n height: 18px;\\n border-radius: 50%;\\n border: none;\\n background: rgba(0, 0, 0, 0.55);\\n color: white;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n opacity: 0;\\n transition: opacity 0.15s;\\n}\\n.hw-composer-preview-remove svg {\\n width: 10px;\\n height: 10px;\\n}\\n.hw-composer-preview:hover .hw-composer-preview-remove {\\n opacity: 1;\\n}\\n.hw-composer-attach {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n color: var(--hw-text-3);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n opacity: 0.7;\\n transition: opacity 0.15s;\\n}\\n.hw-composer-attach:hover {\\n opacity: 1;\\n}\\n.hw-composer-attach svg {\\n width: 16px;\\n height: 16px;\\n}\\n.hw-msg-images {\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n margin-bottom: 4px;\\n}\\n.hw-msg-image-link {\\n display: block;\\n border-radius: 14px;\\n overflow: hidden;\\n line-height: 0;\\n}\\n.hw-msg-image {\\n max-width: 140px;\\n max-height: 80px;\\n object-fit: cover;\\n border-radius: 8px;\\n outline: 1px solid rgba(0, 0, 0, 0.08);\\n outline-offset: -1px;\\n}\\n.hw-msg-files {\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n margin-top: 4px;\\n}\\n.hw-msg-file {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n padding: 8px 12px;\\n border-radius: 10px;\\n background: var(--hw-bg-subtle);\\n text-decoration: none;\\n color: var(--hw-text);\\n transition: background 0.15s;\\n}\\n.hw-msg-file:hover {\\n background: var(--hw-border);\\n}\\n.hw-msg-file-icon {\\n flex-shrink: 0;\\n width: 20px;\\n height: 20px;\\n color: var(--hw-text-3);\\n}\\n.hw-msg-file-icon svg {\\n width: 100%;\\n height: 100%;\\n}\\n.hw-msg-file-info {\\n display: flex;\\n flex-direction: column;\\n min-width: 0;\\n}\\n.hw-msg-file-name {\\n font-size: 13px;\\n font-weight: 500;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n.hw-msg-file-size {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n}\\n.hw-msg-image-link {\\n cursor: pointer;\\n border: none;\\n padding: 0;\\n background: none;\\n display: block;\\n line-height: 0;\\n}\\n.hw-hover-preview {\\n position: fixed;\\n z-index: 2147483001;\\n padding: 6px;\\n border-radius: 14px;\\n background: white;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.06);\\n cursor: pointer;\\n animation: hw-hover-in 0.15s ease-out;\\n}\\n@media (prefers-color-scheme: dark) {\\n .hw-hover-preview {\\n background: #1c1c1e;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.08);\\n }\\n}\\n@keyframes hw-hover-in {\\n from {\\n opacity: 0;\\n transform: scale(0.96) translateY(4px);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1) translateY(0);\\n }\\n}\\n.hw-hover-preview-img {\\n width: 100%;\\n max-height: 200px;\\n object-fit: contain;\\n border-radius: 10px;\\n display: block;\\n outline: 1px solid rgba(0, 0, 0, 0.08);\\n outline-offset: -1px;\\n}\\n.hw-hover-preview--doc {\\n display: flex;\\n align-items: center;\\n gap: 10px;\\n padding: 10px 14px;\\n}\\n.hw-hover-preview-doc-icon {\\n width: 28px;\\n height: 28px;\\n flex-shrink: 0;\\n}\\n.hw-hover-preview-doc-icon svg {\\n width: 100%;\\n height: 100%;\\n}\\n.hw-hover-preview-doc-info {\\n display: flex;\\n flex-direction: column;\\n min-width: 0;\\n}\\n.hw-hover-preview-doc-name {\\n font-size: 13px;\\n font-weight: 500;\\n color: var(--hw-text);\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n.hw-hover-preview-doc-hint {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n}\\n.hw-event {\\n display: flex;\\n justify-content: center;\\n padding: 8px 16px;\\n}\\n.hw-event-text {\\n font-size: 12px;\\n color: var(--hw-text-3);\\n text-align: center;\\n}\\n.hw-event--card {\\n justify-content: flex-start;\\n align-items: center;\\n gap: 10px;\\n background: var(--hw-bg-subtle);\\n padding: 10px 14px;\\n border-radius: 12px;\\n margin: 4px 16px;\\n}\\n.hw-event-avatar {\\n width: 32px;\\n height: 32px;\\n border-radius: 50%;\\n background: var(--hw-agent-bg, var(--hw-agent-bg-default, var(--hw-bg-hover, #e0e0e0)));\\n color: var(--hw-text-2, #555);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 11px;\\n font-weight: 600;\\n flex-shrink: 0;\\n overflow: hidden;\\n}\\n.hw-event-avatar-img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n}\\n.hw-event-avatar .hw-agent-img {\\n object-fit: var(--hw-agent-fit, var(--hw-agent-fit-default, cover));\\n padding: var(--hw-agent-pad, var(--hw-agent-pad-default, 0));\\n box-sizing: border-box;\\n}\\n.hw-event-body {\\n font-size: 13px;\\n line-height: 1.3;\\n}\\n.hw-event-name {\\n font-weight: 600;\\n color: var(--hw-text);\\n}\\n.hw-event-action {\\n color: var(--hw-text-2);\\n}\\n.hw-resolved-banner {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 12px 16px;\\n border-top: 1px solid var(--hw-border);\\n background: var(--hw-bg-subtle);\\n color: var(--hw-text-2);\\n font-size: 13px;\\n flex-shrink: 0;\\n}\\n.hw-new {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n background: var(--hw-bg-subtle);\\n}\\n.hw-new-body {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n padding: 32px 24px;\\n text-align: center;\\n}\\n.hw-new-welcome {\\n flex: 1;\\n padding: 16px 20px;\\n overflow-y: auto;\\n}\\n.hw-new-heading {\\n font-size: 17px;\\n font-weight: 600;\\n color: var(--hw-text);\\n margin-bottom: 6px;\\n}\\n.hw-new-desc {\\n font-size: 13px;\\n color: var(--hw-text-2);\\n margin-bottom: 24px;\\n}\\n.hw-powered {\\n text-align: center;\\n padding: 8px;\\n font-size: 11px;\\n color: var(--hw-text-4);\\n flex-shrink: 0;\\n}\\n.hw-powered a {\\n color: var(--hw-text-2);\\n text-decoration: none;\\n font-weight: 500;\\n}\\n.hw-powered a:hover {\\n color: var(--hw-text);\\n}\\n@media (max-width: 479px) {\\n .hw-widget {\\n bottom: 16px;\\n right: 16px;\\n left: auto;\\n }\\n .hw-window {\\n position: fixed;\\n top: 0;\\n left: 0;\\n right: 0;\\n bottom: 0;\\n width: 100%;\\n height: var(--hw-visible-height, 100%);\\n border-radius: 0;\\n animation: hw-mob-up 0.3s cubic-bezier(0.22, 1, 0.36, 1);\\n }\\n .hw-window--closing {\\n animation: hw-mob-down 0.2s ease forwards;\\n }\\n @keyframes hw-mob-up {\\n from {\\n opacity: 0;\\n transform: translateY(100%);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n }\\n @keyframes hw-mob-down {\\n from {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n to {\\n opacity: 0;\\n transform: translateY(100%);\\n }\\n }\\n .hw-hero {\\n padding-top: calc(20px + env(safe-area-inset-top, 0px));\\n }\\n .hw-header {\\n padding-top: env(safe-area-inset-top, 0px);\\n }\\n .hw-tabs {\\n padding-bottom: env(safe-area-inset-bottom, 0px);\\n }\\n .hw-composer {\\n padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));\\n }\\n .hw-powered {\\n padding-bottom: calc(5px + env(safe-area-inset-bottom, 0px));\\n }\\n .hw-header-close,\\n .hw-header-back,\\n .hw-header-action {\\n width: 34px;\\n height: 34px;\\n }\\n .hw-composer-send {\\n width: 40px;\\n height: 40px;\\n }\\n .hw-window ~ .hw-bubble {\\n display: none;\\n }\\n .hw-messages {\\n padding: 12px 14px;\\n }\\n .hw-msg {\\n max-width: 82%;\\n }\\n .hw-msg--ai {\\n max-width: 100%;\\n }\\n}\\n.hw-preview {\\n position: absolute;\\n bottom: calc(100% + 12px);\\n right: 0;\\n width: 300px;\\n max-width: calc(100vw - 40px);\\n background: var(--hw-bg);\\n border: 1px solid var(--hw-border);\\n border-radius: 16px;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);\\n animation: hw-preview-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\\n overflow: hidden;\\n cursor: pointer;\\n transition: transform 0.15s, box-shadow 0.15s;\\n}\\n.hw-preview.hw-preview--anchored {\\n position: static;\\n bottom: auto;\\n right: auto;\\n width: 100%;\\n max-width: 100%;\\n}\\n.hw-preview.hw-preview--anchored .hw-preview-avatar {\\n background: none;\\n}\\n.hw-preview.hw-preview--anchored .hw-preview-avatar img,\\n.hw-preview.hw-preview--anchored .hw-preview-avatar svg {\\n width: 100%;\\n height: 100%;\\n object-fit: contain;\\n}\\n.hw-preview:hover {\\n transform: translateY(-2px);\\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.08);\\n}\\n@keyframes hw-preview-in {\\n from {\\n opacity: 0;\\n transform: translateY(8px) scale(0.95);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0) scale(1);\\n }\\n}\\n@keyframes hw-preview-out {\\n from {\\n opacity: 1;\\n transform: translateY(0) scale(1);\\n }\\n to {\\n opacity: 0;\\n transform: translateY(8px) scale(0.95);\\n }\\n}\\n.hw-preview-header {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n padding: 12px 14px 0;\\n}\\n.hw-preview-avatar {\\n width: 28px;\\n height: 28px;\\n border-radius: 50%;\\n background:\\n linear-gradient(\\n 135deg,\\n var(--hw-primary),\\n color-mix(in srgb, var(--hw-primary) 50%, black));\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n color: white;\\n flex-shrink: 0;\\n overflow: hidden;\\n}\\n.hw-preview-avatar svg {\\n width: 16px;\\n height: 16px;\\n}\\n.hw-preview-avatar img {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n display: block;\\n}\\n.hw-preview-name {\\n font-size: 13px;\\n font-weight: 600;\\n color: var(--hw-text);\\n flex: 1;\\n}\\n.hw-preview-close {\\n width: 24px;\\n height: 24px;\\n border: none;\\n background: transparent;\\n color: var(--hw-text-3);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 50%;\\n transition: background 0.15s, color 0.15s;\\n flex-shrink: 0;\\n}\\n.hw-preview-close:hover {\\n background: var(--hw-bg-subtle);\\n color: var(--hw-text-2);\\n}\\n.hw-preview-close:active {\\n transform: scale(0.90);\\n transition:\\n transform 0.14s cubic-bezier(0.23, 1, 0.32, 1),\\n background 0.15s,\\n color 0.15s;\\n}\\n.hw-preview-close svg {\\n width: 12px;\\n height: 12px;\\n}\\n.hw-preview-body {\\n padding: 4px 14px;\\n font-size: 14px;\\n line-height: 1.45;\\n color: var(--hw-text-2);\\n}\\n.hw-preview-body:first-of-type {\\n padding-top: 8px;\\n}\\n.hw-preview-body:last-child {\\n padding-bottom: 14px;\\n}\\n.hw-preview-footer {\\n margin-top: 2px;\\n padding: 8px 14px 12px;\\n border-top: 1px solid var(--hw-border);\\n font-size: 11px;\\n line-height: 1.3;\\n color: var(--hw-text-2);\\n opacity: 0.65;\\n}\\n.hw-preview-prompt {\\n padding: 2px 14px 6px;\\n font-size: 14px;\\n font-weight: 500;\\n color: var(--hw-text-1);\\n}\\n.hw-preview-quick-replies {\\n padding: 0 14px 14px;\\n margin-top: 0;\\n}\\n.hw-awaiting {\\n margin-top: 2px;\\n padding-left: 44px;\\n font-size: 11px;\\n line-height: 1.4;\\n color: var(--hw-text-3, var(--hw-text-muted));\\n}\\n.hw-preview-dock {\\n position: absolute;\\n bottom: calc(100% + 12px);\\n right: 0;\\n display: flex;\\n flex-direction: column;\\n align-items: flex-end;\\n gap: 8px;\\n pointer-events: none;\\n}\\n.hw-preview-dock > .hw-preview,\\n.hw-preview-dock > .hw-preview-stack {\\n position: relative;\\n bottom: auto;\\n right: auto;\\n pointer-events: auto;\\n}\\n.hw-preview--closing {\\n animation: hw-preview-out 0.2s ease-in forwards;\\n}\\n.hw-preview-stack {\\n position: absolute;\\n bottom: calc(100% + 12px);\\n right: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n}\\n.hw-preview-stack .hw-preview {\\n position: relative;\\n bottom: auto;\\n right: auto;\\n}\\n.hw-preview-stack.hw-preview-stack--anchored {\\n position: static;\\n bottom: auto;\\n right: auto;\\n width: 100%;\\n}\\n.hw-preview-more {\\n align-self: flex-end;\\n padding: 4px 10px;\\n border: 0;\\n border-radius: 999px;\\n background: var(--hw-bg);\\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), inset 0 0 0 1px var(--hw-border);\\n color: var(--hw-text-2);\\n font: inherit;\\n font-size: 12px;\\n line-height: 1.4;\\n cursor: pointer;\\n transition: background 0.12s, color 0.12s;\\n}\\n.hw-preview-more:hover {\\n background: var(--hw-bg-hover);\\n color: var(--hw-text);\\n}\\n.hw-preview--announcement {\\n width: 340px;\\n}\\n.hw-preview--announcement .hw-preview-body--title {\\n font-weight: 600;\\n color: var(--hw-text);\\n font-size: 15px;\\n line-height: 1.3;\\n padding-top: 10px;\\n}\\n.hw-preview--announcement .hw-preview-body--desc {\\n font-size: 13px;\\n color: var(--hw-text-2);\\n line-height: 1.5;\\n padding-bottom: 16px;\\n}\\n.hw-announcement-badge {\\n display: inline-block;\\n margin: 8px 14px 0;\\n padding: 2px 8px;\\n font-size: 10px;\\n font-weight: 700;\\n text-transform: uppercase;\\n letter-spacing: 0.04em;\\n color: var(--hw-primary);\\n background: color-mix(in srgb, var(--hw-primary) 10%, transparent);\\n border-radius: 4px;\\n}\\n.hw-whats-new {\\n border-radius: 14px;\\n background: var(--hw-bg);\\n border: 0;\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.03);\\n overflow: hidden;\\n}\\n.hw-whats-new-header {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 12px 14px 0;\\n}\\n.hw-whats-new-title {\\n font-size: 12px;\\n font-weight: 600;\\n color: var(--hw-text-2);\\n}\\n.hw-whats-new-view-all {\\n font-size: 11px;\\n font-weight: 500;\\n color: var(--hw-primary);\\n background: none;\\n border: none;\\n cursor: pointer;\\n padding: 0;\\n font-family: inherit;\\n}\\n.hw-whats-new-view-all:hover {\\n opacity: 0.8;\\n}\\n.hw-whats-new-list {\\n display: flex;\\n flex-direction: column;\\n}\\n.hw-whats-new-item {\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n width: 100%;\\n padding: 10px 14px;\\n border: none;\\n border-bottom: 1px solid var(--hw-border);\\n background: none;\\n cursor: pointer;\\n text-align: left;\\n font-family: inherit;\\n color: var(--hw-text);\\n transition: background-color 140ms ease;\\n}\\n.hw-whats-new-item:last-child {\\n border-bottom: none;\\n}\\n.hw-whats-new-item:hover {\\n background: rgba(0, 0, 0, 0.03);\\n}\\n.hw-whats-new-item-top {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n}\\n.hw-whats-new-badge {\\n font-size: 10px;\\n font-weight: 700;\\n text-transform: uppercase;\\n letter-spacing: 0.04em;\\n color: var(--hw-primary);\\n}\\n.hw-whats-new-time {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n margin-left: auto;\\n}\\n.hw-whats-new-item-title {\\n font-size: 13px;\\n font-weight: 600;\\n color: var(--hw-text);\\n line-height: 1.3;\\n display: flex;\\n align-items: baseline;\\n gap: 8px;\\n}\\n.hw-whats-new-time-inline {\\n font-size: 11px;\\n font-weight: 400;\\n color: var(--hw-text-3);\\n margin-left: auto;\\n flex-shrink: 0;\\n}\\n.hw-whats-new-item-body {\\n font-size: 12px;\\n color: var(--hw-text-2);\\n line-height: 1.4;\\n}\\n.hw-tabs-dot {\\n position: absolute;\\n top: -2px;\\n right: -6px;\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: var(--hw-primary);\\n animation: hw-badge-pop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\\n}\\n.hw-bubble-badge-dot {\\n display: block;\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: white;\\n}\\n.hw-content-search {\\n padding: 10px 16px;\\n}\\n.hw-content-search-box {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n padding: 8px 12px;\\n background: var(--hw-bg);\\n border: 1px solid var(--hw-border-md);\\n border-radius: 10px;\\n transition: border-color 0.15s, box-shadow 0.15s;\\n}\\n.hw-content-search-box:focus-within {\\n border-color: var(--hw-focus-border);\\n box-shadow: 0 0 0 3px var(--hw-focus-ring);\\n}\\n.hw-content-search-input {\\n flex: 1;\\n border: none !important;\\n outline: none !important;\\n box-shadow: none !important;\\n background: none;\\n font-size: 13px;\\n color: var(--hw-text-1);\\n font-family: inherit;\\n line-height: 1;\\n -webkit-appearance: none;\\n}\\n.hw-content-search-input:focus,\\n.hw-content-search-input:focus-visible {\\n outline: none !important;\\n box-shadow: none !important;\\n border: none !important;\\n}\\n.hw-content-search-input::placeholder {\\n color: var(--hw-text-3);\\n}\\n.hw-content-search-icon {\\n width: 15px;\\n height: 15px;\\n color: var(--hw-text-3);\\n flex-shrink: 0;\\n}\\n.hw-content-list {\\n display: flex;\\n flex-direction: column;\\n height: 100%;\\n}\\n.hw-content-entries {\\n flex: 1;\\n overflow-y: auto;\\n overscroll-behavior: contain;\\n}\\n.hw-content-entry {\\n display: block;\\n width: 100%;\\n padding: 14px 16px;\\n border: none;\\n border-bottom: 1px solid var(--hw-border);\\n background: none;\\n cursor: pointer;\\n text-align: left;\\n transition: background-color 0.15s ease;\\n -webkit-tap-highlight-color: transparent;\\n}\\n.hw-content-entry:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-content-entry:active {\\n background: var(--hw-border);\\n}\\n.hw-content-entry:last-child {\\n border-bottom: none;\\n}\\n.hw-content-entry-main {\\n display: flex;\\n align-items: center;\\n gap: 12px;\\n}\\n.hw-content-entry-text {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 3px;\\n}\\n.hw-content-entry-title {\\n font-size: 14px;\\n font-weight: 600;\\n color: var(--hw-text-1);\\n line-height: 1.3;\\n}\\n.hw-content-entry-desc {\\n font-size: 13px;\\n color: var(--hw-text-2);\\n line-height: 1.4;\\n display: -webkit-box;\\n -webkit-line-clamp: 2;\\n -webkit-box-orient: vertical;\\n overflow: hidden;\\n}\\n.hw-content-entry-meta {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n margin-top: 2px;\\n}\\n.hw-content-entry-badge {\\n font-size: 11px;\\n font-weight: 500;\\n color: var(--hw-text-3);\\n background: var(--hw-bg-hover);\\n padding: 1px 6px;\\n border-radius: 4px;\\n}\\n.hw-content-entry-date {\\n font-size: 11px;\\n color: var(--hw-text-3);\\n}\\n.hw-content-entry-chevron {\\n width: 16px;\\n height: 16px;\\n color: var(--hw-text-3);\\n flex-shrink: 0;\\n opacity: 0.5;\\n}\\n.hw-content-detail {\\n padding: 16px;\\n overflow-y: auto;\\n overscroll-behavior: contain;\\n flex: 1;\\n min-height: 0;\\n}\\n.hw-content-detail-header {\\n margin-bottom: 16px;\\n}\\n.hw-content-detail-title {\\n font-size: 17px;\\n font-weight: 700;\\n color: var(--hw-text-1);\\n margin: 0 0 6px;\\n line-height: 1.3;\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n}\\n.hw-content-detail-meta {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n.hw-content-detail-date {\\n font-size: 12px;\\n color: var(--hw-text-3);\\n}\\n.hw-content-detail-body {\\n font-size: 14px;\\n line-height: 1.6;\\n color: var(--hw-text-1);\\n}\\n.hw-markdown h1 {\\n font-size: 17px;\\n font-weight: 700;\\n margin: 0;\\n}\\n.hw-markdown h2 {\\n font-size: 15px;\\n font-weight: 600;\\n margin: 0;\\n}\\n.hw-markdown h3 {\\n font-size: 14px;\\n font-weight: 600;\\n margin: 0;\\n}\\n.hw-markdown p {\\n margin: 0;\\n}\\n.hw-markdown p:empty,\\n.hw-markdown div:empty,\\n.hw-markdown p:has(> br:only-child),\\n.hw-markdown div:has(> br:only-child) {\\n display: none;\\n}\\n.hw-markdown > * + * {\\n margin-top: 12px;\\n}\\n.hw-markdown > * + h1,\\n.hw-markdown > * + h2 {\\n margin-top: 20px;\\n}\\n.hw-markdown > * + h3 {\\n margin-top: 16px;\\n}\\n.hw-markdown > h1 + *,\\n.hw-markdown > h2 + *,\\n.hw-markdown > h3 + * {\\n margin-top: 8px;\\n}\\n.hw-markdown > *:first-child {\\n margin-top: 0;\\n}\\n.hw-markdown > *:last-child {\\n margin-bottom: 0;\\n}\\n.hw-markdown > br {\\n display: none;\\n}\\n.hw-markdown ul,\\n.hw-markdown ol {\\n margin: 0;\\n padding-left: 20px;\\n}\\n.hw-markdown li {\\n margin: 4px 0;\\n}\\n.hw-markdown code {\\n font-family:\\n ui-monospace,\\n \\\"SF Mono\\\",\\n monospace;\\n font-size: 12px;\\n background: var(--hw-bg-hover);\\n padding: 1px 5px;\\n border-radius: 4px;\\n}\\n.hw-table-wrap {\\n margin: 10px 0;\\n overflow-x: auto;\\n border: 1px solid var(--hw-border, rgba(0, 0, 0, 0.08));\\n border-radius: 10px;\\n}\\n.hw-table {\\n width: 100%;\\n border-collapse: collapse;\\n font-size: 13px;\\n}\\n.hw-table th {\\n text-align: left;\\n font-weight: 600;\\n font-size: 12px;\\n padding: 8px 12px;\\n background: var(--hw-bg-hover, #f5f5f4);\\n border-bottom: 1px solid var(--hw-border, rgba(0, 0, 0, 0.08));\\n}\\n.hw-table td {\\n padding: 8px 12px;\\n border-bottom: 1px solid var(--hw-border, rgba(0, 0, 0, 0.06));\\n vertical-align: top;\\n}\\n.hw-table tbody tr:last-child td {\\n border-bottom: none;\\n}\\n.hw-code {\\n margin: 10px 0;\\n border-radius: 10px;\\n overflow: hidden;\\n border: 1px solid var(--hw-border, rgba(0, 0, 0, 0.08));\\n background: var(--hw-bg-hover, #f5f5f4);\\n font-family:\\n ui-monospace,\\n \\\"SF Mono\\\",\\n \\\"Menlo\\\",\\n monospace;\\n}\\n.hw-code-header {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 10px;\\n padding: 7px 8px 7px 12px;\\n font-size: 11px;\\n color: var(--hw-text-2, #6b7280);\\n background: rgba(0, 0, 0, 0.03);\\n border-bottom: 1px solid var(--hw-border, rgba(0, 0, 0, 0.06));\\n}\\n.hw-code-lang {\\n text-transform: lowercase;\\n letter-spacing: 0.02em;\\n font-weight: 500;\\n}\\n.hw-code-actions {\\n display: inline-flex;\\n align-items: center;\\n gap: 1px;\\n}\\n.hw-code-action {\\n position: relative;\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n width: 22px;\\n height: 22px;\\n padding: 0;\\n font-family: inherit;\\n color: var(--hw-text-2, #6b7280);\\n background: transparent;\\n border: 1px solid transparent;\\n border-radius: 6px;\\n cursor: pointer;\\n opacity: 0.62;\\n transition:\\n background 120ms ease,\\n color 120ms ease,\\n opacity 120ms ease,\\n scale 120ms ease;\\n}\\n.hw-code-action:hover {\\n color: var(--hw-text, #111);\\n background: rgba(0, 0, 0, 0.06);\\n opacity: 1;\\n}\\n.hw-code-action:active {\\n scale: 0.96;\\n}\\n.hw-code-action svg {\\n width: 13px;\\n height: 13px;\\n}\\n.hw-code-copy-icon,\\n.hw-code-check-icon {\\n position: absolute;\\n inset: 50% auto auto 50%;\\n transition:\\n opacity 180ms cubic-bezier(0.2, 0, 0, 1),\\n scale 180ms cubic-bezier(0.2, 0, 0, 1),\\n filter 180ms cubic-bezier(0.2, 0, 0, 1);\\n translate: -50% -50%;\\n}\\n.hw-code-check-icon {\\n filter: blur(4px);\\n opacity: 0;\\n scale: 0.25;\\n}\\n.hw-code-copy--copied .hw-code-copy-icon {\\n filter: blur(4px);\\n opacity: 0;\\n scale: 0.25;\\n}\\n.hw-code-copy--copied .hw-code-check-icon {\\n filter: blur(0);\\n opacity: 1;\\n scale: 1;\\n}\\n.hw-code-copy-label {\\n position: absolute;\\n width: 1px;\\n height: 1px;\\n overflow: hidden;\\n clip: rect(0, 0, 0, 0);\\n white-space: nowrap;\\n}\\n.hw-code-copy--copied {\\n color: #16a34a;\\n}\\n.hw-code-copy--failed {\\n color: #dc2626;\\n}\\n.hw-code pre {\\n margin: 0;\\n padding: 10px 12px;\\n background: transparent;\\n border-radius: 0;\\n overflow-x: auto;\\n max-width: 100%;\\n max-height: 320px;\\n scrollbar-color: rgba(0, 0, 0, 0.22) transparent;\\n scrollbar-width: thin;\\n}\\n.hw-code pre::-webkit-scrollbar {\\n width: 10px;\\n height: 10px;\\n}\\n.hw-code pre::-webkit-scrollbar-track {\\n background: transparent;\\n}\\n.hw-code pre::-webkit-scrollbar-thumb {\\n background: rgba(0, 0, 0, 0.18);\\n background-clip: content-box;\\n border: 3px solid transparent;\\n border-radius: 999px;\\n}\\n.hw-code pre::-webkit-scrollbar-thumb:hover {\\n background: rgba(0, 0, 0, 0.28);\\n background-clip: content-box;\\n}\\n.hw-code pre code {\\n display: block;\\n background: transparent;\\n padding: 0;\\n font-size: 12px;\\n line-height: 1.55;\\n white-space: pre;\\n color: var(--hw-text, #111);\\n}\\n@media (prefers-color-scheme: dark) {\\n .hw-code {\\n background: rgba(255, 255, 255, 0.04);\\n border-color: rgba(255, 255, 255, 0.08);\\n }\\n .hw-code-header {\\n background: rgba(255, 255, 255, 0.03);\\n border-bottom-color: rgba(255, 255, 255, 0.06);\\n }\\n .hw-code-action:hover,\\n .hw-code-action:focus-visible {\\n background: rgba(255, 255, 255, 0.08);\\n }\\n .hw-code pre {\\n scrollbar-color: rgba(255, 255, 255, 0.26) transparent;\\n }\\n .hw-code pre::-webkit-scrollbar-thumb {\\n background: rgba(255, 255, 255, 0.22);\\n background-clip: content-box;\\n }\\n .hw-code pre::-webkit-scrollbar-thumb:hover {\\n background: rgba(255, 255, 255, 0.32);\\n background-clip: content-box;\\n }\\n}\\n.hw-markdown pre {\\n margin: 8px 0;\\n padding: 10px 12px;\\n background: var(--hw-bg-hover);\\n border-radius: 8px;\\n overflow-x: auto;\\n max-width: 100%;\\n}\\n.hw-markdown pre code {\\n display: block;\\n background: transparent;\\n padding: 0;\\n border-radius: 0;\\n font-size: 12px;\\n line-height: 1.5;\\n white-space: pre;\\n word-break: normal;\\n color: inherit;\\n}\\n.hw-msg-bubble pre {\\n margin: 6px 0;\\n padding: 8px 10px;\\n background: rgba(0, 0, 0, 0.06);\\n border-radius: 6px;\\n overflow-x: auto;\\n max-width: 100%;\\n}\\n.hw-msg-bubble pre code {\\n background: transparent;\\n padding: 0;\\n font-size: 12px;\\n line-height: 1.5;\\n white-space: pre;\\n}\\n.hw-msg-bubble .hw-code pre {\\n margin: 0;\\n padding: 10px 12px;\\n background: transparent;\\n border-radius: 0;\\n}\\n.hw-msg-bubble .hw-code pre code {\\n background: transparent;\\n padding: 0;\\n font-size: 12px;\\n line-height: 1.55;\\n}\\n.hw-msg--team .hw-msg-bubble pre,\\n.hw-msg--visitor .hw-msg-bubble pre {\\n background: rgba(255, 255, 255, 0.12);\\n}\\n.hw-markdown blockquote {\\n margin: 0 0 12px;\\n padding: 8px 12px;\\n border-left: 3px solid var(--hw-border);\\n color: var(--hw-text-2);\\n font-style: italic;\\n}\\n.hw-markdown a {\\n color: var(--hw-primary);\\n text-decoration: underline;\\n text-underline-offset: 2px;\\n}\\n.hw-markdown img {\\n max-width: 100%;\\n border-radius: 8px;\\n margin: 8px 0;\\n outline: 1px solid rgba(0, 0, 0, 0.08);\\n outline-offset: -1px;\\n}\\n.hw-markdown hr {\\n border: none;\\n border-top: 1px solid var(--hw-border);\\n margin: 16px 0;\\n}\\n.hw-content-empty {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n padding: 40px 20px;\\n text-align: center;\\n}\\n.hw-content-empty-title {\\n font-size: 14px;\\n font-weight: 600;\\n color: var(--hw-text-1);\\n margin-bottom: 4px;\\n}\\n.hw-content-empty-desc {\\n font-size: 12px;\\n color: var(--hw-text-3);\\n}\\n.hw-content-loading {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 40px 20px;\\n}\\n.hw-content-load-more {\\n display: block;\\n width: 100%;\\n padding: 10px;\\n border: none;\\n background: none;\\n color: var(--hw-primary);\\n font-size: 13px;\\n font-weight: 500;\\n cursor: pointer;\\n text-align: center;\\n}\\n.hw-content-load-more:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-content-load-more:disabled {\\n opacity: 0.5;\\n cursor: default;\\n}\\n@media (hover: none) {\\n .hw-composer-preview-remove {\\n opacity: 0.7;\\n }\\n}\\n.hw-composer--dragging .hw-composer-box {\\n border-color: var(--hw-primary);\\n background: color-mix(in srgb, var(--hw-primary) 4%, transparent);\\n}\\n.hw-composer-drop-overlay {\\n position: absolute;\\n inset: 0;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n background: color-mix(in srgb, var(--hw-bg) 90%, transparent);\\n border: 2px dashed var(--hw-primary);\\n border-radius: 12px;\\n z-index: 10;\\n pointer-events: none;\\n animation: hw-drop-pulse 1.5s ease-in-out infinite;\\n}\\n.hw-composer-drop-text {\\n font-size: 13px;\\n font-weight: 500;\\n color: var(--hw-primary);\\n}\\n@keyframes hw-drop-pulse {\\n 0%, 100% {\\n opacity: 0.8;\\n }\\n 50% {\\n opacity: 1;\\n }\\n}\\n.hw-disconnect {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n gap: 7px;\\n padding: 7px 14px;\\n background: var(--hw-bg-hover);\\n color: var(--hw-text-2);\\n font-size: 11.5px;\\n font-weight: 500;\\n letter-spacing: -0.01em;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n flex-shrink: 0;\\n animation: hw-disconnect-in 0.18s cubic-bezier(0.22, 1, 0.36, 1);\\n}\\n@keyframes hw-disconnect-in {\\n from {\\n opacity: 0;\\n transform: translateY(-100%);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n.hw-disconnect-spinner {\\n width: 9px;\\n height: 9px;\\n border: 1.5px solid currentColor;\\n border-top-color: transparent;\\n border-radius: 50%;\\n opacity: 0.75;\\n flex-shrink: 0;\\n animation: hw-spin 0.7s linear infinite;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-disconnect {\\n animation: none;\\n }\\n .hw-disconnect-spinner {\\n animation: none;\\n border-top-color: currentColor;\\n opacity: 0.5;\\n }\\n}\\n.hw-error-state {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n padding: 32px 24px;\\n text-align: center;\\n gap: 12px;\\n}\\n.hw-error-icon {\\n width: 48px;\\n height: 48px;\\n border-radius: 50%;\\n background: #fef2f2;\\n color: #ef4444;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.hw-error-icon svg {\\n width: 24px;\\n height: 24px;\\n}\\n.hw-error-title {\\n font-size: 15px;\\n font-weight: 600;\\n color: var(--hw-text);\\n}\\n.hw-error-desc {\\n font-size: 13px;\\n color: var(--hw-text-2);\\n}\\n.hw-error-btn {\\n padding: 8px 20px;\\n border: 1px solid var(--hw-border-md);\\n border-radius: 8px;\\n background: var(--hw-bg);\\n color: var(--hw-text);\\n font-size: 13px;\\n font-weight: 500;\\n cursor: pointer;\\n transition: background 0.15s;\\n}\\n.hw-error-btn:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-send-error {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n padding: 8px 12px;\\n background: #fef2f2;\\n color: #dc2626;\\n font-size: 12px;\\n font-weight: 500;\\n flex-shrink: 0;\\n animation: hw-msg-appear 0.25s ease-out;\\n}\\n.hw-send-error-retry {\\n margin-left: auto;\\n padding: 2px 8px;\\n border: 1px solid #fca5a5;\\n border-radius: 4px;\\n background: none;\\n color: #dc2626;\\n font-size: 11px;\\n font-weight: 600;\\n cursor: pointer;\\n}\\n.hw-send-error-retry:hover {\\n background: #fee2e2;\\n}\\n.hw-resolved {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 12px;\\n padding: 16px 20px;\\n border-top: 1px solid var(--hw-border);\\n flex-shrink: 0;\\n}\\n.hw-resolved-text {\\n font-size: 13px;\\n color: var(--hw-text-3);\\n font-weight: 500;\\n}\\n.hw-resolved-actions {\\n display: flex;\\n gap: 8px;\\n}\\n.hw-resolved-reopen {\\n padding: 6px 16px;\\n border: 1px solid var(--hw-border-md);\\n border-radius: 8px;\\n background: var(--hw-bg);\\n color: var(--hw-text);\\n font-size: 13px;\\n font-weight: 500;\\n cursor: pointer;\\n transition: background 0.15s;\\n}\\n.hw-resolved-reopen:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-csat {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 8px;\\n}\\n.hw-csat-label {\\n font-size: 12px;\\n color: var(--hw-text-3);\\n}\\n.hw-csat-buttons {\\n display: flex;\\n gap: 8px;\\n}\\n.hw-csat-btn {\\n width: 36px;\\n height: 36px;\\n border: 1px solid var(--hw-border-md);\\n border-radius: 8px;\\n background: var(--hw-bg);\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 18px;\\n transition:\\n transform 0.15s,\\n border-color 0.15s,\\n background 0.15s;\\n}\\n.hw-csat-btn:hover {\\n transform: scale(1.1);\\n border-color: var(--hw-text-3);\\n}\\n.hw-csat-btn--selected {\\n border-color: var(--hw-primary);\\n background: var(--hw-bg-hover);\\n transform: scale(1.15);\\n}\\n.hw-csat-thanks {\\n font-size: 12px;\\n color: #22c55e;\\n font-weight: 500;\\n animation: hw-msg-appear 0.25s ease-out;\\n}\\n.hw-load-more-trigger {\\n display: flex;\\n justify-content: center;\\n min-height: 1px;\\n}\\n.hw-load-more-trigger:has(.hw-load-more-spinner) {\\n padding: 8px 0;\\n}\\n.hw-load-more-spinner {\\n display: flex;\\n gap: 3px;\\n}\\n.hw-load-more-spinner > div {\\n width: 5px;\\n height: 5px;\\n border-radius: 50%;\\n background: var(--hw-text-4);\\n animation: hw-loading-pulse 1.4s infinite;\\n}\\n.hw-load-more-spinner > div:nth-child(2) {\\n animation-delay: 0.2s;\\n}\\n.hw-load-more-spinner > div:nth-child(3) {\\n animation-delay: 0.4s;\\n}\\n.hw-drag-handle {\\n display: none;\\n}\\n@media (max-width: 479px) {\\n .hw-drag-handle {\\n display: flex;\\n justify-content: center;\\n padding: 8px 0 4px;\\n flex-shrink: 0;\\n }\\n .hw-drag-handle-pill {\\n width: 32px;\\n height: 4px;\\n border-radius: 2px;\\n background: var(--hw-text-4);\\n }\\n}\\n.hw-msg-bubble p {\\n margin: 0 0 8px;\\n}\\n.hw-msg-bubble p:last-child {\\n margin-bottom: 0;\\n}\\n.hw-msg-bubble strong {\\n font-weight: 600;\\n}\\n.hw-msg-bubble em {\\n font-style: italic;\\n}\\n.hw-msg-bubble a {\\n color: inherit;\\n text-decoration: underline;\\n text-decoration-thickness: 1px;\\n text-underline-offset: 2px;\\n text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);\\n word-break: normal;\\n overflow-wrap: anywhere;\\n}\\n.hw-msg-bubble a:hover {\\n opacity: 0.8;\\n}\\n.hw-msg--visitor .hw-msg-bubble a {\\n color: rgba(255, 255, 255, 0.9);\\n}\\n.hw-msg--visitor .hw-msg-bubble a:hover {\\n color: white;\\n}\\n.hw-msg-bubble ul,\\n.hw-msg-bubble ol {\\n margin: 4px 0 8px;\\n padding-left: 20px;\\n}\\n.hw-msg-bubble li {\\n margin: 2px 0;\\n}\\n.hw-msg-bubble code {\\n padding: 1px 4px;\\n border-radius: 3px;\\n background: rgba(0, 0, 0, 0.06);\\n font-size: 0.9em;\\n font-family:\\n ui-monospace,\\n SFMono-Regular,\\n Menlo,\\n monospace;\\n}\\n.hw-msg-bubble pre {\\n margin: 4px 0 8px;\\n padding: 8px 10px;\\n border-radius: 6px;\\n background: rgba(0, 0, 0, 0.06);\\n overflow-x: auto;\\n font-size: 0.85em;\\n}\\n.hw-msg-bubble pre code {\\n padding: 0;\\n background: none;\\n}\\n.hw-msg-bubble blockquote {\\n margin: 4px 0 8px;\\n padding: 4px 0 4px 12px;\\n border-left: 3px solid var(--hw-border-md);\\n color: var(--hw-text-2);\\n}\\n.hw-widget[data-theme=dark] {\\n --hw-bg: #1c1c1e;\\n --hw-bg-subtle: #161618;\\n --hw-bg-hover: #2c2c2e;\\n --hw-border: rgba(255, 255, 255, 0.08);\\n --hw-border-md: rgba(255, 255, 255, 0.14);\\n --hw-text: #f5f5f5;\\n --hw-text-1: #f5f5f5;\\n --hw-text-2: #a1a1aa;\\n --hw-text-3: #71717a;\\n --hw-text-4: #52525b;\\n --hw-visitor-bubble-bg: #2c2c2e;\\n --hw-visitor-bubble-text: #f5f5f5;\\n --hw-focus-border: rgba(255, 255, 255, 0.28);\\n --hw-focus-ring: rgba(255, 255, 255, 0.08);\\n --hw-brand: #f5f5f5;\\n --hw-on-brand: #1c1c1e;\\n}\\n@media (prefers-color-scheme: dark) {\\n .hw-widget:not([data-theme=light]) .hw-messages {\\n scrollbar-color: rgba(255, 255, 255, 0.26) transparent;\\n }\\n .hw-widget:not([data-theme=light]) .hw-messages::-webkit-scrollbar-thumb {\\n background: rgba(255, 255, 255, 0.2);\\n background-clip: content-box;\\n }\\n .hw-widget:not([data-theme=light]) .hw-messages::-webkit-scrollbar-thumb:hover {\\n background: rgba(255, 255, 255, 0.32);\\n background-clip: content-box;\\n }\\n .hw-widget:not([data-theme=light]) {\\n --hw-bg: #1c1c1e;\\n --hw-bg-subtle: #161618;\\n --hw-bg-hover: #2c2c2e;\\n --hw-border: rgba(255, 255, 255, 0.08);\\n --hw-border-md: rgba(255, 255, 255, 0.14);\\n --hw-text: #f5f5f5;\\n --hw-text-1: #f5f5f5;\\n --hw-text-2: #a1a1aa;\\n --hw-text-3: #71717a;\\n --hw-text-4: #52525b;\\n --hw-visitor-bubble-bg: #2c2c2e;\\n --hw-visitor-bubble-text: #f5f5f5;\\n --hw-focus-border: rgba(255, 255, 255, 0.28);\\n --hw-focus-ring: rgba(255, 255, 255, 0.08);\\n --hw-brand: #f5f5f5;\\n --hw-on-brand: #1c1c1e;\\n }\\n}\\n@media (prefers-color-scheme: dark) {\\n .hw-widget:not([data-theme=light]) .hw-header {\\n background: var(--hw-bg);\\n border-color: var(--hw-border);\\n }\\n .hw-header-bot-icon {\\n background: var(--hw-bg-hover);\\n }\\n .hw-header-name,\\n .hw-header-title {\\n color: var(--hw-text);\\n }\\n .hw-header-status {\\n color: var(--hw-text-2);\\n }\\n .hw-header-close,\\n .hw-header-back {\\n color: var(--hw-text-2);\\n }\\n .hw-header-close:hover,\\n .hw-header-back:hover {\\n background: var(--hw-bg-hover);\\n color: var(--hw-text);\\n }\\n .hw-content-entry {\\n background: var(--hw-bg);\\n border-color: var(--hw-border);\\n }\\n .hw-content-entry:hover {\\n background: var(--hw-bg-hover);\\n border-color: var(--hw-border-md);\\n }\\n .hw-content-empty,\\n .hw-empty {\\n color: var(--hw-text-3);\\n }\\n .hw-conv-card {\\n border-color: var(--hw-border);\\n }\\n .hw-recent-row {\\n border-color: var(--hw-border);\\n }\\n .hw-composer-drop-overlay {\\n background: rgba(0, 0, 0, 0.6);\\n color: var(--hw-text);\\n }\\n .hw-composer--dragging .hw-composer-box {\\n border-color: var(--hw-focus-border);\\n box-shadow: 0 0 0 3px var(--hw-focus-ring);\\n }\\n .hw-hero {\\n background:\\n linear-gradient(\\n 160deg,\\n color-mix(in srgb, var(--hw-primary) 40%, black) 0%,\\n var(--hw-primary) 50%,\\n color-mix(in srgb, var(--hw-primary) 25%, black) 100%);\\n }\\n .hw-sheet {\\n background: var(--hw-bg);\\n }\\n .hw-card {\\n background: var(--hw-bg-hover);\\n border-color: var(--hw-border);\\n }\\n .hw-card:hover {\\n background: #333;\\n }\\n .hw-window {\\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.06);\\n }\\n .hw-bubble:focus-visible {\\n outline-color: var(--hw-text-3);\\n }\\n .hw-msg--visitor .hw-msg-bubble {\\n background: var(--hw-primary);\\n color: white;\\n }\\n .hw-msg-bubble code {\\n background: rgba(255, 255, 255, 0.08);\\n }\\n .hw-msg-bubble pre {\\n background: rgba(255, 255, 255, 0.08);\\n }\\n .hw-composer-box {\\n background: var(--hw-bg);\\n border-color: var(--hw-border);\\n }\\n .hw-composer-input {\\n color: var(--hw-text);\\n }\\n .hw-tabs {\\n background: var(--hw-bg);\\n border-color: var(--hw-border);\\n }\\n .hw-conv-card:hover,\\n .hw-recent-row:hover {\\n background: var(--hw-bg-hover);\\n }\\n .hw-send-error {\\n background: #450a0a;\\n color: #fca5a5;\\n }\\n .hw-error-icon {\\n background: #450a0a;\\n color: #f87171;\\n }\\n .hw-resolved {\\n border-color: var(--hw-border);\\n }\\n .hw-resolved-reopen,\\n .hw-csat-btn {\\n background: var(--hw-bg-hover);\\n border-color: var(--hw-border-md);\\n color: var(--hw-text);\\n }\\n .hw-hover-preview {\\n background: #1c1c1e;\\n border-color: var(--hw-border);\\n }\\n .hw-content-search-box {\\n background: var(--hw-bg-hover);\\n border-color: var(--hw-border-md);\\n }\\n .hw-preview {\\n background: var(--hw-bg);\\n border-color: var(--hw-border);\\n }\\n}\\n.hw-widget[data-hw-placement=docked] {\\n --hw-dock-width: 600px;\\n --hw-dock-bar-width: 480px;\\n --hw-dock-inset: 24px;\\n --hw-bar-max-height: 148px;\\n --hw-dock-surface: #ffffff;\\n --hw-dock-on-surface: #111111;\\n --hw-dock-pill-bg: rgba(44, 44, 48, 0.66);\\n --hw-dock-pill-fg: rgba(255, 255, 255, 0.94);\\n --hw-dock-pill-border: rgba(255, 255, 255, 0.14);\\n}\\n.hw-widget[data-hw-placement=docked] {\\n z-index: 2147483000;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-dock {\\n position: fixed;\\n left: 0;\\n right: 0;\\n bottom: var(--hw-dock-inset);\\n z-index: 2147483000;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n pointer-events: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-dock > * {\\n pointer-events: auto;\\n}\\n.hw-dock-suggestions {\\n display: flex;\\n flex-direction: column;\\n align-items: flex-start;\\n gap: 9px;\\n width: var(--hw-dock-bar-width, var(--hw-dock-width));\\n max-width: calc(100vw - 32px);\\n margin-bottom: 14px;\\n}\\n.hw-dock-pill-row {\\n align-self: flex-start;\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n animation: hw-dock-pill-in 0.42s cubic-bezier(0.2, 0.9, 0.3, 1) both;\\n}\\n.hw-dock-pill-dismiss {\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n width: 20px;\\n height: 20px;\\n flex-shrink: 0;\\n padding: 0;\\n border: 0;\\n background: none;\\n color: var(--hw-dock-pill-fg);\\n cursor: pointer;\\n align-self: flex-start;\\n margin-top: 8px;\\n opacity: 0;\\n transform: scale(0.85);\\n transition:\\n opacity 0.12s linear,\\n transform 0.12s cubic-bezier(0.25, 1, 0.5, 1),\\n color 0.12s linear;\\n}\\n.hw-dock-pill-dismiss svg {\\n width: 11px;\\n height: 11px;\\n}\\n.hw-dock-suggestions:hover .hw-dock-pill-dismiss,\\n.hw-dock-suggestions:focus-within .hw-dock-pill-dismiss {\\n opacity: 1;\\n transform: none;\\n}\\n.hw-dock-pill-dismiss:hover {\\n color: var(--hw-dock-on-surface);\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-dock-pill-dismiss {\\n transition: none;\\n }\\n}\\n@media (hover: none) {\\n .hw-dock-pill-dismiss {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n.hw-dock-pill {\\n align-self: flex-start;\\n padding: 10px 18px;\\n border: 1px solid var(--hw-dock-pill-border, transparent);\\n border-radius: 999px;\\n cursor: pointer;\\n font: inherit;\\n font-size: 14px;\\n font-weight: 500;\\n text-align: left;\\n background: var(--hw-dock-pill-bg);\\n color: var(--hw-dock-pill-fg);\\n backdrop-filter: blur(10px) saturate(1.2);\\n -webkit-backdrop-filter: blur(10px) saturate(1.2);\\n box-shadow: 0 4px 14px -8px rgba(12, 11, 10, 0.28);\\n transition:\\n background 0.16s,\\n border-color 0.16s,\\n transform 0.16s;\\n}\\n.hw-dock-pill {\\n backdrop-filter: blur(18px);\\n -webkit-backdrop-filter: blur(18px);\\n}\\n.hw-dock-pill:hover {\\n background: color-mix(in srgb, var(--hw-dock-pill-bg) 100%, var(--hw-dock-on-surface) 8%);\\n border-color: color-mix(in srgb, var(--hw-dock-pill-border) 100%, var(--hw-dock-on-surface) 10%);\\n transform: translateX(3px);\\n}\\n@keyframes hw-dock-pill-in {\\n from {\\n opacity: 0;\\n transform: translateY(10px) scale(0.97);\\n }\\n to {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n.hw-dock-bar {\\n display: flex;\\n align-items: flex-end;\\n gap: 10px;\\n width: var(--hw-dock-bar-width, var(--hw-dock-width));\\n max-width: calc(100vw - 32px);\\n min-height: 52px;\\n padding: 10px 10px 10px 18px;\\n border: 0;\\n border-radius: 26px;\\n background: var(--hw-dock-surface);\\n color: var(--hw-dock-on-surface);\\n box-shadow:\\n inset 0 1px 0 color-mix(in srgb, var(--hw-dock-on-surface) 9%, transparent),\\n 0 0 0 1px color-mix(in srgb, var(--hw-dock-on-surface) 7%, transparent),\\n 0 2px 6px rgba(12, 11, 10, 0.18),\\n 0 20px 48px -14px rgba(12, 11, 10, 0.45);\\n transition:\\n border-radius 0.18s ease,\\n box-shadow 0.2s cubic-bezier(0.2, 0.8, 0.2, 1),\\n width 0.26s cubic-bezier(0.2, 0.8, 0.2, 1);\\n}\\n.hw-dock-bar:focus-within {\\n box-shadow:\\n inset 0 1px 0 color-mix(in srgb, var(--hw-dock-on-surface) 9%, transparent),\\n 0 0 0 1px color-mix(in srgb, var(--hw-primary, #fb923c) 60%, transparent),\\n 0 2px 6px rgba(12, 11, 10, 0.18),\\n 0 20px 48px -14px rgba(12, 11, 10, 0.45);\\n}\\n.hw-dock-bar[data-grown=true] {\\n border-radius: 20px;\\n}\\n.hw-dock-input {\\n flex: 1;\\n min-width: 0;\\n min-height: 20px;\\n max-height: var(--hw-bar-max-height);\\n padding: 6px 0;\\n border: 0;\\n outline: none;\\n resize: none;\\n overflow-y: auto;\\n background: transparent;\\n color: var(--hw-dock-on-surface);\\n font: inherit;\\n font-size: 14px;\\n line-height: 1.45;\\n transition: height 0.12s ease;\\n}\\n.hw-dock-input::placeholder {\\n color: color-mix(in srgb, var(--hw-dock-on-surface) 45%, transparent);\\n}\\n.hw-dock-send {\\n flex: none;\\n width: 32px;\\n height: 32px;\\n margin-bottom: 1px;\\n border: 0;\\n border-radius: 50%;\\n display: grid;\\n place-items: center;\\n cursor: pointer;\\n background: var(--hw-primary, #fb923c);\\n color: var(--hw-on-brand, #fff);\\n transition: transform 0.16s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.16s;\\n}\\n.hw-dock-send:hover:not(:disabled) {\\n transform: scale(1.06);\\n}\\n.hw-dock-send:disabled {\\n opacity: 0.45;\\n cursor: default;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window {\\n position: fixed;\\n left: 50%;\\n right: auto;\\n margin-left: calc(var(--hw-dock-width) / -2);\\n bottom: calc(var(--hw-dock-inset) + 66px);\\n width: var(--hw-dock-width);\\n max-width: calc(100vw - 32px);\\n height: 420px;\\n}\\n@media (max-width: 640px) {\\n .hw-widget[data-hw-placement=docked] .hw-window {\\n left: 16px;\\n right: 16px;\\n margin-left: 0;\\n width: auto;\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-bubble {\\n display: none;\\n}\\n.hw-widget[data-hw-placement=docked][data-hw-open=true] .hw-window {\\n bottom: calc(var(--hw-dock-inset) + 52px + 12px);\\n}\\n.hw-widget[data-hw-placement=docked][data-hw-open=true] .hw-dock-suggestions {\\n display: none;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-dock-pill,\\n .hw-dock-bar,\\n .hw-dock-input,\\n .hw-dock-send {\\n animation: none;\\n transition: none;\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-composer,\\n.hw-widget[data-hw-placement=docked] .hw-tabs,\\n.hw-widget[data-hw-placement=docked] .hw-footer-tabs {\\n display: none;\\n}\\n.hw-starters {\\n display: flex;\\n flex-direction: column;\\n margin-top: 10px;\\n border-radius: 14px;\\n overflow: hidden;\\n background: var(--hw-bg);\\n box-shadow: inset 0 0 0 1px var(--hw-border);\\n}\\n.hw-starter {\\n display: flex;\\n align-items: center;\\n gap: 10px;\\n width: 100%;\\n padding: 11px 14px;\\n border: 0;\\n border-radius: 0;\\n cursor: pointer;\\n background: transparent;\\n color: var(--hw-text);\\n font: inherit;\\n text-align: left;\\n animation: hw-starter-in 0.3s cubic-bezier(0.2, 0.8, 0.2, 1) both;\\n transition: background 0.12s;\\n}\\n.hw-starter + .hw-starter {\\n box-shadow: inset 0 1px 0 var(--hw-border);\\n}\\n.hw-starter:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-starter-text {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 1px;\\n}\\n.hw-starter-k {\\n font-size: 13px;\\n font-weight: 550;\\n line-height: 1.35;\\n color: var(--hw-text);\\n}\\n.hw-starter-q {\\n font-size: 12px;\\n line-height: 1.35;\\n color: var(--hw-text-3, var(--hw-text-muted));\\n}\\n.hw-starter svg {\\n flex: none;\\n color: var(--hw-text-3, var(--hw-text-muted));\\n opacity: 0.45;\\n transition: opacity 0.15s, transform 0.15s;\\n}\\n.hw-starter:hover svg {\\n opacity: 0.9;\\n transform: translateX(2px);\\n}\\n@keyframes hw-starter-in {\\n from {\\n opacity: 0;\\n transform: translateY(6px);\\n }\\n to {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-back {\\n display: none;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-starter {\\n animation: none;\\n }\\n}\\n@media (prefers-color-scheme: dark) {\\n .hw-widget:not([data-theme=light])[data-hw-placement=docked] {\\n --hw-dock-surface: #1f1f23;\\n --hw-dock-on-surface: #f4f4f6;\\n --hw-dock-pill-bg: rgba(255, 255, 255, 0.1);\\n --hw-dock-pill-fg: #e4e4e7;\\n --hw-dock-pill-border: rgba(255, 255, 255, 0.14);\\n }\\n}\\n.hw-widget[data-theme=dark][data-hw-placement=docked] {\\n --hw-dock-surface: #1f1f23;\\n --hw-dock-on-surface: #f4f4f6;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window {\\n --hw-bg: rgba(255, 255, 255, 0.08);\\n --hw-bg-subtle: transparent;\\n --hw-bg-hover: rgba(255, 255, 255, 0.1);\\n --hw-border: rgba(255, 255, 255, 0.14);\\n --hw-border-md: rgba(255, 255, 255, 0.22);\\n --hw-text: rgba(255, 255, 255, 0.94);\\n --hw-text-1: #ffffff;\\n --hw-text-2: rgba(255, 255, 255, 0.72);\\n --hw-text-3: rgba(255, 255, 255, 0.62);\\n --hw-text-4: rgba(255, 255, 255, 0.46);\\n --hw-visitor-bubble-bg: rgba(255, 255, 255, 0.16);\\n --hw-visitor-bubble-text: #ffffff;\\n --hw-brand: rgba(255, 255, 255, 0.92);\\n --hw-on-brand: #17161a;\\n --hw-focus-border: rgba(255, 255, 255, 0.34);\\n --hw-focus-ring: rgba(255, 255, 255, 0.1);\\n height: 500px;\\n max-height: calc(100vh - 180px);\\n border-radius: 24px;\\n color: var(--hw-text);\\n background:\\n linear-gradient(\\n 180deg,\\n rgba(40, 40, 44, 0.72) 0%,\\n rgba(46, 46, 50, 0.7) 55%,\\n rgba(52, 52, 56, 0.68) 100%);\\n backdrop-filter: blur(30px);\\n -webkit-backdrop-filter: blur(30px);\\n box-shadow: 0 24px 60px -20px rgba(12, 11, 10, 0.5), inset 0 0 0 1px rgba(255, 255, 255, 0.1);\\n}\\n@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {\\n .hw-widget[data-hw-placement=docked] .hw-window {\\n background: #2c2c2e;\\n }\\n}\\n@media (max-width: 640px) {\\n .hw-widget[data-hw-placement=docked] .hw-window {\\n height: min(60vh, 460px);\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header--sub {\\n padding: 14px 12px 8px 16px;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-status {\\n display: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-name {\\n font-size: 15.5px;\\n font-weight: 560;\\n letter-spacing: -0.006em;\\n color: var(--hw-text-1);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-menu-conv-name,\\n.hw-widget[data-hw-placement=docked] .hw-event-name {\\n font-weight: 545;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-bot-icon {\\n border-radius: 50%;\\n overflow: hidden;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-close:hover,\\n.hw-widget[data-hw-placement=docked] .hw-header-menu-btn:hover {\\n background: rgba(255, 255, 255, 0.12);\\n color: #ffffff;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-messages {\\n padding: 4px 22px 16px;\\n gap: 18px;\\n -webkit-mask-image:\\n linear-gradient(\\n 180deg,\\n transparent 0,\\n #000 16px);\\n mask-image:\\n linear-gradient(\\n 180deg,\\n transparent 0,\\n #000 16px);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-msg--ai .hw-msg-bubble,\\n.hw-widget[data-hw-placement=docked] .hw-msg--team .hw-msg-bubble {\\n padding: 0;\\n background: transparent;\\n border-radius: 0;\\n font-size: 15px;\\n line-height: 1.55;\\n color: var(--hw-text);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-msg--visitor .hw-msg-bubble {\\n background: rgba(255, 255, 255, 0.16);\\n color: #ffffff;\\n font-size: 14.5px;\\n line-height: 1.5;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-msg-bubble pre,\\n.hw-widget[data-hw-placement=docked] .hw-msg-bubble code {\\n background: rgba(0, 0, 0, 0.28);\\n color: var(--hw-text-1);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-email-card-row {\\n background: rgba(0, 0, 0, 0.26);\\n border-color: rgba(255, 255, 255, 0.14);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window :focus-visible {\\n outline-color: rgba(255, 255, 255, 0.55);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-email-card-input:focus,\\n.hw-widget[data-hw-placement=docked] .hw-email-card-input:focus-visible {\\n outline: none;\\n box-shadow: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-email-card-row:focus-within {\\n border-color: rgba(255, 255, 255, 0.42);\\n box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.08);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-email-card-submit {\\n background: #ffffff;\\n color: #17161a;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window .hw-header--sub {\\n position: relative;\\n z-index: 3;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-menu {\\n background: #3a3a3f;\\n box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.16), 0 18px 44px -12px rgba(12, 11, 10, 0.62);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-menu button:hover {\\n background: rgba(255, 255, 255, 0.11);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-menu button.hw-header-menu-conv[data-active=true] {\\n background: rgba(255, 255, 255, 0.09);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-header-menu-convs {\\n border-bottom-color: rgba(255, 255, 255, 0.12);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-event--card {\\n margin: 0;\\n background: rgba(255, 255, 255, 0.08);\\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-event-avatar {\\n background: rgba(255, 255, 255, 0.14);\\n color: var(--hw-text-1);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-preview {\\n position: fixed;\\n left: 50%;\\n right: auto;\\n margin-left: calc(var(--hw-dock-bar-width, var(--hw-dock-width)) / -2);\\n bottom: calc(var(--hw-dock-inset) + 52px + 12px);\\n width: var(--hw-dock-bar-width, var(--hw-dock-width));\\n max-width: calc(100vw - 32px);\\n border: 0;\\n border-radius: 24px;\\n color: rgba(255, 255, 255, 0.94);\\n background:\\n linear-gradient(\\n 180deg,\\n rgba(40, 40, 44, 0.74) 0%,\\n rgba(52, 52, 56, 0.7) 100%);\\n backdrop-filter: blur(30px);\\n -webkit-backdrop-filter: blur(30px);\\n box-shadow: 0 24px 60px -20px rgba(12, 11, 10, 0.5), inset 0 0 0 1px rgba(255, 255, 255, 0.1);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-preview-name,\\n.hw-widget[data-hw-placement=docked] .hw-preview-body {\\n color: rgba(255, 255, 255, 0.94);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-preview-close {\\n color: rgba(255, 255, 255, 0.6);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-preview-close:hover {\\n background: rgba(255, 255, 255, 0.12);\\n color: #ffffff;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-preview-footer {\\n color: rgba(255, 255, 255, 0.55);\\n border-top-color: rgba(255, 255, 255, 0.1);\\n}\\n@media (max-width: 640px) {\\n .hw-widget[data-hw-placement=docked] .hw-preview {\\n left: 16px;\\n right: 16px;\\n margin-left: 0;\\n width: auto;\\n }\\n}\\n@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {\\n .hw-widget[data-hw-placement=docked] .hw-preview {\\n background: #2c2c2e;\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-quick-reply-btn {\\n padding: 7px 14px;\\n font-size: 13px;\\n font-weight: 550;\\n border-radius: 999px;\\n background: rgba(255, 255, 255, 0.94);\\n box-shadow: 0 1px 3px rgba(12, 11, 10, 0.22);\\n color: #17161a;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-quick-reply-btn:hover:not(:disabled) {\\n background: #ffffff;\\n box-shadow: 0 4px 12px rgba(12, 11, 10, 0.28);\\n transform: translateY(-1px);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-quick-reply-btn[data-tapped=true] {\\n background: rgba(255, 255, 255, 0.22);\\n color: #ffffff;\\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3);\\n transform: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-quick-reply-btn svg {\\n opacity: 0.55;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-offer {\\n padding: 7px 14px;\\n font-size: 13px;\\n background: rgba(255, 255, 255, 0.94);\\n color: #17161a;\\n box-shadow: 0 1px 3px rgba(12, 11, 10, 0.22);\\n transition:\\n background 0.15s,\\n box-shadow 0.15s,\\n transform 0.15s;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-offer:hover {\\n background: #ffffff;\\n color: #17161a;\\n box-shadow: 0 4px 12px rgba(12, 11, 10, 0.28);\\n transform: translateY(-1px);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-offer svg {\\n opacity: 0.55;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-dock-bar {\\n --hw-dock-on-surface: rgba(255, 255, 255, 0.94);\\n color: rgba(255, 255, 255, 0.94);\\n background:\\n linear-gradient(\\n 180deg,\\n rgba(44, 44, 48, 0.74) 0%,\\n rgba(52, 52, 56, 0.72) 100%);\\n backdrop-filter: blur(30px);\\n -webkit-backdrop-filter: blur(30px);\\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12), 0 18px 40px -16px rgba(12, 11, 10, 0.45);\\n}\\n.hw-widget[data-hw-placement=docked][data-hw-open=true] .hw-dock-bar {\\n width: var(--hw-dock-width);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-dock-bar:focus-within {\\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.26), 0 18px 40px -16px rgba(12, 11, 10, 0.5);\\n}\\n.hw-widget[data-hw-placement=docked][data-hw-open=true] .hw-dock-bar {\\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14), 0 22px 52px -18px rgba(12, 11, 10, 0.52);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-dock-send:not(:disabled) {\\n background: #ffffff;\\n color: #17161a;\\n}\\n@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {\\n .hw-widget[data-hw-placement=docked] .hw-dock-bar {\\n background: #2c2c2e;\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window {\\n transform-origin: 50% 100%;\\n animation: hw-dock-panel-in 0.3s cubic-bezier(0.16, 1, 0.3, 1);\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window--closing {\\n animation: hw-dock-panel-out 0.18s cubic-bezier(0.4, 0, 1, 1) forwards;\\n}\\n@keyframes hw-dock-panel-in {\\n from {\\n opacity: 0;\\n transform: translateY(14px) scale(0.98);\\n }\\n to {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n@keyframes hw-dock-panel-out {\\n from {\\n opacity: 1;\\n transform: none;\\n }\\n to {\\n opacity: 0;\\n transform: translateY(8px) scale(0.99);\\n }\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window .hw-header--sub {\\n animation: hw-dock-settle 0.32s cubic-bezier(0.16, 1, 0.3, 1) 0.06s both;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window .hw-messages {\\n animation: hw-dock-settle 0.34s cubic-bezier(0.16, 1, 0.3, 1) 0.11s both;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-window--closing .hw-header--sub,\\n.hw-widget[data-hw-placement=docked] .hw-window--closing .hw-messages {\\n animation: none;\\n}\\n@keyframes hw-dock-settle {\\n from {\\n opacity: 0;\\n transform: translateY(7px);\\n }\\n to {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-widget[data-hw-placement=docked] .hw-window,\\n .hw-widget[data-hw-placement=docked] .hw-window--closing,\\n .hw-widget[data-hw-placement=docked] .hw-window .hw-header--sub,\\n .hw-widget[data-hw-placement=docked] .hw-window .hw-messages {\\n animation: none;\\n }\\n}\\n.hw-dock-bar {\\n flex-wrap: wrap;\\n padding-left: 18px;\\n padding-right: 8px;\\n}\\n.hw-dock-error {\\n width: var(--hw-dock-width);\\n max-width: calc(100vw - 32px);\\n margin-bottom: 8px;\\n padding: 8px 14px;\\n border-radius: 14px;\\n background: rgba(190, 24, 40, 0.92);\\n color: #ffffff;\\n font-size: 12.5px;\\n line-height: 1.35;\\n box-shadow: 0 10px 26px -12px rgba(12, 11, 10, 0.5);\\n animation: hw-dock-settle 0.22s cubic-bezier(0.16, 1, 0.3, 1) both;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-dock-error {\\n animation: none;\\n }\\n}\\n.hw-dock-previews {\\n flex: 0 0 100%;\\n order: -1;\\n display: flex;\\n flex-wrap: wrap;\\n gap: 8px;\\n padding: 2px 0 8px;\\n}\\n.hw-dock-actions {\\n flex: none;\\n display: flex;\\n align-items: center;\\n gap: 2px;\\n margin-bottom: 1px;\\n}\\n.hw-dock-tool {\\n display: grid;\\n place-items: center;\\n width: 30px;\\n height: 30px;\\n border: 0;\\n border-radius: 50%;\\n background: transparent;\\n color: color-mix(in srgb, var(--hw-dock-on-surface) 52%, transparent);\\n cursor: pointer;\\n transition: background 0.15s, color 0.15s;\\n}\\n.hw-dock-tool:hover:not(:disabled) {\\n background: color-mix(in srgb, var(--hw-dock-on-surface) 8%, transparent);\\n color: var(--hw-dock-on-surface);\\n}\\n.hw-dock-tool:disabled {\\n opacity: 0.4;\\n cursor: default;\\n}\\n.hw-dock-tool[data-active=true] {\\n color: #e11d48;\\n background: rgba(225, 29, 72, 0.12);\\n animation: hw-dock-listening 1.4s ease-in-out infinite;\\n}\\n@keyframes hw-dock-listening {\\n 0%, 100% {\\n box-shadow: 0 0 0 0 rgba(225, 29, 72, 0.35);\\n }\\n 50% {\\n box-shadow: 0 0 0 4px rgba(225, 29, 72, 0);\\n }\\n}\\n.hw-dock-send:disabled {\\n opacity: 1;\\n background: color-mix(in srgb, var(--hw-dock-on-surface) 9%, transparent);\\n color: color-mix(in srgb, var(--hw-dock-on-surface) 38%, transparent);\\n}\\n@media (prefers-reduced-motion: reduce) {\\n .hw-dock-tool[data-active=true] {\\n animation: none;\\n }\\n .hw-dock-bar {\\n transition: none;\\n }\\n}\\n.hw-dock-input:focus,\\n.hw-dock-input:focus-visible {\\n outline: none;\\n box-shadow: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-powered {\\n display: none;\\n}\\n.hw-widget[data-hw-placement=docked] .hw-disconnect {\\n border-radius: 20px 20px 0 0;\\n}\\n.hw-msg-meta {\\n display: flex;\\n align-items: center;\\n gap: 5px;\\n}\\n.hw-msg-author {\\n font-weight: 550;\\n}\\n.hw-msg-meta-sep {\\n opacity: 0.55;\\n}\\n.hw-header-actions {\\n position: relative;\\n display: flex;\\n align-items: center;\\n gap: 2px;\\n}\\n.hw-header-menu-btn {\\n display: grid;\\n place-items: center;\\n width: 30px;\\n height: 30px;\\n border: 0;\\n border-radius: 8px;\\n cursor: pointer;\\n background: transparent;\\n color: var(--hw-text-2, var(--hw-text-muted));\\n transition: background 0.15s, color 0.15s;\\n}\\n.hw-header-menu-btn:hover {\\n background: var(--hw-bg-hover);\\n color: var(--hw-text);\\n}\\n.hw-header-menu {\\n position: absolute;\\n top: 36px;\\n right: 0;\\n z-index: 6;\\n min-width: 236px;\\n max-width: 288px;\\n padding: 5px;\\n border-radius: 14px;\\n background: var(--hw-bg);\\n color: var(--hw-text);\\n box-shadow: 0 0 0 1px var(--hw-border), 0 12px 32px -10px rgba(0, 0, 0, 0.32);\\n animation: hw-menu-in 0.16s cubic-bezier(0.2, 0.8, 0.2, 1) both;\\n}\\n@keyframes hw-menu-in {\\n from {\\n opacity: 0;\\n transform: translateY(-4px) scale(0.98);\\n }\\n to {\\n opacity: 1;\\n transform: none;\\n }\\n}\\n.hw-header-menu button {\\n display: flex;\\n align-items: center;\\n gap: 10px;\\n width: 100%;\\n padding: 9px 10px;\\n border: 0;\\n border-radius: 9px;\\n cursor: pointer;\\n background: transparent;\\n color: var(--hw-text);\\n font: inherit;\\n font-size: 13px;\\n text-align: left;\\n transition: background 0.14s;\\n}\\n.hw-header-menu button:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-header-menu button svg {\\n flex: none;\\n color: var(--hw-text-3, var(--hw-text-muted));\\n}\\n.hw-header-menu button:hover svg {\\n color: var(--hw-brand, var(--hw-primary));\\n}\\n.hw-header-menu-convs {\\n display: flex;\\n flex-direction: column;\\n max-height: 168px;\\n overflow-y: auto;\\n padding-bottom: 5px;\\n margin-bottom: 5px;\\n border-bottom: 1px solid var(--hw-border);\\n}\\n.hw-header-menu button.hw-header-menu-conv {\\n flex-direction: column;\\n align-items: stretch;\\n gap: 2px;\\n padding: 8px 10px;\\n}\\n.hw-header-menu button.hw-header-menu-conv[data-active=true] {\\n background: var(--hw-bg-hover);\\n}\\n.hw-header-menu-conv-top {\\n display: flex;\\n align-items: baseline;\\n justify-content: space-between;\\n gap: 8px;\\n}\\n.hw-header-menu-conv-name {\\n overflow: hidden;\\n font-size: 12.5px;\\n font-weight: 600;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.hw-header-menu-conv-time {\\n flex: none;\\n font-size: 11px;\\n color: var(--hw-text-3, var(--hw-text-muted));\\n}\\n.hw-header-menu-conv-preview {\\n overflow: hidden;\\n font-size: 12px;\\n color: var(--hw-text-2);\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.hw-offers {\\n display: flex;\\n flex-wrap: wrap;\\n gap: 6px;\\n margin-top: 10px;\\n}\\n.hw-offer {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n padding: 8px 14px;\\n border: 0;\\n border-radius: 999px;\\n cursor: pointer;\\n background: var(--hw-bg-hover);\\n color: var(--hw-text);\\n font: inherit;\\n font-size: 12.5px;\\n font-weight: 550;\\n transition: background 0.15s, color 0.15s;\\n}\\n.hw-offer:hover {\\n background: var(--hw-brand, var(--hw-primary));\\n color: var(--hw-on-brand, #fff);\\n}\\n.hw-offer svg {\\n flex: none;\\n}\\n.hw-sources {\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n margin-top: 8px;\\n}\\n.hw-source {\\n display: flex;\\n align-items: center;\\n gap: 9px;\\n padding: 7px 10px;\\n border-radius: 9px;\\n background: transparent;\\n color: var(--hw-text);\\n text-decoration: none;\\n transition: background 0.15s;\\n}\\na.hw-source {\\n cursor: pointer;\\n}\\na.hw-source:hover {\\n background: var(--hw-bg-hover);\\n}\\n.hw-source-n {\\n display: grid;\\n place-items: center;\\n flex: none;\\n width: 16px;\\n height: 16px;\\n border-radius: 4px;\\n background: var(--hw-brand, var(--hw-primary));\\n color: var(--hw-on-brand, #fff);\\n font-size: 10px;\\n font-weight: 700;\\n font-variant-numeric: tabular-nums;\\n}\\n.hw-source-title {\\n flex: 1;\\n min-width: 0;\\n font-size: 12px;\\n font-weight: 550;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\")","\"use client\";\n\n/**\n * `<HelpwayWidget />` — one-line drop-in React component that renders\n * the full Helpway widget natively in React.\n *\n * Since v0.2, this is a native React render (not a script tag injection).\n * The widget-core + widget-react code is bundled with your app, so widget\n * updates ship via `npm update @helpway/react` — no separate widget.js\n * deploy required. Bundle impact: ~120KB gzipped (shared with any other\n * helpway/react imports in your app, so subsequent uses are free).\n *\n * Power-user alternative: import `{ SupportProvider, DefaultWidget, useWidget, … }`\n * directly for programmatic control (render your own chat UI, expose\n * identify() via hook instead of global, etc.).\n *\n * @see https://helpway.ai/docs/quick-start for setup\n * @see https://helpway.ai/docs/react-sdk for the three integration layers\n * (drop-in, provider + hooks, fully headless)\n * @see https://helpway.ai/docs/customization for theming via `theme` prop\n * and the dashboard config\n * @see https://helpway.ai/docs/integration-notes for CSP, SSR, multi-tenant\n */\n\nimport type { DockSuggestion, WidgetPlacement, WidgetTheme } from \"@helpway/widget-core\";\nimport { SupportProvider } from \"./provider\";\nimport { DefaultWidget } from \"./themed/default-widget\";\n// Auto-import CSS so consumers don't need a separate `import \"@helpway/react/styles.css\"` step.\n// Side-effect import — evaluated once per bundle, tree-shaker preserves it via `sideEffects: [\"*.css\"]`.\nimport \"./themed/styles.css\";\n\nexport interface HelpwayWidgetProps {\n\t/**\n\t * Public API key from the Helpway dashboard. Required.\n\t * Format: `pk_live_…` or `pk_test_…`.\n\t */\n\tapiKey: string;\n\t/**\n\t * Override the default API URL. Almost no one needs this —\n\t * exposed for staging / self-hosted setups.\n\t * @default \"https://api.helpway.ai\"\n\t */\n\tapiUrl?: string;\n\t/**\n\t * Widget locale (e.g. \"tr\", \"en\", \"de\"). Falls back to server-side\n\t * detection (Accept-Language + CF-IPCountry) then widget-core default.\n\t */\n\tlocale?: string;\n\t/**\n\t * Deep link: auto-open this conversation after bootstrap.\n\t * Usually sourced from `?hw_conv=` URL param for email CTAs.\n\t */\n\tinitialConversationId?: string;\n\t/**\n\t * HMAC-signed token for cross-device visitor identity restoration.\n\t * Sourced from `#hw_token=` URL fragment in email deep-links.\n\t */\n\tdeepLinkToken?: string;\n\t/**\n\t * Called once after the widget has bootstrapped and exposes\n\t * the full programmatic API object (also available as `window.Helpway`).\n\t */\n\tonReady?: (api: HelpwayPublicAPI) => void;\n\t/**\n\t * Hide the default floating launcher button. Use with\n\t * `customLauncherSelector` or `window.Helpway.open()` to trigger\n\t * the widget from your own UI.\n\t */\n\thideLauncher?: boolean;\n\t/**\n\t * Where the widget lives on the page. The conversation UI is identical\n\t * across placements — only the shell moves.\n\t *\n\t * - `bubble` floating launcher bottom-right (default)\n\t * - `docked` composer bar pinned to the foot of the page; the bar is\n\t * the composer, so the panel above it renders without one\n\t * @default \"bubble\"\n\t */\n\tplacement?: WidgetPlacement;\n\t/**\n\t * Force the widget's appearance instead of following the visitor's OS.\n\t * Set this to match the page you are embedding in — a light page in a\n\t * dark-OS browser otherwise gets a dark widget.\n\t * @default \"system\"\n\t */\n\tcolorScheme?: \"light\" | \"dark\" | \"system\";\n\t/**\n\t * Ways in offered above the docked bar before the visitor types.\n\t * Only used when `placement=\"docked\"`.\n\t */\n\tdockSuggestions?: readonly DockSuggestion[];\n\t/**\n\t * CSS selector for a custom trigger element (e.g. `\"#support-btn\"`).\n\t * Clicking the matched element calls `Helpway.open()`. Combine with\n\t * `hideLauncher` to fully replace the default bubble.\n\t */\n\tcustomLauncherSelector?: string;\n\t/** Fires when the widget panel opens */\n\tonOpen?: () => void;\n\t/** Fires when the widget panel closes */\n\tonClose?: () => void;\n\t/** Fires when the unread count changes */\n\tonUnreadChange?: (count: number) => void;\n\t/**\n\t * Developer-side theme override. Most consumers should configure\n\t * appearance from the dashboard so changes apply without a redeploy\n\t * — see https://helpway.ai/docs/customization. Use this prop only\n\t * for runtime-resolved theming (multi-tenant brand colors, dark/\n\t * light sync with the host app, etc). Values map to CSS custom\n\t * properties on the widget host. See the `WidgetTheme` type for\n\t * the full set of supported keys.\n\t */\n\ttheme?: WidgetTheme;\n\t/**\n\t * @deprecated Legacy prop from the v0.1 script-loader era. If set,\n\t * the `/widget.js` suffix is stripped to derive `apiUrl`. New code\n\t * should use `apiUrl` instead.\n\t */\n\tsrc?: string;\n}\n\n// Re-export for consumers who use the onReady callback type.\n// `onReady` receives the programmatic methods object; the global\n// `window.Helpway` is the callable wrapper around it (HelpwayAPI).\nimport type { HelpwayMethods } from \"@helpway/widget-core\";\nexport type HelpwayPublicAPI = HelpwayMethods;\n\n/**\n * Render this once at the root of your app (e.g. in `_app.tsx`,\n * `layout.tsx`, or `main.tsx`). Unmounting cleanly tears down the\n * widget and its WebSocket connection — useful for route-scoped mounts.\n */\nexport function HelpwayWidget({\n\tapiKey,\n\tapiUrl,\n\tlocale,\n\tinitialConversationId,\n\tdeepLinkToken,\n\tonReady,\n\thideLauncher,\n\tplacement,\n\tcolorScheme,\n\tdockSuggestions,\n\tcustomLauncherSelector,\n\tonOpen,\n\tonClose,\n\tonUnreadChange,\n\ttheme,\n\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\tsrc,\n}: HelpwayWidgetProps) {\n\tconst resolvedApiUrl = apiUrl ?? (src ? src.replace(/\\/widget\\.js$/, \"\") : undefined);\n\n\treturn (\n\t\t<SupportProvider\n\t\t\tapiKey={apiKey}\n\t\t\tapiUrl={resolvedApiUrl}\n\t\t\tlocale={locale}\n\t\t\tinitialConversationId={initialConversationId}\n\t\t\tdeepLinkToken={deepLinkToken}\n\t\t\tonReady={onReady}\n\t\t\tcustomLauncherSelector={customLauncherSelector}\n\t\t\tonOpen={onOpen}\n\t\t\tonClose={onClose}\n\t\t\tonUnreadChange={onUnreadChange}\n\t\t\ttheme={theme}\n\t\t>\n\t\t\t<DefaultWidget\n\t\t\t\thideLauncher={hideLauncher}\n\t\t\t\tplacement={placement}\n\t\t\t\tcolorScheme={colorScheme}\n\t\t\t\tdockSuggestions={dockSuggestions}\n\t\t\t/>\n\t\t</SupportProvider>\n\t);\n}\n","import type { RealtimeEvent } from \"@helpway/types\";\nimport { useEffect, useRef } from \"react\";\nimport { useWidgetContext } from \"../provider\";\n\n/**\n * Subscribe to raw WebSocket events.\n * For advanced usage — most apps should use useTimeline/usePresence instead.\n *\n * Usage:\n * ```tsx\n * useRealtime((event) => {\n * if (event.type === 'timelineItemCreated') { ... }\n * })\n * ```\n *\n * The subscription lives as long as the socket instance, not as long as the\n * handler's identity (#146). Callers pass inline arrows, which are new on every\n * render; with `handler` in the effect deps that meant `handlers.delete` and\n * `handlers.add` on every render above the caller, and any event that arrived\n * between the two was dropped. The latest handler is kept in a ref and one\n * stable wrapper is subscribed per socket.\n */\nexport function useRealtime(handler: (event: RealtimeEvent) => void) {\n\tconst { ws } = useWidgetContext();\n\tconst handlerRef = useRef(handler);\n\n\tuseEffect(() => {\n\t\thandlerRef.current = handler;\n\t});\n\n\tuseEffect(() => {\n\t\treturn ws.onEvent((event) => handlerRef.current(event));\n\t}, [ws]);\n}\n"],"mappings":";;;AAAA,SAAS,kBAAkB,qBAAqB;;;ACWhD,IAAM,SAAS;AACf,IAAM,aAAa;AAEnB,SAAS,OAAO,WAA2B;AAG1C,QAAM,SAAS,UAAU,MAAM,GAAG;AAClC,SAAO,GAAG,MAAM,IAAI,MAAM;AAC3B;AAEA,SAAS,aAAqB;AAC7B,QAAM,KAAK,KAAK,IAAI,EAAE,SAAS,EAAE;AACjC,QAAM,OAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;AACnD,SAAO,GAAG,EAAE,GAAG,IAAI;AACpB;AAMO,SAAS,qBAAqB,WAA2B;AAC/D,MAAI;AACH,UAAMA,cAAa,OAAO,SAAS;AACnC,UAAM,WAAW,aAAa,QAAQA,WAAU;AAChD,QAAI,SAAU,QAAO;AAKrB,UAAM,SAAS,aAAa,QAAQ,UAAU;AAC9C,QAAI,QAAQ;AACX,mBAAa,QAAQA,aAAY,MAAM;AACvC,mBAAa,WAAW,UAAU;AAClC,aAAO;AAAA,IACR;AAEA,UAAM,KAAK,WAAW;AACtB,iBAAa,QAAQA,aAAY,EAAE;AACnC,WAAO;AAAA,EACR,QAAQ;AAEP,WAAO,WAAW;AAAA,EACnB;AACD;AAGO,SAAS,cAAc,WAAmB,iBAA+B;AAC/E,MAAI;AACH,iBAAa,QAAQ,OAAO,SAAS,GAAG,eAAe;AAAA,EACxD,QAAQ;AAAA,EAER;AACD;AAGO,SAAS,eAAe,WAAyB;AACvD,MAAI;AACH,iBAAa,WAAW,OAAO,SAAS,CAAC;AAAA,EAC1C,QAAQ;AAAA,EAER;AACD;;;ADrDO,SAAS,mBAAmB,QAI3B;AACP,SAAO,iBAAiB;AAAA,IACvB,OAAO;AAAA,MACN,cAAc;AAAA,QACb,KAAK,GAAG,OAAO,MAAM;AAAA,QACrB,UAAU;AACT,iBAAO;AAAA,YACN,gBAAgB,OAAO;AAAA,YACvB,gBAAgB,qBAAqB,OAAO,MAAM;AAAA,UACnD;AAAA,QACD;AAAA,QACA,MAAM,KAAK,SAAS;AAEnB,iBAAO,WAAW,MAAM,KAAK,EAAE,GAAG,SAAS,aAAa,UAAU,CAAC;AAAA,QACpE;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD,CAAC;AACF;;;AEpBO,IAAM,YAAY;AAAA,EACxB,kBAAkB;AAAA,IACjB,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,EACZ;AAAA,EACA,kBAAkB;AAAA,IACjB,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,EACZ;AAAA,EACA,uBAAuB;AAAA,IACtB,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,EACZ;AAAA,EACA,iBAAiB;AAAA,IAChB,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,EACZ;AAAA,EACA,sBAAsB;AAAA,IACrB,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,EACZ;AACD;AAOO,IAAM,eAAe,OAAO,KAAK,SAAS;;;ACjD1C,IAAM,cAAc;AAAA,EAC1B,uBAAuB;AAAA,EACvB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,eAAe;AAAA,EACf,wBAAwB;AAAA,EACxB,eAAe;AAAA,EACf,uBAAuB;AACxB;AA8HO,SAAS,gBAAgB,MAAsC;AACrE,SACC,OAAO,SAAS,YAChB,SAAS,QACT,UAAU,QACV,OAAQ,KAAuB,SAAS;AAE1C;;;AC3HO,IAAM,gBAA8B;AAAA,EAC1C;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG;AAAA,MACrC;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,YAAY,QAAQ,mBAAmB;AAAA,MAC5C,EAAE,GAAG,YAAY,QAAQ,gBAAgB;AAAA,IAC1C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,kCAAkC;AAAA,MAClD,EAAE,GAAG,QAAQ,GAAG,iEAAiE;AAAA,IAClF;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,MACA;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,MACA;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,YAAY,QAAQ,iBAAiB;AAAA,MAC1C,EAAE,GAAG,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AAAA,IAC7C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,OAAO,IAAI,QAAQ,IAAI,IAAI,EAAE;AAAA,MACtD,EAAE,GAAG,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,GAAG;AAAA,IAChD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,OAAO,IAAI,QAAQ,GAAG,IAAI,EAAE;AAAA,MACrD,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG,IAAI,OAAO,IAAI,QAAQ,GAAG,IAAI,EAAE;AAAA,MACtD,EAAE,GAAG,QAAQ,IAAI,GAAG,IAAI,GAAG,IAAI,MAAM,IAAI,EAAE;AAAA,MAC3C,EAAE,GAAG,QAAQ,IAAI,GAAG,IAAI,IAAI,IAAI,MAAM,IAAI,GAAG;AAAA,IAC9C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,KAAK,IAAI,MAAM,GAAG,IAAI;AAAA,MACzC,EAAE,GAAG,QAAQ,GAAG,yBAAyB;AAAA,IAC1C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,6DAA6D;AAAA,MAC7E,EAAE,GAAG,YAAY,QAAQ,iBAAiB;AAAA,IAC3C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE;AAAA,MACpC;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ,CAAC,EAAE,GAAG,WAAW,QAAQ,yCAAyC,CAAC;AAAA,EAC5E;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,WAAW,QAAQ,2BAA2B;AAAA,MACnD,EAAE,GAAG,YAAY,QAAQ,mBAAmB;AAAA,MAC5C,EAAE,GAAG,YAAY,QAAQ,mBAAmB;AAAA,IAC7C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,YAAY;AAAA,MAC5B,EAAE,GAAG,QAAQ,GAAG,gBAAgB;AAAA,MAChC,EAAE,GAAG,QAAQ,GAAG,4BAA4B;AAAA,IAC7C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ,CAAC,EAAE,GAAG,QAAQ,GAAG,gEAAgE,CAAC;AAAA,EAC3F;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,YAAY,QAAQ,oCAAoC;AAAA,MAC7D;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,4CAA4C;AAAA,MAC5D,EAAE,GAAG,UAAU,IAAI,GAAG,IAAI,GAAG,GAAG,EAAE;AAAA,MAClC,EAAE,GAAG,QAAQ,GAAG,sDAAsD;AAAA,IACvE;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,OAAO,IAAI,QAAQ,IAAI,IAAI,EAAE;AAAA,MACtD,EAAE,GAAG,QAAQ,GAAG,iBAAiB;AAAA,IAClC;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,OAAO,IAAI,QAAQ,IAAI,IAAI,EAAE;AAAA,MACtD,EAAE,GAAG,QAAQ,IAAI,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AAAA,IAC5C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,4CAA4C;AAAA,MAC5D,EAAE,GAAG,QAAQ,GAAG,iCAAiC;AAAA,IAClD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE;AAAA,MACpC,EAAE,GAAG,QAAQ,GAAG,iBAAiB;AAAA,IAClC;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,GAAG,8CAA8C;AAAA,MAC9D,EAAE,GAAG,QAAQ,GAAG,gBAAgB;AAAA,IACjC;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG;AAAA,MACrC,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE;AAAA,MACpC,EAAE,GAAG,QAAQ,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK;AAAA,MACpD,EAAE,GAAG,QAAQ,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM;AAAA,MACxD,EAAE,GAAG,QAAQ,IAAI,OAAO,IAAI,MAAM,IAAI,OAAO,IAAI,KAAK;AAAA,MACtD,EAAE,GAAG,QAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,IAAI,MAAM;AAAA,IACvD;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AAAA,MAC5C,EAAE,GAAG,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE;AAAA,MAC3C,EAAE,GAAG,QAAQ,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,IAAI,GAAG;AAAA,IAC3C;AAAA,EACD;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,MACP,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,GAAG,GAAG,EAAE;AAAA,MACnC,EAAE,GAAG,UAAU,IAAI,GAAG,IAAI,IAAI,GAAG,EAAE;AAAA,MACnC,EAAE,GAAG,UAAU,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE;AAAA,MACpC,EAAE,GAAG,QAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM;AAAA,MACvD,EAAE,GAAG,QAAQ,IAAI,OAAO,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM;AAAA,IACvD;AAAA,EACD;AACD;AAGO,IAAM,qBAA+B,cAAc,IAAI,CAAC,MAAM,EAAE,IAAI;AAE3E,IAAM,mBAA+C,OAAO;AAAA,EAC3D,cAAc,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AACrC;;;ACpRO,IAAM,cACmC,SAAwB,SAAS,IAC7E,WACA;;;ACaG,IAAM,mBAAN,MAAuB;AAAA,EACrB,KAAuB;AAAA,EACvB,WAAW,oBAAI,IAAkB;AAAA,EACjC;AAAA,EACA,oBAAoB;AAAA,EACpB,uBAAuB;AAAA,EACvB,iBAAuD;AAAA,EACvD,YAAmD;AAAA,EACnD,cAAc;AAAA,EACd,oBAAyC;AAAA,EAEjD,YAAY,QAAgC;AAC3C,SAAK,SAAS;AACd,SAAK,wBAAwB;AAAA,EAC9B;AAAA,EAEQ,0BAAgC;AACvC,QAAI,OAAO,aAAa,YAAa;AACrC,SAAK,oBAAoB,MAAM;AAC9B,UAAI,SAAS,oBAAoB,UAAU;AAE1C,aAAK,SAAS;AAAA,MACf,WAAW,KAAK,IAAI,eAAe,UAAU,MAAM;AAElD,aAAK,UAAU;AACf,aAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AAAA,MAC3B;AAAA,IACD;AACA,aAAS,iBAAiB,oBAAoB,KAAK,iBAAiB;AAAA,EACrE;AAAA;AAAA,EAGA,UAAU,QAA+C;AACxD,WAAO,OAAO,KAAK,QAAQ,MAAM;AAAA,EAClC;AAAA;AAAA,EAGA,UAAgB;AACf,QAAI,KAAK,IAAI,eAAe,UAAU,KAAM;AAE5C,SAAK,cAAc;AAEnB,UAAM,WAAW,KAAK,OAAO,OAAO,WAAW,OAAO,IAAI,QAAQ;AAClE,UAAM,OAAO,KAAK,OAAO,OAAO,QAAQ,WAAW,QAAQ;AAC3D,UAAM,SAAS,IAAI,gBAAgB;AAAA,MAClC,MAAM;AAAA,MACN,IAAI,KAAK,OAAO;AAAA,MAChB,WAAW,KAAK,OAAO;AAAA,MACvB,KAAK,KAAK,OAAO;AAAA;AAAA,MAEjB,GAAG;AAAA,IACJ,CAAC;AAED,UAAM,KAAK,IAAI,UAAU,GAAG,IAAI,OAAO,MAAM,EAAE;AAE/C,OAAG,SAAS,MAAM;AACjB,WAAK,oBAAoB;AAGzB,UAAI,OAAO,aAAa,eAAe,SAAS,oBAAoB,WAAW;AAC9E,aAAK,UAAU;AAAA,MAChB;AAAA,IACD;AAEA,OAAG,YAAY,CAAC,UAAU;AACzB,UAAI;AACH,cAAM,OAAO,KAAK,MAAM,MAAM,IAAc;AAC5C,YAAI,KAAK,SAAS,OAAQ;AAC1B,YAAI,gBAAgB,IAAI,GAAG;AAC1B,qBAAW,WAAW,KAAK,UAAU;AACpC,oBAAQ,IAAI;AAAA,UACb;AAAA,QACD;AAAA,MACD,QAAQ;AAAA,MAER;AAAA,IACD;AAEA,OAAG,UAAU,MAAM;AAClB,WAAK,SAAS;AACd,WAAK,KAAK;AACV,UAAI,CAAC,KAAK,aAAa;AACtB,aAAK,kBAAkB;AAAA,MACxB;AAAA,IACD;AAEA,OAAG,UAAU,MAAM;AAAA,IAEnB;AAEA,SAAK,KAAK;AAAA,EACX;AAAA;AAAA,EAGA,aAAmB;AAClB,SAAK,cAAc;AACnB,SAAK,SAAS;AACd,QAAI,KAAK,gBAAgB;AACxB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACvB;AACA,QAAI,KAAK,qBAAqB,OAAO,aAAa,aAAa;AAC9D,eAAS,oBAAoB,oBAAoB,KAAK,iBAAiB;AACvE,WAAK,oBAAoB;AAAA,IAC1B;AACA,QAAI,KAAK,IAAI;AACZ,WAAK,GAAG,MAAM,KAAM,mBAAmB;AACvC,WAAK,KAAK;AAAA,IACX;AAAA,EACD;AAAA;AAAA,EAGA,KAAK,MAAqC;AACzC,QAAI,KAAK,IAAI,eAAe,UAAU,MAAM;AAC3C,WAAK,GAAG,KAAK,KAAK,UAAU,IAAI,CAAC;AAAA,IAClC;AAAA,EACD;AAAA;AAAA,EAGA,WAAW,gBAAwB,UAAyB;AAC3D,SAAK,KAAK,EAAE,MAAM,UAAU,gBAAgB,SAAS,CAAC;AAAA,EACvD;AAAA;AAAA,EAGA,QAAQ,SAAmC;AAC1C,SAAK,SAAS,IAAI,OAAO;AACzB,WAAO,MAAM;AACZ,WAAK,SAAS,OAAO,OAAO;AAAA,IAC7B;AAAA,EACD;AAAA;AAAA,EAGA,IAAI,cAAuB;AAC1B,WAAO,KAAK,IAAI,eAAe,UAAU;AAAA,EAC1C;AAAA;AAAA,EAIQ,oBAA0B;AACjC,QAAI,KAAK,qBAAqB,KAAK,qBAAsB;AAEzD,UAAM,QAAQ,KAAK,IAAI,MAAO,KAAK,KAAK,mBAAmB,GAAK;AAChE,SAAK;AAEL,SAAK,iBAAiB,WAAW,MAAM;AACtC,WAAK,QAAQ;AAAA,IACd,GAAG,KAAK;AAAA,EACT;AAAA,EAEQ,YAAkB;AACzB,SAAK,SAAS;AACd,SAAK,YAAY,YAAY,MAAM;AAClC,WAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AAAA,IAC3B,GAAG,IAAK;AAAA,EACT;AAAA,EAEQ,WAAiB;AACxB,QAAI,KAAK,WAAW;AACnB,oBAAc,KAAK,SAAS;AAC5B,WAAK,YAAY;AAAA,IAClB;AAAA,EACD;AACD;;;AC1LA,SAAS,mBAAmB;;;ACY5B,IAAM,KAA6B;AAAA;AAAA,EAElC,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,eAAe;AAAA;AAAA,EAGf,0BAA0B;AAAA,EAC1B,qBAAqB;AAAA,EACrB,+BAA+B;AAAA,EAC/B,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA;AAAA,EAGnB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA,EAC3B,6BAA6B;AAAA,EAC7B,qBAAqB;AAAA;AAAA,EAGrB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,gCAAgC;AAAA,EAChC,uBAAuB;AAAA,EACvB,wBAAwB;AAAA,EACxB,wBAAwB;AAAA,EACxB,+BAA+B;AAAA;AAAA,EAG/B,sBAAsB;AAAA,EACtB,0BAA0B;AAAA,EAC1B,qBAAqB;AAAA;AAAA,EAGrB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA;AAAA,EAGtB,sBAAsB;AAAA,EACtB,yBAAyB;AAAA,EACzB,4BAA4B;AAAA,EAC5B,yBAAyB;AAAA,EACzB,sBAAsB;AAAA,EACtB,wBAAwB;AAAA;AAAA,EAGxB,sBAAsB;AAAA,EACtB,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,qBAAqB;AAAA;AAAA,EAGrB,oBAAoB;AAAA;AAAA,EAGpB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA;AAAA,EAGlB,iBAAiB;AAAA,EACjB,eAAe;AAAA;AAAA,EAGf,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,sBAAsB;AAAA,EACtB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,kBAAkB;AAAA;AAAA,EAGlB,eAAe;AAAA,EACf,iBAAiB;AAAA;AAAA,EAGjB,yBAAyB;AAAA,EACzB,wBAAwB;AAAA,EACxB,2BAA2B;AAAA;AAAA,EAG3B,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,oBAAoB;AAAA,EACpB,6BAA6B;AAAA,EAC7B,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,wBAAwB;AAAA;AAAA,EAGxB,mBAAmB;AAAA,EACnB,yBAAyB;AAAA;AAAA,EAGzB,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUrB,8BAA8B;AAAA,EAE9B,iCAAiC;AAAA,EACjC,6BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA,EAM7B,0BAA0B;AAAA,EAC1B,wBAAwB;AACzB;AAIA,IAAI,gBAAgB;AACpB,IAAI,eAAuC,CAAC;AAC5C,IAAI,WAAW;AACf,IAAI,WAAW;AACf,IAAM,YAA+B,CAAC;AAU/B,SAAS,EAAE,KAAa,QAAkD;AAChF,QAAM,QAAQ,aAAa,GAAG,KAAK,GAAG,GAAG,KAAK;AAE9C,MAAI,CAAC,OAAQ,QAAO;AAEpB,SAAO,MAAM,QAAQ,kBAAkB,CAAC,GAAG,MAAc;AACxD,WAAO,OAAO,CAAC,GAAG,SAAS,KAAK,KAAK,CAAC;AAAA,EACvC,CAAC;AACF;AAGO,SAAS,YAAoB;AACnC,SAAO;AACR;AAGO,SAAS,kBAA0B;AACzC,SAAO;AACR;AAQO,SAAS,eAAe,IAA4B;AAC1D,YAAU,KAAK,EAAE;AACjB,SAAO,MAAM;AACZ,UAAM,MAAM,UAAU,QAAQ,EAAE;AAChC,QAAI,OAAO,EAAG,WAAU,OAAO,KAAK,CAAC;AAAA,EACtC;AACD;AAYA,eAAsB,SAAS,SAAgE;AAC9F,MAAI,SAAS,SAAS;AACrB,cAAU,QAAQ;AAAA,EACnB;AAEA,QAAM,WACL,SAAS,WAAW,OAAO,cAAc,cAAc,UAAU,WAAW;AAG7E,kBAAgB,gBAAgB,QAAQ;AAGxC,MAAI,kBAAkB,MAAM;AAC3B,eAAW;AACX,WAAO;AACP;AAAA,EACD;AAGA,MAAI;AACH,UAAM,OAAO,MAAM,kBAAkB,aAAa;AAClD,QAAI,MAAM;AAET,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAChD,YAAI,OAAO,UAAU,UAAU;AAC9B,uBAAa,UAAU,GAAG,EAAE,IAAI;AAAA,QACjC;AAAA,MACD;AAAA,IACD;AAAA,EACD,SAAS,KAAK;AACb,YAAQ,KAAK,6BAA6B,aAAa,gCAAgC,GAAG;AAAA,EAC3F;AAEA,aAAW;AACX,SAAO;AACR;AAMA,eAAsB,UAAU,QAA+B;AAC9D,QAAM,aAAa,gBAAgB,MAAM;AACzC,MAAI,eAAe,cAAe;AAElC,kBAAgB;AAChB,iBAAe,CAAC;AAEhB,MAAI,eAAe,MAAM;AACxB,WAAO;AACP;AAAA,EACD;AAEA,MAAI;AACH,UAAM,OAAO,MAAM,kBAAkB,UAAU;AAC/C,QAAI,MAAM;AACT,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAChD,YAAI,OAAO,UAAU,UAAU;AAC9B,uBAAa,UAAU,GAAG,EAAE,IAAI;AAAA,QACjC;AAAA,MACD;AAAA,IACD;AAAA,EACD,QAAQ;AAAA,EAER;AAEA,SAAO;AACR;AAIA,IAAI,UAAU;AAEd,eAAe,kBAAkB,QAAwD;AAExF,QAAM,MAAM,GAAG,OAAO,IAAI,MAAM;AAEhC,MAAI,MAAM,MAAM,MAAM,GAAG;AACzB,MAAI,CAAC,IAAI,MAAM,OAAO,SAAS,GAAG,GAAG;AAEpC,UAAM,OAAO,OAAO,MAAM,GAAG,EAAE,CAAC;AAChC,UAAM,MAAM,MAAM,GAAG,OAAO,IAAI,IAAI,oBAAoB;AAAA,EACzD;AACA,MAAI,CAAC,IAAI,GAAI,QAAO;AAEpB,QAAM,OAAgC,MAAM,IAAI,KAAK;AAErD,QAAM,WAAW,KAAK;AACtB,MAAI,YAAY,OAAO,aAAa,YAAY,CAAC,MAAM,QAAQ,QAAQ,GAAG;AACzE,UAAM,SAAiC,CAAC;AACxC,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,GAAG;AAC9C,UAAI,OAAO,MAAM,SAAU,QAAO,CAAC,IAAI;AAAA,IACxC;AACA,WAAO;AAAA,EACR;AACA,SAAO;AACR;AAEA,SAAS,gBAAgB,OAAuB;AAE/C,QAAM,WAAW,CAAC,SAAS,SAAS,SAAS,OAAO;AACpD,QAAM,QAAQ,MAAM,YAAY,EAAE,QAAQ,KAAK,GAAG;AAElD,aAAW,KAAK,UAAU;AACzB,QAAI,MAAM,WAAW,CAAC,EAAG,QAAO;AAAA,EACjC;AAGA,SAAO,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK;AAC/B;AAEA,SAAS,SAAe;AACvB;AACA,aAAW,MAAM,WAAW;AAC3B,QAAI;AACH,SAAG;AAAA,IACJ,QAAQ;AAAA,IAER;AAAA,EACD;AACD;;;AC3TO,SAAS,mBAAmB,MAA6B;AAC/D,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,OAAO,OAAO,SAAS,WAAW,IAAI,KAAK,IAAI,EAAE,QAAQ,IAAI,KAAK,QAAQ;AAChF,QAAM,SAAS,MAAM;AACrB,QAAM,UAAU,KAAK,MAAM,SAAS,GAAK;AACzC,QAAM,WAAW,KAAK,MAAM,SAAS,IAAO;AAC5C,QAAM,UAAU,KAAK,MAAM,SAAS,KAAQ;AAE5C,MAAI,UAAU,EAAG,QAAO,EAAE,iBAAiB;AAC3C,MAAI,UAAU,GAAI,QAAO,GAAG,OAAO;AACnC,MAAI,WAAW,GAAI,QAAO,GAAG,QAAQ;AACrC,MAAI,YAAY,EAAG,QAAO,EAAE,uBAAuB;AACnD,MAAI,UAAU,EAAG,QAAO,GAAG,OAAO;AAElC,QAAM,IAAI,OAAO,SAAS,WAAW,IAAI,KAAK,IAAI,IAAI;AACtD,SAAO,EAAE,mBAAmB,UAAU,GAAG,EAAE,OAAO,SAAS,KAAK,UAAU,CAAC;AAC5E;AAKO,SAAS,WAAW,MAA6B;AACvD,QAAM,IAAI,OAAO,SAAS,WAAW,IAAI,KAAK,IAAI,IAAI;AACtD,SAAO,EAAE,mBAAmB,QAAW,EAAE,MAAM,WAAW,QAAQ,UAAU,CAAC;AAC9E;AAOO,SAAS,aAAa,OAAuB;AACnD,MAAI,CAAC,MAAM,WAAW,SAAS,EAAG,QAAO;AACzC,QAAM,WAAW,EAAE,KAAK;AACxB,MAAI,aAAa,OAAO;AACvB,WAAO,MACL,QAAQ,WAAW,EAAE,EACrB,QAAQ,MAAM,GAAG,EACjB,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC;AAAA,EACxC;AACA,SAAO;AACR;AAKO,SAAS,YAAY,OAAuB;AAClD,MAAI,CAAC,MAAO,QAAO;AAGnB,MAAI,MAAM,SAAS,GAAG,EAAG,SAAQ,MAAM,CAAC,KAAK,KAAK,YAAY;AAG9D,QAAM,QAAQ,MAAM,KAAK,EAAE,MAAM,KAAK;AACtC,MAAI,MAAM,UAAU,GAAG;AACtB,aAAS,MAAM,CAAC,IAAI,CAAC,KAAK,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY;AAAA,EACpE;AACA,UAAQ,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY;AAC3C;AAiBO,SAAS,0BACf,KAC8B;AAC9B,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,MAAI;AACH,UAAM,SAAkB,KAAK,MAAM,GAAG;AACtC,WAAO,UAAU,OAAO,WAAW,WAAY,SAAkC;AAAA,EAClF,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAeO,SAAS,oBACf,UACkG;AAClG,QAAM,SAAS,0BAA0B,QAAQ;AACjD,MAAI,QAAQ,SAAS,gBAAiB,QAAO;AAC7C,MAAI,CAAC,MAAM,QAAQ,OAAO,OAAO,KAAK,OAAO,QAAQ,WAAW,EAAG,QAAO;AAI1E,MAAI,OAAO,UAAW,QAAO;AAC7B,SAAO;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO,UAAU;AAAA,IACzB,SAAS,OAAO,QAAQ,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,MAAM,EAAE;AAAA,EAClE;AACD;AAiBO,SAAS,uBACf,UACA,YACgC;AAGhC,QAAM,OAAO,OAAO,SAAS,UAAU,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,UAAU,CAAC,IAAI,SAAS;AAC1F,SAAO,EAAE,SAAS,SAAS,MAAM,GAAG,IAAI,GAAG,QAAQ,SAAS,MAAM,IAAI,EAAE;AACzE;AAkBO,SAAS,uBAAuB,cAI3B;AACX,MAAI,aAAa,WAAW,OAAQ,QAAO;AAC3C,SAAO,aAAa,0BAA0B,UAAU,aAAa,cAAc;AACpF;AAGO,SAAS,mBACf,eAKS;AACT,SAAO,cAAc,OAAO,sBAAsB,EAAE;AACrD;AAcO,IAAM,qBAAqB;AAG3B,SAAS,oBAAoB,MAAc,QAAQ,oBAA4B;AACrF,MAAI,KAAK,UAAU,MAAO,QAAO;AAIjC,QAAM,QAAQ,KAAK,MAAM,GAAG,KAAK;AACjC,QAAM,YAAY,MAAM,YAAY,GAAG;AACvC,QAAM,MAAM,YAAY,QAAQ,MAAM,MAAM,MAAM,GAAG,SAAS,IAAI;AAClE,SAAO,GAAG,IAAI,QAAQ,CAAC;AACxB;;;AF3JO,IAAM,oBAAoB,IAAI,KAAK;AAoL1C,IAAM,sBAAsB;AAUrB,SAAS,gBAAgB,gBAAgC;AAC/D,SAAO,aAAa,cAAc;AACnC;AAEA,SAAS,uBAAuD;AAC/D,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI;AACH,UAAM,MAAM,OAAO,aAAa,QAAQ,mBAAmB;AAC3D,WAAO,MAAO,KAAK,MAAM,GAAG,IAAuC;AAAA,EACpE,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,eAAe,SAA+C;AACtE,MAAI,OAAO,WAAW,YAAa;AACnC,MAAI;AACH,QAAI,SAAS;AACZ,aAAO,aAAa,QAAQ,qBAAqB,KAAK,UAAU,OAAO,CAAC;AAAA,IACzE,OAAO;AACN,aAAO,aAAa,WAAW,mBAAmB;AAAA,IACnD;AAAA,EACD,QAAQ;AAAA,EAER;AACD;AAQA,SAAS,eAAe,MAAoE;AAC3F,MAAI,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO;AAClC,MAAI;AACH,UAAM,SAAS,KAAK,MAAM,IAAI;AAK9B,QAAI,OAAO,WAAW,SAAU,QAAO;AACvC,WAAO,EAAE,MAAM,OAAO,QAAQ,MAAM,OAAO,OAAO,SAAS,KAAK;AAAA,EACjE,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAYA,SAAS,eACR,OACuD;AACvD,WAAS,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,UAAM,OAAO,MAAM,CAAC;AACpB,QAAI,MAAM,SAAS,WAAW,CAAC,KAAK,KAAM;AAC1C,UAAM,SAAS,eAAe,KAAK,IAAI;AACvC,QAAI,OAAQ,QAAO;AAAA,EACpB;AACA,SAAO;AACR;AAuBA,IAAM,sBAAsB;AAErB,SAAS,oBAAoB;AAGnC,QAAM,qBAAqB,oBAAI,IAA2C;AAC1E,QAAM,gBAAgB,CAAC,mBAA2B;AACjD,UAAM,QAAQ,mBAAmB,IAAI,cAAc;AACnD,QAAI,UAAU,QAAW;AACxB,mBAAa,KAAK;AAClB,yBAAmB,OAAO,cAAc;AAAA,IACzC;AAAA,EACD;AAEA,QAAM,QAAQ,YAAyB,CAAC,KAAK,SAAS;AAAA;AAAA,IAErD,SAAS;AAAA,IACT,cAAc;AAAA,IACd,SAAS;AAAA,IACT,SAAS;AAAA,IACT,aAAa;AAAA,IACb,eAAe,CAAC;AAAA,IAChB,sBAAsB;AAAA,IACtB,UAAU,oBAAI,IAAI;AAAA,IAClB,aAAa,oBAAI,IAAI;AAAA,IACrB,cAAc,oBAAI,IAAI;AAAA,IACtB,eAAe,oBAAI,IAAI;AAAA,IACvB,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,iBAAiB,qBAAqB;AAAA,IACtC,sBAAsB,CAAC;AAAA,IACvB,yBAAyB;AAAA,IACzB,wBAAwB;AAAA,IACxB,sBAAsB;AAAA,IACtB,cAAc,oBAAI,IAAI;AAAA;AAAA,IAItB,SAAS,SAAS,SAAS,aAAa;AACvC,UAAI;AAAA,QACH,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,QACA;AAAA,QACA,aAAa,eAAe;AAAA,MAC7B,CAAC;AAAA,IACF;AAAA,IAEA,cAAc,YAAY;AACzB,UAAI,EAAE,cAAc,WAAW,CAAC;AAAA,IACjC;AAAA;AAAA,IAIA,iBAAiB,eAAe;AAC/B,UAAI,EAAE,cAAc,CAAC;AAAA,IACtB;AAAA,IAEA,gBAAgB,cAAc;AAC7B,UAAI,CAAC,WAAW;AAAA,QACf,eAAe,CAAC,cAAc,GAAG,MAAM,aAAa;AAAA,MACrD,EAAE;AAAA,IACH;AAAA,IAEA,sBAAsB,IAAI;AACzB,UAAI,EAAE,sBAAsB,IAAI,MAAM,KAAK,iBAAiB,OAAO,CAAC;AAAA,IACrE;AAAA;AAAA,IAIA,YAAY,gBAAgB,OAAO;AAClC,YAAM,SAAS,eAAe,KAAK;AACnC,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,QAAQ;AACnC,aAAK,IAAI,gBAAgB,KAAK;AAC9B,eAAO;AAAA,UACN,UAAU;AAAA;AAAA;AAAA,UAGV,GAAI,SACD;AAAA,YACA,eAAe,MAAM,cAAc;AAAA,cAAI,CAAC,MACvC,EAAE,OAAO,iBACN;AAAA,gBACA,GAAG;AAAA,gBACH,cAAc,OAAO,QAAQ,EAAE;AAAA,gBAC/B,eAAe,OAAO,SAAS,EAAE;AAAA,cAClC,IACC;AAAA,YACJ;AAAA,UACD,IACC,CAAC;AAAA,QACL;AAAA,MACD,CAAC;AAAA,IACF;AAAA,IAEA,WAAW,gBAAgB,MAAM;AAChC,YAAM,SAAS,KAAK,SAAS,WAAW,KAAK,OAAO,eAAe,KAAK,IAAI,IAAI;AAChF,UAAI,QAAQ;AACX,YAAI,CAAC,WAAW;AAAA,UACf,eAAe,MAAM,cAAc;AAAA,YAAI,CAAC,MACvC,EAAE,OAAO,iBACN;AAAA,cACA,GAAG;AAAA,cACH,cAAc,OAAO,QAAQ,EAAE;AAAA,cAC/B,eAAe,OAAO,SAAS,EAAE;AAAA,YAClC,IACC;AAAA,UACJ;AAAA,QACD,EAAE;AAAA,MACH;AACA,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,QAAQ;AACnC,cAAM,WAAW,KAAK,IAAI,cAAc,KAAK,CAAC;AAG9C,YAAI,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE,EAAG,QAAO;AAenD,cAAM,YAAY,gBAAgB,cAAc;AAChD,YAAI,CAAC,KAAK,aAAa,KAAK,aAAa,MAAM,cAAc,IAAI,cAAc,GAAG;AACjF,eAAK,IAAI,gBAAgB;AAAA,YACxB,GAAG;AAAA,YACH,EAAE,GAAG,MAAM,YAAY,UAAU;AAAA,UAClC,CAAC;AACD,iBAAO,EAAE,UAAU,KAAK;AAAA,QACzB;AACA,cAAM,YAAY,KAAK,YACpB,SAAS;AAAA,UACT,CAAC,MAAM,CAAC,CAAC,EAAE,aAAa,EAAE,SAAS,KAAK,QAAQ,EAAE,GAAG,WAAW,aAAa;AAAA,QAC9E,IACC;AACH,YAAI,aAAa,GAAG;AACnB,gBAAM,aAAa,SAAS,SAAS;AACrC,gBAAMC,UAAS,CAAC,GAAG,QAAQ;AAC3B,UAAAA,QAAO,SAAS,IAAI;AAAA,YACnB,GAAG;AAAA,YACH,YAAY,WAAW,cAAc,WAAW;AAAA,UACjD;AACA,eAAK,IAAI,gBAAgBA,OAAM;AAC/B,iBAAO,EAAE,UAAU,KAAK;AAAA,QACzB;AAKA,cAAM,iBAAiB,CAAC,CAAC,KAAK,aAAa,CAAC,KAAK;AACjD,cAAM,iBAAiB,SAAS,CAAC,GAAG,aAAa;AACjD,YAAI,kBAAkB,gBAAgB;AACrC,eAAK,IAAI,gBAAgB,CAAC,MAAM,GAAG,QAAQ,CAAC;AAC5C,iBAAO,EAAE,UAAU,KAAK;AAAA,QACzB;AAGA,cAAM,OAAO,SAAS,SAAS,SAAS,CAAC;AACzC,cAAM,eAAe,QAAQ,KAAK,YAAY,KAAK;AACnD,cAAM,SAAS,CAAC,GAAG,UAAU,IAAI;AACjC,YAAI,cAAc;AACjB,iBAAO,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AAAA,QAC7D;AACA,aAAK,IAAI,gBAAgB,MAAM;AAC/B,eAAO,EAAE,UAAU,KAAK;AAAA,MACzB,CAAC;AAAA,IACF;AAAA,IAEA,eAAe,gBAAgB,OAAO,MAAM;AAC3C,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,QAAQ;AACnC,cAAM,WAAW,KAAK,IAAI,cAAc,KAAK,CAAC;AAE9C,YAAI,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,EAAE,OAAO,KAAK,GAAG;AAC7D,eAAK;AAAA,YACJ;AAAA,YACA,SAAS,OAAO,CAAC,MAAM,EAAE,OAAO,KAAK;AAAA,UACtC;AACA,iBAAO,EAAE,UAAU,KAAK;AAAA,QACzB;AAGA,aAAK;AAAA,UACJ;AAAA,UACA,SAAS;AAAA,YAAI,CAAC,MACb,EAAE,OAAO,QACN;AAAA,cACA,GAAG;AAAA,cACH,YAAa,EAAyC,cAAc;AAAA,YACrE,IACC;AAAA,UACJ;AAAA,QACD;AACA,eAAO,EAAE,UAAU,KAAK;AAAA,MACzB,CAAC;AAAA,IACF;AAAA,IAEA,cAAc,gBAAgB,IAAI;AACjC,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,QAAQ;AACnC,cAAM,WAAW,KAAK,IAAI,cAAc;AACxC,YAAI,CAAC,SAAU,QAAO;AACtB,aAAK;AAAA,UACJ;AAAA,UACA,SAAS,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAAA,QACnC;AACA,eAAO,EAAE,UAAU,KAAK;AAAA,MACzB,CAAC;AAAA,IACF;AAAA,IAEA,oBAAoB,OAAO,OAAO;AAIjC,UAAI,mBAAmB,IAAI,KAAK,GAAG;AAClC,sBAAc,KAAK;AACnB,2BAAmB;AAAA,UAClB;AAAA,UACA,WAAW,MAAM;AAChB,+BAAmB,OAAO,KAAK;AAC/B,gBAAI,EAAE,gBAAgB,OAAO,KAAK;AAClC,gBAAI,EAAE,UAAU,OAAO,KAAK;AAAA,UAC7B,GAAG,mBAAmB;AAAA,QACvB;AAAA,MACD;AACA,UAAI,CAAC,UAAU;AAId,cAAM,eAAe,IAAI,IAAI,MAAM,QAAQ;AAC3C,cAAM,YAAY,aAAa,IAAI,KAAK,KAAK,CAAC;AAC9C,cAAM,gBAAgB,aAAa,IAAI,KAAK,KAAK,CAAC;AAClD,cAAM,gBAAgB,UAAU,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,gBAAgB,MAAM,EAAE;AAC5E,cAAM,aAAa,CAAC,MAAoB,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,aAAa,CAAC,EAAE;AAM5E,cAAM,OAAO,oBAAI,IAAY;AAC7B,cAAM,SAAyB,CAAC;AAChC,YAAI,mBAAmB;AACvB,mBAAW,KAAK,eAAe;AAC9B,cAAI,KAAK,IAAI,EAAE,EAAE,EAAG;AACpB,eAAK,IAAI,EAAE,EAAE;AACb,iBAAO,KAAK,CAAC;AACb,cAAI,WAAW,CAAC,KAAK,OAAO,WAAW,EAAG,oBAAmB;AAAA,QAC9D;AASA,cAAM,kBAAkB,cAAc,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG;AAOhE,cAAM,eAAe,CAAC,MAAoB,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,aAAa,CAAC,EAAE;AAC9E,cAAM,iBAAiB,oBAAI,IAAoB;AAC/C,eAAO,QAAQ,CAAC,GAAG,MAAM;AACxB,cAAI,aAAa,CAAC,KAAK,OAAO,EAAE,SAAS,YAAY,CAAC,eAAe,IAAI,EAAE,IAAI,GAAG;AACjF,2BAAe,IAAI,EAAE,MAAM,CAAC;AAAA,UAC7B;AAAA,QACD,CAAC;AACD,YAAI,iBAAiB;AACrB,mBAAW,KAAK,eAAe;AAC9B,cAAI,KAAK,IAAI,EAAE,EAAE,EAAG;AACpB,cAAI,aAAa,CAAC,KAAK,OAAO,EAAE,SAAS,YAAY,eAAe,IAAI,EAAE,IAAI,GAAG;AAChF,kBAAM,MAAM,eAAe,IAAI,EAAE,IAAI;AACrC,2BAAe,OAAO,EAAE,IAAI;AAC5B,kBAAM,aAAa,OAAO,GAAG;AAC7B,mBAAO,GAAG,IAAI;AAAA,cACb,GAAG;AAAA,cACH,YAAY,aACP,WAAkD,cAAc,WAAW,KAC7E,EAAE;AAAA,YACN;AACA,iBAAK,IAAI,EAAE,EAAE;AACb;AAAA,UACD;AACA,gBAAM,gBACL,WAAW,CAAC,KACZ,oBACA,CAAC,mBACA,CAAC,mBAAmB,EAAE,aAAa;AACrC,cAAI,eAAe;AAClB,kBAAM,OAAO,OAAO,CAAC;AACrB,mBAAO,CAAC,IAAI;AAAA,cACX,GAAG;AAAA,cACH,YAAY,OACP,KAA4C,cAAc,KAAK,KACjE,EAAE;AAAA,YACN;AACA,iBAAK,IAAI,EAAE,EAAE;AACb,6BAAiB;AACjB;AAAA,UACD;AACA,eAAK,IAAI,EAAE,EAAE;AACb,iBAAO,KAAK,CAAC;AAAA,QACd;AACA,qBAAa,OAAO,KAAK;AACzB,qBAAa,IAAI,OAAO,MAAM;AAI9B,cAAM,WAAW,MAAM,cAAc,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK;AAC/D,cAAM,gBAAgB,WACnB,MAAM,cAAc,OAAO,CAAC,MAAM,EAAE,OAAO,KAAK,IAChD,MAAM,cAAc,IAAI,CAAC,MAAO,EAAE,OAAO,QAAQ,EAAE,GAAG,GAAG,IAAI,MAAM,IAAI,CAAE;AAe5E,cAAM,UAAU,CAAI,MAAsC;AACzD,cAAI,CAAC,EAAE,IAAI,KAAK,EAAG,QAAO;AAC1B,gBAAM,OAAO,IAAI,IAAI,CAAC;AACtB,gBAAM,UAAU,KAAK,IAAI,KAAK;AAC9B,eAAK,OAAO,KAAK;AAEjB,cAAI,CAAC,KAAK,IAAI,KAAK,EAAG,MAAK,IAAI,OAAO,OAAO;AAC7C,iBAAO;AAAA,QACR;AAEA,eAAO;AAAA,UACN,UAAU;AAAA,UACV;AAAA,UACA,aAAa,QAAQ,MAAM,WAAW;AAAA,UACtC,cAAc,QAAQ,MAAM,YAAY;AAAA,UACxC,eAAe,QAAQ,MAAM,aAAa;AAAA,UAC1C,sBACC,MAAM,yBAAyB,QAAQ,QAAQ,MAAM;AAAA,QACvD;AAAA,MACD,CAAC;AAAA,IACF;AAAA;AAAA,IAIA,UAAU,gBAAgB,UAAU;AACnC,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,WAAW;AACtC,aAAK,IAAI,gBAAgB,QAAQ;AACjC,eAAO,EAAE,aAAa,KAAK;AAAA,MAC5B,CAAC;AAAA,IACF;AAAA,IAEA,gBAAgB,gBAAgB,YAAY;AAG3C,oBAAc,cAAc;AAC5B,UAAI,YAAY;AACf,2BAAmB;AAAA,UAClB;AAAA,UACA,WAAW,MAAM;AAChB,+BAAmB,OAAO,cAAc;AACxC,gBAAI,EAAE,gBAAgB,gBAAgB,KAAK;AAC3C,gBAAI,EAAE,UAAU,gBAAgB,KAAK;AAAA,UACtC,GAAG,mBAAmB;AAAA,QACvB;AAAA,MACD;AACA,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,YAAY;AACvC,aAAK,IAAI,gBAAgB,UAAU;AACnC,eAAO,EAAE,cAAc,KAAK;AAAA,MAC7B,CAAC;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkBA,kBAAkB,gBAAgB,OAAO,MAAM;AAQ9C,WAAK;AAGL,UAAI,IAAI,EAAE,aAAa,IAAI,cAAc,GAAG;AAC3C,YAAI,EAAE,gBAAgB,gBAAgB,IAAI;AAAA,MAC3C;AACA,UAAI,CAAC,UAAU;AACd,cAAM,OAAO,IAAI,IAAI,MAAM,aAAa;AACxC,cAAM,OAAO,KAAK,IAAI,cAAc,KAAK;AACzC,aAAK,IAAI,gBAAgB,OAAO,KAAK;AACrC,eAAO,EAAE,eAAe,KAAK;AAAA,MAC9B,CAAC;AAAA,IACF;AAAA,IAEA,YAAY,gBAAgB;AAC3B,UAAI,CAAC,UAAU;AACd,YAAI,CAAC,MAAM,cAAc,IAAI,cAAc,EAAG,QAAO,CAAC;AACtD,cAAM,OAAO,IAAI,IAAI,MAAM,aAAa;AACxC,aAAK,OAAO,cAAc;AAC1B,eAAO,EAAE,eAAe,KAAK;AAAA,MAC9B,CAAC;AAAA,IACF;AAAA;AAAA,IAIA,qBAAqB,SAAS;AAC7B,UAAI,CAAC,WAAW;AAAA,QACf,SAAS,MAAM,UAAU,EAAE,GAAG,MAAM,SAAS,QAAQ,IAAI,MAAM;AAAA,MAChE,EAAE;AAAA,IACH;AAAA;AAAA,IAIA,YAAY,gBAAgB;AAC3B,UAAI,CAAC,OAAO;AAAA,QACX,eAAe,EAAE,cAAc;AAAA,UAAI,CAAC,MACnC,EAAE,OAAO,iBAAiB,EAAE,GAAG,GAAG,aAAa,EAAE,IAAI;AAAA,QACtD;AAAA,MACD,EAAE;AAAA,IACH;AAAA;AAAA,IAIA,QAAQ,MAAM;AACb,UAAI,CAAC,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,iBAAiB,OAAO,OAAO,EAAE;AAAA,QACjC,sBAAsB,OAAO,CAAC,IAAI,EAAE;AAAA,MACrC,EAAE;AAAA,IACH;AAAA,IAEA,wBAAwB,OAAO;AAC9B,UAAI,EAAE,sBAAsB,MAAM,CAAC;AAAA,IACpC;AAAA,IAEA,aAAa,WAAW;AACvB,UAAI,EAAE,aAAa,UAAU,CAAC;AAAA,IAC/B;AAAA,IAEA,QAAQ,MAAM;AACb,UAAI,EAAE,KAAK,CAAC;AAAA,IACb;AAAA,IAEA,0BAA0B,MAAM;AAC/B,UAAI,EAAE,wBAAwB,KAAK,CAAC;AAAA,IACrC;AAAA,IAEA,iBAAiB;AAChB,UAAI,EAAE,iBAAiB,KAAK,CAAC;AAAA,IAC9B;AAAA;AAAA,IAIA,uBAAuB,SAAS;AAC/B,UAAI,CAAC,OAAO;AAAA,QACX,sBAAsB;AAAA,UACrB,GAAG,EAAE,qBAAqB,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ,KAAK;AAAA,UACjE;AAAA,QACD;AAAA,MACD,EAAE;AAAA,IACH;AAAA,IAEA,2BAA2B,MAAM;AAChC,UAAI,MAAM;AACT,YAAI,CAAC,OAAO;AAAA,UACX,sBAAsB,EAAE,qBAAqB,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,QAC3E,EAAE;AAAA,MACH,OAAO;AACN,YAAI,EAAE,sBAAsB,CAAC,EAAE,CAAC;AAAA,MACjC;AAAA,IACD;AAAA,IAEA,2BAA2B,OAAO;AACjC,UAAI,EAAE,yBAAyB,MAAM,CAAC;AAAA,IACvC;AAAA;AAAA,IAIA,gBAAgB,KAAK,MAAM;AAC1B,UAAI,EAAE,aAAa,IAAI,KAAK,EAAE,MAAM,IAAI,KAAK,IAAI,EAAE,CAAC;AAAA,IACrD;AAAA;AAAA,IAIA,oBAAoB,OAAO;AAC1B,YAAM,QAAQ,IAAI;AAElB,cAAQ,MAAM,MAAM;AAAA,QACnB,KAAK,YAAY,qBAAqB;AAErC,cAAI,MAAM,KAAK,eAAe,UAAU;AAWvC,kBAAM,kBACL,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,KAAK;AAChE,kBAAM,WAAW,MAAM,SAAS,IAAI,MAAM,cAAc;AACxD,kBAAM,SAAS,WAAW,CAAC,GAAG;AAC9B,kBAAM,iBAAiB,OAAO,WAAW,YAAY,OAAO,WAAW,eAAe;AACtF,gBAAI,mBAAmB,gBAAgB;AACtC,oBAAM,iBAAiB,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG;AAC3D,oBAAM,gBAAgB,CAAC,kBAAkB,MAAM,KAAK,aAAa;AACjE,kBAAI,eAAe;AAKlB,sBAAM,eAAe,MAAM,gBAAgB,QAAQ,MAAM,IAAI;AAC7D;AAAA,cACD;AAAA,YACD;AACA,kBAAM,WAAW,MAAM,gBAAgB,MAAM,IAAI;AAAA,UAClD;AAGA,cAAI,MAAM,KAAK,WAAW;AACzB,kBAAM,gBAAgB,MAAM,gBAAgB,KAAK;AACjD,kBAAM,UAAU,MAAM,gBAAgB,KAAK;AAI3C,kBAAM,YAAY,MAAM,cAAc;AAAA,UACvC;AAEA,cAAI,MAAM,KAAK,SAAS,aAAa,MAAM,KAAK,MAAM;AACrD,kBAAM,aAAa,CAAC,MAAM,KAAK;AAC/B,kBAAM,eAAe,IAAI;AACzB,kBAAM,gBACL,aAAa,UAAU,aAAa,yBAAyB,MAAM;AASpE,kBAAM,KAAK;AAAA,cACT,MAAM,KAA+C;AAAA,YACvD;AAEA,gBAAI,CAAC,OAAO;AAAA,cACX,eAAe,EAAE,cAAc;AAAA,gBAAI,CAAC,MACnC,EAAE,OAAO,MAAM,iBACZ;AAAA,kBACA,GAAG;AAAA,kBACH,iBAAiB,MAAM,KAAK;AAAA,kBAC5B,eAAe,MAAM,KAAK;AAAA;AAAA,kBAE1B,GAAI,cAAc,CAAC,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,IAAI,CAAC;AAAA,gBAC1E,IACC;AAAA,cACJ;AAAA;AAAA,cAEA,GAAI,cAAc,CAAC,aAAa,SAC7B;AAAA,gBACA,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAOhB,MAAM,KAAK,KAAM,MAAM,KAAK,QAAQ;AAAA,kBACpC,gBAAgB,MAAM;AAAA,kBACtB,WAAW,KAAK,IAAI;AAAA,kBACpB,YAAa,MAAM,KAAsC,YAAY;AAAA,kBACrE,aAAc,MAAM,KAAuC,aAAa;AAAA,kBACxE,GAAI,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;AAAA,gBAClC;AAAA,cACD,IACC,CAAC;AAAA,YACL,EAAE;AAAA,UACH;AACA;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,qBAAqB;AACrC,cAAI,CAAC,OAAO;AAAA,YACX,eAAe,EAAE,cAAc;AAAA,cAAI,CAAC,MACnC,EAAE,OAAO,MAAM,iBAAiB,EAAE,GAAG,GAAG,GAAG,MAAM,QAAQ,IAAI;AAAA,YAC9D;AAAA,UACD,EAAE;AACF;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,oBAAoB;AAEpC,cAAI,CAAC,MAAM,WAAW;AACrB,kBAAM,UAAU,MAAM,gBAAgB,MAAM,QAAQ;AAEpD,gBAAI,MAAM,UAAU;AACnB,yBAAW,MAAM;AAChB,sBAAM,UAAU,MAAM,gBAAgB,KAAK;AAAA,cAC5C,GAAG,GAAI;AAAA,YACR;AAAA,UACD;AACA;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,sBAAsB;AAEtC,gBAAM,gBAAgB,MAAM,gBAAgB,IAAI;AAChD,gBAAM,UAAU,MAAM,gBAAgB,IAAI;AAC1C;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,uBAAuB;AACvC,gBAAM,gBAAgB,MAAM,gBAAgB,KAAK;AACjD,gBAAM,UAAU,MAAM,gBAAgB,KAAK;AAK3C,gBAAM,YAAY,MAAM,cAAc;AACtC;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,eAAe;AAC/B,gBAAM,gBAAgB,MAAM,gBAAgB,KAAK;AACjD,gBAAM,UAAU,MAAM,gBAAgB,KAAK;AAC3C,gBAAM,kBAAkB,MAAM,gBAAgB,MAAM,OAAO,MAAM,IAAI;AACrE;AAAA,QACD;AAAA,QAEA,KAAK,YAAY,qBAAqB;AAMrC,gBAAM,OAAO,MAAM;AAQnB,gBAAM,iBAAiB,MAAM,cAAc,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE;AACvE,cAAI,eAAgB;AACpB,gBAAM,gBAAgB;AAAA,YACrB,IAAI,KAAK;AAAA,YACT,OAAO,KAAK;AAAA,YACZ,QAAQ,KAAK;AAAA,YACb,iBAAiB,KAAK,mBAAmB;AAAA,YACzC,eAAe,KAAK,iBAAiB;AAAA,YACrC,uBAAuB,KAAK,yBAAyB;AAAA,YACrD,uBAAuB;AAAA,YACvB,wBAAwB;AAAA,YACxB,cAAc;AAAA,YACd,eAAe;AAAA,YACf,aAAa;AAAA,UACd,CAAC;AACD;AAAA,QACD;AAAA,QAEA;AACC;AAAA,MACF;AAAA,IACD;AAAA,EACD,EAAE;AAKF,MAAI,OAAO,WAAW,aAAa;AAClC,QAAI,OAAO,MAAM,SAAS,EAAE;AAC5B,UAAM,UAAU,CAAC,MAAM;AACtB,UAAI,EAAE,oBAAoB,MAAM;AAC/B,eAAO,EAAE;AACT,uBAAe,EAAE,eAAe;AAAA,MACjC;AAAA,IACD,CAAC;AAAA,EACF;AAEA,SAAO;AACR;;;AGz9BO,SAAS,gBACf,SACyD;AACzD,QAAM,WAAW,CAAC,YAAoB,SAA6B;AAClE,UAAM,KAAM,QAA+C,OAAO;AAClE,QAAI,OAAO,OAAO,YAAY;AAC7B,aAAQ,GAAoC,GAAG,IAAI;AAAA,IACpD;AACA,YAAQ,KAAK,8BAA8B,OAAO,EAAE;AACpD,WAAO;AAAA,EACR;AACA,QAAM,WAAW,OAAO,OAAO,UAAU,OAAO;AAChD,QAAM,WAAW,OAAO;AACxB,SAAO,UAAU;AACjB,QAAM,QAAQ,UAAU;AACxB,MAAI,OAAO,QAAQ;AAClB,eAAW,SAAS,OAAO;AAC1B,UAAI;AACH,iBAAS,GAAI,KAAgC;AAAA,MAC9C,SAAS,KAAK;AACb,gBAAQ,MAAM,iCAAiC,GAAG;AAAA,MACnD;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAEO,SAAS,iBAAiB,MAYd;AAClB,QAAM,EAAE,OAAO,SAAS,UAAU,OAAO,IAAI;AAE7C,SAAO;AAAA,IACN,OAAO;AACN,YAAM,SAAS,EAAE,QAAQ,IAAI;AAC7B,YAAM,SAAS,EAAE,aAAa,KAAK;AAAA,IACpC;AAAA,IAEA,QAAQ;AACP,YAAM,SAAS,EAAE,QAAQ,KAAK;AAAA,IAC/B;AAAA,IAEA,SAAS;AACR,YAAM,IAAI,MAAM,SAAS;AACzB,UAAI,EAAE,aAAa;AAClB,UAAE,aAAa,KAAK;AACpB,UAAE,QAAQ,IAAI;AACd,gBAAQ,KAAK,MAAM;AAAA,MACpB,OAAO;AACN,UAAE,QAAQ,CAAC,EAAE,MAAM;AAAA,MACpB;AAAA,IACD;AAAA,IAEA,UAAU;AACT,YAAM,SAAS,EAAE,QAAQ,KAAK;AAC9B,YAAM,SAAS,EAAE,aAAa,IAAI;AAClC,cAAQ,KAAK,SAAS;AAAA,IACvB;AAAA,IAEA,OAAO;AACN,YAAM,SAAS,EAAE,aAAa,KAAK;AACnC,cAAQ,KAAK,MAAM;AAAA,IACpB;AAAA,IAEA,WAAW;AACV,YAAM,SAAS,EAAE,QAAQ,KAAK;AAC9B,YAAM,SAAS,EAAE,aAAa,KAAK;AACnC,qBAAe,MAAM;AACrB,UAAI,OAAO,aAAa,aAAa;AACpC,iBAAS,SAAS;AAAA,MACnB;AAAA,IACD;AAAA,IAEA;AAAA,IAEA,gBAAgB,SAAkB;AACjC,YAAM,IAAI,MAAM,SAAS;AACzB,QAAE,aAAa,KAAK;AACpB,QAAE,QAAQ,IAAI;AACd,QAAE,0BAA0B,WAAW,EAAE;AAAA,IAC1C;AAAA,IAEA,iBAAiB,IAAY;AAC5B,YAAM,IAAI,MAAM,SAAS;AACzB,QAAE,aAAa,KAAK;AACpB,QAAE,sBAAsB,EAAE;AAC1B,QAAE,QAAQ,IAAI;AAAA,IACf;AAAA,IAEA,IAAI,cAAc;AACjB,aAAO,MAAM,SAAS,EAAE,cAAc,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC;AAAA,IAChF;AAAA,IAEA,IAAI,SAAS;AACZ,aAAO,MAAM,SAAS,EAAE;AAAA,IACzB;AAAA,IAEA,GAAG,OAAO,IAAI;AACb,cAAQ,GAAG,OAAO,EAAE;AAAA,IACrB;AAAA,IAEA,IAAI,OAAO,IAAI;AACd,cAAQ,IAAI,OAAO,EAAE;AAAA,IACtB;AAAA,EACD;AACD;;;ACvFA,SAAS,WAAW,OAAwB;AAC3C,SAAO,oBAAoB,KAAK,KAAK;AACtC;AAOA,SAAS,QAAQ,KAAqB;AACrC,MAAI,CAAC,WAAW,GAAG,EAAG,QAAO;AAC7B,QAAM,IAAI,KAAK,IAAI,KAAK,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE;AACjE,QAAM,IAAI,KAAK,IAAI,KAAK,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE;AACjE,QAAM,IAAI,KAAK,IAAI,KAAK,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE;AACjE,QAAM,OAAO,CAAC,MAAc,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAC1D,SAAO,IAAI,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;AACvC;AAGA,SAAS,OAAO,MAAmB,MAAc,OAA2B;AAC3E,MAAI,SAAS,QAAQ,UAAU,GAAI;AACnC,OAAK,MAAM,YAAY,MAAM,KAAK;AACnC;AAQO,SAAS,WAAW,MAAmB,OAAgC;AAC7E,MAAI,CAAC,QAAQ,CAAC,MAAO;AAErB,MAAI,MAAM,cAAc;AACvB,WAAO,MAAM,gBAAgB,MAAM,YAAY;AAC/C,WAAO,MAAM,sBAAsB,QAAQ,MAAM,YAAY,CAAC;AAC9D,WAAO,MAAM,cAAc,MAAM,YAAY;AAAA,EAC9C;AACA,SAAO,MAAM,iBAAiB,MAAM,cAAc;AAClD,SAAO,MAAM,0BAA0B,MAAM,eAAe,MAAM,YAAY;AAC9E,SAAO,MAAM,4BAA4B,MAAM,mBAAmB,MAAM,cAAc;AACtF,SAAO,MAAM,WAAW,MAAM,eAAe;AAC7C,SAAO,MAAM,aAAa,MAAM,SAAS;AACzC,SAAO,MAAM,eAAe,MAAM,WAAW;AAC7C,SAAO,MAAM,eAAe,MAAM,MAAM;AACxC,SAAO,MAAM,aAAa,MAAM,UAAU;AAE1C,MAAI,MAAM,aAAa,eAAe;AACrC,WAAO,MAAM,uBAAuB,MAAM;AAC1C,WAAO,MAAM,sBAAsB,MAAM;AACzC,WAAO,MAAM,qBAAqB,MAAM;AACxC,WAAO,MAAM,oBAAoB,GAAG;AAAA,EACrC,WAAW,MAAM,aAAa,gBAAgB;AAC7C,SAAK,MAAM,eAAe,qBAAqB;AAC/C,SAAK,MAAM,eAAe,oBAAoB;AAC9C,SAAK,MAAM,eAAe,mBAAmB;AAC7C,SAAK,MAAM,eAAe,kBAAkB;AAAA,EAC7C;AAKA,MAAI,MAAM,UAAW,MAAK,QAAQ,cAAc,MAAM;AAMtD,MAAI,MAAM,gBAAgB,WAAW,MAAM,gBAAgB,QAAQ;AAClE,SAAK,QAAQ,QAAQ,MAAM;AAAA,EAC5B,WAAW,MAAM,gBAAgB,UAAU;AAC1C,WAAO,KAAK,QAAQ;AAAA,EACrB;AAEA,MAAI,MAAM,cAAc;AACvB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,YAAY,GAAG;AAC9D,UAAI,IAAI,WAAW,IAAI,EAAG,MAAK,MAAM,YAAY,KAAK,KAAK;AAAA,IAC5D;AAAA,EACD;AACD;;;ACpKO,IAAM,qBAAN,MAAyB;AAAA,EACvB,YAAY,oBAAI,IAA2B;AAAA,EAEnD,GAA8B,OAAU,IAAqC;AAC5E,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,EAAG,MAAK,UAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AACnE,SAAK,UAAU,IAAI,KAAK,EAAG,IAAI,EAAc;AAAA,EAC9C;AAAA,EAEA,IAA+B,OAAU,IAAqC;AAC7E,SAAK,UAAU,IAAI,KAAK,GAAG,OAAO,EAAc;AAAA,EACjD;AAAA,EAEA,KACC,UACG,MACI;AACP,UAAM,OAAO,KAAK,CAAC;AACnB,SAAK,UAAU,IAAI,KAAK,GAAG,QAAQ,CAAC,OAAO;AAC1C,UAAI;AACH,WAAG,IAAI;AAAA,MACR,SAAS,KAAK;AACb,gBAAQ,MAAM,kCAAkC,KAAK,MAAM,GAAG;AAAA,MAC/D;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAEA,YAAkB;AACjB,SAAK,UAAU,MAAM;AAAA,EACtB;AACD;;;ACyBO,IAAM,0BAA0B;AAChC,IAAM,4BAA4B;AAElC,SAAS,kBAAkB,MAAoC;AACrE,QAAM,WAAW,KAAK,YAAY;AAClC,QAAM,YAAY,KAAK,aAAa;AACpC,QAAM,WAAW,KAAK,eAAe,CAAC,IAAI,OAAO,WAAW,IAAI,EAAE;AAClE,QAAM,SAAS,KAAK,iBAAiB,CAAC,MAAM,aAAa,CAAkC;AAE3F,MAAI,UAA2D;AAC/D,MAAI,eAAmC;AAEvC,MAAI,qBAAoC;AACxC,MAAI,gBAAyB;AAC7B,MAAI,cAAuB;AAC3B,MAAI,UAAU;AAEd,QAAM,cAAc,MAAM;AACzB,QAAI,kBAAkB,KAAM,QAAO,aAAa;AAChD,QAAI,gBAAgB,KAAM,QAAO,WAAW;AAC5C,oBAAgB;AAChB,kBAAc;AAAA,EACf;AAEA,QAAM,OAAO,CAAC,SAAsB;AACnC,QAAI,gBAAgB,aAAa,QAAQ,KAAK,OAAO,aAAa,UAAU,KAAK,MAAO;AACxF,mBAAe;AACf,SAAK,OAAO,IAAI;AAAA,EACjB;AAEA,QAAM,SAAS,CAAC,WAAiC;AAChD,QAAI,WAAW,CAAC,QAAS;AACzB,UAAM,QAAQ,KAAK,SAAS;AAG5B,QAAI,WAAW,WAAW,UAAU,QAAQ,gBAAiB;AAE7D,UAAM,EAAE,KAAK,gBAAgB,IAAI;AACjC,cAAU;AACV,gBAAY;AACZ,SAAK,EAAE,KAAK,MAAM,CAAC;AAInB,yBAAqB,WAAW,cAAc,UAAU,kBAAkB,MAAM;AAAA,EACjF;AAEA,QAAM,gBAAgB,MAAM;AAC3B,QAAI,QAAS;AACb,QAAI,SAAS;AACZ,UAAI,gBAAgB,KAAM,QAAO,WAAW;AAC5C,oBAAc,SAAS,MAAM;AAC5B,sBAAc;AACd,eAAO,OAAO;AAAA,MACf,GAAG,QAAQ;AACX;AAAA,IACD;AACA,QAAI,uBAAuB,QAAQ,KAAK,OAAO,MAAM,oBAAoB;AACxE,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,gBAAgB,UAAU,aAAa,OAAO;AACjD,6BAAqB;AACrB,aAAK,EAAE,KAAK,aAAa,KAAK,MAAM,CAAC;AAAA,MACtC;AAAA,IACD;AAAA,EACD;AAEA,QAAM,YAAY,KAAK,aAAa,aAAa;AAEjD,SAAO;AAAA,IACN,WAAW;AACV,UAAI,QAAS;AACb,YAAM,MAAM,KAAK,OAAO;AAGxB,UAAI,SAAS,QAAQ,IAAK;AAC1B,kBAAY;AACZ,2BAAqB;AACrB,gBAAU,EAAE,KAAK,iBAAiB,KAAK,SAAS,EAAE;AAClD,sBAAgB,SAAS,MAAM;AAC9B,wBAAgB;AAChB,eAAO,UAAU;AAAA,MAClB,GAAG,SAAS;AAAA,IACb;AAAA,IACA,OAAO;AACN,gBAAU;AACV,kBAAY;AACZ,gBAAU;AACV,gBAAU;AAAA,IACX;AAAA,EACD;AACD;;;AC3IA;AAAA,EAEC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAwB,gBAAgB;AA6lBhC;AA1jBR,IAAM,gBAAgB,cAAyC,IAAI;AAE5D,SAAS,mBAAuC;AACtD,QAAM,MAAM,WAAW,aAAa;AACpC,MAAI,CAAC,KAAK;AACT,UAAM,IAAI,MAAM,wDAAwD;AAAA,EACzE;AACA,SAAO;AACR;AAGO,SAAS,eAAkB,UAAwC;AACzE,QAAM,EAAE,MAAM,IAAI,iBAAiB;AACnC,SAAO,SAAS,OAAO,QAAQ;AAChC;AAGO,SAAS,cAAc;AAC7B,QAAM,EAAE,SAAS,IAAI,iBAAiB;AACtC,SAAO;AACR;AAOO,SAAS,kBAAgC;AAC/C,QAAM,EAAE,OAAO,IAAI,iBAAiB;AACpC,SAAO;AACR;AAoCO,SAAS,gBAAgB;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;AACD,GAAyB;AACxB,QAAM,UAAU,OAON,IAAI;AACd,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAS,KAAK;AAChE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,KAAK;AAC1D,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAS,CAAC;AAc1D,QAAM,kBAAkB,OAA2B,MAAM;AACzD,QAAM,kBAAkB,YAAY,MAAM,gBAAgB,SAAS,CAAC,CAAC;AAErE,MAAI,CAAC,QAAQ,SAAS;AACrB,UAAM,iBAAiB,UAAU,YAAY;AAE7C,UAAMC,UAAS,mBAAmB;AAAA,MACjC,QAAQ;AAAA,MACR;AAAA,IACD,CAAC;AAED,UAAMC,SAAQ,kBAAkB;AAChC,UAAMC,WAAU,IAAI,mBAAmB;AAEvC,UAAMC,MAAK,IAAI,iBAAiB;AAAA,MAC/B,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW;AAAA,MACX;AAAA,IACD,CAAC;AAED,UAAMC,YAAW,OAAO,SAAuB;AAC9C,UAAI;AACH,cAAM,SAAS,MAAMJ,QAAO,OAAO,SAAS,OAAO,IAAI;AACvD,YAAI,OAAO,SAAS;AACnB,UAAAC,OAAM,SAAS,EAAE,qBAAqB;AAAA,YACrC,IAAI,OAAO,QAAQ;AAAA,YACnB,MAAM,OAAO,QAAQ,QAAQ;AAAA,YAC7B,OAAO,OAAO,QAAQ,SAAS;AAAA,UAChC,CAAC;AAAA,QACF;AACA,cAAM,aAAa,KAAK,UAAU;AAClC,YAAI,OAAO,eAAe,YAAY,WAAW,SAAS,GAAG;AAC5D,oBAAU,UAAU;AAIpB,0BAAgB,UAAU;AAAA,QAC3B;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,8BAA8B,GAAG;AAAA,MAChD;AAAA,IACD;AAEA,UAAMI,OAAM,iBAAiB,EAAE,OAAAJ,QAAO,SAAAC,UAAS,UAAAE,WAAU,OAAO,CAAC;AAOjE,YAAQ,UAAU,EAAE,QAAAJ,SAAQ,OAAAC,QAAO,IAAAE,KAAI,UAAAC,WAAU,KAAAC,MAAK,SAAAH,SAAQ;AAAA,EAC/D;AAEA,QAAM,EAAE,QAAQ,OAAO,IAAI,UAAU,KAAK,QAAQ,IAAI,QAAQ;AAE9D,QAAM,iBAAiB,YAAY,MAAM;AACxC,yBAAqB,KAAK;AAC1B,wBAAoB,CAAC,MAAM,IAAI,CAAC;AAAA,EACjC,GAAG,CAAC,CAAC;AAGL,YAAU,MAAM;AACf,QAAI,YAAY;AAEhB,mBAAe,YAAY;AAC1B,UAAI;AACH,cAAM,OAAO,MAAM,OAAO,OAAO,UAAU,MAAM;AACjD,YAAI,UAAW;AAKf,cAAM,iBACL,UAAW,KAA4C,kBAAkB;AAC1E,cAAM,SAAS;AAAA,UACd,QAAQ;AAAA,UACR,SAAU,KAAK,aAAiD,eAAe;AAAA,QAChF,CAAC;AAED,cAAM,SAAS,EAAE,SAAS,KAAK,SAAS,KAAK,SAAS,KAAK,WAAW;AACtE,6BAAqB,KAAK;AAU1B,YAAI,KAAK,SAAS,IAAI;AACrB,wBAAc,QAAQ,KAAK,QAAQ,YAAY,KAAK,QAAQ,EAAE;AAAA,QAC/D;AAEA,cAAM,WAAW,MAAM,OAAO,OAAO,kBAAkB,MAAM;AAC7D,YAAI,UAAW;AAEf,cAAM,kBAAkB,CAAC,OAUlB;AAAA,UACN,IAAI,EAAE;AAAA,UACN,OAAO,EAAE;AAAA,UACT,QAAQ,EAAE;AAAA,UACV,iBAAiB,EAAE;AAAA,UACnB,eAAe,EAAE;AAAA,UACjB,uBAAuB,EAAE;AAAA,UACzB,uBAAuB,EAAE;AAAA,UACzB,wBAAwB,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAY1B,aAAa,EAAE,eAAe;AAAA,QAC/B;AAEA,cAAM,SAAS,EAAE,iBAAiB,SAAS,cAAc,IAAI,eAAe,CAAC;AAO7E,YAAI,KAAK,SAAS,MAAM,KAAK,SAAS,IAAI;AACzC,aAAG,UAAU,EAAE,WAAW,KAAK,QAAQ,IAAI,WAAW,KAAK,QAAQ,GAAG,CAAC;AACvE,aAAG,QAAQ;AAAA,QACZ;AAEA,YAAI,SAAS,cAAc,WAAW,KAAK,CAAC,uBAAuB;AAClE,cAAI;AACH,kBAAM,YAAY,MAAM,OAAO,OAAO,eAAe,OAAO;AAC5D,gBAAI,aAAa,CAAC,UAAU,WAAW;AAAA,YAEvC,WAAW,UAAU,WAAW;AAI/B,uCAAyB,OAAO,UAAU,SAAS;AAAA,YACpD,WAAW,UAAU,gBAAgB;AAIpC,oBAAM,UAAS,oBAAI,KAAK,GAAE,YAAY;AACtC,oBAAM,SAAS,EAAE,gBAAgB;AAAA,gBAChC,IAAI,UAAU;AAAA,gBACd,OAAO;AAAA,gBACP,QAAQ;AAAA,gBACR,iBAAiB,UAAU,mBAAmB;AAAA,gBAC9C,eAAe,UAAU,iBAAiB;AAAA,gBAC1C,uBAAuB,UAAU,yBAAyB;AAAA,gBAC1D,uBAAuB;AAAA,gBACvB,wBAAwB;AAAA,gBACxB,cAAc;AAAA,gBACd,eAAe;AAAA,gBACf,aAAa;AAAA,cACd,CAAC;AACD,kBAAI,UAAU,mBAAmB,CAAC,MAAM,SAAS,EAAE,QAAQ;AAC1D,sBAAM,SAAS;AAAA,kBACd,iBAAiB;AAAA,oBAChB,MAAM,UAAU;AAAA,oBAChB,gBAAgB,UAAU;AAAA,oBAC1B,WAAW,KAAK,IAAI;AAAA,kBACrB;AAAA,gBACD,CAAC;AAAA,cACF;AAAA,YACD;AAAA,UACD,QAAQ;AAAA,UAER;AAAA,QACD;AAKA,qBAAa,SAAS;AAEtB,YAAI,yBAAyB,CAAC,WAAW;AACxC,cAAI,eAAe;AAClB,gBAAI;AACH,oBAAM,WAAW,MAAM,OAAO,OAAO,eAAe,OAAO,EAAE,OAAO,cAAc,CAAC;AACnF,kBAAI,CAAC,aAAa,UAAU,aAAa,SAAS,cAAc,KAAK,SAAS,IAAI;AAGjF,8BAAc,QAAQ,SAAS,mBAAmB,SAAS,SAAS;AACpE,sBAAM,YAAY,MAAM,OAAO,OAAO,UAAU,MAAM;AACtD,oBAAI,CAAC,WAAW;AACf,wBACE,SAAS,EACT,SAAS,UAAU,SAAS,UAAU,SAAS,UAAU,WAAW;AACtE,wBAAM,aAAa,MAAM,OAAO,OAAO,kBAAkB,MAAM;AAC/D,sBAAI,CAAC,WAAW;AACf,0BACE,SAAS,EACT,iBAAiB,WAAW,cAAc,IAAI,eAAe,CAAC;AAAA,kBACjE;AAAA,gBACD;AAAA,cACD;AAAA,YACD,QAAQ;AAAA,YAER;AAAA,UACD;AACA,cAAI,CAAC,WAAW;AACf,kBAAM,SAAS,EAAE,sBAAsB,qBAAqB;AAC5D,kBAAM,SAAS,EAAE,QAAQ,IAAI;AAAA,UAC9B;AAAA,QACD;AAEA,gBAAQ,KAAK,OAAO;AACpB,kBAAU,QAAQ,QAAS,GAAG;AAAA,MAC/B,SAAS,KAAK;AACb,gBAAQ,MAAM,+BAA+B,GAAG;AAChD,YAAI,CAAC,WAAW;AACf,gBAAM,SAAS,EAAE,cAAc,KAAK;AACpC,+BAAqB,IAAI;AAAA,QAC1B;AAAA,MACD;AAAA,IACD;AAYA,UAAM,cACL,OAAO,WAAW,cACf,OACA,kBAAkB;AAAA,MAClB,QAAQ,MAAM,OAAO,SAAS;AAAA,MAC9B,UAAU,MAAM,SAAS,SAAS,OAAO,SAAS;AAAA,MAClD,cAAc,CAAC,aAAa;AAC3B,YAAI,OAAO,qBAAqB,YAAa,QAAO,MAAM;AAAA,QAAC;AAI3D,cAAM,WAAW,IAAI,iBAAiB,QAAQ;AAC9C,iBAAS,QAAQ,SAAS,QAAQ,SAAS,iBAAiB;AAAA,UAC3D,SAAS;AAAA,UACT,WAAW;AAAA,UACX,eAAe;AAAA,QAChB,CAAC;AACD,eAAO,MAAM,SAAS,WAAW;AAAA,MAClC;AAAA,MACA,QAAQ,CAAC,SAAS;AACjB,eAAO,OAAO,WAAW,OAAO,IAAI,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MACrD;AAAA,IACD,CAAC;AACJ,UAAM,aAAa,MAAM;AACxB,mBAAa,SAAS;AAAA,IACvB;AAEA,cAAU;AAEV,UAAM,WAAW,OAAO,QAAQ,UAAU,KAAK,OAAO,OAAO;AAC7D,UAAM,cAAc,OAAO,QAAQ,aAAa,KAAK,OAAO,OAAO;AACnE,WAAO,QAAQ,YAAY,SAAS,eAAe,MAAM;AACxD,eAAS,GAAG,IAAI;AAChB,iBAAW;AAAA,IACZ;AACA,WAAO,QAAQ,eAAe,SAAS,kBAAkB,MAAM;AAC9D,kBAAY,GAAG,IAAI;AACnB,iBAAW;AAAA,IACZ;AACA,WAAO,iBAAiB,YAAY,UAAU;AAI9C,QAAI,gBAAsD;AAC1D,UAAM,mBAAmB,CAAC,mBAA2B;AACpD,UAAI,cAAe,cAAa,aAAa;AAC7C,sBAAgB,WAAW,MAAM;AAChC,eAAO,OAAO,SAAS,OAAO,EAAE,eAAe,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAChE,cAAM,SAAS,EAAE,YAAY,cAAc;AAAA,MAC5C,GAAG,GAAG;AAAA,IACP;AAEA,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AACnC,YAAM,SAAS,EAAE,oBAAoB,KAAK;AAE1C,UAAI,MAAM,SAAS,uBAAuB;AACzC,cAAM,OAAO,MAAM;AACnB,cAAM,mBAAmB,MAAM,eAAe,YAAY,CAAC,KAAK;AAGhE,YAAI,oBAAoB,MAAM,MAAM;AACnC,kBAAQ,KAAK,mBAAmB;AAAA,YAC/B,gBAAgB,MAAM;AAAA,YACtB,MAAM,KAAK;AAAA,YACX,YAAY,eAAe,QAAQ,KAAK,YAAY,OAAO;AAAA,UAC5D,CAAC;AAAA,QACF;AAEA,YAAI,CAAC,iBAAkB;AACvB,cAAM,IAAI,MAAM,SAAS;AACzB,cAAM,YAAY,EAAE,UAAU,EAAE,yBAAyB,MAAM;AAC/D,YAAI,UAAW,kBAAiB,MAAM,cAAc;AAAA,MACrD;AAAA,IACD,CAAC;AAcD,UAAM,gBAAgB;AACtB,QAAI,YAA2B;AAC/B,UAAM,UAAU,YAAY,MAAM;AACjC,UAAI,GAAG,aAAa;AACnB,oBAAY;AACZ,0BAAkB,KAAK;AACvB;AAAA,MACD;AACA,UAAI,cAAc,KAAM,aAAY,KAAK,IAAI;AAC7C,wBAAkB,KAAK,IAAI,IAAI,aAAa,aAAa;AAAA,IAC1D,GAAG,GAAI;AAEP,WAAO,MAAM;AACZ,kBAAY;AACZ,YAAM;AACN,oBAAc,OAAO;AACrB,UAAI,cAAe,cAAa,aAAa;AAC7C,mBAAa,KAAK;AAClB,aAAO,QAAQ,YAAY;AAC3B,aAAO,QAAQ,eAAe;AAC9B,aAAO,oBAAoB,YAAY,UAAU;AACjD,SAAG,WAAW;AAAA,IACf;AAAA,EACD,GAAG,CAAC,QAAQ,OAAO,IAAI,gBAAgB,CAAC;AAGxC,YAAU,MAAM;AACf,QAAI,UAAU,MAAM;AACnB,gBAAU,MAAM;AAChB,sBAAgB,UAAU;AAAA,IAC3B;AAAA,EACD,GAAG,CAAC,MAAM,CAAC;AAGX,YAAU,MAAM;AACf,UAAM,QAAQ,MAAM,UAAU,CAAC,OAAO,SAAS;AAC9C,UAAI,MAAM,UAAU,CAAC,KAAK,QAAQ;AACjC,gBAAQ,KAAK,MAAM;AACnB,iBAAS;AAAA,MACV;AACA,UAAI,CAAC,MAAM,UAAU,KAAK,QAAQ;AACjC,gBAAQ,KAAK,OAAO;AACpB,kBAAU;AAAA,MACX;AACA,YAAM,aAAa,KAAK,cAAc,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,aAAa,CAAC;AAC3E,YAAM,aAAa,MAAM,cAAc,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,aAAa,CAAC;AAC5E,UAAI,eAAe,YAAY;AAC9B,gBAAQ,KAAK,gBAAgB,UAAU;AACvC,yBAAiB,UAAU;AAAA,MAC5B;AAAA,IACD,CAAC;AACD,WAAO;AAAA,EACR,GAAG,CAAC,OAAO,SAAS,QAAQ,SAAS,cAAc,CAAC;AAGpD,YAAU,MAAM;AACf,QAAI,CAAC,uBAAwB;AAC7B,UAAM,UAAU,CAAC,MAAa;AAC7B,QAAE,eAAe;AACjB,UAAI,OAAO;AAAA,IACZ;AAEA,UAAM,SAAS,MAAM;AACpB,YAAMI,MAAK,SAAS,cAAc,sBAAsB;AACxD,UAAIA,KAAI;AACP,QAAAA,IAAG,iBAAiB,SAAS,OAAO;AACpC,eAAOA;AAAA,MACR;AACA,aAAO;AAAA,IACR;AAEA,QAAI,KAAK,OAAO;AAChB,QAAI,WAAoC;AAExC,QAAI,CAAC,IAAI;AACR,iBAAW,IAAI,iBAAiB,MAAM;AACrC,aAAK,OAAO;AACZ,YAAI,GAAI,WAAU,WAAW;AAAA,MAC9B,CAAC;AACD,eAAS,QAAQ,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS,KAAK,CAAC;AAAA,IACnE;AAEA,WAAO,MAAM;AACZ,UAAI,oBAAoB,SAAS,OAAO;AACxC,gBAAU,WAAW;AAAA,IACtB;AAAA,EACD,GAAG,CAAC,wBAAwB,GAAG,CAAC;AAmBhC,YAAU,MAAM;AACf,QAAI,CAAC,SAAS,OAAO,aAAa,YAAa;AAC/C,UAAM,SACJ,SAAS,eAAe,gBAAgB,KAA4B,SAAS;AAC/E,eAAW,QAAQ,KAAK;AAAA,EACzB,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM;AACf,QAAI,OAAO,WAAW,YAAa;AACnC,UAAM,WAAW,gBAAgB,GAAG;AACpC,WAAO,MAAM;AACZ,UAAI,OAAO,YAAY,UAAU;AAChC,eAAO,UAAU;AAAA,MAClB;AACA,cAAQ,UAAU;AAAA,IACnB;AAAA,EACD,GAAG,CAAC,KAAK,OAAO,CAAC;AAEjB,QAAM,WAA+B;AAAA,IACpC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAEA,SAAO,oBAAC,cAAc,UAAd,EAAuB,OAAO,UAAW,UAAS;AAC3D;AA2BO,IAAM,wBAAwB;AAarC,SAAS,yBACR,OACA,SACC;AACD,QAAM,UAAU,GAAG,qBAAqB,GAAG,QAAQ,UAAU;AAC7D,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,cAAc,QAAQ,SAAS,QAAQ,SAAS,SAAS,CAAC;AAChE,QAAM,cAAc,aAAa,QAAQ;AAKzC,QAAM,QAAQ,QAAQ,SAAS,IAAI,CAAC,GAAG,OAAO;AAAA,IAC7C,IAAI,GAAG,OAAO,QAAQ,EAAE,MAAM;AAAA,IAC9B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,MAAM,EAAE;AAAA,IACR,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW,IAAI,KAAK,OAAO,QAAQ,SAAS,SAAS,KAAK,GAAG,EAAE,YAAY;AAAA,IAC3E,UAAU;AAAA,IACV,WAAW;AAAA,EACZ,EAAE;AAEF,MAAI,QAAQ,cAAc;AACzB,UAAM,aACL,QAAQ,aAAa,UACrB,QAAQ,aAAa,QAAQ,IAAI,CAAC,MAAM,UAAK,EAAE,KAAK,EAAE,EAAE,KAAK,IAAI;AAClE,UAAM,KAAK;AAAA,MACV,IAAI,GAAG,OAAO,OAAO,QAAQ,aAAa,MAAM;AAAA,MAChD,gBAAgB;AAAA,MAChB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW;AAAA,MACX,WAAW,IAAI,KAAK,GAAG,EAAE,YAAY;AAAA,MACrC,UAAU;AAAA,MACV,WAAW;AAAA,MACX,UAAU;AAAA,QACT,MAAM;AAAA,QACN,QAAQ,QAAQ,aAAa,UAAU;AAAA,QACvC,SAAS,QAAQ,aAAa,QAAQ,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,MAAM,EAAE;AAAA,QAC/E,QAAQ,QAAQ,aAAa;AAAA,MAC9B;AAAA;AAAA,IAED,CAAQ;AAAA,EACT;AAEA,QAAM,IAAI,MAAM,SAAS;AACzB,IAAE,gBAAgB;AAAA,IACjB,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,eAAe,IAAI,KAAK,GAAG,EAAE,YAAY;AAAA,IACzC,uBAAuB;AAAA,IACvB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,aAAa,MAAM;AAAA,EACpB,CAAC;AAED,IAAE,YAAY,SAAS,KAAY;AAEnC,MAAI,CAAC,EAAE,UAAU,aAAa;AAC7B,UAAM,SAAS;AAAA,MACd,iBAAiB;AAAA,QAChB,MAAM;AAAA,QACN,gBAAgB;AAAA,QAChB,WAAW;AAAA,QACX,UAAU,QAAQ,SAAS,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE;AAAA,QACxD,GAAI,QAAQ,eACT;AAAA,UACA,cAAc;AAAA,YACb,QAAQ,QAAQ,aAAa;AAAA,YAC7B,QAAQ,QAAQ,aAAa,UAAU;AAAA,YACvC,SAAS,QAAQ,aAAa,QAAQ,IAAI,CAAC,OAAO;AAAA,cACjD,IAAI,EAAE;AAAA,cACN,OAAO,EAAE;AAAA,YACV,EAAE;AAAA,UACH;AAAA,QACD,IACC,CAAC;AAAA,MACL;AAAA,IACD,CAAC;AAAA,EACF;AACD;AAEA,SAAS,cAAsB;AAC9B,MAAI,OAAO,aAAa,aAAa;AACpC,UAAM,SAAS,SAAS,cAAc,uBAAuB;AAC7D,QAAI,QAAQ;AACX,YAAM,MAAM,OAAO,aAAa,KAAK;AACrC,UAAI,KAAK;AACR,YAAI;AACH,gBAAM,MAAM,IAAI,IAAI,GAAG;AACvB,iBAAO,GAAG,IAAI,QAAQ,KAAK,IAAI,IAAI;AAAA,QACpC,QAAQ;AAAA,QAER;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;;;ACrwBA,SAAS,eAAAC,eAAa,aAAAC,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;;;ACRzD,SAAS,eAAAC,cAAa,aAAAC,YAAW,SAAS,UAAAC,eAAc;AAiBxD,SAAS,WAAW,WAAmB,WAA2B;AACjE,SAAO,WAAW,SAAS,IAAI,SAAS;AACzC;AAEA,SAAS,WAAW,WAAmB,WAA4B;AAClE,MAAI;AACH,WAAO,aAAa,QAAQ,WAAW,WAAW,SAAS,CAAC,MAAM;AAAA,EACnE,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,aAAa,WAAmB,WAAgC;AACxE,MAAI;AACH,UAAM,MAAM,aAAa,QAAQ,WAAW,WAAW,SAAS,CAAC;AACjE,QAAI,CAAC,IAAK,QAAO,oBAAI,IAAI;AACzB,WAAO,IAAI,IAAI,KAAK,MAAM,GAAG,CAAa;AAAA,EAC3C,QAAQ;AACP,WAAO,oBAAI,IAAI;AAAA,EAChB;AACD;AAEA,SAAS,YAAY,WAAmB,WAAmB,MAAoB;AAC9E,MAAI;AACH,UAAM,OAAO,aAAa,WAAW,SAAS;AAC9C,SAAK,IAAI,IAAI;AACb,iBAAa,QAAQ,WAAW,WAAW,SAAS,GAAG,KAAK,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,EACjF,QAAQ;AAAA,EAER;AACD;AAEA,SAAS,aAAa,WAAmB,WAAmB,OAAuB;AAClF,MAAI;AACH,UAAM,OAAO,aAAa,WAAW,SAAS;AAC9C,eAAW,KAAK,MAAO,MAAK,IAAI,CAAC;AACjC,iBAAa,QAAQ,WAAW,WAAW,SAAS,GAAG,KAAK,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,EACjF,QAAQ;AAAA,EAER;AACD;AAEA,SAAS,aAAa,SAA8B,MAAwC;AAC3F,SAAO,QAAQ,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,IAAI,CAAC;AAC/C;AAEA,IAAM,aAAiC,CAAC;AAYjC,SAAS,mBAAmB;AAClC,QAAM,EAAE,QAAQ,MAAM,IAAI,iBAAiB;AAC3C,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,OAAO;AAC/C,QAAM,YAAY,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK;AAC1D,QAAM,YAAY,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK;AAC1D,QAAM,cAAc,eAAe,CAAC,MAAM,CAAC,EAAE,SAAS,OAAO;AAC7D,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,aAAa,WAAW,KAAK;AACzE,QAAM,mBAAmB;AAAA,IACxB,MAAM,YAAY,OAAO,CAACC,OAAMA,GAAE,eAAe;AAAA,IACjD,CAAC,WAAW;AAAA,EACb;AACA,QAAM,aAAaC,QAAO,KAAK;AAE/B,EAAAC,WAAU,MAAM;AACf,QAAI,CAAC,WAAW,CAAC,aAAa,CAAC,aAAa,iBAAiB,WAAW,EAAG;AAC3E,QAAI,WAAW,QAAS;AACxB,eAAW,UAAU;AAErB,UAAM,eAAe,CAAC,WAAW,WAAW,SAAS;AACrD,QAAI,UAAU,iBAAiB;AAC/B,QAAI,cAAc;AAClB,UAAM,WAAqB,CAAC;AAE5B,aAAS,UAAU,SAA8B,KAAuB;AACvE,eAAS,KAAK,GAAG,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAI3C,UAAI,EAAE,gBAAgB,CAAC,gBAAgB,QAAQ,SAAS,GAAG;AAC1D,cAAM,OAAO,aAAa,WAAY,SAAU;AAChD,cAAM,SAAS,aAAa,SAAS,IAAI;AACzC,uBAAe,OAAO;AAEtB,cAAM,SAAS,OAAO,CAAC;AACvB,YAAI,UAAU,CAAC,MAAM,SAAS,EAAE,QAAQ;AACvC,gBAAM,aAAa,IAAI,SAAS;AAChC,gBAAM,SAAS,EAAE,uBAAuB;AAAA,YACvC,OAAO,OAAO;AAAA,YACd,MAAM,OAAO;AAAA,YACb,MAAM,OAAO;AAAA,YACb,OAAO,IAAI;AAAA,YACX,OAAO,aAAc,OAAO,aAAa,UAAU,KAAK,OAAQ;AAAA,UACjE,CAAC;AAAA,QACF;AAAA,MACD;AAEA;AACA,UAAI,YAAY,GAAG;AAClB,YAAI,gBAAgB,CAAC,aAAa;AAEjC,cAAI,SAAS,SAAS,GAAG;AACxB,yBAAa,WAAY,WAAY,QAAQ;AAAA,UAC9C;AACA,gBAAM,SAAS,EAAE,2BAA2B,CAAC;AAAA,QAC9C,OAAO;AACN,gBAAM,SAAS,EAAE,2BAA2B,WAAW;AAAA,QACxD;AAAA,MACD;AAAA,IACD;AAEA,eAAW,OAAO,kBAAkB;AACnC,YAAM,WAAW,iBAAiB,IAAI,EAAE,IAAI,UAAU,CAAC;AACvD,YAAM,SAAS,MAAM,SAAS,EAAE,aAAa,IAAI,QAAQ;AACzD,UAAI,UAAU,KAAK,IAAI,IAAI,OAAO,KAAK,mBAAmB;AACzD,kBAAU,OAAO,MAA6B,GAAG;AAAA,MAClD,OAAO;AACN,eAAO,OAAO,WACZ,MAAM,EAAE,OAAO,IAAI,IAAI,MAAM,GAAG,OAAO,GAAG,UAAU,UAAU,EAAE,CAAC,EACjE,KAAK,CAAC,WAA4C;AAClD,gBAAM,UAAU,OAAO,SAAS,CAAC;AACjC,gBAAM,SAAS,EAAE,gBAAgB,UAAU,OAAO;AAClD,oBAAU,SAAS,GAAG;AAAA,QACvB,CAAC,EACA,MAAM,MAAM;AACZ,oBAAU,CAAC,GAAG,GAAG;AAAA,QAClB,CAAC;AAAA,MACH;AAAA,IACD;AAAA,EACD,GAAG,CAAC,SAAS,WAAW,WAAW,aAAa,kBAAkB,QAAQ,KAAK,CAAC;AAEhF,QAAM,gBAAgBC;AAAA,IACrB,CAAC,SAAiB;AACjB,UAAI,CAAC,aAAa,CAAC,aAAa,iBAAiB,WAAW,EAAG;AAC/D,kBAAY,WAAW,WAAW,IAAI;AAGtC,YAAM,OAAO,aAAa,WAAW,SAAS;AAC9C,UAAI,QAAQ;AACZ,iBAAW,OAAO,kBAAkB;AACnC,cAAM,WAAW,iBAAiB,IAAI,EAAE,IAAI,UAAU,CAAC;AACvD,cAAM,SAAS,MAAM,SAAS,EAAE,aAAa,IAAI,QAAQ;AACzD,YAAI,QAAQ;AACX,mBAAS,aAAa,OAAO,MAA6B,IAAI,EAAE;AAAA,QACjE;AAAA,MACD;AACA,YAAM,SAAS,EAAE,2BAA2B,KAAK;AACjD,YAAM,SAAS,EAAE,2BAA2B,IAAI;AAAA,IACjD;AAAA,IACA,CAAC,WAAW,WAAW,kBAAkB,KAAK;AAAA,EAC/C;AAEA,QAAM,cAAcA,aAAY,MAAM;AACrC,QAAI,CAAC,aAAa,CAAC,aAAa,iBAAiB,WAAW,EAAG;AAC/D,eAAW,OAAO,kBAAkB;AACnC,YAAM,WAAW,iBAAiB,IAAI,EAAE,IAAI,UAAU,CAAC;AACvD,YAAM,SAAS,MAAM,SAAS,EAAE,aAAa,IAAI,QAAQ;AACzD,UAAI,QAAQ;AACX,cAAM,UAAU,OAAO;AACvB,qBAAa,WAAW,WAAW,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAAA,MAC9D;AAAA,IACD;AACA,UAAM,SAAS,EAAE,2BAA2B,CAAC;AAC7C,UAAM,SAAS,EAAE,2BAA2B;AAAA,EAC7C,GAAG,CAAC,WAAW,WAAW,kBAAkB,KAAK,CAAC;AAElD,QAAM,mBAAmBA,aAAY,MAAiC;AACrE,QAAI,iBAAiB,WAAW,KAAK,CAAC,aAAa,CAAC,UAAW,QAAO,CAAC;AACvE,UAAM,OAAO,aAAa,WAAW,SAAS;AAC9C,UAAM,SAAoC,CAAC;AAC3C,eAAW,OAAO,kBAAkB;AACnC,YAAM,WAAW,iBAAiB,IAAI,EAAE,IAAI,UAAU,CAAC;AACvD,YAAM,SAAS,MAAM,SAAS,EAAE,aAAa,IAAI,QAAQ;AACzD,UAAI,QAAQ;AACX,mBAAW,SAAS,aAAa,OAAO,MAA6B,IAAI,GAAG;AAC3E,iBAAO,KAAK,EAAE,GAAG,OAAO,OAAO,IAAI,GAAG,CAAC;AAAA,QACxC;AAAA,MACD;AAAA,IACD;AACA,WAAO;AAAA,EACR,GAAG,CAAC,kBAAkB,WAAW,WAAW,KAAK,CAAC;AAElD,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;;;AC3LO,SAAS,mBAA2B;AAC1C,SAAO,eAAe,CAAC,MAAM,mBAAmB,EAAE,aAAa,CAAC;AACjE;;;AC3BA,SAAS,eAAAC,cAAa,YAAAC,iBAAgB;AAUtC,SAAS,qBAAgE;AACxE,MAAI,OAAO,WAAW,YAAa,QAAO,CAAC;AAC3C,QAAM,MAAM,OAAO,SAAS;AAC5B,MAAI,CAAC,IAAK,QAAO,CAAC;AAClB,SAAO,EAAE,MAAM,EAAE,KAAK,OAAO,SAAS,SAAS,OAAO,SAAS,SAAS,EAAE;AAC3E;AAeA,IAAM,kBAAkB;AACxB,IAAM,gBAAgB,KAAK,OAAO;AAU3B,IAAM,iBAAiB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,EAAE,KAAK,GAAG;AAEH,SAAS,YAAY,qBAAoC;AAC/D,QAAM,EAAE,QAAQ,IAAI,OAAO,gBAAgB,IAAI,iBAAiB;AAGhE,QAAM,iBAAiB;AACvB,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAS,EAAE;AACnC,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAS,KAAK;AACtD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAA8B,CAAC,CAAC;AACtE,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAwB,IAAI;AAC9D,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAAwB,IAAI;AAE1E,QAAM,WAAWC;AAAA,IAChB,OAAO,UAAkB;AACxB,UAAI,CAAC,eAAgB;AAErB,YAAM,YAAY,kBAAkB,YAAY;AAChD,YAAM,QAAQ,MAAM,MAAM,GAAG,SAAS;AACtC,UAAI,MAAM,WAAW,EAAG;AAGxB,YAAM,UAA+B,MAAM,IAAI,CAAC,UAAU;AAAA,QACzD,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,QAC3D;AAAA,QACA,YAAY,KAAK,KAAK,WAAW,QAAQ,IAAI,IAAI,gBAAgB,IAAI,IAAI;AAAA,QACzE,aAAa;AAAA,QACb,OAAO;AAAA,QACP,MAAM;AAAA,MACP,EAAE;AAEF,qBAAe,CAAC,SAAS,CAAC,GAAG,MAAM,GAAG,OAAO,CAAC;AAG9C,iBAAW,QAAQ,SAAS;AAC3B,YAAI;AACH,cAAI,KAAK,KAAK,OAAO,eAAe;AACnC,kBAAM,IAAI,MAAM,EAAE,uBAAuB,CAAC;AAAA,UAC3C;AAGA,gBAAM,SAAS,MAAM,aAAa,KAAK,IAAI;AAM3C,gBAAM,kBAAkB,eAAe,WAAW,OAAO,IAAI,SAAY;AACzE,gBAAM,SAAS,MAAM,OAAO,OAAO,iBAAiB,OAAO;AAAA,YAC1D,GAAI,kBAAkB,EAAE,gBAAgB,gBAAgB,IAAI,CAAC;AAAA,YAC7D;AAAA,YACA,UAAU,KAAK,KAAK,QAAQ;AAAA,YAC5B,UAAU,KAAK,KAAK;AAAA,UACrB,CAAC;AAED;AAAA,YAAe,CAAC,SACf,KAAK;AAAA,cAAI,CAAC,MACT,EAAE,OAAO,KAAK,KAAK,EAAE,GAAG,GAAG,aAAa,OAAO,MAAM,OAAO,KAAK,IAAI;AAAA,YACtE;AAAA,UACD;AAAA,QACD,SAAS,KAAK;AACb,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD;AAAA,YAAe,CAAC,SACf,KAAK,IAAI,CAAC,MAAO,EAAE,OAAO,KAAK,KAAK,EAAE,GAAG,GAAG,aAAa,OAAO,OAAO,QAAQ,IAAI,CAAE;AAAA,UACtF;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAC,gBAAgB,YAAY,QAAQ,MAAM;AAAA,EAC5C;AAEA,QAAM,mBAAmBA,aAAY,CAAC,OAAe;AACpD,mBAAe,CAAC,SAAS;AACxB,YAAM,OAAO,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACzC,UAAI,MAAM,WAAY,KAAI,gBAAgB,KAAK,UAAU;AACzD,aAAO,KAAK,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAAA,IACtC,CAAC;AAAA,EACF,GAAG,CAAC,CAAC;AAUL,QAAM,SAASA;AAAA,IACd,OAAO,aAA0D;AAChE,YAAMC,kBAAiB,UAAU,kBAAkB;AACnD,YAAM,SAAS,UAAU,QAAQ;AACjC,YAAM,UAAU,OAAO,KAAK;AAC5B,YAAM,aAAa,YAAY,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAK;AAChF,YAAM,UAAU,QAAQ,SAAS;AACjC,YAAM,iBAAiB,WAAW,SAAS;AAE3C,UAAI,CAACA,mBAAkB,aAAc;AAOrC,UAAI,CAAC,SAAS;AACb,YAAI,gBAAgB;AACnB,uBAAa,EAAE,yBAAyB,CAAC;AACzC,qBAAW,MAAM,aAAa,IAAI,GAAG,GAAI;AAAA,QAC1C;AACA;AAAA,MACD;AAGA,YAAM,iBAAiB,YAAY,KAAK,CAAC,MAAM,EAAE,WAAW;AAC5D,UAAI,eAAgB;AAOpB,YAAM,eAAe,cAAc,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AACvF,YAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,YAAM,mBAAmB,MAAM,SAAS,EAAE,SAAS,MAAM;AACzD,YAAM,iBAA+B;AAAA,QACpC,IAAI;AAAA,QACJ,gBAAAA;AAAA,QACA,gBAAgB;AAAA,QAChB,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,MAAM,UAAU,UAAU;AAAA,QAC1B,OACC,WAAW,iBACP;AAAA,UACD,GAAI,UAAU,CAAC,EAAE,MAAM,QAAiB,MAAM,QAAQ,CAAC,IAAI,CAAC;AAAA,UAC5D,GAAG;AAAA,QACJ,IACC;AAAA,QACJ,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,QACX,UAAU;AAAA,QACV,WAAW;AAAA,MACZ;AAGA,YAAM,sBAAsB;AAC5B,YAAM,eAAe;AACrB,YAAM,SAAS,EAAE,WAAWA,iBAAgB,cAAc;AAkB1D,YAAM,SAAS,EAAE,gBAAgBA,iBAAgB,IAAI;AACrD,cAAQ,EAAE;AACV,qBAAe,CAAC,CAAC;AACjB,SAAG,WAAWA,iBAAgB,KAAK;AACnC,sBAAgB,IAAI;AACpB,UAAI;AAOH,cAAM,qBAAqBA,gBAAe,WAAW,OAAO;AAK5D,cAAM,0BAA0BA,gBAAe,WAAW,MAAM;AAChE,YAAI,yBAAyB;AAC5B,gBAAM,aAAaA,gBAAe,MAAM,OAAO,MAAM;AACrD,gBAAM,SAAS,MAAM,OAAO,OAAO,yBAAyB,OAAO;AAAA,YAClE;AAAA,YACA,GAAI,UAAU,EAAE,MAAM,QAAQ,IAAI,CAAC;AAAA,UACpC,CAAC;AAID,gBAAM,SAAS,EAAE,oBAAoBA,iBAAgB,OAAO,cAAc;AAO1E,cAAI;AACH,kBAAM,WAAW,MAAM,OAAO,OAAO,YAAY,MAAM;AAAA,cACtD,gBAAgB,OAAO;AAAA,cACvB,OAAO;AAAA,YACR,CAAC;AACD,gBAAI,UAAU,OAAO;AACpB,oBAAM,SAAS,EAAE,YAAY,OAAO,gBAAgB,SAAS,KAAuB;AAAA,YACrF;AAAA,UACD,QAAQ;AAAA,UAGR;AAAA,QACD,WAAW,oBAAoB;AAC9B,gBAAM,eAAe,gBAAgB;AACrC,gBAAM,SAAS,MAAM,OAAO,OAAO,mBAAmB,OAAO;AAAA,YAC5D,GAAI,UAAU,EAAE,MAAM,QAAQ,IAAI,CAAC;AAAA,YACnC,GAAI,iBAAiB,EAAE,OAAO,WAAW,IAAI,CAAC;AAAA;AAAA;AAAA,YAG9C,GAAG,mBAAmB;AAAA,YACtB,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,UACxC,CAAC;AACD,gBAAM,OAAO,OAAO;AAIpB,gBAAM,SAAS,EAAE,oBAAoBA,iBAAgB,KAAK,EAAE;AAC5D,cAAI,OAAO,MAAM;AAChB,kBAAM,SAAS,EAAE,eAAe,KAAK,IAAI,cAAc,OAAO,IAAoB;AAAA,UACnF;AACA,cAAI,OAAO,cAAc;AACxB,+BAAmB,KAAK,EAAE;AAAA,UAC3B;AAAA,QACD,OAAO;AACN,gBAAM,SAAS,MAAM,OAAO,OAAO,YAAY,OAAO;AAAA,YACrD,gBAAAA;AAAA,YACA,GAAI,UAAU,EAAE,MAAM,QAAQ,IAAI,CAAC;AAAA,YACnC,GAAI,iBAAiB,EAAE,OAAO,WAAW,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,YAK9C,GAAG,mBAAmB;AAAA,UACvB,CAAC;AAKD,gBACE,SAAS,EACT,eAAeA,iBAAgB,cAAc,OAAO,IAAoB;AAAA,QAC3E;AAGA,mBAAW,KAAK,qBAAqB;AACpC,cAAI,EAAE,WAAY,KAAI,gBAAgB,EAAE,UAAU;AAAA,QACnD;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,8BAA8B,GAAG;AAE/C,cAAM,SAAS,EAAE,cAAcA,iBAAgB,YAAY;AAE3D,cAAM,SAAS,EAAE,gBAAgBA,iBAAgB,KAAK;AACtD,gBAAQ,YAAY;AACpB,uBAAe,mBAAmB;AAClC,qBAAa,eAAe,QAAQ,IAAI,UAAU,EAAE,mBAAmB,CAAC;AAExE,mBAAW,MAAM,aAAa,IAAI,GAAG,GAAI;AAAA,MAC1C,UAAE;AACD,wBAAgB,KAAK;AAAA,MACtB;AAAA,IACD;AAAA,IACA,CAAC,MAAM,aAAa,qBAAqB,cAAc,QAAQ,IAAI,OAAO,eAAe;AAAA,EAC1F;AAEA,QAAM,iBAAiBD,aAAY,MAAM,aAAa,IAAI,GAAG,CAAC,CAAC;AAE/D,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;AAIA,SAAS,aAAa,MAA6B;AAClD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACvC,UAAM,SAAS,IAAI,WAAW;AAC9B,WAAO,SAAS,MAAM;AAErB,YAAM,SAAS,OAAO;AACtB,YAAM,SAAS,OAAO,MAAM,GAAG,EAAE,CAAC;AAClC,UAAI,CAAC,OAAQ,QAAO,OAAO,IAAI,MAAM,uBAAuB,CAAC;AAC7D,cAAQ,MAAM;AAAA,IACf;AACA,WAAO,UAAU,MAAM,OAAO,IAAI,MAAM,qBAAqB,CAAC;AAC9D,WAAO,cAAc,IAAI;AAAA,EAC1B,CAAC;AACF;;;AC1WA,SAAS,eAAAE,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAMlD,SAAS,mBAAmB;AAClC,QAAM,EAAE,QAAQ,OAAO,gBAAgB,IAAI,iBAAiB;AAC5D,QAAM,gBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa;AAC3D,QAAM,wBAAwB,eAAe,CAAC,MAAM,EAAE,qBAAqB;AAC3E,QAAM,CAAC,YAAY,aAAa,IAAIC,UAAS,KAAK;AAElD,QAAM,YAAYC,QAAO,MAAM;AAC/B,QAAM,WAAWA,QAAO,KAAK;AAC7B,QAAM,qBAAqBA,QAAO,eAAe;AAKjD,EAAAC,WAAU,MAAM;AACf,cAAU,UAAU;AACpB,aAAS,UAAU;AACnB,uBAAmB,UAAU;AAAA,EAC9B,CAAC;AAED,QAAM,SAASC,aAAY,OAAO,SAAiB;AAClD,kBAAc,IAAI;AAOlB,UAAM,qBAAqB,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AACvF,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,sBAAsB,cAAc,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC9F,UAAM,mBAAmB,SAAS,QAAQ,SAAS,EAAE,SAAS,MAAM;AAEpE,UAAM,gBAA8B;AAAA,MACnC,IAAI;AAAA,MACJ,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,MAChB,MAAM;AAAA,MACN,YAAY;AAAA,MACZ;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW;AAAA,MACX,WAAW;AAAA,MACX,UAAU;AAAA,MACV,WAAW;AAAA,IACZ;AAGA,UAAMC,SAAQ,SAAS,QAAQ,SAAS;AACxC,IAAAA,OAAM,gBAAgB;AAAA,MACrB,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,iBAAiB;AAAA,MACjB,eAAe;AAAA,MACf,uBAAuB;AAAA,MACvB,uBAAuB;AAAA,MACvB,wBAAwB;AAAA,MACxB,cAAc;AAAA,MACd,eAAe;AAAA,MACf,aAAa;AAAA,IACd,CAAC;AACD,IAAAA,OAAM,YAAY,oBAAoB,CAAC,aAAa,CAAC;AACrD,IAAAA,OAAM,sBAAsB,kBAAkB;AAE9C,QAAI;AACH,YAAM,eAAe,mBAAmB,QAAQ;AAChD,YAAM,SAAS,MAAM,UAAU,QAAQ,OAAO,mBAAmB,OAAO;AAAA,QACvE;AAAA,QACA,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,MACxC,CAAC;AACD,YAAM,OAAO,OAAO;AAKpB,eAAS,QAAQ,SAAS,EAAE,oBAAoB,oBAAoB,KAAK,EAAE;AAC3E,UAAI,OAAO,MAAM;AAChB,iBAAS,QACP,SAAS,EACT,eAAe,KAAK,IAAI,qBAAqB,OAAO,IAAoB;AAAA,MAC3E;AAOA,UAAI,OAAO,aAAa;AACvB,cAAM,UAAU,OAAO;AACvB,cAAM,WAAW,SAAS,QAAQ,SAAS,EAAE,SAAS,IAAI,KAAK,EAAE,KAAK,CAAC;AACvE,cAAM,iBAAiB,SAAS,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ,EAAE;AACjE,iBAAS,QAAQ,SAAS,EAAE,YAAY,KAAK,IAAI,CAAC,SAAS,GAAG,cAAc,CAAC;AAAA,MAC9E;AACA,aAAO;AAAA,IACR,SAAS,KAAK;AAEb,eAAS,QAAQ,SAAS,EAAE,cAAc,oBAAoB,mBAAmB;AACjF,YAAM,QAAQ,SAAS,QACrB,SAAS,EACT,cAAc,OAAO,CAAC,MAAM,EAAE,OAAO,kBAAkB;AACzD,eAAS,QAAQ,SAAS,EAAE,eAAe,OAAO,sBAAsB,KAAK,CAAC;AAC9E,YAAM;AAAA,IACP,UAAE;AACD,oBAAc,KAAK;AAAA,IACpB;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,eAAe,QAAQ,YAAY,sBAAsB;AACnE;;;AChGO,SAAS,qBAAqB,MAGnC;AACD,QAAM,aACL,MAAM,0BAA0B,UAAU,MAAM,wBAAwB,OAAO;AAChF,SAAO;AAAA,IACN,WAAW,MAAM,gBAAgB,YAAY,yBAAyB;AAAA,IACtE,YAAY,MAAM,iBAAiB,YAAY,0BAA0B;AAAA,EAC1E;AACD;AAcO,SAAS,oBAAoB;AACnC,QAAM,oBAAoB,eAAe,CAAC,MAAM;AAC/C,UAAM,KAAK,EAAE;AACb,WAAO,KAAK,EAAE,cAAc,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI;AAAA,EACxD,CAAC;AACD,QAAM,kBAAkB,eAAe,CAAC,MAAM,EAAE,aAAa,IAAI;AACjE,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,SAAS,IAAI;AAEzD,QAAM,EAAE,WAAW,WAAW,IAAI,qBAAqB,iBAAiB;AACxE,QAAM,cAAc,mBAAmB,eAAe;AAEtD,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA,cAAc,CAAC,CAAC;AAAA;AAAA,IAEhB;AAAA;AAAA,IAEA,YAAY,aAAa;AAAA,EAC1B;AACD;;;ACjEA,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;AAS7B,SAAS,UAAkB;AACjC,QAAM,CAAC,KAAK,MAAM,IAAIC,UAAS,MAAM,gBAAgB,CAAC;AAEtD,EAAAC,WAAU,MAAM;AAEf,WAAO,eAAe,MAAM;AAC3B,aAAO,gBAAgB,CAAC;AAAA,IACzB,CAAC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO;AACR;;;ACpBA,SAAS,eAAAC,cAAa,UAAAC,eAAc;AAc7B,SAAS,YAAY,gBAA+B;AAC1D,QAAM,EAAE,GAAG,IAAI,iBAAiB;AAChC,QAAM,WAAW;AAAA,IAAe,CAAC,MAChC,iBAAkB,EAAE,YAAY,IAAI,cAAc,KAAK,QAAS;AAAA,EACjE;AACA,QAAM,iBAAiB;AAAA,IAAe,CAAC,MACtC,iBAAkB,EAAE,aAAa,IAAI,cAAc,KAAK,QAAS;AAAA,EAClE;AACA,QAAM,cAAcC,QAA6C,IAAI;AACrE,QAAM,kBAAkBA,QAAO,KAAK;AAEpC,QAAM,YAAYC;AAAA,IACjB,CAAC,WAAoB;AACpB,UAAI,CAAC,eAAgB;AAGrB,UAAI,YAAY,QAAS,cAAa,YAAY,OAAO;AAEzD,UAAI,QAAQ;AAEX,YAAI,CAAC,gBAAgB,SAAS;AAC7B,0BAAgB,UAAU;AAC1B,aAAG,WAAW,gBAAgB,IAAI;AAAA,QACnC;AAEA,oBAAY,UAAU,WAAW,MAAM;AACtC,0BAAgB,UAAU;AAC1B,aAAG,WAAW,gBAAgB,KAAK;AAAA,QACpC,GAAG,GAAI;AAAA,MACR,OAAO;AAEN,YAAI,gBAAgB,SAAS;AAC5B,0BAAgB,UAAU;AAC1B,aAAG,WAAW,gBAAgB,KAAK;AAAA,QACpC;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAC,gBAAgB,EAAE;AAAA,EACpB;AAEA,SAAO,EAAE,UAAU,gBAAgB,UAAU;AAC9C;;;ACvDA,SAAS,eAAAC,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAKzD,IAAM,cAA8B,CAAC;AAK9B,SAAS,YAAY,gBAA+B;AAC1D,QAAM,EAAE,QAAQ,MAAM,IAAI,iBAAiB;AAC3C,QAAM,WAAW;AAAA,IAAe,CAAC,MAChC,iBAAiB,EAAE,SAAS,IAAI,cAAc,KAAK,cAAc;AAAA,EAClE;AACA,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAS,KAAK;AAChD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,YAAYC,QAA2B,MAAS;AAGtD,QAAM,YAAYA,QAAO,MAAM;AAC/B,QAAM,WAAWA,QAAO,KAAK;AAK7B,EAAAC,WAAU,MAAM;AACf,cAAU,UAAU;AACpB,aAAS,UAAU;AAAA,EACpB,CAAC;AAGD,EAAAA,WAAU,MAAM;AACf,QAAI,CAAC,eAAgB;AAKrB,QAAI,eAAe,WAAW,OAAO,EAAG;AAExC,QAAI,YAAY;AAQhB,UAAM,mBAAmB,SAAS,QAAQ,SAAS,EAAE,SAAS,IAAI,cAAc;AAChF,UAAM,UAAU,CAAC,CAAC,oBAAoB,iBAAiB,SAAS;AAChE,QAAI,SAAS;AACZ,eAAS,QAAQ,SAAS,EAAE,YAAY,cAAc;AACtD,gBAAU,QAAQ,OAAO,SACvB,OAAO,EAAE,eAAe,CAAC,EACzB,MAAM,MAAM;AAAA,MAAC,CAAC;AAChB,aAAO,MAAM;AACZ,oBAAY;AAAA,MACb;AAAA,IACD;AAEA,iBAAa,IAAI;AACjB,mBAAe,OAAO;AACrB,UAAI;AACH,cAAM,OAAO,MAAM,UAAU,QAAQ,OAAO,YAAY,MAAM;AAAA,UAC7D;AAAA,UACA,OAAO;AAAA,QACR,CAAC;AAED,YAAI,UAAW;AAGf,YAAI,KAAK,MAAM,SAAS,GAAG;AAC1B,mBAAS,QAAQ,SAAS,EAAE,YAAY,gBAAiB,KAAK,KAAuB;AAAA,QACtF;AACA,mBAAW,KAAK,OAAO;AACvB,kBAAU,UAAU,KAAK,cAAc;AAGvC,iBAAS,QAAQ,SAAS,EAAE,YAAY,cAAe;AACvD,kBAAU,QAAQ,OAAO,SAAS,OAAO,EAAE,eAAgC,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAC7F,SAAS,KAAK;AACb,gBAAQ,MAAM,iCAAiC,GAAG;AAAA,MACnD,UAAE;AACD,YAAI,CAAC,UAAW,cAAa,KAAK;AAAA,MACnC;AAAA,IACD;AAEA,SAAK;AACL,WAAO,MAAM;AACZ,kBAAY;AAAA,IACb;AAAA,EACD,GAAG,CAAC,cAAc,CAAC;AAEnB,QAAM,WAAWC,aAAY,YAAY;AACxC,QAAI,CAAC,kBAAkB,CAAC,WAAW,UAAW;AAE9C,iBAAa,IAAI;AACjB,QAAI;AACH,YAAM,OAAO,MAAM,UAAU,QAAQ,OAAO,YAAY,MAAM;AAAA,QAC7D;AAAA,QACA,QAAQ,UAAU;AAAA,QAClB,OAAO;AAAA,MACR,CAAC;AAED,YAAM,WAAW,SAAS,QAAQ,SAAS,EAAE,SAAS,IAAI,cAAc,KAAK,CAAC;AAC9E,eAAS,QAAQ,SAAS,EAAE,YAAY,gBAAgB,CAAC,GAAG,KAAK,OAAyB,GAAG,QAAQ,CAAC;AACtG,iBAAW,KAAK,OAAO;AACvB,gBAAU,UAAU,KAAK,cAAc;AAAA,IACxC,UAAE;AACD,mBAAa,KAAK;AAAA,IACnB;AAAA,EACD,GAAG,CAAC,gBAAgB,SAAS,SAAS,CAAC;AAEvC,SAAO,EAAE,OAAO,UAAU,WAAW,SAAS,SAAS;AACxD;;;ACxGO,SAAS,YAAY;AAC3B,QAAM,cAAc;AAAA,IAAe,CAAC,MACnC,EAAE,cAAc,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC;AAAA,EAC1D;AAEA,SAAO,EAAE,YAAY;AACtB;;;ACNO,SAAS,YAAY;AAC3B,QAAM,EAAE,OAAO,IAAI,iBAAiB;AACpC,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,OAAO;AAC/C,QAAM,eAAe,eAAe,CAAC,MAAM,EAAE,YAAY;AACzD,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,OAAO;AAC/C,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,OAAO;AAC/C,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AAEvD,iBAAe,SAAS,MAarB;AACF,WAAO,OAAO,OAAO,SAAS,OAAO,IAAI;AAAA,EAC1C;AAEA,SAAO,EAAE,SAAS,cAAc,SAAS,SAAS,aAAa,SAAS;AACzE;;;ACnCA,SAAS,eAAAC,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;;;ACDzD,SAAS,eAAAC,cAAa,UAAAC,SAAQ,YAAAC,iBAAgB;;;ACsB3C,gBAAAC,MAyBD,YAzBC;AAMI,SAAS,MAAM,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACzD,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,wCAAuC,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ;AAAA;AAAA,EAC5G;AAEF;AAqBO,SAAS,iBAAiB,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACpE,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,6EAA4E,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACxK;AAEF;AAqBO,SAAS,SAAS,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC5D,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,2RAA0R,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACtX;AAEF;AAGO,SAAS,cAAc,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACjE,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,sLAAqL,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ;AAAA;AAAA,EAC1P;AAEF;AAGO,SAAS,YAAY,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC/D,SACC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ;AAAA,wBAAAA,KAAC,UAAK,GAAE,YAAW,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA,QACtG,gBAAAA,KAAC,UAAK,GAAE,oBAAmB,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA;AAAA,EAC/G;AAEF;AAGO,SAAS,SAAS,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC5D,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,wqBAAuqB,QAAO,gBAAe,aAAY,KAAI,gBAAe,SAAQ;AAAA;AAAA,EAC7uB;AAEF;AAGO,SAAS,aAAa,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAChE,SACC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ;AAAA,wBAAAA,KAAC,UAAK,GAAE,sXAAqX,QAAO,gBAAe,aAAY,KAAI,gBAAe,SAAQ;AAAA,QAC1b,gBAAAA,KAAC,UAAK,GAAE,miBAAkiB,MAAK,gBAAe,QAAO,gBAAe,aAAY,QAAO,eAAc,UAAS;AAAA;AAAA;AAAA,EAC/nB;AAEF;AAqBO,SAAS,YAAY,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC/D,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,+bAA8b,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EAC1hB;AAEF;AAoBO,SAAS,SAAS,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC5D,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,2wBAA0wB,MAAK,gBAAe;AAAA;AAAA,EACvyB;AAEF;AAGO,SAAS,cAAc,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACjE,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,8fAA6f,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACzlB;AAEF;AAGO,SAAS,cAAc,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACjE,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,qUAAoU,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACha;AAEF;AAGO,SAAS,eAAe,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAClE,SACC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ;AAAA,wBAAAA,KAAC,UAAK,GAAE,qHAAoH,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA,QAC/M,gBAAAA,KAAC,UAAK,GAAE,gBAAe,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ;AAAA,QACnF,gBAAAA,KAAC,UAAK,GAAE,mGAAkG,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA;AAAA,EAC9L;AAEF;AAGO,SAAS,cAAc,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AACjE,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,8OAA6O,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACzU;AAEF;AAGO,SAAS,SAAS,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC5D,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MAChD,QAAQ,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAAA,MACjD,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAM;AAAA,MACL,GAAG;AAAA,MAEJ,0BAAAA,KAAC,UAAK,GAAE,0oBAAyoB,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ;AAAA;AAAA,EACruB;AAEF;AAMO,SAAS,SAAS,EAAE,OAAO,IAAI,GAAG,MAAM,GAAc;AAC5D,SACC;AAAA,IAAC;AAAA;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,eAAY;AAAA,MACX,GAAG;AAAA,MAEJ;AAAA,wBAAAA,KAAC,YAAO,IAAG,KAAI,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe;AAAA,QACnD,gBAAAA,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe;AAAA,QACpD,gBAAAA,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe;AAAA;AAAA;AAAA,EACrD;AAEF;;;AD/LM,gBAAAC,MA6BD,QAAAC,aA7BC;AApKN,IAAM,YAAY;AAClB,IAAM,sBAAsB;AAuBrB,SAAS,SAAS;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAkB;AACjB,QAAM,MAAMC,QAA4B,IAAI;AAC5C,QAAM,eAAeA,QAAyB,IAAI;AAIlD,QAAM,sBAAsBA;AAAA,IAC3B,OAAO,QAAQ,eAAe,IAAI,WAAW,gBAAgB,SAAS;AAAA,EACvE;AAEA,QAAM,gBAAgBC;AAAA,IACrB,CAAC,MAA2B;AAC3B,UAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,UAAU;AACrC,UAAE,eAAe;AACjB,iBAAS;AAAA,MACV;AAAA,IACD;AAAA,IACA,CAAC,QAAQ;AAAA,EACV;AAEA,QAAM,eAAeA;AAAA,IACpB,CAAC,MAA8C;AAC9C,YAAM,QAAQ,EAAE,OAAO;AACvB,UAAI,MAAM,SAAS,UAAW;AAC9B,mBAAa,KAAK;AAClB,iBAAW,MAAM,SAAS,CAAC;AAQ3B,UAAI,CAAC,oBAAoB,SAAS;AACjC,cAAM,KAAK,IAAI;AACf,YAAI,IAAI;AACP,aAAG,MAAM,SAAS;AAClB,aAAG,MAAM,SAAS,GAAG,KAAK,IAAI,GAAG,cAAc,GAAG,CAAC;AAAA,QACpD;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAC,cAAc,QAAQ;AAAA,EACxB;AAGA,QAAM,cAAcA;AAAA,IACnB,CAAC,MAA4B;AAC5B,UAAI,CAAC,WAAY;AACjB,YAAM,QAAQ,aAAa,EAAE,aAAa;AAC1C,UAAI,MAAM,SAAS,GAAG;AACrB,UAAE,eAAe;AACjB,mBAAW,KAAK;AAAA,MACjB;AAAA,IACD;AAAA,IACA,CAAC,UAAU;AAAA,EACZ;AAGA,QAAM,CAAC,YAAY,aAAa,IAAIC,UAAS,KAAK;AAClD,QAAM,eAAeF,QAAO,CAAC;AAE7B,QAAM,kBAAkBC,aAAY,CAAC,MAAuB;AAC3D,MAAE,eAAe;AACjB,iBAAa;AACb,QAAI,aAAa,YAAY,EAAG,eAAc,IAAI;AAAA,EACnD,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkBA,aAAY,CAAC,MAAuB;AAC3D,MAAE,eAAe;AACjB,iBAAa;AACb,QAAI,aAAa,YAAY,EAAG,eAAc,KAAK;AAAA,EACpD,GAAG,CAAC,CAAC;AAEL,QAAM,iBAAiBA,aAAY,CAAC,MAAuB;AAC1D,MAAE,eAAe;AACjB,MAAE,aAAa,aAAa;AAAA,EAC7B,GAAG,CAAC,CAAC;AAEL,QAAM,aAAaA;AAAA,IAClB,CAAC,MAAuB;AACvB,QAAE,eAAe;AACjB,mBAAa,UAAU;AACvB,oBAAc,KAAK;AACnB,UAAI,CAAC,WAAY;AACjB,YAAM,QAAQ,aAAa,EAAE,YAAY;AACzC,UAAI,MAAM,SAAS,EAAG,YAAW,KAAK;AAAA,IACvC;AAAA,IACA,CAAC,UAAU;AAAA,EACZ;AAGA,QAAM,kBAAkBA,aAAY,MAAM;AACzC,iBAAa,SAAS,MAAM;AAAA,EAC7B,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmBA;AAAA,IACxB,CAAC,MAA2C;AAC3C,UAAI,CAAC,cAAc,CAAC,EAAE,OAAO,MAAO;AACpC,iBAAW,MAAM,KAAK,EAAE,OAAO,KAAK,CAAC;AACrC,QAAE,OAAO,QAAQ;AAAA,IAClB;AAAA,IACA,CAAC,UAAU;AAAA,EACZ;AAEA,QAAM,UAAU,KAAK,KAAK,EAAE,SAAS;AACrC,QAAM,iBAAiB,eAAe,YAAY,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC7E,QAAM,iBAAiB,aAAa,KAAK,CAAC,MAAM,EAAE,WAAW,KAAK;AAMlE,QAAM,WAAW,WAAW,mBAAmB,CAAC;AAChD,QAAM,gBAAgB,KAAK,UAAU;AACrC,QAAM,cAAc,KAAK,SAAS;AAElC,SACC,gBAAAH;AAAA,IAAC;AAAA;AAAA,MACA,WAAW,eAAe,UAAU,yBAAyB,EAAE,IAAI,aAAa,0BAA0B,EAAE;AAAA,MAC5G,aAAa;AAAA,MACb,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,QAAQ;AAAA,MAER,0BAAAC,MAAC,SAAI,WAAU,mBAAkB,OAAO,EAAE,UAAU,WAAW,GAE7D;AAAA,sBACA,gBAAAD,KAAC,SAAI,WAAU,4BACd,0BAAAA,KAAC,UAAK,WAAU,yBAAyB,YAAE,mBAAmB,GAAE,GACjE;AAAA,QAGA,eAAe,YAAY,SAAS,KACpC,gBAAAA,KAAC,SAAI,WAAU,wBACb,sBAAY,IAAI,CAAC,MACjB,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAEA,YAAY;AAAA,YACZ,UAAU,qBAAqB,MAAM,mBAAmB,EAAE,EAAE,IAAI;AAAA;AAAA,UAF3D,EAAE;AAAA,QAGR,CACA,GACF;AAAA,QAGD,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACA;AAAA,YACA,WAAU;AAAA,YACV,OAAO;AAAA,YACP,UAAU;AAAA,YACV,WAAW;AAAA,YACX,SAAS;AAAA,YACT,aAAa,eAAe,EAAE,oBAAoB;AAAA,YAClD,MAAM;AAAA,YACN,UAAU,YAAY;AAAA,YACtB,cAAY,EAAE,mBAAmB;AAAA;AAAA,QAClC;AAAA,QACA,gBAAAC,MAAC,SAAI,WAAU,uBACd;AAAA,0BAAAA,MAAC,SAAI,WAAU,4BACd;AAAA,4BAAAD;AAAA,cAAC;AAAA;AAAA,gBACA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,SAAS;AAAA,gBACT,UAAU,YAAY;AAAA,gBACtB,cAAY,EAAE,oBAAoB;AAAA,gBAElC,0BAAAA,KAAC,iBAAc;AAAA;AAAA,YAChB;AAAA,YACA,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACA,KAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ;AAAA,gBACR,UAAQ;AAAA,gBACR,QAAM;AAAA,gBACN,UAAU;AAAA;AAAA,YACX;AAAA,YACC,iBACA,gBAAAA,KAAC,UAAK,WAAW,yBAAyB,cAAc,gCAAgC,EAAE,IACxF,sBAAY,KAAK,QACnB;AAAA,aAEF;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACA,MAAK;AAAA,cACL,WAAW,oBAAoB,WAAW,CAAC,eAAe,CAAC,WAAW,6BAA6B,4BAA4B;AAAA,cAC/H,SAAS,MAAM,SAAS;AAAA,cACxB,UAAU,YAAY,CAAC,WAAW,gBAAgB;AAAA,cAClD,cAAY,EAAE,kBAAkB;AAAA,cAEhC,0BAAAA,KAAC,YAAS;AAAA;AAAA,UACX;AAAA,WACD;AAAA,SACD;AAAA;AAAA,EACD;AAEF;AAYO,SAAS,aAAa,EAAE,YAAY,GAAG,SAAS,GAA6D;AACnH,SACC,gBAAAC,MAAC,SAAI,WAAW,uBAAuB,EAAE,QAAQ,+BAA+B,EAAE,IAChF;AAAA,MAAE,aACF,gBAAAD,KAAC,SAAI,KAAK,EAAE,YAAY,KAAK,EAAE,KAAK,MAAM,WAAU,2BAA0B,IAE9E,gBAAAA,KAAC,SAAI,WAAU,4BACd,0BAAAA,KAAC,UAAK,WAAU,2BACd,YAAE,KAAK,KAAK,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,KAAK,QACjD,GACD;AAAA,IAEA,EAAE,eAAe,gBAAAA,KAAC,SAAI,WAAU,8BAA6B;AAAA,IAC7D,EAAE,SAAS,gBAAAA,KAAC,SAAI,WAAU,6BAA4B,OAAO,EAAE,OAAO,eAAC;AAAA,IACvE,YACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS;AAAA,QACT,cAAY,EAAE,oBAAoB;AAAA,QAElC,0BAAAA,KAAC,SAAM;AAAA;AAAA,IACR;AAAA,KAEF;AAEF;AAIA,SAAS,aAAa,MAA4B;AACjD,QAAM,QAAgB,CAAC;AACvB,MAAI,KAAK,OAAO;AACf,aAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC3C,YAAM,OAAO,KAAK,MAAM,CAAC;AACzB,UAAI,KAAM,OAAM,KAAK,IAAI;AAAA,IAC1B;AAAA,EACD;AACA,SAAO;AACR;;;AD2CM,SAiGA,UA5FC,OAAAK,MALD,QAAAC,aAAA;AA7PN,SAAS,oBAAoB,aAAoD;AAChF,QAAM,CAAC,cAAc,eAAe,IAAIC,UAAwB,IAAI;AACpE,QAAM,aAAa,eAAe,CAAC,GAAG;AAAA,IAAI,CAAC,UAC1C,OAAO,UAAU,WAAW,QAAQ,MAAM;AAAA,EAC3C;AACA,QAAM,MAAM,UAAU,KAAK,GAAG;AAC9B,SAAO;AAAA,IACN,WAAW,iBAAiB,MAAM,CAAC,IAAI;AAAA,IACvC,SAAS,MAAM,gBAAgB,GAAG;AAAA,EACnC;AACD;AAyCA,SAAS,kBAA0C;AAClD,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,QAAQ;AAId,SAAO,MAAM,qBAAqB,MAAM,2BAA2B;AACpE;AAQA,SAAS,aAAa,QAAiC;AACtD,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAChD,QAAM,SAASC,QAA2B,IAAI;AAI9C,QAAM,YAAYA,QAAO,MAAM;AAC/B,EAAAC,WAAU,MAAM;AACf,cAAU,UAAU;AAAA,EACrB,GAAG,CAAC,MAAM,CAAC;AAIX,QAAM,CAAC,SAAS,IAAIF,UAAS,MAAM,gBAAgB,MAAM,IAAI;AAI7D,EAAAE;AAAA,IACC,MAAM,MAAM;AACX,aAAO,SAAS,KAAK;AACrB,aAAO,UAAU;AAAA,IAClB;AAAA,IACA,CAAC;AAAA,EACF;AAEA,QAAM,SAASC,aAAY,MAAM;AAChC,QAAI,OAAO,SAAS;AACnB,aAAO,QAAQ,KAAK;AACpB;AAAA,IACD;AACA,UAAM,OAAO,gBAAgB;AAC7B,QAAI,CAAC,KAAM;AACX,UAAM,MAAM,IAAI,KAAK;AACrB,QAAI,OAAO,OAAO,aAAa,cAAc,SAAS,gBAAgB,QAAQ,OAAO;AACrF,QAAI,aAAa;AACjB,QAAI,iBAAiB;AACrB,QAAI,WAAW,CAAC,UAAU;AACzB,eAAS,IAAI,MAAM,aAAa,IAAI,MAAM,QAAQ,QAAQ,KAAK;AAC9D,cAAM,SAAS,MAAM,QAAQ,CAAC;AAC9B,YAAI,CAAC,QAAQ,QAAS;AACtB,cAAM,OAAO,OAAO,CAAC,GAAG,YAAY,KAAK;AACzC,YAAI,KAAM,WAAU,QAAQ,IAAI;AAAA,MACjC;AAAA,IACD;AACA,UAAM,SAAS,MAAM;AACpB,aAAO,UAAU;AACjB,mBAAa,KAAK;AAAA,IACnB;AACA,QAAI,QAAQ;AACZ,QAAI,UAAU;AACd,WAAO,UAAU;AACjB,iBAAa,IAAI;AACjB,QAAI,MAAM;AAAA,EACX,GAAG,CAAC,CAAC;AAIL,QAAM,OAAOA,aAAY,MAAM;AAC9B,WAAO,SAAS,KAAK;AAAA,EACtB,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,WAAW,WAAW,QAAQ,KAAK;AAC7C;AAGA,IAAM,aAAa;AAEnB,IAAM,WAAW;AAGjB,SAAS,UAAU,MAAmC;AACrD,MAAI,CAAC,MAAM,MAAO,QAAO,CAAC;AAC1B,QAAM,MAAc,CAAC;AACrB,WAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC3C,UAAM,OAAO,KAAK,MAAM,CAAC;AACzB,QAAI,KAAM,KAAI,KAAK,IAAI;AAAA,EACxB;AACA,SAAO;AACR;AAEO,SAAS,UAAU;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAmB;AAClB,QAAM,CAAC,SAAS,UAAU,IAAIH,UAAS,KAAK;AAC5C,QAAM,WAAWC,QAA4B,IAAI;AACjD,QAAM,SAASA,QAAuB,IAAI;AAC1C,QAAM,eAAeA,QAAyB,IAAI;AAClD,QAAM,EAAE,WAAW,kBAAkB,SAAS,aAAa,IAAI,oBAAoB,WAAW;AAI9F,QAAM,YAAY,aAAa,CAAC,UAAU;AACzC,UAAM,UAAU,SAAS,SAAS,SAAS;AAC3C,aAAS,UAAU,GAAG,QAAQ,QAAQ,QAAQ,EAAE,CAAC,IAAI,KAAK,KAAK,KAAK;AACpE,aAAS,SAAS,MAAM;AAAA,EACzB,CAAC;AAKD,QAAM,OAAOE,aAAY,MAAM;AAC9B,UAAM,KAAK,SAAS;AACpB,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,MAAM,CAAC,IAAK;AACjB,OAAG,MAAM,SAAS;AAClB,UAAM,OAAO,KAAK,IAAI,YAAY,GAAG,YAAY;AACjD,OAAG,MAAM,SAAS,GAAG,IAAI;AACzB,QAAI,QAAQ,QAAQ,OAAO,WAAW,SAAS;AAAA,EAChD,GAAG,CAAC,CAAC;AAGL,EAAAD,WAAU,MAAM,CAAC,MAAM,KAAK,CAAC;AAE7B,QAAM,gBAAgBC;AAAA,IACrB,CAAC,UAAoD;AACpD,UAAI,MAAM,QAAQ,WAAW,MAAM,SAAU;AAC7C,YAAM,eAAe;AACrB,UAAI,CAAC,MAAM,KAAK,KAAK,SAAU;AAC/B,eAAS;AAAA,IACV;AAAA,IACA,CAAC,OAAO,UAAU,QAAQ;AAAA,EAC3B;AAIA,QAAM,cAAcA;AAAA,IACnB,CAAC,UAAqD;AACrD,UAAI,CAAC,WAAY;AACjB,YAAM,QAAQ,UAAU,MAAM,aAAa;AAC3C,UAAI,CAAC,MAAM,OAAQ;AACnB,YAAM,eAAe;AACrB,iBAAW,KAAK;AAAA,IACjB;AAAA,IACA,CAAC,UAAU;AAAA,EACZ;AASA,QAAM,kBAAkB,WAAW,CAAC,CAAC,iBAAiB,UAAU,CAAC,MAAM,KAAK;AAK5E,QAAM,aAAa,CAAC,UAA4C;AAC/D,UAAM,OAAO,MAAM;AACnB,QAAI,QAAQ,MAAM,cAAc,SAAS,IAAI,EAAG;AAChD,eAAW,KAAK;AAMhB,cAAU,KAAK;AAAA,EAChB;AAIA,QAAM,YAAY,aAAa,KAAK,CAAC,MAAM,EAAE,WAAW,KAAK;AAC7D,QAAM,gBAAgB,aAAa,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,KAAK;AACnE,QAAM,WAAW,CAAC,CAAC,MAAM,KAAK,KAAK,kBAAkB,CAAC,aAAa,CAAC;AAEpE,SACC,gBAAAJ,MAAC,SAAI,WAAU,WAAU,SAAS,MAAM,WAAW,IAAI,GAAG,QAAQ,YAChE;AAAA,uBACA,gBAAAD,KAAC,SAAI,WAAU,uBACb,2BAAiB,IAAI,CAAC,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,MAKhC,gBAAAC;AAAA,QAAC;AAAA;AAAA,UAEA,WAAU;AAAA,UACV,OAAO,EAAE,gBAAgB,GAAG,MAAM,QAAQ,EAAE,KAAK;AAAA,UAEjD;AAAA,4BAAAD;AAAA,cAAC;AAAA;AAAA,gBACA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,SAAS,MAAM,eAAe,QAAQ;AAAA,gBAErC;AAAA;AAAA,YACF;AAAA,YACC,UAAU,KACV,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,cAAY,EAAE,qBAAqB;AAAA,gBACnC,SAAS;AAAA,gBAET,0BAAAA;AAAA,kBAAC;AAAA;AAAA,oBACA,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,QAAO;AAAA,oBACP,aAAY;AAAA,oBACZ,eAAc;AAAA,oBACd,eAAY;AAAA,oBAEZ,0BAAAA,KAAC,UAAK,GAAE,wBAAuB;AAAA;AAAA,gBAChC;AAAA;AAAA,YACD;AAAA;AAAA;AAAA,QA5BI;AAAA,MA8BN;AAAA,KACA,GACF;AAAA,IAGA,aACA,gBAAAA,KAAC,SAAI,WAAU,iBAAgB,MAAK,SAClC,qBACF;AAAA,IAED,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACA,WAAU;AAAA,QACV,KAAK;AAAA,QACL,cAAW;AAAA,QACX,aAAa;AAAA,QACb,cAAc;AAAA,QAIb;AAAA,WAAC,CAAC,aAAa,UACf,gBAAAD,KAAC,SAAI,WAAU,oBACb,sBAAY,IAAI,CAAC,MACjB,gBAAAA;AAAA,YAAC;AAAA;AAAA,cAEA,YAAY;AAAA,cACZ,UAAU,qBAAqB,MAAM,mBAAmB,EAAE,EAAE,IAAI;AAAA;AAAA,YAF3D,EAAE;AAAA,UAGR,CACA,GACF;AAAA,UAQD,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACA,KAAK;AAAA,cACL,WAAU;AAAA,cACV,MAAM;AAAA,cACN;AAAA,cACA,aAAa,eAAe,EAAE,wBAAwB;AAAA,cACtD,cAAY,EAAE,wBAAwB;AAAA,cACtC,UAAU,CAAC,UAAU;AACpB,yBAAS,MAAM,OAAO,KAAK;AAC3B,oBAAI,UAAW,oBAAmB;AAClC,qBAAK;AAAA,cACN;AAAA,cACA,WAAW;AAAA,cACX,SAAS;AAAA;AAAA,UACV;AAAA,UACA,gBAAAC,MAAC,SAAI,WAAU,mBACb;AAAA,sBAAU,aACV,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,eAAa,UAAU,YAAY,SAAS;AAAA,gBAC5C,cAAY,EAAE,qBAAqB;AAAA,gBACnC,gBAAc,UAAU;AAAA,gBACxB;AAAA,gBACA,SAAS,UAAU;AAAA,gBAEnB,0BAAAA,KAAC,YAAS;AAAA;AAAA,YACX;AAAA,YAEA,cACA,gBAAAC,MAAA,YACC;AAAA,8BAAAD;AAAA,gBAAC;AAAA;AAAA,kBACA,MAAK;AAAA,kBACL,WAAU;AAAA,kBACV,cAAY,EAAE,oBAAoB;AAAA,kBAClC;AAAA,kBACA,SAAS,MAAM,aAAa,SAAS,MAAM;AAAA,kBAE3C,0BAAAA,KAAC,iBAAc,MAAM,IAAI;AAAA;AAAA,cAC1B;AAAA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACA,KAAK;AAAA,kBACL,MAAK;AAAA,kBACL,QAAQ;AAAA,kBACR,UAAQ;AAAA,kBACR,QAAM;AAAA,kBACN,UAAU,CAAC,UAAU;AACpB,wBAAI,CAAC,MAAM,OAAO,MAAO;AACzB,+BAAW,MAAM,KAAK,MAAM,OAAO,KAAK,CAAC;AAEzC,0BAAM,OAAO,QAAQ;AAAA,kBACtB;AAAA;AAAA,cACD;AAAA,eACD;AAAA,YAED,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,cAAY,EAAE,kBAAkB;AAAA,gBAChC,UAAU,CAAC;AAAA,gBACX,SAAS;AAAA,gBAET,0BAAAA,KAAC,eAAY,MAAM,IAAI;AAAA;AAAA,YACxB;AAAA,aACD;AAAA;AAAA;AAAA,IACD;AAAA,KACD;AAEF;AAIA,SAAS,WAAW;AACnB,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ;AAAA,wBAAAD,KAAC,UAAK,GAAE,8DAA6D;AAAA,QACrE,gBAAAA,KAAC,UAAK,GAAE,oCAAmC;AAAA,QAC3C,gBAAAA,KAAC,UAAK,GAAE,YAAW;AAAA;AAAA;AAAA,EACpB;AAEF;;;AGleA,SAAS,YAAAM,iBAAgB;;;ACGlB,SAAS,cAAc,MAAsB;AACnD,SAAO,KACL,QAAQ,gBAAgB,EAAE,EAC1B,QAAQ,kBAAkB,IAAI,EAC9B,QAAQ,cAAc,IAAI,EAC1B,QAAQ,eAAe,EAAE,EACzB,QAAQ,qBAAqB,IAAI,EACjC,QAAQ,YAAY,IAAI,EACxB,QAAQ,WAAW,GAAG,EACtB,QAAQ,OAAO,GAAG,EAClB,KAAK;AACR;;;ADkFE,SAEE,OAAAC,MAFF,QAAAC,aAAA;AAxBK,SAAS,qBAAqB;AAAA,EACpC;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA,aAAa,OAAO;AACrB,GAA8B;AAC7B,QAAM,WAAW,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAC7D,QAAM,iBAAiB,eAAe,CAAC,MAAM,EAAE,0BAA0B;AACzE,QAAM,YAAY,eAAe,CAAC,MAAM,EAAE,aAAa,IAAI,KAAK;AAEhE,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,QAAM,sBAAsB,cAAc,aAAa,gCAAgC;AAIvF,QAAM,EAAE,SAAS,OAAO,IAAI,uBAAuB,UAAU,UAAU;AAIvE,QAAM,OAAO,OAAO,CAAC;AAErB,SACC,gBAAAA,MAAC,SAAI,WAAW,oBAAoB,mBAAmB,GAAG,KAAK,GAC7D;AAAA,YAAQ,IAAI,CAAC,YACb,gBAAAD;AAAA,MAAC;AAAA;AAAA,QAEA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW,CAAC,SAAS,eAAe,IAAI;AAAA;AAAA,MAPnC,QAAQ;AAAA,IAQd,CACA;AAAA,IACA,QACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM,OAAO,KAAK,MAAM,KAAK,KAAK;AAAA,QAE1C,iBAAO,WAAW,IAChB,EAAE,+BAA+B,IACjC,EAAE,6BAA6B,EAAE,OAAO,OAAO,OAAO,CAAC;AAAA;AAAA,IAC3D;AAAA,KAEF;AAEF;AAEA,SAAS,wBAAwB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAQG;AACF,QAAM,CAAC,SAAS,UAAU,IAAIE,UAAS,KAAK;AAE5C,QAAM,cAAc,CAAC,MAAkB;AACtC,MAAE,gBAAgB;AAClB,eAAW,IAAI;AACf,eAAW,MAAM;AAChB,gBAAU,QAAQ,IAAI;AACtB,iBAAW,KAAK;AAAA,IACjB,GAAG,GAAG;AAAA,EACP;AAEA,QAAM,iBAAiB,cAAc,aAAa,0BAA0B;AAE5E,SACC,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACA,WAAW,uCAAuC,cAAc,GAAG,UAAU,wBAAwB,EAAE,GAAG,KAAK;AAAA,MAC/G,SAAS,MAAM,OAAO,QAAQ,MAAM,QAAQ,KAAK;AAAA,MACjD,MAAK;AAAA,MACL,UAAU;AAAA,MAEV;AAAA,wBAAAA,MAAC,SAAI,WAAU,qBACd;AAAA,0BAAAD,KAAC,SAAI,WAAU,qBAAqB,kBAAO;AAAA,UAC3C,gBAAAA,KAAC,SAAI,WAAU,mBAAmB,qBAAU;AAAA,UAC5C,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACA,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS;AAAA,cACT,cAAY,EAAE,qBAAqB;AAAA,cAEnC,0BAAAA,KAAC,SAAM,MAAM,IAAI;AAAA;AAAA,UAClB;AAAA,WACD;AAAA,QACA,gBAAAA,KAAC,SAAI,WAAU,0CAA0C,kBAAQ,OAAM;AAAA,QACtE,QAAQ,SACP,MAAM;AACN,gBAAM,QAAQ,cAAc,QAAQ,IAAI;AACxC,iBACC,gBAAAA,KAAC,SAAI,WAAU,yCACb,8BAAoB,KAAK,GAC3B;AAAA,QAEF,GAAG;AAAA,QACH,QAAQ,SAAS,gBAAAA,KAAC,SAAI,WAAU,yBAAyB,kBAAQ,OAAM;AAAA,QACvE,UAAU,QAAQ,WAAW,SAAS,gBAAAA,KAAC,SAAI,WAAU,qBAAqB,kBAAO;AAAA;AAAA;AAAA,EACnF;AAEF;;;AE7LA,SAAS,eAAAG,eAAa,aAAAC,mBAAiB;;;ACAvC,SAAS,eAAAC,cAAa,aAAAC,YAAW,YAAAC,iBAAgB;AAsBjD,IAAMC,cAAiC,CAAC;AAIxC,SAAS,QAAQ,OAAe,MAAc;AAC7C,SAAO,QAAQ,KAAK,IAAI,IAAI;AAC7B;AAEA,SAAS,UAAU,OAAe,MAAc,MAAc;AAC7D,SAAO,QAAQ,KAAK,IAAI,IAAI,WAAW,IAAI;AAC5C;AASA,SAAS,UAAa,OAAmD,KAAuB;AAC/F,QAAM,QAAQ,MAAM,IAAI,GAAG;AAC3B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,KAAK,IAAI,IAAI,MAAM,KAAK,kBAAmB,QAAO;AACtD,SAAO,MAAM;AACd;AAMO,SAAS,cAAc,OAAe;AAC5C,QAAM,EAAE,QAAQ,MAAM,IAAI,iBAAiB;AAC3C,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,aAAa,WAAW,KAAKA;AACzE,QAAM,MAAM,YAAY,KAAK,CAACC,OAAMA,GAAE,OAAO,KAAK,KAAK;AAEvD,QAAM,OAAO,UAAU;AACvB,QAAM,QAAQ,MAAM,SAAS,EAAE;AAE/B,QAAM,CAAC,SAAS,UAAU,IAAIC;AAAA,IAC7B,MAAM,UAAsB,OAAO,QAAQ,OAAO,IAAI,CAAC,GAAG,SAAS,CAAC;AAAA,EACrE;AACA,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAAoC,IAAI;AACpE,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAChD,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAAS,KAAK;AAC5D,QAAM,CAAC,SAAS,UAAU,IAAIA;AAAA,IAC7B,MAAM,UAAsB,OAAO,QAAQ,OAAO,IAAI,CAAC,GAAG,WAAW;AAAA,EACtE;AACA,QAAM,CAAC,OAAO,QAAQ,IAAIA;AAAA,IACzB,MAAM,UAAsB,OAAO,QAAQ,OAAO,IAAI,CAAC,GAAG,SAAS;AAAA,EACpE;AACA,QAAM,CAAC,MAAM,OAAO,IAAIA;AAAA,IACvB,MAAM,UAAsB,OAAO,QAAQ,OAAO,IAAI,CAAC,GAAG,QAAQ;AAAA,EACnE;AAEA,QAAM,eAAeC;AAAA,IACpB,OAAO,SAA+D;AACrE,UAAI,CAAC,IAAK;AACV,YAAM,IAAI,MAAM,QAAQ;AACxB,YAAM,QAAQ,MAAM,SAAS,MAAM;AAEnC,mBAAa,IAAI;AACjB,UAAI;AACH,cAAM,SAAS,MAAM,OAAO,OAAO,WAAW,MAAM;AAAA,UACnD;AAAA,UACA,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ,MAAM;AAAA,UACd,UAAU,UAAU;AAAA,QACrB,CAAC;AAED,YAAI,OAAO,OAAO;AACjB,qBAAW,CAAC,SAAS;AACpB,kBAAM,YAAY,QAAQ,OAAO,QAAS,CAAC,GAAG,MAAM,GAAG,OAAO,KAAM;AACpE,gBAAI,CAAC,MAAM,QAAQ;AAClB,oBAAM,SAAS,EAAE,gBAAgB,QAAQ,OAAO,UAAU,CAAC,GAAG;AAAA,gBAC7D,OAAO;AAAA,gBACP,OAAO,OAAO;AAAA,gBACd,SAAS,OAAO;AAAA,gBAChB,MAAM;AAAA,cACP,CAAsB;AAAA,YACvB;AACA,mBAAO;AAAA,UACR,CAAC;AACD,qBAAW,OAAO,OAAO;AACzB,mBAAS,OAAO,KAAK;AACrB,kBAAQ,CAAC;AAAA,QACV;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,gCAAgC,GAAG;AAAA,MAClD,UAAE;AACD,qBAAa,KAAK;AAAA,MACnB;AAAA,IACD;AAAA,IACA,CAAC,QAAQ,OAAO,KAAK,KAAK;AAAA,EAC3B;AAEA,QAAM,WAAWA,aAAY,MAAM;AAClC,QAAI,CAAC,WAAW,UAAW;AAC3B,iBAAa,EAAE,MAAM,OAAO,EAAE,CAAC;AAAA,EAChC,GAAG,CAAC,cAAc,SAAS,WAAW,IAAI,CAAC;AAE3C,QAAM,cAAcA;AAAA,IACnB,OAAO,SAAiB;AACvB,UAAI,CAAC,IAAK;AAGV,YAAM,SAAS;AAAA,QACd,MAAM,SAAS,EAAE;AAAA,QACjB,UAAU,OAAO,UAAU,GAAG,IAAI;AAAA,MACnC;AACA,UAAI,QAAQ;AACX,kBAAU,MAAM;AAChB;AAAA,MACD;AAEA,yBAAmB,IAAI;AACvB,UAAI;AACH,cAAM,SAAS,MAAM,OAAO,OAAO,WAAW,MAAM;AAAA,UACnD;AAAA,UACA;AAAA,UACA,UAAU,UAAU;AAAA,QACrB,CAAC;AACD,YAAI,OAAO,OAAO;AACjB,gBAAM,QAAQ,OAAO;AACrB,oBAAU,KAAK;AACf,gBAAM,SAAS,EAAE;AAAA,YAChB,UAAU,OAAO,UAAU,GAAG,IAAI;AAAA,YAClC;AAAA,UACD;AAAA,QACD;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,iCAAiC,GAAG;AAAA,MACnD,UAAE;AACD,2BAAmB,KAAK;AAAA,MACzB;AAAA,IACD;AAAA,IACA,CAAC,QAAQ,OAAO,KAAK,KAAK;AAAA,EAC3B;AAEA,QAAM,cAAcA,aAAY,MAAM;AACrC,cAAU,IAAI;AAAA,EACf,GAAG,CAAC,CAAC;AAGL,EAAAC,WAAU,MAAM;AACf,QAAI,OAAO,QAAQ,WAAW,GAAG;AAChC,mBAAa,EAAE,MAAM,GAAG,OAAO,KAAK,CAAC;AAAA,IACtC;AAAA,EACD,GAAG,CAAC,GAAG,CAAC;AAER,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;;;AC3LA,SAAS,aAAAC,YAAW,UAAAC,eAAc;AAiShC,gBAAAC,YAAA;AA/RF,IAAM,YAAY;AAElB,IAAM,aAAa;AAEnB,SAAS,kBAAkB,MAAc,MAAuB;AAC/D,MAAI,KAAM,QAAO;AACjB,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,4DAA4D,KAAK,OAAO,EAAG,QAAO;AACtF,MAAI,sBAAsB,KAAK,OAAO,KAAK,2BAA2B,KAAK,OAAO,EAAG,QAAO;AAC5F,MAAI,wDAAwD,KAAK,OAAO,EAAG,QAAO;AAClF,MAAI,WAAW,KAAK,OAAO,EAAG,QAAO;AACrC,SAAO;AACR;AAEO,SAAS,qBAAqB,GAAU,MAAyB;AACvE,QAAM,SAAS,EAAE;AACjB,QAAM,MAAM,QAAQ,QAA2B,eAAe;AAC9D,MAAI,CAAC,OAAO,CAAC,KAAK,SAAS,GAAG,EAAG;AACjC,QAAM,QAAQ,IAAI,QAAQ,UAAU;AACpC,QAAM,OAAO,OAAO,cAAc,UAAU;AAC5C,QAAM,OAAO,MAAM,eAAe;AAClC,MAAI,CAAC,KAAM;AACX,OAAK,UAAU,WAAW,UAAU,IAAI,EAAE;AAAA,IACzC,MAAM,YAAY,GAAG;AAAA,IACrB,MAAM,YAAY,KAAK,IAAI;AAAA,EAC5B;AACD;AAYO,SAAS,eAAe,IAAoB;AAKlD,QAAM,aAAuB,CAAC;AAC9B,QAAM,uBAAuB,CAAC,MAAc,cAAkB,CAAC;AAC/D,QAAM,OAAO,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA,IAKf;AAAA,IACA,CAAC,QAAQ,MAA0B,SAAiB;AACnD,YAAM,UAAU,KAAK,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM;AACtF,YAAM,YAAY,kBAAkB,MAAM,IAAI;AAC9C,YAAM,YAAY,cAAc,SAAS,oBAAoB,SAAS,MAAM;AAM5E,YAAM,UAAU,QAAQ,QAAQ,OAAO,EAAE;AACzC,iBAAW;AAAA,QACV,gGAAgG,SAAS,0IAA0I,SAAS,GAAG,UAAU,8EAA8E,SAAS,IAAI,OAAO;AAAA,MAC5W;AAKA,aAAO;AAAA;AAAA,EAAO,qBAAqB,WAAW,SAAS,CAAC,CAAC;AAAA;AAAA;AAAA,IAC1D;AAAA,EACD;AAEA,MAAI,OAAO,KAET,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EAEpB,QAAQ,gBAAgB,aAAa,EACrC,QAAQ,eAAe,aAAa,EACpC,QAAQ,cAAc,aAAa,EAEnC,QAAQ,WAAW,QAAQ,EAE3B,QAAQ,sBAAsB,8BAA8B,EAE5D,QAAQ,kBAAkB,qBAAqB,EAE/C,QAAQ,cAAc,aAAa,EAEnC,QAAQ,cAAc,iBAAiB,EAEvC,QAAQ,6BAA6B,2BAA2B,EAEhE;AAAA,IACA;AAAA,IACA;AAAA,EACD,EAEC;AAAA,IACA;AAAA,IACA;AAAA,EACD,EAEC,QAAQ,iBAAiB,6BAA6B,EAEtD,QAAQ,iBAAiB,aAAa,EAGtC,QAAQ,kBAAkB,eAAe;AAM3C,QAAM,SAAmB,CAAC;AAC1B,QAAM,mBAAmB,CAAC,MAAc,UAAc,CAAC;AACvD,SAAO,KAAK;AAAA;AAAA,IAEX;AAAA,IACA,CAAC,QAAQ,YAAoB,cAAsB;AAClD,YAAM,QAAQ,CAAC,SACd,KAAK,KAAK,EAAE,QAAQ,YAAY,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AACnE,YAAM,OAAO,MAAM,UAAU,EAC3B,IAAI,CAAC,MAAM,OAAO,CAAC,OAAO,EAC1B,KAAK,EAAE;AACT,YAAM,OAAO,UACX,KAAK,EACL,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,OAAO,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,OAAO,EAC5E,KAAK,EAAE;AACT,aAAO;AAAA,QACN,iEAAiE,IAAI,uBAAuB,IAAI;AAAA,MACjG;AACA,aAAO;AAAA;AAAA,EAAO,iBAAiB,OAAO,SAAS,CAAC,CAAC;AAAA;AAAA;AAAA,IAClD;AAAA,EACD;AAKA,SAAO,KACL,QAAQ,2BAA2B,CAAC,MAAM,OAAO,EAAE,QAAQ,OAAO,EAAE,CAAC;AAAA,CAAS,EAC9E;AAAA,IACA;AAAA,IACA,CAAC,MAAM,OAAO,EAAE,QAAQ,OAAO,EAAE,EAAE,QAAQ,eAAe,QAAQ,CAAC;AAAA;AAAA,EACpE;AAED,SAAO,KAEL,QAAQ,SAAS,SAAS,EAE1B,QAAQ,OAAO,QAAQ;AAKzB,SAAO,KACL,QAAQ,4BAA4B,IAAI,EACxC,QAAQ,8BAA8B,IAAI,EAC1C,QAAQ,eAAe,KAAK;AAG9B,MACC,CAAC,KAAK,WAAW,IAAI,KACrB,CAAC,KAAK,WAAW,KAAK,KACtB,CAAC,KAAK,WAAW,KAAK,KACtB,CAAC,KAAK,WAAW,aAAa,KAC9B,CAAC,KAAK,WAAW,KAAK,GACrB;AACD,WAAO,MAAM,IAAI;AAAA,EAClB;AAGA,MAAI,OAAO,SAAS,GAAG;AAEtB,WAAO,KAAK,QAAQ,2BAA2B,CAAC,IAAI,QAAgB;AACnE,YAAM,IAAI,OAAO,SAAS,KAAK,EAAE;AACjC,aAAO,OAAO,CAAC,KAAK;AAAA,IACrB,CAAC;AAGD,WAAO,KAAK,QAAQ,8DAA8D,IAAI;AAAA,EACvF;AAIA,SAAO,KAAK,QAAQ,qDAAqD,IAAI;AAK7E,MAAI,WAAW,SAAS,GAAG;AAE1B,WAAO,KAAK,QAAQ,+BAA+B,CAAC,IAAI,QAAgB;AACvE,YAAM,IAAI,OAAO,SAAS,KAAK,EAAE;AACjC,aAAO,WAAW,CAAC,KAAK;AAAA,IACzB,CAAC;AAID,WAAO,KAAK,QAAQ,wDAAwD,IAAI;AAAA,EACjF;AAEA,SAAO;AACR;AAOO,SAAS,YAAY,MAAsB;AACjD,SAAO,KACL,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB;AAAA,IACA;AAAA,IACA;AAAA,EACD,EACC,QAAQ,OAAO,QAAQ;AAC1B;AAOO,SAAS,gBAAgB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACD,GAIG;AACF,QAAM,UAAUD,QAAuB,IAAI;AAC3C,QAAM,OAAO,aAAa,eAAe,eAAe,YAAY,IAAI;AAOxE,EAAAD,WAAU,MAAM;AACf,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AAEX,UAAM,mBAAmB,CAAC,OAAyB;AAElD,YAAM,gBAAgB,MAAM,KAAK,GAAG,QAAQ,EAAE;AAAA,QAC7C,CAAC,MAAM,EAAE,YAAY;AAAA,MACtB;AACA,UAAI,cAAe,QAAO;AAC1B,YAAM,OAAO,GAAG,eAAe;AAC/B,aAAO,KAAK,QAAQ,UAAU,EAAE,MAAM;AAAA,IACvC;AAEA,UAAM,gBAAgB,MAAM;AAC3B,YAAM,aAAa,KAAK,iBAAiB,QAAQ;AACjD,iBAAW,QAAQ,CAAC,OAAO;AAC1B,YAAI,iBAAiB,EAAE,EAAG,IAAG,OAAO;AAAA,MACrC,CAAC;AAAA,IACF;AACA,kBAAc;AAAA,EACf,GAAG,CAAC,IAAI,CAAC;AAKT,EAAAA,WAAU,MAAM;AACf,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AACX,UAAM,UAAU,CAAC,MAAa;AAC7B,2BAAqB,GAAG,IAAI;AAAA,IAC7B;AACA,SAAK,iBAAiB,SAAS,OAAO;AACtC,WAAO,MAAM;AACZ,WAAK,oBAAoB,SAAS,OAAO;AAAA,IAC1C;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,MAAI,CAAC,KAAM,QAAO;AAElB,SACC,gBAAAE;AAAA,IAAC;AAAA;AAAA,MACA,KAAK;AAAA,MACL,WAAW,eAAe,aAAa,EAAE;AAAA,MAIzC,yBAAyB,EAAE,QAAQ,KAAK;AAAA;AAAA,EACzC;AAEF;AAEA,SAAS,YAAY,KAAwB,SAAS,OAAO;AAC5D,QAAM,QAAQ,IAAI,cAAc,qBAAqB;AACrD,MAAI,CAAC,MAAO;AACZ,QAAM,WAAW,MAAM,eAAe;AACtC,QAAM,cAAc,SAAS,WAAW;AACxC,MAAI,UAAU,IAAI,SAAS,yBAAyB,sBAAsB;AAC1E,aAAW,MAAM;AAChB,UAAM,cAAc;AACpB,QAAI,UAAU,OAAO,wBAAwB,sBAAsB;AAAA,EACpE,GAAG,IAAI;AACR;AAQO,SAAS,sBAAsB,SAAyB;AAC9D,MAAI,MAAM;AACV,QAAM,UAAU,IAAI,MAAM,MAAM,KAAK,CAAC,GAAG;AACzC,MAAI,SAAS,MAAM,EAAG,QAAO;AAG7B,QAAM,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,GAAG;AACxC,MAAI,OAAO,MAAM,EAAG,QAAO;AAC3B,SAAO;AACR;;;AC3TS,SAkGP,YAAAC,WAlGO,OAAAC,MAUJ,QAAAC,aAVI;AARF,SAAS,kBAAkB;AAAA,EACjC;AAAA,EACA;AACD,GAGG;AACF,MAAI,aAAa,CAAC,OAAO;AACxB,WAAO,gBAAAD,KAAC,mBAAgB;AAAA,EACzB;AAEA,QAAM,QAAQ,MAAM,aAAa,WAAW,MAAM,aAAa,YAAY,MAAM,aAAa,QAAQ;AAEtG,SACC,gBAAAC,MAAC,SAAI,WAAU,qBACd;AAAA,oBAAAA,MAAC,SAAI,WAAU,4BACd;AAAA,sBAAAD,KAAC,QAAG,WAAU,2BAA2B,gBAAM,OAAM;AAAA,OACnD,SAAS,MAAM,gBAChB,gBAAAC,MAAC,SAAI,WAAU,0BACb;AAAA,iBAAS,gBAAAD,KAAC,UAAK,WAAU,0BAA0B,iBAAM;AAAA,QACzD,MAAM,eACN,gBAAAA,KAAC,UAAK,WAAU,0BACd,6BAAmB,MAAM,WAAW,GACtC;AAAA,SAEF;AAAA,OAEF;AAAA,KACE,MAAM,QAAQ,MAAM,aACrB,gBAAAA,KAAC,SAAI,WAAU,0BACd,0BAAAA,KAAC,mBAAgB,UAAU,MAAM,UAAU,cAAc,MAAM,MAAM,GACtE;AAAA,KAEF;AAEF;AAkBA,SAAS,kBAAkB;AAC1B,QAAM,WAA2E;AAAA,IAChF;AAAA,MACC,aAAa;AAAA,MACb,OAAO;AAAA,QACN,EAAE,IAAI,OAAO,IAAI,MAAM;AAAA,QACvB,EAAE,IAAI,OAAO,IAAI,MAAM;AAAA,QACvB,EAAE,IAAI,OAAO,IAAI,MAAM;AAAA,MACxB;AAAA,IACD;AAAA,IACA;AAAA,MACC,aAAa;AAAA,MACb,OAAO;AAAA,QACN,EAAE,IAAI,OAAO,IAAI,MAAM;AAAA,QACvB,EAAE,IAAI,OAAO,IAAI,MAAM;AAAA,MACxB;AAAA,IACD;AAAA,EACD;AAEA,SACC,gBAAAC,MAAC,SAAI,WAAU,qBACd;AAAA,oBAAAA,MAAC,SAAI,WAAU,4BACd;AAAA,sBAAAD,KAAC,QAAG,WAAU,2BACb,0BAAAA,KAAC,UAAK,WAAU,iCAAgC,GACjD;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,0BACd;AAAA,wBAAAD,KAAC,UAAK,WAAU,iCAAgC;AAAA,QAChD,gBAAAA,KAAC,UAAK,WAAU,gCAA+B;AAAA,SAChD;AAAA,OACD;AAAA,IACA,gBAAAA,KAAC,SAAI,WAAU,0BACd,0BAAAA,KAAC,SAAI,WAAU,eACb,mBAAS,IAAI,CAAC,GAAG,MACjB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEA,aAAa,EAAE;AAAA,QACf,OAAO,EAAE;AAAA;AAAA,MAFJ;AAAA,IAGN,CACA,GACF,GACD;AAAA,KACD;AAEF;AAEA,SAAS,gBAAgB;AAAA,EACxB;AAAA,EACA;AACD,GAGG;AACF,SACC,gBAAAC,MAAAF,WAAA,EACC;AAAA,oBAAAC,KAAC,QACA,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACA,WAAU;AAAA,QACV,OAAO,EAAE,SAAS,SAAS,OAAO,YAAY;AAAA;AAAA,IAC/C,GACD;AAAA,IACC,MAAM,IAAI,CAAC,MAAM,MACjB,gBAAAA,KAAC,QACA,0BAAAA,KAAC,QACA,0BAAAC,MAAC,SAAI,WAAU,4BACd;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACA,WAAU;AAAA,UACV,OAAO,EAAE,SAAS,SAAS,OAAO,KAAK,GAAG;AAAA;AAAA,MAC3C;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACA,WAAU;AAAA,UACV,OAAO,EAAE,SAAS,SAAS,OAAO,KAAK,IAAI,WAAW,EAAE;AAAA;AAAA,MACzD;AAAA,OACD,GACD,KAZQ,CAaT,CACA;AAAA,KACF;AAEF;;;ACrIA,SAAS,eAAAE,eAAa,UAAAC,SAAQ,YAAAC,kBAAgB;AA+CxC,SACC,OAAAC,MADD,QAAAC,aAAA;AAxCC,SAAS,gBAAgB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GASG;AACF,QAAM,CAAC,YAAY,aAAa,IAAIF,WAAS,EAAE;AAC/C,QAAM,cAAcD,QAAsC,MAAS;AAEnE,QAAM,eAAeD;AAAA,IACpB,CAAC,UAAkB;AAClB,oBAAc,KAAK;AACnB,UAAI,CAAC,SAAU;AACf,mBAAa,YAAY,OAAO;AAChC,kBAAY,UAAU,WAAW,MAAM;AACtC,iBAAS,MAAM,KAAK,CAAC;AAAA,MACtB,GAAG,GAAG;AAAA,IACP;AAAA,IACA,CAAC,QAAQ;AAAA,EACV;AAEA,SACC,gBAAAI,MAAC,SAAI,WAAU,mBAEb;AAAA,gBACA,gBAAAD,KAAC,SAAI,WAAU,qBACd,0BAAAC,MAAC,SAAI,WAAU,yBACd;AAAA,sBAAAA,MAAC,SAAI,WAAU,0BAAyB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAClJ;AAAA,wBAAAD,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,QAC9B,gBAAAA,KAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,SAAQ;AAAA,SAC7C;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,aAAa,qBAAqB,EAAE,eAAe;AAAA,UACnD,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAK;AAAA;AAAA,MAC7C;AAAA,OACD,GACD;AAAA,IAIA,aAAa,QAAQ,WAAW,KAChC,gBAAAA,KAAC,SAAI,WAAU,uBACb,WAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACf,gBAAAC,MAAC,SAAY,WAAU,4BACtB;AAAA,sBAAAD,KAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,OAAO,QAAQ,GAAG,GAAG;AAAA,MACnF,gBAAAA,KAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,OAAO,QAAQ,GAAG,GAAG;AAAA,MACnF,gBAAAA,KAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,OAAO,QAAQ,GAAG,GAAG;AAAA,SAH1E,CAIV,CACA,GACF;AAAA,IAIA,CAAC,aAAa,QAAQ,WAAW,KACjC,gBAAAC,MAAC,SAAI,WAAU,oBACd;AAAA,sBAAAD,KAAC,SAAI,WAAU,0BACb,uBAAa,EAAE,mBAAmB,IAAI,EAAE,oBAAoB,GAC9D;AAAA,MACA,gBAAAA,KAAC,SAAI,WAAU,yBACb,uBAAa,EAAE,sBAAsB,IAAI,EAAE,mBAAmB,GAChE;AAAA,OACD;AAAA,IAIA,QAAQ,SAAS,KACjB,gBAAAC,MAAC,SAAI,WAAU,sBACb;AAAA,cAAQ,IAAI,CAAC,UACb,gBAAAD,KAAC,oBAAkC,OAAc,UAAoB,WAA9C,MAAM,IAA0D,CACvF;AAAA,MACA,WACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS;AAAA,UACT,UAAU;AAAA,UAET,sBAAY,EAAE,gBAAgB,IAAI,EAAE,kBAAkB;AAAA;AAAA,MACxD;AAAA,OAEF;AAAA,KAEF;AAEF;AAIA,SAAS,aAAa,MAAqB,SAAS,IAAY;AAC/D,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,QAAQ,KAAK,QAAQ,oBAAoB,EAAE,EAAE,KAAK;AACxD,SAAO,MAAM,SAAS,SAAS,GAAG,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ;AACjE;AAEA,SAAS,iBAAiB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACD,GAIG;AACF,QAAM,EAAE,aAAa,IAAI;AAGzB,QAAM,QAAQ,SAAS,aACpB,aAAa,QAAQ,UAAU,KAAK,OACpC,aAAa,WAAW,aAAa,YAAY,aAAa,QAAQ;AAEzE,QAAM,gBAAgB,SAAS,iBAC3B,QAAQ,kBAAkB,SAAS,MAAM,OAAO,aAAa,QAAQ,aAAa,MAAM,OACzF,aAAa,WAAW,aAAa,WAAW,aAAa,eAAe;AAE/E,QAAM,UAAU,gBAAgB,aAAa,aAAa,IAAI,aAAa,MAAM,IAAI;AAErF,SACC,gBAAAA,KAAC,YAAO,MAAK,UAAS,WAAU,oBAAmB,SAAS,MAAM,SAAS,MAAM,IAAI,GACpF,0BAAAC,MAAC,SAAI,WAAU,yBACd;AAAA,oBAAAA,MAAC,SAAI,WAAU,yBACd;AAAA,sBAAAD,KAAC,UAAK,WAAU,0BAA0B,gBAAM,OAAM;AAAA,MACrD,WACA,gBAAAA,KAAC,UAAK,WAAU,yBAAyB,mBAAQ;AAAA,OAEhD,SAAS,MAAM,gBAChB,gBAAAC,MAAC,SAAI,WAAU,yBACb;AAAA,iBAAS,gBAAAD,KAAC,UAAK,WAAU,0BAA0B,iBAAM;AAAA,QACzD,MAAM,eACN,gBAAAA,KAAC,UAAK,WAAU,yBAAyB,6BAAmB,MAAM,WAAW,GAAE;AAAA,SAEjF;AAAA,OAEF;AAAA,IACA,gBAAAA,KAAC,SAAI,WAAU,4BAA2B,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACpJ,0BAAAA,KAAC,cAAS,QAAO,kBAAiB,GACnC;AAAA,KACD,GACD;AAEF;;;AClKA,SAAS,aAAAE,YAAW,UAAAC,gBAAc;;;ACAlC,SAAS,eAAAC,eAAa,UAAAC,UAAQ,YAAAC,kBAAgB;AAI9C,IAAMC,cAAiC,CAAC;AAIxC,SAAS,cAAc,OAAe,MAAc;AACnD,SAAO,WAAW,KAAK,IAAI,IAAI;AAChC;AAEA,SAAS,SAAS,OAAe,MAAc,WAAmB;AACjE,SAAO,WAAW,KAAK,IAAI,IAAI,UAAU,SAAS;AACnD;AAEA,SAASC,WAAU,OAAe,MAAc,MAAc;AAC7D,SAAO,WAAW,KAAK,IAAI,IAAI,WAAW,IAAI;AAC/C;AAQA,SAASC,WAAa,OAAmD,KAAuB;AAC/F,QAAM,QAAQ,MAAM,IAAI,GAAG;AAC3B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,KAAK,IAAI,IAAI,MAAM,KAAK,kBAAmB,QAAO;AACtD,SAAO,MAAM;AACd;AAMO,SAAS,qBAAqB,OAAe;AACnD,QAAM,EAAE,QAAQ,MAAM,IAAI,iBAAiB;AAC3C,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,aAAa,WAAW,KAAKF;AACzE,QAAM,MAAM,YAAY,KAAK,CAACG,OAAMA,GAAE,OAAO,KAAK,KAAK;AAEvD,QAAM,OAAO,UAAU;AACvB,QAAM,QAAQ,MAAM,SAAS,EAAE;AAG/B,QAAM,mBAAmBD,WAA8B,OAAO,cAAc,OAAO,IAAI,CAAC;AACxF,QAAM,CAAC,YAAY,aAAa,IAAIE,WAA6B,oBAAoB,CAAC,CAAC;AACvF,QAAM,CAAC,qBAAqB,sBAAsB,IAAIA,WAAS,KAAK;AAGpE,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAA6B,CAAC,CAAC;AACzD,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,WAAS,KAAK;AAC1D,QAAM,CAAC,cAAc,eAAe,IAAIA,WAAS,KAAK;AACtD,QAAM,eAAeC,SAAO,CAAC;AAG7B,QAAM,CAAC,QAAQ,SAAS,IAAID,WAAoC,IAAI;AACpE,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,WAAS,KAAK;AAG5D,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,WAAkC,IAAI;AAGlF,QAAM,mBAAmBC,SAA2B,oBAAoB,CAAC,CAAC;AAG1E,QAAM,kBAAkBC,cAAY,YAAY;AAC/C,QAAI,CAAC,IAAK;AACV,2BAAuB,IAAI;AAC3B,QAAI;AACH,YAAM,SAAS,MAAM,OAAO,OAAO,WAAW,MAAM;AAAA,QACnD;AAAA,QACA,MAAM;AAAA,QACN,OAAO;AAAA,QACP,UAAU,UAAU;AAAA,MACrB,CAAC;AACD,UAAI,OAAO,OAAO;AACjB,yBAAiB,UAAU,OAAO;AAClC,sBAAc,OAAO,KAAK;AAC1B,cAAM,SAAS,EAAE,gBAAgB,cAAc,OAAO,UAAU,CAAC,GAAG,OAAO,KAAK;AAAA,MACjF;AAAA,IACD,SAAS,KAAK;AACb,cAAQ,MAAM,4CAA4C,GAAG;AAAA,IAC9D,UAAE;AACD,6BAAuB,KAAK;AAAA,IAC7B;AAAA,EACD,GAAG,CAAC,QAAQ,OAAO,KAAK,KAAK,CAAC;AAG9B,QAAM,YAAYA,cAAY,MAAM;AACnC,QAAI,OAAO,WAAW,WAAW,GAAG;AACnC,sBAAgB;AAAA,IACjB;AAAA,EACD,GAAG,CAAC,iBAAiB,KAAK,WAAW,MAAM,CAAC;AAG5C,QAAM,aAAaA;AAAA,IAClB,OAAO,SAAmF;AACzF,UAAI,CAAC,KAAK,eAAgB;AAC1B,YAAM,IAAI,MAAM,QAAQ;AACxB,YAAM,QAAQ,MAAM,SAAS,MAAM;AAEnC,wBAAkB,IAAI;AACtB,UAAI;AACH,cAAM,SAAS,MAAM,OAAO,OAAO,WAAW,MAAM;AAAA,UACnD;AAAA,UACA,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ,MAAM;AAAA,UACd,WAAW,MAAM;AAAA,UACjB,YAAY,IAAI;AAAA,UAChB,UAAU,UAAU;AAAA,QACrB,CAAC;AACD,YAAI,OAAO,OAAO;AACjB,mBAAS,CAAC,SAAS;AAClB,kBAAM,YAAY,QAAQ,OAAO,QAAS,CAAC,GAAG,MAAM,GAAG,OAAO,KAAM;AACpE,gBAAI,CAAC,MAAM,UAAU,MAAM,WAAW;AACrC,oBAAM,SAAS,EAAE;AAAA,gBAChB,SAAS,OAAO,UAAU,GAAG,KAAK,SAAS;AAAA,gBAC3C,EAAE,OAAO,WAAW,SAAS,OAAO,SAAS,MAAM,EAAE;AAAA,cACtD;AAAA,YACD;AACA,mBAAO;AAAA,UACR,CAAC;AACD,0BAAgB,OAAO,OAAO;AAC9B,uBAAa,UAAU;AAAA,QACxB;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,uCAAuC,GAAG;AAAA,MACzD,UAAE;AACD,0BAAkB,KAAK;AAAA,MACxB;AAAA,IACD;AAAA,IACA,CAAC,QAAQ,OAAO,KAAK,KAAK;AAAA,EAC3B;AAGA,QAAM,iBAAiBA;AAAA,IACtB,CAAC,aAA+B;AAC/B,wBAAkB,QAAQ;AAC1B,gBAAU,IAAI;AAEd,YAAM,SAASJ;AAAA,QACd,MAAM,SAAS,EAAE;AAAA,QACjB,SAAS,OAAO,UAAU,GAAG,SAAS,IAAI;AAAA,MAC3C;AACA,UAAI,QAAQ;AACX,iBAAS,OAAO,KAAK;AACrB,wBAAgB,OAAO,OAAO;AAC9B,qBAAa,UAAU,OAAO;AAC9B;AAAA,MACD;AAEA,eAAS,CAAC,CAAC;AACX,iBAAW,EAAE,MAAM,GAAG,OAAO,MAAM,WAAW,SAAS,KAAK,CAAC;AAAA,IAC9D;AAAA,IACA,CAAC,YAAY,OAAO,KAAK;AAAA,EAC1B;AAGA,QAAM,gBAAgBI,cAAY,MAAM;AACvC,QAAI,CAAC,gBAAgB,kBAAkB,CAAC,eAAgB;AACxD,eAAW;AAAA,MACV,MAAM,aAAa,UAAU;AAAA,MAC7B,WAAW,eAAe;AAAA,IAC3B,CAAC;AAAA,EACF,GAAG,CAAC,YAAY,cAAc,gBAAgB,cAAc,CAAC;AAG7D,QAAM,cAAcA;AAAA,IACnB,CAAC,UAAkB;AAClB,eAAS,CAAC,CAAC;AACX,iBAAW;AAAA,QACV,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ,SAAS;AAAA,QACjB,WAAW,QAAQ,SAAY,gBAAgB;AAAA,MAChD,CAAC;AAAA,IACF;AAAA,IACA,CAAC,YAAY,cAAc;AAAA,EAC5B;AAGA,QAAM,cAAcA;AAAA,IACnB,OAAO,SAAiB;AACvB,UAAI,CAAC,KAAK,eAAgB;AAE1B,YAAM,SAASJ;AAAA,QACd,MAAM,SAAS,EAAE;AAAA,QACjBD,WAAU,OAAO,UAAU,GAAG,IAAI;AAAA,MACnC;AACA,UAAI,QAAQ;AACX,kBAAU,MAAM;AAChB;AAAA,MACD;AAEA,yBAAmB,IAAI;AACvB,UAAI;AACH,cAAM,SAAS,MAAM,OAAO,OAAO,WAAW,MAAM;AAAA,UACnD;AAAA,UACA;AAAA,UACA,YAAY,IAAI;AAAA,UAChB,UAAU,UAAU;AAAA,QACrB,CAAC;AACD,YAAI,OAAO,OAAO;AACjB,gBAAM,QAAQ,OAAO;AACrB,oBAAU,KAAK;AACf,gBAAM,SAAS,EAAE;AAAA,YAChBA,WAAU,OAAO,UAAU,GAAG,IAAI;AAAA,YAClC;AAAA,UACD;AAAA,QACD;AAAA,MACD,SAAS,KAAK;AACb,gBAAQ,MAAM,wCAAwC,GAAG;AAAA,MAC1D,UAAE;AACD,2BAAmB,KAAK;AAAA,MACzB;AAAA,IACD;AAAA,IACA,CAAC,QAAQ,OAAO,KAAK,KAAK;AAAA,EAC3B;AAGA,QAAM,mBAAmBK;AAAA,IACxB,CAAC,UAAkB;AAClB,UAAI,CAAC,MAAM,KAAK,GAAG;AAClB,sBAAc,iBAAiB,OAAO;AACtC;AAAA,MACD;AACA,YAAM,IAAI,MAAM,YAAY;AAC5B;AAAA,QACC,iBAAiB,QAAQ;AAAA,UAAO,CAAC,QAChC,IAAI,MAAM,YAAY,EAAE,SAAS,CAAC,MACjC,IAAI,aAAa,eAAe,IAAI,YAAY,EAAE,SAAS,CAAC;AAAA,QAC9D;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAC;AAAA,EACF;AAEA,QAAM,cAAcA,cAAY,MAAM;AACrC,cAAU,IAAI;AAAA,EACf,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgBA,cAAY,MAAM;AACvC,sBAAkB,IAAI;AACtB,aAAS,CAAC,CAAC;AACX,cAAU,IAAI;AAAA,EACf,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;;;ADzMS,gBAAAC,YAAA;AAtDF,SAAS,sBAAsB;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAMG;AACF,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI,qBAAqB,IAAI,EAAE;AAG/B,EAAAC,WAAU,MAAM;AACf,cAAU;AAAA,EACX,GAAG,CAAC,SAAS,CAAC;AAGd,EAAAA,WAAU,MAAM;AACf,QAAI,cAAc,YAAY,kBAAkB;AAC/C,kBAAY,UAAU;AAAA,IACvB;AAAA,EACD,GAAG,CAAC,YAAY,SAAS,WAAW,CAAC;AAGrC,QAAM,cAAcC,SAAO,OAAO;AAClC,EAAAD,WAAU,MAAM;AACf,QAAI,YAAY,YAAY,sBAAsB,YAAY,MAAM;AACnE,oBAAc;AAAA,IACf;AACA,gBAAY,UAAU;AAAA,EACvB,GAAG,CAAC,SAAS,aAAa,CAAC;AAG3B,MAAI,YAAY,oBAAoB,YAAY;AAC/C,WAAO,gBAAAD,KAAC,qBAAkB,OAAO,QAAQ,WAAW,iBAAiB;AAAA,EACtE;AAGA,MAAI,YAAY,sBAAsB,gBAAgB;AACrD,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,SAAS;AAAA,QACT,WAAW;AAAA,QACX,SAAS;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,mBAAmB,EAAE,eAAe;AAAA,QACpC,SAAS,IAAI;AAAA;AAAA,IACd;AAAA,EAEF;AAGA,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,SAAS;AAAA,MACT,WAAW;AAAA,MACX,SAAS;AAAA,MACT,UAAU,CAAC,SAAS;AACnB,cAAM,MAAM,WAAW,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAClD,YAAI,KAAK;AACR,yBAAe,GAAG;AAClB,2BAAiB,GAAG;AAAA,QACrB;AAAA,MACD;AAAA,MACA,YAAY,MAAM;AAAA,MAAC;AAAA,MACnB,UAAU;AAAA,MACV,mBAAmB,EAAE,eAAe;AAAA;AAAA,EACrC;AAEF;;;AL3EG,gBAAAG,aAAA;AAlBI,SAAS,eAAe;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAOG;AAEF,MAAI,IAAI,YAAY,aAAa,IAAI,gBAAgB;AACpD,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA,SAAS,WAAW;AAAA,QACpB;AAAA,QACA,kBAAkB,qBAAqB,MAAM;AAAA,QAAC;AAAA,QAC9C;AAAA;AAAA,IACD;AAAA,EAEF;AAGA,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACD;AAEF;AAIA,SAAS,mBAAmB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAKG;AACF,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI,cAAc,IAAI,EAAE;AAExB,EAAAC,YAAU,MAAM;AACf,QAAI,WAAY,aAAY,UAAU;AAAA,EACvC,GAAG,CAAC,YAAY,WAAW,CAAC;AAE5B,QAAM,eAAeC;AAAA,IACpB,CAAC,UAAkB;AAClB,mBAAa,EAAE,MAAM,GAAG,QAAQ,SAAS,QAAW,OAAO,KAAK,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,YAAY;AAAA,EACd;AAEA,MAAI,cAAc,YAAY;AAC7B,WAAO,gBAAAF,MAAC,qBAAkB,OAAO,QAAQ,WAAW,iBAAiB;AAAA,EACtE;AAEA,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,mBAAmB,GAAG,EAAE,eAAe,CAAC,IAAI,aAAa,IAAI,KAAK,EAAE,YAAY,CAAC;AAAA,MACjF,SAAS,IAAI;AAAA;AAAA,EACd;AAEF;;;AO/EQ,gBAAAG,aAAA;AAXR,IAAM,WAAqC;AAAA,EAC1C,MAAM;AAAA,EACN,WAAW;AAAA,EACX,WAAW;AAAA,EACX,eAAe;AAAA,EACf,WAAW;AAAA,EACX,MAAM;AACP;AAEO,SAAS,wBAAwB,EAAE,KAAK,GAAqB;AACnE,QAAM,OAAO,SAAS,IAAI,KAAK;AAC/B,SAAO,gBAAAA,MAAC,QAAK;AACd;;;ACzBA,SAAS,aAAAC,aAAW,WAAAC,UAAS,UAAAC,UAAQ,YAAAC,kBAAgB;AA4IjD,gBAAAC,OACA,QAAAC,aADA;AAjIJ,IAAM,aAAa;AAEnB,SAAS,iBAA0B;AAClC,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI,OAAO,OAAO,iBAAiB,eAAe,OAAO,aAAa,QAAQ,UAAU,MAAM,KAAK;AAClG,WAAO;AAAA,EACR;AACA,QAAM,SAAS,OAAO,UAAU,UAAU;AAC1C,SAAO,OAAO,SAAS,WAAW,KAAK,OAAO,SAAS,UAAU;AAClE;AAEA,SAAS,SAAS,MAA4B;AAC7C,MAAI,KAAK,UAAW,QAAO;AAC3B,MAAI,KAAK,UAAW,QAAO;AAC3B,MAAI,KAAK,OAAQ,QAAO;AACxB,SAAO,KAAK;AACb;AAEO,SAAS,qBAAqB;AACpC,QAAM,CAAC,SAAS,UAAU,IAAIC,WAAS,KAAK;AAC5C,QAAM,CAAC,MAAM,OAAO,IAAIA,WAAS,IAAI;AACrC,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAAuB,CAAC,CAAC;AACrD,QAAM,YAAYC,SAAqB,CAAC,CAAC;AAKzC,QAAM,WAAW,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAC7D,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,QAAQ;AACpD,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AACvD,QAAM,kBAAkB,eAAe,CAAC,MAAM,EAAE,YAAY;AAC5D,QAAM,EAAE,MAAM,IAAI,iBAAiB;AAEnC,EAAAC,YAAU,MAAM;AACf,eAAW,eAAe,CAAC;AAAA,EAC5B,GAAG,CAAC,CAAC;AAEL,QAAM,YAAYC;AAAA,IACjB,MAAM,CAAC,OAAqC;AAC3C,YAAM,IAAgB;AAAA,QACrB,GAAG;AAAA,QACH,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,QAC3D,GAAG,KAAK,IAAI;AAAA,MACb;AACA,gBAAU,UAAU,CAAC,GAAG,GAAG,UAAU,OAAO,EAAE,MAAM,GAAG,UAAU;AACjE,gBAAU,UAAU,OAAO;AAAA,IAC5B;AAAA,IACA,CAAC;AAAA,EACF;AAIA,EAAAD,YAAU,MAAM;AACf,QAAI,CAAC,QAAS;AACd,QAAI,OAAO,WAAW,eAAe,OAAO,OAAO,UAAU,WAAY;AACzE,UAAM,gBAAgB,OAAO,MAAM,KAAK,MAAM;AAC9C,UAAM,WAAW,OAAO,OAA0B,SAAuB;AACxE,YAAM,MAAM,OAAO,UAAU,WAAW,QAAQ,iBAAiB,MAAM,MAAM,SAAS,IAAI,MAAM;AAChG,YAAM,SAAS,IAAI,SAAS,QAAQ;AACpC,UAAI,QAAQ;AACX,cAAM,SAAS,MAAM,WAAW,OAAO,UAAU,YAAY,EAAE,iBAAiB,OAAO,MAAM,SAAS;AACtG,cAAM,QAAQ,IAAI,MAAM,QAAQ,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AACvD,kBAAU,EAAE,MAAM,QAAQ,OAAO,UAAK,MAAM,IAAI,KAAK,IAAI,QAAQ,UAAU,MAAM,IAAI,EAAE,CAAC;AAAA,MACzF;AACA,UAAI;AACH,cAAM,MAAM,MAAM,cAAc,OAAO,IAAI;AAC3C,YAAI,QAAQ;AACX,gBAAM,QAAQ,IAAI,MAAM,QAAQ,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AACvD,oBAAU,EAAE,MAAM,QAAQ,OAAO,UAAK,IAAI,MAAM,IAAI,KAAK,GAAG,CAAC;AAAA,QAC9D;AACA,eAAO;AAAA,MACR,SAAS,KAAK;AACb,YAAI,QAAQ;AACX,gBAAM,QAAQ,IAAI,MAAM,QAAQ,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AACvD,oBAAU,EAAE,MAAM,SAAS,OAAO,UAAK,KAAK,IAAI,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE,CAAC;AAAA,QAC3G;AACA,cAAM;AAAA,MACP;AAAA,IACD;AACA,WAAO,QAAQ;AACf,WAAO,MAAM;AACZ,aAAO,QAAQ;AAAA,IAChB;AAAA,EACD,GAAG,CAAC,SAAS,SAAS,CAAC;AAGvB,EAAAA,YAAU,MAAM;AACf,QAAI,CAAC,QAAS;AACd,UAAM,WAAW,MAAM,SAAS,EAAE;AAClC,UAAM,SAAS;AAAA,MACd,qBAAqB,CAAC,OAAO;AAC5B,kBAAU,EAAE,MAAM,MAAM,OAAO,GAAG,MAAM,QAAQ,UAAU,EAAE,EAAE,CAAC;AAC/D,iBAAS,EAAE;AAAA,MACZ;AAAA,IACD,CAAC;AACD,WAAO,MAAM;AACZ,YAAM,SAAS,EAAE,qBAAqB,SAAS,CAAC;AAAA,IACjD;AAAA,EACD,GAAG,CAAC,SAAS,OAAO,SAAS,CAAC;AAG9B,QAAM,iBAAiB,WAAW,YAAY,IAAI,QAAQ,KAAK,CAAC,IAAI,CAAC;AACrE,QAAM,mBAAmBC;AAAA,IACxB,MAAM,eAAe,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE,IAAI,SAAS,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,KAAK,GAAG;AAAA,IACjF,CAAC,cAAc;AAAA,EAChB;AACA,QAAM,aAAaF,SAAO,gBAAgB;AAC1C,EAAAC,YAAU,MAAM;AACf,QAAI,CAAC,QAAS;AACd,QAAI,WAAW,YAAY,kBAAkB;AAC5C,iBAAW,UAAU;AACrB,gBAAU;AAAA,QACT,MAAM;AAAA,QACN,OAAO,YAAY,eAAe,MAAM;AAAA,QACxC,QAAQ,eACN,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,KAAK,EAAE,QAAQ,IAAI,MAAM,GAAG,EAAE,CAAC,EAAE,EAClE,KAAK,KAAK;AAAA,MACb,CAAC;AAAA,IACF;AAAA,EACD,GAAG,CAAC,kBAAkB,gBAAgB,SAAS,SAAS,CAAC;AAEzD,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,WAAW,WAAW,YAAY,IAAI,QAAQ,IAAI;AACxD,QAAM,OAAO,WAAW,gBAAgB,IAAI,QAAQ,IAAI;AAExD,SACC,gBAAAH,MAAC,SAAI,OAAO,OAAO,MAClB;AAAA,oBAAAA,MAAC,SAAI,OAAO,OAAO,QAClB;AAAA,sBAAAD,MAAC,YAAO,sBAAQ;AAAA,MAChB,gBAAAC,MAAC,UAAK,OAAO,OAAO,MAClB;AAAA;AAAA,QAAI;AAAA,QAAQ,WAAW,SAAS,MAAM,GAAG,EAAE,IAAI;AAAA,QAAI;AAAA,QAAU,eAAe;AAAA,QAAO;AAAA,QAAW,WAAW,MAAM;AAAA,QAAI;AAAA,QAAO,OAAO,MAAM;AAAA,SACzI;AAAA,MACA,gBAAAD,MAAC,YAAO,MAAK,UAAS,OAAO,OAAO,KAAK,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAI,iBAAO,SAAS,QAAO;AAAA,MACpG,gBAAAA,MAAC,YAAO,MAAK,UAAS,OAAO,OAAO,KAAK,SAAS,MAAM;AAAE,kBAAU,UAAU,CAAC;AAAG,kBAAU,CAAC,CAAC;AAAA,MAAG,GAAG,mBAAK;AAAA,OAC1G;AAAA,IACC,QACA,gBAAAC,MAAC,SAAI,OAAO,OAAO,MAClB;AAAA,sBAAAA,MAAC,SAAI,OAAO,OAAO,SAClB;AAAA,wBAAAD,MAAC,SAAI,OAAO,OAAO,cAAc,+BAAiB;AAAA,QACjD,eAAe,WAAW,IAC1B,gBAAAA,MAAC,SAAI,OAAO,OAAO,OAAO,mBAAK,IAE/B,eAAe,IAAI,CAAC,GAAG,MACtB,gBAAAC,MAAC,SAAe,OAAO,OAAO,KAC7B;AAAA,0BAAAD,MAAC,UAAK,OAAO,EAAE,GAAG,OAAO,OAAO,YAAY,SAAS,SAAS,CAAC,CAAC,EAAE,GAAI,aAAE;AAAA,UACxE,gBAAAA,MAAC,UAAK,OAAO,OAAO,QAAS,mBAAS,CAAC,GAAE;AAAA,UACzC,gBAAAA,MAAC,UAAK,OAAO,OAAO,IAAK,YAAE,UAAU,MAAM,IAAI,EAAE,GAAE;AAAA,UACnD,gBAAAA,MAAC,UAAK,OAAO,OAAO,MAAQ,aAAE,QAAQ,IAAI,MAAM,GAAG,EAAE,GAAE;AAAA,aAJ9C,EAAE,EAKZ,CACA;AAAA,SAEH;AAAA,MACA,gBAAAC,MAAC,SAAI,OAAO,OAAO,SAClB;AAAA,wBAAAD,MAAC,SAAI,OAAO,OAAO,cAAc,oBAAM;AAAA,QACtC,OAAO,WAAW,IAClB,gBAAAA,MAAC,SAAI,OAAO,OAAO,OAAO,iDAA8B,IAExD,OAAO,IAAI,CAAC,MACX,gBAAAC,MAAC,SAAe,OAAO,OAAO,KAC7B;AAAA,0BAAAD,MAAC,UAAK,OAAO,EAAE,GAAG,OAAO,OAAO,YAAY,UAAU,EAAE,IAAI,EAAE,GAAI,YAAE,MAAK;AAAA,UACzE,gBAAAA,MAAC,UAAK,OAAO,OAAO,IAAK,cAAI,KAAK,EAAE,CAAC,EAAE,YAAY,EAAE,MAAM,IAAI,EAAE,GAAE;AAAA,UACnE,gBAAAA,MAAC,UAAK,OAAO,OAAO,SAAU,YAAE,OAAM;AAAA,UACrC,EAAE,UAAU,gBAAAA,MAAC,UAAK,OAAO,OAAO,QAAS,YAAE,QAAO;AAAA,aAJ1C,EAAE,EAKZ,CACA;AAAA,SAEH;AAAA,OACD;AAAA,KAEF;AAEF;AAEA,SAAS,UAAU,GAAoB;AACtC,MAAI,MAAM,OAAW,QAAO;AAC5B,MAAI;AACH,UAAM,IAAI,KAAK,UAAU,CAAC;AAC1B,QAAI,CAAC,EAAG,QAAO;AACf,WAAO,EAAE,SAAS,MAAM,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,WAAM;AAAA,EACjD,QAAQ;AACP,WAAO,OAAO,CAAC;AAAA,EAChB;AACD;AAEA,SAAS,SAAS,QAAwB;AACzC,UAAQ,QAAQ;AAAA,IACf,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR;AACC,aAAO;AAAA,EACT;AACD;AAEA,SAAS,UAAU,MAAkC;AACpD,UAAQ,MAAM;AAAA,IACb,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,EACT;AACD;AAEA,IAAM,SAA8C;AAAA,EACnD,MAAM;AAAA,IACL,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,EAChB;AAAA,EACA,QAAQ;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,cAAc;AAAA,EACf;AAAA,EACA,MAAM,EAAE,MAAM,GAAG,OAAO,WAAW,UAAU,GAAG;AAAA,EAChD,KAAK;AAAA,IACJ,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,UAAU;AAAA,EACX;AAAA,EACA,MAAM,EAAE,SAAS,QAAQ,eAAe,UAAU,WAAW,qBAAqB,UAAU,OAAO;AAAA,EACnG,SAAS,EAAE,cAAc,qBAAqB,SAAS,WAAW;AAAA,EAClE,cAAc,EAAE,OAAO,WAAW,UAAU,IAAI,eAAe,aAAa,eAAe,KAAK,cAAc,EAAE;AAAA,EAChH,KAAK;AAAA,IACJ,SAAS;AAAA,IACT,qBAAqB;AAAA,IACrB,KAAK;AAAA,IACL,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,WAAW;AAAA,EACZ;AAAA,EACA,OAAO;AAAA,IACN,SAAS;AAAA,IACT,cAAc;AAAA,IACd,SAAS;AAAA,IACT,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,EACZ;AAAA,EACA,QAAQ,EAAE,OAAO,UAAU;AAAA,EAC3B,IAAI,EAAE,OAAO,WAAW,UAAU,GAAG;AAAA,EACrC,MAAM,EAAE,OAAO,WAAW,YAAY,UAAU,UAAU,UAAU,cAAc,WAAW;AAAA,EAC7F,SAAS,EAAE,OAAO,UAAU;AAAA,EAC5B,QAAQ,EAAE,YAAY,UAAU,OAAO,WAAW,UAAU,IAAI,YAAY,YAAY,WAAW,YAAY;AAAA,EAC/G,OAAO,EAAE,OAAO,WAAW,WAAW,UAAU,UAAU,GAAG;AAC9D;;;ACzRA,SAAS,aAAAM,aAAW,iBAAiB,UAAAC,UAAQ,YAAAC,kBAAgB;AAC7D,SAAS,oBAAoB;AA4FtB,SAgKL,YAAAC,WAhKK,OAAAC,OAWF,QAAAC,aAXE;AApDA,SAAS,cAAc;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAuB;AACtB,QAAM,cAAc,WAAW,MAAM;AACrC,QAAM,YAAYC,SAAuB,IAAI;AAE7C,QAAM,aACL,OAAO,OAAO,CAAC,MAAyD,EAAE,SAAS,OAAO,KAC1F,CAAC;AACF,QAAM,YACL,OAAO,OAAO,CAAC,MAAwD,EAAE,SAAS,MAAM,KAAK,CAAC;AAC/F,QAAM,eACL,OAAO;AAAA,IACN,CAAC,MAAgE,EAAE,SAAS;AAAA,EAC7E,KAAK,CAAC;AAIP,QAAM,UACL,OAAO;AAAA,IACN,CAAC,MAA0D,EAAE,SAAS;AAAA,EACvE,KAAK,CAAC;AACP,QAAM,UAAU,KAAK,SAAS;AAE9B,EAAAC,YAAU,MAAM;AACf,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,UAAW,WAAW,QAAQ,WAAW,OAAS;AACvD,UAAM,cAAc,CAAC,UAAiB;AACrC,2BAAqB,OAAO,MAAM;AAAA,IACnC;AACA,WAAO,iBAAiB,SAAS,WAAW;AAC5C,WAAO,MAAM;AACZ,aAAO,oBAAoB,SAAS,WAAW;AAAA,IAChD;AAAA,EACD,GAAG,CAAC,MAAM,CAAC;AAGX,SACC,gBAAAH,MAAC,SAAI,WAAW,UAAU,WAAW,IACpC,0BAAAC,MAAC,SAAI,WAAU,eAEb;AAAA,eAAW,SAAS,KACpB,gBAAAD,MAAC,SAAI,WAAU,iBACb,qBAAW,IAAI,CAAC,KAAK,MACrB,gBAAAA,MAAC,wBAA6B,KAAK,IAAI,OAAZ,CAAiB,CAC5C,GACF;AAAA,IAQA,WACA,gBAAAC,MAAC,SAAI,WAAU,iBAAgB,KAAK,WAClC;AAAA,iBAAW,QAAQ,WAAW,SAC9B,gBAAAD;AAAA,QAAC;AAAA;AAAA,UACA,yBAAyB;AAAA,YACxB,QAAQ,eAAe,YAAY,sBAAsB,IAAI,IAAI,IAAI;AAAA,UACtE;AAAA;AAAA,MACD,IAEA,gBAAAA,MAAC,UAAK,yBAAyB,EAAE,QAAQ,YAAY,IAAI,EAAE,GAAG;AAAA,MAE9D,aAAa,gBAAAA,MAAC,UAAK,WAAU,uBAAsB;AAAA,OACrD;AAAA,IAIA,UAAU,SAAS,KACnB,gBAAAA,MAAC,SAAI,WAAU,gBACb,oBAAU,IAAI,CAAC,MAAM,MACrB,gBAAAA,MAAC,YAAiB,QAAH,CAAe,CAC9B,GACF;AAAA,IAIA,aAAa,SAAS,KACtB,gBAAAA,MAAC,SAAI,WAAU,gBACb,uBAAa,IAAI,CAAC,IAAI,MACtB,gBAAAA,MAAC,mBAAwB,SAAS,MAAZ,CAAgB,CACtC,GACF;AAAA,IAIA,QAAQ,SAAS,KACjB,gBAAAA,MAAC,SAAI,WAAU,cACb,kBAAQ;AAAA,MAAI,CAAC,KAAK,MAClB,IAAI,YACH,gBAAAC;AAAA,QAAC;AAAA;AAAA,UAEA,MAAM,IAAI;AAAA,UACV,QAAO;AAAA,UACP,KAAI;AAAA,UACJ,WAAU;AAAA,UACV,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,UAElC;AAAA,4BAAAD,MAAC,UAAK,WAAU,eAAe,cAAI,GAAE;AAAA,YACrC,gBAAAA,MAAC,UAAK,WAAU,mBAAmB,cAAI,OAAM;AAAA;AAAA;AAAA,QARxC,IAAI;AAAA,MASV,IAEA,gBAAAC,MAAC,SAA0B,WAAU,aACpC;AAAA,wBAAAD,MAAC,UAAK,WAAU,eAAe,cAAI,GAAE;AAAA,QACrC,gBAAAA,MAAC,UAAK,WAAU,mBAAmB,cAAI,OAAM;AAAA,WAFpC,IAAI,WAGd;AAAA,IAEF,GACD;AAAA,IAKA,UAAU,SAAS,mBACnB,gBAAAA,MAAC,qBAAkB,UAAoB,OAAO,iBAAiB;AAAA,KAqB9D,MAAM;AACP,YAAM,YAAY,WAAW;AAC7B,YAAM,OAAO,YAAY,OAAQ,cAAc;AAC/C,YAAM,YAAY,cAAc,CAAC,CAAC,cAAc,CAAC,CAAC;AAClD,UAAI,CAAC,YAAY,CAAC,UAAW,QAAO;AACpC,aACC,gBAAAC,MAAC,SAAI,WAAU,eACb;AAAA,oBAAY,gBAAAD,MAAC,UAAK,WAAU,iBAAiB,gBAAK;AAAA,QAClD,YAAY,aAAa,gBAAAA,MAAC,UAAK,WAAU,mBAAkB,kBAAC;AAAA,QAC5D,aAAa,gBAAAA,MAAC,UAAK,WAAU,eAAe,qBAAU;AAAA,SACxD;AAAA,IAEF,GAAG;AAAA,KACJ,GACD;AAEF;AAIA,SAAS,kBAAkB;AAAA,EAC1B;AAAA,EACA;AACD,GAGG;AACF,QAAM,CAAC,UAAU,WAAW,IAAII,WAAwB,IAAI;AAC5D,QAAM,WAAW,SAAS,aAAa,aAAa;AAEpD,QAAM,YAAY,CAAC,aAAqB;AACvC,QAAI,SAAU;AACd,gBAAY,QAAQ;AACpB,YAAQ,UAAU,SAAS,MAAM;AAAA,EAClC;AAEA,SACC,gBAAAJ;AAAA,IAAC;AAAA;AAAA,MACA,WAAU;AAAA,MACV,kBAAgB,SAAS,YAAY,SAAS;AAAA,MAE7C,mBAAS,QAAQ,IAAI,CAAC,QAAQ;AAC9B,cAAM,WAAW,aAAa,IAAI;AAClC,eACC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAEA,MAAK;AAAA,YACL,WAAU;AAAA,YACV,eAAa,WAAW,SAAS;AAAA,YACjC,UAAU;AAAA,YACV,SAAS,MAAM,UAAU,IAAI,EAAE;AAAA,YAE9B,cAAI;AAAA;AAAA,UAPA,IAAI;AAAA,QAQV;AAAA,MAEF,CAAC;AAAA;AAAA,EACF;AAEF;AAIA,SAAS,qBAAqB,EAAE,IAAI,GAAoB;AACvD,QAAM,CAAC,OAAO,QAAQ,IAAII,WAAS,KAAK;AACxC,QAAM,MAAMF,SAA0B,IAAI;AAE1C,SACC,gBAAAD,MAAAF,WAAA,EACC;AAAA,oBAAAC;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,QAAO;AAAA,QACP,KAAI;AAAA,QACJ,WAAU;AAAA,QACV,cAAY,EAAE,wBAAwB;AAAA,QACtC,cAAc,MAAM,SAAS,IAAI;AAAA,QACjC,cAAc,MAAM,SAAS,KAAK;AAAA,QAKlC,0BAAAA,MAAC,SAAI,KAAU,KAAI,IAAG,WAAU,gBAAe,SAAQ,QAAO;AAAA;AAAA,IAC/D;AAAA,IACC,SAAS,gBAAAA,MAAC,mBAAgB,KAAU,WAAW,KAAK,MAAM,KAAK;AAAA,KACjE;AAEF;AAIA,IAAM,mBAAmB,oBAAI,IAAI,CAAC,OAAO,OAAO,OAAO,OAAO,QAAQ,OAAO,QAAQ,KAAK,CAAC;AAE3F,SAAS,SAAS,EAAE,KAAK,GAA0D;AAClF,QAAM,CAAC,OAAO,QAAQ,IAAII,WAAS,KAAK;AACxC,QAAM,MAAMF,SAA0B,IAAI;AAC1C,QAAM,MAAM,KAAK,SAAS,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,KAAK;AAC7D,QAAM,gBAAgB,iBAAiB,IAAI,GAAG;AAC9C,QAAM,UAAU,KAAK,SAAS,WAAW,QAAQ;AAEjD,SACC,gBAAAD,MAAAF,WAAA,EACC;AAAA,oBAAAE;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA,MAAM,KAAK;AAAA,QACX,QAAO;AAAA,QACP,KAAI;AAAA,QACJ,WAAU;AAAA,QACV,cAAc,MAAM,iBAAiB,SAAS,IAAI;AAAA,QAClD,cAAc,MAAM,SAAS,KAAK;AAAA,QAElC;AAAA,0BAAAD,MAAC,UAAK,WAAU,oBACf,0BAAAA,MAAC,gBAAa,KAAU,GACzB;AAAA,UACA,gBAAAC,MAAC,UAAK,WAAU,oBACf;AAAA,4BAAAD,MAAC,UAAK,WAAU,oBAAoB,eAAK,UAAS;AAAA,YAClD,gBAAAA,MAAC,UAAK,WAAU,oBAAoB,yBAAe,KAAK,QAAQ,GAAE;AAAA,aACnE;AAAA;AAAA;AAAA,IACD;AAAA,IACC,SACA,kBACC,UACA,gBAAAA,MAAC,mBAAgB,KAAK,KAAK,KAAK,WAAW,KAAK,MAAM,KAAK,KAAK,IAEhE,gBAAAA,MAAC,sBAAmB,UAAU,KAAK,UAAU,KAAU,WAAW,KAAK,MAAM,KAAK,KAAK;AAAA,KAE1F;AAEF;AAIO,SAAS,gBAAgB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAKG;AACF,QAAM,CAAC,OAAO,QAAQ,IAAII,WAA8B,EAAE,SAAS,EAAE,CAAC;AACtE,QAAM,CAAC,cAAc,eAAe,IAAIA,WAA4C,IAAI;AAExF,kBAAgB,MAAM;AACrB,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ;AAEb,UAAM,OAAO,OAAO,sBAAsB;AAC1C,UAAM,KAAK;AACX,UAAM,MAAM;AACZ,UAAM,KAAK,OAAO;AAElB,QAAI,OAAO,KAAK,OAAO,KAAK,QAAQ,IAAI,KAAK;AAC7C,QAAI,OAAO,EAAG,QAAO;AACrB,QAAI,OAAO,KAAK,KAAK,EAAG,QAAO,KAAK,KAAK;AAEzC,UAAM,aAAa;AACnB,QAAI,MAAM,KAAK,MAAM,aAAa;AAClC,QAAI,MAAM,EAAG,OAAM,KAAK,SAAS;AAEjC,aAAS,EAAE,MAAM,KAAK,OAAO,IAAI,SAAS,EAAE,CAAC;AAK7C,UAAM,OAAO,OAAO,YAAY;AAChC,oBAAgB,gBAAgB,aAAa,OAAO,SAAS,IAAI;AAAA,EAClE,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,cAAc,MAAM;AACzB,QAAI,OAAQ,QAAO;AAAA,aAGV,KAAM,QAAO,KAAK,MAAM,UAAU,qBAAqB;AAAA,EACjE;AAEA,MAAI,CAAC,aAAc,QAAO;AAE1B,SAAO;AAAA,IACN,gBAAAJ,MAAC,SAAI,WAAU,oBAAmB,OAAc,SAAS,aACxD,0BAAAA,MAAC,SAAI,KAAU,KAAI,IAAG,WAAU,wBAAuB,GACxD;AAAA,IACA;AAAA,EACD;AACD;AAIA,SAAS,mBAAmB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAKG;AACF,QAAM,CAAC,OAAO,QAAQ,IAAII,WAA8B,EAAE,SAAS,EAAE,CAAC;AACtE,QAAM,CAAC,cAAc,eAAe,IAAIA,WAA4C,IAAI;AAExF,kBAAgB,MAAM;AACrB,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ;AAEb,UAAM,OAAO,OAAO,sBAAsB;AAC1C,UAAM,KAAK;AACX,UAAM,KAAK;AACX,UAAM,MAAM;AACZ,UAAM,KAAK,OAAO;AAElB,QAAI,OAAO,KAAK,OAAO,KAAK,QAAQ,IAAI,KAAK;AAC7C,QAAI,OAAO,EAAG,QAAO;AACrB,QAAI,OAAO,KAAK,KAAK,EAAG,QAAO,KAAK,KAAK;AAEzC,QAAI,MAAM,KAAK,MAAM,KAAK;AAC1B,QAAI,MAAM,EAAG,OAAM,KAAK,SAAS;AAEjC,aAAS,EAAE,MAAM,KAAK,OAAO,IAAI,SAAS,EAAE,CAAC;AAC7C,UAAM,OAAO,OAAO,YAAY;AAChC,oBAAgB,gBAAgB,aAAa,OAAO,SAAS,IAAI;AAAA,EAClE,GAAG,CAAC,SAAS,CAAC;AAEd,MAAI,CAAC,aAAc,QAAO;AAE1B,SAAO;AAAA,IACN,gBAAAH;AAAA,MAAC;AAAA;AAAA,QACA,WAAU;AAAA,QACV;AAAA,QACA,SAAS,MAAM,OAAO,KAAK,MAAM,UAAU,qBAAqB;AAAA,QAEhE;AAAA,0BAAAD,MAAC,SAAI,WAAU,6BACd,0BAAAA,MAAC,gBAAa,KAAU,GACzB;AAAA,UACA,gBAAAC,MAAC,SAAI,WAAU,6BACd;AAAA,4BAAAD,MAAC,UAAK,WAAU,6BAA6B,oBAAS;AAAA,YACtD,gBAAAA,MAAC,UAAK,WAAU,6BAA6B,YAAE,sBAAsB,GAAE;AAAA,aACxE;AAAA;AAAA;AAAA,IACD;AAAA,IACA;AAAA,EACD;AACD;AAIA,SAAS,eAAe,OAAuB;AAC9C,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC5D,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,CAAC,CAAC;AAC7C;AAIA,IAAM,mBAA2C;AAAA,EAChD,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AACN;AAEA,SAAS,aAAa,EAAE,IAAI,GAAoB;AAC/C,QAAM,QAAQ,iBAAiB,GAAG,KAAK;AAEvC,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAc;AAAA,MACd,gBAAe;AAAA,MAEf;AAAA,wBAAAD,MAAC,UAAK,GAAE,8DAA6D;AAAA,QACrE,gBAAAA,MAAC,cAAS,QAAO,kBAAiB;AAAA,QACjC,QAAQ,SACR,gBAAAA,MAAC,UAAK,GAAE,KAAI,GAAE,MAAK,UAAS,KAAI,MAAM,OAAO,QAAO,QAAO,YAAW,OAAM,iBAE5E;AAAA,QAEA,QAAQ,SACR,gBAAAA,MAAC,UAAK,GAAE,KAAI,GAAE,MAAK,UAAS,KAAI,MAAM,OAAO,QAAO,QAAO,YAAW,OAAM,iBAE5E;AAAA;AAAA;AAAA,EAEF;AAEF;AAIA,SAAS,gBAAgB,EAAE,QAAQ,GAAiC;AACnE,QAAM,YAAY,MAAM;AACvB,QAAI;AAAE,aAAO,IAAI,IAAI,QAAQ,GAAG,EAAE;AAAA,IAAU,QAAQ;AAAE,aAAO,QAAQ;AAAA,IAAK;AAAA,EAC3E,GAAG;AACH,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,MAAM,QAAQ;AAAA,MACd,QAAO;AAAA,MACP,KAAI;AAAA,MACJ,WAAU;AAAA,MACV,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,MAEjC;AAAA,gBAAQ,YACR,gBAAAD;AAAA,UAAC;AAAA;AAAA,YACA,KAAK,QAAQ;AAAA,YACb,KAAI;AAAA,YACJ,WAAU;AAAA,YACV,SAAQ;AAAA,YACR,SAAS,CAAC,MAAM;AAAE,cAAC,EAAE,OAA4B,MAAM,UAAU;AAAA,YAAQ;AAAA;AAAA,QAC1E;AAAA,QAED,gBAAAC,MAAC,SAAI,WAAU,wBACb;AAAA,kBAAQ,WACR,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACA,KAAK,QAAQ;AAAA,cACb,KAAI;AAAA,cACJ,WAAU;AAAA,cACV,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,SAAS,CAAC,MAAM;AAAE,gBAAC,EAAE,OAA4B,MAAM,UAAU;AAAA,cAAQ;AAAA;AAAA,UAC1E;AAAA,UAEA,QAAQ,SAAS,gBAAAA,MAAC,SAAI,WAAU,yBAAyB,kBAAQ,OAAM;AAAA,UACvE,QAAQ,eACR,gBAAAA,MAAC,SAAI,WAAU,wBAAwB,kBAAQ,YAAY,MAAM,GAAG,GAAG,GAAE;AAAA,UAE1E,gBAAAA,MAAC,SAAI,WAAU,uBAAuB,oBAAS;AAAA,WAChD;AAAA;AAAA;AAAA,EACD;AAEF;;;ACngBA,OAAO,SAAS,aAAAK,aAAW,UAAAC,gBAAc;AAyLrC,SAGG,OAAAC,OAHH,QAAAC,aAAA;AArLJ,SAAS,WAAW,KAAoE;AACvF,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,MAAM,QAAQ,GAAG,EAAG,QAAO;AAC/B,MAAI;AACH,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO,MAAM,QAAQ,MAAM,IAAI,SAAS;AAAA,EACzC,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAYA,IAAM,eAAe,IAAI,KAAK,eAAe,OAAO;AAEpD,IAAM,kBAAkB,oBAAI,IAAiC;AAC7D,SAAS,qBAAqB,QAAqC;AAClE,QAAM,MAAM,gBAAgB,IAAI,MAAM;AACtC,MAAI,IAAK,QAAO;AAChB,QAAM,MAAM,IAAI,KAAK,eAAe,QAAQ;AAAA,IAC3C,SAAS;AAAA,IACT,OAAO;AAAA,IACP,KAAK;AAAA,EACN,CAAC;AACD,kBAAgB,IAAI,QAAQ,GAAG;AAC/B,SAAO;AACR;AAeO,SAAS,YAAY;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAqB;AACpB,QAAM,YAAYC,SAAuB,IAAI;AAC7C,QAAM,SAASA,SAAuB,IAAI;AAC1C,QAAM,eAAeA,SAAuB,IAAI;AAChD,QAAM,mBAAmBA,SAAO,MAAM,MAAM;AAC5C,QAAM,mBAAmBA,SAAO,IAAI;AAEpC,QAAM,eAAeA,SAAO,KAAK;AAOjC,QAAM,SAAS,gBAAgB;AAC/B,QAAM,uBAAuB,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAEzE,QAAM,sBAAsB,MAAM;AAAA,IACjC,CAAC,UAAkB,WAAmB;AACrC,UAAI,CAAC,qBAAsB;AAI3B,aAAO,OAAO,cACZ,OAAO,EAAE,gBAAgB,sBAAsB,QAAQ,SAAS,CAAC,EACjE,MAAM,CAAC,QAAiB;AACxB,gBAAQ,KAAK,mCAAmC,GAAG;AAAA,MACpD,CAAC;AAAA,IACH;AAAA,IACA,CAAC,QAAQ,oBAAoB;AAAA,EAC9B;AAGA,EAAAC,YAAU,MAAM;AACf,UAAM,YAAY,iBAAiB;AACnC,UAAM,WAAW,MAAM;AACvB,qBAAiB,UAAU;AAG3B,QAAI,iBAAiB,WAAW,WAAW,WAAW;AAErD,YAAM,WAAW,MAAM,MAAM,SAAS,CAAC;AACvC,YAAM,eAAe,YAAY,IAAI,MAAM,YAAY,CAAC,IAAI;AAE5D,UAAI,iBAAiB,WAAW,CAAC,gBAAgB,UAAU,OAAO,cAAc,IAAI;AAKnF,cAAM,kBAAkB,aAAa;AACrC,kBAAU,SAAS,eAAe;AAAA,UACjC,UAAU,iBAAiB,WAAW,kBAAkB,YAAY;AAAA,QACrE,CAAC;AAAA,MACF;AACA,uBAAiB,UAAU;AAAA,IAC5B;AAAA,EACD,GAAG,CAAC,KAAK,CAAC;AAeV,EAAAA,YAAU,MAAM;AACf,QAAI,eAAe;AAClB,gBAAU,SAAS,eAAe,EAAE,UAAU,UAA4B,CAAC;AAAA,IAC5E;AACA,iBAAa,UAAU,CAAC,CAAC;AAAA,EAC1B,GAAG,CAAC,aAAa,CAAC;AAGlB,EAAAA,YAAU,MAAM;AACf,QAAI,YAAY,gBAAgB;AAC/B,gBAAU,SAAS,eAAe,EAAE,UAAU,SAAS,CAAC;AAAA,IACzD;AAAA,EACD,GAAG,CAAC,UAAU,cAAc,CAAC;AAG7B,EAAAA,YAAU,MAAM;AACf,QAAI,CAAC,WAAW,CAAC,cAAc,CAAC,OAAO,QAAS;AAEhD,UAAM,WAAW,IAAI;AAAA,MACpB,CAAC,YAAY;AACZ,YAAI,QAAQ,CAAC,GAAG,kBAAkB,CAAC,eAAe;AAEjD,gBAAM,YAAY,aAAa;AAC/B,gBAAM,mBAAmB,WAAW,gBAAgB;AACpD,gBAAM,gBAAgB,WAAW,aAAa;AAE9C,qBAAW;AAGX,gCAAsB,MAAM;AAC3B,gBAAI,WAAW;AACd,oBAAM,kBAAkB,UAAU;AAClC,wBAAU,YAAY,iBAAiB,kBAAkB;AAAA,YAC1D;AAAA,UACD,CAAC;AAAA,QACF;AAAA,MACD;AAAA,MACA,EAAE,MAAM,aAAa,SAAS,WAAW,IAAI;AAAA,IAC9C;AAEA,aAAS,QAAQ,OAAO,OAAO;AAC/B,WAAO,MAAM,SAAS,WAAW;AAAA,EAClC,GAAG,CAAC,SAAS,YAAY,aAAa,CAAC;AAEvC,MAAI,MAAM,WAAW,GAAG;AACvB,WACC,gBAAAH;AAAA,MAAC;AAAA;AAAA,QACA,WAAU;AAAA,QACV,MAAK;AAAA,QACL,cAAY,EAAE,sBAAsB;AAAA,QACpC,aAAU;AAAA,QAEV,0BAAAC,MAAC,SAAI,WAAU,YACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,iBACd,0BAAAA,MAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,KACvE,0BAAAA,MAAC,UAAK,GAAE,kCAAiC,GAC1C,GACD;AAAA,UACA,gBAAAA,MAAC,SAAI,WAAU,iBAAiB,YAAE,6BAA6B,GAAE;AAAA,WAClE;AAAA;AAAA,IACD;AAAA,EAEF;AAEA,MAAI,cAAc;AAKlB,QAAM,WAAW,aAAa,OAAO,oBAAI,KAAK,CAAC;AAC/C,QAAM,YAAY,oBAAI,KAAK;AAC3B,YAAU,QAAQ,UAAU,QAAQ,IAAI,CAAC;AACzC,QAAM,eAAe,aAAa,OAAO,SAAS;AAElD,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,KAAK;AAAA,MACL,WAAU;AAAA,MACV,MAAK;AAAA,MACL,cAAY,EAAE,sBAAsB;AAAA,MACpC,aAAU;AAAA,MAGV;AAAA,wBAAAD,MAAC,SAAI,KAAK,QAAQ,WAAU,wBAC1B,2BACA,gBAAAC,MAAC,SAAI,WAAU,wBACd;AAAA,0BAAAD,MAAC,SAAI;AAAA,UACL,gBAAAA,MAAC,SAAI;AAAA,UACL,gBAAAA,MAAC,SAAI;AAAA,WACN,GAEF;AAAA,QAEC;AAAA,UACA,GAAG,MAAM,IAAI,CAAC,SAAS;AACtB,gBAAI,KAAK,SAAS,SAAS;AAC1B,qBACC,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBAEA,MAAM,KAAK,QAAQ;AAAA;AAAA,gBADb,KAA4C,cAAc,KAAK;AAAA,cAEtE;AAAA,YAEF;AAIA,kBAAM,WAAW,IAAI,KAAK,KAAK,SAAS;AACxC,kBAAM,UAAU,aAAa,OAAO,QAAQ;AAC5C,kBAAM,cAAc,YAAY;AAChC,gBAAI,YAAa,eAAc;AAC/B,kBAAM,cAAc,eAAe,YAAY;AAC/C,kBAAM,YACL,YAAY,eACT,EAAE,kBAAkB,IACpB,qBAAqB,UAAU,CAAC,EAAE,OAAO,QAAQ;AAGrD,kBAAM,SAAS,KAAK,YAAY,YAAY,KAAK,YAAY,OAAO;AAEpE,mBACC,gBAAAC;AAAA,cAAC,MAAM;AAAA,cAAN;AAAA,gBAGC;AAAA,iCACA,gBAAAA,MAAC,SAAI,WAAU,eACd;AAAA,oCAAAD,MAAC,SAAI,WAAU,oBAAmB;AAAA,oBAClC,gBAAAA,MAAC,SAAI,WAAU,oBAAoB,qBAAU;AAAA,oBAC7C,gBAAAA,MAAC,SAAI,WAAU,oBAAmB;AAAA,qBACnC;AAAA,kBAED,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAM,KAAK,QAAQ;AAAA,sBACnB;AAAA,sBACA,OAAO,WAAW,KAAK,KAAK;AAAA,sBAC5B,UAAU;AAAA,wBACR,KACC;AAAA,sBACH;AAAA,sBACA,iBAAiB;AAAA;AAAA,kBASlB;AAAA;AAAA;AAAA,cA1BM,KAA4C,cAAc,KAAK;AAAA,YA2BtE;AAAA,UAEF,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAeD,GAAI,iBAAiB,uBAClB;AAAA,YACA,gBAAAC,MAAC,MAAM,UAAN,EAUC;AAAA;AAAA,cACD,gBAAAD,MAAC,iBAAc,MAAM,eAAe,QAAO,MAAK,OAAO,MAAM,WAAS,MAAC;AAAA,iBAXnD,gBAAgB,oBAAoB,CAYzD;AAAA,UACD,IACC,CAAC;AAAA,QACL;AAAA,QAGC;AAAA,SAkBC,kBAAkB,aAAa,CAAC,iBACjC,gBAAAA,MAAC,SAAI,WAAU,aACd,0BAAAC,MAAC,SAAI,WAAU,kBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,iBAAgB;AAAA,UAC/B,gBAAAA,MAAC,SAAI,WAAU,iBAAgB;AAAA,UAC/B,gBAAAA,MAAC,SAAI,WAAU,iBAAgB;AAAA,WAChC,GACD;AAAA,QAGD,gBAAAA,MAAC,SAAI,KAAK,WAAW;AAAA;AAAA;AAAA,EACtB;AAEF;AAUA,SAAS,eAAe,MAAgC;AACvD,MAAI,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO;AAClC,MAAI;AACH,UAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,QAAI,KAAK,UAAU,KAAK,KAAM,QAAO;AAAA,EACtC,QAAQ;AAAA,EAER;AACA,SAAO;AACR;AAEA,SAAS,UAAU,EAAE,KAAK,GAAqB;AAC9C,QAAM,OAAO,eAAe,IAAI;AAGhC,MAAI,MAAM;AACT,UAAM,UAAU,KAAK,WAAW,WAAW,EAAE,eAAe,IAAI,EAAE,aAAa;AAE/E,WACC,gBAAAC,MAAC,SAAI,WAAU,2BACd;AAAA,sBAAAD,MAAC,SAAI,WAAU,mBACb,eAAK,QACL,gBAAAA,MAAC,SAAI,KAAK,KAAK,OAAO,KAAI,IAAG,WAAU,uBAAsB,IAE7D,gBAAAA,MAAC,UAAM,sBAAY,KAAK,IAAI,GAAE,GAEhC;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,iBACd;AAAA,wBAAAD,MAAC,UAAK,WAAU,iBAAiB,eAAK,MAAK;AAAA,QAAQ;AAAA,QACnD,gBAAAA,MAAC,UAAK,WAAU,mBAAmB,mBAAQ;AAAA,SAC5C;AAAA,OACD;AAAA,EAEF;AAGA,SACC,gBAAAA,MAAC,SAAI,WAAU,YACd,0BAAAA,MAAC,SAAI,WAAU,iBAAiB,gBAAK,GACtC;AAEF;;;ACrZA,SAAS,aAAAI,aAAW,YAAAC,kBAAgB;AA6KjC,SA0BC,YAAAC,WAxBgB,OAAAC,OAFjB,QAAAC,cAAA;AAtHI,SAAS,eAAe;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB;AACD,GAAwB;AACvB,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,eAAe;AACvD,QAAM,iBAAiB,eAAe,CAAC,MAAM,EAAE,cAAc;AAC7D,QAAM,wBAAwB,eAAe,CAAC,MAAM,EAAE,qBAAqB;AAC3E,QAAM,YAAY,eAAe,CAAC,MAAM,EAAE,aAAa,IAAI,KAAK;AAChE,QAAM,SAAS,gBAAgB;AAM/B,QAAM,aAAa,SAAS,cAAc;AAC1C,QAAM,cAAc,SAAS,eAAe;AAC5C,QAAM,CAAC,SAAS,UAAU,IAAIC,WAAS,KAAK;AAK5C,EAAAC,YAAU,MAAM;AACf,QAAI,CAAC,WAAW,QAAQ,aAAc;AACtC,QAAI,iBAAiB,QAAQ,iBAAiB,EAAG;AACjD,UAAM,QAAQ,WAAW,MAAM;AAC9B,iBAAW,IAAI;AACf,iBAAW,MAAM,eAAe,GAAG,GAAG;AAAA,IACvC,GAAG,aAAa;AAChB,WAAO,MAAM,aAAa,KAAK;AAAA,EAChC,GAAG,CAAC,SAAS,gBAAgB,aAAa,CAAC;AAE3C,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,cAAc,CAAC,MAAkB;AACtC,MAAE,gBAAgB;AAClB,eAAW,IAAI;AACf,eAAW,MAAM;AAChB,qBAAe;AACf,iBAAW,KAAK;AAAA,IACjB,GAAG,GAAG;AAAA,EACP;AAEA,QAAM,cAAc,MAAM;AAKzB,UAAM,eAAe,QAAQ;AAC7B,mBAAe;AACf,0BAAsB,YAAY;AAClC,WAAO;AAAA,EACR;AAmBA,QAAM,mBAAmB,CAAC,aAAqB;AAC9C,UAAM,SAAS,QAAQ;AACvB,UAAM,SAAS,QAAQ,cAAc;AACrC,QAAI,UAAU,CAAC,OAAO,WAAW,qBAAqB,GAAG;AACxD,aAAO,OAAO,cACZ,OAAO,EAAE,gBAAgB,QAAQ,QAAQ,SAAS,CAAC,EACnD,MAAM,CAAC,QAAiB;AACxB,gBAAQ,KAAK,gDAAgD,GAAG;AAAA,MACjE,CAAC;AAAA,IACH;AACA,mBAAe;AACf,0BAAsB,MAAM;AAC5B,WAAO;AAAA,EACR;AAEA,QAAM,YAAY,QAAQ,UAAU,SAAS,QAAQ,WAAW,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC,GAAG;AAAA,IACzF,CAAC,MAAM,EAAE,KAAK,KAAK,EAAE,SAAS;AAAA,EAC/B;AAIA,QAAM,KACL,QAAQ,gBAAgB,QAAQ,aAAa,QAAQ,SAAS,IAAI,QAAQ,eAAe;AAE1F,QAAM,iBAAiB,cAAc,aAAa,0BAA0B;AAE5E,SACC,gBAAAF;AAAA,IAAC;AAAA;AAAA,MACA,WAAW,cAAc,cAAc,GAAG,UAAU,wBAAwB,EAAE;AAAA,MAC9E,SAAS;AAAA,MAOT,WAAW,CAAC,MAAM;AACjB,YAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,IAAK;AACxC,YAAI,EAAE,WAAW,EAAE,cAAe;AAClC,UAAE,eAAe;AACjB,oBAAY;AAAA,MACb;AAAA,MACA,MAAK;AAAA,MACL,UAAU;AAAA,MAEV;AAAA,wBAAAA,OAAC,SAAI,WAAU,qBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,qBACb,wBAAc,gBAAAA,MAAC,SAAI,KAAK,aAAa,KAAI,IAAG,IAAK,QACnD;AAAA,UACA,gBAAAA,MAAC,SAAI,WAAU,mBAAmB,sBAAW;AAAA,UAC7C,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACA,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS;AAAA,cACT,cAAY,EAAE,qBAAqB;AAAA,cAEnC,0BAAAA,MAAC,SAAM,MAAM,IAAI;AAAA;AAAA,UAClB;AAAA,WACD;AAAA,QAEC,SAAS,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,UAKd,gBAAAA,MAAC,SAAiB,WAAU,mBAC1B,8BAAoB,EAAE,IAAI,KADlB,EAAE,IAEZ;AAAA,SACA;AAAA,QAEA,MACA,gBAAAC,OAAAF,WAAA,EACE;AAAA,aAAG,UAAU,gBAAAC,MAAC,SAAI,WAAU,mBAAmB,aAAG,QAAO;AAAA,UAQ1D,gBAAAA,MAAC,SAAI,WAAU,6CACb,aAAG,QAAQ,IAAI,CAAC,QAChB,gBAAAA;AAAA,YAAC;AAAA;AAAA,cAEA,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS,CAAC,MAAM;AACf,kBAAE,gBAAgB;AAClB,iCAAiB,IAAI,EAAE;AAAA,cACxB;AAAA,cAEC,cAAI;AAAA;AAAA,YARA,IAAI;AAAA,UASV,CACA,GACF;AAAA,WACD;AAAA,QAGA,UAAU,QAAQ,WAAW,SAAS,gBAAAA,MAAC,SAAI,WAAU,qBAAqB,kBAAO;AAAA;AAAA;AAAA,EACnF;AAEF;;;A3BrJG,SAqiCG,YAAAI,WAriCH,OAAAC,OAm1BE,QAAAC,cAn1BF;AAxEH,SAASC,cAAa,OAAuB;AAC5C,MAAI,CAAC,MAAM,WAAW,SAAS,EAAG,QAAO;AACzC,QAAM,WAAW,EAAE,KAAK;AAExB,MAAI,aAAa;AAChB,WAAO,MACL,QAAQ,WAAW,EAAE,EACrB,QAAQ,MAAM,GAAG,EACjB,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC;AACxC,SAAO;AACR;AA6BA,IAAM,qBAAyC,CAAC;AAahD,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB;AAQ5B,SAAS,YAAY,EAAE,UAAU,GAA2B;AAC3D,SACC,gBAAAF;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,eAAY;AAAA,MAEZ,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACA,GAAE;AAAA,UACF,MAAK;AAAA;AAAA,MACN;AAAA;AAAA,EACD;AAEF;AAkBO,SAAS,WAAW;AAAA,EAC1B;AAAA,EACA,aAAa;AACd,GAGG;AACF,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AACvD,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,SAAS,OAAO;AACxD,QAAM,WAAW,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAC7D,QAAM,WAAW,eAAe,CAAC,MAAM;AACtC,QAAI,cAAc,CAAC,EAAE,qBAAsB,QAAO;AAClD,UAAM,IAAI,EAAE,cAAc,KAAK,CAACG,OAAMA,GAAE,OAAO,EAAE,oBAAoB;AACrE,WAAO,GAAG,gBAAgB,GAAG,gBAAgB,IAAI;AAAA,EAClD,CAAC;AAMD,QAAM,YAAY,aAAa,uBAAuB;AAItD,MAAI,CAAC,cAAc,YAAY,UAAU,eAAe;AACvD,WACC,gBAAAH;AAAA,MAAC;AAAA;AAAA,QACA,KAAK,SAAS;AAAA,QACd,KAAK,SAAS,gBAAgB;AAAA,QAC9B,WAAW,gBAAgB,aAAa,EAAE;AAAA;AAAA,IAC3C;AAAA,EAEF;AAGA,MAAI,aAAa,WAAW;AAC3B,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,KAAK,YAAY;AAAA,QACjB,KAAI;AAAA,QACJ,WAAW,gBAAgB,SAAS,IAAI,aAAa,EAAE;AAAA;AAAA,IACxD;AAAA,EAEF;AAOA,MAAI,aAAa,cAAc;AAC9B,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,WAAW,iBAAiB,aAAa,EAAE;AAAA,QAC3C,OAAO;AAAA,UACN,iBAAiB;AAAA,UACjB,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,gBAAgB;AAAA,UAChB,cAAc;AAAA,QACf;AAAA,QAEA,0BAAAA,MAAC,mBAAgB,UAAU,YAAY,cAAc;AAAA;AAAA,IACtD;AAAA,EAEF;AAKA,MAAI,SAAS;AACZ,WACC,gBAAAA,MAAC,SAAI,KAAK,SAAS,KAAI,IAAG,WAAW,mCAAmC,aAAa,EAAE,IAAI;AAAA,EAE7F;AAEA,SAAO,gBAAAA,MAAC,eAAY,WAAsB;AAC3C;AAYA,SAAS,aAAa,EAAE,UAAU,GAA2B;AAC5D,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AACvD,QAAM,CAAC,WAAW,YAAY,IAAII,WAAS,KAAK;AAChD,QAAM,SAAS,aAAa,mBAAmB;AAE/C,EAAAC,YAAU,MAAM;AACf,QAAI,CAAC,OAAQ;AACb,iBAAa,KAAK;AAClB,UAAM,MAAM,IAAI,MAAM;AACtB,QAAI,MAAM;AACV,QAAI,IAAI,UAAU;AACjB,mBAAa,IAAI;AACjB;AAAA,IACD;AACA,QAAI,SAAS,MAAM,aAAa,IAAI;AACpC,QAAI,UAAU,MAAM,aAAa,IAAI;AAAA,EACtC,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,QAAQ;AACX,WACC,gBAAAL;AAAA,MAAC;AAAA;AAAA,QACA,KAAK;AAAA,QACL,KAAI;AAAA,QACJ,WAAW,mCAAmC,aAAa,EAAE;AAAA,QAC7D,OAAO,EAAE,SAAS,YAAY,IAAI,GAAG,YAAY,qBAAqB;AAAA;AAAA,IACvE;AAAA,EAEF;AACA,SAAO,gBAAAA,MAAC,cAAW,WAAsB,YAAU,MAAC;AACrD;AAQA,IAAM,aAAqC;AAAA;AAAA;AAAA,EAG1C,SACC;AAAA,EACD,MAAM;AAAA,EACN,OACC;AAAA,EACD,OACC;AAAA,EACD,SACC;AAAA,EACD,MAAM;AAAA,EACN,OACC;AAAA,EACD,QACC;AAAA,EACD,WACC;AAAA,EACD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,WACC;AAAA,EACD,MAAM;AAAA,EACN,SACC;AAAA,EACD,SACC;AAAA,EACD,QACC;AAAA,EACD,OACC;AAAA,EACD,QACC;AAAA,EACD,SACC;AAAA,EACD,MAAM;AAAA,EACN,OACC;AAAA,EACD,QACC;AAAA,EACD,QACC;AAAA,EACD,OACC;AAAA,EACD,QACC;AAAA,EACD,SACC;AAAA,EACD,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,UACC;AAAA,EACD,OACC;AAAA,EACD,KAAK;AAAA,EACL,eACC;AAAA,EACD,SACC;AAAA,EACD,MAAM;AAAA,EACN,QACC;AAAA,EACD,SACC;AAAA,EACD,OACC;AAAA,EACD,WACC;AAAA,EACD,OACC;AAAA,EACD,MAAM;AAAA,EACN,QACC;AAAA,EACD,SACC;AAAA,EACD,WACC;AAAA,EACD,MAAM;AAAA,EACN,cACC;AAAA,EACD,MAAM;AAAA,EACN,UACC;AACF;AAOA,SAAS,gBAAgB,EAAE,SAAS,GAAyB;AAC5D,QAAM,aAAa,WAAW,QAAQ,KAAK,WAAW;AACtD;AAAA;AAAA,IAEC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,OAAM;AAAA,QACN,OAAO,EAAE,OAAO,OAAO,QAAQ,MAAM;AAAA,QACrC,yBAAyB,EAAE,QAAQ,cAAc,GAAG;AAAA;AAAA,IACrD;AAAA;AAEF;AAUA,SAAS,WAAW,EAAE,OAAO,GAAwB;AACpD,MAAI,CAAC,OAAQ,QAAO,gBAAAA,MAAC,SAAM,MAAM,IAAI;AACrC,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ,0BAAAA,MAAC,UAAK,GAAE,yBAAwB;AAAA;AAAA,EACjC;AAEF;AAMO,SAAS,cAAc;AAAA,EAC7B,eAAe;AAAA,EACf,YAAY;AAAA,EACZ;AAAA,EACA;AACD,IAeI,CAAC,GAAG;AACP,QAAM,EAAE,SAAS,SAAS,YAAY,IAAI,UAAU;AACpD,UAAQ;AACR,QAAM,EAAE,QAAQ,OAAO,mBAAmB,gBAAgB,eAAe,IAAI,iBAAiB;AAC9F,QAAM,EAAE,eAAe,QAAQ,YAAY,sBAAsB,IAAI,iBAAiB;AACtF,QAAM,WAAW,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAC7D,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AACvD,QAAM,EAAE,YAAY,IAAI,UAAU;AAKlC,QAAM,gBAAgB,iBAAiB;AAEvC,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,aAAa,WAAW,KAAK;AACzE,QAAM,EAAE,kBAAkB,eAAe,iBAAiB,IAAI,iBAAiB;AAC/E,QAAM,0BAA0B,eAAe,CAAC,MAAM,EAAE,uBAAuB;AAI/E,QAAM,kBAAkB,eAAe,CAAC,MAAM,CAAC,CAAC,EAAE,eAAe;AAEjE,QAAM,iBAAiB,eAAe,CAAC,MAAM,EAAE,SAAS,OAAO;AAG/D,MAAI,QAAQ,IAAI,aAAa,cAAc;AAC1C,YAAQ,MAAM,YAAY;AAAA,MACzB,UAAU,aAAa;AAAA,MACvB,SAAS,gBAAgB,SAAS;AAAA,MAClC;AAAA,IACD,CAAC;AAAA,EACF;AAEA,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,MAAM;AAClD,QAAM,CAAC,WAAW,YAAY,IAAII,WAAS,KAAK;AAChD,QAAM,SAAS,eAAe;AAC9B,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAc,MAAM;AACtD,QAAM,CAAC,SAAS,UAAU,IAAIA,WAAkB,IAAI;AACpD,QAAM,CAAC,SAAS,UAAU,IAAIA,WAAS,EAAE;AACzC,QAAM,CAAC,mBAAmB,oBAAoB,IAAIA,WAAwB,IAAI;AAC9E,QAAM,CAAC,qBAAqB,sBAAsB,IAAIA,WAAwB,IAAI;AAIlF,QAAM,kBAAkBE,SAAO,QAAQ;AACvC,EAAAD,YAAU,MAAM;AACf,QAAI,YAAY,aAAa,gBAAgB,WAAW,YAAY,gBAAgB;AACnF,iBAAW,cAAc;AAAA,IAC1B;AACA,oBAAgB,UAAU;AAAA,EAC3B,GAAG,CAAC,UAAU,OAAO,CAAC;AAGtB,QAAM,UAAU,eAAe,CAAC,MAAM,EAAE,sBAAsB;AAC9D,EAAAA,YAAU,MAAM;AACf,QAAI,YAAY,MAAM;AACrB,UAAI,QAAQ,SAAS,EAAG,YAAW,OAAO;AAC1C,iBAAW,KAAK;AAChB,mBAAa,MAAM;AACnB,YAAM,SAAS,EAAE,0BAA0B,IAAI;AAAA,IAChD;AAAA,EACD,GAAG,CAAC,SAAS,KAAK,CAAC;AAEnB,QAAM,gBAAgBC,SAAsC,MAAS;AAKrE,QAAM,gBAAgB,aAAa;AACnC,QAAM,0BAA0B,CAAC,iBAAiB,kBAAkB;AACpE,QAAM,iBAAiB,eAAe,WAAW,SAAS,IACvD,EAAE,aAAa,IACf,0BACC,EAAE,wBAAwB,IAC1B;AAEJ,QAAM,mBAAmBC;AAAA,IACxB,CAAC,OAAe;AACf,4BAAsB,EAAE;AACxB,iBAAW,cAAc;AAAA,IAC1B;AAAA,IACA,CAAC,qBAAqB;AAAA,EACvB;AAEA,QAAM,sBAAsBA,cAAY,MAAM;AAS7C,UAAM,UAAU,aAAa;AAC7B,QAAI,CAAC,SAAS;AAGb,iBAAW,KAAK;AAChB;AAAA,IACD;AACA,UAAM,SAAS,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC3E,UAAM,cAA4B;AAAA,MACjC,IAAI,gBAAgB,MAAM;AAAA,MAC1B,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,MAChB,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,UAAU;AAAA,MACV,WAAW;AAAA,IACZ;AACA,UAAM,SAAS,EAAE,YAAY,QAAQ,CAAC,WAAW,CAAC;AAClD,0BAAsB,MAAM;AAC5B,eAAW,cAAc;AAAA,EAC1B,GAAG,CAAC,aAAa,IAAI,OAAO,uBAAuB,cAAc,CAAC;AASlE,QAAM,iBAAiBD,SAAO,KAAK;AACnC,EAAAD,YAAU,MAAM;AACf,QAAI,CAAC,QAAQ;AACZ,qBAAe,UAAU;AACzB;AAAA,IACD;AACA,QAAI,eAAe,WAAW,CAAC,QAAS;AACxC,mBAAe,UAAU;AACzB,QAAI,YAAY,KAAM;AACtB,UAAM,aAAa,cAAc,CAAC;AAClC,QAAI,WAAY,kBAAiB,WAAW,EAAE;AAAA,QACzC,qBAAoB;AAAA,EAC1B,GAAG,CAAC,QAAQ,SAAS,SAAS,eAAe,kBAAkB,mBAAmB,CAAC;AAQnF,QAAM,eAAe,YAAY,QAAQ;AACzC,QAAM,UAAUC,SAAO,YAAY;AAGnC,EAAAD,YAAU,MAAM;AACf,YAAQ,UAAU;AAAA,EACnB,CAAC;AACD,QAAM,kBAAkBC,SAAsB,IAAI;AAOlD,QAAM,iBAAiBC,cAAY,MAAM;AACxC,UAAM,QAAQ,MAAM,SAAS;AAC7B,QAAI,MAAM,OAAQ;AAClB,UAAM,YAAY,MAAM,cAAc,KAAK,CAAC,SAAS,CAAC,KAAK,GAAG,WAAW,OAAO,CAAC;AACjF,QAAI,CAAC,UAAW;AAChB,UAAM,QAAQ,IAAI;AAAA,EACnB,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,iBAAiBA;AAAA,IACtB,CAAC,aAAsB;AACtB,YAAM,QAAQ,YAAY,QAAQ,QAAQ,MAAM,KAAK;AAOrD,YAAM,mBAAmB,QAAQ,QAAQ,YAAY,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAChF,UAAI,CAAC,QAAQ,CAAC,iBAAkB;AAMhC,YAAM,SAAS,EAAE,QAAQ,IAAI;AAC7B,UAAI,UAAU;AACb,gBAAQ,QAAQ,QAAQ,EAAE;AAC1B,aAAK,QAAQ,QAAQ,OAAO,EAAE,MAAM,gBAAgB,SAAS,CAAC;AAC9D;AAAA,MACD;AAOA,0BAAoB;AACpB,YAAM,WAAW,MAAM,SAAS,EAAE;AAClC,cAAQ,QAAQ,QAAQ,EAAE;AAC1B,UAAI,CAAC,UAAU;AAGd,wBAAgB,UAAU;AAC1B;AAAA,MACD;AACA,WAAK,QAAQ,QAAQ,OAAO,EAAE,MAAM,gBAAgB,SAAS,CAAC;AAAA,IAC/D;AAAA,IACA,CAAC,UAAU,qBAAqB,KAAK;AAAA,EACtC;AAEA,EAAAF,YAAU,MAAM;AACf,QAAI,CAAC,YAAY,gBAAgB,WAAW,KAAM;AAClD,UAAM,OAAO,gBAAgB;AAC7B,oBAAgB,UAAU;AAC1B,SAAK,QAAQ,QAAQ,OAAO,EAAE,MAAM,gBAAgB,SAAS,CAAC;AAAA,EAC/D,GAAG,CAAC,QAAQ,CAAC;AAIb,QAAM,CAAC,UAAU,WAAW,IAAID,WAAS,KAAK;AAC9C,EAAAC,YAAU,MAAM;AACf,QAAI,CAAC,SAAU;AACf,UAAM,QAAQ,MAAM,YAAY,KAAK;AACrC,UAAM,QAAQ,CAAC,UAAyB;AACvC,UAAI,MAAM,QAAQ,SAAU,aAAY,KAAK;AAAA,IAC9C;AACA,aAAS,iBAAiB,SAAS,KAAK;AACxC,aAAS,iBAAiB,WAAW,KAAK;AAC1C,WAAO,MAAM;AACZ,eAAS,oBAAoB,SAAS,KAAK;AAC3C,eAAS,oBAAoB,WAAW,KAAK;AAAA,IAC9C;AAAA,EACD,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,SAASE,cAAY,MAAM;AAChC,QAAI,YAAY,kBAAkB;AAEjC,YAAM,QAAQ,UAAU,WAAW,UAAU,IAAI,UAAU,MAAM,CAAC,IAAI;AACtE,YAAM,mBAAmB,QAAQ,YAAY,KAAK,CAACC,OAAMA,GAAE,OAAO,KAAK,IAAI;AAC3E,UAAI,kBAAkB,YAAY,aAAa,qBAAqB;AACnE,mBAAW,kBAAkB;AAC7B,6BAAqB,IAAI;AACzB;AAAA,MACD;AACA,iBAAW,IAAI;AACf,2BAAqB,IAAI;AACzB;AAAA,IACD;AACA,QAAI,YAAY,oBAAoB;AACnC,iBAAW,IAAI;AACf,6BAAuB,IAAI;AAC3B;AAAA,IACD;AAOA,UAAM,YAAY,MAAM,SAAS,EAAE;AACnC,QAAI,aAAa,CAAC,UAAU,WAAW,OAAO,GAAG;AAChD,YAAM,SAAS,EAAE,YAAY,SAAS;AACtC,aAAO,OAAO,SAAS,OAAO,EAAE,gBAAgB,UAAU,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC5E;AACA,0BAAsB,IAAI;AAC1B,eAAW,IAAI;AAAA,EAChB,GAAG,CAAC,uBAAuB,SAAS,WAAW,aAAa,qBAAqB,QAAQ,KAAK,CAAC;AAE/F,QAAM,YAAYD;AAAA,IACjB,CAAC,QAAa;AAEb,kBAAY,QAAQ,SAAS,IAAI,EAAE,SAAS,SAAS;AAErD,YAAM,QAAQ,YAAY,QAAQ,GAAG;AACrC,mBAAa,GAAG;AAChB,iBAAW,OAAO,WAAW,IAAI;AACjC,UAAI,OAAO,YAAY,MAAM;AAC5B,8BAAsB,MAAM,QAAQ;AAAA,MACrC,WAAW,CAAC,OAAO;AAClB,8BAAsB,IAAI;AAAA,MAC3B;AAAA,IACD;AAAA,IACA,CAAC,WAAW,SAAS,UAAU,qBAAqB;AAAA,EACrD;AASA,QAAM,uBAAuB,eAAe,CAAC,MAAM,EAAE,oBAAoB;AACzE,EAAAF,YAAU,MAAM;AACf,QAAI,CAAC,qBAAsB;AAC3B,UAAM,EAAE,MAAM,MAAM,IAAI;AACxB,kBAAc,IAAI;AAClB,cAAU,WAAW,KAAK,EAAE;AAC5B,yBAAqB,IAAI;AACzB,eAAW,gBAAgB;AAC3B,UAAM,SAAS,EAAE,wBAAwB,IAAI;AAAA,EAC9C,GAAG,CAAC,sBAAsB,eAAe,WAAW,KAAK,CAAC;AAE1D,QAAM,eAAe,eAAe,CAAC,MAAM,EAAE,OAAO;AAEpD,QAAM,oBAAoBE,cAAY,MAAM;AAC3C,QAAI,aAAa;AAChB,YAAM,YAAY,MAAM,SAAS,EAAE;AACnC,UAAI,aAAa,CAAC,UAAU,WAAW,OAAO,GAAG;AAChD,cAAM,SAAS,EAAE,YAAY,SAAS;AACtC,eAAO,OAAO,SAAS,OAAO,EAAE,gBAAgB,UAAU,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAC5E;AACA,mBAAa,IAAI;AACjB,oBAAc,UAAU,WAAW,MAAM;AACxC,qBAAa,KAAK;AAClB,qBAAa,KAAK;AAAA,MACnB,GAAG,GAAG;AAAA,IACP,OAAO;AACN,mBAAa,KAAK;AAClB,iBAAW,IAAI;AACf,mBAAa,MAAM;AACnB,mBAAa,IAAI;AAAA,IAClB;AAAA,EACD,GAAG,CAAC,aAAa,cAAc,QAAQ,KAAK,CAAC;AAE7C,QAAM,cAAcA,cAAY,MAAM;AACrC,UAAM,YAAY,MAAM,SAAS,EAAE;AACnC,QAAI,aAAa,CAAC,UAAU,WAAW,OAAO,GAAG;AAChD,YAAM,SAAS,EAAE,YAAY,SAAS;AACtC,aAAO,OAAO,SAAS,OAAO,EAAE,gBAAgB,UAAU,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC5E;AACA,iBAAa,IAAI;AACjB,kBAAc,UAAU,WAAW,MAAM;AACxC,mBAAa,KAAK;AAClB,mBAAa,KAAK;AAAA,IACnB,GAAG,GAAG;AAAA,EACP,GAAG,CAAC,cAAc,QAAQ,KAAK,CAAC;AAEhC,QAAM,wBAAwBA,cAAY,YAAY;AACrD,UAAM,UAAU,QAAQ,KAAK;AAC7B,QAAI,CAAC,WAAW,WAAY;AAC5B,UAAM,OAAO,MAAM,OAAO,OAAO;AACjC,QAAI,MAAM;AACT,iBAAW,EAAE;AACb,iBAAW,cAAc;AAAA,IAC1B;AAAA,EACD,GAAG,CAAC,SAAS,YAAY,MAAM,CAAC;AAEhC,QAAM,YAAYD,SAAuB,IAAI;AAC7C,QAAM,YAAYA,SAA0B,IAAI;AAChD,QAAM,cAAcA,SAAyE,CAAC,CAAC;AAC/F,QAAM,cAAcA,SAAO,CAAC;AAC5B,QAAM,cAAcA,SAAO,CAAC;AAE5B,QAAM,mBAAmBC,cAAY,CAAC,MAAwB;AAC7D,gBAAY,UAAU,EAAE,QAAQ,CAAC,GAAG,WAAW;AAC/C,gBAAY,UAAU;AAAA,EACvB,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkBA,cAAY,CAAC,MAAwB;AAC5D,UAAM,SAAS,EAAE,QAAQ,CAAC,GAAG,WAAW,KAAK,YAAY;AACzD,gBAAY,UAAU;AACtB,QAAI,QAAQ,KAAK,UAAU,SAAS;AACnC,gBAAU,QAAQ,MAAM,YAAY,cAAc,KAAK,IAAI,OAAO,GAAG,CAAC;AACtE,gBAAU,QAAQ,MAAM,UAAU,GAAG,KAAK,IAAI,IAAI,QAAQ,KAAK,GAAG,CAAC;AAAA,IACpE;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,QAAM,iBAAiBA,cAAY,MAAM;AACxC,QAAI,UAAU,SAAS;AACtB,gBAAU,QAAQ,MAAM,YAAY;AACpC,gBAAU,QAAQ,MAAM,UAAU;AAAA,IACnC;AACA,QAAI,YAAY,UAAU,IAAI;AAC7B,kBAAY;AAAA,IACb;AAAA,EACD,GAAG,CAAC,WAAW,CAAC;AAQhB,EAAAF,YAAU,MAAM;AACf,QAAI,CAAC,UAAU,CAAC,UAAU,QAAS;AACnC,UAAM,KAAK,OAAO;AAClB,QAAI,CAAC,GAAI;AACT,UAAM,MAAM,UAAU;AACtB,UAAM,cAAc,MAAM;AACzB,UAAI,MAAM,YAAY,uBAAuB,GAAG,GAAG,MAAM,IAAI;AAAA,IAC9D;AACA,gBAAY;AACZ,OAAG,iBAAiB,UAAU,WAAW;AACzC,OAAG,iBAAiB,UAAU,WAAW;AACzC,WAAO,MAAM;AACZ,SAAG,oBAAoB,UAAU,WAAW;AAC5C,SAAG,oBAAoB,UAAU,WAAW;AAC5C,UAAI,MAAM,eAAe,qBAAqB;AAAA,IAC/C;AAAA,EACD,GAAG,CAAC,MAAM,CAAC;AAOX,EAAAA,YAAU,MAAM;AACf,QAAI,CAAC,UAAU,CAAC,UAAU,QAAS;AACnC,UAAM,MAAM,UAAU;AACtB,UAAM,gBAAgB,CAAC,MAAqB;AAC3C,UAAI,EAAE,QAAQ,UAAU;AACvB,YAAI,SAAS;AACZ,iBAAO;AAAA,QACR,OAAO;AACN,sBAAY;AACZ,qBAAW,MAAM,UAAU,SAAS,MAAM,GAAG,GAAG;AAAA,QACjD;AAAA,MACD;AAAA,IACD;AACA,QAAI,iBAAiB,WAAW,aAAa;AAC7C,WAAO,MAAM,IAAI,oBAAoB,WAAW,aAAa;AAAA,EAC9D,GAAG,CAAC,QAAQ,SAAS,aAAa,MAAM,CAAC;AAezC,EAAAA,YAAU,MAAM;AACf,QAAI,CAAC,UAAU,CAAC,UAAU,WAAW,aAAc;AACnD,UAAM,MAAM,UAAU;AACtB,UAAM,eAAe,MACpB,IAAI;AAAA,MACH;AAAA,IACD;AACD,UAAM,YAAY,MAAsB;AAGvC,YAAM,OAAO,IAAI,YAAY;AAC7B,UAAI,gBAAgB,WAAY,QAAO,KAAK;AAC5C,aAAO,SAAS;AAAA,IACjB;AACA,UAAM,YAAY,CAAC,MAAqB;AACvC,UAAI,EAAE,QAAQ,MAAO;AACrB,YAAM,YAAY,aAAa;AAC/B,UAAI,UAAU,WAAW,EAAG;AAC5B,YAAM,QAAQ,UAAU,CAAC;AACzB,YAAM,OAAO,UAAU,UAAU,SAAS,CAAC;AAC3C,YAAM,SAAS,UAAU;AACzB,UAAI,EAAE,YAAY,WAAW,OAAO;AACnC,UAAE,eAAe;AACjB,cAAM,MAAM;AAAA,MACb,WAAW,CAAC,EAAE,YAAY,WAAW,MAAM;AAC1C,UAAE,eAAe;AACjB,eAAO,MAAM;AAAA,MACd;AAAA,IACD;AACA,QAAI,iBAAiB,WAAW,SAAS;AAMzC,QAAI,cAAc,UAAU;AAC3B,YAAM,YAAY,aAAa;AAC/B,UAAI,UAAU,SAAS,EAAG,WAAU,CAAC,GAAG,MAAM;AAAA,IAC/C;AACA,WAAO,MAAM,IAAI,oBAAoB,WAAW,SAAS;AAAA,EAC1D,GAAG,CAAC,QAAQ,cAAc,SAAS,CAAC;AAEpC,QAAM,aAAa,YAAY;AAI/B,QAAM,EAAE,YAAY,cAAc,aAAa,WAAW,IAAI,kBAAkB;AAChF,QAAM,cAAc,aAAa;AACjC,QAAM,2BAA2B,CAAC,eAAe,gBAAgB;AACjE,QAAM,eAAe,aAAa,WAAW,SAAS,IACnD,EAAE,WAAW,IACb,2BACC,EAAE,sBAAsB,IACxB;AACJ,QAAM,aAAa,aAAa,cAAc;AAC9C,QAAM,iBAAiB,aAAa,kBAAkB;AACtD,QAAM,gBAAgB,aAAa,iBAAiB;AACpD,QAAM,cAAc,aAAa,eAAe;AAOhD,QAAM,oBAAoB,CAAC,CAAC,aAAa;AAEzC,SACC,gBAAAJ;AAAA,IAAC;AAAA;AAAA,MACA,WAAU;AAAA,MACV,qBAAmB;AAAA,MAInB,gBAAc,SAAS,SAAS;AAAA,MAChC,cAAY,gBAAgB,WAAW,SAAY;AAAA,MACnD,mBAAiB,oBAAoB,SAAS;AAAA,MAC9C,OACC;AAAA,QACC,gBAAgB;AAAA,QAChB,uBAAuB,mBAAmB,iBAAiB,SAAS;AAAA,QACpE,sBAAsB,mBAAmB,gBAAgB,SAAS;AAAA,QAClE,qBAAqB,mBAAmB,iBAAiB,MAAM;AAAA,QAC/D,oBAAoB,mBAAmB,gBAAgB,MAAM;AAAA,MAC9D;AAAA,MAGA;AAAA,sBAAc,YAAY,WAC1B,gBAAAD;AAAA,UAAC;AAAA;AAAA,YACA,OAAO,aAAa;AAAA,YACpB,UAAU,aAAa;AAAA,YACvB,UAAU,MAAM,eAAe;AAAA,YAC/B,UAAU,aAAa;AAAA,YACvB,aAAa,WAAW,SAAY;AAAA,YACpC,cAAc,CAAC,aAAa,eAAe,QAAQ;AAAA,YACnD,aAAa,aAAa;AAAA,YAC1B,YAAY,aAAa;AAAA,YACzB,oBAAoB,aAAa;AAAA,YACjC,UAAU;AAAA,YACV,WAAW,aAAa;AAAA,YACxB,kBAAkB,aAAa;AAAA;AAAA,QAChC;AAAA,QAEA,UAAU,CAAC,WAAW,CAAC,qBACvB,gBAAAA,MAAC,SAAI,WAAW,aAAa,YAAY,uBAAuB,EAAE,IACjE,0BAAAC,OAAC,SAAI,WAAU,uBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,UACrE,gBAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,UACrE,gBAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,WACtE,GACD;AAAA,QAEA,UAAU,qBACV,gBAAAA,MAAC,SAAI,WAAW,aAAa,YAAY,uBAAuB,EAAE,IACjE,0BAAAC,OAAC,SAAI,WAAU,sBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,2BAA2B,YAAE,mBAAmB,GAAE;AAAA,UACjE,gBAAAA,MAAC,YAAO,MAAK,UAAS,WAAU,4BAA2B,SAAS,gBAClE,YAAE,cAAc,GAClB;AAAA,WACD,GACD;AAAA,QAEA,UAAU,WACV,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACA,KAAK;AAAA,YACL,WAAW,aAAa,YAAY,uBAAuB,EAAE,IAC5D,YAAY,mBAAmB,uBAAuB,EACvD;AAAA,YACA,MAAK;AAAA,YACL,cAAY,EAAE,kBAAkB;AAAA,YAChC,cAAW;AAAA,YACX,cAAc;AAAA,YACd,aAAa;AAAA,YACb,YAAY;AAAA,YAGZ;AAAA,8BAAAD,MAAC,SAAI,WAAU,kBACd,0BAAAA,MAAC,SAAI,WAAU,uBAAsB,GACtC;AAAA,cAEC,kBACA,gBAAAC,OAAC,SAAI,WAAU,iBACd;AAAA,gCAAAD,MAAC,SAAI,WAAU,yBAAwB;AAAA,gBACtC,EAAE,qBAAqB;AAAA,iBACzB;AAAA,eAGC,YAAY,oBAAoB,YAAY,wBAC5C,MAAM;AACN,sBAAM,QAAQ,UAAU,QAAQ,YAAY,EAAE;AAC9C,sBAAM,aAAa,YAAY,KAAK,CAACQ,OAAMA,GAAE,OAAO,KAAK;AAEzD,sBAAM,cACL,YAAY,sBAAsB,sBAC/B,sBACA,YAAY,QACXN,cAAa,WAAW,KAAK,IAC7B,EAAE,gBAAgB;AACvB,uBACC,gBAAAD,OAAC,SAAI,WAAU,iCACd;AAAA,kCAAAD;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,SAAS;AAAA,sBACT,cAAY,EAAE,kBAAkB;AAAA,sBAEhC,0BAAAA;AAAA,wBAAC;AAAA;AAAA,0BACA,SAAQ;AAAA,0BACR,MAAK;AAAA,0BACL,QAAO;AAAA,0BACP,aAAa;AAAA,0BACb,eAAc;AAAA,0BACd,gBAAe;AAAA,0BAEf,0BAAAA,MAAC,UAAK,GAAE,mBAAkB;AAAA;AAAA,sBAC3B;AAAA;AAAA,kBACD;AAAA,kBACA,gBAAAA,MAAC,SAAI,WAAU,mBAAmB,uBAAY;AAAA,kBAC9C,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,SAAS;AAAA,sBACT,cAAY,EAAE,mBAAmB;AAAA,sBAEjC,0BAAAA,MAAC,cAAW,QAAQ,cAAc,UAAU;AAAA;AAAA,kBAC7C;AAAA,mBACD;AAAA,cAEF,GAAG;AAAA,cACH,YAAY,QAAQ,YAAY,oBAAoB,YAAY,sBAChE,gBAAAC,OAAC,SAAI,WAAU,4BACd;AAAA,gCAAAD;AAAA,kBAAC;AAAA;AAAA,oBACA,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,SAAS;AAAA,oBACT,cAAY,EAAE,kBAAkB;AAAA,oBAEhC,0BAAAA;AAAA,sBAAC;AAAA;AAAA,wBACA,SAAQ;AAAA,wBACR,MAAK;AAAA,wBACL,QAAO;AAAA,wBACP,aAAa;AAAA,wBACb,eAAc;AAAA,wBACd,gBAAe;AAAA,wBAEf,0BAAAA,MAAC,UAAK,GAAE,mBAAkB;AAAA;AAAA,oBAC3B;AAAA;AAAA,gBACD;AAAA,gBACA,gBAAAC,OAAC,SAAI,WAAU,sBACd;AAAA,kCAAAD;AAAA,oBAAC;AAAA;AAAA,sBACA,WAAW,qBAAqB,eAAe,8BAA8B,EAAE;AAAA,sBAE9E,0BAAgB,aAChB,gBAAAA,MAAC,SAAI,KAAK,YAAY,KAAK,YAAY,WAAU,uBAAsB,IACpE,eACH,gBAAAA,MAAC,UAAK,WAAU,4BACd,qBACC,MAAM,GAAG,EACT,IAAI,CAAC,MAAc,EAAE,CAAC,CAAC,EACvB,KAAK,EAAE,EACP,MAAM,GAAG,CAAC,EACV,YAAY,GACf,IAEA,gBAAAA,MAAC,cAAW;AAAA;AAAA,kBAEd;AAAA,kBACA,gBAAAC,OAAC,SAAI,WAAU,kBACd;AAAA,oCAAAD,MAAC,SAAI,WAAU,kBAAkB,sBAAW;AAAA,oBAM5C,gBAAAA,MAAC,SAAI,WAAU,oBAAoB,wBAAa;AAAA,qBACjD;AAAA,mBACD;AAAA,gBACA,gBAAAC,OAAC,SAAI,WAAU,qBACd;AAAA,kCAAAD;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,iBAAc;AAAA,sBACd,iBAAe;AAAA,sBACf,cAAY,EAAE,qBAAqB;AAAA,sBACnC,SAAS,CAAC,UAAU;AACnB,8BAAM,gBAAgB;AACtB,oCAAY,CAAC,SAAS,CAAC,IAAI;AAAA,sBAC5B;AAAA,sBAEA,0BAAAA,MAAC,YAAS,MAAM,IAAI;AAAA;AAAA,kBACrB;AAAA,kBACA,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,SAAS;AAAA,sBACT,cAAY,EAAE,mBAAmB;AAAA,sBAEjC,0BAAAA,MAAC,cAAW,QAAQ,cAAc,UAAU;AAAA;AAAA,kBAC7C;AAAA,kBACC,YACA,gBAAAC,OAAC,SAAI,WAAU,kBAAiB,MAAK,QAKnC;AAAA,kCAAc,SAAS,KACvB,gBAAAD,MAAC,SAAI,WAAU,wBACb,wBAAc,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,SAC/B,gBAAAC;AAAA,sBAAC;AAAA;AAAA,wBACA,MAAK;AAAA,wBACL,MAAK;AAAA,wBAEL,WAAU;AAAA,wBACV,eAAa,KAAK,OAAO,WAAW,SAAS;AAAA,wBAC7C,SAAS,MAAM;AACd,sCAAY,KAAK;AACjB,2CAAiB,KAAK,EAAE;AAAA,wBACzB;AAAA,wBAEA;AAAA,0CAAAA,OAAC,UAAK,WAAU,2BACf;AAAA,4CAAAD,MAAC,UAAK,WAAU,4BACd,+BAAqB,IAAI,EAAE,aAAa,aAC1C;AAAA,4BACC,KAAK,iBACL,gBAAAA,MAAC,UAAK,WAAU,4BACd,6BAAmB,KAAK,aAAa,GACvC;AAAA,6BAEF;AAAA,0BACA,gBAAAA,MAAC,UAAK,WAAU,+BACd,eAAK,mBAAmB,EAAE,mBAAmB,GAC/C;AAAA;AAAA;AAAA,sBApBK,KAAK;AAAA,oBAqBX,CACA,GACF;AAAA,oBAED,gBAAAC;AAAA,sBAAC;AAAA;AAAA,wBACA,MAAK;AAAA,wBACL,MAAK;AAAA,wBACL,SAAS,MAAM;AACd,sCAAY,KAAK;AACjB,8CAAoB;AAAA,wBACrB;AAAA,wBAEA;AAAA,0CAAAD,MAAC,eAAY,MAAM,IAAI;AAAA,0BACtB,EAAE,yBAAyB;AAAA;AAAA;AAAA,oBAC7B;AAAA,qBACD;AAAA,mBAEF;AAAA,iBACD;AAAA,cAIA,YAAY,QAAQ,cAAc,UAClC,gBAAAC,OAAAF,WAAA,EACC;AAAA,gCAAAE,OAAC,SAAI,WAAU,WACd;AAAA,kCAAAA,OAAC,SAAI,WAAU,eACd;AAAA,oCAAAD,MAAC,SAAI,WAAU,oBACd,0BAAAA,MAAC,cAAW,GACb;AAAA,oBACA,gBAAAA;AAAA,sBAAC;AAAA;AAAA,wBACA,MAAK;AAAA,wBACL,WAAU;AAAA,wBACV,SAAS;AAAA,wBACT,cAAY,EAAE,mBAAmB;AAAA,wBAEjC,0BAAAA,MAAC,cAAW,QAAQ,cAAc,UAAU;AAAA;AAAA,oBAC7C;AAAA,qBACD;AAAA,kBACA,gBAAAA,MAAC,SAAI,WAAU,oBACb,yBAAe,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,MACtC,gBAAAC;AAAA,oBAAC;AAAA;AAAA,sBAEA,WAAW,MAAM,IAAI,0BAA0B;AAAA,sBAE9C;AAAA,4BAAI,KAAK,gBAAAD,MAAC,QAAG;AAAA,wBACb;AAAA;AAAA;AAAA,oBAJI;AAAA,kBAKN,CACA,GACF;AAAA,kBACA,gBAAAA,MAAC,SAAI,WAAU,oBAAoB,wBAAa;AAAA,mBACjD;AAAA,gBAGA,gBAAAA,MAAC,SAAI,WAAU,YACd,0BAAAC,OAAC,SAAI,WAAU,kBACd;AAAA,kCAAAA,OAAC,YAAO,MAAK,UAAS,WAAU,WAAU,SAAS,qBAClD;AAAA,oCAAAA,OAAC,SAAI,WAAU,gBACd;AAAA,sCAAAD,MAAC,SAAI,WAAU,iBAAiB,YAAE,wBAAwB,GAAE;AAAA,sBAC5D,gBAAAA,MAAC,SAAI,WAAU,gBAAgB,YAAE,mBAAmB,GAAE;AAAA,uBACvD;AAAA,oBACA,gBAAAA,MAAC,SAAI,WAAU,iBACd,0BAAAA,MAAC,YAAS,GACX;AAAA,qBACD;AAAA,kBACC,iBAAiB,SAAS,KAC1B,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA,WAAW,MAAM;AAChB,kCAAU,WAAW,iBAAiB,CAAC,EAAG,EAAE,EAAE;AAAA,sBAC/C;AAAA,sBACA,UAAU,CAAC,MAAM,UAAU;AAC1B,kCAAU,WAAW,KAAK,EAAE;AAC5B,6CAAqB,IAAI;AACzB,mCAAW,gBAAgB;AAC3B,sCAAc,IAAI;AAAA,sBACnB;AAAA;AAAA,kBACD;AAAA,kBAED,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACA;AAAA,sBACA,UAAU;AAAA,sBACV,iBAAiB,MAAM,UAAU,UAAU;AAAA;AAAA,kBAC5C;AAAA,mBACD,GACD;AAAA,iBACD;AAAA,cAIA,YAAY,QAAQ,cAAc,cAClC,gBAAAC,OAAC,SAAI,WAAU,iCACd;AAAA,gCAAAD,MAAC,SAAI,WAAU,oBAAmB;AAAA,gBAClC,gBAAAA,MAAC,SAAI,WAAU,mBAAmB,YAAE,iBAAiB,GAAE;AAAA,gBACvD,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACA,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,SAAS;AAAA,oBACT,cAAY,EAAE,mBAAmB;AAAA,oBAEjC,0BAAAA,MAAC,cAAW,QAAQ,cAAc,UAAU;AAAA;AAAA,gBAC7C;AAAA,iBACD;AAAA,cAIA,YAAY,QACZ,UAAU,WAAW,UAAU,MAC9B,MAAM;AACN,sBAAM,QAAQ,UAAU,QAAQ,YAAY,EAAE;AAC9C,sBAAM,aAAa,YAAY,KAAK,CAACQ,OAAMA,GAAE,OAAO,KAAK;AACzD,oBAAI,CAAC,WAAY,QAAO;AACxB,uBACC,gBAAAP,OAAC,SAAI,WAAU,iCACd;AAAA,kCAAAD,MAAC,SAAI,WAAU,oBAAmB;AAAA,kBAClC,gBAAAA,MAAC,SAAI,WAAU,mBAAmB,UAAAE,cAAa,WAAW,KAAK,GAAE;AAAA,kBACjE,gBAAAF;AAAA,oBAAC;AAAA;AAAA,sBACA,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,SAAS;AAAA,sBACT,cAAY,EAAE,mBAAmB;AAAA,sBAEjC,0BAAAA,MAAC,cAAW,QAAQ,cAAc,UAAU;AAAA;AAAA,kBAC7C;AAAA,mBACD;AAAA,cAEF,GAAG;AAAA,eAGF,YAAY,QAAQ,cAAc,WACnC,gBAAAC,OAAC,SAAI,WAAU,cACb;AAAA,4BAAY,QAAQ,cAAc,cAClC,gBAAAD;AAAA,kBAAC;AAAA;AAAA,oBACA;AAAA,oBACA,UAAU;AAAA,oBACV,YAAY;AAAA;AAAA,gBACb;AAAA,gBAGA,YAAY,SACZ,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACA,MAAM;AAAA,oBACN,cAAc;AAAA,oBACd,UAAU;AAAA,oBACV,cAAc;AAAA,oBACd;AAAA;AAAA,gBACD;AAAA,gBAGA,YAAY,kBAAkB,YAC9B,gBAAAA,MAAC,oBAAiB,gBAAgB,UAAU,UAAU,iBAAiB;AAAA,gBAIvE,UAAU,WAAW,UAAU,MAC9B,MAAM;AACN,wBAAM,QAAQ,UAAU,QAAQ,YAAY,EAAE;AAC9C,wBAAM,aAAa,YAAY,KAAK,CAACQ,OAAMA,GAAE,OAAO,KAAK;AACzD,sBAAI,CAAC,WAAY,QAAO;AACxB,yBACC,gBAAAR;AAAA,oBAAC;AAAA;AAAA,sBACA,KAAK;AAAA,sBACL,YAAY,YAAY;AAAA,sBACxB,YAAY;AAAA,sBACZ;AAAA,sBACA,eAAe,CAAC,SAAS;AACxB,6CAAqB,IAAI;AACzB,mCAAW,gBAAgB;AAK3B,sCAAc,IAAI;AAAA,sBACnB;AAAA,sBACA,kBAAkB,CAAC,QAAQ;AAC1B,+CAAuB,IAAI,KAAK;AAChC,mCAAW,kBAAkB;AAAA,sBAC9B;AAAA;AAAA,kBACD;AAAA,gBAEF,GAAG;AAAA,iBACL;AAAA,cAIA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACA;AAAA,kBACA,aAAa;AAAA,kBACb,aAAa;AAAA,kBACb;AAAA,kBACA,iBAAiB,aAAa,mBAAmB;AAAA,kBACjD;AAAA;AAAA,cACD;AAAA,cAID,gBAAAC,OAAC,SAAI,WAAU,cACb;AAAA,kBAAE,mBAAmB;AAAA,gBAAG;AAAA,gBACzB,gBAAAD,MAAC,OAAE,MAAK,sBAAqB,QAAO,UAAS,KAAI,uBAAsB,qBAEvE;AAAA,iBACD;AAAA;AAAA;AAAA,QACD;AAAA,QAUA,WAAW,CAAC,UAAU,CAAC,eAAe,CAAC,gBACvC,gBAAAC,OAAC,SAAI,WAAU,mBAMd;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACA,YAAY,kBAAkB,IAAI;AAAA,cAClC,QAAQ,gBAAAA,MAAC,cAAW;AAAA,cACpB,QAAQ,CAAC,MAAM,UAAU;AACxB,8BAAc,IAAI;AAClB,kCAAkB;AAClB,2BAAW,MAAM;AAChB,4BAAU,WAAW,KAAK,EAAE;AAC5B,uCAAqB,IAAI;AACzB,6BAAW,gBAAgB;AAAA,gBAC5B,GAAG,EAAE;AAAA,cACN;AAAA;AAAA,UACD;AAAA,UAUA,gBAAAA,MAAC,kBAAe,QAAQ,mBAAmB,QAAQ,gBAAAA,MAAC,cAAW,GAAI,eAAe,MAAM;AAAA,WACzF;AAAA,QAID,gBAAAA,MAAC,sBAAmB;AAAA,QAOnB,WAAW,CAAC,gBAAgB,CAAC,gBAAgB,WAC7C,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACA,KAAK;AAAA,YACL,MAAK;AAAA,YACL,WAAW;AAAA,cACV;AAAA,cACA,cAAc,WAAW;AAAA,cACzB,kBAAkB,SAAS,uBAAuB,aAAa,KAAK;AAAA,cACpE,SAAS,oBAAoB;AAAA,cAC7B,aAAa,mBAAmB,aAAa,aAAa,SAAS,UAChE,sBACA;AAAA,YACJ,EACE,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,YACV,SAAS;AAAA,YACT,cAAY,SAAS,EAAE,2BAA2B,IAAI,EAAE,kBAAkB;AAAA,YAC1E,iBAAe;AAAA,YACf,iBAAc;AAAA,YAEd;AAAA,8BAAAD;AAAA,gBAAC;AAAA;AAAA,kBACA,WAAW,sCAAsC,SAAS,2BAA2B,EAAE;AAAA,kBAEvF,0BAAAA,MAAC,gBAAa;AAAA;AAAA,cACf;AAAA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACA,WAAW,wCAAwC,CAAC,SAAS,2BAA2B,EAAE;AAAA,kBAE1F,0BAAAA,MAAC,SAAM,MAAM,IAAI;AAAA;AAAA,cAClB;AAAA,cACC,kBAAkB,UAAU,CAAC,UAC7B,gBAAAA,MAAC,UAAK,WAAU,mBACd,4BAAkB,SAAS,EAAE,aAAa,IAAI,aAChD;AAAA,cAEA,CAAC,WAAW,cAAc,KAAK,gBAAgB,KAAK,0BAA0B,MAC9E,gBAAAC,OAAC,SAAI,WAAU,mBACb;AAAA,8BAAc,IAAI,cAAc;AAAA,gBAKhC,gBAAgB,MAAM,gBAAgB,KAAK,0BAA0B,MACrE,gBAAAD,MAAC,UAAK,WAAU,uBAAsB;AAAA,iBAExC;AAAA;AAAA;AAAA,QAEF;AAAA;AAAA;AAAA,EAEF;AAEF;AAIA,SAAS,OAAO;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,0BAA0B;AAC3B,GAOG;AACF,SACC,gBAAAC,OAAC,SAAI,WAAU,WAAU,MAAK,WAC7B;AAAA,oBAAAA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAW,gBAAgB,cAAc,SAAS,yBAAyB,EAAE;AAAA,QAC7E,SAAS,MAAM,YAAY,MAAM;AAAA,QACjC,MAAK;AAAA,QACL,iBAAe,cAAc;AAAA,QAE7B;AAAA,0BAAAD,MAAC,YAAS;AAAA,UACV,gBAAAA,MAAC,UAAM,YAAE,aAAa,GAAE;AAAA;AAAA;AAAA,IACzB;AAAA,IACC,mBACA,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAW,gBAAgB,cAAc,aAAa,yBAAyB,EAAE;AAAA,QACjF,SAAS,MAAM,YAAY,UAAU;AAAA,QACrC,MAAK;AAAA,QACL,iBAAe,cAAc;AAAA,QAE7B;AAAA,0BAAAA,OAAC,UAAK,WAAU,qBACf;AAAA,4BAAAD,MAAC,gBAAa;AAAA,YACb,cAAc,KACd,gBAAAA,MAAC,UAAK,WAAU,iBAAiB,wBAAc,KAAK,QAAQ,aAAY;AAAA,aAE1E;AAAA,UACA,gBAAAA,MAAC,UAAM,YAAE,iBAAiB,GAAE;AAAA;AAAA;AAAA,IAC7B;AAAA,IAGA,YAAY,IAAI,CAAC,QACjB,gBAAAC;AAAA,MAAC;AAAA;AAAA,QAEA,MAAK;AAAA,QACL,WAAW,gBAAgB,cAAc,WAAW,IAAI,EAAE,KAAK,yBAAyB,EAAE;AAAA,QAC1F,SAAS,MAAM,YAAY,WAAW,IAAI,EAAE,EAAE;AAAA,QAC9C,MAAK;AAAA,QACL,iBAAe,cAAc,WAAW,IAAI,EAAE;AAAA,QAE9C;AAAA,0BAAAA,OAAC,UAAK,WAAU,qBACf;AAAA,4BAAAD,MAAC,2BAAwB,MAAM,IAAI,MAAM;AAAA,YACxC,IAAI,mBAAmB,0BAA0B,KAAK,gBAAAA,MAAC,UAAK,WAAU,eAAc;AAAA,aACtF;AAAA,UACA,gBAAAA,MAAC,UAAM,UAAAE,cAAa,IAAI,KAAK,GAAE;AAAA;AAAA;AAAA,MAX1B,IAAI;AAAA,IAYV,CACA;AAAA,KACF;AAEF;AAIA,SAAS,SAAS;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACD,GAIG;AACF,QAAM,SAAS,cAAc,MAAM,GAAG,CAAC;AACvC,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,SACC,gBAAAD,OAAC,SAAI,WAAU,kBACd;AAAA,oBAAAD,MAAC,SAAI,WAAU,oBAAoB,YAAE,6BAA6B,GAAE;AAAA,IACnE,OAAO,IAAI,CAAC,MAAM,MAClB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEA,cAAc;AAAA,QACd;AAAA,QACA,QAAQ,MAAM,OAAO,SAAS;AAAA;AAAA,MAHzB,KAAK;AAAA,IAIX,CACA;AAAA,IACA,cAAc,SAAS,KACvB,gBAAAA,MAAC,YAAO,MAAK,UAAS,WAAU,qBAAoB,SAAS,iBAC3D,YAAE,gBAAgB,GACpB;AAAA,KAEF;AAEF;AAIA,SAAS,aAAa;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AACD,GAIG;AACF,MAAI,cAAc,WAAW,GAAG;AAC/B,WACC,gBAAAC,OAAC,SAAI,WAAU,kBACd;AAAA,sBAAAD,MAAC,SAAI,WAAU,sBACd,0BAAAA,MAAC,gBAAa,GACf;AAAA,MACA,gBAAAA,MAAC,SAAI,WAAU,kBAAkB,YAAE,oBAAoB,GAAE;AAAA,MACzD,gBAAAA,MAAC,SAAI,WAAU,iBAAiB,YAAE,yBAAyB,GAAE;AAAA,MAC7D,gBAAAA,MAAC,YAAO,MAAK,UAAS,WAAU,gBAAe,SAAS,YACtD,YAAE,2BAA2B,GAC/B;AAAA,OACD;AAAA,EAEF;AAEA,SACC,gBAAAA,MAAC,SAAI,WAAU,eACb,wBAAc,IAAI,CAAC,SACnB,gBAAAA,MAAC,oBAA+B,cAAc,MAAM,YAA7B,KAAK,EAA4C,CACxE,GACF;AAEF;AAIA,SAAS,aAAa,EAAE,KAAK,GAAkC;AAC9D,QAAM,YAAY,eAAe,CAAC,MAAM,EAAE,aAAa,IAAI,KAAK;AAQhE,QAAM,EAAE,WAAW,WAAW,IAAI,qBAAqB,IAAI;AAC3D,QAAM,SAAS,CAAC,CAAC;AACjB,QAAM,cAAc,aAAa;AACjC,QAAM,UAAU,KAAK,mBAAmB,EAAE,mBAAmB;AAC7D,SACC,gBAAAC,OAAAF,WAAA,EACC;AAAA,oBAAAC,MAAC,SAAI,WAAW,sBAAsB,SAAS,+BAA+B,EAAE,IAC9E,mBACA,aACC,gBAAAA,MAAC,SAAI,KAAK,YAAY,KAAK,aAAa,WAAU,2BAA0B,IAE5E,gBAAAA,MAAC,UAAK,WAAU,gCACd,sBACC,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EACf,KAAK,EAAE,EACP,MAAM,GAAG,CAAC,EACV,YAAY,GACf,IAGD,gBAAAA,MAAC,cAAW,GAEd;AAAA,IACA,gBAAAC,OAAC,SAAI,WAAU,wBACd;AAAA,sBAAAA,OAAC,SAAI,WAAU,oBACd;AAAA,wBAAAD,MAAC,UAAK,WAAU,qBAAqB,uBAAY;AAAA,QAChD,KAAK,iBACL,gBAAAA,MAAC,UAAK,WAAU,qBAAqB,6BAAmB,KAAK,aAAa,GAAE;AAAA,SAE9E;AAAA,MACA,gBAAAA,MAAC,SAAI,WAAU,wBAAwB,mBAAQ;AAAA,OAChD;AAAA,KACD;AAEF;AAIA,SAAS,iBAAiB;AAAA,EACzB,cAAc;AAAA,EACd;AACD,GAGG;AACF,QAAM,YAAY,KAAK,cAAc;AASrC,QAAM,WAAW,CAAC,aAAa,uBAAuB,IAAI;AAE1D,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,MAAK;AAAA,MACL,WAAW,gBAAgB,YAAY,yBAAyB,EAAE;AAAA,MAClE,SAAS,MAAM,SAAS,KAAK,EAAE;AAAA,MAE/B;AAAA,wBAAAD,MAAC,SAAI,WAAU,oBACd,0BAAAA,MAAC,gBAAa,MAAY,GAC3B;AAAA,QACC,aAAa,gBAAAA,MAAC,SAAI,WAAU,sBAAsB,eAAK,aAAY;AAAA,QACnE,YAAY,gBAAAA,MAAC,SAAI,WAAU,eAAe,YAAE,4BAA4B,GAAE;AAAA;AAAA;AAAA,EAC5E;AAEF;AAIA,SAAS,gBAAgB;AAAA,EACxB,cAAc;AAAA,EACd;AAAA,EACA;AACD,GAIG;AACF,QAAM,YAAY,KAAK,cAAc;AACrC,QAAM,WAAW,CAAC,aAAa,uBAAuB,IAAI;AAE1D,SACC,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACA,MAAK;AAAA,MACL,WAAW,iBAAiB,YAAY,0BAA0B,EAAE,IAAI,SAAS,wBAAwB,EAAE;AAAA,MAC3G,SAAS,MAAM,SAAS,KAAK,EAAE;AAAA,MAE/B;AAAA,wBAAAD,MAAC,gBAAa,MAAY;AAAA,QACzB,aAAa,gBAAAA,MAAC,SAAI,WAAU,uBAAuB,eAAK,aAAY;AAAA,QACpE,YAAY,gBAAAA,MAAC,SAAI,WAAU,eAAe,YAAE,4BAA4B,GAAE;AAAA;AAAA;AAAA,EAC5E;AAEF;AAIA,SAAS,kBAAkB,EAAE,eAAe,GAAgC;AAC3E,QAAM,EAAE,QAAQ,MAAM,IAAI,iBAAiB;AAC3C,QAAM,gBAAgB,eAAe,CAAC,MAAM,EAAE,oBAAoB;AAClE,QAAM,CAAC,OAAO,QAAQ,IAAII,WAAS,EAAE;AACrC,QAAM,CAAC,cAAc,eAAe,IAAIA,WAAS,KAAK;AACtD,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAS,KAAK;AAChD,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAS,KAAK;AAE9C,QAAM,eAAe,YAAY;AAChC,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,CAAC,WAAW,CAAC,6BAA6B,KAAK,OAAO,GAAG;AAC5D,kBAAY,IAAI;AAChB;AAAA,IACD;AACA,gBAAY,KAAK;AAEjB,UAAM,kBAAkB,MAAM,SAAS,EAAE,SAAS,WAAW;AAC7D,UAAM,sBAAsB,iBAAiB,MAAM,sBAAsB,KAAK,IAAI,CAAC;AACnF,kBAAc;AAAA,MACb,IAAI;AAAA,MACJ,MAAM,iBAAiB,QAAQ;AAAA,MAC/B,OAAO;AAAA,IACR,CAAC;AACD,iBAAa,IAAI;AACjB,oBAAgB,IAAI;AACpB,QAAI;AACH,YAAM,SAAS,MAAM,OAAO,OAAO,aAAa,OAAO;AAAA,QACtD,OAAO;AAAA,QACP,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;AAAA,MAC5C,CAAC;AACD,UAAI,OAAO,SAAS;AACnB,sBAAc;AAAA,UACb,IAAI,OAAO,QAAQ;AAAA,UACnB,MAAM,OAAO,QAAQ;AAAA,UACrB,OAAO,OAAO,QAAQ;AAAA,QACvB,CAAC;AAAA,MACF;AAAA,IAED,QAAQ;AACP,UAAI,iBAAiB;AACpB,sBAAc,eAAe;AAAA,MAC9B,OAAO;AACN,sBAAc,EAAE,IAAI,IAAI,MAAM,MAAM,OAAO,KAAK,CAAC;AAAA,MAClD;AACA,mBAAa,KAAK;AAAA,IACnB,UAAE;AACD,sBAAgB,KAAK;AAAA,IACtB;AAAA,EACD;AAEA,MAAI,WAAW;AACd,WACC,gBAAAH,OAAC,SAAI,WAAU,wCACd;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACA,OAAM;AAAA,UACN,QAAO;AAAA,UACP,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,QAAO;AAAA,UACP,aAAa;AAAA,UACb,eAAc;AAAA,UACd,gBAAe;AAAA,UAEf,0BAAAA,MAAC,cAAS,QAAO,kBAAiB;AAAA;AAAA,MACnC;AAAA,MACC,EAAE,oBAAoB;AAAA,OACxB;AAAA,EAEF;AAOA,SACC,gBAAAC,OAAC,SAAI,WAAU,iBACd;AAAA,oBAAAD,MAAC,OAAE,WAAU,uBAAuB,YAAE,oBAAoB,GAAE;AAAA,IAC5D,gBAAAA,MAAC,OAAE,WAAU,0BAA0B,YAAE,uBAAuB,GAAE;AAAA,IAClE,gBAAAC,OAAC,SAAI,WAAU,qBACd;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAW,sBAAsB,WAAW,gCAAgC,EAAE;AAAA,UAC9E,OAAO;AAAA,UACP,UAAU,CAAC,MAAM;AAChB,qBAAS,EAAE,OAAO,KAAK;AACvB,wBAAY,KAAK;AAAA,UAClB;AAAA,UACA,WAAW,CAAC,MAAM;AACjB,gBAAI,EAAE,QAAQ,QAAS,cAAa;AAAA,UACrC;AAAA,UACA,aAAa,EAAE,0BAA0B;AAAA;AAAA,MAC1C;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS;AAAA,UACT,UAAU,gBAAgB,CAAC,MAAM,KAAK;AAAA,UACtC,cAAY,EAAE,uBAAuB;AAAA,UAEpC,yBACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACA,OAAM;AAAA,cACN,QAAO;AAAA,cACP,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,QAAO;AAAA,cACP,aAAa;AAAA,cACb,eAAY;AAAA,cAEZ,0BAAAA,MAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK,iBAAgB,MAAK,kBAAiB,MACpE,0BAAAA;AAAA,gBAAC;AAAA;AAAA,kBACA,eAAc;AAAA,kBACd,QAAO;AAAA,kBACP,KAAI;AAAA,kBACJ,aAAY;AAAA;AAAA,cACb,GACD;AAAA;AAAA,UACD,IAEA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACA,OAAM;AAAA,cACN,QAAO;AAAA,cACP,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,QAAO;AAAA,cACP,aAAa;AAAA,cACb,eAAc;AAAA,cACd,gBAAe;AAAA,cACf,eAAY;AAAA,cAEZ,0BAAAA,MAAC,UAAK,GAAE,yBAAwB;AAAA;AAAA,UACjC;AAAA;AAAA,MAEF;AAAA,OACD;AAAA,KACD;AAEF;AAIA,SAAS,oBAAoB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAMG;AAEF,SACC,gBAAAC,OAAC,SAAI,WAAU,UAOd;AAAA,oBAAAD,MAAC,SAAI,WAAU,kBACd,0BAAAA,MAAC,iBAAc,MAAM,gBAAgB,QAAO,MAAK,OAAO,MAAM,GAC/D;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,EAAE,wBAAwB;AAAA;AAAA,IACxC;AAAA,KACD;AAEF;AAIA,SAAS,iBAAiB;AAAA,EACzB;AAAA,EACA;AACD,GAIG;AACF,QAAM,EAAE,OAAO,WAAW,SAAS,SAAS,IAAI,YAAY,cAAc;AAC1E,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI,YAAY,cAAc;AAC9B,QAAM,EAAE,UAAU,gBAAgB,UAAU,IAAI,YAAY,cAAc;AAC1E,QAAM,gBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,IAAI,cAAc,KAAK,EAAE;AACrF,QAAM,cAAc,eAAe,CAAC,MAAM,EAAE,WAAW;AACvD,QAAM,iBAAiB,eAAe,CAAC,MAAM,EAAE,SAAS,OAAO;AAO/D,QAAM,eAAe,CAAC,CAAC,UAAU,UAAU,MAAM,UAAU;AAQ3D,QAAM,aAAa,eAAe,CAAC,MAAM;AACxC,UAAM,OAAO,EAAE,cAAc,KAAK,CAAC,MAAM,EAAE,OAAO,cAAc;AAChE,WAAO,MAAM,WAAW;AAAA,EACzB,CAAC;AAQD,QAAM,sBAAsB,MAAM;AAAA,IACjC,CAAC,OAAO,GAAG,SAAS,aAAa,QAAS,GAAqC,SAAS;AAAA,EACzF,EAAE;AACF,QAAM,aAAa,MAAM;AAAA,IACxB,CAAC,OAAO,GAAG,SAAS,aAAa,QAAS,GAAqC,SAAS;AAAA,EACzF;AAKA,QAAM,kBAAkB,eAAe,CAAC,MAAM,EAAE,SAAS,KAAK;AAC9D,QAAM,WAAW,CAAC,CAAC,gBAAgB,SAAS,CAAC,CAAC;AAC9C,QAAM,sBACL,CAAC,CAAC,aAAa,uBAAuB,CAAC,YAAY,uBAAuB,KAAK;AAChF,QAAM,aAAa,uBAAuB,CAAC,CAAC;AAE5C,MAAI,aAAa,MAAM,WAAW,GAAG;AACpC,WACC,gBAAAA,MAAC,SAAI,WAAU,eACd,0BAAAC,OAAC,SAAI,WAAU,wBAEd;AAAA,sBAAAA,OAAC,SAAI,WAAU,mBACd;AAAA,wBAAAD,MAAC,SAAI,WAAU,kCAAiC;AAAA,QAChD,gBAAAC,OAAC,SAAI,WAAU,sBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,UACrE,gBAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,WACtE;AAAA,SACD;AAAA,MAEA,gBAAAA,MAAC,SAAI,WAAU,0CACd,0BAAAA,MAAC,SAAI,WAAU,sBAAqB,OAAO,EAAE,YAAY,WAAW,GACnE,0BAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG,GACtE,GACD;AAAA,MAEA,gBAAAC,OAAC,SAAI,WAAU,mBACd;AAAA,wBAAAD,MAAC,SAAI,WAAU,kCAAiC;AAAA,QAChD,gBAAAC,OAAC,SAAI,WAAU,sBACd;AAAA,0BAAAD,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,UACrE,gBAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,IAAI,GAAG;AAAA,UACrE,gBAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,GAAG,GAAG;AAAA,WACrE;AAAA,SACD;AAAA,OACD,GACD;AAAA,EAEF;AAEA,SACC,gBAAAC,OAAAF,WAAA,EACC;AAAA,oBAAAC;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QAQA,UAAU,YAAY,CAAC;AAAA,QACvB,gBAAgB,kBAAkB,CAAC;AAAA,QACnC,eAAe,iBAAiB;AAAA,QAChC;AAAA,QACA,eAAe;AAAA,QACf,YAAY;AAAA,QAYZ,qBACC,cAAc,eACb,gBAAAC,OAAAF,WAAA,EACE;AAAA,wBAAc,gBAAAC,MAAC,qBAAkB,gBAAgB,mBAAmB,QAAW;AAAA,UAC/E,gBACA,gBAAAA,MAAC,SAAI,WAAU,eACb,oBAAU,IAAI,CAAC,OAAO,UAAU;AAChC,kBAAM,WAAW,OAAO,UAAU,WAAW,QAAQ,MAAM;AAC3D,kBAAM,QAAQ,OAAO,UAAU,WAAW,OAAO,MAAM;AAOvD,mBACC,gBAAAC;AAAA,cAAC;AAAA;AAAA,gBAEA,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,OAAO,EAAE,gBAAgB,GAAG,KAAK,QAAQ,EAAE,KAAK;AAAA,gBAChD,SAAS,MAAM;AACd,uBAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAAA,gBAC/B;AAAA,gBAEA;AAAA,kCAAAA,OAAC,UAAK,WAAU,mBACf;AAAA,oCAAAD,MAAC,UAAK,WAAU,gBAAgB,mBAAS,UAAS;AAAA,oBACjD,SAAS,gBAAAA,MAAC,UAAK,WAAU,gBAAgB,oBAAS;AAAA,qBACpD;AAAA,kBACA,gBAAAA,MAAC,oBAAiB,MAAM,IAAI;AAAA;AAAA;AAAA,cAZvB;AAAA,YAaN;AAAA,UAEF,CAAC,GACF;AAAA,WAEF,IACG;AAAA;AAAA,IAEN;AAAA,IAKC,cAAc,gBAAAA,MAAC,kBAAe,gBAAgC;AAAA,IAC9D,aACA,gBAAAC,OAAC,SAAI,WAAU,iBACb;AAAA;AAAA,MACD,gBAAAD;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS,MAAM;AACd,2BAAe;AACf,mBAAO;AAAA,UACR;AAAA,UAEC,YAAE,cAAc;AAAA;AAAA,MAClB;AAAA,OACD;AAAA,IAED,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA,cAAc;AAAA,QACd,UAAU;AAAA,QACV,UAAU;AAAA,QACV;AAAA,QACA;AAAA,QACA,YAAY;AAAA,QACZ,oBAAoB;AAAA,QACpB,UAAU;AAAA;AAAA,IACX;AAAA,KACD;AAEF;AAIA,SAAS,eAAe,EAAE,eAAe,GAA+B;AACvE,QAAM,EAAE,OAAO,IAAI,iBAAiB;AACpC,QAAM,CAAC,YAAY,aAAa,IAAII,WAAgC,IAAI;AACxE,QAAM,CAAC,eAAe,gBAAgB,IAAIA,WAAS,KAAK;AAExD,QAAM,aAAa,CAAC,WAA2B;AAC9C,kBAAc,MAAM;AACpB,qBAAiB,IAAI;AAErB,WAAO,OAAO,SAAS,OAAO,EAAE,gBAAgB,OAAO,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACzE;AAEA,SACC,gBAAAH,OAAC,SAAI,WAAU,eACd;AAAA,oBAAAD,MAAC,SAAI,WAAU,oBAAoB,YAAE,sBAAsB,GAAE;AAAA,IAC5D,CAAC,gBACD,gBAAAC,OAAC,SAAI,WAAU,WACd;AAAA,sBAAAD,MAAC,SAAI,WAAU,iBAAiB,YAAE,mBAAmB,GAAE;AAAA,MACvD,gBAAAC,OAAC,SAAI,WAAU,mBACd;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACA,MAAK;AAAA,YACL,WAAW,eAAe,eAAe,SAAS,0BAA0B,EAAE;AAAA,YAC9E,SAAS,MAAM,WAAW,MAAM;AAAA,YAChC,cAAY,EAAE,kBAAkB;AAAA,YAChC;AAAA;AAAA,QAED;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACA,MAAK;AAAA,YACL,WAAW,eAAe,eAAe,QAAQ,0BAA0B,EAAE;AAAA,YAC7E,SAAS,MAAM,WAAW,KAAK;AAAA,YAC/B,cAAY,EAAE,iBAAiB;AAAA,YAC/B;AAAA;AAAA,QAED;AAAA,SACD;AAAA,OACD,IAEA,gBAAAA,MAAC,SAAI,WAAU,kBAAkB,YAAE,oBAAoB,GAAE;AAAA,KAE3D;AAEF;AAiBA,SAAS,aAAa;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAKG;AACF,QAAM,SAAS,iBAAiB;AAChC,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,QAAM,UAAU,OAAO,MAAM,GAAG,CAAC;AACjC,QAAM,gBAAgB,IAAI,IAAI,iBAAiB,IAAI,CAACQ,OAAM,CAACA,GAAE,IAAIA,GAAE,SAAS,UAAU,CAAC,CAAC;AAExF,SACC,gBAAAP,OAAC,SAAI,WAAU,gBACd;AAAA,oBAAAA,OAAC,SAAI,WAAU,uBACd;AAAA,sBAAAD,MAAC,UAAK,WAAU,sBAAsB,UAAAE,cAAa,kBAAkB,GAAE;AAAA,MACvE,gBAAAD,OAAC,YAAO,MAAK,UAAS,WAAU,yBAAwB,SAAS,WAC/D;AAAA,QAAAC,cAAa,iBAAiB;AAAA,QAAE;AAAA,SAClC;AAAA,OACD;AAAA,IACA,gBAAAF,MAAC,SAAI,WAAU,qBACb,kBAAQ,IAAI,CAAC,UAAU;AACvB,YAAM,aAAa,cAAc,IAAI,MAAM,KAAK;AAChD,aACC,gBAAAC;AAAA,QAAC;AAAA;AAAA,UAEA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS,MAAM,SAAS,MAAM,MAAM,MAAM,KAAK;AAAA,UAE9C;AAAA,0BAAc,MAAM,aAAa,UAAU,KAC3C,gBAAAA,OAAC,SAAI,WAAU,yBACd;AAAA,8BAAAD,MAAC,UAAK,WAAU,sBAAsB,gBAAM,aAAa,UAAU,GAAE;AAAA,cACpE,MAAM,eACN,gBAAAA,MAAC,UAAK,WAAU,qBACd,6BAAmB,MAAM,WAAW,GACtC;AAAA,eAEF;AAAA,YAED,gBAAAC,OAAC,SAAI,WAAU,2BACb;AAAA,oBAAM;AAAA,cACN,CAAC,cAAc,MAAM,eACrB,gBAAAD,MAAC,UAAK,WAAU,4BACd,6BAAmB,MAAM,WAAW,GACtC;AAAA,eAEF;AAAA,YACC,MAAM,SACL,MAAM;AACN,oBAAM,QAAQ,cAAc,MAAM,IAAI;AACtC,qBACC,gBAAAA,MAAC,SAAI,WAAU,0BACb,gBAAM,SAAS,KAAK,GAAG,MAAM,MAAM,GAAG,EAAE,CAAC,WAAM,OACjD;AAAA,YAEF,GAAG;AAAA;AAAA;AAAA,QA/BC,MAAM;AAAA,MAgCZ;AAAA,IAEF,CAAC,GACF;AAAA,KACD;AAEF;;;A4B1oEyB,SAAR,YAA6B,KAAK,EAAE,SAAS,IAAI,CAAC,GAAG;AAC1D,MAAI,CAAC,OAAO,OAAO,aAAa,YAAa;AAE7C,QAAM,OAAO,SAAS,QAAQ,SAAS,qBAAqB,MAAM,EAAE,CAAC;AACrE,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,OAAO;AAEb,MAAI,aAAa,OAAO;AACtB,QAAI,KAAK,YAAY;AACnB,WAAK,aAAa,OAAO,KAAK,UAAU;AAAA,IAC1C,OAAO;AACL,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF,OAAO;AACL,SAAK,YAAY,KAAK;AAAA,EACxB;AAEA,MAAI,MAAM,YAAY;AACpB,UAAM,WAAW,UAAU;AAAA,EAC7B,OAAO;AACL,UAAM,YAAY,SAAS,eAAe,GAAG,CAAC;AAAA,EAChD;AACF;;;ACvB8B,YAAY,y/mGAA+gnG;;;ACuKhknG,gBAAAS,aAAA;AAnCI,SAAS,cAAc;AAAA,EAC7B;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;AAAA,EACA;AAAA;AAAA,EAEA;AACD,GAAuB;AACtB,QAAM,iBAAiB,WAAW,MAAM,IAAI,QAAQ,iBAAiB,EAAE,IAAI;AAE3E,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAEA,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACD;AAAA;AAAA,EACD;AAEF;;;AC9KA,SAAS,aAAAC,aAAW,UAAAC,gBAAc;AAqB3B,SAAS,YAAY,SAAyC;AACpE,QAAM,EAAE,GAAG,IAAI,iBAAiB;AAChC,QAAM,aAAaC,SAAO,OAAO;AAEjC,EAAAC,YAAU,MAAM;AACf,eAAW,UAAU;AAAA,EACtB,CAAC;AAED,EAAAA,YAAU,MAAM;AACf,WAAO,GAAG,QAAQ,CAAC,UAAU,WAAW,QAAQ,KAAK,CAAC;AAAA,EACvD,GAAG,CAAC,EAAE,CAAC;AACR;","names":["storageKey","merged","client","store","emitter","ws","identify","api","el","useCallback","useEffect","useRef","useState","useCallback","useEffect","useRef","t","useRef","useEffect","useCallback","useCallback","useState","useState","useCallback","conversationId","useCallback","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","store","useEffect","useState","useState","useEffect","useCallback","useRef","useRef","useCallback","useCallback","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","useCallback","useEffect","useRef","useState","useCallback","useRef","useState","jsx","jsx","jsx","jsx","jsx","jsx","jsx","jsxs","useRef","useCallback","useState","jsx","jsxs","useState","useRef","useEffect","useCallback","useState","jsx","jsxs","useState","useCallback","useEffect","useCallback","useEffect","useState","EMPTY_TABS","t","useState","useCallback","useEffect","useEffect","useRef","jsx","Fragment","jsx","jsxs","useCallback","useRef","useState","jsx","jsxs","useEffect","useRef","useCallback","useRef","useState","EMPTY_TABS","detailKey","readCache","t","useState","useRef","useCallback","jsx","useEffect","useRef","jsx","useEffect","useCallback","jsx","useEffect","useMemo","useRef","useState","jsx","jsxs","useState","useRef","useEffect","useMemo","useEffect","useRef","useState","Fragment","jsx","jsxs","useRef","useEffect","useState","useEffect","useRef","jsx","jsxs","useRef","useEffect","useEffect","useState","Fragment","jsx","jsxs","useState","useEffect","Fragment","jsx","jsxs","resolveLabel","c","useState","useEffect","useRef","useCallback","t","jsx","useEffect","useRef","useRef","useEffect"]}