{"version":3,"sources":["../src/ChatWidget.tsx","../src/ui/button.tsx","../src/utils/cn.ts","../src/components/conversation.tsx","../src/ui/avatar.tsx","../src/components/message.tsx","../src/components/file-icons/describe-file.ts","../src/components/file-icons/file-icon-map.ts","../src/components/file-icons/framework-icons.tsx","../src/contexts/chat-portal-context.tsx","../src/ui/textarea.tsx","../src/ui/tooltip.tsx","../src/components/prompt-input.tsx","../src/components/input-plugin-popover.tsx","../src/hooks/use-dictation.ts","../src/utils/speech-recognition.ts","../src/components/dictation-button.tsx","../src/agent-config/field.ts","../src/agent-config/descriptor.ts","../src/config.ts","../src/components/chat-error-banner.tsx","../src/utils/chat-error-protocol.ts","../src/utils/chat-error-recovery.ts","../src/components/interface.tsx","../src/utils/follow-ups.ts","../src/utils/page-context.ts","../src/utils/custom-message-data.ts","../src/utils/message-part-renderers.ts","../src/utils/assistant-content.ts","../src/components/loader.tsx","../src/components/transcript/TextShimmer.tsx","../src/components/transcript/toolRegistry.tsx","../src/components/follow-up-suggestions.tsx","../src/components/suggestion2.tsx","../src/components/message-item.tsx","../src/components/response.tsx","../src/hooks/use-code-scroll.ts","../src/hooks/use-smooth-text.ts","../src/components/collapsible-code.tsx","../src/ui/collapsible.tsx","../src/utils/highlight.ts","../src/components/markdown-table.tsx","../src/components/citation-markers.tsx","../src/utils/url-safety.ts","../src/utils/citation-tokens.ts","../src/charts/chart-block.tsx","../src/charts/chart-spec.ts","../src/charts/chart-renderers.tsx","../src/charts/chart-geometry.ts","../src/charts/chart-tooltip.tsx","../src/charts/use-chart-width.ts","../src/charts/chart-code.tsx","../src/components/mermaid-block.tsx","../src/generative/registry.ts","../src/components/sources.tsx","../src/components/message-attachments.tsx","../src/utils/file-parts.ts","../src/components/message-actions.tsx","../src/utils/feedback.ts","../src/components/transcript/AgentTurnTranscript.tsx","../src/components/transcript/AgentToolCall.tsx","../src/components/code-block.tsx","../src/components/transcript/AgentThinkingTool.tsx","../src/components/transcript/types.ts","../src/components/action-result-card.tsx","../src/contexts/chat-storage-context.tsx","../src/utils/color.ts","../src/hooks/use-open-triggers.ts","../src/hooks/use-hosted-auth.ts","../src/ui/input.tsx","../src/ui/dialog.tsx","../src/components/action-primitives.tsx","../src/actions/templates.ts","../src/components/tool.tsx","../src/charts/chart-tool-renderer.tsx","../src/theme-presets.ts"],"sourcesContent":["'use client';\n\n/**\n * ChatWidget - Self-contained AI chat widget component\n *\n * This component can be embedded in any React application.\n * It handles its own state, styling, and API communication.\n *\n * The mounted handler authenticates the browser and supplies published client\n * configuration plus an opaque browser-storage scope through `/bootstrap`.\n * Callers can render `<ChatWidget />` with no identity or agent props.\n */\n\nimport { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, type ReactNode } from 'react';\nimport ChatInterface from './components/interface';\nimport type {\n  ActionRenderer,\n  ChatContext,\n  InputPlugin,\n  MessagePartRenderers,\n  StarterPrompt,\n  ThemeConfig,\n  ToolRenderer,\n} from './types';\nimport type { AgentBootstrap, AgentConfig } from './config';\nimport { formatConfigIssues, mergeAgentClientConfig, readAgentBootstrap } from './config';\n\n// Bootstrap revisions already reported for carrying client fields this bundle\n// doesn't understand — one console line per revision, not per mount/remount.\nconst warnedBootstrapRevisions = new Set<string>();\nimport { MessageCircle, X } from 'lucide-react';\nimport { ChatStorageProvider } from './contexts/chat-storage-context';\nimport { ChatPortalProvider } from './contexts/chat-portal-context';\nimport { hexToHslTriplet } from './utils/color';\nimport { useOpenTriggers, type OpenTriggerSource } from './hooks/use-open-triggers';\nimport { hostedApiBase, useHostedAuth } from './hooks/use-hosted-auth';\n\n// Hosts that passed BOTH `publishableKey` and `apiBase` — warned once per key.\nconst warnedHostedApiBase = new Set<string>();\n\nexport interface ChatWidgetProps {\n  /** Full canonical config for caller overrides or an authenticated preview. */\n  config?: AgentConfig;\n  /** Handler mount. The widget calls `${apiBase}/bootstrap` on mount. */\n  apiBase?: string;\n  /** Generic transport headers (for example a host's CSRF token). */\n  headers?: Record<string, string>;\n  requestCredentials?: RequestCredentials;\n  /**\n   * HOSTED RUNTIME MODE — for apps with no server route (Vite/Lovable/Bolt,\n   * Supabase-backed SPAs). Pass the agent's publishable key (`pk_live_…`, from\n   * the dashboard or the mordn MCP server) and the widget talks to\n   * `api.mordn.com/v1/hosted/<key>` directly instead of `apiBase`. The key is\n   * public by design: it selects the agent and grants nothing on its own — the\n   * hosted runtime enforces the agent's origin allowlist and verifies the end\n   * user from `getUserToken`. Mutually exclusive with `apiBase`.\n   */\n  publishableKey?: string;\n  /**\n   * Hosted mode only: returns the signed-in user's access token from the app's\n   * identity provider (e.g. Supabase `session.access_token`, Clerk `getToken()`),\n   * or `null` when nobody is signed in. Sent as `Authorization: Bearer …` and\n   * verified server-side against the agent's configured JWKS — the browser\n   * never asserts an id, it only presents a token somebody else signed.\n   * Re-resolved every few minutes so expiring tokens stay fresh. Callback\n   * identity is ignored; signal login/logout/account switches with\n   * `authSessionKey` or the ref's `resetAuth()` after updating your session.\n   */\n  getUserToken?: () => Promise<string | null | undefined> | string | null | undefined;\n  /**\n   * Hosted mode only: local auth lifecycle marker (e.g. an incrementing counter).\n   * Change on login, logout, or account switch to drop stale auth and mounted\n   * chat state before resolving the new token. NOT identity: never sent to the\n   * server or used as a storage scope. Stable across same-session token refreshes.\n   */\n  authSessionKey?: string | number | null;\n  /**\n   * Hosted mode only: allow unauthenticated visitors. When no token is\n   * available the widget sends a persisted random visitor id instead, and the\n   * runtime scopes history to it as an explicitly anonymous (`anon:`) user.\n   * Only takes effect when the agent's hosted settings also allow anonymous\n   * visitors. Default false.\n   */\n  anonymous?: boolean;\n  /** Hosted mode only: API origin override for a self-hosted chat-api. Default `https://api.mordn.com`. */\n  hostedBaseUrl?: string;\n  className?: string;\n  conversationId?: string;\n  initialMessages?: any[];\n  /**\n   * Per-turn context (#162, #239): a static object, `'auto'` for the built-in\n   * safe page capture, or a function resolved fresh at send time. See\n   * `buildAutoPageContext` for opting into richer capture. Untrusted\n   * server-side until the handler opts in via `getContext` /\n   * `trustClientContext`.\n   */\n  context?: ChatContext | 'auto' | (() => ChatContext | Promise<ChatContext>);\n  getStarterPrompts?: () => StarterPrompt[] | Promise<StarterPrompt[]>;\n  onClose?: () => void;\n  open?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  onStateChange?: (open: boolean) => void;\n  headerActions?: ReactNode;\n  inputPlugins?: InputPlugin[];\n  toolRenderers?: Record<string, ToolRenderer>;\n  actionRenderers?: Record<string, ActionRenderer>;\n  /** Host React code only: render custom data-* parts, never published JSON config. */\n  messagePartRenderers?: MessagePartRenderers;\n  onFeedback?: (feedback: import('./types').FeedbackEvent) => void;\n  /**\n   * Host-supplied colors, applied LIVE: change this prop (e.g. when the host\n   * app flips light/dark, or a user picks a brand palette) and the open panel,\n   * launcher and portalled menus repaint in place — no remount, no lost\n   * conversation, no new bootstrap. Same three-hex contract as the published\n   * `client.theme` (invalid or partial themes are ignored whole).\n   *\n   * Precedence: this prop > `config.client.theme` > the published theme from\n   * `/bootstrap`. `undefined` defers to those sources; `null` forces the stock\n   * palette even when a theme is published.\n   *\n   * Presentation only: it is never sent to the server and never enters\n   * `AgentConfig`, so a host can theme the widget without authoring a full\n   * config document.\n   */\n  theme?: ThemeConfig | null;\n}\n\n/**\n * Imperative handle exposed via a ref on `<ChatWidget>`. Lets the host app\n * drive the popup panel programmatically. Opening is gated by\n * `config.client.allowAutoReopen` so a dismissed panel is never\n * re-surfaced without explicit opt-in; closing is always allowed. Only\n * meaningful in the `popup` layout (inline/page are always-open surfaces).\n * `resetAuth()` applies to hosted mode in every layout.\n */\nexport interface ChatWidgetHandle {\n  /** Open the panel. No-op unless `allowAutoReopen` is set. */\n  open: () => void;\n  /** Close the panel. Always allowed. */\n  close: () => void;\n  /** Toggle the panel. Opening obeys the same `allowAutoReopen` gate as `open()`. */\n  toggle: () => void;\n  /** Whether the panel is currently open. */\n  readonly isOpen: boolean;\n  /**\n   * Hosted mode only: drop auth/bootstrap/mounted chat state and resolve the\n   * latest getUserToken again. Call AFTER updating the host's session source.\n   * Equivalent to changing authSessionKey; does not erase persisted chat data.\n   */\n  resetAuth: () => void;\n}\n\nexport const ChatWidget = forwardRef<ChatWidgetHandle, ChatWidgetProps>(function ChatWidget({\n  config: explicitConfig,\n  apiBase: apiBaseProp,\n  headers,\n  requestCredentials: requestCredentialsProp,\n  publishableKey,\n  getUserToken,\n  authSessionKey,\n  anonymous,\n  hostedBaseUrl,\n  conversationId,\n  initialMessages,\n  className,\n  getStarterPrompts,\n  context,\n  onClose,\n  headerActions,\n  open,\n  onOpenChange,\n  onStateChange,\n  inputPlugins,\n  toolRenderers,\n  actionRenderers,\n  messagePartRenderers,\n  onFeedback,\n  theme: themeProp,\n}: ChatWidgetProps, ref) {\n  // Hosted runtime mode: a publishable key REPLACES apiBase — the widget talks\n  // to the hosted runtime directly. Cookies are never sent cross-origin in this\n  // mode; identity travels as the verified token from `getUserToken`.\n  const hostedKey = typeof publishableKey === 'string' && publishableKey.trim() !== '' ? publishableKey.trim() : null;\n  const hostedMode = hostedKey !== null;\n  if (hostedKey && apiBaseProp !== undefined && !warnedHostedApiBase.has(hostedKey)) {\n    warnedHostedApiBase.add(hostedKey);\n    console.warn('[chat-widget] `apiBase` is ignored when `publishableKey` is set — hosted mode talks to api.mordn.com directly.');\n  }\n  const apiBase = (hostedKey ? hostedApiBase(hostedKey, hostedBaseUrl) : apiBaseProp ?? '/api/chat').replace(/\\/+$/, '');\n  const requestCredentials: RequestCredentials | undefined = hostedMode ? 'omit' : requestCredentialsProp;\n  const hostedAuth = useHostedAuth({\n    enabled: hostedMode,\n    getUserToken: hostedMode ? getUserToken : undefined,\n    anonymous: hostedMode ? anonymous : false,\n    // Include the destination so a changed key/origin cannot reuse old auth.\n    sessionKey: hostedMode ? JSON.stringify([apiBase, authSessionKey ?? null]) : null,\n  });\n  const resetAuth = useCallback(() => {\n    if (hostedMode) hostedAuth.reset();\n  }, [hostedMode, hostedAuth.reset]);\n\n  const [bootstrapResult, setBootstrapResult] = useState<{\n    request: object;\n    value: AgentBootstrap | null;\n    error: string | null;\n  } | null>(null);\n  const [bootstrapAttempt, setBootstrapAttempt] = useState(0);\n  // Host headers plus (hosted mode) the Authorization / visitor header, value-keyed\n  // so a token refresh re-issues bootstrap and updates the transport headers.\n  const headersKey = JSON.stringify([headers ?? null, hostedAuth.headers]);\n  const stableHeaders = useMemo(\n    () => (hostedMode ? { ...(headers ?? {}), ...hostedAuth.headers } : headers),\n    // eslint-disable-next-line react-hooks/exhaustive-deps -- value-keyed on purpose\n    [headersKey, hostedMode],\n  );\n  const hostedAuthReady = hostedAuth.ready;\n  const bootstrapRequest = useMemo(() => ({}), [\n    apiBase, stableHeaders, requestCredentials, bootstrapAttempt, hostedAuthReady, hostedAuth.session,\n  ]);\n  // Never render/persist the previous session's scope while auth or bootstrap\n  // is changing — effects run too late to be the visibility boundary.\n  const bootstrapCurrent = hostedAuthReady && bootstrapResult?.request === bootstrapRequest;\n  const bootstrap = bootstrapCurrent ? bootstrapResult.value : null;\n  const bootstrapError = bootstrapCurrent ? bootstrapResult.error : null;\n  const bootstrapReady = bootstrapCurrent;\n\n  useEffect(() => {\n    // Hosted mode: wait for THIS session, not only the initial mount, so a\n    // transition never bootstraps with the previous token or as a visitor.\n    if (!hostedAuthReady) return;\n    const controller = new AbortController();\n    setBootstrapResult(null);\n    fetch(`${apiBase}/bootstrap`, {\n      method: 'GET',\n      headers: stableHeaders,\n      credentials: requestCredentials,\n      signal: controller.signal,\n    })\n      .then(async (response) => {\n        if (!response.ok) throw new Error(`bootstrap failed (${response.status})`);\n        const value: unknown = await response.json();\n        // TOLERANT read (config-evolution contract): the server may be newer\n        // than this bundle (or the published revision newer than both) and\n        // carry client fields this build doesn't know. They are dropped and the\n        // schema default applies — never a broken widget. Only a wrong protocol\n        // version or a missing required envelope field is fatal.\n        const read = readAgentBootstrap(value);\n        if (!read.ok) {\n          throw new Error(`bootstrap returned an invalid response (${formatConfigIssues(read.issues)})`);\n        }\n        if (read.dropped.length > 0 && !warnedBootstrapRevisions.has(read.value.revision)) {\n          warnedBootstrapRevisions.add(read.value.revision);\n          console.info(\n            '[chat-widget] bootstrap contained fields this widget version does not understand and ignored them: ' +\n              read.dropped.map((issue) => issue.path).join(', ') +\n              '. Upgrade @mordn/chat-widget to apply them.',\n          );\n        }\n        return read.value;\n      })\n      .then((value) => {\n        // Abort alone is insufficient: a response body/custom fetch may finish\n        // after cleanup, or ignore the signal altogether.\n        if (!controller.signal.aborted) setBootstrapResult({ request: bootstrapRequest, value, error: null });\n      })\n      .catch((error) => {\n        if (controller.signal.aborted) return;\n        setBootstrapResult({\n          request: bootstrapRequest,\n          value: null,\n          error: error instanceof Error ? error.message : 'bootstrap failed',\n        });\n      });\n    return () => controller.abort();\n  }, [apiBase, stableHeaders, requestCredentials, bootstrapRequest, hostedAuthReady]);\n\n  const client = mergeAgentClientConfig(bootstrap?.client, explicitConfig?.client);\n  const { greeting, subGreeting, assistantName, theme: configTheme, features, display, starterPrompts, capabilitiesPrompt, feedback } = client;\n  // Resolve the effective theme. The host prop wins over every config source\n  // and is the live channel: the published theme arrives once per bootstrap,\n  // while this prop can change on any render. Re-keyed on the three color\n  // strings so an inline `theme={{ ... }}` object literal (a new identity every\n  // render) doesn't churn interfaceConfig or the portal host.\n  const themeSource = themeProp !== undefined ? themeProp : configTheme;\n  const hasTheme = themeSource != null;\n  const themeBackground = themeSource?.backgroundColor;\n  const themeText = themeSource?.textColor;\n  const themePrimary = themeSource?.primaryColor;\n  const theme = useMemo<ThemeConfig | undefined>(\n    () =>\n      hasTheme\n        ? {\n            backgroundColor: themeBackground as string,\n            textColor: themeText as string,\n            primaryColor: themePrimary as string,\n          }\n        : undefined,\n    [hasTheme, themeBackground, themeText, themePrimary],\n  );\n  const persistState = client.persistState;\n  const allowAutoReopen = client.allowAutoReopen;\n  const layout = display?.layout || 'popup';\n  // Controlled mode: consumer provides `open` prop. We delegate state to\n  // them and skip the built-in FAB so they can render their own trigger.\n  const isControlled = open !== undefined;\n  const showToggleButton = !isControlled && display?.showToggleButton !== false;\n  // Resize only makes sense for the popup layout — inline/page take their\n  // size from the parent container.\n  const resizable = layout === 'popup' && display?.resizable !== false;\n  const size = display?.size || 'default';\n\n  // Persist the panel's open/closed state. Default on; only meaningful for\n  // the uncontrolled popup layout (controlled mode → host owns `open`;\n  // inline/page are always open).\n  const persistEnabled = persistState !== false && !isControlled && layout === 'popup';\n  // localStorage key for the panel state, scoped to (agent, user) using the\n  // SAME `chat-<prefix>-` convention as the chat cache (chat-storage-context),\n  // so clearChatStorage() wipes it on sign-out and distinct identities never\n  // collide. `null` when identity is incomplete → we never persist (no\n  // shared/static fallback bucket; same cross-user-leak guard as the cache).\n  const panelStateKey =\n    persistEnabled && bootstrap?.storageScope\n      ? `chat-${encodeURIComponent(bootstrap.storageScope)}-panel-open`\n      : null;\n\n  // Open state is meaningful for popup layout only. Inline and page modes\n  // are always \"open\" since they're embedded surfaces, not floating panels.\n  // Initialise from `defaultOpen` (SSR-safe — no localStorage read in the\n  // initialiser, which would cause a hydration mismatch); reconcile with any\n  // persisted preference in the effect below.\n  const [internalIsOpen, setInternalIsOpen] = useState(\n    layout !== 'popup' ? true : (display?.defaultOpen || false)\n  );\n  const isOpen = isControlled ? open : internalIsOpen;\n\n  // Hydrate the persisted open/closed preference once the (agent, user) scope\n  // is known. A stored 'closed' overrides `defaultOpen` — this is the\n  // \"dismiss-and-stay-dismissed\" guarantee. Client-side only; restoring the\n  // saved value is initialisation, so it deliberately does NOT fire\n  // onStateChange.\n  useEffect(() => {\n    if (!panelStateKey) return;\n    if (typeof window === 'undefined' || !window.localStorage) return;\n    try {\n      const stored = window.localStorage.getItem(panelStateKey);\n      if (stored === 'open') setInternalIsOpen(true);\n      else if (stored === 'closed') setInternalIsOpen(false);\n      else setInternalIsOpen(display?.defaultOpen || false);\n    } catch {\n      /* localStorage unavailable (private mode / quota) — ignore. */\n    }\n  }, [panelStateKey, display?.defaultOpen]);\n\n  // Single entry point for changing open state: handles controlled vs\n  // uncontrolled, persistence, the onStateChange callback, and the\n  // allowAutoReopen gate for programmatic opens.\n  const setOpenState = useCallback(\n    (next: boolean, opts?: { programmatic?: boolean }) => {\n      if (next === isOpen) return; // no-op: nothing changed\n      // Gate programmatic *opening* behind allowAutoReopen. User actions\n      // (FAB / toggle / close X) pass programmatic:false and are always\n      // honoured. Closing is always allowed.\n      if (next && opts?.programmatic && !allowAutoReopen) return;\n      if (isControlled) {\n        onOpenChange?.(next);\n      } else {\n        setInternalIsOpen(next);\n        if (panelStateKey && typeof window !== 'undefined' && window.localStorage) {\n          try {\n            window.localStorage.setItem(panelStateKey, next ? 'open' : 'closed');\n          } catch {\n            /* ignore persistence failure */\n          }\n        }\n      }\n      onStateChange?.(next);\n    },\n    [isOpen, allowAutoReopen, isControlled, onOpenChange, onStateChange, panelStateKey]\n  );\n\n  // User-driven open/close helper (always allowed). Used by the FAB and the\n  // panel's own close button.\n  const setIsOpen = useCallback((next: boolean) => setOpenState(next), [setOpenState]);\n\n  // Expose an imperative handle so hosts can drive the panel. Opening is\n  // gated by allowAutoReopen; closing and reading are always available.\n  useImperativeHandle(\n    ref,\n    (): ChatWidgetHandle => ({\n      open: () => setOpenState(true, { programmatic: true }),\n      close: () => setOpenState(false),\n      toggle: () => setOpenState(!isOpen, { programmatic: !isOpen }),\n      isOpen,\n      resetAuth,\n    }),\n    [setOpenState, isOpen, resetAuth]\n  );\n\n  // Page-chrome triggers share state/persistence with the launcher. Explicit\n  // keyboard shortcuts and attribute clicks bypass automatic-reopen suppression\n  // (#245); CustomEvents preserve the imperative API's programmatic gate.\n  const triggerOpen = useCallback(\n    (source: OpenTriggerSource) => setOpenState(true, { programmatic: source === 'programmatic' }),\n    [setOpenState]\n  );\n  const triggerClose = useCallback(() => setOpenState(false), [setOpenState]);\n  const triggerToggle = useCallback(\n    (source: OpenTriggerSource) => setOpenState(!isOpen, { programmatic: source === 'programmatic' }),\n    [setOpenState, isOpen]\n  );\n  useOpenTriggers(display?.keyboardShortcut, { open: triggerOpen, close: triggerClose, toggle: triggerToggle });\n\n  const [isResizing, setIsResizing] = useState(false);\n  const containerRef = useRef<HTMLDivElement>(null);\n  const fabRef = useRef<HTMLButtonElement>(null);\n\n  // ── Close choreography (popup) ───────────────────────────────────────────\n  // The panel unmounts on close, but not in the same frame it was told to\n  // close: the entrance is animated and an instant vanish read like a crash\n  // (a chat-slide-out-right keyframe existed and was never wired). While\n  // `isClosing` the panel stays mounted with data-closing=\"true\", plays the\n  // exit animation, and unmounts on animationend — with a timer safety net in\n  // case the animation never runs (host display:none, animations stripped).\n  // Reduced-motion users skip the choreography entirely.\n  const [isClosing, setIsClosing] = useState(false);\n  const wasOpenRef = useRef(isOpen);\n  useEffect(() => {\n    const wasOpen = wasOpenRef.current;\n    wasOpenRef.current = isOpen;\n    if (isOpen) {\n      setIsClosing(false);\n      return;\n    }\n    if (wasOpen && layout === 'popup') {\n      const reduceMotion =\n        typeof window !== 'undefined' &&\n        typeof window.matchMedia === 'function' &&\n        window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n      if (reduceMotion) return;\n      setIsClosing(true);\n      const safety = setTimeout(() => setIsClosing(false), 320);\n      return () => clearTimeout(safety);\n    }\n  }, [isOpen, layout]);\n\n  // ── Focus choreography (popup) ───────────────────────────────────────────\n  // Opening moves focus INTO the panel (the container itself, tabIndex=-1 —\n  // tabbing then flows to the composer naturally, without force-popping the\n  // mobile keyboard); closing hands it back to the launcher, but only when\n  // focus was actually inside the panel (or already dropped to body after an\n  // unmount) — a host that closes the widget programmatically while the user\n  // works elsewhere must not have focus stolen.\n  useEffect(() => {\n    if (layout !== 'popup') return;\n    if (isOpen) {\n      const raf = requestAnimationFrame(() => {\n        containerRef.current?.focus({ preventScroll: true });\n      });\n      return () => cancelAnimationFrame(raf);\n    }\n    const active = document.activeElement;\n    if (\n      fabRef.current &&\n      (active === null || active === document.body || containerRef.current?.contains(active))\n    ) {\n      fabRef.current.focus({ preventScroll: true });\n    }\n  }, [isOpen, layout]);\n\n  // Escape closes the popup — unless something inside (a Radix menu, a\n  // dialog) already claimed the keypress via preventDefault.\n  const handlePanelKeyDown = useCallback(\n    (e: React.KeyboardEvent<HTMLDivElement>) => {\n      // isComposing: an IME user pressing Escape is cancelling their\n      // composition, not the panel.\n      if (e.key === 'Escape' && !e.defaultPrevented && !e.nativeEvent.isComposing) {\n        e.stopPropagation();\n        setIsOpen(false);\n      }\n    },\n    [setIsOpen]\n  );\n\n  // Build CSS custom properties from display + theme config.\n  //\n  // Theme handling: the widget's CSS expects `--chat-primary`, `--chat-background`\n  // and `--chat-text` to be HSL TRIPLETS (e.g. \"0 0% 14.5%\") because they're\n  // consumed inside `hsl(var(--chat-primary))`. Consumers naturally want to\n  // pass hex colors though, so we convert when we can detect hex; anything\n  // else is forwarded as-is on the assumption the caller knows what they're\n  // doing (e.g. they passed an HSL triplet directly).\n  const customStyles = useMemo(() => {\n    const styles: Record<string, string> = {};\n    if (display?.width) {\n      styles['--chat-widget-width'] = display.width;\n    }\n\n    // Theming is all-or-nothing: exactly three declared colors (background,\n    // text, primary). If any is missing or not valid hex the theme is ignored\n    // and the stock palette applies -- a theme is never half-applied. The\n    // widget renders what the client declared; contrast is their call (the\n    // playground is where combinations get validated).\n    const parse = (t: string | null) => {\n      const m = t ? /^([\\d.]+) ([\\d.]+)% ([\\d.]+)%$/.exec(t.trim()) : null;\n      return m ? { h: +m[1], s: +m[2], l: +m[3] } : null;\n    };\n    const bg = theme ? parse(hexToHslTriplet(theme.backgroundColor)) : null;\n    const text = theme ? parse(hexToHslTriplet(theme.textColor)) : null;\n    const primaryTriplet = theme ? hexToHslTriplet(theme.primaryColor) : null;\n\n    if (bg && text && primaryTriplet) {\n      // Every neutral is a named stop on ONE ramp between the two poles:\n      // fraction = how far from the background toward the text color. Hue,\n      // saturation and lightness all interpolate, so the whole panel\n      // re-anchors on the declared colors and nothing else.\n      const lerp = (from: number, to: number, f: number) =>\n        Math.round((from + (to - from) * f) * 10) / 10;\n      const hueDelta = (() => {\n        let d = text.h - bg.h;\n        if (d > 180) d -= 360;\n        if (d < -180) d += 360;\n        return d;\n      })();\n      const tone = (f: number) =>\n        `${(lerp(0, hueDelta, f) + bg.h + 360) % 360} ${lerp(bg.s, text.s, f)}% ${lerp(bg.l, text.l, f)}%`;\n\n      // STRUCTURAL stops (surfaces, hovers, dividers, borders) get a floor:\n      // when the declared poles sit close together (near-mono palettes — or\n      // bg === text by mistake), a pure fraction of that tiny range makes\n      // the widget's own furniture invisible: no borders, no dividers, no\n      // hover feedback. Ink stops stay verbatim fractions — the declared\n      // text contrast is the client's call (validated in the playground) —\n      // but structure never silently vanishes. Each structural stop is\n      // guaranteed a minimum lightness offset from the background, pushed\n      // toward the text pole, flipping to the other side only when the\n      // background sits so close to that extreme there's no room left.\n      const dir = text.l >= bg.l ? 1 : -1;\n      const clampL = (n: number) => Math.min(100, Math.max(0, n));\n      const structuralTone = (f: number, minDelta: number) => {\n        const lerped = lerp(bg.l, text.l, f);\n        let l = Math.abs(lerped - bg.l) >= minDelta ? lerped : clampL(bg.l + minDelta * dir);\n        if (Math.abs(l - bg.l) + 0.25 < minDelta) l = clampL(bg.l - minDelta * dir);\n        return `${(lerp(0, hueDelta, f) + bg.h + 360) % 360} ${lerp(bg.s, text.s, f)}% ${l}%`;\n      };\n\n      // Renderer design ramp. These are semantic stops — not hard-coded light\n      // colors — derived from the same background→text line as the rest of the\n      // widget. Close structural roles intentionally share a stop (border-soft /\n      // hairline) so the UI gains hierarchy without recreating a dozen\n      // indistinguishable grays.\n      styles['--chat-background'] = tone(0);\n      styles['--chat-surface'] = structuralTone(0.025, 2); // quiet inset canvas\n      styles['--chat-hover-bg'] = structuralTone(0.047, 4); // hover / selected row\n      styles['--chat-hairline'] = structuralTone(0.064, 5.5); // section rules\n      styles['--chat-border-soft'] = styles['--chat-hairline']; // nested surfaces\n      styles['--chat-border'] = structuralTone(0.12, 7); // primary outline\n      styles['--chat-text-subtle'] = tone(0.28); // disabled / model metadata\n      styles['--chat-text-faint'] = tone(0.46); // paths / timestamps / chevrons\n      styles['--chat-text-muted'] = tone(0.72); // secondary copy / controls\n      styles['--chat-text-body'] = tone(0.88); // paragraphs / table cells\n      styles['--chat-text-strong'] = styles['--chat-text-body']; // backwards-compatible alias\n      styles['--chat-text'] = tone(1);\n      styles['--chat-primary'] = primaryTriplet;\n\n      // A soft accent fill for citations, file tiles, and selected inline tokens.\n      // It is derived from background→primary (not background→text), so a host's\n      // declared brand color remains visible without compromising dark themes.\n      const primary = parse(primaryTriplet)!;\n      const tintHue = primary.s < 1 ? bg.h : primary.h;\n      const tintSaturation = lerp(bg.s, primary.s, 0.8);\n      const primaryTone = (f: number) =>\n        `${tintHue} ${tintSaturation}% ${lerp(bg.l, primary.l, f)}%`;\n      styles['--chat-primary-tint'] = primaryTone(0.1);\n      // Text ON the brand color — the send button, the launcher icon, and\n      // user-bubble text are all painted over --chat-primary. We intentionally\n      // do NOT pick a near-black/near-white foreground here: the user-bubble\n      // text, button label, and launcher icon default to the BACKGROUND color\n      // via the `var(--chat-primary-foreground, var(--chat-background))`\n      // fallback chain in styles.src.css. Using the background color as the\n      // text-on-accent is the conventional, correct choice across the realistic\n      // theme space:\n      //   - light theme (light bg + medium/dark accent)  → white text on the\n      //     accent (bg is white) — the branded look, AA-passing for the common\n      //     accents (red/blue/green/indigo on white all clear 4.5:1).\n      //   - dark theme (dark bg + light accent)          → dark text on the\n      //     accent (bg is dark) — the conventional dark-theme look.\n      //   - stock (near-black primary on white)          → white text, as\n      //     before.\n      // The earlier luminance-based contrast picker produced \"black on a dark\n      // accent\" for saturated mid-tone accents (red-500, rose, emerald-600,\n      // amber-600) — technically AA but visually muddy, and not what a themed\n      // customer expects. Dropping it also retires the miscalibrated 0.179\n      // crossover (the true crossover vs the emitted triplet luminances is\n      // 0.196). `--chat-primary-foreground` is simply not set, so every usage\n      // site falls through to `--chat-background`.\n      //\n      // Known edge: a LIGHT accent (yellow / cream / pastel / near-white\n      // primaryColor) on a LIGHT background renders background-colored (i.e.\n      // light) text on a light accent — low contrast. That corner is rare in\n      // practice (a white-on-white or yellow-on-white brand bubble is an\n      // unusual configuration), and ThemeConfig is deliberately 3 colors with\n      // no userTextColor override, so the background-color default is the\n      // documented contract. If a host hits that corner, the fix is to choose\n      // a primaryColor that contrasts with their background — the same\n      // contract that already governs textColor.\n      // Scrim over content: translucency is the intent here, so alpha is\n      // correct; direction just follows which pole is lighter.\n      styles['--chat-overlay'] =\n        text.l > bg.l ? 'rgba(255, 255, 255, 0.04)' : 'rgba(0, 0, 0, 0.02)';\n    }\n    return styles;\n  }, [display?.width, theme?.backgroundColor, theme?.textColor, theme?.primaryColor]);\n\n  // ── Resize (pointer + keyboard) ──────────────────────────────────────────\n  // Pointer Events instead of mouse events so mouse, touch and pen all drag\n  // through one path (the old onMouseDown version was silently unusable on\n  // touch). Pointer capture keeps move/up targeting the handle itself, so no\n  // document-level listeners to leak.\n\n  // Resize constraints (reasonable bounds for any chat widget).\n  const RESIZE_MIN_PX = 300;\n  const resizeMaxPx = () => Math.min(800, window.innerWidth * 0.8);\n\n  const applyPanelWidth = useCallback((px: number) => {\n    const clamped = Math.min(resizeMaxPx(), Math.max(RESIZE_MIN_PX, px));\n    containerRef.current?.style.setProperty('--chat-widget-width', `${clamped}px`);\n  }, []);\n\n  const handleResizePointerDown = useCallback(\n    (e: React.PointerEvent<HTMLDivElement>) => {\n      if (!resizable) return;\n      e.preventDefault();\n      e.currentTarget.setPointerCapture?.(e.pointerId);\n      setIsResizing(true);\n      document.body.style.cursor = 'ew-resize';\n      document.body.style.userSelect = 'none';\n    },\n    [resizable]\n  );\n\n  const handleResizePointerMove = useCallback(\n    (e: React.PointerEvent<HTMLDivElement>) => {\n      if (!isResizing) return;\n      // Panel is anchored to the right edge: width = viewport edge → pointer.\n      applyPanelWidth(window.innerWidth - e.clientX);\n    },\n    [isResizing, applyPanelWidth]\n  );\n\n  const endResize = useCallback(() => {\n    setIsResizing(false);\n  }, []);\n\n  // Restore the page-wide drag affordances when the drag ends — INCLUDING\n  // when the widget unmounts mid-drag (host closes the panel, route change).\n  // The old cleanup removed its listeners but left the host page stuck with\n  // cursor:ew-resize and text selection disabled.\n  useEffect(() => {\n    if (!isResizing) return;\n    return () => {\n      document.body.style.cursor = '';\n      document.body.style.userSelect = '';\n    };\n  }, [isResizing]);\n\n  // Keyboard operability for the separator: arrows nudge, Home/End jump to\n  // the bounds. The panel is right-anchored, so ArrowLeft grows it.\n  const handleResizeKeyDown = useCallback(\n    (e: React.KeyboardEvent<HTMLDivElement>) => {\n      if (!resizable || !containerRef.current) return;\n      const current = parseFloat(getComputedStyle(containerRef.current).width);\n      if (Number.isNaN(current)) return;\n      const step = 16;\n      if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n        e.preventDefault();\n        applyPanelWidth(current + step);\n      } else if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n        e.preventDefault();\n        applyPanelWidth(current - step);\n      } else if (e.key === 'Home') {\n        e.preventDefault();\n        applyPanelWidth(RESIZE_MIN_PX);\n      } else if (e.key === 'End') {\n        e.preventDefault();\n        applyPanelWidth(resizeMaxPx());\n      }\n    },\n    [resizable, applyPanelWidth]\n  );\n\n  const interfaceConfig = useMemo(() => ({\n    apiBase,\n    headers: stableHeaders,\n    requestCredentials,\n    requestConfig: explicitConfig,\n    greeting,\n    theme,\n    features,\n    starterPrompts,\n    getStarterPrompts,\n    capabilitiesPrompt,\n    subGreeting,\n    assistantName,\n    starterPromptsLayout: display?.starterPromptsLayout,\n    context,\n    inputPlugins,\n    toolRenderers,\n    actionRenderers,\n    messagePartRenderers,\n    feedback,\n    streamingThrottleMs: client.streamingThrottleMs,\n    onFeedback,\n  }), [apiBase, stableHeaders, requestCredentials, explicitConfig, greeting, subGreeting, assistantName, theme, features, starterPrompts, getStarterPrompts, capabilitiesPrompt, display?.starterPromptsLayout, context, inputPlugins, toolRenderers, actionRenderers, messagePartRenderers, feedback, client.streamingThrottleMs, onFeedback]);\n\n  // Default launcher position respects iOS safe areas (home indicator /\n  // rounded corners) — a fixed 24px bottom put the FAB under the home\n  // indicator on every modern iPhone. Hosts overriding the position own\n  // their own env() handling.\n  const togglePosition = display?.toggleButtonPosition || {\n    bottom: 'calc(24px + env(safe-area-inset-bottom, 0px))',\n    right: 'calc(24px + env(safe-area-inset-right, 0px))',\n  };\n\n  // Common interface — same for all three layouts. The wrapper differs.\n  // Internal only -- NOT a theme mode. Picks which of the two shipped syntax\n  // palettes (and scrim direction) fits behind the declared background; it\n  // never overrides a declared token.\n  const isDarkTheme = (() => {\n    const lightnessOf = (hex: string | undefined): number | null => {\n      const t = hex ? hexToHslTriplet(hex) : null;\n      const m = t ? /([\\d.]+)%$/.exec(t) : null;\n      return m ? parseFloat(m[1]) : null;\n    };\n    const bgL = lightnessOf(theme?.backgroundColor);\n    const textL = lightnessOf(theme?.textColor);\n    // Ramp DIRECTION, not absolute lightness: a theme whose text is lighter\n    // than its background IS a dark theme — the same signal the overlay\n    // scrim already keys on, and no knife-edge flip between a #808080 and a\n    // #7d7d7d background. The old `lightness < 50` check survives only as a\n    // fallback for a partially-invalid theme (which the ramp rejects\n    // wholesale anyway).\n    if (bgL !== null && textL !== null) return textL > bgL;\n    return bgL !== null ? bgL < 50 : false;\n  })();\n  const themeClass = isDarkTheme ? 'chat-dark' : '';\n\n  // Do not initialise the conversation or any browser persistence until an\n  // authenticated, runtime-validated bootstrap has supplied its opaque scope.\n  if (!bootstrapReady) return null;\n\n  // Fail closed: a missing/invalid bootstrap must never fall through to a chat\n  // surface with unscoped persistence or request config. Keep the recovery state\n  // outside ChatInterface so no conversation/history requests can start.\n  if (bootstrapError || !bootstrap) {\n    const failureLayoutClass =\n      layout === 'page'\n        ? 'chat-widget-page'\n        : layout === 'inline'\n          ? 'chat-widget-inline'\n          : 'chat-widget-popup';\n    return (\n      <div\n        className={`chat-widget-container chat-widget-content ${failureLayoutClass} ${themeClass} ${className || ''}`}\n        style={customStyles as React.CSSProperties}\n      >\n        <div\n          role=\"alert\"\n          aria-live=\"assertive\"\n          className=\"flex h-full min-h-48 flex-col items-center justify-center gap-3 p-6 text-center\"\n        >\n          <p className=\"text-base font-semibold\">Chat couldn&apos;t start</p>\n          <p className=\"max-w-sm text-sm text-muted-foreground\">\n            We couldn&apos;t securely initialize this chat. Check your connection and try again.\n          </p>\n          <button\n            type=\"button\"\n            className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n            onClick={() => setBootstrapAttempt((attempt) => attempt + 1)}\n          >\n            Retry\n          </button>\n        </div>\n      </div>\n    );\n  }\n\n  // INLINE layout: render the chat interface in place inside the parent. No\n  // toggle button, no fixed positioning, no resize. Caller owns sizing via\n  // parent CSS (e.g. wrap in a div with h-[600px] w-full).\n  if (layout === 'inline') {\n    return (\n      <ChatStorageProvider storageScope={bootstrap?.storageScope}>\n        <div\n          ref={containerRef}\n          className={`chat-widget-container chat-widget-inline chat-widget-content ${themeClass} ${className || ''}`}\n          style={customStyles as React.CSSProperties}\n        >\n          <ChatPortalProvider themeClass={themeClass} style={customStyles as React.CSSProperties}>\n            <ChatInterface\n              id={conversationId}\n              initialMessages={initialMessages}\n              config={interfaceConfig}\n              onClose={onClose}\n              headerActions={headerActions}\n            />\n          </ChatPortalProvider>\n        </div>\n      </ChatStorageProvider>\n    );\n  }\n\n  // PAGE layout: full-viewport chat surface. Same internal interface as\n  // inline; the difference is only the wrapper CSS class which sets\n  // height: 100dvh and provides a dedicated chat route experience.\n  if (layout === 'page') {\n    return (\n      <ChatStorageProvider storageScope={bootstrap?.storageScope}>\n        <div\n          ref={containerRef}\n          className={`chat-widget-container chat-widget-page chat-widget-content ${themeClass} ${className || ''}`}\n          style={customStyles as React.CSSProperties}\n        >\n          <ChatPortalProvider themeClass={themeClass} style={customStyles as React.CSSProperties}>\n            <ChatInterface\n              id={conversationId}\n              initialMessages={initialMessages}\n              config={interfaceConfig}\n              onClose={onClose}\n              headerActions={headerActions}\n            />\n          </ChatPortalProvider>\n        </div>\n      </ChatStorageProvider>\n    );\n  }\n\n  // POPUP layout (default, backward compatible): floating side panel with\n  // FAB toggle and slide-in animation.\n  return (\n    <ChatStorageProvider storageScope={bootstrap?.storageScope}>\n      {showToggleButton && !isOpen && (\n        // Wrap the launcher in a `.chat-widget-container` so its scoped Tailwind\n        // utilities (fixed, rounded-full, p-4, bg-primary, …) and the --chat-*\n        // tokens resolve. scope-css.js scopes every utility to\n        // `.chat-widget-container <util>` (descendant), so a launcher rendered\n        // OUTSIDE the container gets none of them — unpositioned and colorless —\n        // in a host app. The wrapper is in normal flow with zero footprint; the\n        // fixed-position button escapes it.\n        <div className={`chat-widget-container ${themeClass}`} style={customStyles as React.CSSProperties}>\n          <button\n            ref={fabRef}\n            onClick={() => setIsOpen(true)}\n            // Transition scoped to transform/shadow (transition-all animated\n            // everything, including layout props) + a real press state and a\n            // theme-aware focus ring. motion-reduce strips the movement.\n            className=\"fixed z-50 rounded-full bg-primary text-primary-foreground shadow-lg p-4 transition-[transform,box-shadow] duration-200 hover:scale-105 hover:shadow-xl active:scale-95 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none motion-reduce:hover:scale-100 motion-reduce:active:scale-100\"\n            style={togglePosition}\n            aria-label=\"Open chat\"\n            aria-haspopup=\"dialog\"\n          >\n            <MessageCircle className=\"h-6 w-6\" />\n          </button>\n        </div>\n      )}\n\n      {(isOpen || isClosing) && (\n        <div\n          ref={containerRef}\n          className={`chat-widget-container chat-widget-popup chat-widget-content ${themeClass} ${className || ''}`}\n          data-size={size}\n          data-resizing={isResizing}\n          data-closing={isClosing ? 'true' : undefined}\n          style={customStyles as React.CSSProperties}\n          // Non-modal dialog: focus moves in on open (see focus effect) but\n          // the host page stays interactive — no trap, no aria-modal.\n          role=\"dialog\"\n          aria-label=\"Chat\"\n          tabIndex={-1}\n          onKeyDown={handlePanelKeyDown}\n          onAnimationEnd={() => {\n            if (isClosing) setIsClosing(false);\n          }}\n        >\n          {resizable && (\n            <div\n              onPointerDown={handleResizePointerDown}\n              onPointerMove={handleResizePointerMove}\n              onPointerUp={endResize}\n              onPointerCancel={endResize}\n              onKeyDown={handleResizeKeyDown}\n              className=\"chat-widget-resize-handle\"\n              // A real separator: focusable, arrow-key operable (see\n              // handleResizeKeyDown), announced with its orientation.\n              role=\"separator\"\n              aria-orientation=\"vertical\"\n              tabIndex={0}\n              aria-label=\"Resize chat panel — arrow keys to adjust, Home/End for min/max\"\n            />\n          )}\n          <div className=\"w-full h-full overflow-hidden\">\n            <ChatPortalProvider themeClass={themeClass} style={customStyles as React.CSSProperties}>\n              <ChatInterface\n                id={conversationId}\n                initialMessages={initialMessages}\n                config={interfaceConfig}\n                // popup also closes its own panel; consumer's onClose still\n                // fires for any cleanup they want (e.g. analytics).\n                onClose={() => {\n                  setIsOpen(false);\n                  onClose?.();\n                }}\n                headerActions={headerActions}\n              />\n            </ChatPortalProvider>\n          </div>\n        </div>\n      )}\n    </ChatStorageProvider>\n  );\n});\n\n// Export ChatWidget as default\nexport default ChatWidget;\n","import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../utils/cn\"\n\nconst buttonVariants = cva(\n  \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90\",\n        destructive:\n          \"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n        outline:\n          \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\n        secondary:\n          \"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80\",\n        ghost:\n          \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n        link: \"text-primary underline-offset-4 hover:underline\",\n      },\n      size: {\n        default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n        sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n        lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n        icon: \"size-9\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Button({\n  className,\n  variant,\n  size,\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean\n  }) {\n  const Comp = asChild ? Slot : \"button\"\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Button, buttonVariants }\n","import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs))\n}\n","\"use client\";\n\nimport { Button } from \"../ui/button\";\nimport { cn } from \"../utils/cn\";\nimport { ArrowDownIcon } from \"lucide-react\";\nimport type { ComponentProps } from \"react\";\nimport { useCallback } from \"react\";\nimport { StickToBottom, useStickToBottomContext } from \"use-stick-to-bottom\";\n\nexport type ConversationProps = ComponentProps<typeof StickToBottom> & {\n  /** Receives the actual scroll viewport element (StickToBottom owns it and\n   *  exposes it via contextRef.scrollRef — a plain `ref` won't reach it). Used\n   *  for reverse-pagination scroll-position management. */\n  onScrollRef?: (el: HTMLElement | null) => void;\n};\n\nexport const Conversation = ({ className, onScrollRef, ...props }: ConversationProps) => (\n  // NOTE: the live region lives on ConversationContent (below), NOT here.\n  // StickToBottom renders this root as the scroll viewport, with an inner\n  // scroll-container div and then the content div (StickToBottom.Content) that\n  // actually wraps the streamed message nodes. Putting role=\"log\"/aria-live on\n  // the root would (a) scope announcements to the whole viewport — including the\n  // floating scroll-to-bottom button — and (b) risk a nested second live region.\n  // We scope the live region tightly to the content div instead.\n  <StickToBottom\n    contextRef={\n      onScrollRef\n        ? (ctx) => onScrollRef(ctx?.scrollRef.current ?? null)\n        : undefined\n    }\n    className={cn(\"relative flex-1 overflow-y-auto\", className)}\n    // `instant` (not `smooth`) for the INITIAL position: when a conversation\n    // loads (first mount / tab switch) it should appear already pinned to the\n    // bottom, NOT paint at the top and then animate a scroll down — that read as\n    // a flashy re-scroll on every tab switch. Live streaming still follows\n    // smoothly via `resize`.\n    initial=\"instant\"\n    resize=\"smooth\"\n    {...props}\n  />\n);\n\nexport type ConversationContentProps = ComponentProps<\n  typeof StickToBottom.Content\n>;\n\nexport const ConversationContent = ({\n  className,\n  ...props\n}: ConversationContentProps) => (\n  // Live region for streamed assistant responses. This is the div that directly\n  // wraps the rendered message nodes (StickToBottom wires its `contentRef`\n  // here), so appended/changed text lands INSIDE the boundary and is announced.\n  //   - role=\"log\": ordered, append-style updates (chat transcript semantics).\n  //   - aria-live=\"polite\": announce without interrupting the user.\n  //   - aria-atomic=\"false\": announce only what changed, not the whole log.\n  //   - aria-relevant=\"additions text\": new nodes + text edits to existing ones.\n  // Per-character drip is suppressed for reduced-motion users (see\n  // use-smooth-text.ts) so SRs announce coherent chunks rather than fragments.\n  <StickToBottom.Content\n    aria-atomic=\"false\"\n    aria-live=\"polite\"\n    aria-relevant=\"additions text\"\n    className={cn(\"p-4\", className)}\n    role=\"log\"\n    {...props}\n  />\n);\n\nexport type ConversationEmptyStateProps = ComponentProps<\"div\"> & {\n  title?: string;\n  description?: string;\n  icon?: React.ReactNode;\n};\n\nexport const ConversationEmptyState = ({\n  className,\n  title = \"No messages yet\",\n  description = \"Start a conversation to see messages here\",\n  icon,\n  children,\n  ...props\n}: ConversationEmptyStateProps) => (\n  <div\n    className={cn(\n      \"flex size-full flex-col items-center justify-center gap-3 p-8 text-center\",\n      className\n    )}\n    {...props}\n  >\n    {children ?? (\n      <>\n        {icon && <div className=\"text-muted-foreground\">{icon}</div>}\n        <div className=\"space-y-1\">\n          <h3 className=\"font-medium text-sm\">{title}</h3>\n          {description && (\n            <p className=\"text-muted-foreground text-sm\">{description}</p>\n          )}\n        </div>\n      </>\n    )}\n  </div>\n);\n\nexport type ConversationScrollButtonProps = ComponentProps<typeof Button>;\n\nexport const ConversationScrollButton = ({\n  className,\n  ...props\n}: ConversationScrollButtonProps) => {\n  const { isAtBottom, scrollToBottom } = useStickToBottomContext();\n\n  const handleScrollToBottom = useCallback(() => {\n    scrollToBottom();\n  }, [scrollToBottom]);\n\n  return (\n    !isAtBottom && (\n      <Button\n        className={cn(\n          \"absolute bottom-4 left-[50%] translate-x-[-50%] rounded-full\",\n          className\n        )}\n        aria-label=\"Scroll to bottom\"\n        onClick={handleScrollToBottom}\n        size=\"icon\"\n        type=\"button\"\n        variant=\"outline\"\n        {...props}\n      >\n        <ArrowDownIcon className=\"size-4\" />\n      </Button>\n    )\n  );\n};\n","\"use client\"\n\nimport * as React from \"react\"\nimport * as AvatarPrimitive from \"@radix-ui/react-avatar\"\n\nimport { cn } from \"../utils/cn\"\n\nfunction Avatar({\n  className,\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Root>) {\n  return (\n    <AvatarPrimitive.Root\n      data-slot=\"avatar\"\n      className={cn(\n        \"relative flex size-8 shrink-0 overflow-hidden rounded-full\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarImage({\n  className,\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Image>) {\n  return (\n    <AvatarPrimitive.Image\n      data-slot=\"avatar-image\"\n      className={cn(\"aspect-square size-full\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarFallback({\n  className,\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {\n  return (\n    <AvatarPrimitive.Fallback\n      data-slot=\"avatar-fallback\"\n      className={cn(\n        \"bg-muted flex size-full items-center justify-center rounded-full\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Avatar, AvatarImage, AvatarFallback }\n","import {\n  Avatar,\n  AvatarFallback,\n  AvatarImage,\n} from \"../ui/avatar\";\nimport { cn } from \"../utils/cn\";\nimport type { UIMessage } from \"ai\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentProps, HTMLAttributes, ReactNode } from \"react\";\n\nexport type MessageProps = HTMLAttributes<HTMLDivElement> & {\n  from: UIMessage[\"role\"];\n};\n\nexport const Message = ({ className, from, ...props }: MessageProps) => (\n  <div\n    className={cn(\n      \"group flex w-full items-end justify-end gap-2\",\n      from === \"user\" ? \"is-user\" : \"is-assistant flex-row-reverse justify-end\",\n      className\n    )}\n    {...props}\n  />\n);\n\nconst messageContentVariants = cva(\n  // `min-w-0` lets the bubble shrink inside its flex row instead of being forced\n  // to its content's intrinsic width; `break-words` wraps long unbreakable\n  // tokens (URLs, hashes) rather than overflowing. See styles.src.css for the\n  // matching `overflow-wrap: anywhere` rule.\n  \"flex min-w-0 flex-col gap-2 overflow-hidden break-words leading-relaxed chat-message-content\",\n  {\n    variants: {\n      variant: {\n        contained: [\n          // User messages: compact, high-contrast bubbles on the right. The\n          // tighter tail corner and 1.45 line-height match the renderer rhythm\n          // without changing the public MessageContent API.\n          \"group-[.is-user]:max-w-[var(--chat-message-max-width)] group-[.is-user]:rounded-2xl group-[.is-user]:rounded-br-[5px] group-[.is-user]:px-[15px] group-[.is-user]:py-[9px] group-[.is-user]:text-[14px] group-[.is-user]:leading-[1.45]\",\n          // Assistant messages: no bubble by default, just text on background.\n          \"group-[.is-assistant]:max-w-full\",\n        ],\n        flat: [\n          \"group-[.is-user]:max-w-[var(--chat-message-max-width)] group-[.is-user]:px-[15px] group-[.is-user]:py-[9px] group-[.is-user]:rounded-2xl group-[.is-user]:rounded-br-[5px] group-[.is-user]:leading-[1.45]\",\n          \"group-[.is-assistant]:max-w-full\",\n        ],\n        surface: [\n          \"rounded-2xl border px-4 py-3 shadow-sm\",\n          \"border-[hsl(var(--chat-border))] bg-[hsl(var(--chat-surface)/0.64)]\",\n          \"group-[.is-user]:max-w-[var(--chat-message-max-width)] group-[.is-user]:rounded-br-lg\",\n          \"group-[.is-assistant]:max-w-full group-[.is-assistant]:rounded-bl-lg\",\n        ],\n        ghost: [\n          \"max-w-full\",\n        ],\n      },\n      density: {\n        compact: \"text-[13px] leading-relaxed group-[.is-user]:px-3 group-[.is-user]:py-2\",\n        balanced: \"text-[14px] leading-relaxed\",\n        spacious: \"text-[15px] leading-7 group-[.is-user]:px-5 group-[.is-user]:py-4\",\n      },\n    },\n    defaultVariants: {\n      variant: \"contained\",\n      density: \"balanced\",\n    },\n  }\n);\n\nexport type MessageContentProps = HTMLAttributes<HTMLDivElement> &\n  VariantProps<typeof messageContentVariants>;\n\nexport const MessageContent = ({\n  children,\n  className,\n  variant,\n  density,\n  ...props\n}: MessageContentProps) => (\n  <div\n    className={cn(messageContentVariants({ variant, density, className }))}\n    {...props}\n  >\n    {children}\n  </div>\n);\n\nexport type MessageMetadataProps = HTMLAttributes<HTMLDivElement> & {\n  items?: ReactNode[];\n};\n\nexport const MessageMetadata = ({ items, children, className, ...props }: MessageMetadataProps) => {\n  const content = children ?? items?.filter(Boolean).map((item, i) => (\n    <span className=\"inline-flex items-center gap-1\" key={i}>\n      {i > 0 && <span className=\"text-[hsl(var(--chat-text-subtle))]\" aria-hidden=\"true\">·</span>}\n      <span>{item}</span>\n    </span>\n  ));\n\n  if (!content) return null;\n\n  return (\n    <div\n      className={cn(\n        \"not-prose mt-2 flex flex-wrap items-center gap-1.5 text-[11px] leading-none text-[hsl(var(--chat-text-muted))]\",\n        className\n      )}\n      {...props}\n    >\n      {content}\n    </div>\n  );\n};\n\nexport type MessageAvatarProps = ComponentProps<typeof Avatar> & {\n  src: string;\n  name?: string;\n};\n\nexport const MessageAvatar = ({\n  src,\n  name,\n  className,\n  ...props\n}: MessageAvatarProps) => (\n  <Avatar className={cn(\"size-8 ring-1 ring-border\", className)} {...props}>\n    <AvatarImage alt=\"\" className=\"mt-0 mb-0\" src={src} />\n    <AvatarFallback>{name?.slice(0, 2) || \"ME\"}</AvatarFallback>\n  </Avatar>\n);\n","import type { ComponentType } from 'react';\nimport { FileText } from 'lucide-react';\nimport { getFileIconByExtension } from './file-icon-map';\n\n/**\n * One shared \"what does this file look like\" helper for every attachment chip\n * (composer chips + message attachments — previously two byte-identical copies\n * with generic lucide glyphs). The icon comes from the ported brand-icon map\n * (real Python/TS/React/PDF/Excel glyphs); the label stays a short uppercase\n * hint so the chip always says something even for unknown types.\n */\nexport function describeFile(file: { filename?: string; mediaType?: string }): {\n  Icon: ComponentType<{ className?: string }>;\n  label: string;\n} {\n  const filename = file.filename || '';\n  const mt = (file.mediaType || '').toLowerCase();\n  const ext = filename.toLowerCase().split('.').pop() || '';\n\n  // Extension-based brand icon first — it covers code, docs, sheets, slides,\n  // data files and images. `returnNullForUnknown` so we can fall through to\n  // the media-type heuristics for extensionless uploads.\n  const byName = filename ? getFileIconByExtension(filename, true) : null;\n  if (byName) {\n    return { Icon: byName, label: labelFor(ext, mt) };\n  }\n\n  // No recognizable filename — fall back to broad media-type buckets.\n  const byMime = mt === 'application/pdf'\n    ? getFileIconByExtension('x.pdf', true)\n    : mt.includes('spreadsheet') || mt.includes('excel')\n      ? getFileIconByExtension('x.xlsx', true)\n      : mt.includes('presentation') || mt.includes('powerpoint')\n        ? getFileIconByExtension('x.pptx', true)\n        : mt.includes('wordprocessing') || mt.includes('msword')\n          ? getFileIconByExtension('x.docx', true)\n          : mt.startsWith('text/')\n            ? getFileIconByExtension('x.txt', true)\n            : mt.startsWith('image/')\n              ? getFileIconByExtension('x.png', true)\n              : null;\n\n  return { Icon: byMime ?? FileText, label: labelFor(ext, mt) };\n}\n\nfunction labelFor(ext: string, mt: string): string {\n  if (ext) return ext.toUpperCase();\n  if (mt === 'application/pdf') return 'PDF';\n  if (mt.includes('spreadsheet') || mt.includes('excel')) return 'Spreadsheet';\n  if (mt.includes('presentation') || mt.includes('powerpoint')) return 'Slides';\n  if (mt.includes('wordprocessing') || mt.includes('msword')) return 'Doc';\n  if (mt.startsWith('text/')) return 'Text';\n  if (mt.startsWith('image/')) return 'Image';\n  return 'File';\n}\n","// File-extension-to-icon dispatch — mirrors Crunch's getFileIconByExtension.\nimport { FileText } from 'lucide-react';\nimport {\n  TypeScriptIcon,\n  JavaScriptIcon,\n  PythonIcon,\n  GoIcon,\n  RustIcon,\n  ReactIcon,\n  VueIcon,\n  SvelteIcon,\n  AstroIcon,\n  SwiftIcon,\n  KotlinIcon,\n  RubyIcon,\n  PHPIcon,\n  JavaIcon,\n  CIcon,\n  CppIcon,\n  CSharpIcon,\n  CSSIcon,\n  HTMLIcon,\n  SCSSIcon,\n  JSONIcon,\n  YAMLIcon,\n  ShellIcon,\n  SQLIcon,\n  GraphQLIcon,\n  PrismaIcon,\n  DockerIcon,\n  TOMLIcon,\n  MarkdownIcon,\n  MarkdownInfoIcon,\n  CSVIcon,\n  SQLiteIcon,\n  ParquetIcon,\n  ArrowDataIcon,\n  ExcelIcon,\n  PDFIcon,\n  ImageFileIcon,\n  SVGIcon,\n  TxtIcon,\n  WordIcon,\n  PowerPointIcon,\n  NpmIcon,\n  GitIcon,\n  LockFileIcon,\n  LicenseIcon,\n} from './framework-icons';\n\nexport function getFileIconByExtension(\n  filename: string,\n  returnNullForUnknown = false,\n): React.ComponentType<{ className?: string }> | null {\n  const filenameLower = filename.toLowerCase();\n  const baseFilename = filenameLower.split('/').pop() || filenameLower;\n\n  // Dockerfile\n  if (filenameLower === 'dockerfile' || filenameLower.endsWith('/dockerfile')) {\n    return DockerIcon;\n  }\n\n  // Git files\n  if (\n    baseFilename === '.gitignore' ||\n    baseFilename === '.gitattributes' ||\n    baseFilename === '.gitmodules' ||\n    baseFilename === '.gitkeep'\n  ) {\n    return GitIcon;\n  }\n\n  // .npmrc\n  if (baseFilename === '.npmrc') {\n    return NpmIcon;\n  }\n\n  // .prettierrc\n  if (baseFilename === '.prettierrc') {\n    return JSONIcon;\n  }\n\n  // LICENSE / COPYING\n  if (\n    baseFilename === 'license' ||\n    baseFilename === 'license.md' ||\n    baseFilename === 'license.txt' ||\n    baseFilename === 'copying' ||\n    baseFilename === 'copying.md' ||\n    baseFilename === 'copying.txt'\n  ) {\n    return LicenseIcon;\n  }\n\n  // Lock files\n  if (\n    baseFilename === 'package-lock.json' ||\n    baseFilename === 'yarn.lock' ||\n    baseFilename === 'pnpm-lock.yaml' ||\n    baseFilename === 'bun.lockb' ||\n    baseFilename === 'composer.lock' ||\n    baseFilename === 'gemfile.lock' ||\n    baseFilename === 'cargo.lock' ||\n    baseFilename === 'poetry.lock' ||\n    baseFilename === 'pipfile.lock' ||\n    baseFilename.endsWith('.lock')\n  ) {\n    return LockFileIcon;\n  }\n\n  // .env files\n  if (baseFilename === '.env') {\n    return TOMLIcon;\n  }\n  if (baseFilename.startsWith('.env.')) {\n    return ShellIcon;\n  }\n\n  // Markdown — README gets info icon\n  if (filenameLower.endsWith('.md') || filenameLower.endsWith('.mdx')) {\n    const nameWithoutExt = baseFilename.replace(/\\.(md|mdx)$/, '');\n    if (nameWithoutExt === 'readme') {\n      return MarkdownInfoIcon;\n    }\n    return MarkdownIcon;\n  }\n\n  // JavaScript files\n  if (\n    filenameLower.endsWith('.js') ||\n    filenameLower.endsWith('.mjs') ||\n    filenameLower.endsWith('.cjs')\n  ) {\n    return JavaScriptIcon;\n  }\n\n  const ext = filename.split('.').pop()?.toLowerCase() || '';\n\n  switch (ext) {\n    case 'tsx':\n      return ReactIcon;\n    case 'ts':\n      return TypeScriptIcon;\n    case 'js':\n    case 'mjs':\n    case 'cjs':\n      return JavaScriptIcon;\n    case 'jsx':\n      return ReactIcon;\n    case 'py':\n    case 'pyw':\n    case 'pyi':\n      return PythonIcon;\n    case 'go':\n      return GoIcon;\n    case 'rs':\n      return RustIcon;\n    case 'css':\n      return CSSIcon;\n    case 'html':\n    case 'htm':\n      return HTMLIcon;\n    case 'scss':\n    case 'sass':\n      return SCSSIcon;\n    case 'json':\n    case 'jsonc':\n      return JSONIcon;\n    case 'yaml':\n    case 'yml':\n      return YAMLIcon;\n    case 'sh':\n    case 'bash':\n    case 'zsh':\n      return ShellIcon;\n    case 'sql':\n      return SQLIcon;\n    case 'graphql':\n    case 'gql':\n      return GraphQLIcon;\n    case 'prisma':\n      return PrismaIcon;\n    case 'dockerfile':\n      return DockerIcon;\n    case 'toml':\n      return TOMLIcon;\n    case 'env':\n      return TOMLIcon;\n    case 'java':\n      return JavaIcon;\n    case 'c':\n    case 'h':\n      return CIcon;\n    case 'cpp':\n    case 'cc':\n    case 'cxx':\n    case 'hpp':\n      return CppIcon;\n    case 'cs':\n      return CSharpIcon;\n    case 'php':\n      return PHPIcon;\n    case 'rb':\n      return RubyIcon;\n    case 'kt':\n      return KotlinIcon;\n    case 'vue':\n      return VueIcon;\n    case 'svelte':\n      return SvelteIcon;\n    case 'astro':\n      return AstroIcon;\n    case 'swift':\n      return SwiftIcon;\n    // Data files\n    case 'csv':\n    case 'tsv':\n      return CSVIcon;\n    case 'db':\n    case 'sqlite':\n    case 'sqlite3':\n      return SQLiteIcon;\n    case 'parquet':\n    case 'pq':\n      return ParquetIcon;\n    case 'xlsx':\n    case 'xls':\n      return ExcelIcon;\n    case 'arrow':\n    case 'feather':\n    case 'ipc':\n      return ArrowDataIcon;\n    // Documents\n    case 'pdf':\n      return PDFIcon;\n    case 'doc':\n    case 'docx':\n      return WordIcon;\n    case 'ppt':\n    case 'pptx':\n      return PowerPointIcon;\n    // Images\n    case 'png':\n    case 'jpg':\n    case 'jpeg':\n    case 'gif':\n    case 'webp':\n    case 'ico':\n    case 'bmp':\n      return ImageFileIcon;\n    case 'svg':\n      return SVGIcon;\n    case 'txt':\n      return TxtIcon;\n    default:\n      return returnNullForUnknown ? null : FileText;\n  }\n}\n\n// ── Widget additions (not in the jarvis/Crunch original) ────────────────────\n\n/**\n * Map a fenced-code language tag (```python, ```tsx …) to the same brand\n * icons, by translating the tag to a representative file extension and\n * reusing the dispatch above. Unknown tags fall back to the generic file icon.\n */\nconst LANGUAGE_TO_EXT: Record<string, string> = {\n  javascript: 'js', js: 'js', jsx: 'jsx',\n  typescript: 'ts', ts: 'ts', tsx: 'tsx',\n  python: 'py', py: 'py',\n  go: 'go', golang: 'go',\n  rust: 'rs', rs: 'rs',\n  ruby: 'rb', rb: 'rb',\n  java: 'java', kotlin: 'kt', kt: 'kt',\n  c: 'c', cpp: 'cpp', 'c++': 'cpp', csharp: 'cs', 'c#': 'cs', cs: 'cs',\n  php: 'php', swift: 'swift',\n  html: 'html', xml: 'html', svg: 'svg',\n  css: 'css', scss: 'scss', sass: 'scss', less: 'css',\n  json: 'json', jsonc: 'json', json5: 'json',\n  yaml: 'yaml', yml: 'yaml', toml: 'toml',\n  bash: 'sh', sh: 'sh', shell: 'sh', zsh: 'sh', console: 'sh', powershell: 'sh',\n  sql: 'sql', postgres: 'sql', mysql: 'sql', sqlite: 'sql',\n  graphql: 'graphql', gql: 'graphql', prisma: 'prisma',\n  dockerfile: 'dockerfile', docker: 'dockerfile',\n  markdown: 'md', md: 'md', mdx: 'md', text: 'txt', txt: 'txt',\n  vue: 'vue', svelte: 'svelte', astro: 'astro',\n};\n\nexport function getFileIconByLanguage(\n  language: string,\n): React.ComponentType<{ className?: string }> {\n  const ext = LANGUAGE_TO_EXT[language.toLowerCase().trim()];\n  return (ext ? getFileIconByExtension(`x.${ext}`, true) : null) ?? FileText;\n}\n","// Framework/language file icons with brand colours — ported from Crunch.\n// Each icon embeds its brand colour in the SVG so callers just size it.\n\ninterface IconProps {\n  className?: string;\n}\n\n// ── Language icons ───────────────────────────────────────────────────────────\n\nexport function TypeScriptIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 32 32\" className={className} xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M23.827 8.243A4.424 4.424 0 0 1 26.05 9.524a5.853 5.853 0 0 1 .852 1.143c.011.045-1.534 1.083-2.471 1.662-.034.023-.169-.124-.322-.35a2.014 2.014 0 0 0-1.67-1c-1.077-.074-1.771.49-1.766 1.433a1.3 1.3 0 0 0 .153.666c.237.49.677.784 2.059 1.383 2.544 1.095 3.636 1.817 4.31 2.843a5.158 5.158 0 0 1 .416 4.333 4.764 4.764 0 0 1-3.932 2.815 10.9 10.9 0 0 1-2.708-.028 6.531 6.531 0 0 1-3.616-1.884 6.278 6.278 0 0 1-.926-1.371 2.655 2.655 0 0 1 .327-.208c.158-.09.756-.434 1.32-.761L19.1 19.6l.214.312a4.771 4.771 0 0 0 1.35 1.292 3.3 3.3 0 0 0 3.458-.175 1.545 1.545 0 0 0 .2-1.974c-.276-.395-.84-.727-2.443-1.422a8.8 8.8 0 0 1-3.349-2.055 4.687 4.687 0 0 1-.976-1.777 7.116 7.116 0 0 1-.062-2.268 4.332 4.332 0 0 1 3.644-3.374A9 9 0 0 1 23.827 8.243ZM15.484 9.726l.011 1.454h-4.63V24.328H7.6V11.183H2.97V9.755A13.986 13.986 0 0 1 3.01 8.289c.017-.023 2.832-.034 6.245-.028l6.211.017Z\" fill=\"#007acc\" />\n    </svg>\n  );\n}\n\nexport function JavaScriptIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 800 800\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M241.667 100H308.333V166.667H241.667V333.333C241.667 351.014 234.643 367.971 222.14 380.474 209.638 392.976 192.681 400 175 400 192.681 400 209.638 407.024 222.14 419.526 234.643 432.029 241.667 448.986 241.667 466.667V633.333H308.333V700H241.667C206 691 175 670 175 633.333V500C175 482.319 167.976 465.362 155.474 452.86 142.971 440.357 126.014 433.333 108.333 433.333H75V366.667H108.333C126.014 366.667 142.971 359.643 155.474 347.14 167.976 334.638 175 317.681 175 300V166.667C175 148.986 182.024 132.029 194.526 119.526 207.029 107.024 223.986 100 241.667 100ZM557.833 100C575.514 100 592.471 107.024 604.974 119.526 617.476 132.029 624.5 148.986 624.5 166.667V300C624.5 317.681 631.524 334.638 644.026 347.14 656.529 359.643 673.486 366.667 691.167 366.667H724.5V433.333H691.167C673.486 433.333 656.529 440.357 644.026 452.86 631.524 465.362 624.5 482.319 624.5 500V633.333C624.5 651.014 617.476 667.971 604.974 680.474 592.471 692.976 575.514 700 557.833 700H491.167V633.333H557.833V466.667C557.833 448.986 564.857 432.029 577.36 419.526 589.862 407.024 606.819 400 624.5 400 606.819 400 589.862 392.976 577.36 380.474 564.857 367.971 557.833 351.014 557.833 333.333V166.667H491.167V100H557.833Z\" fill=\"#f6de19\" />\n    </svg>\n  );\n}\n\nexport function PythonIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"16 16 32 32\" className={className} fill=\"none\">\n      <defs>\n        <linearGradient id=\"py_a\" x1=\"19.075\" x2=\"34.898\" y1=\"18.782\" y2=\"34.658\" gradientUnits=\"userSpaceOnUse\">\n          <stop stopColor=\"#387EB8\" /><stop offset=\"1\" stopColor=\"#366994\" />\n        </linearGradient>\n        <linearGradient id=\"py_b\" x1=\"28.809\" x2=\"45.803\" y1=\"28.882\" y2=\"45.163\" gradientUnits=\"userSpaceOnUse\">\n          <stop stopColor=\"#FFE052\" /><stop offset=\"1\" stopColor=\"#FFC331\" />\n        </linearGradient>\n      </defs>\n      <path fill=\"url(#py_a)\" d=\"M31.885 16c-8.124 0-7.617 3.523-7.617 3.523l.01 3.65h7.752v1.095H21.197S16 23.678 16 31.876c0 8.196 4.537 7.906 4.537 7.906h2.708v-3.804s-.146-4.537 4.465-4.537h7.688s4.32.07 4.32-4.175v-7.019S40.374 16 31.885 16zm-4.275 2.454a1.394 1.394 0 1 1 0 2.79 1.393 1.393 0 0 1-1.395-1.395c0-.771.624-1.395 1.395-1.395z\" />\n      <path fill=\"url(#py_b)\" d=\"M32.115 47.833c8.124 0 7.617-3.523 7.617-3.523l-.01-3.65H31.97v-1.095h10.832S48 40.155 48 31.958c0-8.197-4.537-7.906-4.537-7.906h-2.708v3.803s.146 4.537-4.465 4.537h-7.688s-4.32-.07-4.32 4.175v7.019s-.656 4.247 7.833 4.247zm4.275-2.454a1.393 1.393 0 0 1-1.395-1.395 1.394 1.394 0 1 1 1.395 1.395z\" />\n    </svg>\n  );\n}\n\nexport function GoIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 207 78\" className={className}>\n      <g fill=\"#000\" fillRule=\"evenodd\">\n        <path d=\"m16.2 24.1c-.4 0-.5-.2-.3-.5l2.1-2.7c.2-.3.7-.5 1.1-.5h35.7c.4 0 .5.3.3.6l-1.7 2.6c-.2.3-.7.6-1 .6z\" />\n        <path d=\"m1.1 33.3c-.4 0-.5-.2-.3-.5l2.1-2.7c.2-.3.7-.5 1.1-.5h45.6c.4 0 .6.3.5.6l-.8 2.4c-.1.4-.5.6-.9.6z\" />\n        <path d=\"m25.3 42.5c-.4 0-.5-.3-.3-.6l1.4-2.5c.2-.3.6-.6 1-.6h20c.4 0 .6.3.6.7l-.2 2.4c0 .4-.4.7-.7.7z\" />\n        <g transform=\"translate(55)\">\n          <path d=\"m74.1 22.3c-6.3 1.6-10.6 2.8-16.8 4.4-1.5.4-1.6.5-2.9-1-1.5-1.7-2.6-2.8-4.7-3.8-6.3-3.1-12.4-2.2-18.1 1.5-6.8 4.4-10.3 10.9-10.2 19 .1 8 5.6 14.6 13.5 15.7 6.8.9 12.5-1.5 17-6.6.9-1.1 1.7-2.3 2.7-3.7-3.6 0-8.1 0-19.3 0-2.1 0-2.6-1.3-1.9-3 1.3-3.1 3.7-8.3 5.1-10.9.3-.6 1-1.6 2.5-1.6h36.4c-.2 2.7-.2 5.4-.6 8.1-1.1 7.2-3.8 13.8-8.2 19.6-7.2 9.5-16.6 15.4-28.5 17-9.8 1.3-18.9-.6-26.9-6.6-7.4-5.6-11.6-13-12.7-22.2-1.3-10.9 1.9-20.7 8.5-29.3 7.1-9.3 16.5-15.2 28-17.3 9.4-1.7 18.4-.6 26.5 4.9 5.3 3.5 9.1 8.3 11.6 14.1.6.9.2 1.4-1 1.7z\" />\n          <path d=\"m107.2 77.6c-9.1-.2-17.4-2.8-24.4-8.8-5.9-5.1-9.6-11.6-10.8-19.3-1.8-11.3 1.3-21.3 8.1-30.2 7.3-9.6 16.1-14.6 28-16.7 10.2-1.8 19.8-.8 28.5 5.1 7.9 5.4 12.8 12.7 14.1 22.3 1.7 13.5-2.2 24.5-11.5 33.9-6.6 6.7-14.7 10.9-24 12.8-2.7.5-5.4.6-8 .9zm23.8-40.4c-.1-1.3-.1-2.3-.3-3.3-1.8-9.9-10.9-15.5-20.4-13.3-9.3 2.1-15.3 8-17.5 17.4-1.8 7.8 2 15.7 9.2 18.9 5.5 2.4 11 2.1 16.3-.6 7.9-4.1 12.2-10.5 12.7-19.1z\" fillRule=\"nonzero\" />\n        </g>\n      </g>\n    </svg>\n  );\n}\n\nexport function RustIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 224 224\" className={className} fill=\"#000\">\n      <path d=\"M218.46 109.358l-9.062-5.614c-.076-.882-.162-1.762-.258-2.642l7.803-7.265a3.107 3.107 0 00.933-2.89 3.093 3.093 0 00-1.967-2.312l-9.97-3.715c-.25-.863-.512-1.72-.781-2.58l6.214-8.628a3.114 3.114 0 00-.592-4.263 3.134 3.134 0 00-1.431-.637l-10.507-1.709a80.869 80.869 0 00-1.263-2.353l4.417-9.7a3.12 3.12 0 00-.243-3.035 3.106 3.106 0 00-2.705-1.385l-10.671.372a85.152 85.152 0 00-1.685-2.044l2.456-10.381a3.125 3.125 0 00-3.762-3.763l-10.384 2.456a88.996 88.996 0 00-2.047-1.684l.373-10.671a3.11 3.11 0 00-1.385-2.704 3.127 3.127 0 00-3.034-.246l-9.681 4.417c-.782-.429-1.567-.854-2.353-1.265l-1.713-10.506a3.098 3.098 0 00-1.887-2.373 3.108 3.108 0 00-3.014.35l-8.628 6.213c-.85-.27-1.703-.53-2.56-.778l-3.716-9.97a3.111 3.111 0 00-2.311-1.97 3.134 3.134 0 00-2.89.933l-7.266 7.802a93.746 93.746 0 00-2.643-.258l-5.614-9.082A3.125 3.125 0 00111.97 4c-1.09 0-2.085.56-2.642 1.478l-5.615 9.081a93.32 93.32 0 00-2.642.259l-7.266-7.802a3.13 3.13 0 00-2.89-.933 3.106 3.106 0 00-2.312 1.97l-3.715 9.97c-.857.247-1.71.506-2.56.778L73.7 12.588a3.101 3.101 0 00-3.014-.35A3.127 3.127 0 0068.8 14.61l-1.713 10.506c-.79.41-1.575.832-2.353 1.265l-9.681-4.417a3.125 3.125 0 00-4.42 2.95l.372 10.67c-.69.553-1.373 1.115-2.048 1.685l-10.383-2.456a3.143 3.143 0 00-2.93.832 3.124 3.124 0 00-.833 2.93l2.436 10.383a93.897 93.897 0 00-1.68 2.043l-10.672-.372a3.138 3.138 0 00-2.704 1.385 3.126 3.126 0 00-.246 3.035l4.418 9.7c-.43.779-.855 1.563-1.266 2.353l-10.507 1.71a3.097 3.097 0 00-2.373 1.886 3.117 3.117 0 00.35 3.013l6.214 8.628a89.12 89.12 0 00-.78 2.58l-9.97 3.715a3.117 3.117 0 00-1.035 5.202l7.803 7.265c-.098.879-.184 1.76-.258 2.642l-9.062 5.614A3.122 3.122 0 004 112.021c0 1.092.56 2.084 1.478 2.642l9.062 5.614c.074.882.16 1.762.258 2.642l-7.803 7.265a3.117 3.117 0 001.034 5.201l9.97 3.716a110 110 0 00.78 2.58l-6.212 8.627a3.112 3.112 0 00.6 4.27c.419.33.916.547 1.443.63l10.507 1.709c.407.792.83 1.576 1.265 2.353l-4.417 9.68a3.126 3.126 0 002.95 4.42l10.65-.374c.553.69 1.115 1.372 1.685 2.047l-2.456 10.382a3.125 3.125 0 003.763 3.762l10.383-2.454c.69.574 1.374 1.137 2.047 1.683l-.373 10.672a3.11 3.11 0 001.385 2.704c.834.609 1.972.654 2.81.136l9.7-4.417c.779.43 1.564.854 2.353 1.265l1.71 10.507a3.098 3.098 0 001.886 2.373c1.034.397 2.197-.008 2.798-.868l6.213-8.628c.863.27 1.714.53 2.579.78l3.716 9.97a3.117 3.117 0 005.201 1.034l7.265-7.803c.881.098 1.762.184 2.642.258l5.614 9.063A3.108 3.108 0 00111.98 220c1.09 0 2.084-.56 2.642-1.478l5.614-9.062c.882-.076 1.762-.162 2.642-.258l7.265 7.803a3.117 3.117 0 005.201-1.034l3.716-9.97c.862-.25 1.717-.51 2.579-.78l8.628 6.213c.602.86 1.762 1.263 2.798.868a3.106 3.106 0 001.887-2.373l1.709-10.507c.79-.411 1.574-.835 2.353-1.265l9.7 4.417c.838.518 1.98.473 2.81-.136a3.11 3.11 0 001.386-2.704l-.374-10.672c.674-.546 1.355-1.109 2.047-1.683l10.383 2.454a3.125 3.125 0 003.762-3.762l-2.456-10.382c.574-.69 1.137-1.374 1.685-2.047l10.65.374a3.126 3.126 0 002.95-4.42l-4.417-9.68c.435-.777.858-1.56 1.265-2.353l10.507-1.709a3.107 3.107 0 001.443-.63 3.112 3.112 0 00.6-4.27l-6.212-8.628c.268-.86.53-1.717.78-2.579l9.97-3.716a3.117 3.117 0 001.034-5.201l-7.803-7.265c.098-.88.184-1.76.258-2.642l9.062-5.614A3.122 3.122 0 00220 112.021a3.12 3.12 0 00-1.54-2.663z\" />\n    </svg>\n  );\n}\n\nexport function ReactIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 569 512\" className={className} fill=\"none\" fillRule=\"evenodd\">\n      <g fill=\"#087EA4\" fillRule=\"nonzero\">\n        <path d=\"M285.5 201c-30.1 0-54.5 24.4-54.5 54.5s24.4 54.5 54.5 54.5S340 285.6 340 255.5 315.6 201 285.5 201\" />\n        <path d=\"M568.96 255.994c0-42.786-39.622-80.313-102.708-105.01.843-5.56 1.606-11.062 2.148-16.463 6.222-61.48-8.591-105.852-41.69-124.967-37.033-21.383-89.34-5.863-142.23 36.462-52.89-42.325-105.197-57.845-142.23-36.462-33.099 19.115-47.912 63.488-41.69 124.967.542 5.401 1.285 10.923 2.148 16.505-5.259 2.008-10.417 4.136-15.375 6.365C31.011 182.71 0 217.765 0 255.994c0 42.787 39.622 80.313 102.708 105.01-.863 5.56-1.606 11.062-2.148 16.463-6.222 61.48 8.591 105.852 41.69 124.967 11.38 6.453 24.274 9.752 37.354 9.557 31.352 0 67.964-16.504 104.876-46.02 36.892 29.516 73.524 46.02 104.916 46.02 13.08.192 25.973-3.107 37.354-9.557 33.099-19.115 47.912-63.488 41.69-124.967-.542-5.401-1.305-10.923-2.148-16.465 63.086-24.656 102.709-62.243 102.709-95.01M389.155 27.103c8.41-.203 16.723 1.834 24.087 5.903 22.982 13.272 33.3 49.272 28.28 98.765-.34 3.373-.742 6.786-1.224 10.22-26.231-7.902-53.092-13.538-80.287-16.846-16.486-21.92-34.818-42.388-54.796-61.178 31.372-24.255 60.818-36.864 83.92-36.864m-10.798 283.103c-10.152 17.625-21.206 34.714-33.119 51.199-20.19 2.075-40.477 3.107-60.776 3.092-20.292.014-40.572-1.018-60.758-3.092-11.881-16.486-22.902-33.575-33.018-51.2-10.151-17.576-19.377-35.671-27.335-54.101-7.985-18.475-14.673-37.443-19.954-56.719 5.281-19.277 11.969-38.243 19.954-56.717 7.958-18.43 17.184-36.525 27.335-54.1 10.115-17.626 21.137-34.715 33.018-51.201 20.186-2.075 40.466-3.106 60.758-3.09 20.299-.014 40.586 1.018 60.776 3.09 11.913 16.486 22.967 33.575 33.119 51.2 10.15 17.576 19.376 35.672 27.333 54.102 7.985 18.474 14.673 37.44 19.955 56.717-5.282 19.276-11.97 38.244-19.955 56.719-7.957 18.43-17.183 36.525-27.333 54.1\" />\n      </g>\n    </svg>\n  );\n}\n\nexport function VueIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 256 221\" className={className} preserveAspectRatio=\"xMidYMid\">\n      <path d=\"M204.8 0H256L128 220.8 0 0h97.92L128 51.2 157.44 0h47.36Z\" fill=\"#41B883\" />\n      <path d=\"m0 0 128 220.8L256 0h-51.2L128 132.48 50.56 0H0Z\" fill=\"#41B883\" />\n      <path d=\"M50.56 0 128 133.12 204.8 0h-47.36L128 51.2 97.92 0H50.56Z\" fill=\"#35495E\" />\n    </svg>\n  );\n}\n\nexport function SvelteIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 256 308\" className={className} preserveAspectRatio=\"xMidYMid\">\n      <path d=\"M239.682 40.707C211.113-.182 154.69-12.301 113.895 13.69L42.247 59.356a82.198 82.198 0 00-37.135 55.056 86.566 86.566 0 008.536 55.576 82.425 82.425 0 00-12.296 30.719 87.596 87.596 0 0014.964 66.244c28.574 40.893 84.997 53.007 125.787 27.016l71.648-45.664a82.182 82.182 0 0037.135-55.057 86.601 86.601 0 00-8.53-55.577 82.409 82.409 0 0012.29-30.718 87.573 87.573 0 00-14.963-66.244\" fill=\"#FF3E00\" />\n      <path d=\"M106.889 270.841c-23.102 6.007-47.497-3.036-61.103-22.648a52.685 52.685 0 01-9.003-39.85 49.978 49.978 0 011.713-6.693l1.35-4.115 3.671 2.697a92.447 92.447 0 0028.036 14.007l2.663.808-.245 2.659a16.067 16.067 0 002.89 10.656 17.143 17.143 0 0018.397 6.828 15.786 15.786 0 004.403-1.935l71.67-45.672a14.922 14.922 0 006.734-9.977 15.923 15.923 0 00-2.713-12.011 17.156 17.156 0 00-18.404-6.832 15.78 15.78 0 00-4.396 1.933l-27.35 17.434a52.298 52.298 0 01-14.553 6.391c-23.101 6.007-47.497-3.036-61.101-22.649a52.681 52.681 0 01-9.004-39.849 49.428 49.428 0 0122.34-33.114l71.664-45.677a52.218 52.218 0 0114.563-6.398c23.101-6.007 47.497 3.036 61.101 22.648a52.685 52.685 0 019.004 39.85 50.559 50.559 0 01-1.713 6.692l-1.35 4.116-3.67-2.693a92.373 92.373 0 00-28.037-14.013l-2.664-.809.246-2.658a16.099 16.099 0 00-2.89-10.656 17.143 17.143 0 00-18.398-6.828 15.786 15.786 0 00-4.402 1.935l-71.67 45.674a14.898 14.898 0 00-6.73 9.975 15.9 15.9 0 002.709 12.012 17.156 17.156 0 0018.404 6.832 15.841 15.841 0 004.402-1.935l27.345-17.427a52.147 52.147 0 0114.552-6.397c23.101-6.006 47.497 3.037 61.102 22.65a52.681 52.681 0 019.003 39.848 49.453 49.453 0 01-22.34 33.12l-71.664 45.673a52.218 52.218 0 01-14.563 6.398\" fill=\"#FFF\" />\n    </svg>\n  );\n}\n\nexport function AstroIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 85 107\" className={className} fill=\"none\">\n      <path d=\"M27.59 91.136c-4.834-4.418-6.246-13.703-4.232-20.429 3.492 4.241 8.33 5.584 13.342 6.343 7.737 1.17 15.336.732 22.523-2.804.822-.405 1.582-.943 2.48-1.489.675 1.957.85 3.932.615 5.943-.573 4.896-3.01 8.678-6.885 11.545-1.55 1.147-3.19 2.172-4.79 3.253-4.917 3.323-6.247 7.22-4.4 12.888.044.139.084.277.183.614-2.51-1.124-4.344-2.76-5.742-4.911-1.475-2.27-2.177-4.78-2.214-7.498-.019-1.322-.019-2.656-.197-3.96-.434-3.178-1.926-4.601-4.737-4.683-2.884-.084-5.166 1.699-5.771 4.507-.046.216-.113.429-.18.68l.004.001ZM0 69.587s14.314-6.973 28.668-6.973L39.49 29.12c.405-1.62 1.588-2.72 2.924-2.72 1.335 0 2.518 1.1 2.924 2.72L56.16 62.614c17 0 28.668 6.973 28.668 6.973S60.514 3.352 60.467 3.219C59.769 1.261 58.591 0 57.003 0H27.827c-1.588 0-2.718 1.261-3.464 3.22C24.311 3.35 0 69.586 0 69.586Z\" fill=\"#17191E\" />\n    </svg>\n  );\n}\n\nexport function SwiftIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} xmlns=\"http://www.w3.org/2000/svg\">\n      <path fill=\"#D15F3E\" fillRule=\"evenodd\" d=\"M18.103 21.018c-2.827 1.633-6.714 1.801-10.625.125C4.312 19.796 1.684 17.438 0 14.743c.808.674 1.752 1.213 2.762 1.684 4.039 1.893 8.077 1.764 10.918.005l-.004-.004c-4.042-3.1-7.478-7.142-10.038-10.442C3.1 5.446 2.695 4.773 2.29 4.166c3.1 2.83 8.018 6.4 9.77 7.411-3.705-3.908-7.007-8.758-6.872-8.623C11.048 8.882 16.506 12.25 16.506 12.25c.18.102.32.187.432.263.118-.3.222-.613.309-.936.943-3.436-.135-7.343-2.493-10.577 5.456 3.301 8.69 9.5 7.343 14.687-.035.14-.074.278-.115.414.016.019.032.038.048.058 2.694 3.369 1.953 6.939-1.383 5.93z\" />\n    </svg>\n  );\n}\n\nexport function KotlinIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} xmlns=\"http://www.w3.org/2000/svg\" role=\"img\">\n      <title>Kotlin</title>\n      <path d=\"M1.3 24l11.3-11.5L24 24zM0 0h12L0 12.5zM13.4 0L0 14v10l12-12L24 0z\" fill=\"#E37834\" />\n    </svg>\n  );\n}\n\nexport function RubyIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 32 32\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <defs>\n        <linearGradient id=\"ruby0\" x1=\"22.594\" x2=\"8.892\" y1=\"19.841\" y2=\"28\" gradientUnits=\"userSpaceOnUse\">\n          <stop stopColor=\"#FB7655\" /><stop offset=\"0\" stopColor=\"#FB7655\" /><stop offset=\"1\" stopColor=\"#E42B1E\" />\n        </linearGradient>\n        <linearGradient id=\"ruby1\" x1=\"26.663\" x2=\"20.984\" y1=\"26.781\" y2=\"21.726\" gradientUnits=\"userSpaceOnUse\">\n          <stop stopColor=\"#871101\" /><stop offset=\"1\" stopColor=\"#871101\" stopOpacity=\"0\" />\n        </linearGradient>\n      </defs>\n      <path fillRule=\"evenodd\" clipRule=\"evenodd\" d=\"M22.594 19.841L8.892 28l17.742-1.207L28 8.853l-5.406 10.988z\" fill=\"url(#ruby0)\" />\n      <path fillRule=\"evenodd\" clipRule=\"evenodd\" d=\"M26.663 26.781l-1.525-10.555-4.154 5.5 5.679 5.055z\" fill=\"url(#ruby1)\" />\n      <path fillRule=\"evenodd\" clipRule=\"evenodd\" d=\"M26.684 26.78L15.512 25.9l-6.56 2.076 17.732-1.196z\" fill=\"#871101\" />\n    </svg>\n  );\n}\n\nexport function PHPIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 128 128\" className={className} xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M41.52 15.02c9.367-16.72 32.129-20.53 46.165-6.08 2.177 2.24 3.857 4.954 5.085 7.97 1.013 3.348 1.517 7.054 1.517 10.898 0 5.97-1.2 12.25-3.418 17.935-2.217 5.688-5.45 10.768-9.407 14.406-2.64 2.428-5.587 4.222-8.8 5.205-1.834.565-3.76.866-5.792.866-2.422 0-4.996-.43-7.736-1.393l-1.491 4.25c3.177 1.118 6.27 1.646 9.227 1.646 2.789.002 5.456-.47 7.95-1.336 2.5-.864 4.824-2.12 6.958-3.678 4.27-3.115 7.779-7.422 10.49-12.338 1.807-3.28 3.26-6.835 4.33-10.517 1.431-4.908 2.19-10.041 2.19-15.045 0-1.925-.112-3.828-.345-5.695 30.573 17.93 28.36 50.572 22.733 68.837C116.097 107.441 110.871 127.446 110.871 127.446H88.973c0 0 0-8.588-1.644-20.005-1.513-10.522-18.964-10.48-20.254-.172-.595 4.76-.43 20.178-.43 20.178H44.319c0 0-3.008-24.043-5.585-41.22-1.572-10.487-15.853-10.401-13.31-.857 3.438 12.88 2.715 27.855-1.938 37.614-1.674 3.511-3.012 6.234-5.585 4.46-2.572-1.775-5.685-4.637-7.719-5.326-2.034-.687 1.246-4.582 1.933-8.409 3.005-16.747-5.153-22.33-8.159-44.656C.03 39.875 18.148 21.54 41.521 15.02zM30.434 55.316a2.886 2.886 0 100-5.773 2.886 2.886 0 000 5.773z\" fill=\"#A074C4\" />\n    </svg>\n  );\n}\n\nexport function JavaIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 256 346\" className={className} preserveAspectRatio=\"xMidYMid\">\n      <path d=\"M83 267s-14 8 9 11c27 3 41 2 71-3 0 0 8 5 19 9-67 29-153-2-99-17M74 230s-15 11 8 13c29 3 52 3 92-4 0 0 6 5 15 8-82 24-173 2-115-17\" fill=\"#5382A1\" />\n      <path d=\"M144 166c17 19-4 36-4 36s42-22 22-49c-18-26-32-38 44-82 0 0-119 29-62 95\" fill=\"#E76F00\" />\n      <path d=\"M233 295s10 8-10 15c-39 12-163 15-197 0-12-5 11-13 18-14l12-2c-14-9-89 19-38 28 138 22 251-10 215-27M89 190s-63 15-22 21c17 2 51 2 83-1 26-2 52-7 52-7l-16 9c-64 16-187 8-151-9 30-14 54-13 54-13M202 253c64-33 34-66 13-61l-7 2s2-3 6-5c41-14 73 43-14 66l2-2\" fill=\"#5382A1\" />\n      <path d=\"M162 0s36 36-34 91c-56 45-12 70 0 99-32-30-56-56-40-80 23-35 89-53 74-110\" fill=\"#E76F00\" />\n      <path d=\"M95 345c62 4 158-3 160-32 0 0-4 11-51 20-53 10-119 9-158 2 0 0 8 7 49 10\" fill=\"#5382A1\" />\n    </svg>\n  );\n}\n\nexport function CIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 128 128\" className={className} xmlns=\"http://www.w3.org/2000/svg\" preserveAspectRatio=\"xMidYMid meet\">\n      <path d=\"M111.21 107.69L99.92 85.46c-.16-.32-.46-.55-.81-.63s-.71.01-.99.23c-6.32 5.01-17.18 8.79-25.27 8.79-15.63 0-26.55-10.58-26.55-25.73s10.92-25.73 26.55-25.73c8.46 0 17.14 2.72 22.64 7.11.27.22.64.3.98.24.34-.07.64-.29.81-.6l12.52-22.81c.28-.51.15-1.15-.31-1.51-9.47-7.5-21.49-11.15-36.75-11.15-32.5 0-56.08 22.91-56.08 54.46 0 31.56 23.58 54.46 56.08 54.46 14.87 0 27.72-4.52 38.18-13.45.42-.36.54-.96.29-1.45z\" fill=\"#40C0E7\" />\n    </svg>\n  );\n}\n\nexport function CppIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 256 288\" className={className} preserveAspectRatio=\"xMidYMid\">\n      <path fill=\"#649AD2\" d=\"M255.987 84.59c-.002-4.837-1.037-9.112-3.13-12.781-2.054-3.608-5.133-6.632-9.261-9.023-34.08-19.651-68.195-39.242-102.264-58.913-9.185-5.303-18.09-5.11-27.208.27-13.565 8-81.48 46.91-101.719 58.632C4.071 67.6.015 74.984.013 84.58 0 124.101.013 163.62 0 203.141c0 4.73.993 8.923 2.993 12.537 2.056 3.717 5.177 6.824 9.401 9.269 20.24 11.722 88.164 50.63 101.726 58.631 9.121 5.382 18.027 5.575 27.215.27 34.07-19.672 68.186-39.262 102.272-58.913 4.224-2.444 7.345-5.553 9.401-9.267 1.997-3.614 2.992-7.806 2.992-12.539 0 0 0-79.018-.013-118.539\" />\n      <path fill=\"#004482\" d=\"M128.392 143.476l-125.4 72.202c2.057 3.717 5.178 6.824 9.402 9.269 20.24 11.722 88.164 50.63 101.726 58.631 9.121 5.382 18.027 5.575 27.215.27 34.07-19.672 68.186-39.262 102.272-58.913 4.224-2.444 7.345-5.553 9.401-9.267l-124.616-72.192\" />\n      <path fill=\"#1A4674\" d=\"M91.25 164.863c7.297 12.738 21.014 21.33 36.75 21.33 15.833 0 29.628-8.7 36.888-21.576l-36.496-21.141-37.142 21.387\" />\n      <path fill=\"#01589C\" d=\"M255.987 84.59c-.002-4.837-1.037-9.112-3.13-12.781l-124.465 71.667 124.616 72.192c1.997-3.614 2.99-7.806 2.992-12.539 0 0 0-79.018-.013-118.539\" />\n      <path fill=\"#FFF\" d=\"M249.135 148.636h-9.738v9.74h-9.74v-9.74h-9.737V138.9h9.737v-9.738h9.74v9.738h9.738v9.737zM128 58.847c31.135 0 58.358 16.74 73.17 41.709l.444.759-37.001 21.307c-7.333-12.609-20.978-21.094-36.613-21.094-23.38 0-42.333 18.953-42.333 42.332a42.13 42.13 0 005.583 21.003c7.297 12.738 21.014 21.33 36.75 21.33 15.659 0 29.325-8.51 36.647-21.153l.241-.423 36.947 21.406c-14.65 25.597-42.228 42.851-73.835 42.851-31.549 0-59.084-17.185-73.754-42.707-7.162-12.459-11.26-26.904-11.26-42.307 0-46.95 38.061-85.013 85.014-85.013zm75.865 70.314v9.738h9.737v9.737h-9.737v9.74h-9.738v-9.74h-9.738V138.9h9.738v-9.738h9.738z\" />\n    </svg>\n  );\n}\n\nexport function CSharpIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 -1.43 255.58 290.11\" className={className} preserveAspectRatio=\"xMidYMid\">\n      <path fill=\"#a179dc\" d=\"M255.57 84.45c0-4.83-1.04-9.1-3.13-12.76a24.4 24.4 0 00-9.24-9C209.17 43.05 175.1 23.5 141.1 3.86c-9.17-5.3-18.06-5.1-27.16.27-13.54 7.98-81.35 46.83-101.55 58.53C4.06 67.5.02 74.87 0 84.44v118.37c0 4.72 1 8.9 2.99 12.51 2.05 3.72 5.17 6.82 9.38 9.26 20.21 11.7 88.02 50.55 101.56 58.53 9.11 5.38 18 5.57 27.17.27 34.02-19.64 68.08-39.2 102.1-58.81a24.33 24.33 0 009.4-9.25c1.99-3.61 2.98-7.8 2.98-12.52l-.01-118.35\" />\n      <path fill=\"#280068\" d=\"M128.18 143.24L2.98 215.33c2.06 3.7 5.18 6.8 9.4 9.25 20.2 11.7 88.01 50.55 101.55 58.53 9.11 5.38 18 5.57 27.17.27 34.02-19.64 68.08-39.2 102.1-58.81a24.33 24.33 0 009.4-9.25z\" />\n      <path fill=\"#390091\" d=\"M255.57 84.45c0-4.83-1.04-9.1-3.13-12.76l-124.26 71.55 124.41 72.07c2-3.6 2.99-7.79 3-12.51 0 0 0-78.9-.02-118.35\" />\n      <g fill=\"#fff\">\n        <path d=\"M201.9 116.3v13.47h13.47v-13.48h6.73v13.48h13.48v6.73H222.1v13.48h13.48v6.74H222.1v13.47h-6.73V156.7h-13.48v13.48h-6.73V156.7h-13.48v-6.73h13.47V136.5h-13.47v-6.74h13.47v-13.48zm13.47 20.2h-13.48v13.48h13.48z\" />\n        <path d=\"M128.46 48.63a94.96 94.96 0 0182.26 47.45l-.16-.27-41.35 23.8A47.28 47.28 0 00129 96.33h-.54a47.3 47.3 0 00-47.3 47.3 47.08 47.08 0 006.23 23.47 47.28 47.28 0 0082.29-.27l-.2.35 41.29 23.91a94.97 94.97 0 01-81.25 47.54h-1.06a94.96 94.96 0 01-95-95 95 95 0 0195-95z\" />\n      </g>\n    </svg>\n  );\n}\n\n// ── Style / markup icons ─────────────────────────────────────────────────────\n\nexport function CSSIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 16 16\" className={className} xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M7.76 14l.752-2.914H6.045L5.3 14H3.532l.746-2.914H2V9.365h2.712l.701-2.806H2.947V4.838h2.91L6.567 2h1.766l-.71 2.838h2.46L10.8 2h1.768l-.717 2.838H14v1.72h-2.598l-.707 2.807h2.375v1.72h-2.807L9.5 14zm-1.313-4.608h2.507L9.673 6.542H7.167z\" fill=\"#519ABA\" />\n    </svg>\n  );\n}\n\nexport function HTMLIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M9.953 16.912L8.594 18.361 2.03 12.202l6.16-6.563 1.458 1.37-4.79 5.103 5.094 4.782z\" fill=\"#e37834\" />\n      <path d=\"M14.048 16.912l1.36 1.449 6.562-6.16-6.16-6.562-1.458 1.37 4.79 5.103-5.094 4.782z\" fill=\"#e37834\" />\n    </svg>\n  );\n}\n\nexport function SCSSIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 32 32\" className={className} xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M16.171 18.7c-.481.221-1.008.509-2.063 1.088-.4.225-.818.45-1.207.662-.027-.027-.055-.061-.082-.089-2.087-2.23-5.947-3.805-5.783-6.8.061-1.091.436-3.955 7.413-7.433 5.742-2.83 10.311-2.046 11.1-.307C26.683 8.3 23.1 12.913 17.17 13.582a4.469 4.469 0 01-3.751-.948c-.314-.341-.361-.361-.477-.293-.191.1-.068.409 0 .586a3.5 3.5 0 002.141 1.684 11.4 11.4 0 006.956-.689c3.594-1.391 6.4-5.258 5.578-8.5-.825-3.287-6.281-4.371-11.443-2.537a26 26 0 00-8.79 5.047c-2.844 2.66-3.294 4.972-3.11 5.94.662 3.437 5.4 5.674 7.3 7.331-.1.055-.184.1-.259.143-.948.471-4.562 2.36-5.463 4.358-1.023 2.264.164 3.887.948 4.105a5.832 5.832 0 006.281-2.544 6.3 6.3 0 00.559-5.8 5.03 5.03 0 01.716-.477c.484-.286.945-.568 1.354-.786l0 0a10.475 10.475 0 014.475-.989c3.246.382 3.887 2.407 3.764 3.26a2.157 2.157 0 01-1.03 1.459c-.225.143-.3.191-.28.293.027.15.136.143.327.116a2.535 2.535 0 001.766-2.257c.1-2-1.807-4.194-5.183-4.174a7.753 7.753 0 00-2.946.587q-.225.093-.437.2zm-4.825 7.839c-1.078 1.173-2.578 1.616-3.226 1.241-.7-.4-.423-2.135.9-3.376a17.18 17.18 0 012.53-1.889c.157-.1.389-.232.668-.4.048-.027.075-.041.075-.041l.164-.1A4.658 4.658 0 0111.346 26.539z\" fill=\"#cd6799\" />\n    </svg>\n  );\n}\n\n// ── Config / data icons ──────────────────────────────────────────────────────\n\nexport function JSONIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 32 32\" className={className} xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M4.014 14.976a2.51 2.51 0 001.567-.518 2.377 2.377 0 00.805-1.358 15.261 15.261 0 00.212-2.947q.012-2.085.075-2.747a5.236 5.236 0 01.418-1.686 3.025 3.025 0 01.755-1.018A3.046 3.046 0 019 4.125 6.762 6.762 0 0110.544 4h.7v1.96h-.387a2.338 2.338 0 00-1.723.468 3.4 3.4 0 00-1.425 2.092 36.054 36.054 0 00-.137 4.133 4.734 4.734 0 01-.768 2.06A4.567 4.567 0 016.1 16a3.809 3.809 0 011.992 1.754 8.861 8.861 0 01.618 3.865q0 2.435.05 2.9a1.755 1.755 0 00.504 1.186 2.639 2.639 0 001.592.337h.387V28h-.7a5.655 5.655 0 01-1.773-.2 2.97 2.97 0 01-1.324-.93 3.353 3.353 0 01-.681-1.63 24.175 24.175 0 01-.169-3.234 16.469 16.469 0 00-.212-3.109 2.408 2.408 0 00-.805-1.361 2.489 2.489 0 00-1.567-.524z\" fill=\"#fbc02d\" />\n      <path d=\"M27.986 17.011a2.489 2.489 0 00-1.567.524 2.408 2.408 0 00-.805 1.361 16.469 16.469 0 00-.212 3.109 24.175 24.175 0 01-.169 3.234 3.353 3.353 0 01-.681 1.63 2.97 2.97 0 01-1.324.93 5.655 5.655 0 01-1.773.2h-.7V26.04h.387a2.639 2.639 0 001.592-.337 1.755 1.755 0 00.506-1.186q.05-.462.05-2.9a8.861 8.861 0 01.618-3.865A3.809 3.809 0 0125.9 16a4.567 4.567 0 01-1.7-1.286 4.734 4.734 0 01-.768-2.06 36.054 36.054 0 01-.137-4.133 3.4 3.4 0 00-.425-2.092 2.338 2.338 0 00-1.723-.468h-.387V4h.7A6.762 6.762 0 0123 4.125a3.046 3.046 0 011.149.581 3.025 3.025 0 01.755 1.018 5.236 5.236 0 01.418 1.686q.062.662.075 2.747a15.261 15.261 0 00.212 2.947 2.377 2.377 0 00.805 1.355 2.51 2.51 0 001.567.518z\" fill=\"#fbc02d\" />\n    </svg>\n  );\n}\n\nexport function YAMLIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 800 800\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M305.909 587.814L468.322 598.598l-7.047 106.131-162.413-10.784 7.047-106.131zM335.836 95.079l-9.807 427.412 131.127 8.705 46.789-424.957-168.109-11.16z\" fill=\"#A074C4\" />\n    </svg>\n  );\n}\n\nexport function ShellIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path fillRule=\"evenodd\" d=\"M7 8.5C7 6.296 8.738 4.501 11.005 4.09L11 3c0-.552.448-1 1-1s1 .448 1 1v1l-.004.089C15.263 4.502 17 6.296 17 8.5c0 .552-.448 1-1 1a1 1 0 01-.993-.883L15 8.5c0-1.349-1.316-2.5-3-2.5S9 7.151 9 8.5c0 1.299 1.22 2.414 2.814 2.495L12 11c2.734 0 5 1.983 5 4.5 0 2.202-1.734 3.995-4 4.41V21c0 .552-.448 1-1 1s-1-.448-1-1v-1.09c-2.265-.414-4-2.208-4-4.41 0-.552.448-1 1-1s1 .448 1 1c0 1.349 1.316 2.5 3 2.5s3-1.151 3-2.5c0-1.299-1.22-2.414-2.814-2.495L12 13c-2.734 0-5-1.983-5-4.5z\" fill=\"#8DC149\" />\n    </svg>\n  );\n}\n\nexport function SQLIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 688 629\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M342.833 342.867C344.6 342.867 346.667 342.9 348.733 342.9 416.633 342.9 482.9 335.9 546.867 322.6L540.6 323.7C595.4 314 644.233 294.167 687.167 266.1L685.667 267V342.9C685.667 363.434 670.344 382.478 639.7 400.034 603.533 419.367 561.533 433.934 517.167 441.434L514.733 441.767C464.867 451.567 407.5 457.2 348.867 457.2 346.767 457.2 344.667 457.2 342.567 457.167H342.9C341.133 457.167 339.033 457.2 336.9 457.2 278.233 457.2 220.9 451.567 165.367 440.867L171.033 441.767C124.167 433.934 82.1667 419.367 43.7667 398.934L46 400.034C15.3556 382.478 0 363.434 0 342.9V267C41.5 294.167 90.3 314 142.767 323.334L145.133 323.667C202.8 335.9 269.1 342.9 337 342.9 339.067 342.9 341.167 342.9 343.233 342.867H342.9 342.833zM342.833 514.267C344.6 514.267 346.667 514.3 348.733 514.3 416.633 514.3 482.9 507.3 546.867 494L540.6 495.1C595.4 485.4 644.233 465.567 687.167 437.5L685.667 438.4V514.3C685.667 534.834 670.344 553.878 639.7 571.434 603.533 590.767 561.533 605.334 517.167 612.834L514.733 613.167C464.867 622.967 407.5 628.6 348.867 628.6 346.767 628.6 344.667 628.6 342.567 628.567H342.9C341.133 628.567 339.033 628.6 336.9 628.6 278.233 628.6 220.9 622.967 165.367 612.267L171.033 613.167C124.2 605.334 82.2 590.767 43.7667 570.334L46 571.434C15.3333 553.878 0 534.834 0 514.3V438.4C41.4667 465.567 90.2667 485.4 142.733 494.734L145.1 495.067C202.767 507.3 269.067 514.3 336.967 514.3 339.033 514.3 341.1 514.3 343.2 514.267H342.833zM342.833 0C344.567 0 346.6-.066 348.633-.066 407.333-.066 464.733 5.567 520.3 16.3L514.633 15.4C561.467 23.234 603.467 37.8 641.9 58.234L639.667 57.134C670.311 74.689 685.633 93.734 685.633 114.267V171.4C685.633 191.934 670.311 210.978 639.667 228.534 603.5 247.867 561.5 262.434 517.133 269.934L514.7 270.267C464.833 280.067 407.467 285.7 348.833 285.7 346.733 285.7 344.633 285.7 342.533 285.667H342.867C341.1 285.667 339 285.7 336.867 285.7 278.2 285.7 220.867 280.067 165.333 269.367L171 270.267C124.167 262.434 82.1667 247.867 43.7333 227.434L46 228.534C15.3333 210.978 0 191.934 0 171.4V114.267C41.4667 141.434 90.2667 161.267 142.733 170.6L145.1 170.934C202.767 183.167 269.067 190.167 336.967 190.167 339.033 190.167 341.1 190.167 343.2 190.134H342.833z\" fill=\"#F55385\" />\n    </svg>\n  );\n}\n\nexport function GraphQLIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 256 288\" className={className} xmlns=\"http://www.w3.org/2000/svg\" preserveAspectRatio=\"xMidYMid\">\n      <g fillRule=\"evenodd\">\n        <path d=\"M152.576 32.963l59.146 34.15c1.665-1.765 3.61-3.322 5.818-4.604C229.806 55.457 245.452 59.644 252.577 71.91c7.052 12.268 2.865 27.913-9.402 35.038-2.19 1.26-4.49 2.16-6.831 2.72v68.325c2.316.562 4.59 1.457 6.758 2.703 12.34 7.125 16.527 22.77 9.402 35.037-7.052 12.267-22.77 16.454-35.037 9.402-2.442-1.394-4.564-3.141-6.34-5.137L152.34 253.93c.84 2.539 1.295 5.255 1.295 8.079 0 14.103-11.459 25.635-25.635 25.635s-25.635-11.459-25.635-25.635c0-2.52.362-4.954 1.037-7.253L44.27 220.615c-1.647 1.73-3.566 3.258-5.737 4.52-12.34 7.051-27.986 2.864-35.037-9.403-7.052-12.267-2.865-27.912 9.402-35.037 2.168-1.247 4.443-2.142 6.757-2.704v-68.323c-2.341-.56-4.641-1.461-6.831-2.72C-5.44 99.896-9.628 84.178-2.577 71.91 5.474 59.644 21.194 55.457 33.46 62.509c2.195 1.275 4.131 2.822 5.79 4.575l59.163-34.158c-.682-2.31-1.048-4.757-1.048-7.29 0-14.177 11.459-25.636 25.635-25.636s25.635 11.459 25.635 25.636c0 2.547-.37 5.007-1.06 7.328z\" fill=\"#E535AB\" />\n      </g>\n    </svg>\n  );\n}\n\nexport function PrismaIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 32 32\" className={className} xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M25.21 24.21L12.739 27.928a.525.525 0 01-.667-.606L16.528 5.811a.43.43 0 01.809-.094l8.249 17.661a.6.6 0 01-.376.832zm2.139-.878L17.8 2.883A1.531 1.531 0 0016.491 2a1.513 1.513 0 00-1.4.729L4.736 19.648a1.592 1.592 0 00.018 1.7l5.064 7.909a1.628 1.628 0 001.83.678l14.7-4.383a1.6 1.6 0 001-2.218z\" fill=\"#519ABA\" fillRule=\"evenodd\" />\n    </svg>\n  );\n}\n\nexport function DockerIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} xmlns=\"http://www.w3.org/2000/svg\">\n      <path fill=\"#0DB7ED\" fillRule=\"evenodd\" d=\"M6.942 14.9a.44.44 0 01.158.03c-.053.031-.089.088-.089.154 0 .099.08.179.179.179a.24.24 0 00.156-.093.76.76 0 01.034.168c0 .241-.196.437-.437.437a.437.437 0 01-.438-.437c0-.242.196-.438.437-.438zm0 1.185a.851.851 0 01-.748-.748c0-.412.336-.748.748-.748s.748.336.748.748-.336.748-.748.748zM20.386 11.184c-2.124 5.628-6.92 8.135-12.576 8.135-2.672 0-4.803-.919-6.167-2.452l.01-.006c.393.02.744.026 1.101.026.327 0 .646-.003.941-.02l.084-.006c.751-.047 1.333-.151 1.876-.306h.001c.099-.028.195-.058.286-.09.103-.035.157-.147.122-.25-.035-.102-.147-.156-.25-.12-.69.239-1.6.37-2.715.395-.567.013-1.187-.002-1.86-.045-.139-.186-.268-.379-.386-.579l-.186-.34a2.31 2.31 0 01-.118-.214c.465.15.985.272 1.555.363.66.105 1.385.165 2.158.165a23.2 23.2 0 001.319-.04l.368-.026.133-.013.308-.036.147-.02.09-.014.14-.024.134-.024.124-.026.22-.05c.343-.08.652-.17.894-.268h.001c.1-.033.153-.145.12-.248-.033-.1-.145-.154-.247-.12-.69.238-1.6.37-2.715.395-.567.013-1.187-.002-1.86-.045a7.1 7.1 0 01-.386-.579l-.186-.34-.183-.332c1.524.484 3.28.784 5.232.84h.345l.705-.016c6.248-.207 11.479-2.022 14.227-6.084zm-7.281 7.026l.01.005c.393.02.744.026 1.101.026.327 0 .646-.003.941-.02l.084-.006c.751-.047 1.333-.151 1.876-.306h.001c.099-.028.195-.058.286-.09.103-.035.157-.147.122-.25-.035-.102-.147-.156-.25-.12-.69.239-1.6.37-2.715.395-.567.013-1.187-.002-1.86-.045a7.1 7.1 0 01-.386-.579 4.89 4.89 0 01-.665-1.248c-.732-1.915-.916-4.144-.54-6.496.13.784.383 1.54.749 2.242.82 1.568 2.044 2.8 3.517 3.546l.004.002c1.466.74 3.025.998 4.486.672.662-.148 1.171-.434 1.474-.84.26-.348.33-.71.204-1.03-.125-.32-.406-.542-.797-.653-.387-.11-.878-.125-1.444.04l.006-.002c-.456.132-.88.401-1.15.795-.085.124-.15.261-.19.406l-.003.012c-.028.096-.044.197-.048.297v.015c-.008.127.006.25.04.365.04.132.108.238.197.305a.48.48 0 00.28.095c.159 0 .319-.06.436-.165.03.002.058.01.058.01l-2.044 1.05c-.006-.008-.012-.016-.016-.024v-.004c.016-.05.034-.1.055-.148l.024-.051.051-.094.03-.047c.192-.28.284-.61.264-.945-.017-.277-.106-.532-.256-.742a1.28 1.28 0 00-.25-.276 1.22 1.22 0 00-.34-.205 1.03 1.03 0 00-.416-.08c-.3.016-.573.122-.798.317l-.01.008c-.196.17-.34.38-.416.615-.078.243-.093.488-.048.706.044.214.14.384.275.502l.001.001c.148.13.314.19.471.19.003 0 .006-.001.01 0h.003c.178-.001.34-.074.458-.183.02-.004.04-.01.04-.01 0 .02.002.04.005.058a.733.733 0 01-.158.412c-.175.24-.442.412-.758.526-.334.12-.745.182-1.194.17-.44-.012-.896-.107-1.316-.298a3.35 3.35 0 01-.856-.546l-.002-.002c-.327-.276-.615-.601-.853-.96-.5.083-.951.033-1.334-.143-.405-.186-.67-.515-.734-.96-.062-.434.085-.948.426-1.486.338-.535.842-1.065 1.48-1.544.007 0 .013-.006.02-.009.008-.005.015-.01.023-.016l3.064-1.855-.003.003c.126-.078.266-.144.417-.193l.06-.016a1.2 1.2 0 01.305-.052l.063-.002c.075 0 .15.006.222.017.39.06.73.22.996.462.278.253.456.588.508.966.058.428-.06.872-.328 1.255-.27.385-.687.687-1.19.88a4.63 4.63 0 01-.716.245l-.005.001a5.36 5.36 0 01-.83.157l-.058.006a7.25 7.25 0 01-.946.045c-.304 0-.608-.013-.91-.04l-.038-.004.018-.024.03-.047z\" />\n    </svg>\n  );\n}\n\nexport function TOMLIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 20 20\" className={className} xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M10 13a3 3 0 110-6 3 3 0 010 6zm7.476-1.246c-1.394-.754-1.394-2.754 0-3.508a1 1 0 00.376-1.404l-1.067-1.733a1 1 0 00-1.327-.355l-.447.243c-1.329.719-2.945-.244-2.945-1.755V3a1 1 0 00-1-1H8.934a1 1 0 00-1 1v.242c0 1.511-1.616 2.474-2.945 1.755l-.447-.243a1 1 0 00-1.327.355L2.148 6.842a1 1 0 00.376 1.404c1.394.754 1.394 2.754 0 3.508a1 1 0 00-.376 1.404l1.067 1.733a1 1 0 001.327.355l.447-.243c1.329-.719 2.945.244 2.945 1.755V17a1 1 0 001 1h2.132a1 1 0 001-1v-.242c0-1.511 1.616-2.474 2.945-1.755l.447.243a1 1 0 001.327-.355l1.067-1.733a1 1 0 00-.376-1.404z\" fill=\"#5C5F62\" />\n    </svg>\n  );\n}\n\n// ── Data file icons ──────────────────────────────────────────────────────────\n\nexport function CSVIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M14 2H6C5.46957 2 4.96086 2.21071 4.58579 2.58579 4.21071 2.96086 4 3.46957 4 4V20C4 20.5304 4.21071 21.0391 4.58579 21.4142 4.96086 21.7893 5.46957 22 6 22H18C18.5304 22 19.0391 21.7893 19.4142 21.4142 19.7893 21.0391 20 20.5304 20 20V8L14 2z\" stroke=\"#22c55e\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n      <path d=\"M14 2V8H20\" stroke=\"#22c55e\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n      <path d=\"M8 13H16\" stroke=\"#22c55e\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n      <path d=\"M8 17H16\" stroke=\"#22c55e\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n      <path d=\"M12 13V17\" stroke=\"#22c55e\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n    </svg>\n  );\n}\n\nexport function SQLiteIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <ellipse cx=\"12\" cy=\"5\" rx=\"8\" ry=\"3\" stroke=\"#3b82f6\" strokeWidth=\"2\" />\n      <path d=\"M4 5V19C4 20.6569 7.58172 22 12 22 16.4183 22 20 20.6569 20 19V5\" stroke=\"#3b82f6\" strokeWidth=\"2\" />\n      <path d=\"M4 12C4 13.6569 7.58172 15 12 15 16.4183 15 20 13.6569 20 12\" stroke=\"#3b82f6\" strokeWidth=\"2\" />\n    </svg>\n  );\n}\n\nexport function ParquetIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <rect x=\"3\" y=\"3\" width=\"5\" height=\"18\" rx=\"1\" stroke=\"#a855f7\" strokeWidth=\"2\" />\n      <rect x=\"10\" y=\"3\" width=\"5\" height=\"18\" rx=\"1\" stroke=\"#a855f7\" strokeWidth=\"2\" />\n      <rect x=\"17\" y=\"3\" width=\"4\" height=\"18\" rx=\"1\" stroke=\"#a855f7\" strokeWidth=\"2\" />\n    </svg>\n  );\n}\n\nexport function ArrowDataIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M5 12H19\" stroke=\"#f97316\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n      <path d=\"M12 5L19 12L12 19\" stroke=\"#f97316\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n      <path d=\"M5 5V19\" stroke=\"#f97316\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n    </svg>\n  );\n}\n\nexport function ExcelIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M7 2H17C18.1046 2 19 2.89543 19 4V20C19 21.1046 18.1046 22 17 22H7C5.89543 22 5 21.1046 5 20V4C5 2.89543 5.89543 2 7 2z\" fill=\"#2E7D32\" />\n      <path d=\"M9 8L12 12L15 8M9 16L12 12\" stroke=\"white\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n    </svg>\n  );\n}\n\n// ── Document icons ───────────────────────────────────────────────────────────\n\nexport function PDFIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"-4 0 40 40\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M25.669 26.096c-.488.144-1.203.16-1.97.049-.824-.12-1.664-.371-2.49-.742 1.473-.214 2.615-.148 3.592.198.231.082.612.301.868.495zm-8.214-1.35l-.177.048c-.396.108-.782.213-1.153.307l-.5.127c-1.008.255-2.038.515-3.056.825.387-.932.746-1.875 1.098-2.796.26-.683.526-1.38.801-2.067.14.23.285.46.437.692.69 1.05 1.557 2.022 2.55 2.864zm-.563-10.513c.066 1.15-.183 2.257-.547 3.319-.449-1.313-.658-2.763-.097-3.933.144-.3.262-.46.338-.544.118.182.273.59.306 1.158zm-5.259 14.573c-.252.45-.51.872-.773 1.27-.636.96-1.677 1.986-2.211 1.986-.053 0-.117-.008-.21-.107-.06-.062-.069-.107-.066-.169.018-.352.485-.98 1.162-1.562.614-.528 1.308-.998 2.098-1.418zm17.737-2.66c-.082-1.174-2.058-1.927-2.078-1.934-.764-.271-1.594-.403-2.537-.403-1.01 0-2.099.146-3.497.473-1.244-.882-2.319-1.986-3.122-3.209-.355-.54-.673-1.079-.951-1.605.678-1.622 1.289-3.366 1.178-5.32-.09-1.566-.796-2.618-1.756-2.618-.659 0-1.226.488-1.688 1.452-.822 1.717-.606 3.915.643 6.537-.45 1.057-.868 2.152-1.273 3.213-.503 1.319-1.022 2.679-1.607 3.973-1.639.649-2.986 1.436-4.109 2.402-.735.631-1.622 1.597-1.672 2.605-.025.475.138.91.469 1.259.351.37.793.565 1.278.566 1.603 0 3.146-2.203 3.439-2.645.589-.888 1.14-1.878 1.68-3.021 1.361-.492 2.811-.859 4.217-1.214l.503-.128c.379-.096.749-.19 1.11-.28.872-.22 1.697-.426 2.48-.627 1.104.48 2.616.744 3.48.451.758-.257 1.585-.94 2.242-1.225-.116.474-.272.905-.473 1.27-1.043-.554-2.353-1.01-3.118-.794-.643.18-.998.861-.724 1.448.892.899 2.914 1.762 4.03 1.512.885-.198 1.171-.868 1.022-1.448-.898-1.042-2.282-1.27-2.282-1.27s1.116.352 1.895 1.213c.86-1.235 1.334-2.682 1.22-.63z\" fill=\"#EB5757\" />\n    </svg>\n  );\n}\n\nexport function WordIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M7 2H17C18.1046 2 19 2.89543 19 4V20C19 21.1046 18.1046 22 17 22H7C5.89543 22 5 21.1046 5 20V4C5 2.89543 5.89543 2 7 2z\" fill=\"#2196F3\" />\n      <path d=\"M8 8L10 16L12 10L14 16L16 8\" stroke=\"white\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n    </svg>\n  );\n}\n\nexport function PowerPointIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M7 2H17C18.1046 2 19 2.89543 19 4V20C19 21.1046 18.1046 22 17 22H7C5.89543 22 5 21.1046 5 20V4C5 2.89543 5.89543 2 7 2z\" fill=\"#FF5722\" />\n      <path d=\"M9 7V17M9 7H13C14.6569 7 16 8.34315 16 10 16 11.6569 14.6569 13 13 13H9\" stroke=\"white\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n    </svg>\n  );\n}\n\n// ── Special file icons ───────────────────────────────────────────────────────\n\nexport function SVGIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <rect x=\"10\" y=\"10\" width=\"11\" height=\"11\" fill=\"#A174C4\" />\n      <path d=\"M13 8c0-.989-.293-1.956-.843-2.778-.55-.822-1.33-1.463-2.244-1.842a5.334 5.334 0 00-4.888.284A5.316 5.316 0 003.097 7.024a5.316 5.316 0 00.284 4.889A5.316 5.316 0 008 13V8h5z\" fill=\"#A174C4\" />\n    </svg>\n  );\n}\n\nexport function ImageFileIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" fill=\"#4CAF50\" />\n      <circle cx=\"8.5\" cy=\"8.5\" r=\"2\" fill=\"#FFF59D\" />\n      <path d=\"M21 15L16.5 10.5C16.1 10.1 15.5 10.1 15.1 10.5L10 15.6L8.4 14C8 13.6 7.4 13.6 7 14L3 18V19C3 20.1 3.9 21 5 21H19C20.1 21 21 20.1 21 19V15z\" fill=\"#81C784\" />\n    </svg>\n  );\n}\n\nexport function TxtIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M4 14h13.5M4 10h8M4 6h16M4 18.5h10\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n    </svg>\n  );\n}\n\nexport function MarkdownIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} xmlns=\"http://www.w3.org/2000/svg\">\n      <g>\n        <path fill=\"none\" d=\"M0 0h24v24H0z\" />\n        <path d=\"M3 3h18a1 1 0 011 1v16a1 1 0 01-1 1H3a1 1 0 01-1-1V4a1 1 0 011-1zm4 12.5v-4l2 2 2-2v4h2v-7h-2l-2 2-2-2H5v7h2zm11-3v-4h-2v4h-2l3 3 3-3h-2z\" fill=\"#3B82F6\" />\n      </g>\n    </svg>\n  );\n}\n\nexport function MarkdownInfoIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\">\n      <g transform=\"scale(1.1) translate(-1.2, -1.2)\">\n        <path d=\"M11 11H12V16M21 12C21 16.9706 16.9706 21 12 21 7.02944 21 3 16.9706 3 12 3 7.02944 7.02944 3 12 3 16.9706 3 21 7.02944 21 12z\" stroke=\"#3B82F6\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n        <path d=\"M12 7.25a.75.75 0 100 1.5.75.75 0 000-1.5z\" fill=\"#3B82F6\" stroke=\"#3B82F6\" strokeWidth=\"0.5\" />\n      </g>\n    </svg>\n  );\n}\n\nexport function NpmIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M3 21H12V7.5H16.5V21H21V3H3V21z\" fill=\"#CB3837\" />\n    </svg>\n  );\n}\n\nexport function GitIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M22.104 11.065L12.935 1.896a1.373 1.373 0 00-1.912 0L9.12 3.8l2.415 2.415a1.63 1.63 0 012.07 2.07l2.328 2.327a1.63 1.63 0 011.663.382 1.764 1.764 0 010 2.496 1.765 1.765 0 01-2.497 0 1.626 1.626 0 01-.35-1.75l-2.17-2.17v5.712c.153.076.298.177.425.305a1.764 1.764 0 010 2.496 1.764 1.764 0 01-2.496 0 1.764 1.764 0 010-2.496c.155-.155.335-.273.527-.351V9.227a1.64 1.64 0 01-.527-.35 1.614 1.614 0 01-.347-1.76L8.183 4.736 1.896 11.022a1.373 1.373 0 000 1.913l9.17 9.169c.527.528 1.383.528 1.912 0l9.126-9.126a1.373 1.373 0 000-1.913z\" fill=\"#F05032\" />\n    </svg>\n  );\n}\n\nexport function LockFileIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <rect x=\"5\" y=\"10\" width=\"14\" height=\"11\" rx=\"2\" stroke=\"#f59e0b\" strokeWidth=\"1.5\"  />\n      <path d=\"M8 10V7c0-2.209 1.791-4 4-4s4 1.791 4 4v3\" stroke=\"#f59e0b\" strokeWidth=\"1.5\" strokeLinecap=\"round\"  />\n      <circle cx=\"12\" cy=\"15\" r=\"1.5\" fill=\"#f59e0b\"  />\n      <path d=\"M12 16.5V18\" stroke=\"#f59e0b\" strokeWidth=\"1.5\" strokeLinecap=\"round\"  />\n    </svg>\n  );\n}\n\nexport function LicenseIcon({ className }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M14 2H6C4.89543 2 4 2.89543 4 4V20C4 21.1046 4.89543 22 6 22H18C19.1046 22 20 21.1046 20 20V8L14 2z\" stroke=\"#a855f7\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"  />\n      <path d=\"M14 2V8H20\" stroke=\"#a855f7\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"  />\n      <circle cx=\"12\" cy=\"14\" r=\"3\" stroke=\"#a855f7\" strokeWidth=\"1.5\"  />\n      <path d=\"M10.5 14L11.5 15L13.5 13\" stroke=\"#a855f7\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"  />\n    </svg>\n  );\n}\n","'use client';\n\n/**\n * Portal container for the widget's Radix primitives.\n *\n * Radix Popover/Tooltip/Select/DropdownMenu/Dialog portal their content to\n * `document.body` by default — OUTSIDE the widget's `.chat-widget-container`.\n * Every widget utility class is scoped by `scripts/scope-css.js` to\n * `.chat-widget-container <util>` (a DESCENDANT selector), and the `--chat-*`\n * design tokens + `.dark` overrides are defined only on `.chat-widget-container`.\n * So portalled content rendered on `document.body` matches none of those rules\n * and its tokens are undefined → popovers/menus/tooltips render transparent /\n * unstyled (and never dark) in a host app. It \"worked\" in our own dashboard only\n * because that page happens to sit inside compatible styling.\n *\n * Fix: mount a body-level `<div class=\"chat-widget-container [dark]\">` that\n * carries the tokens + theme + per-instance overrides, and portal Radix content\n * INTO it. The content is then a descendant of `.chat-widget-container` (scoped\n * utilities match, tokens resolve, dark applies) while still living on\n * `document.body` (so it escapes the widget's own overflow / stacking context —\n * the whole reason Radix portals in the first place).\n *\n * One host element is created per ChatWidget instance, so multiple widgets with\n * different themes on the same page don't collide.\n */\n\nimport {\n  createContext,\n  useContext,\n  useEffect,\n  useState,\n  type CSSProperties,\n  type ReactNode,\n} from 'react';\n\nconst ChatPortalContainerContext = createContext<HTMLElement | null>(null);\n\n/**\n * The element Radix portals should mount into. `null` until the body-level host\n * is created (SSR / first client render) — callers pass `container ?? undefined`\n * so Radix falls back to its default (`document.body`) in that window.\n */\nexport function useChatPortalContainer(): HTMLElement | null {\n  return useContext(ChatPortalContainerContext);\n}\n\nexport interface ChatPortalProviderProps {\n  /** `''` or `'dark'` — mirrors the widget container's theme class. */\n  themeClass?: string;\n  /** The widget's `--chat-*` custom-property overrides (from theme props). */\n  style?: CSSProperties;\n  children: ReactNode;\n}\n\nexport function ChatPortalProvider({\n  themeClass,\n  style,\n  children,\n}: ChatPortalProviderProps) {\n  const [container, setContainer] = useState<HTMLElement | null>(null);\n\n  // Create/destroy the body-level host element (client-only; guarded for SSR).\n  useEffect(() => {\n    if (typeof document === 'undefined') return;\n    const el = document.createElement('div');\n    el.setAttribute('data-mordn-chat-portal', '');\n    document.body.appendChild(el);\n    setContainer(el);\n    return () => {\n      el.remove();\n    };\n  }, []);\n\n  // Keep the theme class + custom-property overrides in sync with the widget.\n  useEffect(() => {\n    if (!container) return;\n    container.className = `chat-widget-container${themeClass ? ` ${themeClass}` : ''}`;\n    // Reset then re-apply so removed overrides don't linger.\n    container.removeAttribute('style');\n    if (style) {\n      for (const [key, value] of Object.entries(style)) {\n        if (value != null) container.style.setProperty(key, String(value));\n      }\n    }\n  }, [container, themeClass, style]);\n\n  return (\n    <ChatPortalContainerContext.Provider value={container}>\n      {children}\n    </ChatPortalContainerContext.Provider>\n  );\n}\n","import * as React from \"react\"\n\nimport { cn } from \"../utils/cn\"\n\nconst Textarea = React.forwardRef<\n  HTMLTextAreaElement,\n  React.ComponentProps<\"textarea\">\n>(({ className, ...props }, ref) => {\n  return (\n    <textarea\n      ref={ref}\n      data-slot=\"textarea\"\n      className={cn(\n        \"border-input placeholder:text-muted-foreground focus-visible:border-ring aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-[14px] transition-colors outline-none disabled:cursor-not-allowed disabled:opacity-50\",\n        className\n      )}\n      {...props}\n    />\n  )\n})\nTextarea.displayName = \"Textarea\"\n\nexport { Textarea }\n","\"use client\"\n\nimport * as React from \"react\"\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\"\n\nimport { cn } from \"../utils/cn\"\nimport { useChatPortalContainer } from \"../contexts/chat-portal-context\"\n\nfunction TooltipProvider({\n  delayDuration = 0,\n  ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {\n  return (\n    <TooltipPrimitive.Provider\n      data-slot=\"tooltip-provider\"\n      delayDuration={delayDuration}\n      {...props}\n    />\n  )\n}\n\nfunction Tooltip({\n  ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Root>) {\n  return (\n    <TooltipProvider>\n      <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />\n    </TooltipProvider>\n  )\n}\n\nfunction TooltipTrigger({\n  ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {\n  return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />\n}\n\nfunction TooltipContent({\n  className,\n  sideOffset = 0,\n  children,\n  ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Content>) {\n  const container = useChatPortalContainer()\n  return (\n    <TooltipPrimitive.Portal container={container ?? undefined}>\n      <TooltipPrimitive.Content\n        data-slot=\"tooltip-content\"\n        sideOffset={sideOffset}\n        className={cn(\n          \"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance\",\n          className\n        )}\n        {...props}\n      >\n        {children}\n        <TooltipPrimitive.Arrow className=\"bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]\" />\n      </TooltipPrimitive.Content>\n    </TooltipPrimitive.Portal>\n  )\n}\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }\n","\"use client\";\n\nimport { Button } from \"../ui/button\";\nimport { describeFile } from \"./file-icons/describe-file\";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from \"../ui/dropdown-menu\";\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from \"../ui/select\";\nimport { Textarea } from \"../ui/textarea\";\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from \"../ui/tooltip\";\nimport { cn } from \"../utils/cn\";\nimport type { ChatStatus, FileUIPart } from \"ai\";\nimport {\n  FileIcon,\n  ArrowUpIcon,\n  ImageIcon,\n  Loader2Icon,\n  PaperclipIcon,\n  PlusIcon,\n  SquareIcon,\n  XIcon,\n} from \"lucide-react\";\nimport { nanoid } from \"nanoid\";\nimport React, {\n  type ChangeEventHandler,\n  Children,\n  ClipboardEventHandler,\n  type ComponentProps,\n  createContext,\n  type FormEvent,\n  type FormEventHandler,\n  Fragment,\n  type HTMLAttributes,\n  type KeyboardEventHandler,\n  type RefObject,\n  useCallback,\n  useContext,\n  useEffect,\n  useLayoutEffect,\n  useMemo,\n  useRef,\n  useState,\n} from \"react\";\n\ntype AttachmentsContext = {\n  files: (FileUIPart & { id: string })[];\n  add: (files: File[] | FileList) => void;\n  remove: (id: string) => void;\n  clear: () => void;\n  openFileDialog: () => void;\n  fileInputRef: RefObject<HTMLInputElement | null>;\n};\n\nconst AttachmentsContext = createContext<AttachmentsContext | null>(null);\n\nexport const usePromptInputAttachments = () => {\n  const context = useContext(AttachmentsContext);\n\n  if (!context) {\n    throw new Error(\n      \"usePromptInputAttachments must be used within a PromptInput\"\n    );\n  }\n\n  return context;\n};\n\nexport type PromptInputAttachmentProps = HTMLAttributes<HTMLDivElement> & {\n  data: FileUIPart & { id: string };\n  className?: string;\n};\n\nexport function PromptInputAttachment({\n  data,\n  className,\n  ...props\n}: PromptInputAttachmentProps) {\n  const attachments = usePromptInputAttachments();\n  const isImage = data.mediaType?.startsWith(\"image/\") && !!data.url;\n\n  return (\n    <div\n      className={cn(\n        \"group relative rounded-[11px] border border-[hsl(var(--chat-border-soft))] bg-[hsl(var(--chat-surface))]\",\n        // Images keep the square thumbnail. Other files use a compact chip\n        // showing a token-driven type tile + filename.\n        isImage ? \"h-14 w-14\" : \"h-12 max-w-[240px]\",\n        className,\n      )}\n      key={data.id}\n      {...props}\n    >\n      {isImage ? (\n        <img\n          alt={data.filename || \"attachment\"}\n          className=\"size-full rounded-lg object-cover\"\n          height={56}\n          src={data.url}\n          width={56}\n        />\n      ) : (\n        <NonImageChip data={data} />\n      )}\n      <Button\n        aria-label=\"Remove attachment\"\n        className=\"-right-1 -top-1 absolute size-5 rounded-full p-0 opacity-70 transition-opacity hover:opacity-100 focus-visible:opacity-100 [&_svg]:size-2.5\"\n        onClick={() => attachments.remove(data.id)}\n        size=\"icon\"\n        type=\"button\"\n        variant=\"outline\"\n      >\n        <XIcon className=\"h-2 w-2 shrink-0\" />\n      </Button>\n    </div>\n  );\n}\n\nfunction NonImageChip({ data }: { data: FileUIPart & { id: string } }) {\n  const { Icon, label } = describeFile(data);\n  return (\n    <div className=\"flex size-full items-center gap-2.5 px-2.5\">\n      <span className=\"flex size-[26px] flex-shrink-0 items-center justify-center rounded-[7px] bg-[hsl(var(--chat-primary-tint))] text-[hsl(var(--chat-primary))]\">\n        <Icon className=\"size-4\" />\n      </span>\n      <div className=\"min-w-0 flex flex-col leading-tight\">\n        <span className=\"truncate text-[12.5px] font-medium text-[hsl(var(--chat-text))]\">\n          {data.filename || \"attachment\"}\n        </span>\n        <span className=\"mt-0.5 text-[11px] text-[hsl(var(--chat-text-faint))]\">\n          {label}\n        </span>\n      </div>\n    </div>\n  );\n}\n\n// describeFile (shared with message attachments) now lives in\n// ./file-icons/describe-file — brand icons + a short uppercase label.\n\nexport type PromptInputAttachmentsProps = Omit<\n  HTMLAttributes<HTMLDivElement>,\n  \"children\"\n> & {\n  children: (attachment: FileUIPart & { id: string }) => React.ReactNode;\n};\n\nexport function PromptInputAttachments({\n  className,\n  children,\n  ...props\n}: PromptInputAttachmentsProps) {\n  const attachments = usePromptInputAttachments();\n  const [height, setHeight] = useState(0);\n  const contentRef = useRef<HTMLDivElement>(null);\n\n  useLayoutEffect(() => {\n    const el = contentRef.current;\n    if (!el) {\n      return;\n    }\n    const ro = new ResizeObserver(() => {\n      setHeight(el.getBoundingClientRect().height);\n    });\n    ro.observe(el);\n    setHeight(el.getBoundingClientRect().height);\n    return () => ro.disconnect();\n  }, []);\n\n  return (\n    <div\n      aria-live=\"polite\"\n      className={cn(\n        \"overflow-hidden transition-[height] duration-200 ease-out\",\n        className\n      )}\n      style={{ height: attachments.files.length ? height : 0 }}\n      {...props}\n    >\n      <div className=\"flex flex-wrap gap-2 p-3 pt-3\" ref={contentRef}>\n        {attachments.files.map((file) => (\n          <Fragment key={file.id}>{children(file)}</Fragment>\n        ))}\n      </div>\n    </div>\n  );\n}\n\nexport type PromptInputActionAddAttachmentsProps = ComponentProps<\n  typeof DropdownMenuItem\n> & {\n  label?: string;\n};\n\nexport const PromptInputActionAddAttachments = ({\n  label = \"Add photos or files\",\n  ...props\n}: PromptInputActionAddAttachmentsProps) => {\n  const attachments = usePromptInputAttachments();\n\n  return (\n    <DropdownMenuItem\n      {...props}\n      onSelect={(e) => {\n        e.preventDefault();\n        attachments.openFileDialog();\n      }}\n    >\n      <ImageIcon className=\"mr-2 size-4\" /> {label}\n    </DropdownMenuItem>\n  );\n};\n\nexport type PromptInputMessage = {\n  text?: string;\n  files?: FileUIPart[];\n};\n\nexport type PromptInputProps = Omit<\n  HTMLAttributes<HTMLFormElement>,\n  \"onSubmit\" | \"onError\"\n> & {\n  accept?: string; // e.g., \"image/*\" or leave undefined for any\n  multiple?: boolean;\n  // When true, accepts drops anywhere on document. Default false (opt-in).\n  globalDrop?: boolean;\n  // Render a hidden input with given name and keep it in sync for native form posts. Default false.\n  syncHiddenInput?: boolean;\n  // Minimal constraints\n  maxFiles?: number;\n  maxFileSize?: number; // bytes\n  onError?: (err: {\n    code: \"max_files\" | \"max_file_size\" | \"accept\";\n    message: string;\n  }) => void;\n  onSubmit: (\n    message: PromptInputMessage,\n    event: FormEvent<HTMLFormElement>\n    // Returning `false` (or resolving to `false`) signals the submission was\n    // rejected — e.g. a turn is already streaming — so the composer keeps the\n    // typed text and attachments instead of clearing them.\n  ) => void | boolean | Promise<void | boolean>;\n};\n\nexport const PromptInput = ({\n  className,\n  accept,\n  multiple,\n  globalDrop,\n  syncHiddenInput,\n  maxFiles,\n  maxFileSize,\n  onError,\n  onSubmit,\n  ...props\n}: PromptInputProps) => {\n  const [items, setItems] = useState<(FileUIPart & { id: string })[]>([]);\n  const inputRef = useRef<HTMLInputElement | null>(null);\n  const anchorRef = useRef<HTMLSpanElement>(null);\n  const formRef = useRef<HTMLFormElement | null>(null);\n\n  // Mirror of `items` for the unmount-only cleanup below, so that effect can\n  // stay `[]`-deps (run once) while still seeing the latest attachment list\n  // when the component actually unmounts.\n  const itemsRef = useRef(items);\n  itemsRef.current = items;\n\n  // `remove` and `clear` revoke the blob: URLs they create, but neither one\n  // fires if the widget itself unmounts (e.g. the host tears down the chat\n  // panel) while attachments are still staged — those object URLs would\n  // otherwise leak for the life of the document. Revoke whatever's left on\n  // unmount, guarded to blob: URLs only (server-hosted/data: URLs aren't ours\n  // to revoke).\n  useEffect(() => {\n    return () => {\n      for (const file of itemsRef.current) {\n        if (file.url?.startsWith(\"blob:\")) {\n          try {\n            URL.revokeObjectURL(file.url);\n          } catch {\n            // Already revoked / invalid — nothing to do.\n          }\n        }\n      }\n    };\n  }, []);\n\n  // Find nearest form to scope drag & drop\n  useEffect(() => {\n    const root = anchorRef.current?.closest(\"form\");\n    if (root instanceof HTMLFormElement) {\n      formRef.current = root;\n    }\n  }, []);\n\n  const openFileDialog = useCallback(() => {\n    inputRef.current?.click();\n  }, []);\n\n  const matchesAccept = useCallback(\n    (f: File) => {\n      if (!accept || accept.trim() === \"\") {\n        return true;\n      }\n      // Proper HTML `accept` parsing: comma-separated tokens, each is\n      // one of:\n      //   - \"*/*\" — match anything\n      //   - \"<type>/*\" — match by MIME prefix (image/*, audio/*, …)\n      //   - \"<type>/<subtype>\" — exact MIME (application/pdf)\n      //   - \".ext\" — extension match against the filename\n      // A file matches if ANY token matches. Previous version matched\n      // only image/* when image/* was in the list, dropping every\n      // non-image even if PDF/xlsx/etc. were explicitly listed.\n      const tokens = accept\n        .split(\",\")\n        .map((t) => t.trim().toLowerCase())\n        .filter(Boolean);\n      const fileType = (f.type || \"\").toLowerCase();\n      const fileName = f.name.toLowerCase();\n      return tokens.some((token) => {\n        if (token === \"*/*\") return true;\n        if (token.startsWith(\".\")) return fileName.endsWith(token);\n        if (token.endsWith(\"/*\")) {\n          const prefix = token.slice(0, -1); // \"image/\" from \"image/*\"\n          return fileType.startsWith(prefix);\n        }\n        return fileType === token;\n      });\n    },\n    [accept]\n  );\n\n  const add = useCallback(\n    (files: File[] | FileList) => {\n      const incoming = Array.from(files);\n      const accepted = incoming.filter((f) => matchesAccept(f));\n      if (accepted.length === 0) {\n        onError?.({\n          code: \"accept\",\n          message: \"No files match the accepted types.\",\n        });\n        return;\n      }\n      const withinSize = (f: File) =>\n        maxFileSize ? f.size <= maxFileSize : true;\n      const sized = accepted.filter(withinSize);\n      if (sized.length === 0 && accepted.length > 0) {\n        onError?.({\n          code: \"max_file_size\",\n          message: \"All files exceed the maximum size.\",\n        });\n        return;\n      }\n      setItems((prev) => {\n        const capacity =\n          typeof maxFiles === \"number\"\n            ? Math.max(0, maxFiles - prev.length)\n            : undefined;\n        const capped =\n          typeof capacity === \"number\" ? sized.slice(0, capacity) : sized;\n        if (typeof capacity === \"number\" && sized.length > capacity) {\n          onError?.({\n            code: \"max_files\",\n            message: \"Too many files. Some were not added.\",\n          });\n        }\n        const next: (FileUIPart & { id: string })[] = [];\n        for (const file of capped) {\n          next.push({\n            id: nanoid(),\n            type: \"file\",\n            url: URL.createObjectURL(file),\n            mediaType: file.type,\n            filename: file.name,\n          });\n        }\n        return prev.concat(next);\n      });\n    },\n    [matchesAccept, maxFiles, maxFileSize, onError]\n  );\n\n  const remove = useCallback((id: string) => {\n    setItems((prev) => {\n      const found = prev.find((file) => file.id === id);\n      if (found?.url) {\n        URL.revokeObjectURL(found.url);\n      }\n      return prev.filter((file) => file.id !== id);\n    });\n  }, []);\n\n  const clear = useCallback(() => {\n    setItems((prev) => {\n      for (const file of prev) {\n        if (file.url) {\n          URL.revokeObjectURL(file.url);\n        }\n      }\n      return [];\n    });\n  }, []);\n\n  // Note: File input cannot be programmatically set for security reasons\n  // The syncHiddenInput prop is no longer functional\n  useEffect(() => {\n    if (syncHiddenInput && inputRef.current) {\n      // Clear the input when items are cleared\n      if (items.length === 0) {\n        inputRef.current.value = \"\";\n      }\n    }\n  }, [items, syncHiddenInput]);\n\n  // Attach drop handlers on nearest form and document (opt-in)\n  useEffect(() => {\n    const form = formRef.current;\n    if (!form) {\n      return;\n    }\n    // When globalDrop is enabled the document-level handler below already\n    // catches drops anywhere (including over the form). Running this form-level\n    // handler too would call add() twice for a single drop — bubbling fires the\n    // form listener and then the document listener — and attach every file\n    // twice. Let the document handler own drops in that mode.\n    if (globalDrop) {\n      return;\n    }\n    const onDragOver = (e: DragEvent) => {\n      if (e.dataTransfer?.types?.includes(\"Files\")) {\n        e.preventDefault();\n      }\n    };\n    const onDrop = (e: DragEvent) => {\n      if (e.dataTransfer?.types?.includes(\"Files\")) {\n        e.preventDefault();\n      }\n      if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {\n        add(e.dataTransfer.files);\n      }\n    };\n    form.addEventListener(\"dragover\", onDragOver);\n    form.addEventListener(\"drop\", onDrop);\n    return () => {\n      form.removeEventListener(\"dragover\", onDragOver);\n      form.removeEventListener(\"drop\", onDrop);\n    };\n  }, [add, globalDrop]);\n\n  useEffect(() => {\n    if (!globalDrop) {\n      return;\n    }\n    const onDragOver = (e: DragEvent) => {\n      if (e.dataTransfer?.types?.includes(\"Files\")) {\n        e.preventDefault();\n      }\n    };\n    const onDrop = (e: DragEvent) => {\n      if (e.dataTransfer?.types?.includes(\"Files\")) {\n        e.preventDefault();\n      }\n      if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {\n        add(e.dataTransfer.files);\n      }\n    };\n    document.addEventListener(\"dragover\", onDragOver);\n    document.addEventListener(\"drop\", onDrop);\n    return () => {\n      document.removeEventListener(\"dragover\", onDragOver);\n      document.removeEventListener(\"drop\", onDrop);\n    };\n  }, [add, globalDrop]);\n\n  const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {\n    if (event.currentTarget.files) {\n      add(event.currentTarget.files);\n    }\n    // Reset the input value so picking the same file again still fires a\n    // change event. Without this, selecting file A, removing it, then trying\n    // to add A again is silently dropped (the value hasn't changed).\n    event.currentTarget.value = \"\";\n  };\n\n  const handleSubmit: FormEventHandler<HTMLFormElement> = async (event) => {\n    event.preventDefault();\n\n    // Capture text + files synchronously, before any await. Once we await the\n    // (possibly async) onSubmit, `event.currentTarget` is null and the\n    // controlled value may already have changed.\n    const form = event.currentTarget;\n    const messageEl = form.elements.namedItem(\n      \"message\"\n    ) as HTMLTextAreaElement | null;\n    const text = messageEl?.value ?? \"\";\n\n    const files: FileUIPart[] = items.map(({ ...item }) => ({\n      ...item,\n    }));\n\n    try {\n      // `onSubmit` is frequently async — e.g. it uploads the attachments to a\n      // server before sending. Await it so the attachments are only released\n      // once the send has actually succeeded. Clearing eagerly (the previous\n      // behaviour) revoked the blob: object URLs while the upload was still\n      // reading them, and dropped the user's attachments on a failed send so\n      // they had nothing to retry with. Use the `text` captured synchronously\n      // above — `event.currentTarget` is null after the await.\n      const accepted = await onSubmit({ text, files }, event);\n      // Only clear once the handler has ACCEPTED the submission. If it returns\n      // `false` (e.g. a turn is mid-stream), keep the files so the user doesn't\n      // silently lose them on a blocked Enter.\n      if (accepted !== false) {\n        // Success — safe to clear and revoke the now-unused object URLs.\n        clear();\n      }\n    } catch {\n      // Keep the attachments mounted so the user can retry after a failed send.\n    }\n  };\n\n  const ctx = useMemo<AttachmentsContext>(\n    () => ({\n      files: items.map((item) => ({ ...item, id: item.id })),\n      add,\n      remove,\n      clear,\n      openFileDialog,\n      fileInputRef: inputRef,\n    }),\n    [items, add, remove, clear, openFileDialog]\n  );\n\n  return (\n    <AttachmentsContext.Provider value={ctx}>\n      <span aria-hidden=\"true\" className=\"hidden\" ref={anchorRef} />\n      <input\n        accept={accept}\n        aria-label=\"Upload files\"\n        className=\"hidden\"\n        multiple={multiple}\n        onChange={handleChange}\n        ref={inputRef}\n        title=\"Upload files\"\n        type=\"file\"\n      />\n      <form\n        className={cn(\n          // The form border + horizontal divider colour both come from\n          // the styles.src.css `.chat-widget-container form ...` rules so\n          // there's a single token (--chat-border) controlling both.\n          // No utility classes for border colour here.\n          // The chat-prompt-box class applied by the caller owns the single\n          // composer fill; this base primitive contributes structure only.\n          \"w-full overflow-hidden rounded-xl bg-transparent transition-colors\",\n          \"[&:focus-within]:shadow-none [&:focus]:shadow-none shadow-none\",\n          className\n        )}\n        onSubmit={handleSubmit}\n        style={{ boxShadow: 'none' }}\n        {...props}\n      />\n    </AttachmentsContext.Provider>\n  );\n};\n\nexport type PromptInputBodyProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputBody = ({\n  className,\n  ...props\n}: PromptInputBodyProps) => (\n  <div className={cn(className, \"flex flex-col\")} {...props} />\n);\n\nexport type PromptInputTextareaProps = ComponentProps<typeof Textarea>;\n\n// Resting height (empty, one line ≈ leading-7) and max height before scrolling.\nconst TEXTAREA_MIN_HEIGHT = 28;\nconst TEXTAREA_MAX_HEIGHT = 192;\n\nexport const PromptInputTextarea = React.forwardRef<\n  HTMLTextAreaElement,\n  PromptInputTextareaProps\n>(({\n  onChange,\n  onKeyDown: externalOnKeyDown,\n  className,\n  placeholder = \"Ask anything…\",\n  value,\n  ...props\n}, ref) => {\n  const attachments = usePromptInputAttachments();\n  // Track IME composition so Enter doesn't submit mid-composition. Some\n  // browsers only surface this through composition events rather than\n  // KeyboardEvent.isComposing, so we track both.\n  const [isComposing, setIsComposing] = useState(false);\n\n  // Auto-grow via JS scrollHeight measurement — works in every browser. (The\n  // CSS `field-sizing-content` property isn't supported in Safari/Firefox, so\n  // the textarea wouldn't grow there.) The textarea grows with content up to\n  // TEXTAREA_MAX_HEIGHT, then scrolls.\n  const innerRef = useRef<HTMLTextAreaElement | null>(null);\n  const setRefs = (node: HTMLTextAreaElement | null) => {\n    innerRef.current = node;\n    if (typeof ref === \"function\") ref(node);\n    else if (ref) (ref as React.MutableRefObject<HTMLTextAreaElement | null>).current = node;\n  };\n  const resize = () => {\n    const el = innerRef.current;\n    if (!el) return;\n    el.style.height = \"auto\";\n    const next = Math.min(el.scrollHeight, TEXTAREA_MAX_HEIGHT);\n    el.style.height = `${Math.max(next, TEXTAREA_MIN_HEIGHT)}px`;\n    el.style.overflowY = el.scrollHeight > TEXTAREA_MAX_HEIGHT ? \"auto\" : \"hidden\";\n  };\n  // Re-measure whenever the value changes (covers controlled value resets like\n  // clearing the input after send).\n  useLayoutEffect(resize, [value]);\n\n  const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = (e) => {\n    // Let external handlers (e.g. inputPlugins popover navigation) run\n    // first. If they call preventDefault we skip the built-in\n    // Enter-to-submit behaviour entirely.\n    externalOnKeyDown?.(e);\n    if (e.defaultPrevented) return;\n\n    if (e.key === \"Enter\") {\n      // Don't submit if IME composition is in progress\n      if (isComposing || e.nativeEvent.isComposing) {\n        return;\n      }\n\n      if (e.shiftKey) {\n        // Allow newline\n        return;\n      }\n\n      // Submit on Enter (without Shift)\n      e.preventDefault();\n      const form = e.currentTarget.form;\n      // Respect a disabled submit button — Enter shouldn't bypass the guard\n      // the button already enforces (e.g. empty input, or send disabled).\n      const submitButton = form?.querySelector(\n        'button[type=\"submit\"]'\n      ) as HTMLButtonElement | null;\n      if (submitButton?.disabled) {\n        return;\n      }\n      if (form) {\n        form.requestSubmit();\n      }\n      return;\n    }\n\n    // Backspace on an empty textarea removes the most recent attachment, so a\n    // mistaken attachment can be undone without reaching for the mouse.\n    if (\n      e.key === \"Backspace\" &&\n      e.currentTarget.value === \"\" &&\n      attachments.files.length > 0\n    ) {\n      e.preventDefault();\n      const lastAttachment = attachments.files.at(-1);\n      if (lastAttachment) {\n        attachments.remove(lastAttachment.id);\n      }\n    }\n  };\n\n  const handlePaste: ClipboardEventHandler<HTMLTextAreaElement> = (event) => {\n    const items = event.clipboardData?.items;\n    \n    if (!items) {\n      return;\n    }\n\n    const files: File[] = [];\n    \n    for (const item of items) {\n      if (item.kind === \"file\") {\n        const file = item.getAsFile();\n        if (file) {\n          files.push(file);\n        }\n      }\n    }\n\n    if (files.length > 0) {\n      event.preventDefault();\n      attachments.add(files);\n    }\n  };\n\n  return (\n    <Textarea\n      ref={setRefs}\n      rows={1}\n      value={value}\n      className={cn(\n        \"w-full resize-none rounded-none border-none px-3 py-2.5 shadow-none outline-none ring-0\",\n        \"focus-visible:ring-0 focus-visible:shadow-none focus:ring-0 focus:shadow-none\",\n        className\n      )}\n      style={{ minHeight: TEXTAREA_MIN_HEIGHT, maxHeight: TEXTAREA_MAX_HEIGHT, overflowY: \"hidden\" }}\n      name=\"message\"\n      onChange={(e) => {\n        onChange?.(e);\n        resize();\n      }}\n      onKeyDown={handleKeyDown}\n      onCompositionStart={() => setIsComposing(true)}\n      onCompositionEnd={() => setIsComposing(false)}\n      onPaste={handlePaste}\n      placeholder={placeholder}\n      {...props}\n    />\n  );\n});\nPromptInputTextarea.displayName = \"PromptInputTextarea\";\n\nexport type PromptInputToolbarProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputToolbar = ({\n  className,\n  ...props\n}: PromptInputToolbarProps) => (\n  <div\n    className={cn(\"flex items-center justify-between p-1\", className)}\n    {...props}\n  />\n);\n\nexport type PromptInputToolsProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputTools = ({\n  className,\n  ...props\n}: PromptInputToolsProps) => (\n  <div\n    className={cn(\n      \"flex items-center gap-1\",\n      \"[&_button:first-child]:rounded-bl-xl\",\n      className\n    )}\n    {...props}\n  />\n);\n\nexport type PromptInputButtonProps = ComponentProps<typeof Button> & {\n  // Optional hover tooltip. Also rendered as an sr-only label so icon-only\n  // buttons are announced. Matches the Action component's tooltip convention.\n  tooltip?: string;\n  label?: string;\n};\n\nexport const PromptInputButton = ({\n  variant = \"ghost\",\n  className,\n  size,\n  tooltip,\n  label,\n  children,\n  ...props\n}: PromptInputButtonProps) => {\n  const newSize =\n    (size ?? Children.count(children) > 1) ? \"default\" : \"icon\";\n\n  const button = (\n    <Button\n      className={cn(\n        \"shrink-0 gap-1.5 rounded-lg\",\n        variant === \"ghost\" && \"text-muted-foreground\",\n        newSize === \"default\" && \"px-3\",\n        className\n      )}\n      size={newSize}\n      type=\"button\"\n      variant={variant}\n      {...props}\n    >\n      {children}\n      {(label || tooltip) && (\n        <span className=\"sr-only\">{label || tooltip}</span>\n      )}\n    </Button>\n  );\n\n  if (!tooltip) {\n    return button;\n  }\n\n  return (\n    <TooltipProvider>\n      <Tooltip>\n        <TooltipTrigger asChild>{button}</TooltipTrigger>\n        <TooltipContent>\n          <p>{tooltip}</p>\n        </TooltipContent>\n      </Tooltip>\n    </TooltipProvider>\n  );\n};\n\nexport type PromptInputActionMenuProps = ComponentProps<typeof DropdownMenu>;\nexport const PromptInputActionMenu = (props: PromptInputActionMenuProps) => (\n  <DropdownMenu {...props} />\n);\n\nexport type PromptInputActionMenuTriggerProps = ComponentProps<\n  typeof Button\n> & {};\nexport const PromptInputActionMenuTrigger = ({\n  className,\n  children,\n  ...props\n}: PromptInputActionMenuTriggerProps) => (\n  <DropdownMenuTrigger asChild>\n    <PromptInputButton className={className} {...props}>\n      {children ?? <PlusIcon className=\"size-4\" />}\n    </PromptInputButton>\n  </DropdownMenuTrigger>\n);\n\nexport type PromptInputActionMenuContentProps = ComponentProps<\n  typeof DropdownMenuContent\n>;\nexport const PromptInputActionMenuContent = ({\n  className,\n  ...props\n}: PromptInputActionMenuContentProps) => (\n  <DropdownMenuContent align=\"start\" className={cn(className)} {...props} />\n);\n\nexport type PromptInputActionMenuItemProps = ComponentProps<\n  typeof DropdownMenuItem\n>;\nexport const PromptInputActionMenuItem = ({\n  className,\n  ...props\n}: PromptInputActionMenuItemProps) => (\n  <DropdownMenuItem className={cn(className)} {...props} />\n);\n\n// Note: Actions that perform side-effects (like opening a file dialog)\n// are provided in opt-in modules (e.g., prompt-input-attachments).\n\nexport type PromptInputSubmitProps = ComponentProps<typeof Button> & {\n  status?: ChatStatus;\n  /**\n   * Called when the user clicks the button while a response is streaming.\n   * When provided, the button STOPS being a form-submit during the\n   * streaming state and instead calls this handler. The submit action\n   * (Enter / click) still works normally in `ready` and `error` states.\n   *\n   * Usage: `onStop={chat.stop}` from useChat. Without this prop, the\n   * button stays a plain submit and the streaming icon is purely\n   * cosmetic — backwards compatible for consumers who don't wire stop.\n   */\n  onStop?: () => void;\n};\n\nexport const PromptInputSubmit = ({\n  className,\n  variant = \"default\",\n  size = \"icon\",\n  status,\n  onStop,\n  onClick,\n  children,\n  ...props\n}: PromptInputSubmitProps) => {\n  let Icon = <ArrowUpIcon className=\"size-4\" />;\n\n  if (status === \"submitted\") {\n    Icon = <Loader2Icon className=\"size-4 animate-spin\" />;\n  } else if (status === \"streaming\") {\n    Icon = <SquareIcon className=\"size-4\" />;\n  } else if (status === \"error\") {\n    Icon = <XIcon className=\"size-4\" />;\n  }\n\n  // While streaming, the click means \"stop\" — short-circuit form submit\n  // by setting type=\"button\" and calling onStop directly.\n  const isStopping = status === \"streaming\" && !!onStop;\n\n  // The button is icon-only, so it needs an accessible name in EVERY\n  // state — not just while stopping. Derive it from the same `status`\n  // that picks the icon so the label and glyph never disagree.\n  const label = isStopping\n    ? \"Stop generating\"\n    : status === \"submitted\"\n      ? \"Sending…\"\n      : status === \"streaming\"\n        ? \"Stop generating\"\n        : \"Send message\";\n\n  return (\n    <Button\n      className={cn(\"chat-prompt-submit gap-1.5 rounded-full\", className)}\n      size={size}\n      type={isStopping ? \"button\" : \"submit\"}\n      variant={variant}\n      onClick={(e) => {\n        if (isStopping) {\n          e.preventDefault();\n          onStop();\n        }\n        onClick?.(e);\n      }}\n      aria-label={label}\n      aria-busy={status === \"submitted\" || undefined}\n      {...props}\n    >\n      {children ?? Icon}\n    </Button>\n  );\n};\n\nexport type PromptInputModelSelectProps = ComponentProps<typeof Select>;\n\nexport const PromptInputModelSelect = (props: PromptInputModelSelectProps) => (\n  <Select {...props} />\n);\n\nexport type PromptInputModelSelectTriggerProps = ComponentProps<\n  typeof SelectTrigger\n>;\n\nexport const PromptInputModelSelectTrigger = ({\n  className,\n  ...props\n}: PromptInputModelSelectTriggerProps) => (\n  <SelectTrigger\n    className={cn(\n      \"border-none bg-transparent font-medium text-muted-foreground shadow-none transition-colors\",\n      'hover:bg-accent hover:text-foreground [&[aria-expanded=\"true\"]]:bg-accent [&[aria-expanded=\"true\"]]:text-foreground',\n      className\n    )}\n    {...props}\n  />\n);\n\nexport type PromptInputModelSelectContentProps = ComponentProps<\n  typeof SelectContent\n>;\n\nexport const PromptInputModelSelectContent = ({\n  className,\n  ...props\n}: PromptInputModelSelectContentProps) => (\n  <SelectContent className={cn(className)} {...props} />\n);\n\nexport type PromptInputModelSelectItemProps = ComponentProps<typeof SelectItem>;\n\nexport const PromptInputModelSelectItem = ({\n  className,\n  ...props\n}: PromptInputModelSelectItemProps) => (\n  <SelectItem className={cn(className)} {...props} />\n);\n\nexport type PromptInputModelSelectValueProps = ComponentProps<\n  typeof SelectValue\n>;\n\nexport const PromptInputModelSelectValue = ({\n  className,\n  ...props\n}: PromptInputModelSelectValueProps) => (\n  <SelectValue className={cn(className)} {...props} />\n);\n","\"use client\";\n\n/**\n * Trigger-driven autocomplete for the chat input. Generic: knows nothing\n * about portfolios, stocks, slash commands, etc. The host app passes an\n * array of InputPlugin definitions to ChatWidget; this component wires\n * them up to the textarea.\n *\n * Behaviour:\n *   - User types a trigger char (e.g. '@'). We capture the offset and\n *     start tracking the query.\n *   - As the user keeps typing, we extract the substring from the\n *     trigger to the cursor and (debounced) call `plugin.fetch(query)`.\n *   - Results render INLINE in a panel above the input — same layout\n *     spot as the StarterMessages suggestions, so we don't fight the\n *     panel's overflow boundaries with an absolute popover.\n *   - ArrowUp/Down navigate, Enter selects, Escape closes.\n *   - On select, we replace the trigger+query span with the plugin's\n *     `onSelect(item)` text.\n *\n * Edge cases handled:\n *   - Trigger only fires when preceded by whitespace or beginning of\n *     input (so an email address \"foo@bar\" doesn't open the popover).\n *   - Whitespace inside the query closes the popover.\n *   - Backspacing past the trigger char closes the popover.\n *   - Race-condition on activation: keydown sets active synchronously\n *     before the textarea's onChange fires, so on the first render\n *     `value` is still pre-keystroke. We skip the trigger-still-present\n *     check until value is long enough to include the trigger.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport type { InputPlugin, InputPluginItem } from \"../types\";\n\ninterface ActiveSession {\n  plugin: InputPlugin;\n  /** Index of the trigger character within the textarea value. */\n  triggerIndex: number;\n}\n\ninterface UseInputPluginsOptions {\n  textareaRef: React.RefObject<HTMLTextAreaElement | null>;\n  value: string;\n  setValue: (next: string) => void;\n  plugins?: InputPlugin[];\n}\n\nconst FETCH_DEBOUNCE_MS = 120;\n\nexport function useInputPlugins({ textareaRef, value, setValue, plugins }: UseInputPluginsOptions) {\n  const [active, setActive] = useState<ActiveSession | null>(null);\n  const [items, setItems] = useState<InputPluginItem[]>([]);\n  const [highlight, setHighlight] = useState(0);\n  const [loading, setLoading] = useState(false);\n  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n  const requestIdRef = useRef(0);\n  // Latches to true the first time we observe `value[triggerIndex]` ===\n  // trigger char. Until that flips, we're in the activation race window\n  // where `value` may still be pre-keystroke; we don't validate. After\n  // it flips, any deviation closes the session — including\n  // `value.length === triggerIndex` from backspacing to empty, which\n  // would otherwise look like the activation race.\n  const sessionValidatedRef = useRef(false);\n\n  const pluginsByTrigger = useMemo(() => {\n    const map = new Map<string, InputPlugin>();\n    for (const p of plugins ?? []) {\n      if (p.trigger.length === 1) map.set(p.trigger, p);\n    }\n    return map;\n  }, [plugins]);\n\n  const query = useMemo(() => {\n    if (!active) return \"\";\n    const ta = textareaRef.current;\n    if (!ta) return \"\";\n    const cursor = ta.selectionEnd ?? value.length;\n    if (cursor <= active.triggerIndex) return \"\";\n    return value.slice(active.triggerIndex + 1, cursor);\n  }, [active, value, textareaRef]);\n\n  useEffect(() => {\n    if (!active) {\n      sessionValidatedRef.current = false;\n      return;\n    }\n    // Latch validated as soon as we see the trigger char in its slot.\n    if (value[active.triggerIndex] === active.plugin.trigger) {\n      sessionValidatedRef.current = true;\n    }\n    // Pre-validation: in the activation race window, just wait.\n    if (!sessionValidatedRef.current) return;\n    // Post-validation: any deviation from `value[triggerIndex] === trigger`\n    // means the user backspaced over the trigger or cleared the input.\n    if (value[active.triggerIndex] !== active.plugin.trigger) {\n      setActive(null);\n      return;\n    }\n    if (/\\s/.test(query)) {\n      setActive(null);\n    }\n  }, [active, value, query]);\n\n  // Fetch — sync if the plugin returns an array directly (e.g. a\n  // host-side prefetched cache filter), debounced+loading if it\n  // returns a Promise.\n  useEffect(() => {\n    if (!active) {\n      setItems([]);\n      setLoading(false);\n      return;\n    }\n    if (debounceRef.current) clearTimeout(debounceRef.current);\n    const reqId = ++requestIdRef.current;\n    const result = active.plugin.fetch(query);\n    if (Array.isArray(result)) {\n      // Sync cache hit — no loading flash, no debounce.\n      setItems(result);\n      setHighlight(0);\n      setLoading(false);\n      return;\n    }\n    // Async path: show loading, debounce keystrokes.\n    setLoading(true);\n    debounceRef.current = setTimeout(async () => {\n      try {\n        const items = await result;\n        if (reqId !== requestIdRef.current) return;\n        setItems(items);\n        setHighlight(0);\n      } catch (err) {\n        console.error(\"[input-plugin] fetch failed:\", err);\n        if (reqId !== requestIdRef.current) return;\n        setItems([]);\n      } finally {\n        if (reqId === requestIdRef.current) setLoading(false);\n      }\n    }, FETCH_DEBOUNCE_MS);\n    return () => {\n      if (debounceRef.current) clearTimeout(debounceRef.current);\n    };\n  }, [active, query]);\n\n  const close = useCallback(() => {\n    setActive(null);\n    setItems([]);\n    setHighlight(0);\n  }, []);\n\n  const selectItem = useCallback(\n    (item: InputPluginItem) => {\n      if (!active) return;\n      const ta = textareaRef.current;\n      const cursor = ta?.selectionEnd ?? value.length;\n      const replacement = active.plugin.onSelect(item);\n      const before = value.slice(0, active.triggerIndex);\n      const after = value.slice(cursor);\n      const next = `${before}${replacement}${after}`;\n      setValue(next);\n      const newCursor = before.length + replacement.length;\n      setTimeout(() => {\n        const t = textareaRef.current;\n        if (!t) return;\n        t.focus();\n        try {\n          t.setSelectionRange(newCursor, newCursor);\n        } catch {\n          // Some browsers throw on setSelectionRange in certain states.\n        }\n      }, 0);\n      close();\n    },\n    [active, value, setValue, close, textareaRef],\n  );\n\n  const onKeyDown = useCallback(\n    (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n      if (active) {\n        if (e.key === \"ArrowDown\") {\n          e.preventDefault();\n          setHighlight((h) => (items.length === 0 ? 0 : (h + 1) % items.length));\n          return;\n        }\n        if (e.key === \"ArrowUp\") {\n          e.preventDefault();\n          setHighlight((h) => (items.length === 0 ? 0 : (h - 1 + items.length) % items.length));\n          return;\n        }\n        if (e.key === \"Enter\") {\n          if (items.length > 0) {\n            e.preventDefault();\n            selectItem(items[highlight]);\n          }\n          return;\n        }\n        if (e.key === \"Escape\") {\n          e.preventDefault();\n          close();\n          return;\n        }\n      }\n      if (e.key.length === 1 && pluginsByTrigger.has(e.key) && !e.metaKey && !e.ctrlKey && !e.altKey) {\n        const ta = e.currentTarget;\n        const cursor = ta.selectionStart ?? value.length;\n        const prevChar = cursor > 0 ? value[cursor - 1] : \"\";\n        if (cursor === 0 || /\\s/.test(prevChar)) {\n          const plugin = pluginsByTrigger.get(e.key)!;\n          setActive({ plugin, triggerIndex: cursor });\n        }\n      }\n    },\n    [active, items, highlight, selectItem, close, pluginsByTrigger, value],\n  );\n\n  // Inline panel rendered above the input. Same layout slot the\n  // StarterMessages component uses — keeps the visual language\n  // consistent and dodges every overflow / portal pitfall.\n  const panel = active ? (\n    <PluginPanel\n      plugin={active.plugin}\n      items={items}\n      loading={loading}\n      highlight={highlight}\n      onHover={setHighlight}\n      onSelect={selectItem}\n    />\n  ) : null;\n\n  return { onKeyDown, panel, isOpen: !!active };\n}\n\ninterface PluginPanelProps {\n  plugin: InputPlugin;\n  items: InputPluginItem[];\n  loading: boolean;\n  highlight: number;\n  onHover: (idx: number) => void;\n  onSelect: (item: InputPluginItem) => void;\n}\n\nfunction PluginPanel({ plugin, items, loading, highlight, onHover, onSelect }: PluginPanelProps) {\n  // Track the scrollable viewport + the rendered item buttons so\n  // ArrowUp/Down can scroll the highlighted row into view (Radix's\n  // ScrollArea doesn't auto-scroll the keyboard focus target).\n  const viewportRef = useRef<HTMLDivElement | null>(null);\n  const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n  useEffect(() => {\n    const btn = itemRefs.current[highlight];\n    const viewport = viewportRef.current;\n    if (!btn || !viewport) return;\n    // Use bounding-client-rect deltas — offsetTop chains depend on the\n    // nearest positioned ancestor, which Radix's ScrollArea wraps in\n    // extra DOM, so offsetTop math doesn't reliably give us the button\n    // position relative to the viewport.\n    const btnRect = btn.getBoundingClientRect();\n    const viewRect = viewport.getBoundingClientRect();\n    if (btnRect.top < viewRect.top) {\n      viewport.scrollTop -= viewRect.top - btnRect.top;\n    } else if (btnRect.bottom > viewRect.bottom) {\n      viewport.scrollTop += btnRect.bottom - viewRect.bottom;\n    }\n  }, [highlight]);\n\n  // A compact, inset command palette above the composer. It stays in flow (so\n  // it cannot escape the widget or fight portal boundaries) but reads as its\n  // own elevated surface with the same radius and token ramp as the composer.\n  return (\n    <div\n      role=\"listbox\"\n      className=\"mb-2 overflow-hidden rounded-[11px] border border-[hsl(var(--chat-border-soft))] bg-[hsl(var(--chat-background))] shadow-[0_6px_20px_rgba(0,0,0,0.07)]\"\n      onMouseDown={(e) => e.preventDefault()}\n    >\n      {plugin.heading && (\n        <div\n          className=\"px-3 py-1.5 text-[11px] font-semibold uppercase tracking-wide\"\n          style={{\n            color: \"hsl(var(--chat-text-subtle))\",\n            borderBottom: \"1px solid hsl(var(--chat-hairline))\",\n          }}\n        >\n          {plugin.heading}\n        </div>\n      )}\n\n      {loading && items.length === 0 && (\n        <div\n          className=\"px-3 py-2 text-[13px]\"\n          style={{ color: \"hsl(var(--chat-text)/0.5)\" }}\n        >\n          Loading…\n        </div>\n      )}\n      {!loading && items.length === 0 && (\n        <div\n          className=\"px-3 py-2 text-[13px]\"\n          style={{ color: \"hsl(var(--chat-text)/0.5)\" }}\n        >\n          {plugin.emptyText ?? \"No results\"}\n        </div>\n      )}\n      {items.length > 0 && (\n        <div\n          ref={viewportRef}\n          className=\"max-h-[200px] overflow-y-auto\"\n        >\n          <div className=\"py-1\">\n            {items.map((item, idx) => (\n              <div key={item.id}>\n                <button\n                  ref={(el) => {\n                    itemRefs.current[idx] = el;\n                  }}\n                  type=\"button\"\n                  role=\"option\"\n                  aria-selected={idx === highlight}\n                  onMouseEnter={() => onHover(idx)}\n                  onClick={() => onSelect(item)}\n                  className={cn(\n                    \"w-full text-left px-3 py-2\",\n                    \"flex items-center justify-between gap-3\",\n                    \"transition-colors duration-150 ease-out\",\n                    \"cursor-pointer\",\n                  )}\n                  style={{\n                    backgroundColor:\n                      idx === highlight ? \"hsl(var(--chat-hover-bg))\" : \"transparent\",\n                  }}\n                >\n                  <span className=\"truncate text-[12.5px] font-medium text-[hsl(var(--chat-text))]\">\n                    {item.label}\n                  </span>\n                  {item.sublabel && (\n                    <span className=\"flex-shrink-0 text-[11.5px] text-[hsl(var(--chat-text-faint))]\">\n                      {item.sublabel}\n                    </span>\n                  )}\n                </button>\n                {idx < items.length - 1 && (\n                  <div\n                    className=\"h-px mx-3\"\n                    style={{ backgroundColor: \"hsl(var(--chat-hairline))\" }}\n                  />\n                )}\n              </div>\n            ))}\n          </div>\n        </div>\n      )}\n    </div>\n  );\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport {\n  classifyDictationError,\n  composeDictation,\n  dictationNotice,\n  foldDictationResults,\n  getSpeechRecognition,\n  resolveDictationLanguage,\n  type SpeechRecognitionLike,\n} from '../utils/speech-recognition';\n\n/**\n * Composer dictation on the browser's built-in `SpeechRecognition`.\n *\n * Speak → words land in the textarea at the caret → the user edits and sends\n * like any typed message. This is dictation, not voice mode: nothing is ever\n * auto-sent, no audio is played back, and no audio passes through the host or\n * mordn — the recognizer is the browser's own (Chrome/Safari may hand audio to\n * Google/Apple speech services; that is the browser's contract, not ours).\n *\n * Shape mirrors `useInputPlugins`: same `textareaRef` / `value` / `setValue`\n * inputs, same \"set the value, then restore the caret on the next tick\" idiom\n * for insertion.\n *\n * State machine: idle → requesting (start() called, permission prompt may be\n * up) → listening → idle. `denied` is sticky for the mount: the browser will\n * keep refusing until the user changes site permissions, so the button shows\n * a blocked state instead of failing on every tap.\n */\n\nexport type DictationState = 'idle' | 'requesting' | 'listening' | 'denied';\n\nexport interface UseDictationOptions {\n  textareaRef: React.RefObject<HTMLTextAreaElement | null>;\n  value: string;\n  setValue: (next: string) => void;\n  /** `features.voiceInput` — false renders nothing and makes every action a no-op. */\n  enabled: boolean;\n  /** `features.voiceInputLanguage` — BCP-47; falls back to page, then browser language. */\n  lang?: string;\n}\n\nexport interface DictationApi {\n  /** False on the server and in browsers without the API; the button renders nothing. */\n  supported: boolean;\n  state: DictationState;\n  /** Inline notice for a transient failure (offline, no microphone). */\n  notice: string | null;\n  clearNotice: () => void;\n  start: () => void;\n  stop: () => void;\n  toggle: () => void;\n  /**\n   * Call from the textarea's onChange (typing, paste, cut). Any manual edit\n   * ends the session — merging live edits with a moving interim span produces\n   * caret jumps and duplicated words. What is on screen stays as the user\n   * left it; restarting is one tap.\n   */\n  onManualEdit: () => void;\n  /** Escape stops dictation. Skips events another handler already claimed. */\n  onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;\n}\n\nexport function useDictation({ textareaRef, value, setValue, enabled, lang }: UseDictationOptions): DictationApi {\n  // Feature-detect after mount so server and first client render agree\n  // (no hydration mismatch) and SSR never touches `window`.\n  const [supported, setSupported] = useState(false);\n  useEffect(() => {\n    setSupported(getSpeechRecognition() !== null);\n  }, []);\n\n  const [state, setState] = useState<DictationState>('idle');\n  const [notice, setNotice] = useState<string | null>(null);\n\n  const recognizerRef = useRef<SpeechRecognitionLike | null>(null);\n  // Text around the selection when the session started; dictation is\n  // inserted between them.\n  const snapshotRef = useRef<{ before: string; after: string }>({ before: '', after: '' });\n  const committedRef = useRef('');\n  // Set when the user edited manually mid-session: the recognizer's final\n  // `onend` must then leave the text alone rather than re-render a stale span.\n  const detachedRef = useRef(false);\n  const stateRef = useRef<DictationState>('idle');\n  stateRef.current = state;\n\n  const placeCaret = useCallback(\n    (caret: number) => {\n      setTimeout(() => {\n        const t = textareaRef.current;\n        if (!t) return;\n        try {\n          t.setSelectionRange(caret, caret);\n        } catch {\n          // Some browsers throw on setSelectionRange in certain states.\n        }\n      }, 0);\n    },\n    [textareaRef],\n  );\n\n  const render = useCallback(\n    (committed: string, interim: string) => {\n      if (detachedRef.current) return;\n      const { before, after } = snapshotRef.current;\n      const next = composeDictation(before, committed, interim, after);\n      setValue(next.value);\n      placeCaret(next.caret);\n    },\n    [setValue, placeCaret],\n  );\n\n  const stop = useCallback(() => {\n    const r = recognizerRef.current;\n    if (!r) return;\n    try {\n      r.stop(); // `onend` finalizes: drops the interim tail, resets state.\n    } catch {\n      /* already stopped */\n    }\n  }, []);\n\n  const start = useCallback(() => {\n    if (!enabled) return;\n    if (recognizerRef.current) return; // already requesting/listening\n    if (stateRef.current === 'denied') return;\n    const Ctor = getSpeechRecognition();\n    if (!Ctor) return;\n\n    const ta = textareaRef.current;\n    const selStart = ta?.selectionStart ?? value.length;\n    const selEnd = ta?.selectionEnd ?? value.length;\n    snapshotRef.current = { before: value.slice(0, selStart), after: value.slice(selEnd) };\n    committedRef.current = '';\n    detachedRef.current = false;\n    setNotice(null);\n\n    const recognizer = new Ctor();\n    recognizer.continuous = true;\n    recognizer.interimResults = true;\n    recognizer.maxAlternatives = 1;\n    const language = resolveDictationLanguage(lang);\n    if (language) recognizer.lang = language;\n\n    recognizer.onstart = () => setState('listening');\n    recognizer.onresult = (event) => {\n      const { committed, interim } = foldDictationResults(snapshotRef.current.before, event.results);\n      committedRef.current = committed;\n      render(committed, interim);\n    };\n    recognizer.onerror = (event) => {\n      const kind = classifyDictationError(event.error);\n      if (kind === 'denied') {\n        setState('denied');\n        return; // `onend` follows and cleans up; state stays denied.\n      }\n      const message = dictationNotice(kind);\n      if (message) setNotice(message);\n    };\n    recognizer.onend = () => {\n      recognizerRef.current = null;\n      // Commit what the browser confirmed; the unconfirmed interim tail goes.\n      render(committedRef.current, '');\n      setState((s) => (s === 'denied' ? 'denied' : 'idle'));\n    };\n\n    recognizerRef.current = recognizer;\n    setState('requesting');\n    try {\n      recognizer.start();\n    } catch {\n      // Chrome throws InvalidStateError if a session is already running.\n      recognizerRef.current = null;\n      setState('idle');\n    }\n  }, [enabled, textareaRef, value, lang, render]);\n\n  const toggle = useCallback(() => {\n    if (recognizerRef.current) stop();\n    else start();\n  }, [start, stop]);\n\n  const onManualEdit = useCallback(() => {\n    if (!recognizerRef.current) return;\n    detachedRef.current = true;\n    stop();\n  }, [stop]);\n\n  const onKeyDown = useCallback(\n    (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n      if (event.key !== 'Escape' || event.defaultPrevented) return;\n      if (!recognizerRef.current) return;\n      event.preventDefault();\n      stop();\n    },\n    [stop],\n  );\n\n  // Disabled while a session runs (config hot-swap), or unmount: abort hard.\n  useEffect(() => {\n    if (enabled) return;\n    recognizerRef.current?.abort();\n  }, [enabled]);\n  useEffect(\n    () => () => {\n      detachedRef.current = true; // never setValue on an unmounted composer\n      recognizerRef.current?.abort();\n      recognizerRef.current = null;\n    },\n    [],\n  );\n\n  const clearNotice = useCallback(() => setNotice(null), []);\n\n  return { supported, state, notice, clearNotice, start, stop, toggle, onManualEdit, onKeyDown };\n}\n","/**\n * Browser speech recognition primitives for composer dictation.\n *\n * Everything the dictation hook needs that is NOT React: feature detection,\n * a minimal ambient type shim (TypeScript's `lib.dom` does not ship\n * `SpeechRecognition` types), the error-code → state mapper, and the pure\n * text-joining helpers. Zero dependencies. Nothing here touches the network\n * or the server — the browser's recognizer produces text, and that text\n * enters the widget exactly like typed input.\n */\n\n// ── Ambient shim (only the members we use) ─────────────────────────────────\n\nexport interface SpeechRecognitionAlternativeLike {\n  transcript: string;\n  confidence: number;\n}\n\nexport interface SpeechRecognitionResultLike {\n  isFinal: boolean;\n  readonly length: number;\n  [index: number]: SpeechRecognitionAlternativeLike;\n}\n\nexport interface SpeechRecognitionResultListLike {\n  readonly length: number;\n  [index: number]: SpeechRecognitionResultLike;\n}\n\nexport interface SpeechRecognitionEventLike {\n  resultIndex: number;\n  results: SpeechRecognitionResultListLike;\n}\n\nexport interface SpeechRecognitionErrorEventLike {\n  /** W3C error code: 'not-allowed' | 'no-speech' | 'network' | 'audio-capture' | 'aborted' | … */\n  error: string;\n  message?: string;\n}\n\nexport interface SpeechRecognitionLike {\n  lang: string;\n  continuous: boolean;\n  interimResults: boolean;\n  maxAlternatives: number;\n  onstart: ((event: unknown) => void) | null;\n  onresult: ((event: SpeechRecognitionEventLike) => void) | null;\n  onerror: ((event: SpeechRecognitionErrorEventLike) => void) | null;\n  onend: ((event: unknown) => void) | null;\n  start(): void;\n  stop(): void;\n  abort(): void;\n}\n\nexport type SpeechRecognitionCtor = new () => SpeechRecognitionLike;\n\n/**\n * Returns the browser's recognizer constructor, or `null` when the API is\n * absent (SSR, Firefox with the pref off, older WebViews). Callers render\n * nothing in the `null` case — the unsupported browser must look exactly\n * like it did before dictation existed.\n */\nexport function getSpeechRecognition(): SpeechRecognitionCtor | null {\n  if (typeof window === 'undefined') return null;\n  const w = window as unknown as {\n    SpeechRecognition?: SpeechRecognitionCtor;\n    webkitSpeechRecognition?: SpeechRecognitionCtor;\n  };\n  return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;\n}\n\n// ── Errors ─────────────────────────────────────────────────────────────────\n\nexport type DictationErrorKind = 'denied' | 'no-speech' | 'network' | 'no-mic' | 'aborted' | 'unknown';\n\n/** Maps a W3C `SpeechRecognitionErrorEvent.error` code to what the UI does about it. */\nexport function classifyDictationError(code: string | undefined): DictationErrorKind {\n  switch (code) {\n    case 'not-allowed':\n    case 'service-not-allowed':\n      return 'denied';\n    case 'no-speech':\n      return 'no-speech';\n    case 'network':\n      return 'network';\n    case 'audio-capture':\n      return 'no-mic';\n    case 'aborted':\n      return 'aborted';\n    default:\n      return 'unknown';\n  }\n}\n\n/**\n * User-facing inline notice for a transient failure, or `null` when the\n * failure needs no message (a silence timeout, our own abort, or a permission\n * denial — which the button itself reports through its blocked state).\n */\nexport function dictationNotice(kind: DictationErrorKind): string | null {\n  switch (kind) {\n    case 'network':\n      return 'Dictation needs an internet connection.';\n    case 'no-mic':\n      return 'No microphone was found.';\n    case 'unknown':\n      return 'Dictation stopped unexpectedly. Try again.';\n    default:\n      return null;\n  }\n}\n\n// ── Text assembly ──────────────────────────────────────────────────────────\n\nconst SENTENCE_END = /[.!?]\\s*$/;\nconst LEADING_PUNCTUATION = /^[,.;:!?)\\]}%]/;\n\n/**\n * Formats a recognized segment so it reads naturally after `before`:\n * a single joining space when `before` doesn't already end in whitespace (and\n * the segment doesn't start with closing punctuation), and a capital letter\n * when the segment opens a sentence. Browsers return raw, mostly lowercase,\n * mostly unpunctuated text; this is the minimum that makes the result look\n * typed. Returns '' for an empty segment.\n */\nexport function joinDictation(before: string, segment: string): string {\n  const text = segment.trim();\n  if (!text) return '';\n  const startsSentence = before.trim() === '' || SENTENCE_END.test(before);\n  const cased = startsSentence ? text.charAt(0).toUpperCase() + text.slice(1) : text;\n  const needsSpace = before.length > 0 && !/\\s$/.test(before) && !LEADING_PUNCTUATION.test(cased);\n  return (needsSpace ? ' ' : '') + cased;\n}\n\nexport interface DictationComposition {\n  /** The full textarea value. */\n  value: string;\n  /** Caret position — the end of the dictated span. */\n  caret: number;\n}\n\n/**\n * Builds the textarea value while dictating: the text before the caret at\n * start, the committed (final) segments, the live interim tail, then the\n * text that was after the selection. Pure, so the hook's `onresult` handler\n * is a one-liner and the join rules are unit-testable.\n */\nexport function composeDictation(\n  before: string,\n  committed: string,\n  interim: string,\n  after: string,\n): DictationComposition {\n  const head = before + committed + joinDictation(before + committed, interim);\n  const caret = head.length;\n  // Keep a space between the dictated span and any trailing text.\n  const gap = after && head.length > before.length && !/^\\s/.test(after) && !/\\s$/.test(head) ? ' ' : '';\n  return { value: head + gap + after, caret };\n}\n\n/**\n * Folds a batch of recognizer results into `{ committed, interim }`. The\n * results list is cumulative for the session (`continuous: true`), so we\n * rebuild from index 0 each time — idempotent, and immune to the\n * `resultIndex` quirks across engines.\n */\nexport function foldDictationResults(\n  before: string,\n  results: SpeechRecognitionResultListLike,\n): { committed: string; interim: string } {\n  let committed = '';\n  const interim: string[] = [];\n  for (let i = 0; i < results.length; i++) {\n    const result = results[i];\n    const transcript = result?.[0]?.transcript ?? '';\n    if (!transcript) continue;\n    if (result.isFinal) committed += joinDictation(before + committed, transcript);\n    else interim.push(transcript.trim());\n  }\n  return { committed, interim: interim.filter(Boolean).join(' ') };\n}\n\n/**\n * Recognition language: an explicit BCP-47 override wins, then the page's\n * `<html lang>`, then the browser language. `undefined` lets the recognizer\n * pick its own default.\n */\nexport function resolveDictationLanguage(override?: string): string | undefined {\n  const explicit = override?.trim();\n  if (explicit) return explicit;\n  if (typeof document !== 'undefined') {\n    const pageLang = document.documentElement?.lang?.trim();\n    if (pageLang) return pageLang;\n  }\n  if (typeof navigator !== 'undefined' && navigator.language) return navigator.language;\n  return undefined;\n}\n","import { MicIcon, MicOffIcon } from 'lucide-react';\n\nimport type { DictationApi } from '../hooks/use-dictation';\nimport { cn } from '../utils/cn';\nimport { PromptInputButton } from './prompt-input';\n\n/**\n * Microphone toggle in the composer action row — same 32px ghost icon-button\n * recipe as `AttachButton`. Renders nothing when the browser has no speech\n * recognition, so an unsupported browser looks exactly like before.\n *\n * Module-scope on purpose (never define a component inside `ChatInterface`).\n */\nexport function DictationButton({ dictation }: { dictation: DictationApi }) {\n  if (!dictation.supported) return null;\n\n  const { state } = dictation;\n  const active = state === 'listening' || state === 'requesting';\n  const denied = state === 'denied';\n\n  const label = denied\n    ? 'Microphone access is blocked — allow it in your browser settings'\n    : active\n      ? 'Stop dictation'\n      : 'Start dictation';\n\n  return (\n    <>\n      <PromptInputButton\n        variant=\"ghost\"\n        size=\"icon\"\n        tooltip={label}\n        aria-label={label}\n        aria-pressed={active}\n        aria-disabled={denied || undefined}\n        data-dictation-state={state}\n        onClick={() => {\n          if (denied) return;\n          dictation.toggle();\n        }}\n        className={cn(\n          // Quiet icon button at rest (mirrors AttachButton).\n          'size-8 rounded-[7px] text-[hsl(var(--chat-text-faint))] hover:bg-[hsl(var(--chat-hover-bg))] hover:text-[hsl(var(--chat-text))]',\n          // Permission prompt up: mid-tone, no pulse yet.\n          state === 'requesting' && 'text-[hsl(var(--chat-text-muted))]',\n          // Listening: primary mic on the primary tint disc + pulsing ring (CSS).\n          state === 'listening' &&\n            'chat-dictation-active bg-[hsl(var(--chat-primary-tint))] text-[hsl(var(--chat-primary))] hover:bg-[hsl(var(--chat-primary-tint))] hover:text-[hsl(var(--chat-primary))]',\n          denied && 'cursor-not-allowed text-[hsl(var(--chat-text-subtle))] hover:bg-transparent hover:text-[hsl(var(--chat-text-subtle))]',\n        )}\n      >\n        {denied ? <MicOffIcon className=\"size-4\" /> : <MicIcon className=\"size-4\" />}\n      </PromptInputButton>\n      {/* Screen-reader status; the visual state lives on the button. */}\n      <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n        {state === 'requesting' ? 'Waiting for microphone permission' : state === 'listening' ? 'Listening' : ''}\n      </span>\n    </>\n  );\n}\n","/**\n * Tiny declarative field schema + reader used by the canonical AgentConfig\n * contract (`src/config.ts`).\n *\n * WHY THIS EXISTS (and why it isn't zod): the config contract is consumed by\n * three repos and, more importantly, by MANY DEPLOYED VERSIONS of this package\n * at once. A field that the dashboard publishes today is read tomorrow by a\n * customer's server that was installed six weeks ago. The one property the\n * validator must therefore have is *forward tolerance*: a document that carries\n * a field this build has never heard of must still load. A hand-rolled engine\n * lets us make that guarantee structural — every validator in the package is\n * derived from ONE descriptor, and the read mode (strict vs tolerant) is a\n * parameter, so \"strict here, tolerant there\" can never drift.\n *\n * Two modes, one descriptor:\n *\n *   • `strict`   — the WRITER contract. Unknown keys and invalid values are\n *                  errors. Used where a document is authored or accepted for\n *                  storage (publish, preview trust boundary). Strictness at the\n *                  writer is what keeps typos and junk out of the store.\n *   • `tolerant` — the READER contract. Unknown keys are DROPPED (recorded, not\n *                  fatal). An OPTIONAL known field whose value this build cannot\n *                  interpret (a new enum member, a changed shape) is DROPPED so\n *                  the schema default applies. Only a missing/invalid REQUIRED\n *                  field is fatal. Used by every runtime consumer: the customer's\n *                  handler, the hosted config fetcher, the browser bootstrap.\n *\n * The invariant this buys: within one `schemaVersion`, an OLDER reader can\n * always load a NEWER document (additive fields are ignored; new enum members\n * fall back to defaults). A change that would break that — removing a field,\n * changing a field's type or meaning, making an optional field required — is a\n * new `schemaVersion`. See docs/config-evolution.md.\n *\n * The reader always returns a NEW value containing only known, valid fields.\n * Callers never observe unknown keys, so downstream code cannot accidentally\n * depend on something the contract does not define.\n */\n\nexport type Primitive = string | number | boolean;\n\nexport type FieldSpec =\n  | { kind: 'boolean' }\n  | { kind: 'string'; nonEmpty?: boolean }\n  | { kind: 'number'; integer?: boolean; min?: number; max?: number }\n  | { kind: 'literal'; value: Primitive }\n  | { kind: 'enum'; values: readonly Primitive[] }\n  | { kind: 'object'; fields: FieldMap }\n  | { kind: 'array'; item: FieldSpec }\n  | { kind: 'union'; options: readonly FieldSpec[] };\n\nexport interface Field {\n  spec: FieldSpec;\n  /**\n   * A required field that is missing or invalid is fatal in BOTH modes. Keep\n   * this list tiny: every required field is a field an old reader cannot\n   * default, i.e. a field that can never be added to an existing object\n   * without a schema-version bump.\n   */\n  required?: boolean;\n  /**\n   * First package version whose canonical schema carried this field. Purely\n   * informational (docs, dashboards showing \"requires widget ≥ x\"), but\n   * mandatory so a field can never be added without recording when.\n   */\n  since: string;\n  /** One-line, human-readable meaning. Surfaces in the schema description. */\n  description: string;\n  /**\n   * Default applied by consumers when the field is absent or dropped. Only\n   * meaningful on leaf fields. Recorded in the schema description so the\n   * dashboard and docs can show it without a second source of truth.\n   */\n  default?: Primitive;\n}\n\nexport type FieldMap = Record<string, Field>;\n\nexport type ReadMode = 'strict' | 'tolerant';\n\nexport type ReadIssueCode = 'unknown_key' | 'invalid_value' | 'missing_required';\n\nexport interface ReadIssue {\n  /** Dotted path from the document root, e.g. `client.features.voiceInput`. */\n  path: string;\n  code: ReadIssueCode;\n  message: string;\n}\n\nexport type ReadResult<T> =\n  | {\n      ok: true;\n      value: T;\n      /**\n       * Fields the reader ignored. Empty in strict mode (anything here would\n       * have been an error). Non-empty in tolerant mode means \"this document\n       * was written by a newer schema than this build knows\" — worth logging\n       * once, never worth failing over.\n       */\n      dropped: ReadIssue[];\n    }\n  | { ok: false; issues: ReadIssue[] };\n\n// ── helpers ──────────────────────────────────────────────────────────────────\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n  typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst join = (path: string, key: string | number): string =>\n  path === '' ? String(key) : `${path}.${key}`;\n\n/** Human label for a spec — used in issue messages and the schema description. */\nexport function describeSpec(spec: FieldSpec): string {\n  switch (spec.kind) {\n    case 'boolean':\n      return 'boolean';\n    case 'string':\n      return spec.nonEmpty ? 'non-empty string' : 'string';\n    case 'number': {\n      const base = spec.integer ? 'integer' : 'number';\n      const lo = spec.min !== undefined ? ` ≥ ${spec.min}` : '';\n      const hi = spec.max !== undefined ? ` ≤ ${spec.max}` : '';\n      return `${base}${lo}${hi}`;\n    }\n    case 'literal':\n      return `literal ${JSON.stringify(spec.value)}`;\n    case 'enum':\n      return `one of ${spec.values.map((v) => JSON.stringify(v)).join(' | ')}`;\n    case 'object':\n      return 'object';\n    case 'array':\n      return `array of ${describeSpec(spec.item)}`;\n    case 'union':\n      return spec.options.map(describeSpec).join(' | ');\n  }\n}\n\n// ── reader ───────────────────────────────────────────────────────────────────\n\n/**\n * One issue describing a dropped optional field/item, at ITS path, with the\n * nested causes summarised relative to it (`textColor: required field is\n * missing`). Keeps `dropped` readable in logs: one line per thing that vanished.\n */\nfunction droppedIssue(path: string, causes: readonly ReadIssue[]): ReadIssue {\n  if (causes.length === 1 && causes[0].path === path) {\n    return { path, code: 'invalid_value', message: causes[0].message };\n  }\n  const detail = causes\n    .map((c) => `${c.path.startsWith(`${path}.`) ? c.path.slice(path.length + 1) : c.path}: ${c.message}`)\n    .join('; ');\n  return { path, code: 'invalid_value', message: `dropped (${detail})` };\n}\n\ninterface Ctx {\n  mode: ReadMode;\n  dropped: ReadIssue[];\n}\n\ntype Inner = { ok: true; value: unknown } | { ok: false; issues: ReadIssue[] };\n\nfunction readSpec(value: unknown, spec: FieldSpec, path: string, ctx: Ctx): Inner {\n  const invalid = (message: string): Inner => ({\n    ok: false,\n    issues: [{ path, code: 'invalid_value', message }],\n  });\n\n  switch (spec.kind) {\n    case 'boolean':\n      return typeof value === 'boolean' ? { ok: true, value } : invalid('expected a boolean');\n\n    case 'string':\n      if (typeof value !== 'string') return invalid('expected a string');\n      if (spec.nonEmpty && value.trim().length === 0) return invalid('expected a non-empty string');\n      return { ok: true, value };\n\n    case 'number': {\n      if (typeof value !== 'number' || !Number.isFinite(value)) return invalid('expected a finite number');\n      if (spec.integer && !Number.isSafeInteger(value)) return invalid('expected an integer');\n      if (spec.min !== undefined && value < spec.min) return invalid(`expected a value ≥ ${spec.min}`);\n      if (spec.max !== undefined && value > spec.max) return invalid(`expected a value ≤ ${spec.max}`);\n      return { ok: true, value };\n    }\n\n    case 'literal':\n      return value === spec.value\n        ? { ok: true, value }\n        : invalid(`expected ${JSON.stringify(spec.value)}`);\n\n    case 'enum':\n      return (spec.values as readonly unknown[]).includes(value)\n        ? { ok: true, value }\n        : invalid(`expected ${describeSpec(spec)}`);\n\n    case 'object':\n      return readFields(value, spec.fields, path, ctx);\n\n    case 'array': {\n      if (!Array.isArray(value)) return invalid('expected an array');\n      const out: unknown[] = [];\n      const issues: ReadIssue[] = [];\n      value.forEach((item, index) => {\n        const read = readSpec(item, spec.item, join(path, index), ctx);\n        if (read.ok) {\n          out.push(read.value);\n        } else if (ctx.mode === 'tolerant') {\n          // A single unreadable item must not take the whole list down: an\n          // older widget still renders the starter prompts it understands.\n          ctx.dropped.push(droppedIssue(join(path, index), read.issues));\n        } else {\n          issues.push(...read.issues);\n        }\n      });\n      return issues.length > 0 ? { ok: false, issues } : { ok: true, value: out };\n    }\n\n    case 'union': {\n      // First option that reads cleanly wins. In tolerant mode an object option\n      // may itself drop unknown keys — that is still a clean read.\n      for (const option of spec.options) {\n        const before = ctx.dropped.length;\n        const read = readSpec(value, option, path, ctx);\n        if (read.ok) return read;\n        // Roll back drops recorded by an option that ultimately failed.\n        ctx.dropped.length = before;\n      }\n      return invalid(`expected ${describeSpec(spec)}`);\n    }\n  }\n}\n\nfunction readFields(value: unknown, fields: FieldMap, path: string, ctx: Ctx): Inner {\n  if (!isRecord(value)) {\n    return { ok: false, issues: [{ path, code: 'invalid_value', message: 'expected an object' }] };\n  }\n\n  const out: Record<string, unknown> = {};\n  const issues: ReadIssue[] = [];\n\n  // Unknown keys: fatal for a writer, ignorable for a reader.\n  for (const key of Object.keys(value)) {\n    if (key in fields) continue;\n    const issue: ReadIssue = {\n      path: join(path, key),\n      code: 'unknown_key',\n      message: 'not part of this schema version',\n    };\n    if (ctx.mode === 'strict') issues.push(issue);\n    else ctx.dropped.push(issue);\n  }\n\n  for (const [key, field] of Object.entries(fields)) {\n    const fieldPath = join(path, key);\n    const present = key in value && value[key] !== undefined;\n\n    if (!present) {\n      if (field.required) {\n        issues.push({ path: fieldPath, code: 'missing_required', message: 'required field is missing' });\n      }\n      continue;\n    }\n\n    const read = readSpec(value[key], field.spec, fieldPath, ctx);\n    if (read.ok) {\n      out[key] = read.value;\n      continue;\n    }\n\n    // Invalid value. Required → always fatal. Optional → fatal for a writer,\n    // dropped (default applies) for a reader. The drop is reported at the\n    // FIELD's path (that is what disappeared), with the nested causes folded\n    // into the message.\n    if (field.required || ctx.mode === 'strict') {\n      issues.push(...read.issues);\n    } else {\n      ctx.dropped.push(droppedIssue(fieldPath, read.issues));\n    }\n  }\n\n  return issues.length > 0 ? { ok: false, issues } : { ok: true, value: out };\n}\n\n/**\n * Read `value` against `fields`. See the module doc for the two modes.\n *\n * `T` is the caller's promise about the shape `fields` describes; the engine\n * cannot prove it (that is what the `satisfies Record<keyof T, Field>` gate in\n * the descriptor is for).\n */\nexport function readObject<T>(value: unknown, fields: FieldMap, mode: ReadMode): ReadResult<T> {\n  const ctx: Ctx = { mode, dropped: [] };\n  const read = readFields(value, fields, '', ctx);\n  if (!read.ok) return { ok: false, issues: read.issues };\n  return { ok: true, value: read.value as T, dropped: ctx.dropped };\n}\n\n// ── schema description (for snapshots, docs, dashboards) ─────────────────────\n\nexport interface FieldDescription {\n  path: string;\n  kind: string;\n  required: boolean;\n  since: string;\n  description: string;\n  default?: Primitive;\n  enum?: Primitive[];\n  min?: number;\n  max?: number;\n  integer?: boolean;\n  literal?: Primitive;\n}\n\n/**\n * Flatten a field map into a sorted list of leaf-and-branch descriptions. This\n * is the machine-readable form of the contract: the compatibility gate diffs\n * it against the last released baseline, and dashboards/docs can render it.\n */\nexport function describeFields(fields: FieldMap, prefix = ''): FieldDescription[] {\n  const out: FieldDescription[] = [];\n  for (const [key, field] of Object.entries(fields)) {\n    const path = join(prefix, key);\n    describeInto(out, path, field.spec, field);\n  }\n  return out.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n}\n\nfunction describeInto(out: FieldDescription[], path: string, spec: FieldSpec, field: Field): void {\n  const base: FieldDescription = {\n    path,\n    kind: spec.kind === 'union' ? spec.options.map((o) => o.kind).join('|') : spec.kind,\n    required: field.required === true,\n    since: field.since,\n    description: field.description,\n  };\n  if (field.default !== undefined) base.default = field.default;\n  if (spec.kind === 'enum') base.enum = [...spec.values];\n  if (spec.kind === 'literal') base.literal = spec.value;\n  if (spec.kind === 'number') {\n    if (spec.integer) base.integer = true;\n    if (spec.min !== undefined) base.min = spec.min;\n    if (spec.max !== undefined) base.max = spec.max;\n  }\n  out.push(base);\n\n  const children = (s: FieldSpec): void => {\n    if (s.kind === 'object') out.push(...describeFields(s.fields, path));\n    else if (s.kind === 'array') children(s.item);\n    else if (s.kind === 'union') s.options.forEach(children);\n  };\n  children(spec);\n}\n","/**\n * THE schema descriptor for the canonical AgentConfig contract (schema v1).\n *\n * Everything that validates, describes, or defaults an agent configuration in\n * this package is derived from the field maps below — `isAgentConfig` (strict\n * writer), `readAgentConfig` / `readAgentBootstrap` (tolerant readers),\n * `resolveFeatures` (defaults), `describeAgentConfigSchema()` (the\n * machine-readable contract the compatibility gate snapshots). There is no\n * second list of keys anywhere. Adding a field is ONE entry here plus the\n * matching optional property on the TypeScript interface.\n *\n * GATES (they fail the build / the test suite, on purpose):\n *\n *   1. Every field map is declared `satisfies Record<keyof <Interface>, Field>`.\n *      Add a property to `FeatureConfig` without a descriptor entry → type\n *      error. Add a descriptor entry without the property → type error. The\n *      type and the contract cannot drift.\n *   2. `test/config-evolution.test.ts` snapshots `describeAgentConfigSchema()`\n *      and diffs it against the baseline of the LAST RELEASE. Removing a field,\n *      changing its kind, tightening a range, dropping an enum member, or\n *      making an optional field required fails the suite — those are\n *      schema-major changes and need a new `schemaVersion`, not a PR.\n *\n * RULES OF THE ROAD (full text in docs/config-evolution.md):\n *\n *   • New fields are OPTIONAL and carry `since` + a `default` where one exists.\n *   • A field's meaning never changes. Need different semantics? New field.\n *   • Enum members may be ADDED (old readers drop the unknown value and apply\n *     the default) but never removed or renamed.\n *   • `required: true` is reserved for the envelope — fields no reader can\n *     default. New required fields cannot be added to an existing object.\n */\n\nimport type { DisplayConfig, FeatureConfig, ThemeConfig } from '../types';\nimport type {\n  AgentBootstrap,\n  AgentClientConfig,\n  AgentConfig,\n  AgentRuntimeConfig,\n  SerializableFollowUpConfig,\n  SerializableMemoryConfig,\n  SerializableSandboxConfig,\n  SerializableStarterPrompt,\n  SerializableTitleConfig,\n} from '../config';\nimport type { Field, FieldMap } from './field';\n\n/** Schema major. Bumps only for breaking changes (see module doc). */\nexport const AGENT_CONFIG_SCHEMA_VERSION = 1 as const;\n\n/** The release that introduced the canonical schema — `since` for every v1 field. */\nconst V1 = '0.15.0';\n/** 0.20.0 — composer voice dictation. */\nconst V0_20 = '0.20.0';\n\n// ── runtime ──────────────────────────────────────────────────────────────────\n\nconst FOLLOW_UP_FIELDS = {\n  enabled: { spec: { kind: 'boolean' }, since: V1, description: 'Generate follow-up suggestions after each reply.' },\n  max: { spec: { kind: 'number', integer: true, min: 1, max: 5 }, since: V1, description: 'Maximum follow-up suggestions per reply.' },\n  timeoutMs: { spec: { kind: 'number', integer: true, min: 1 }, since: V1, description: 'Time budget for follow-up generation.' },\n} satisfies Record<keyof SerializableFollowUpConfig, Field>;\n\nconst TITLE_FIELDS = {\n  enabled: { spec: { kind: 'boolean' }, since: V1, description: 'Name conversations with a lightweight model call after the first exchange.' },\n  timeoutMs: { spec: { kind: 'number', integer: true, min: 1 }, since: V1, description: 'Time budget for title generation.' },\n} satisfies Record<keyof SerializableTitleConfig, Field>;\n\nconst MEMORY_FIELDS = {\n  enabled: { spec: { kind: 'boolean' }, required: true, since: V1, description: 'Long-term memory on/off.' },\n  inject: { spec: { kind: 'boolean' }, required: true, since: V1, description: 'Inject recalled memories before generation.' },\n  extract: { spec: { kind: 'boolean' }, required: true, since: V1, description: 'Extract and store memories after a completed turn.' },\n  limit: { spec: { kind: 'number', integer: true, min: 1, max: 20 }, required: true, since: V1, description: 'Maximum memories injected per turn.' },\n} satisfies Record<keyof SerializableMemoryConfig, Field>;\n\nconst SANDBOX_FIELDS = {\n  enabled: { spec: { kind: 'boolean' }, required: true, since: '0.25.0', default: false, description: 'Enable Mordn-managed sandboxes for verified users; subject to published config and operator policy.' },\n} satisfies Record<keyof SerializableSandboxConfig, Field>;\n\nexport const RUNTIME_FIELDS = {\n  model: { spec: { kind: 'string', nonEmpty: true }, required: true, since: V1, description: 'Gateway model identifier the handler runs.' },\n  systemPrompt: { spec: { kind: 'string' }, since: V1, description: 'System prompt.' },\n  temperature: { spec: { kind: 'number', min: 0, max: 2 }, since: V1, description: 'Sampling temperature.' },\n  maxOutputTokens: { spec: { kind: 'number', integer: true, min: 1 }, since: V1, description: 'Output token cap per turn.' },\n  followUps: {\n    spec: { kind: 'union', options: [{ kind: 'boolean' }, { kind: 'object', fields: FOLLOW_UP_FIELDS }] },\n    since: V1,\n    description: 'Follow-up suggestions: boolean shorthand or detailed settings.',\n  },\n  titles: {\n    spec: { kind: 'union', options: [{ kind: 'boolean' }, { kind: 'object', fields: TITLE_FIELDS }] },\n    since: V1,\n    description: 'Smart thread titles: boolean shorthand or detailed settings.',\n  },\n  memory: { spec: { kind: 'object', fields: MEMORY_FIELDS }, since: V1, description: 'Long-term memory settings.' },\n  sandbox: { spec: { kind: 'object', fields: SANDBOX_FIELDS }, since: '0.25.0', description: 'Managed workspace per verified user within this tenant and agent, shared across conversations. Absent means off.' },\n} satisfies Record<keyof AgentRuntimeConfig, Field>;\n\n// ── client ───────────────────────────────────────────────────────────────────\n\nconst THEME_FIELDS = {\n  backgroundColor: { spec: { kind: 'string' }, required: true, since: V1, description: 'Chat background color (hex).' },\n  textColor: { spec: { kind: 'string' }, required: true, since: V1, description: 'Body text color (hex).' },\n  primaryColor: { spec: { kind: 'string' }, required: true, since: V1, description: 'Primary accent color (hex).' },\n} satisfies Record<keyof ThemeConfig, Field>;\n\nexport const FEATURE_FIELDS = {\n  fileUpload: { spec: { kind: 'boolean' }, since: V1, default: false, description: 'Show the attach button and accept file uploads.' },\n  fileUploadAccept: { spec: { kind: 'string' }, since: V1, default: 'image/*', description: 'HTML `accept` filter for the file picker.' },\n  fileUploadMaxBytes: { spec: { kind: 'number', integer: true, min: 1 }, since: V1, description: 'Client-side per-file size cap in bytes.' },\n  webSearch: { spec: { kind: 'boolean' }, since: V1, default: false, description: 'Enable web search.' },\n  voiceInput: { spec: { kind: 'boolean' }, since: V0_20, default: true, description: 'Show the microphone button for browser speech-to-text dictation into the composer (rendered only where the browser supports it; never auto-sends).' },\n  voiceInputLanguage: { spec: { kind: 'string' }, since: V0_20, description: 'BCP-47 language for dictation. Defaults to the page language, then the browser language.' },\n} satisfies Record<keyof FeatureConfig, Field>;\n\nconst TOGGLE_POSITION_FIELDS = {\n  bottom: { spec: { kind: 'string' }, since: V1, description: 'CSS offset from the bottom edge.' },\n  right: { spec: { kind: 'string' }, since: V1, description: 'CSS offset from the right edge.' },\n} satisfies Record<keyof NonNullable<DisplayConfig['toggleButtonPosition']>, Field>;\n\nexport const DISPLAY_FIELDS = {\n  layout: { spec: { kind: 'enum', values: ['popup', 'inline', 'page'] }, since: V1, default: 'popup', description: 'Layout shape the widget renders in.' },\n  size: { spec: { kind: 'enum', values: ['compact', 'default', 'large', 'full'] }, since: V1, default: 'default', description: 'Width preset (popup layout).' },\n  width: { spec: { kind: 'string' }, since: V1, description: 'Custom CSS width override.' },\n  resizable: { spec: { kind: 'boolean' }, since: V1, default: true, description: 'Drag-to-resize.' },\n  defaultOpen: { spec: { kind: 'boolean' }, since: V1, default: false, description: 'Start open.' },\n  starterPromptsLayout: { spec: { kind: 'enum', values: ['list', 'grid'] }, since: V1, default: 'list', description: 'Empty-state starter prompt layout.' },\n  showToggleButton: { spec: { kind: 'boolean' }, since: V1, default: true, description: 'Render the floating toggle button.' },\n  toggleButtonPosition: { spec: { kind: 'object', fields: TOGGLE_POSITION_FIELDS }, since: V1, description: 'Toggle button offsets.' },\n  keyboardShortcut: {\n    spec: { kind: 'union', options: [{ kind: 'string' }, { kind: 'literal', value: false }] },\n    since: V1,\n    description: 'Keyboard combo that toggles the widget, or `false` for none.',\n  },\n} satisfies Record<keyof DisplayConfig, Field>;\n\nconst STARTER_PROMPT_FIELDS = {\n  title: { spec: { kind: 'string' }, required: true, since: V1, description: 'Prompt text (sent as the message when clicked).' },\n  subtitle: { spec: { kind: 'string' }, since: V1, description: 'Secondary line.' },\n} satisfies Record<keyof SerializableStarterPrompt, Field>;\n\nexport const CLIENT_FIELDS = {\n  greeting: { spec: { kind: 'string' }, since: V1, description: 'Empty-state headline.' },\n  subGreeting: { spec: { kind: 'string' }, since: V1, description: 'Faint line under the greeting.' },\n  assistantName: { spec: { kind: 'string' }, since: V1, description: \"The assistant's display name.\" },\n  theme: { spec: { kind: 'object', fields: THEME_FIELDS }, since: V1, description: 'Color theme (all-or-nothing).' },\n  features: { spec: { kind: 'object', fields: FEATURE_FIELDS }, since: V1, description: 'Feature flags.' },\n  display: { spec: { kind: 'object', fields: DISPLAY_FIELDS }, since: V1, description: 'Layout and chrome.' },\n  starterPrompts: { spec: { kind: 'array', item: { kind: 'object', fields: STARTER_PROMPT_FIELDS } }, since: V1, description: 'Empty-state starter prompts.' },\n  capabilitiesPrompt: { spec: { kind: 'string' }, since: V1, description: 'Client-visible capabilities blurb.' },\n  feedback: { spec: { kind: 'boolean' }, since: V1, default: false, description: 'Show per-message feedback controls.' },\n  streamingThrottleMs: { spec: { kind: 'number', integer: true, min: 0 }, since: V1, description: 'Render throttle for streamed text.' },\n  persistState: { spec: { kind: 'boolean' }, since: V1, description: 'Persist open/closed state per user.' },\n  allowAutoReopen: { spec: { kind: 'boolean' }, since: V1, description: 'Allow the widget to reopen itself after an explicit dismiss.' },\n} satisfies Record<keyof AgentClientConfig, Field>;\n\n// ── envelopes ────────────────────────────────────────────────────────────────\n\nexport const AGENT_CONFIG_FIELDS = {\n  schemaVersion: { spec: { kind: 'literal', value: AGENT_CONFIG_SCHEMA_VERSION }, required: true, since: V1, description: 'Schema major.' },\n  runtime: { spec: { kind: 'object', fields: RUNTIME_FIELDS }, required: true, since: V1, description: 'Server-side runtime settings.' },\n  client: { spec: { kind: 'object', fields: CLIENT_FIELDS }, required: true, since: V1, description: 'Browser-safe client projection.' },\n} satisfies Record<keyof AgentConfig, Field>;\n\n/** Independent of `schemaVersion`: transport shape and config schema evolve separately. */\nexport const BOOTSTRAP_PROTOCOL_VERSION = 1 as const;\n\nexport const BOOTSTRAP_FIELDS = {\n  protocolVersion: { spec: { kind: 'literal', value: BOOTSTRAP_PROTOCOL_VERSION }, required: true, since: V1, description: 'Bootstrap envelope version.' },\n  agent: { spec: { kind: 'string', nonEmpty: true }, required: true, since: V1, description: 'Resolved agent identifier.' },\n  revision: { spec: { kind: 'string', nonEmpty: true }, required: true, since: V1, description: 'Published revision identifier.' },\n  client: { spec: { kind: 'object', fields: CLIENT_FIELDS }, required: true, since: V1, description: 'Browser-safe client projection.' },\n  storageScope: { spec: { kind: 'string', nonEmpty: true }, required: true, since: V1, description: 'Opaque browser storage namespace.' },\n} satisfies Record<keyof AgentBootstrap, Field>;\n\n// ── defaults ─────────────────────────────────────────────────────────────────\n\n/** Collect the `default`s declared on a field map — the one place defaults live. */\nexport function defaultsOf<T extends FieldMap>(fields: T): Partial<Record<keyof T, unknown>> {\n  const out: Partial<Record<keyof T, unknown>> = {};\n  for (const key of Object.keys(fields) as Array<keyof T>) {\n    const d = fields[key].default;\n    if (d !== undefined) out[key] = d;\n  }\n  return out;\n}\n","/**\n * Canonical, JSON-serializable agent configuration shared by the control plane,\n * server handler, bootstrap response, and browser preview transport.\n *\n * Validation lives in two flavours, both derived from ONE descriptor\n * (`src/agent-config/descriptor.ts`) so they cannot drift:\n *\n *   • `isAgentConfig` / `isAgentBootstrap` — STRICT. The writer contract.\n *     Unknown keys are errors. Use where a document is authored or accepted\n *     for storage (publish, preview trust boundary).\n *   • `readAgentConfig` / `readAgentBootstrap` — TOLERANT. The reader\n *     contract. Unknown keys and uninterpretable optional values are dropped\n *     (and reported), never fatal. Use in every runtime consumer, so a\n *     document published by a NEWER dashboard/schema loads on an OLDER\n *     deployed widget. See docs/config-evolution.md.\n */\nimport type { DisplayConfig, FeatureConfig, ThemeConfig } from './types';\nimport { describeFields, readObject, type ReadIssue, type ReadResult } from './agent-config/field';\nimport {\n  AGENT_CONFIG_FIELDS,\n  AGENT_CONFIG_SCHEMA_VERSION,\n  BOOTSTRAP_FIELDS,\n  BOOTSTRAP_PROTOCOL_VERSION,\n  FEATURE_FIELDS,\n  defaultsOf,\n} from './agent-config/descriptor';\n\nexport { AGENT_CONFIG_SCHEMA_VERSION, BOOTSTRAP_PROTOCOL_VERSION };\nexport type { ReadIssue as ConfigReadIssue, ReadResult as ConfigReadResult };\nexport type { FieldDescription as ConfigFieldDescription } from './agent-config/field';\n\nexport interface SerializableStarterPrompt {\n  title: string;\n  subtitle?: string;\n}\n\nexport interface SerializableFollowUpConfig {\n  enabled?: boolean;\n  max?: number;\n  timeoutMs?: number;\n}\n\nexport interface SerializableTitleConfig {\n  enabled?: boolean;\n  timeoutMs?: number;\n}\n\nexport interface SerializableMemoryConfig {\n  enabled: boolean;\n  /** Inject recalled memories before generation. */\n  inject: boolean;\n  /** Extract and store memories after a completed turn. */\n  extract: boolean;\n  /** Maximum memories injected per turn. */\n  limit: number;\n}\n\n/** Managed workspace per verified user within an agent/tenant; absent means off. */\nexport interface SerializableSandboxConfig {\n  enabled: boolean;\n}\n\nexport interface AgentRuntimeConfig {\n  model: string;\n  systemPrompt?: string;\n  temperature?: number;\n  maxOutputTokens?: number;\n  followUps?: boolean | SerializableFollowUpConfig;\n  /**\n   * Smart thread titles: a lightweight post-response model call names the\n   * conversation after its first exchange. Default ON — pass `false` to keep\n   * the first-message-prefix placeholder titles.\n   */\n  titles?: boolean | SerializableTitleConfig;\n  memory?: SerializableMemoryConfig;\n  /** Enable sandboxes: Mordn-managed, shared across this user's conversations. */\n  sandbox?: SerializableSandboxConfig;\n}\n\nexport interface AgentClientConfig {\n  greeting?: string;\n  /** Faint line under the greeting headline (free display text). */\n  subGreeting?: string;\n  /** The assistant's name (identity, not the greeting sub line). */\n  assistantName?: string;\n  theme?: ThemeConfig;\n  features?: FeatureConfig;\n  display?: DisplayConfig;\n  starterPrompts?: SerializableStarterPrompt[];\n  capabilitiesPrompt?: string;\n  feedback?: boolean;\n  streamingThrottleMs?: number;\n  persistState?: boolean;\n  allowAutoReopen?: boolean;\n}\n\nexport interface AgentConfig {\n  schemaVersion: typeof AGENT_CONFIG_SCHEMA_VERSION;\n  runtime: AgentRuntimeConfig;\n  client: AgentClientConfig;\n}\n\n/** Hosted control-plane record consumed by the handler. */\nexport interface PublishedAgentConfig {\n  agent: string;\n  revision: string;\n  config: AgentConfig;\n}\n\n/** Browser-safe projection returned from GET /bootstrap. */\nexport interface AgentBootstrap {\n  protocolVersion: typeof BOOTSTRAP_PROTOCOL_VERSION;\n  agent: string;\n  revision: string;\n  client: AgentClientConfig;\n  storageScope: string;\n}\n\nexport function mergeAgentClientConfig(\n  published: AgentClientConfig | undefined,\n  explicit: AgentClientConfig | undefined,\n): AgentClientConfig {\n  if (!published) return explicit ?? {};\n  if (!explicit) return published;\n  return {\n    ...published,\n    ...explicit,\n    theme: explicit.theme ?? published.theme,\n    features:\n      published.features || explicit.features\n        ? { ...published.features, ...explicit.features }\n        : undefined,\n    display:\n      published.display || explicit.display\n        ? {\n            ...published.display,\n            ...explicit.display,\n            toggleButtonPosition:\n              published.display?.toggleButtonPosition || explicit.display?.toggleButtonPosition\n                ? {\n                    ...published.display?.toggleButtonPosition,\n                    ...explicit.display?.toggleButtonPosition,\n                  }\n                : undefined,\n          }\n        : undefined,\n  };\n}\n\n// ── Readers (tolerant) ───────────────────────────────────────────────────────\n\n/**\n * Read a complete schema-v1 config the way a RUNTIME must: fields this build\n * doesn't know are dropped and reported in `dropped`, never fatal. Fails only\n * on a wrong `schemaVersion` or a missing/invalid required field. Use in the\n * handler, the hosted config fetcher, and any other consumer of a published\n * document. The returned `value` contains only known, valid fields.\n */\nexport function readAgentConfig(value: unknown): ReadResult<AgentConfig> {\n  return readObject<AgentConfig>(value, AGENT_CONFIG_FIELDS, 'tolerant');\n}\n\n/** Tolerant reader for the browser-safe bootstrap envelope (see `readAgentConfig`). */\nexport function readAgentBootstrap(value: unknown): ReadResult<AgentBootstrap> {\n  return readObject<AgentBootstrap>(value, BOOTSTRAP_FIELDS, 'tolerant');\n}\n\n// ── Validators (strict) ──────────────────────────────────────────────────────\n\n/**\n * Validate the complete, strict schema-v1 config before it is authored,\n * stored, or trusted as a preview. Unknown keys are rejected — this is what\n * keeps typos and junk out of published revisions. Runtime consumers must use\n * `readAgentConfig` instead, or a newer dashboard will break older deployments.\n */\nexport function isAgentConfig(value: unknown): value is AgentConfig {\n  return readObject<AgentConfig>(value, AGENT_CONFIG_FIELDS, 'strict').ok;\n}\n\n/** Strict validator for the bootstrap envelope. Browsers should prefer `readAgentBootstrap`. */\nexport function isAgentBootstrap(value: unknown): value is AgentBootstrap {\n  return readObject<AgentBootstrap>(value, BOOTSTRAP_FIELDS, 'strict').ok;\n}\n\n// ── Defaults ─────────────────────────────────────────────────────────────────\n\n/** `FeatureConfig` with every defaulted flag resolved. */\nexport interface ResolvedFeatureConfig {\n  fileUpload: boolean;\n  fileUploadAccept: string;\n  fileUploadMaxBytes?: number;\n  webSearch: boolean;\n  voiceInput: boolean;\n  voiceInputLanguage?: string;\n}\n\n/** Feature defaults, sourced from the descriptor — the single place they live. */\nexport const DEFAULT_FEATURES: ResolvedFeatureConfig = defaultsOf(FEATURE_FIELDS) as ResolvedFeatureConfig;\n\n/**\n * Apply schema defaults to a (possibly partial or absent) `features` object.\n * Consumers read flags from the result instead of sprinkling `=== true` /\n * `?? 'image/*'` fallbacks through UI code, so a default changes in one place.\n */\nexport function resolveFeatures(features?: FeatureConfig | null): ResolvedFeatureConfig {\n  const resolved: ResolvedFeatureConfig = { ...DEFAULT_FEATURES };\n  if (!features) return resolved;\n  for (const [key, value] of Object.entries(features)) {\n    if (value !== undefined) (resolved as unknown as Record<string, unknown>)[key] = value;\n  }\n  return resolved;\n}\n\n// ── Schema description ───────────────────────────────────────────────────────\n\n/**\n * Machine-readable description of the whole contract: every path with its\n * kind, requiredness, `since`, default and constraints. The compatibility gate\n * (`test/config-evolution.test.ts`) snapshots this and diffs it against the\n * last release; dashboards and docs can render it directly.\n */\nexport function describeAgentConfigSchema() {\n  return {\n    schemaVersion: AGENT_CONFIG_SCHEMA_VERSION,\n    bootstrapProtocolVersion: BOOTSTRAP_PROTOCOL_VERSION,\n    config: describeFields(AGENT_CONFIG_FIELDS),\n    bootstrap: describeFields(BOOTSTRAP_FIELDS),\n  };\n}\n\n/** One-line summary of read issues for error messages and logs. */\nexport function formatConfigIssues(issues: readonly ReadIssue[]): string {\n  return issues.map((issue) => `${issue.path || '<root>'}: ${issue.message}`).join('; ');\n}\n","\"use client\";\n\n/**\n * Inline error banner shown above the chat input when a stream errors,\n * disconnects, or the model returns an error finish reason. Generic —\n * the consumer doesn't customise content, just wires up the actions\n * via the props below.\n *\n * Styling uses the widget's `--chat-*` tokens, so it picks up the host\n * app's theme without extra wiring. Inline (not toast) so the user\n * doesn't lose context of what they were just doing.\n */\n\nimport { AlertTriangleIcon, XIcon } from \"lucide-react\";\nimport { useEffect, useState } from \"react\";\nimport { getChatErrorRecovery } from \"../utils/chat-error-recovery\";\nimport { messageForErrorKind } from \"../utils/chat-error-protocol\";\n\n// These strings are emitted by the server taxonomy and contain no provider\n// detail. Keep the raw network/provider message off-screen, but preserve the\n// package-owned guidance instead of collapsing every category to a generic line.\nconst SAFE_SERVER_MESSAGES = new Set([\n  \"The assistant is handling a lot of requests right now. Please try again in a moment.\",\n  \"The assistant is not configured correctly. Please contact support.\",\n  \"The assistant is temporarily unavailable. Please try again.\",\n  \"I can't help with that request.\",\n  \"That request couldn't be processed. Try rephrasing or shortening your message.\",\n  \"The configured model could not complete this request. Try a different request or contact support.\",\n  \"A tool the assistant was using failed. Please try again.\",\n  \"An error occurred while generating the response.\",\n]);\n\nconst NON_RETRYABLE_SERVER_MESSAGES = new Set([\n  \"The assistant is not configured correctly. Please contact support.\",\n  \"I can't help with that request.\",\n  \"That request couldn't be processed. Try rephrasing or shortening your message.\",\n  \"The configured model could not complete this request. Try a different request or contact support.\",\n]);\n\nexport interface ChatErrorBannerProps {\n  /** The error to surface. When null, the component renders nothing. */\n  error: Error | null | undefined;\n  /** Whether to show the \"Try again\" affordance. Hidden when there is\n   *  no last user message to regenerate from. */\n  canRetry?: boolean;\n  /** Click handler for \"Try again\" — typically `useChat().regenerate`. */\n  onRetry?: () => void;\n  /** Click handler for the dismiss X — typically `useChat().clearError`. */\n  onDismiss?: () => void;\n}\n\nexport function ChatErrorBanner({\n  error,\n  canRetry = true,\n  onRetry,\n  onDismiss,\n}: ChatErrorBannerProps) {\n  const recovery = getChatErrorRecovery(error);\n  const metadata = recovery?.metadata;\n  const retryAt = recovery?.retryAt;\n  const [clock, setClock] = useState(Date.now);\n  useEffect(() => {\n    setClock(Date.now());\n    if (retryAt === undefined || retryAt <= Date.now()) return;\n    // Only unlock a MANUAL retry. Never regenerate from a timer: a failed\n    // response can already have executed tools with external side effects.\n    const timer = setTimeout(() => setClock(Date.now()), retryAt - Date.now());\n    return () => clearTimeout(timer);\n  }, [retryAt]);\n  const waiting = retryAt !== undefined && retryAt > Math.max(clock, Date.now());\n  if (!error) return null;\n\n  // A user-initiated Stop surfaces through useChat's error state as an\n  // AbortError. That is not a failure — the partial answer is already on\n  // screen and persisted — so rendering an alert banner for it (previously a\n  // softened \"Stopped.\" with a warning icon and a Try again link) read as\n  // \"the generation errored\". Client-side aborts only come from the stop\n  // button or navigation; real server-side failures arrive as error chunks\n  // with their own messages and still render below.\n  if (metadata ? metadata.kind === \"abort\" :\n      error.name === \"AbortError\" || error.message === \"The response was aborted.\") return null;\n\n  // Versioned metadata takes precedence over ALL prose (including custom or\n  // translated onError text). Legacy servers retain their safe-string fallback.\n  // Never display arbitrary error copy, or the opaque trace reference, in DOM.\n  const friendly = metadata ? messageForErrorKind(metadata.kind) : friendlyErrorMessage(error);\n  const retryable = metadata?.retryable ?? !NON_RETRYABLE_SERVER_MESSAGES.has(error.message ?? \"\");\n\n  return (\n    <div\n      role=\"alert\"\n      className=\"mb-3 flex items-center gap-2 rounded-[9px] px-3 py-2.5 text-[13px]\"\n      style={{\n        backgroundColor: \"hsl(var(--chat-surface))\",\n        border: \"1px solid hsl(var(--chat-border-soft))\",\n      }}\n    >\n      <AlertTriangleIcon\n        className=\"size-3.5 flex-shrink-0\"\n        style={{ color: \"hsl(var(--chat-text-faint))\" }}\n      />\n      <div className=\"flex-1 min-w-0\">\n        <span style={{ color: \"hsl(var(--chat-text-body))\" }}>{friendly}</span>\n        {waiting && <span> Please wait before trying again.</span>}\n      </div>\n      {canRetry && retryable && onRetry && (\n        <button\n          type=\"button\"\n          disabled={waiting}\n          onClick={() => {\n            if (retryAt === undefined || Date.now() >= retryAt) onRetry();\n          }}\n          className=\"rounded-sm text-[12px] font-medium underline underline-offset-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\"\n          style={{ color: \"hsl(var(--chat-text-body))\" }}\n        >\n          Try again\n        </button>\n      )}\n      {onDismiss && (\n        <button\n          type=\"button\"\n          onClick={onDismiss}\n          aria-label=\"Dismiss\"\n          className=\"-mr-1 flex size-5 flex-shrink-0 items-center justify-center rounded-md transition-colors hover:bg-[hsl(var(--chat-hover-bg))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\"\n          style={{ color: \"hsl(var(--chat-text-faint))\" }}\n        >\n          <XIcon className=\"size-3\" />\n        </button>\n      )}\n    </div>\n  );\n}\n\nfunction friendlyErrorMessage(error: Error): string {\n  const raw = error.message ?? \"\";\n  if (SAFE_SERVER_MESSAGES.has(raw)) return raw;\n  if (/network|fetch|disconnect|ECONN/i.test(raw)) {\n    return \"Connection issue. Check your network and try again.\";\n  }\n  if (/rate.?limit|429/i.test(raw)) {\n    return \"You're sending messages too fast. Wait a moment and try again.\";\n  }\n  if (/timeout/i.test(raw)) return \"The response took too long.\";\n  return \"Something went wrong while generating the response.\";\n}\n","/** Browser-safe, versioned error contract. Never add provider payloads, messages,\n * codes, stacks or causes here. Metadata is a UI hint, NOT server authorization\n * or permission to replay a request (tools may already have had side effects).\n */\nexport const CHAT_ERROR_VERSION = 1 as const;\nexport const CHAT_ERROR_DATA_TYPE = 'data-chat-error' as const;\n/** JSON metadata in a header preserves the existing HTTP status and body. */\nexport const CHAT_ERROR_HEADER = 'x-chat-error';\nexport const MAX_RETRY_AFTER_MS = 15 * 60_000;\n\nexport type ChatErrorKind =\n  | 'abort'\n  | 'rate_limit'\n  | 'auth'\n  | 'transient'\n  | 'content_policy'\n  | 'prompt'\n  | 'model'\n  | 'tool'\n  | 'unknown';\n\nexport interface ChatErrorMetadata {\n  version: typeof CHAT_ERROR_VERSION;\n  kind: ChatErrorKind;\n  retryable: boolean;\n  retryAfterMs?: number;\n  /** Opaque correlation reference, not user-facing copy or a URL. */\n  traceId?: string;\n}\n\nconst MESSAGES: Record<ChatErrorKind, string> = {\n  abort: 'The response was aborted.',\n  rate_limit: 'The assistant is handling a lot of requests right now. Please try again in a moment.',\n  auth: 'The assistant is not configured correctly. Please contact support.',\n  transient: 'The assistant is temporarily unavailable. Please try again.',\n  content_policy: \"I can't help with that request.\",\n  prompt: \"That request couldn't be processed. Try rephrasing or shortening your message.\",\n  model: 'The configured model could not complete this request. Try a different request or contact support.',\n  tool: 'A tool the assistant was using failed. Please try again.',\n  unknown: 'An error occurred while generating the response.',\n};\n\nexport function messageForErrorKind(kind: ChatErrorKind): string {\n  return Object.prototype.hasOwnProperty.call(MESSAGES, kind) ? MESSAGES[kind] : MESSAGES.unknown;\n}\n\n/** Fail closed on unknown versions/kinds and malformed core fields. Return a\n * fresh allowlisted projection, never spread untrusted data into an Error/DOM.\n * Optional invalid hints are dropped. Contradictory retry hints cannot enable\n * retries for auth/policy/tool/etc. No caller should use this as server policy.\n */\nexport function parseChatErrorMetadata(value: unknown): ChatErrorMetadata | undefined {\n  try {\n    if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;\n    // Read each property once, including for non-JSON callers with getters.\n    const { version, kind: rawKind, retryable: rawRetryable, retryAfterMs, traceId } = value as Record<string, unknown>;\n    if (version !== CHAT_ERROR_VERSION || typeof rawKind !== 'string' ||\n        !Object.prototype.hasOwnProperty.call(MESSAGES, rawKind) ||\n        typeof rawRetryable !== 'boolean') return undefined;\n    const kind = rawKind as ChatErrorKind;\n    const retryable = rawRetryable && (kind === 'rate_limit' || kind === 'transient');\n    const metadata: ChatErrorMetadata = { version: CHAT_ERROR_VERSION, kind, retryable };\n    if (retryable && typeof retryAfterMs === 'number' && Number.isFinite(retryAfterMs) && retryAfterMs >= 0) {\n      metadata.retryAfterMs = Math.min(Math.ceil(retryAfterMs), MAX_RETRY_AFTER_MS);\n    }\n    if (typeof traceId === 'string' && traceId.length >= 8 && traceId.length <= 128 &&\n        !/[^A-Za-z0-9._-]/.test(traceId)) {\n      metadata.traceId = traceId;\n    }\n    return metadata;\n  } catch {\n    return undefined;\n  }\n}\n\nexport function parseChatErrorHeader(value: string | null): ChatErrorMetadata | undefined {\n  if (!value || value.length > 2048) return undefined;\n  try { return parseChatErrorMetadata(JSON.parse(value)); } catch { return undefined; }\n}\n\n/** Server-side projection. Deliberately accepts only the public fields, not\n * `cause`, `code`, `status` or `message` from ClassifiedChatError. */\nexport function toChatErrorMetadata(\n  classified: Pick<ChatErrorMetadata, 'kind' | 'retryable' | 'retryAfterMs'>,\n  traceId: string,\n): ChatErrorMetadata {\n  return parseChatErrorMetadata({\n    version: CHAT_ERROR_VERSION,\n    kind: classified.kind,\n    retryable: classified.retryable,\n    retryAfterMs: classified.retryAfterMs,\n    traceId,\n  }) ?? { version: CHAT_ERROR_VERSION, kind: 'unknown', retryable: false };\n}\n","import type { ChatTransport, UIMessage, UIMessageChunk } from 'ai';\nimport {\n  CHAT_ERROR_DATA_TYPE,\n  CHAT_ERROR_HEADER,\n  messageForErrorKind,\n  parseChatErrorHeader,\n  parseChatErrorMetadata,\n  type ChatErrorMetadata,\n} from './chat-error-protocol';\n\ninterface ErrorRecovery {\n  readonly metadata: Readonly<ChatErrorMetadata>;\n  /** Absolute deadline captured on receipt, so re-renders/tab switches do not\n   * restart a server-specified wait. Never schedules a network request. */\n  readonly retryAt?: number;\n}\nconst recoveryByError = new WeakMap<Error, ErrorRecovery>();\n\nexport function getChatErrorRecovery(error: Error | null | undefined): ErrorRecovery | undefined {\n  return error ? recoveryByError.get(error) : undefined;\n}\n\nfunction recovery(metadata: ChatErrorMetadata): ErrorRecovery {\n  return Object.freeze({\n    metadata: Object.freeze(metadata),\n    ...(metadata.retryAfterMs !== undefined ? { retryAt: Date.now() + metadata.retryAfterMs } : {}),\n  });\n}\n\n/** Use wrapTransport for a Chat: recovery must belong to each response stream,\n * not to a Chat-wide callback slot. A stopped response can still have queued\n * callbacks after the next request begins, and aborts skip the SDK onError hook.\n * The low-level onData/onError pair is only for a single, isolated stream.\n * Nothing is persisted in message parts or automatically retried.\n */\nexport function createChatErrorRecovery() {\n  let pending: ErrorRecovery | undefined;\n  const reset = () => { pending = undefined; };\n  return {\n    reset,\n    /** Preserve the transport's method receiver and SDK request signatures. Each\n     * send/reconnect has its own accumulator, including overlapping responses. */\n    wrapTransport<UI_MESSAGE extends UIMessage>(transport: ChatTransport<UI_MESSAGE>): ChatTransport<UI_MESSAGE> {\n      const wrap = (stream: ReadableStream<UIMessageChunk>) => {\n        const local = createChatErrorRecovery();\n        return stream.pipeThrough(new TransformStream<UIMessageChunk, UIMessageChunk>({\n          transform(chunk, controller) {\n            if (chunk.type === CHAT_ERROR_DATA_TYPE) {\n              // This reserved control part must never become transcript data,\n              // even when a custom server mistakenly omits transient:true.\n              if (!('transient' in chunk) || chunk.transient !== true) return;\n              local.onData(chunk);\n            }\n            if (chunk.type === 'error') {\n              const error = new Error(chunk.errorText);\n              local.onError(error);\n              // The SDK passes stream failures to onError and stores this exact\n              // Error. No unscoped callback association or prose matching needed.\n              controller.error(error);\n              return;\n            }\n            controller.enqueue(chunk);\n          },\n        }));\n      };\n      return {\n        async sendMessages(options) { return wrap(await transport.sendMessages(options)); },\n        async reconnectToStream(options) {\n          const stream = await transport.reconnectToStream(options);\n          return stream === null ? null : wrap(stream);\n        },\n      };\n    },\n    onData(part: unknown) {\n      try {\n        if (!part || typeof part !== 'object') return;\n        const candidate = part as { type?: unknown; data?: unknown; transient?: unknown };\n        if (candidate.type !== CHAT_ERROR_DATA_TYPE || candidate.transient !== true) return;\n        const metadata = parseChatErrorMetadata(candidate.data);\n        if (metadata && !pending) pending = recovery(metadata);\n      } catch {\n        // Non-JSON callers can supply throwing getters. Ignore bad metadata.\n      }\n    },\n    onError(error: Error) {\n      if (pending && !recoveryByError.has(error)) recoveryByError.set(error, pending);\n      reset();\n    },\n    /** DefaultChatTransport fetch seam. Non-OK HTTP bodies remain untouched for\n     * old servers. New-server metadata yields an Error with package-owned copy;\n     * no arbitrary HTTP body/provider secret is promoted to a UI message. */\n    fetch: (async (input: RequestInfo | URL, init?: RequestInit) => {\n      reset();\n      const response = await globalThis.fetch(input, init);\n      if (!response.ok) {\n        const metadata = parseChatErrorHeader(response.headers.get(CHAT_ERROR_HEADER));\n        if (metadata) {\n          const error = new Error(messageForErrorKind(metadata.kind));\n          recoveryByError.set(error, recovery(metadata));\n          // We replace the transport's error path, so release its unread body.\n          void response.body?.cancel().catch(() => {});\n          throw error;\n        }\n      }\n      return response;\n    }) satisfies typeof fetch,\n  };\n}\n","'use client';\n\nimport {\n  Conversation,\n  ConversationContent,\n  ConversationScrollButton,\n} from './conversation';\nimport { Message, MessageContent } from './message';\nimport {\n  PromptInput,\n  PromptInputAttachment,\n  PromptInputAttachments,\n  PromptInputBody,\n  PromptInputButton,\n  type PromptInputMessage,\n  PromptInputModelSelect,\n  PromptInputModelSelectContent,\n  PromptInputModelSelectItem,\n  PromptInputModelSelectTrigger,\n  PromptInputModelSelectValue,\n  PromptInputSubmit,\n  PromptInputTextarea,\n  PromptInputToolbar,\n  PromptInputTools,\n  usePromptInputAttachments,\n} from './prompt-input';\nimport {\n  Actions,\n  Action,\n} from './actions';\nimport { MessageAttachments } from './message-attachments';\nimport { useInputPlugins } from './input-plugin-popover';\nimport { useDictation } from '../hooks/use-dictation';\nimport { DictationButton } from './dictation-button';\nimport { resolveFeatures } from '../config';\nimport { ChatErrorBanner } from './chat-error-banner';\nimport { createChatErrorRecovery } from '../utils/chat-error-recovery';\nimport { MessageActions } from './message-actions';\nimport { useState, useEffect, useRef, useMemo, useCallback } from 'react';\nimport { HistoryIcon, MessageSquareIcon, SearchIcon, PaperclipIcon, SquarePenIcon, XIcon } from 'lucide-react';\nimport { cn } from '../utils/cn';\nimport { MAX_FOLLOW_UP_COUNT, normalizeFollowUpSuggestions } from '../utils/follow-ups';\nimport { resolveChatContext } from '../utils/page-context';\nimport {\n  hasRenderableAssistantContent,\n  messagesForTranscript,\n} from '../utils/assistant-content';\nimport { Button } from '../ui/button';\nimport { Input } from '../ui/input';\nimport { Fragment } from 'react';\nimport { Chat, useChat } from '@ai-sdk/react';\nimport { DefaultChatTransport, lastAssistantMessageIsCompleteWithApprovalResponses, type UIMessage } from 'ai';\nimport { Response } from './response';\nimport { GlobeIcon, RefreshCcwIcon, CopyIcon } from 'lucide-react';\nimport {\n  Source,\n  Sources,\n  SourcesContent,\n  SourcesTrigger,\n} from './sources';\nimport {\n  Reasoning,\n  ReasoningContent,\n  ReasoningTrigger,\n} from './reasoning';\nimport { Loader } from './loader';\nimport { TextShimmer } from './transcript/TextShimmer';\nimport { pickPlanningVerb } from './transcript/toolRegistry';\nimport {\n  Tool,\n  ToolContent,\n  ToolHeader,\n  ToolInput,\n  ToolOutput,\n} from './tool';\nimport { FollowUpSuggestions } from './follow-up-suggestions';\nimport { StarterMessages } from './suggestion2';\nimport { MessageItem } from './message-item';\nimport { useChatStorageKey } from '../contexts/chat-storage-context';\nimport type { StarterPrompt, ChatContext } from '../types';\n\ntype Conversation = {\n  id: string;\n  title: string;\n  model: string;\n  created_at: string;\n  updated_at: string;\n  message_count: number;\n  metadata?: any;\n};\n\nfunction formatConversationTime(value: string): string {\n  const date = new Date(value);\n  if (Number.isNaN(date.getTime())) return '';\n  const diffMs = Date.now() - date.getTime();\n  const diffMinutes = Math.max(0, Math.floor(diffMs / 60_000));\n  if (diffMinutes < 1) return 'now';\n  if (diffMinutes < 60) return `${diffMinutes}m`;\n  const diffHours = Math.floor(diffMinutes / 60);\n  if (diffHours < 24) return `${diffHours}h`;\n  if (diffHours < 7 * 24) return date.toLocaleDateString(undefined, { weekday: 'short' });\n  return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n}\n\n/**\n * Storage access that can never throw. Safari private mode (historically a\n * QuotaExceededError on ANY setItem), storage disabled by policy, a full\n * origin quota, or SSR must all degrade to \"no persistence\" — never to a\n * crashed widget inside someone else's app. Every other file already guards\n * its storage access; interface.tsx was the lone gap and holds the most\n * storage code, so the guard lives here as one helper instead of ad-hoc\n * try/catch at every call site.\n */\nconst makeSafeStorage = (resolve: () => Storage) => ({\n  get(key: string): string | null {\n    try {\n      return resolve().getItem(key);\n    } catch {\n      return null;\n    }\n  },\n  set(key: string, value: string): void {\n    try {\n      resolve().setItem(key, value);\n    } catch {\n      /* persistence is best-effort */\n    }\n  },\n  remove(key: string): void {\n    try {\n      resolve().removeItem(key);\n    } catch {\n      /* ignore */\n    }\n  },\n  keys(): string[] {\n    try {\n      const store = resolve();\n      const out: string[] = [];\n      for (let i = 0; i < store.length; i++) {\n        const k = store.key(i);\n        if (k) out.push(k);\n      }\n      return out;\n    } catch {\n      return [];\n    }\n  },\n});\n\nconst safeStorage = makeSafeStorage(() => window.localStorage);\n// Drafts live in sessionStorage on purpose: a half-typed message should\n// survive tab switches and panel close/reopen within the visit, but is not\n// worth carrying across browser sessions the way conversation tabs are.\nconst safeSession = makeSafeStorage(() => window.sessionStorage);\n\ntype ChatTab = {\n  id: string;\n  title: string;\n  isActive: boolean;\n};\n\n/**\n * Attachment button — compact ghost icon on the left of the prompt row, sized\n * to match the send button with a muted paperclip that doesn't\n * compete with the text or the send action. Reads the attachments context.\n *\n * Hoisted to MODULE scope deliberately: it used to be defined inside\n * ChatInterface's render, which makes React see a brand-new component type\n * every render — unmounting and remounting the subtree each time (transient\n * state/focus loss + wasted work). A component must never be defined inside\n * another component's body.\n */\nfunction AttachButton() {\n  const attachments = usePromptInputAttachments();\n  return (\n    <PromptInputButton\n      variant=\"ghost\"\n      size=\"icon\"\n      // Quiet icon button: faint at rest, then the shared hover surface and\n      // full text color on interaction.\n      className=\"size-8 rounded-[7px] text-[hsl(var(--chat-text-faint))] hover:bg-[hsl(var(--chat-hover-bg))] hover:text-[hsl(var(--chat-text))]\"\n      aria-label=\"Attach files\"\n      onClick={() => attachments.openFileDialog()}\n    >\n      {/* lucide's Paperclip runs bottom-left→top-right; rotate -45° to\n          stand it upright (vertical). */}\n      <PaperclipIcon className=\"size-4 -rotate-45\" />\n    </PromptInputButton>\n  );\n}\n\nexport default function ChatInterface({ id, initialMessages, config, onClose, headerActions }: { id?: string; initialMessages?: any[]; config?: any; onClose?: () => void; headerActions?: React.ReactNode } = {}) {\n  // Storage key prefix is scoped to (agent, user). It is `null` when identity\n  // is incomplete — in that case storageKey() returns null and every caller\n  // must skip persistence (no shared/static fallback bucket → no cross-user leak).\n  const { storageKeyPrefix } = useChatStorageKey();\n  const storageKey = (key: string): string | null =>\n    storageKeyPrefix ? `chat-${storageKeyPrefix}-${key}` : null;\n\n  // Base path for every widget request, normalised ONCE: a trailing slash on\n  // the configured apiBase (an easy config typo, especially for cross-origin\n  // embeds) would otherwise produce double-slash URLs (`…/api/chat//upload`)\n  // that literal-matching routers and proxies 404. feedback.ts already guards\n  // this on its own path — this brings the other five call sites in line.\n  // A bare '/' (root mount) strips to '' so `${apiBase}/history` stays a\n  // proper root-relative path instead of a scheme-relative '//history'.\n  const apiBase = String(config?.apiBase ?? '/api/chat').replace(/\\/+$/, '');\n\n  // Feature flags with schema defaults applied (config-evolution contract):\n  // read flags from here, never from `config.features` directly, so a default\n  // lives in exactly one place (the schema descriptor).\n  const features = resolveFeatures(config?.features);\n\n  // Per-tab composer drafts (sessionStorage — see safeSession above). Scoped\n  // exactly like every other persisted key; null when identity is incomplete,\n  // in which case drafts simply don't persist.\n  const draftKey = (tabId: string): string | null =>\n    storageKeyPrefix && tabId ? `chat-${storageKeyPrefix}-draft-${tabId}` : null;\n\n  // Get theme mode from config (defaults to 'light')\n\n  const [input, setInput] = useState('');\n  const inputRef = useRef<HTMLTextAreaElement | null>(null);\n  const inputPlugins = useInputPlugins({\n    textareaRef: inputRef,\n    value: input,\n    setValue: setInput,\n    plugins: config?.inputPlugins,\n  });\n  // Voice dictation (features.voiceInput, default on). Speech lands in the\n  // same `input` state as typing; the hook renders nothing where the browser\n  // has no SpeechRecognition, and never submits on its own.\n  const dictation = useDictation({\n    textareaRef: inputRef,\n    value: input,\n    setValue: setInput,\n    enabled: features.voiceInput,\n    lang: features.voiceInputLanguage,\n  });\n  const [showHistory, setShowHistory] = useState(false);\n  const [conversations, setConversations] = useState<Conversation[]>([]);\n  const [loadingHistory, setLoadingHistory] = useState(false);\n  const [historyLoaded, setHistoryLoaded] = useState(false);\n  const [searchQuery, setSearchQuery] = useState('');\n  const [uploadError, setUploadError] = useState<string | null>(null);\n\n  // Dynamic starter prompts (#164). Resolved once when first needed; falls\n  // back to the static config.starterPrompts on empty result or error. The\n  // one-shot ref guards against re-resolving if the host passes an inline\n  // (non-memoised) getStarterPrompts.\n  const [dynamicPrompts, setDynamicPrompts] = useState<StarterPrompt[] | null>(null);\n  const dynamicPromptsResolved = useRef(false);\n  useEffect(() => {\n    if (dynamicPromptsResolved.current) return;\n    const getPrompts = config?.getStarterPrompts;\n    if (typeof getPrompts !== 'function') return;\n    dynamicPromptsResolved.current = true;\n    let cancelled = false;\n    Promise.resolve()\n      .then(() => getPrompts())\n      .then((p: StarterPrompt[]) => {\n        if (!cancelled && Array.isArray(p) && p.length > 0) setDynamicPrompts(p);\n      })\n      .catch(() => {\n        /* fall back to static starterPrompts */\n      });\n    return () => {\n      cancelled = true;\n    };\n  }, [config?.getStarterPrompts]);\n\n  // Dynamic prompts win when present; otherwise the static list.\n  const effectiveStarterPrompts: StarterPrompt[] | undefined =\n    (dynamicPrompts && dynamicPrompts.length > 0 ? dynamicPrompts : config?.starterPrompts) ?? undefined;\n\n  // AI follow-up chips (#134). The preferred path is a server-emitted\n  // `data-follow-ups` part on the completed assistant message; the legacy\n  // client generator/static config remains as an override/fallback.\n  const [followUps, setFollowUps] = useState<string[]>([]);\n  const followUpsForRef = useRef<string | null>(null);\n\n  // Auto-dismiss upload errors after 5 seconds\n  useEffect(() => {\n    if (uploadError) {\n      const timeoutId = setTimeout(() => setUploadError(null), 5000);\n      return () => clearTimeout(timeoutId);\n    }\n  }, [uploadError]);\n\n  // Tab management\n  const [tabs, setTabs] = useState<ChatTab[]>([]);\n  const [activeTabId, setActiveTabId] = useState<string>('');\n  const [initialTabCreated, setInitialTabCreated] = useState(false);\n  const [isInitializing, setIsInitializing] = useState(true);\n  // True while switching tabs and the new tab's messages are mid-fetch.\n  // Distinct from isInitializing (which only covers first mount) so the\n  // empty-state gate stays closed during tab switches too.\n  const [isLoadingMessages, setIsLoadingMessages] = useState(false);\n\n  // ── History lazy-loading (reverse pagination) ───────────────────────────────\n  // We load the most-recent page on open and fetch older pages when the user\n  // scrolls near the top. `hasMoreHistory` gates further fetches; the server\n  // supplies an opaque composite cursor for the next page; the ref guards\n  // against concurrent / duplicate fetches. PAGE_SIZE is the request count.\n  const HISTORY_PAGE_SIZE = 30;\n  const [hasMoreHistory, setHasMoreHistory] = useState(false);\n  const [loadingOlder, setLoadingOlder] = useState(false);\n  const historyCursorRef = useRef<string | null>(null);\n  const loadingOlderRef = useRef(false);\n\n  // Track last synced tab to prevent infinite loops\n  const lastSyncedTabId = useRef<string>('');\n\n  // Ref-based initialization guard to ensure initialization runs only once\n  const hasInitialized = useRef(false);\n\n  // Live mirrors for values that async callbacks must read FRESH. A callback\n  // that awaited a fetch would otherwise act on the state it closed over at\n  // call time — exactly the stale view that lets one tab's response land in\n  // another tab. `activeTabIdRef` is written synchronously at every activation\n  // site (not in an effect) so even an await that resolves between commits\n  // sees the truth; `statusRef` mirrors the stream status for callbacks whose\n  // dep arrays would otherwise go stale (e.g. createNewTab).\n  const activeTabIdRef = useRef<string>('');\n  const statusRef = useRef<string>('ready');\n  // Monotonic generation for conversation loads: a resolved fetch applies only\n  // if it is still the LATEST load AND its conversation is still active.\n  // Guards the tab-switch race (slow tab-A fetch resolving after tab B was\n  // activated) without threading AbortControllers through every path.\n  const loadGenRef = useRef(0);\n\n  // Mounted flag for async flows (uploads, history fetches) whose resolutions\n  // can outlive the component — e.g. the popup unmounts this whole tree on\n  // close while an upload is mid-flight. NOTE: (re)set in the effect BODY, not\n  // the ref initialiser — React 18 StrictMode runs mount → cleanup → mount,\n  // and an initialiser-only flag would stay false after the second mount.\n  const mountedRef = useRef(true);\n  useEffect(() => {\n    mountedRef.current = true;\n    return () => {\n      mountedRef.current = false;\n    };\n  }, []);\n\n  // `initialMessages` (public prop, previously accepted-but-ignored): the\n  // seed transcript for conversations that don't exist server-side yet — a\n  // welcome exchange, an SSR-prepared transcript. Captured ONCE by contract\n  // (\"initial\"); reacting to later mutations would fight the server as the\n  // source of truth once a conversation persists.\n  const initialMessagesRef = useRef<any[] | undefined>(initialMessages);\n\n  // First-class per-turn context (#162, #239). Holds the RAW `context` prop\n  // union (object | 'auto' | function) in a ref so the transport's\n  // prepareSendMessagesRequest always reads the latest value without\n  // re-creating the chat (and resetting the stream) on every context change.\n  // The union is collapsed to a concrete object by `resolveChatContext` inside\n  // the transport (see below) — i.e. AT SEND TIME, so 'auto'/function capture\n  // reflects SPA navigation between messages.\n  const contextRef = useRef<ChatContext | 'auto' | (() => ChatContext | Promise<ChatContext>) | undefined>(config?.context);\n  useEffect(() => {\n    contextRef.current = config?.context;\n  }, [config?.context]);\n\n  // Generic transport headers are resolved per request so rotating CSRF/session\n  // metadata does not require recreating the chat transport.\n  const headersRef = useRef<Record<string, string>>({});\n  useEffect(() => {\n    headersRef.current = config?.headers ?? {};\n  }, [config?.headers]);\n\n  // The full canonical config is included only as request data. The production\n  // handler ignores it; an explicitly configured server preview resolver may\n  // validate and replace the published config with it.\n  const requestConfigRef = useRef(config?.requestConfig);\n  useEffect(() => {\n    requestConfigRef.current = config?.requestConfig;\n  }, [config?.requestConfig]);\n\n  // ── One Chat instance per tab ────────────────────────────────────────────\n  //\n  // Each conversation owns its own Chat (its own stream and its own message\n  // list), and `useChat` renders whichever one is active. A background tab's\n  // stream keeps running and keeps writing into ITS list, so switching away\n  // mid-answer no longer throws the response away — switch back and it is\n  // still streaming.\n  //\n  // This replaces a single instance re-keyed by `id: activeTabId`. That shape\n  // forced an abort on every activation (`stopIfStreaming`), because the old\n  // tab's still-open stream would otherwise append into whatever conversation\n  // had just become current. Separate instances make that contamination\n  // unrepresentable rather than guarded against.\n  //\n  // The registry is a ref, not state: creating a Chat must not schedule a\n  // render, and instances must survive re-renders. `getChat` is idempotent —\n  // the same tab id always returns the same instance, which is what lets a\n  // background stream keep its identity across switches.\n  const chatsRef = useRef<Map<string, Chat<UIMessage>>>(new Map());\n\n  const buildTransport = useCallback(\n    (recovery: ReturnType<typeof createChatErrorRecovery>) =>\n      new DefaultChatTransport({\n      api: apiBase || '/',\n      fetch: recovery.fetch,\n      // Resolved PER REQUEST (see headersRef above) so host-injected headers\n      // are never stale — a static object froze the mount-time values.\n      headers: () => headersRef.current,\n      // Cookie mode for cross-origin apiBase deployments whose getUserId\n      // reads a session cookie (see ChatWidgetProps.requestCredentials).\n      credentials: config?.requestCredentials,\n      // Attach first-class per-turn context (#162, #239) to the request body.\n      // Read the RAW prop union from a ref (so the latest value is sent without\n      // re-creating the chat) and collapse it to a concrete object HERE, at send\n      // time, via resolveChatContext: 'auto' → live page capture, function →\n      // called/awaited (degrades to {} on throw), object → as-is. Resolving at\n      // send time is what makes 'auto'/function reflect SPA route changes\n      // between messages. When it resolves to undefined we omit `context`\n      // entirely so it serialises away — zero overhead, same as before.\n      //\n      // The AI SDK awaits prepareSendMessagesRequest (it may return a Promise),\n      // so an async resolver here is supported and does not block anything else.\n      //\n      // CRITICAL: the callback receives `id` and `messages` as SEPARATE fields,\n      // NOT inside `body` (which is only the optional custom-body object, usually\n      // empty). Whatever we return as `body` IS the entire request payload — so\n      // we must explicitly include `id` and `messages`, or the server receives\n      // `{}` and rejects with \"Missing conversation id\". (Default transport adds\n      // these for you; once you override prepareSendMessagesRequest you own them.)\n      prepareSendMessagesRequest: async ({ id, messages, body }) => {\n        const resolvedContext = await resolveChatContext(contextRef.current);\n        return {\n          body: {\n            ...body,\n            id,\n            messages,\n            ...(resolvedContext !== undefined ? { context: resolvedContext } : {}),\n            config: requestConfigRef.current,\n          },\n        };\n      },\n      }),\n    [apiBase, config?.requestCredentials],\n  );\n\n  /**\n   * The Chat for a tab, created on first use and reused forever after. Reusing\n   * the instance is the whole point: it is what carries an in-flight stream\n   * across a tab switch.\n   */\n  const getChat = useCallback(\n    (tabId: string): Chat<UIMessage> => {\n      const existing = chatsRef.current.get(tabId);\n      if (existing) return existing;\n      // Recovery belongs to this Chat, including when it streams in background.\n      const recovery = createChatErrorRecovery();\n      const created = new Chat<UIMessage>({\n        id: tabId,\n        transport: recovery.wrapTransport(buildTransport(recovery)),\n        // Human-in-the-loop tool approval: once the user has answered all\n        // pending approval requests on the last assistant message, send the\n        // responses back so the SDK resumes (runs or skips the tool). Without\n        // this the approve/deny clicks wouldn't continue the turn.\n        sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,\n      });\n      chatsRef.current.set(tabId, created);\n      return created;\n    },\n    [buildTransport],\n  );\n\n  const activeChat = getChat(activeTabId || 'temp-id');\n\n  const { messages, sendMessage, status, setMessages, stop, regenerate, error, clearError, addToolApprovalResponse } = useChat({\n    chat: activeChat,\n    // Throttle UI updates while streaming. Default 50ms (~20Hz) for snappy\n    // streaming — safe because rendering is targeted (only the active message\n    // bubble re-renders per tick; see message-item.tsx). Host-tunable.\n    experimental_throttle: config?.streamingThrottleMs ?? 50,\n  });\n\n  // Keep the live status mirror in sync (see statusRef above).\n  useEffect(() => {\n    statusRef.current = status;\n  }, [status]);\n\n  // Single activation point for changing the active tab: writes the live ref\n  // SYNCHRONOUSLY (before React re-renders) so any in-flight load's staleness\n  // check compares against the real active tab, then updates state. Every\n  // path that changes the active tab MUST go through this.\n  const activateTab = (tabId: string) => {\n    activeTabIdRef.current = tabId;\n    setActiveTabId(tabId);\n  };\n\n  // (There is deliberately no abort-on-activation here. Each tab owns its own\n  // Chat instance, so a background stream writes into its own message list and\n  // cannot contaminate the tab you switched to — the reason the abort existed.\n  // Streams now survive a tab switch, which is the point: the server never\n  // cancelled them anyway, so aborting only threw away an answer the user had\n  // already paid for.)\n\n  // Approve / deny a paused tool (human-in-the-loop). Passed down to the tool\n  // renderer; the SDK auto-resumes via sendAutomaticallyWhen above.\n  const handleToolApproval = useCallback(\n    (approvalId: string, approved: boolean) => {\n      addToolApprovalResponse({ id: approvalId, approved });\n    },\n    [addToolApprovalResponse],\n  );\n\n  // Synchronous in-flight latch for handleSubmit. `status` only flips to\n  // 'submitted' once sendMessage() runs — which, with attachments, is AFTER\n  // the entire upload round-trip. For that whole window `status` still reads\n  // 'ready', so a second Enter (or a starter-prompt double-click — they all\n  // funnel through handleSubmit) would start a parallel upload and a\n  // duplicate turn. A ref flips synchronously and closes the window.\n  const submittingRef = useRef(false);\n\n  const handleSubmit = async (message: PromptInputMessage) => {\n    // Ignore submits while a turn is in flight. The send button already swaps to\n    // a Stop button when streaming, but pressing Enter bypasses the button and\n    // calls form.requestSubmit() directly — so without this guard a user could\n    // queue a second message (or several) mid-response. This is the single choke\n    // point both Enter and the button funnel through, so guarding here covers\n    // every submission path. To interrupt, the user uses the Stop button.\n    if (submittingRef.current || status === 'submitted' || status === 'streaming') {\n      return false;\n    }\n\n    const hasText = Boolean(message.text);\n    const hasAttachments = Boolean(message.files?.length);\n\n    if (!(hasText || hasAttachments)) {\n      return false;\n    }\n\n    submittingRef.current = true;\n    // Sending ends dictation: the text being sent is what is on screen now.\n    dictation.stop();\n    try {\n\n    // Upload files to Supabase first if there are attachments\n    let uploadedFiles: any[] = [];\n    if (message.files && message.files.length > 0) {\n      try {\n        // Upload all files in parallel for better performance\n        const uploadPromises = message.files.map(async (file) => {\n          try {\n            // Convert blob URL back to File object\n            const response = await fetch(file.url);\n            const blob = await response.blob();\n            const fileObj = new File([blob], file.filename || 'unknown', { type: file.mediaType });\n\n            // Upload to our API\n            const formData = new FormData();\n            formData.append('file', fileObj);\n            formData.append('conversationId', activeTabId || 'default');\n            const uploadResponse = await fetch(`${apiBase}/upload`, {\n              method: 'POST',\n              headers: config?.headers,\n              body: formData,\n              credentials: config?.requestCredentials\n            });\n\n            if (!uploadResponse.ok) {\n              const errorText = await uploadResponse.text().catch(() => '<unreadable body>');\n              console.error(`Upload failed for ${file.filename}:`, errorText);\n              return null; // Return null for failed uploads\n            }\n\n            const uploadResult = await uploadResponse.json();\n            return {\n              id: (file as any).id || 'unknown',\n              type: 'file',\n              url: uploadResult.url,\n              storagePath: uploadResult.storagePath,\n              filename: uploadResult.filename,\n              mediaType: uploadResult.mediaType,\n              size: uploadResult.size\n            };\n          } catch (error) {\n            console.error(`Error uploading ${file.filename}:`, error);\n            return null; // Return null for failed uploads\n          }\n        });\n\n        // Wait for all uploads to complete\n        const results = await Promise.all(uploadPromises);\n\n        // Filter out null results (failed uploads)\n        uploadedFiles = results.filter(result => result !== null);\n\n        // If no files uploaded successfully, abort the send. Throwing (rather\n        // than returning) lets PromptInput keep the attachments mounted so the\n        // user can retry instead of having to re-pick every file.\n        if (uploadedFiles.length === 0) {\n          throw new Error('All file uploads failed. Please try again.');\n        }\n\n        // If only some files uploaded, show warning to user\n        if (uploadedFiles.length < message.files.length) {\n          const warnMsg = `Warning: Only ${uploadedFiles.length} of ${message.files.length} files uploaded successfully.`;\n          setUploadError(warnMsg);\n          console.warn(warnMsg);\n        }\n\n      } catch (error) {\n        const errorMsg =\n          error instanceof Error\n            ? error.message\n            : 'Error uploading files. Please try again.';\n        setUploadError(errorMsg);\n        console.error('Error in file upload process:', error);\n        // Re-throw so PromptInput's submit handler preserves the attachments\n        // for retry instead of clearing them. (The finally below still clears\n        // the in-flight latch on this path.)\n        throw error instanceof Error ? error : new Error(errorMsg);\n      }\n    }\n\n    sendMessage({\n      text: message.text || 'Sent with attachments',\n      files: uploadedFiles\n    });\n    // Model and webSearch are sent via transport's prepareSendMessagesRequest using refs\n\n    // No optimistic prefix title (removed): the tab stays \"New Chat\" until the\n    // server's generated thread title arrives as a data-thread-title part a few\n    // seconds after the first answer. Keeping the default is what lets the\n    // server retry naming on the next turn if generation ever fails.\n\n    setInput('');\n    // The sent message is no longer a draft.\n    const sentDraftKey = draftKey(activeTabId);\n    if (sentDraftKey) safeSession.remove(sentDraftKey);\n    // StickToBottom handles scrolling automatically\n\n    } finally {\n      submittingRef.current = false;\n    }\n  };\n\n  // Centralized function to load a conversation's messages\n  const loadConversation = async (conversationId: string) => {\n    // A tab's Chat outlives every switch away from it, so re-entering a tab is\n    // NOT a reason to refetch: its messages are already in its own instance.\n    // Refetching would overwrite them — and if the tab is mid-answer, it would\n    // replace a live streaming message with the last persisted state, which is\n    // exactly the \"switch back and the answer is gone\" bug this change fixes\n    // (the server has not written the assistant turn yet).\n    const chat = chatsRef.current.get(conversationId);\n    if (chat && (chat.messages.length > 0 || chat.status === 'submitted' || chat.status === 'streaming')) {\n      return;\n    }\n\n    // Staleness guard: this load only gets to write state while it is BOTH the\n    // latest load started (gen) and loading the tab that is still active\n    // (activeTabIdRef). Otherwise a slow fetch for a previously-viewed tab\n    // would overwrite the current tab's messages and corrupt the reverse-\n    // pagination cursor. Checked after EVERY await.\n    const gen = ++loadGenRef.current;\n    const isCurrent = () =>\n      mountedRef.current &&\n      gen === loadGenRef.current &&\n      conversationId === activeTabIdRef.current;\n\n    try {\n      // Initial load: only the most-recent page. Older messages stream in as the\n      // user scrolls up (loadOlderMessages), so a long conversation opens fast\n      // and pinned to the bottom instead of pulling its whole history at once.\n      // conversationId/userId are free-form host-supplied strings (emails with\n      // '+', ids with '/', '#'…) — encode them or the URL truncates/mis-routes.\n      // The userId param is informational only (identity is server-verified);\n      // cache:'no-store' keeps one user's history out of any intermediary\n      // cache regardless of response-header handling.\n      const response = await fetch(\n        `${apiBase}/history/${encodeURIComponent(conversationId)}?limit=${HISTORY_PAGE_SIZE}`,\n        { cache: 'no-store', headers: config?.headers, credentials: config?.requestCredentials },\n      );\n      if (!isCurrent()) return;\n      if (response.ok) {\n        const data = await response.json();\n        if (!isCurrent()) return;\n        const loadedMessages = data.messages || [];\n\n        // The server owns the opaque composite cursor (timestamp + message id).\n        historyCursorRef.current = typeof data.nextCursor === 'string' ? data.nextCursor : null;\n        setHasMoreHistory(Boolean(data.hasMore));\n        // Safe to apply immediately: by the time the fetch resolved, the\n        // render that re-keyed useChat to this conversation has long since\n        // committed, and isCurrent() above proves this tab is still active.\n        setMessages(loadedMessages);\n      } else if (response.status === 404) {\n        // Conversation doesn't exist yet - this is normal for new chats.\n        // Fresh conversations start from the host's initialMessages seed\n        // (usually undefined → empty).\n        historyCursorRef.current = null;\n        setHasMoreHistory(false);\n        setMessages(initialMessagesRef.current ?? []);\n      } else {\n        console.error('Error loading messages:', response.status, response.statusText);\n      }\n    } catch (error) {\n      if (!isCurrent()) return;\n      console.error('Error loading conversation:', error);\n    }\n  };\n\n  // Fetch the previous page of history (older messages) and PREPEND it. Called\n  // when the user scrolls near the top. Compensates the scroll position so the\n  // viewport stays put as content is inserted above it (no jump). Guarded by a\n  // ref so overlapping scroll events don't double-fetch the same page.\n  const scrollViewportRef = useRef<HTMLElement | null>(null);\n  const loadOlderMessages = useCallback(async () => {\n    if (loadingOlderRef.current || !hasMoreHistory || !historyCursorRef.current) return;\n    if (!activeTabId) return;\n    loadingOlderRef.current = true;\n    setLoadingOlder(true);\n\n    // The page we fetch belongs to THIS conversation. If the user switches\n    // tabs while the fetch is in flight, dropping the result is the only\n    // correct move — prepending it would splice another conversation's\n    // messages (and cursor) into the newly-active tab.\n    const conversationId = activeTabId;\n    const isCurrent = () => mountedRef.current && conversationId === activeTabIdRef.current;\n\n    const viewport = scrollViewportRef.current;\n    const prevScrollHeight = viewport?.scrollHeight ?? 0;\n    const prevScrollTop = viewport?.scrollTop ?? 0;\n\n    try {\n      const res = await fetch(\n        `${apiBase}/history/${encodeURIComponent(activeTabId)}` +\n          `?limit=${HISTORY_PAGE_SIZE}&cursor=${encodeURIComponent(historyCursorRef.current)}`,\n        { cache: 'no-store', headers: config?.headers, credentials: config?.requestCredentials },\n      );\n      if (!res.ok || !isCurrent()) return;\n      const data = await res.json();\n      if (!isCurrent()) return;\n      const older = data.messages || [];\n      if (older.length === 0) {\n        setHasMoreHistory(false);\n        return;\n      }\n      historyCursorRef.current =\n        typeof data.nextCursor === 'string' ? data.nextCursor : historyCursorRef.current;\n      setHasMoreHistory(Boolean(data.hasMore));\n      // Prepend, de-duping by id (defensive against overlap at the boundary).\n      setMessages((prev) => {\n        const existing = new Set(prev.map((m) => m.id));\n        const fresh = older.filter((m: { id: string }) => !existing.has(m.id));\n        return [...fresh, ...prev];\n      });\n      // After the prepend renders, restore scroll so the viewport doesn't jump:\n      // new scrollTop = old scrollTop + (new height − old height).\n      requestAnimationFrame(() => {\n        const v = scrollViewportRef.current;\n        if (v) v.scrollTop = prevScrollTop + (v.scrollHeight - prevScrollHeight);\n      });\n    } catch (err) {\n      console.error('Error loading older messages:', err);\n    } finally {\n      loadingOlderRef.current = false;\n      setLoadingOlder(false);\n    }\n  }, [hasMoreHistory, config?.apiBase, config?.headers, config?.requestCredentials, activeTabId, setMessages]);\n\n  // Tab management functions\n  // Generate unique tab ID with better collision avoidance\n  const generateUniqueTabId = (): string => {\n    let newTabId: string;\n    let attempts = 0;\n    do {\n      newTabId = `chat-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n      attempts++;\n    } while (tabs.find(tab => tab.id === newTabId) && attempts < 10);\n    \n    if (attempts >= 10) {\n      throw new Error('Unable to generate unique tab ID');\n    }\n    \n    return newTabId;\n  };\n\n  const createNewTab = useCallback(() => {\n    // Additional safeguard: prevent creating tabs if we're still loading\n    if (!initialTabCreated) {\n      console.warn('Cannot create new tab while initializing');\n      return;\n    }\n\n    // A new tab gets its own Chat instance, so it cannot inherit the previous\n    // tab's in-flight stream — that stream keeps running in its own tab.\n\n    // Generate a unique ID for the new tab\n    const newTabId = generateUniqueTabId();\n\n    setTabs(prevTabs => {\n      // Check if tab with this ID already exists using prevTabs (current state)\n      const existingTab = prevTabs.find(tab => tab.id === newTabId);\n      if (existingTab) {\n        console.warn('Tab with ID already exists:', newTabId);\n        return prevTabs; // Return unchanged\n      }\n\n      const newTab: ChatTab = {\n        id: newTabId,\n        title: 'New Chat',\n        isActive: true,\n      };\n\n      // Save current tab's state before switching\n      const updatedTabs = prevTabs.map(tab => ({\n        ...tab,\n        isActive: false,\n      }));\n\n      return [...updatedTabs, newTab];\n    });\n\n    activateTab(newTabId);\n    // New conversations start from the host's initialMessages seed (usually\n    // undefined → empty) — same as the 404 path in loadConversation.\n    setMessages(initialMessagesRef.current ?? []);\n    setInput('');\n  }, [initialTabCreated]);\n\n  const startNewConversation = useCallback(() => {\n    createNewTab();\n  }, [createNewTab]);\n\n  // Identity-change teardown: when the (agent, user) scope changes WITHOUT a\n  // full page reload (e.g. user switches account in-app), clear the previous\n  // scope's persisted keys so the new identity never inherits stale tabs.\n  const prevPrefixRef = useRef<string | null>(storageKeyPrefix);\n  useEffect(() => {\n    const prev = prevPrefixRef.current;\n    if (prev && prev !== storageKeyPrefix) {\n      const stalePrefix = `chat-${prev}-`;\n      safeStorage\n        .keys()\n        .filter((k) => k.startsWith(stalePrefix))\n        .forEach((k) => safeStorage.remove(k));\n    }\n    prevPrefixRef.current = storageKeyPrefix;\n  }, [storageKeyPrefix]);\n\n  const switchToTab = async (tabId: string) => {\n    const targetTab = tabs.find(tab => tab.id === tabId);\n    if (!targetTab) return;\n\n    // No abort here: the tab we are leaving keeps streaming into its own Chat.\n    // Come back mid-answer and it is still going.\n\n    // Update active tab (metadata only)\n    setTabs(prevTabs =>\n      prevTabs.map(tab => ({\n        ...tab,\n        isActive: tab.id === tabId,\n      }))\n    );\n\n    // Change active tab - useChat will reinitialize with new ID. Setting\n    // isLoadingMessages immediately gates the starter-prompt empty state\n    // so we don't flash it during the API fetch below.\n    activateTab(tabId);\n    setIsLoadingMessages(true);\n    try {\n      await loadConversation(tabId);\n    } finally {\n      setIsLoadingMessages(false);\n    }\n  };\n\n  const closeTab = (tabId: string) => {\n    if (tabs.length <= 1) return; // Don't close the last tab\n\n    // A closed tab's draft goes with it.\n    const closedDraftKey = draftKey(tabId);\n    if (closedDraftKey) safeSession.remove(closedDraftKey);\n\n    // …and so does its Chat instance, or the registry would grow for the life\n    // of the session. Closing a tab IS the one place a stream should be\n    // abandoned: the user has dismissed the conversation.\n    //\n    // Note the server-side consequence changed: the handler now forwards the\n    // client abort to the model by default (`propagateClientAbort`), so the turn\n    // stops generating rather than running to completion, and history shows the\n    // *partial* answer it had produced. That is the deliberate trade — a\n    // dismissed conversation should not keep billing tokens nobody will read.\n    // Hosts that need the old finish-in-background behaviour opt out with\n    // `propagateClientAbort: false`.\n    const closedChat = chatsRef.current.get(tabId);\n    if (closedChat) {\n      if (closedChat.status === 'submitted' || closedChat.status === 'streaming') {\n        try {\n          closedChat.stop();\n        } catch {\n          /* best-effort — a failed abort must never block closing a tab */\n        }\n      }\n      chatsRef.current.delete(tabId);\n    }\n\n    const filteredTabs = tabs.filter(tab => tab.id !== tabId);\n\n    // If we're closing the active tab, switch to another tab\n    if (tabId === activeTabId && filteredTabs.length > 0) {\n      const newActiveTab = filteredTabs[0];\n\n      // Update tabs first\n      setTabs(filteredTabs.map(tab => ({\n        ...tab,\n        isActive: tab.id === newActiveTab.id\n      })));\n\n      // Then switch to the new active tab (this will load messages)\n      switchToTab(newActiveTab.id);\n    } else {\n      // Just remove the tab\n      setTabs(filteredTabs);\n    }\n\n    // Update localStorage immediately when tab is closed\n    const tabsKey = storageKey('tabs');\n    if (filteredTabs.length > 0 && tabsKey) {\n      safeStorage.set(tabsKey, JSON.stringify(filteredTabs));\n      if (tabId === activeTabId) {\n        const newActiveTab = filteredTabs[0];\n        const activeKey = storageKey('active-tab-id');\n        if (activeKey) safeStorage.set(activeKey, newActiveTab.id);\n      }\n    }\n  };\n\n  const fetchConversations = async () => {\n    if (historyLoaded) return; // Don't reload if already loaded\n\n    setLoadingHistory(true);\n    try {\n      const response = await fetch(\n        `${apiBase}/history`,\n        { cache: 'no-store', headers: config?.headers, credentials: config?.requestCredentials },\n      );\n\n      if (response.ok) {\n        const data = await response.json();\n        if (!mountedRef.current) return;\n        setConversations(data.conversations || []);\n        setHistoryLoaded(true);\n      } else {\n        console.error('[ChatInterface] Failed to fetch chat history, status:', response.status);\n        const errorText = await response.text().catch(() => '<unreadable body>');\n        console.error('[ChatInterface] Error response:', errorText);\n      }\n    } catch (error) {\n      console.error('[ChatInterface] Error fetching chat history:', error);\n    } finally {\n      if (mountedRef.current) setLoadingHistory(false);\n    }\n  };\n\n  useEffect(() => {\n    if (showHistory && !historyLoaded) {\n      fetchConversations();\n    }\n  }, [showHistory, historyLoaded]);\n\n  useEffect(() => {\n    if (!historyLoaded) {\n      fetchConversations();\n    }\n  }, [historyLoaded]);\n\n  // Note: Message loading is now handled in switchToTab function\n  // useChat will automatically manage messages when activeTabId changes\n\n  // Conversation component (StickToBottom) handles auto-scroll automatically during streaming\n\n  // Tab Persistence: Save tabs to localStorage with debouncing\n  // Only saves metadata (id, title, model, webSearch) - no messages\n  useEffect(() => {\n    if (tabs.length > 0) {\n      const timeoutId = setTimeout(() => {\n        const tabsKey = storageKey('tabs');\n        const activeKey = storageKey('active-tab-id');\n        if (tabsKey) safeStorage.set(tabsKey, JSON.stringify(tabs));\n        if (activeKey) safeStorage.set(activeKey, activeTabId);\n      }, 500); // Debounce 500ms\n\n      return () => clearTimeout(timeoutId);\n    }\n  }, [tabs, activeTabId, storageKeyPrefix]);\n\n  // Draft persistence: a half-typed message survives tab switches AND panel\n  // close/reopen (the popup unmounts this whole tree on close — losing the\n  // draft was the single most jarring data loss in the widget). Debounced;\n  // an empty input removes the key so abandoned tabs don't accrete junk.\n  useEffect(() => {\n    if (isInitializing) return; // never persist the pre-restore empty state\n    const key = draftKey(activeTabId);\n    if (!key) return;\n    const timeoutId = setTimeout(() => {\n      if (input) safeSession.set(key, input);\n      else safeSession.remove(key);\n    }, 300);\n    return () => clearTimeout(timeoutId);\n  }, [input, activeTabId, storageKeyPrefix, isInitializing]);\n\n  // Tab Persistence: restore tabs from localStorage. Runs once PER REAL SCOPE.\n  // If identity (agent, user) isn't known at mount, we provisionally start a\n  // clean tab but stay un-initialized, so when the prefix transitions\n  // null → real this effect re-runs and restores that scope's saved tabs.\n  useEffect(() => {\n    if (hasInitialized.current) return;\n\n    // A host-pinned conversation (the public `conversationId` prop — the\n    // ChatInterface `id`) wins over restored tabs: the widget opens ON that\n    // conversation, whether or not it exists server-side yet (a brand-new id\n    // 404s in loadConversation and starts from the initialMessages seed).\n    // Restored tabs would silently override the host's explicit navigation\n    // intent. Both props were previously accepted-but-ignored.\n    if (id) {\n      setTabs([{ id, title: 'Chat', isActive: true }]);\n      activateTab(id);\n      setInitialTabCreated(true);\n      hasInitialized.current = true;\n      return;\n    }\n\n    const startCleanTab = () => {\n      const initialTabId = `chat-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n      setTabs([{ id: initialTabId, title: 'New Chat', isActive: true }]);\n      activateTab(initialTabId);\n      setInitialTabCreated(true);\n      setIsInitializing(false);\n    };\n\n    // No complete identity yet → usable provisional clean tab, but DON'T mark\n    // initialized so restore can still happen once the scope is known.\n    if (!storageKeyPrefix) {\n      if (!initialTabCreated && tabs.length === 0) startCleanTab();\n      return;\n    }\n\n    const loadInitialTabs = () => {\n      const savedTabs = safeStorage.get(`chat-${storageKeyPrefix}-tabs`);\n      const savedActiveTabId = safeStorage.get(`chat-${storageKeyPrefix}-active-tab-id`);\n\n      if (savedTabs && savedTabs !== '[]') {\n        // Restore saved tabs. Don't flip isInitializing yet — the\n        // separate message-load effect below owns that, so the empty\n        // state stays gated until we know whether there are messages\n        // to render.\n        //\n        // Trust NOTHING about the stored shape. JSON.parse succeeding does\n        // not mean the value is a tab array: a corrupted write, another\n        // script sharing the key, or a legacy widget version's schema would\n        // all parse fine and then crash tabs.map() at render. Keep only\n        // structurally-valid entries, drop unknown fields, and recompute\n        // isActive from the restored active id (stored flags can be stale).\n        const parsed: unknown = JSON.parse(savedTabs);\n        const validTabs = (Array.isArray(parsed) ? parsed : []).filter(\n          (t): t is { id: string; title: string } =>\n            !!t &&\n            typeof (t as { id?: unknown }).id === 'string' &&\n            ((t as { id: string }).id.length > 0) &&\n            typeof (t as { title?: unknown }).title === 'string'\n        );\n        if (validTabs.length === 0) {\n          startCleanTab();\n          return;\n        }\n        // The stored active id must point at a restored tab — a stale or\n        // foreign value would key useChat to a tab that doesn't exist.\n        const activeId =\n          savedActiveTabId && validTabs.some((t) => t.id === savedActiveTabId)\n            ? savedActiveTabId\n            : validTabs[0].id;\n        setTabs(validTabs.map((t) => ({ id: t.id, title: t.title, isActive: t.id === activeId })));\n        activateTab(activeId);\n        setInitialTabCreated(true);\n      } else if (tabs.length === 0) {\n        // Clean start (no saved tabs) — create one empty tab and finish.\n        startCleanTab();\n      }\n    };\n\n    try {\n      loadInitialTabs();\n    } catch (err) {\n      // Corrupted stored JSON or similar — never leave the widget stuck on\n      // the loader OR tabless. The previous version of this catch logged\n      // \"falling back to a clean state\" without actually creating one,\n      // leaving zero tabs and useChat keyed to nothing.\n      console.error('[chat-widget] init failed, falling back to clean start:', err);\n      try {\n        startCleanTab();\n      } catch {\n        setIsInitializing(false);\n      }\n    }\n    // Only lock initialization once a REAL scope has been processed.\n    hasInitialized.current = true;\n    // Re-run when identity arrives (null → real). `id` is captured for lint\n    // completeness; the hasInitialized lock makes later changes no-ops (the\n    // prop is initial-only by contract).\n  }, [storageKeyPrefix, id]);\n\n  // Load messages for active tab when identity is fully resolved.\n  const hasLoadedInitialMessages = useRef(false);\n  useEffect(() => {\n    if (hasLoadedInitialMessages.current) return; // Only run once\n    if (!activeTabId) return; // Wait for activeTabId to be set\n\n    // Load the conversation messages, then flip isInitializing false. This\n    // keeps the empty-state gate closed until the saved messages render —\n    // otherwise the starter prompts flash for the duration of the fetch.\n    (async () => {\n      try {\n        await loadConversation(activeTabId);\n      } finally {\n        hasLoadedInitialMessages.current = true;\n        setIsInitializing(false);\n      }\n    })();\n  }, [activeTabId, storageKeyPrefix, id]);\n\n  // Handle state updates when active tab changes\n  // Messages are loaded in switchToTab function, not here\n  useEffect(() => {\n    if (isInitializing) return; // Don't sync during initialization\n\n    if (activeTabId && tabs.length > 0 && activeTabId !== lastSyncedTabId.current) {\n      lastSyncedTabId.current = activeTabId;\n      // Restore this tab's saved draft instead of unconditionally wiping the\n      // composer — switching tabs used to destroy a half-typed message.\n      const key = draftKey(activeTabId);\n      setInput((key && safeSession.get(key)) || '');\n    }\n  }, [activeTabId, isInitializing, tabs.length]); // Only depend on activeTabId\n\n  // Keep tab titles as default for now\n  // Tab title updates removed to fix chat flow\n\n  // Group and filter conversations\n  const groupedConversations = useMemo(() => {\n    const filtered = conversations.filter(conv =>\n      searchQuery === '' ||\n      conv.title.toLowerCase().includes(searchQuery.toLowerCase())\n    );\n\n    const groups: { [key: string]: Conversation[] } = {};\n    const now = new Date();\n    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n    const yesterday = new Date(today);\n    yesterday.setDate(yesterday.getDate() - 1);\n\n    filtered.forEach(conv => {\n      const convDate = new Date(conv.updated_at);\n      const diffTime = now.getTime() - convDate.getTime();\n      const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));\n      const diffWeeks = Math.floor(diffDays / 7);\n      const diffMonths = Math.floor(diffDays / 30);\n\n      let groupKey: string;\n\n      if (convDate >= today) {\n        groupKey = 'Today';\n      } else if (convDate >= yesterday) {\n        groupKey = 'Yesterday';\n      } else if (diffDays <= 7) {\n        // Show individual days for the past week\n        groupKey = `${diffDays}d ago`;\n      } else if (diffWeeks <= 4) {\n        // Show weeks for the past month\n        groupKey = `${diffWeeks}w ago`;\n      } else if (diffMonths <= 12) {\n        // Show months for the past year\n        groupKey = `${diffMonths}mo ago`;\n      } else {\n        // Show years for older\n        const diffYears = Math.floor(diffMonths / 12);\n        groupKey = `${diffYears}y ago`;\n      }\n\n      if (!groups[groupKey]) {\n        groups[groupKey] = [];\n      }\n      groups[groupKey].push(conv);\n    });\n\n    // Sort group keys in chronological order\n    const sortedGroups = Object.entries(groups).sort((a, b) => {\n      const order = ['Today', 'Yesterday'];\n      const aIndex = order.indexOf(a[0]);\n      const bIndex = order.indexOf(b[0]);\n\n      if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;\n      if (aIndex !== -1) return -1;\n      if (bIndex !== -1) return 1;\n\n      // Extract numbers for comparison\n      const aMatch = a[0].match(/(\\d+)([dw]|mo|y)/);\n      const bMatch = b[0].match(/(\\d+)([dw]|mo|y)/);\n\n      if (aMatch && bMatch) {\n        const aNum = parseInt(aMatch[1]);\n        const bNum = parseInt(bMatch[1]);\n        const aUnit = aMatch[2];\n        const bUnit = bMatch[2];\n\n        // Convert to days for comparison\n        const unitToDays: { [key: string]: number } = { 'd': 1, 'w': 7, 'mo': 30, 'y': 365 };\n        const aDays = aNum * unitToDays[aUnit];\n        const bDays = bNum * unitToDays[bUnit];\n\n        return aDays - bDays;\n      }\n\n      return 0;\n    });\n\n    return sortedGroups;\n  }, [conversations, searchQuery]);\n\n  // Stable regenerate handler so the memoized list / MessageItem don't see a\n  // new function reference each render.\n  const handleRegenerate = useCallback(() => {\n    // Defense in depth: the regenerate button only renders when the turn is\n    // done, but this callback is also handed to renderers that could invoke\n    // it at any time. Starting a second turn while one is streaming is the\n    // same contamination class as an un-aborted tab switch. (The error\n    // banner's retry path is separate and intentionally allows status\n    // 'error'.) Reads the live mirror, not the render-time status, because\n    // this callback is memoised.\n    if (statusRef.current !== 'ready') return;\n    regenerate?.();\n  }, [regenerate]);\n\n  // Reuse only generic transport headers for the best-effort feedback POST.\n  const feedbackHeaders = useMemo(\n    () => config?.headers ?? {},\n    [config?.headers],\n  );\n\n  // Smart thread titles: after the first exchange the handler renames the\n  // conversation server-side and appends a persistent `data-thread-title` part\n  // to the assistant message. Adopt it for the owning tab, replacing the\n  // optimistic first-message-prefix placeholder. The part is persisted with the\n  // message, so this also re-applies harmlessly on history reload.\n  useEffect(() => {\n    const last = messages[messages.length - 1];\n    if (status !== 'ready' || !last || last.role !== 'assistant') return;\n    const dataPart = (last.parts ?? []).find(\n      (part) => (part as { type?: string }).type === 'data-thread-title',\n    ) as { data?: { title?: unknown } } | undefined;\n    const rawTitle = dataPart?.data?.title;\n    const title = typeof rawTitle === 'string' ? rawTitle.trim() : '';\n    if (!title) return;\n    setTabs((prevTabs) =>\n      prevTabs.map((tab) =>\n        tab.id === activeTabId && tab.title !== title ? { ...tab, title } : tab,\n      ),\n    );\n  }, [messages, status, activeTabId]);\n\n  // Follow-up chips (#134): the handler appends a `data-follow-ups` part after\n  // the assistant's text settles, already filtered and capped server-side. The\n  // client just renders what it is served. Chips clear as soon as a new turn\n  // starts, so stale suggestions never sit above an in-flight response.\n  useEffect(() => {\n    const last = messages[messages.length - 1];\n    const settledAssistant = status === 'ready' && !!last && last.role === 'assistant';\n    if (!settledAssistant) {\n      if (followUpsForRef.current !== null) {\n        followUpsForRef.current = null;\n        setFollowUps([]);\n      }\n      return;\n    }\n\n    const dataPart = (last.parts ?? []).find(\n      (part) => (part as { type?: string }).type === 'data-follow-ups',\n    ) as { data?: { suggestions?: unknown } } | undefined;\n    // MAX_FOLLOW_UP_COUNT is a structural bound on untrusted parsed data, not a\n    // policy knob: how many to show is settled by runtime.followUps.max.\n    const suggestions = normalizeFollowUpSuggestions(\n      dataPart?.data?.suggestions,\n      MAX_FOLLOW_UP_COUNT,\n    );\n    followUpsForRef.current = suggestions.length > 0 ? last.id : null;\n    setFollowUps(suggestions);\n  }, [messages, status]);\n\n  const handleSelectConversation = async (selectedConversationId: string, conversationTitle: string) => {\n    try {\n      // Check if this conversation is already open in a tab\n      const existingTab = tabs.find(tab => tab.id === selectedConversationId);\n\n      if (existingTab) {\n        // Just switch to the existing tab\n        switchToTab(selectedConversationId);\n        setShowHistory(false);\n        return;\n      }\n\n      // Opening a conversation from history is an activation like any other —\n      // and like any other, the tab being left keeps its stream.\n\n      // Create a new tab with the loaded conversation metadata\n      const newTab: ChatTab = {\n        id: selectedConversationId,\n        title: conversationTitle,\n        isActive: true,\n      };\n\n      setTabs(prevTabs => {\n        // Save current tab's metadata before switching\n        const updatedTabs = prevTabs.map(tab => ({\n          ...tab,\n          isActive: false,\n        }));\n        return [...updatedTabs, newTab];\n      });\n\n      activateTab(selectedConversationId);\n\n      // Load messages using centralized function\n      await loadConversation(selectedConversationId);\n\n      // Close the history dropdown\n      setShowHistory(false);\n    } catch (error) {\n      console.error('Error loading conversation:', error);\n    }\n  };\n\n  const dropdownRef = useRef<HTMLDivElement>(null);\n  // The popover is anchored to the HEADER, not the history button (see the\n  // comment at its render site), so it is NOT a descendant of dropdownRef —\n  // the outside-click check must test both, or clicks inside the panel (the\n  // search field, scrollbar, empty states) read as \"outside\" and dismiss it.\n  const historyPanelRef = useRef<HTMLDivElement>(null);\n\n  // Close dropdown when clicking outside\n  useEffect(() => {\n    const handleClickOutside = (event: MouseEvent) => {\n      const target = event.target as Node;\n      const inButton = dropdownRef.current?.contains(target) ?? false;\n      const inPanel = historyPanelRef.current?.contains(target) ?? false;\n      if (!inButton && !inPanel) {\n        setShowHistory(false);\n      }\n    };\n\n    if (showHistory) {\n      document.addEventListener('mousedown', handleClickOutside);\n    }\n\n    return () => {\n      document.removeEventListener('mousedown', handleClickOutside);\n    };\n  }, [showHistory]);\n\n  // Whether to show the \"thinking\" loader. Naively gating on status==='submitted'\n  // leaves a visible gap: the first token flips status to 'streaming' (loader\n  // unmounts) but experimental_throttle delays the text paint by up to 200ms, so\n  // the user sees an empty bubble for a beat. Keep the loader up through that\n  // window — while submitted, OR while streaming but the assistant's last turn\n  // has produced nothing renderable yet (no text/tool/source/file parts). Tool\n  // calls and text both clear it the instant they render, so a legit tool-using\n  // turn doesn't hang the loader.\n  const lastMessage = messages.at(-1);\n  const lastAssistantHasContent = hasRenderableAssistantContent(lastMessage, config?.messagePartRenderers);\n  const showThinking =\n    status === 'submitted' || (status === 'streaming' && !lastAssistantHasContent);\n\n  // The AI SDK adds an empty assistant message before its first streamed part.\n  // Do not render that zero-height MessageItem while the planning indicator owns\n  // the slot: its assistant-after-user mt-4 would push the indicator down for one\n  // frame. The real assistant row takes over the same slot once content arrives.\n  const transcriptMessages = useMemo(\n    () => messagesForTranscript(messages, showThinking, config?.messagePartRenderers),\n    [messages, showThinking, config?.messagePartRenderers],\n  );\n\n  // Memoized message list. Each message is a memoized <MessageItem>; the SDK\n  // reuses old message refs and clones only the streaming (last) one, so only\n  // the active bubble re-renders per tick. Assistant turns render through the\n  // transcript (in-order text / compact tool rows / thinking) inside MessageItem.\n  const renderedMessages = useMemo(\n    () =>\n      transcriptMessages.map((m, i) => (\n        <MessageItem\n          key={m.id}\n          message={m}\n          isFirst={i === 0}\n          isLast={i === transcriptMessages.length - 1}\n          prevRole={i > 0 ? transcriptMessages[i - 1].role : undefined}\n          status={status}\n          toolRenderers={config?.toolRenderers}\n          actionRenderers={config?.actionRenderers}\n          messagePartRenderers={config?.messagePartRenderers}\n          onRegenerate={handleRegenerate}\n          onToolApproval={handleToolApproval}\n          feedbackEnabled={config?.feedback === true}\n          conversationId={activeTabId}\n          feedbackApiBase={config?.apiBase}\n          feedbackHeaders={feedbackHeaders}\n          feedbackCredentials={config?.requestCredentials}\n          onFeedback={config?.onFeedback}\n        />\n      )),\n    [transcriptMessages, status, config?.toolRenderers, config?.actionRenderers, config?.messagePartRenderers, handleRegenerate, handleToolApproval, config?.feedback, activeTabId, config?.apiBase, feedbackHeaders, config?.requestCredentials, config?.onFeedback],\n  );\n\n  // Seed the planning verb from the last USER message id: it exists from the\n  // moment of submit and doesn't change when the assistant message arrives,\n  // so the verb never flips mid-gap.\n  const lastUserMessageId = messages.findLast((m) => m.role === 'user')?.id ?? 'planning';\n  const planningVerb = pickPlanningVerb(lastUserMessageId);\n\n  return (\n    <div className=\"w-full h-full flex flex-col bg-[hsl(var(--chat-background))] overflow-hidden ring-1 ring-[hsl(var(--chat-border))]\">\n      <div className=\"flex flex-col h-full w-full overflow-hidden relative chat-widget-container\">\n        {/* Header Section with Tabs */}\n        {/* backdrop-blur removed: the header is a flex sibling of the scroll\n            area, nothing ever renders behind it — the blur was dead CSS\n            implying a frosted effect that never happened. */}\n        <div className=\"relative z-20 flex min-h-[52px] items-center gap-2 border-b px-3 py-2\" style={{\n          borderColor: 'hsl(var(--chat-border))',\n          backgroundColor: 'hsl(var(--chat-background))'\n        }}>\n          {/* Tabs Container with Scroll */}\n          <div\n            className=\"flex items-center gap-1 flex-1 min-w-0 overflow-x-auto scrollbar-hide py-0.5 scroll-smooth\"\n            role=\"tablist\"\n            aria-label=\"Conversations\"\n          >\n            {/* Apple-style Tab Pills */}\n            {tabs.map((tab) => (\n              <div\n                key={tab.id}\n                className={cn(\n                  'group relative flex min-w-0 flex-shrink-0 cursor-pointer items-center gap-1.5 rounded-lg px-3 py-1.5 transition-colors duration-150',\n                  tab.isActive\n                    ? 'bg-[hsl(var(--chat-hover-bg))] text-[hsl(var(--chat-text))]'\n                    : 'bg-transparent text-[hsl(var(--chat-text-muted))] hover:bg-[hsl(var(--chat-hover-bg))]',\n                )}\n                onClick={(e) => {\n                  e.stopPropagation();\n                  switchToTab(tab.id);\n                }}\n                // Keyboard operability: these pills were click-only <div>s —\n                // a keyboard user could not switch conversations at all.\n                role=\"tab\"\n                aria-selected={tab.isActive}\n                tabIndex={0}\n                onKeyDown={(e) => {\n                  if (e.key === 'Enter' || e.key === ' ') {\n                    e.preventDefault();\n                    switchToTab(tab.id);\n                  }\n                }}\n              >\n                {/* Tab Title */}\n                <span className=\"truncate max-w-28 text-[13px] font-medium transition-colors\">\n                  {tab.title}\n                </span>\n\n                {/* Close Button. Two rules learned the hard way:\n                    (1) while hidden it must be pointer-events-none — an\n                    invisible-but-tappable X swallowed touch taps meant to\n                    ACTIVATE the tab (touch has no hover to reveal it);\n                    (2) keyboard focus isn't blocked by pointer-events, and\n                    focus-visible re-reveals + re-enables it, so it stays\n                    keyboard-closable. Hover reveal rides the pill's `group`. */}\n                {tabs.length > 1 && (\n                  <button\n                    type=\"button\"\n                    aria-label={`Close ${tab.title}`}\n                    onClick={(e) => {\n                      e.stopPropagation();\n                      closeTab(tab.id);\n                    }}\n                    className={cn(\n                      'rounded-lg p-1 transition-all duration-150 flex-shrink-0 -mr-1',\n                      'hover:bg-[hsl(var(--chat-hover-bg))]',\n                      'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.4)]',\n                      tab.isActive\n                        ? 'opacity-60 hover:opacity-100 focus-visible:opacity-100'\n                        : 'opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-visible:opacity-100 focus-visible:pointer-events-auto'\n                    )}\n                  >\n                    <XIcon className=\"h-3 w-3\" strokeWidth={2.5} />\n                  </button>\n                )}\n              </div>\n            ))}\n          </div>\n\n          {/* Fixed Action Buttons */}\n          <div className=\"flex items-center gap-0.5 flex-shrink-0\">\n            {/* Plus Icon */}\n            <button\n              type=\"button\"\n              onClick={createNewTab}\n              aria-label=\"New chat\"\n              className=\"chat-header-icon-button flex size-7 items-center justify-center rounded-[7px] text-[hsl(var(--chat-text-faint))] transition-colors duration-150 hover:bg-[hsl(var(--chat-hover-bg))] hover:text-[hsl(var(--chat-text))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\"\n              title=\"New Chat\"\n            >\n              <SquarePenIcon className=\"size-[15px]\" strokeWidth={1.8} />\n            </button>\n\n            {/* History Icon */}\n            <div ref={dropdownRef}>\n              <button\n                type=\"button\"\n                onClick={() => setShowHistory(!showHistory)}\n                aria-label=\"Chat history\"\n                aria-expanded={showHistory}\n                className={cn(\n                  'chat-header-icon-button flex size-7 items-center justify-center rounded-[7px] transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]',\n                  showHistory\n                    ? 'bg-[hsl(var(--chat-hover-bg))] text-[hsl(var(--chat-text))]'\n                    : 'text-[hsl(var(--chat-text-faint))] hover:bg-[hsl(var(--chat-hover-bg))] hover:text-[hsl(var(--chat-text))]',\n                )}\n                title=\"Chat History\"\n              >\n                <HistoryIcon className=\"h-4 w-4\" strokeWidth={2} />\n              </button>\n            </div>\n\n            {/* Chat History Dropdown — anchored to the HEADER row, not the\n                history button. A right-0 origin on the button wrapper left the\n                popover starting from the button and extending past the widget's\n                left edge (clipped by the root overflow-hidden) once close /\n                header-action buttons sat to its right. Anchoring to the full\n                header makes right-0 the widget's right edge, so the popover\n                extends leftward only into the header width. */}\n            {showHistory && (\n              <div ref={historyPanelRef} className=\"absolute right-3 top-full z-50 mt-1.5 overflow-hidden rounded-[11px] shadow-[0_6px_20px_rgba(0,0,0,0.07)] animate-in fade-in slide-in-from-top-1 duration-150\" style={{\n                width: 'min(20rem, calc(100% - 1.5rem))',\n                backgroundColor: 'hsl(var(--chat-background))',\n                border: '1px solid hsl(var(--chat-border-soft))'\n              }}>\n                {/* The search field is the only inset surface; the surrounding\n                    header and results share the popover background so the panel\n                    remains visually continuous. */}\n                <div className=\"p-2.5 pb-2\" style={{ backgroundColor: 'hsl(var(--chat-background))' }}>\n                  <div className=\"relative\">\n                    {/* Centered via inset-y-0 + my-auto, NOT top-1/2/-translate-y-1/2:\n                        the translate utilities depend on @property-initialized\n                        --tw-* vars, which some host pages strip — leaving the icon\n                        pinned off-center (seen live on the demo). Auto margins\n                        need no custom properties. */}\n                    <SearchIcon\n                      className=\"pointer-events-none absolute left-2.5 inset-y-0 my-auto size-[13px] text-[hsl(var(--chat-text-faint))]\"\n                      aria-hidden=\"true\"\n                    />\n                    <input\n                      type=\"search\"\n                      placeholder=\"Search chats\"\n                      value={searchQuery}\n                      onChange={(e) => setSearchQuery(e.target.value)}\n                      aria-label=\"Search chats\"\n                      className=\"h-9 w-full rounded-[9px] bg-[hsl(var(--chat-surface))] pl-8 pr-2.5 text-[13px] text-[hsl(var(--chat-text))] placeholder:text-[hsl(var(--chat-text-subtle))] focus:outline-none focus:ring-2 focus:ring-[hsl(var(--chat-primary)/0.18)]\"\n                    />\n                  </div>\n                </div>\n\n                {/* Content Area */}\n                <div className=\"max-h-[300px] overflow-y-auto ai-assistant-scrollbar\">\n                  {loadingHistory ? (\n                    <div className=\"flex items-center justify-center py-12\">\n                      <div className=\"text-[13px]\" style={{ color: 'hsl(var(--chat-text-muted))' }}>Loading...</div>\n                    </div>\n                  ) : conversations.length === 0 ? (\n                    <div className=\"flex flex-col items-center justify-center py-12 px-4 text-center\">\n                      <div className=\"w-12 h-12 rounded-full flex items-center justify-center mb-3\" style={{\n                        backgroundColor: 'hsl(var(--chat-surface))'\n                      }}>\n                        <MessageSquareIcon className=\"h-5 w-5\" style={{ color: 'hsl(var(--chat-text-subtle))' }} strokeWidth={2} />\n                      </div>\n                      <p className=\"text-[13px] font-medium mb-0.5\" style={{ color: 'hsl(var(--chat-text))' }}>No Conversations</p>\n                      <p className=\"text-[12px]\" style={{ color: 'hsl(var(--chat-text-muted))' }}>Start a new chat to begin</p>\n                    </div>\n                  ) : groupedConversations.length === 0 ? (\n                    <div className=\"flex flex-col items-center justify-center py-12 px-4 text-center\">\n                      <div className=\"w-12 h-12 rounded-full flex items-center justify-center mb-3\" style={{\n                        backgroundColor: 'hsl(var(--chat-surface))'\n                      }}>\n                        <SearchIcon className=\"h-5 w-5\" style={{ color: 'hsl(var(--chat-text-subtle))' }} strokeWidth={2} />\n                      </div>\n                      <p className=\"text-[13px] font-medium mb-0.5\" style={{ color: 'hsl(var(--chat-text))' }}>No Results</p>\n                      <p className=\"text-[12px]\" style={{ color: 'hsl(var(--chat-text-muted))' }}>Try a different search</p>\n                    </div>\n                  ) : (\n                    <div className=\"py-0.5\">\n                      {groupedConversations.map(([groupName, groupConversations]) => (\n                        <div key={groupName} className=\"mb-0.5\">\n                          {/* Group Header */}\n                          {/* Sticky group header DOES overlay the scrolling\n                              list — a translucent background makes the\n                              backdrop blur real (it was inert behind an\n                              opaque fill). */}\n                          <div className=\"px-2.5 py-1 sticky top-0 backdrop-blur-sm z-10\" style={{\n                            backgroundColor: 'hsl(var(--chat-background) / 0.85)'\n                          }}>\n\n                            <h3 className=\"text-[10px] font-semibold uppercase tracking-[0.08em] text-[hsl(var(--chat-text-subtle))]\">{groupName}</h3>\n                          </div>\n\n                          {/* Conversation Items */}\n                          <div className=\"px-1 space-y-0.5\">\n                            {groupConversations.map((conversation) => {\n                              const isActiveConversation = activeTabId === conversation.id;\n                              return (\n                                <button\n                                  key={conversation.id}\n                                  type=\"button\"\n                                  className={cn(\n                                    'group relative w-full rounded-[10px] px-2.5 py-2 text-left transition-colors duration-150',\n                                    isActiveConversation\n                                      ? 'bg-[hsl(var(--chat-hover-bg))]'\n                                      : 'hover:bg-[hsl(var(--chat-surface))]',\n                                  )}\n                                  aria-current={isActiveConversation ? 'page' : undefined}\n                                  onClick={() => handleSelectConversation(conversation.id, conversation.title)}\n                                >\n                                  <div className=\"flex min-w-0 items-start gap-3\">\n                                    <div className=\"min-w-0 flex-1\">\n                                      <div className=\"flex min-w-0 items-center gap-2\">\n                                        <p\n                                          className={cn(\n                                            'min-w-0 flex-1 truncate text-[13px] leading-5',\n                                            isActiveConversation\n                                              ? 'font-semibold text-[hsl(var(--chat-text))]'\n                                              : 'font-medium text-[hsl(var(--chat-text-body))]',\n                                          )}\n                                        >\n                                          {conversation.title}\n                                        </p>\n                                        <time\n                                          dateTime={conversation.updated_at}\n                                          className=\"flex-shrink-0 font-mono text-[11px] text-[hsl(var(--chat-text-faint))]\"\n                                        >\n                                          {formatConversationTime(conversation.updated_at)}\n                                        </time>\n                                      </div>\n                                      <p className=\"truncate text-[12px] leading-4 text-[hsl(var(--chat-text-faint))]\">\n                                        {conversation.message_count} {conversation.message_count === 1 ? 'message' : 'messages'}\n                                      </p>\n                                    </div>\n                                  </div>\n                                </button>\n                              );\n                            })}\n                          </div>\n                        </div>\n                      ))}\n                    </div>\n                  )}\n                </div>\n              </div>\n            )}\n\n            {/* Consumer-supplied header actions (expand, settings, etc.)\n                rendered before the close button so they sit to its left. */}\n            {headerActions}\n\n            {/* Close Chat Widget Button */}\n            {onClose && (\n              <button\n                type=\"button\"\n                onClick={onClose}\n                aria-label=\"Close chat\"\n                className=\"chat-header-icon-button flex size-7 items-center justify-center rounded-[7px] text-[hsl(var(--chat-text-faint))] transition-colors duration-150 hover:bg-[hsl(var(--chat-hover-bg))] hover:text-[hsl(var(--chat-text))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\"\n                title=\"Close Chat\"\n              >\n                <XIcon className=\"h-4 w-4\" strokeWidth={2} />\n              </button>\n            )}\n          </div>\n        </div>\n\n        <Conversation\n          className=\"flex-1 max-w-full ai-assistant-scrollbar\"\n          // Capture the scroll viewport (StickToBottom owns it) so reverse-\n          // pagination can read/restore scroll position; trigger loadOlderMessages\n          // when scrolled near the top.\n          onScrollRef={(el) => {\n            scrollViewportRef.current = el;\n          }}\n          onScroll={(e: React.UIEvent<HTMLElement>) => {\n            const el = e.currentTarget;\n            if (el.scrollTop < 120 && hasMoreHistory && !loadingOlderRef.current) {\n              void loadOlderMessages();\n            }\n          }}\n        >\n          <ConversationContent className=\"max-w-[96%] mx-auto py-6\">\n            {hasMoreHistory && (\n              <div className=\"flex justify-center py-2\" aria-hidden={!loadingOlder}>\n                {loadingOlder && <Loader size={14} />}\n              </div>\n            )}\n            {renderedMessages}\n            {/* Follow-up suggestions (#134/#220) — a \"Related\" block attached\n                under the completed assistant reply, INSIDE the conversation so\n                it reads as part of the answer and scrolls away with it.\n                Tapping a row sends it as the next message. */}\n            {followUps.length > 0 && (\n              <FollowUpSuggestions\n                suggestions={followUps}\n                onSelect={(text) => {\n                  setFollowUps([]);\n                  followUpsForRef.current = null;\n                  void handleSubmit({ text });\n                }}\n              />\n            )}\n            {showThinking && (\n              // The ONLY pre-content indicator: a shimmering planning verb\n              // (\"One moment\", \"Working on it\", …) with no spinner. It uses the\n              // same assistant row + mt-4 geometry as the response that replaces\n              // it, so the submitted → empty-assistant → first-content transition\n              // never changes its vertical or horizontal anchor. The shimmer's\n              // transparent text color is protected by its scoped CSS selector.\n              <div className=\"mt-4\">\n                <Message from=\"assistant\">\n                  <MessageContent>\n                    <TextShimmer as=\"span\" className=\"text-[13px] font-medium leading-relaxed\">\n                      {planningVerb}\n                    </TextShimmer>\n                  </MessageContent>\n                </Message>\n              </div>\n            )}\n          </ConversationContent>\n          <ConversationScrollButton />\n        </Conversation>\n\n        <div className=\"px-5 pb-5\">\n          {/* Upload Error Display — themed via the semantic danger token\n              (raw red-* utilities keyed to the OS dark: variant clashed with\n              custom themes and disagreed with ChatErrorBanner below). */}\n          {uploadError && (\n            <div\n              role=\"alert\"\n              className=\"mb-3 px-4 py-3 rounded-2xl text-sm shadow-sm\"\n              style={{\n                backgroundColor: 'hsl(var(--chat-danger) / 0.08)',\n                border: '1px solid hsl(var(--chat-danger) / 0.25)',\n                color: 'hsl(var(--chat-danger))',\n              }}\n            >\n              {uploadError}\n            </div>\n          )}\n          {dictation.notice && (\n            <div\n              role=\"alert\"\n              className=\"mb-3 px-4 py-3 rounded-2xl text-sm shadow-sm\"\n              style={{\n                backgroundColor: 'hsl(var(--chat-danger) / 0.08)',\n                border: '1px solid hsl(var(--chat-danger) / 0.25)',\n                color: 'hsl(var(--chat-danger))',\n              }}\n            >\n              {dictation.notice}\n            </div>\n          )}\n\n          {/* While we're still hydrating tabs from localStorage and the\n              active tab from the API, hold render so we don't briefly flash\n              the starter prompts before the previous conversation arrives.\n              Once initialised, either show prompts (if truly empty) or the\n              messages above this block. */}\n          {(isInitializing || isLoadingMessages) ? (\n            <div className=\"flex items-center justify-center py-8\" role=\"status\" aria-label=\"Loading conversation\">\n              <div className=\"h-4 w-4 rounded-full border-2 border-current border-t-transparent animate-spin\" style={{ color: 'hsl(var(--chat-text-muted))' }} />\n            </div>\n          ) : (\n            messages.length === 0 && status !== 'submitted' &&\n            ((effectiveStarterPrompts && effectiveStarterPrompts.length > 0) || config?.capabilitiesPrompt || config?.greeting || config?.subGreeting) ? (\n              <div className=\"mb-1 flex flex-col gap-4\">\n                {/* Empty-state greeting — a strong headline plus an optional faint\n                    sub line. Both optional via config (greeting / subGreeting);\n                    when neither is set the block collapses and only the starter\n                    prompts show, so existing embeds are unaffected. `assistantName`\n                    is identity, not part of this block. */}\n                {(config?.greeting || config?.subGreeting) && (\n                  <div className=\"px-1\">\n                    <h2\n                      className=\"text-[17px] font-semibold leading-tight text-[hsl(var(--chat-text))]\"\n                      style={{ letterSpacing: '-0.01em' }}\n                    >\n                      {config?.greeting || 'How can I help?'}\n                    </h2>\n                    {config?.subGreeting && (\n                      <p className=\"mt-1 text-[13px] text-[hsl(var(--chat-text-faint))]\">\n                        {config.subGreeting}\n                      </p>\n                    )}\n                  </div>\n                )}\n                {effectiveStarterPrompts && effectiveStarterPrompts.length > 0 && (\n                  <StarterMessages\n                    prompts={effectiveStarterPrompts}\n                    layout={config?.starterPromptsLayout ?? 'list'}\n                    onPromptSelect={(prompt) => {\n                      handleSubmit({ text: prompt.title });\n                    }}\n                  />\n                )}\n                {/* Always-available \"capability discoverability\" onramp (#164).\n                    Opt-in via config.capabilitiesPrompt; sends that prompt as\n                    the user's message so a blank input never strands the user. */}\n                {config?.capabilitiesPrompt && (\n                  <button\n                    type=\"button\"\n                    onClick={() => handleSubmit({ text: config.capabilitiesPrompt })}\n                    className=\"mx-3 mb-3 text-[12px] underline underline-offset-2 text-[hsl(var(--chat-text)/0.45)] hover:text-[hsl(var(--chat-text)/0.7)] transition-colors\"\n                  >\n                    Not sure where to start?\n                  </button>\n                )}\n              </div>\n            ) : null\n          )}\n\n          {/* Inline error banner — appears between the message stream\n              and the input when a stream errored / disconnected. */}\n          <ChatErrorBanner\n            error={error ?? null}\n            canRetry={messages.some((m) => m.role === 'user')}\n            onRetry={() => {\n              clearError?.();\n              regenerate?.();\n            }}\n            onDismiss={clearError}\n          />\n\n          {/* Inline mention/command panel — renders above the input\n              when an InputPlugin is active. Same layout slot as the\n              StarterMessages so the visual language stays consistent. */}\n          {inputPlugins.panel}\n\n          <PromptInput\n            onSubmit={handleSubmit}\n            className=\"chat-prompt-box\"\n            globalDrop\n            multiple\n            accept={features.fileUploadAccept}\n            maxFileSize={features.fileUploadMaxBytes}\n            onError={(err) => {\n              if (err.code === 'max_file_size') {\n                setUploadError(\n                  features.fileUploadMaxBytes\n                    ? `File too large (max ${Math.floor(\n                        features.fileUploadMaxBytes / 1024 / 1024,\n                      )} MB).`\n                    : 'File too large.',\n                );\n              } else if (err.code === 'accept') {\n                setUploadError('That file type is not supported.');\n              } else if (err.code === 'max_files') {\n                setUploadError('Too many files attached.');\n              }\n            }}\n          >\n            <PromptInputBody>\n              <PromptInputAttachments>\n                {(attachment) => <PromptInputAttachment data={attachment} />}\n              </PromptInputAttachments>\n              {/* Two-zone composer: the editor sits on its own row; a bottom\n                  action row carries attach on the left and send on the right.\n                  `chat-prompt-box` supplies one quiet bordered surface and a\n                  token-derived focus ring in every theme. */}\n              <PromptInputTextarea\n                ref={inputRef}\n                onChange={(e) => {\n                  // A manual edit (typing, paste, cut) ends dictation first\n                  // so the recognizer can't overwrite what the user just did.\n                  dictation.onManualEdit();\n                  setInput(e.target.value);\n                }}\n                onKeyDown={(e) => {\n                  // Input plugins own the keys while their panel is open;\n                  // dictation only takes Escape when nothing else claimed it.\n                  inputPlugins.onKeyDown(e);\n                  if (!e.defaultPrevented) dictation.onKeyDown(e);\n                }}\n                placeholder={dictation.state === 'listening' && !input ? 'Listening…' : undefined}\n                value={input}\n                className=\"min-h-0 w-full px-3.5 pt-3 pb-1 text-[13.5px] leading-6\"\n              />\n              <div className=\"flex items-center gap-1.5 px-2.5 pb-2.5\">\n                {features.fileUpload && <AttachButton />}\n                {/* Right cluster: actions on the message. Dictation sits\n                    immediately left of Send — the convention users know from\n                    every mainstream chat composer — while Attach stays on the\n                    left with the other \"add to message\" controls. */}\n                <div className=\"ml-auto flex items-center gap-1.5\">\n                  {features.voiceInput && <DictationButton dictation={dictation} />}\n                  <PromptInputSubmit\n                    // Filled circular send button, right-aligned in the action row.\n                    // Colors come entirely from the Button default variant tokens\n                    // (bg-primary / text-primary-foreground / disabled:opacity-50).\n                    className=\"size-8 rounded-full p-0 [&_svg]:size-3.5\"\n                    disabled={status === 'streaming' || status === 'submitted' ? false : !input}\n                    status={status}\n                    onStop={stop}\n                  />\n                </div>\n              </div>\n            </PromptInputBody>\n          </PromptInput>\n        </div>\n      </div>\n    </div>\n  );\n}","export const DEFAULT_FOLLOW_UP_COUNT = 3;\nexport const MAX_FOLLOW_UP_COUNT = 5;\nexport const MAX_FOLLOW_UP_CHARS = 160;\n\n/** JSON-safe follow-up config stored in a hosted agent version. */\nexport interface SerializedFollowUpConfig {\n  enabled?: boolean;\n  max?: number;\n  timeoutMs?: number;\n}\n\n/** Normalize an untrusted hosted/config blob without allowing functions through. */\nexport function normalizeSerializedFollowUpConfig(\n  value: unknown,\n): boolean | SerializedFollowUpConfig | null {\n  if (typeof value === 'boolean') return value;\n  if (!value || typeof value !== 'object' || Array.isArray(value)) return null;\n  const raw = value as Record<string, unknown>;\n  return {\n    ...(typeof raw.enabled === 'boolean' ? { enabled: raw.enabled } : {}),\n    ...(typeof raw.max === 'number' && Number.isFinite(raw.max) ? { max: raw.max } : {}),\n    ...(typeof raw.timeoutMs === 'number' && Number.isFinite(raw.timeoutMs)\n      ? { timeoutMs: raw.timeoutMs }\n      : {}),\n  };\n}\n\n/** Clamp a public max setting to the small, bounded chip range the UI supports. */\nexport function resolveFollowUpCount(value: unknown): number {\n  if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_FOLLOW_UP_COUNT;\n  return Math.min(MAX_FOLLOW_UP_COUNT, Math.max(1, Math.floor(value)));\n}\n\n/** Keep model/host output compact, de-duplicated, and free of multiline noise. */\nexport function normalizeFollowUpSuggestions(value: unknown, max: number): string[] {\n  if (!Array.isArray(value)) return [];\n  const limit = resolveFollowUpCount(max);\n  const seen = new Set<string>();\n  const clean: string[] = [];\n\n  for (const item of value) {\n    if (typeof item !== 'string') continue;\n    const text = item.replace(/\\s+/g, ' ').trim().slice(0, MAX_FOLLOW_UP_CHARS).trim();\n    if (!text) continue;\n    const key = text.toLocaleLowerCase();\n    if (seen.has(key)) continue;\n    seen.add(key);\n    clean.push(text);\n    if (clean.length >= limit) break;\n  }\n  return clean;\n}\n","// Built-in page-context capture for the `context: 'auto'` prop (#239).\n//\n// A docs host that wants the assistant to know which page the user is on would\n// otherwise have to hand-wire `context={{ route: location.pathname }}` and keep\n// it fresh across SPA navigation. `context: 'auto'` captures that shape for\n// them; this module is the single source of what \"auto\" means.\n//\n// SECURITY: the captured object is CLIENT-controlled input, exactly like a\n// hand-written `context` object. It changes nothing about the server trust\n// boundary — the handler still only sees it when it opts in via a server-side\n// `getContext` or `trustClientContext: true` (see ChatWidgetConfig.context).\n//\n// To keep that boundary safe the DEFAULT capture is deliberately narrow:\n// `origin + pathname`, the pathname, and the title — never the query string and\n// (almost) never the fragment. Query strings and fragments routinely carry\n// password-reset tokens, OAuth `state`/`code`, signed-URL signatures, tenant\n// ids, raw search text, and client-side router state; shipping those to a model\n// provider (once a host flips on `trustClientContext`) would be a real leak. A\n// fragment is included ONLY when it looks like a plain docs anchor (see\n// `isSafeAnchorHash`); anything token- or router-state-shaped is dropped.\n//\n// We also capture no identity data: no cookies, no `document.referrer`, no\n// `navigator.userAgent`. Hosts that genuinely need the query string or a\n// non-anchor fragment opt in EXPLICITLY through the function form\n// (`buildAutoPageContext({ includeQuery: true })`) — never the bare `'auto'`\n// string literal, which always uses the safe defaults.\n\nimport type { ChatContext } from '../types';\n\n/**\n * Options for {@link buildAutoPageContext}. Both default to the safe capture;\n * set them only when the host has decided the extra data is safe to send to the\n * model provider under its `trustClientContext` / `getContext` policy.\n */\nexport interface AutoPageContextOptions {\n  /**\n   * Append the query string (`?...`) to the captured `url` AND expose it as a\n   * separate `query` field (the raw `location.search`, including the leading\n   * `?`). Default `false` — the query string is stripped entirely because it\n   * routinely carries reset tokens, OAuth `state`/`code`, signed-URL\n   * signatures, and PII in search params.\n   */\n  includeQuery?: boolean;\n  /**\n   * Bypass the conservative safe-anchor heuristic and capture the fragment\n   * (`#...`) verbatim whenever one is present. Default `false` — by default a\n   * fragment is captured ONLY when {@link isSafeAnchorHash} accepts it (a plain\n   * docs anchor), so token-bearing / router-state fragments are dropped.\n   */\n  includeHash?: boolean;\n}\n\n// A fragment we are willing to ship by default: a plain in-page anchor such as\n// `#installation` or `#step-2.1`. Deliberately conservative — it must start\n// with an alphanumeric, be at most 129 chars total (`#` + up to 128), and use\n// only a restricted anchor alphabet. The explicit exclusions below then reject\n// anything shaped like query data or a route/state payload:\n//   - `=` / `&` / `?` → `#access_token=…&state=…` (OAuth implicit flow, forms)\n//   - `/`             → `#/app/users/42` (hash-router state, deep links)\n// Token/state fragments fail on both the alphabet AND these exclusions, so they\n// are dropped and the caller must opt in via `includeHash: true` to send them.\nconst SAFE_ANCHOR_RE = /^#[A-Za-z0-9][A-Za-z0-9\\-_.:]{0,128}$/;\n\n/**\n * True when `hash` (including its leading `#`) looks like a plain docs anchor\n * safe to include by default — NOT a token-bearing or router-state fragment.\n *\n * Rejects (→ dropped from the default capture): empty/`\"#\"`, anything\n * containing `=`, `&`, `?`, or `/` (query- or route-shaped), fragments longer\n * than 128 chars after the `#`, and anything using characters outside the\n * restricted anchor alphabet (e.g. `%`, spaces, `#access_token=…`).\n */\nexport function isSafeAnchorHash(hash: string): boolean {\n  if (!hash || hash === '#') return false;\n  // Defense-in-depth: the regex already excludes these, but assert the intent\n  // explicitly so the exclusion set is obvious and independently guaranteed.\n  if (\n    hash.includes('=') ||\n    hash.includes('&') ||\n    hash.includes('?') ||\n    hash.includes('/')\n  ) {\n    return false;\n  }\n  return SAFE_ANCHOR_RE.test(hash);\n}\n\n/**\n * Snapshot the current page location as a {@link ChatContext}.\n *\n * Read from `window.location` / `document` at call time, so calling it AT SEND\n * TIME reflects SPA route changes between messages. Every browser global is\n * guarded, so this is safe to call during SSR / in a non-browser runtime — it\n * returns `{}` there rather than throwing (no `window`/`document` access\n * outside the guards).\n *\n * Captured fields — the SAFE DEFAULT deliberately excludes the query string and\n * non-anchor fragments (see the security note above):\n * - `url`   — `origin + pathname` (NO query, NO fragment)\n * - `path`  — `pathname`\n * - `title` — `document.title` (omitted when empty)\n * - `hash`  — the fragment, included ONLY when {@link isSafeAnchorHash} accepts\n *             it as a plain docs anchor; otherwise omitted entirely\n *\n * Opt in to more, explicitly, via {@link AutoPageContextOptions} — only through\n * the function form (`buildAutoPageContext({ … })`); the bare `'auto'` string\n * literal ALWAYS uses these safe defaults:\n * - `includeQuery: true` — append the query string to `url` AND add a `query`\n *   field (raw `location.search`, including the leading `?`)\n * - `includeHash: true`  — capture the fragment verbatim, bypassing the anchor\n *   heuristic\n *\n * Never captures identity data (cookies, `document.referrer`,\n * `navigator.userAgent`). Any individual field whose global is unexpectedly\n * unavailable is simply omitted; the helper never throws.\n */\nexport function buildAutoPageContext(\n  options?: AutoPageContextOptions,\n): ChatContext {\n  // SSR / non-browser: no location to read. Return an empty context so the\n  // send path can spread it away to nothing (same shape as an undefined prop).\n  if (typeof window === 'undefined' || typeof document === 'undefined') {\n    return {};\n  }\n\n  const includeQuery = options?.includeQuery ?? false;\n  const includeHash = options?.includeHash ?? false;\n\n  const context: ChatContext = {};\n\n  const loc = window.location;\n  if (loc) {\n    // Safe base: origin + pathname, NEVER the query or fragment. `pathname`\n    // alone would drop the origin; `href` would leak `?query#fragment`. Build\n    // the URL from the discrete parts we trust.\n    const origin = typeof loc.origin === 'string' ? loc.origin : '';\n    const pathname = typeof loc.pathname === 'string' ? loc.pathname : '';\n    const search = typeof loc.search === 'string' ? loc.search : '';\n\n    let url = origin + pathname;\n    // Query string: excluded by default (tokens / OAuth state / signed URLs /\n    // PII in search params). Only appended — and mirrored into a `query`\n    // field — when the host explicitly opts in.\n    if (includeQuery && search) {\n      url += search;\n      context.query = search;\n    }\n    if (url) context.url = url;\n\n    if (pathname) context.path = pathname;\n\n    // Fragment: by default include it ONLY when it looks like a plain docs\n    // anchor. `includeHash: true` bypasses the heuristic and takes the raw\n    // fragment (still omitting an empty/\"#\"-only hash — that is just noise).\n    const hash = typeof loc.hash === 'string' ? loc.hash : '';\n    if (hash && hash !== '#') {\n      if (includeHash || isSafeAnchorHash(hash)) {\n        context.hash = hash;\n      }\n    }\n  }\n\n  // `document.title` is a string (\"\" when unset); include it only when present\n  // so the shape stays minimal on title-less pages.\n  if (typeof document.title === 'string' && document.title) {\n    context.title = document.title;\n  }\n\n  return context;\n}\n\n/**\n * Resolve the `context` prop union ({@link ChatWidgetConfig.context}) to the\n * concrete {@link ChatContext} object that ships with a turn. This is the ONE\n * place the union is collapsed, called AT SEND TIME so `'auto'` and the\n * function form both reflect the live page/app state per message:\n *\n * - `'auto'`          → {@link buildAutoPageContext} with the SAFE DEFAULTS\n *                        (no query, anchor-only hash). Richer capture is opt-in\n *                        through the function form, e.g.\n *                        `context: () => buildAutoPageContext({ includeQuery: true })`\n * - a function        → called and awaited (sync or `Promise`); if it throws\n *                        or rejects, degrade to `{}` and `console.warn` ONCE so\n *                        a host bug in context assembly never blocks the message\n * - an object         → returned as-is (today's behaviour, unchanged)\n * - `undefined`       → `undefined` (serialises away — zero overhead)\n *\n * SECURITY: resolving `'auto'` or a function does not change the trust\n * boundary — the result is still untrusted client input the server only reads\n * when it opts in (see ChatWidgetConfig.context). This helper adds no identity\n * data of its own.\n */\nexport async function resolveChatContext(\n  context:\n    | ChatContext\n    | 'auto'\n    | (() => ChatContext | Promise<ChatContext>)\n    | undefined,\n): Promise<ChatContext | undefined> {\n  if (context === undefined) return undefined;\n  // The string literal ALWAYS uses the safe defaults. Hosts wanting the query\n  // string or a non-anchor fragment go through the function form.\n  if (context === 'auto') return buildAutoPageContext();\n\n  if (typeof context === 'function') {\n    try {\n      return await context();\n    } catch (err) {\n      // A host-supplied context function threw/rejected. Context is an\n      // enhancement, never a gate on sending — drop it for this turn and warn\n      // once so the failure is debuggable without spamming the console on\n      // every subsequent send.\n      warnContextResolveFailedOnce(err);\n      return {};\n    }\n  }\n\n  // Plain object (or any other already-resolved value): pass through unchanged.\n  return context;\n}\n\n// One-shot guard for the function-form failure warning: a broken context\n// function would otherwise log on every single send.\nlet warnedContextResolveFailed = false;\nfunction warnContextResolveFailedOnce(err: unknown): void {\n  if (warnedContextResolveFailed) return;\n  warnedContextResolveFailed = true;\n  console.warn(\n    '[mordn] context function threw; sending this turn without context.',\n    err,\n  );\n}\n","import type { MessageDataPart } from '../types';\n\n/**\n * Shared presentation/persistence eligibility, not payload validation or proof\n * of server origin. Never use this to authenticate client-supplied parts.\n * No renderer registration or React runtime is needed to preserve history.\n */\nexport function isCustomMessageDataPart(part: { type: string }): part is MessageDataPart {\n  return part.type.startsWith('data-') &&\n    part.type.length > 5 &&\n    part.type !== 'data-follow-ups' &&\n    part.type !== 'data-thread-title' &&\n    // Reserved even when a host accidentally replays transient error metadata.\n    part.type !== 'data-chat-error' &&\n    (part as { transient?: unknown }).transient !== true &&\n    Object.prototype.hasOwnProperty.call(part, 'data');\n}\n","import type { MessagePartRenderer, MessagePartRenderers } from '../types';\nimport { isCustomMessageDataPart } from './custom-message-data';\n\nexport { isCustomMessageDataPart } from './custom-message-data';\n\n/** Do not dispatch inherited entries or non-functions supplied by untyped hosts. */\nexport function getMessagePartRenderer(\n  part: { type: string },\n  renderers?: MessagePartRenderers,\n): MessagePartRenderer | undefined {\n  if (!isCustomMessageDataPart(part) || !renderers ||\n      !Object.prototype.hasOwnProperty.call(renderers, part.type)) return undefined;\n  const renderer = renderers[part.type];\n  return typeof renderer === 'function' ? renderer : undefined;\n}\n","import type { UIMessage } from 'ai';\nimport type { MessagePartRenderers } from '../types';\nimport { getMessagePartRenderer } from './message-part-renderers';\n\n/**\n * Whether an assistant message currently has anything the transcript can paint.\n * Keep this aligned with MessageItem / AgentTurnTranscript: metadata-only parts\n * such as step-start and data-follow-ups must not dismiss the planning state.\n */\nexport function hasRenderableAssistantContent(\n  message: UIMessage | undefined,\n  messagePartRenderers?: MessagePartRenderers,\n): boolean {\n  if (message?.role !== 'assistant') return false;\n\n  return (message.parts ?? []).some((part) => {\n    if (part.type === 'text' || part.type === 'reasoning') {\n      return part.text.trim().length > 0;\n    }\n\n    return (\n      part.type === 'source-url' ||\n      part.type === 'file' ||\n      part.type === 'dynamic-tool' ||\n      part.type.startsWith('tool-') ||\n      // Registration opts the part into transcript ownership. Never invoke a\n      // host render callback here (it may return null or a component).\n      !!getMessagePartRenderer(part, messagePartRenderers)\n    );\n  });\n}\n\n/**\n * The AI SDK inserts an empty assistant message before the first streamed part.\n * While the global planning indicator owns that pre-content slot, omit the empty\n * row so MessageItem's turn spacing cannot move the indicator before content.\n */\nexport function messagesForTranscript(\n  messages: UIMessage[],\n  showPlanning: boolean,\n  messagePartRenderers?: MessagePartRenderers,\n): UIMessage[] {\n  if (!showPlanning) return messages;\n\n  const last = messages.at(-1);\n  if (last?.role !== 'assistant' || hasRenderableAssistantContent(last, messagePartRenderers)) {\n    return messages;\n  }\n\n  return messages.slice(0, -1);\n}\n","import { cn } from \"../utils/cn\";\nimport type { HTMLAttributes } from \"react\";\n\ntype LoaderIconProps = {\n  size?: number;\n};\n\nconst LoaderIcon = ({ size = 16 }: LoaderIconProps) => (\n  <svg\n    aria-hidden=\"true\"\n    height={size}\n    strokeLinejoin=\"round\"\n    style={{ color: \"currentcolor\" }}\n    viewBox=\"0 0 16 16\"\n    width={size}\n  >\n    <title>Loader</title>\n    <g clipPath=\"url(#clip0_2393_1490)\">\n      <path d=\"M8 0V4\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n      <path\n        d=\"M8 16V12\"\n        opacity=\"0.5\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M3.29773 1.52783L5.64887 4.7639\"\n        opacity=\"0.9\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M12.7023 1.52783L10.3511 4.7639\"\n        opacity=\"0.1\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M12.7023 14.472L10.3511 11.236\"\n        opacity=\"0.4\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M3.29773 14.472L5.64887 11.236\"\n        opacity=\"0.6\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M15.6085 5.52783L11.8043 6.7639\"\n        opacity=\"0.2\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M0.391602 10.472L4.19583 9.23598\"\n        opacity=\"0.7\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M15.6085 10.4722L11.8043 9.2361\"\n        opacity=\"0.3\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M0.391602 5.52783L4.19583 6.7639\"\n        opacity=\"0.8\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n    </g>\n    <defs>\n      <clipPath id=\"clip0_2393_1490\">\n        <rect fill=\"white\" height=\"16\" width=\"16\" />\n      </clipPath>\n    </defs>\n  </svg>\n);\n\nexport type LoaderProps = HTMLAttributes<HTMLDivElement> & {\n  size?: number;\n};\n\nexport const Loader = ({ className, size = 16, ...props }: LoaderProps) => (\n  <div\n    aria-label=\"Loading\"\n    className={cn(\n      \"inline-flex animate-spin items-center justify-center\",\n      className\n    )}\n    role=\"status\"\n    {...props}\n  >\n    <LoaderIcon size={size} />\n  </div>\n);\n","import { memo, type CSSProperties, type ElementType, type ReactNode } from 'react';\nimport { cn } from '../../utils/cn';\n\n/**\n * A quiet \"still working\" cue: a low-contrast highlight swept along a line of\n * text. Reads as the status of *that* line — not a separate spinner widget.\n * Pure CSS (`.chat-text-shimmer` in styles.src.css) so the package stays\n * dependency-free; we only set the per-instance band width (`--spread`, scaled\n * to the text length so one pass covers the whole line) and duration inline.\n */\ninterface TextShimmerProps {\n  children: ReactNode;\n  as?: ElementType;\n  className?: string;\n  /** Sweep duration in seconds. */\n  duration?: number;\n  /** px of band half-width per character. */\n  spread?: number;\n}\n\nexport const TextShimmer = memo(function TextShimmer({\n  children,\n  as: Component = 'span',\n  className,\n  duration = 1.4,\n  spread = 2,\n}: TextShimmerProps) {\n  const dynamicSpread =\n    typeof children === 'string' ? children.length * spread : 60;\n  const Tag = Component as ElementType;\n\n  return (\n    <Tag\n      className={cn('chat-text-shimmer', className)}\n      style={\n        {\n          ['--spread']: `${dynamicSpread}px`,\n          animationDuration: `${duration}s`,\n        } as CSSProperties\n      }\n    >\n      {children}\n    </Tag>\n  );\n});\n","import type { ToolPart, ToolStatus, TurnState } from './types';\n\nexport const SUBTITLE_MAX = 44;\n\nexport function truncate(s: string, n = SUBTITLE_MAX): string {\n  const t = s.trim();\n  return t.length > n ? `${t.slice(0, n - 1)}…` : t;\n}\n\n/**\n * Turn a tool slug into friendly running / done verbs for an ASSISTANT voice.\n * \"getUserPortfolios\" → running \"Looking up your portfolios\" / done \"Pulled up\n * your portfolios\". We keep this generic (no host-specific table) by parsing\n * the common verb prefixes assistants' tools use, then humanizing the rest.\n */\nconst VERB_PREFIXES: Array<{ re: RegExp; running: string; done: string }> = [\n  { re: /^(get|fetch|load|list|read|retrieve)/i, running: 'Looking up', done: 'Pulled up' },\n  { re: /^(search|find|lookup|query)/i, running: 'Searching', done: 'Searched' },\n  { re: /^(analy[sz]e|assess|evaluate|review)/i, running: 'Analyzing', done: 'Analyzed' },\n  { re: /^(calculate|compute|run)/i, running: 'Working out', done: 'Worked out' },\n  { re: /^(create|add|build|generate|make)/i, running: 'Putting together', done: 'Put together' },\n  { re: /^(update|edit|modify|set|save)/i, running: 'Updating', done: 'Updated' },\n  { re: /^(delete|remove)/i, running: 'Removing', done: 'Removed' },\n];\n\nconst KNOWN: Record<string, { running: string; done: string }> = {\n  web_search: { running: 'Searching the web', done: 'Searched the web' },\n  web_search_preview: { running: 'Searching the web', done: 'Searched the web' },\n  code_execution: { running: 'Running the numbers', done: 'Ran the numbers' },\n};\n\n/** \"getUserPortfolios\" → \"user portfolios\" ; \"get_financials\" → \"financials\". */\nfunction humanizeObject(slug: string): string {\n  let s = slug\n    .replace(/^(get|fetch|load|list|read|retrieve|search|find|lookup|query|analy[sz]e|assess|evaluate|review|calculate|compute|run|create|add|build|generate|make|update|edit|modify|set|save|delete|remove)/i, '')\n    .replace(/[_-]+/g, ' ')\n    .replace(/([a-z])([A-Z])/g, '$1 $2')\n    .trim()\n    .toLowerCase();\n  // Drop a leading possessive-ish word duplication; keep it simple.\n  return s;\n}\n\nfunction titleCase(slug: string): string {\n  const cleaned = slug.replace(/[_-]+/g, ' ').replace(/([a-z])([A-Z])/g, '$1 $2').trim();\n  if (!cleaned) return 'that';\n  return cleaned.charAt(0).toUpperCase() + cleaned.slice(1).toLowerCase();\n}\n\nexport function getToolVerb(tool: string, isPending: boolean): string {\n  const known = KNOWN[tool];\n  if (known) return isPending ? known.running : known.done;\n\n  for (const p of VERB_PREFIXES) {\n    if (p.re.test(tool)) {\n      const obj = humanizeObject(tool);\n      const verb = isPending ? p.running : p.done;\n      return obj ? `${verb} ${obj}` : verb;\n    }\n  }\n  // Unknown shape → neutral, still friendly.\n  return isPending ? `Working on ${titleCase(tool).toLowerCase()}` : titleCase(tool);\n}\n\n/** A one-line subtitle from the input — the most salient string/number arg. */\nexport function getToolSubtitle(part: ToolPart): string {\n  const input = part.state.input;\n  // Prefer obviously-identifying keys first.\n  const PREFERRED = ['symbol', 'ticker', 'name', 'query', 'q', 'portfolioId', 'id', 'filePath', 'path'];\n  for (const k of PREFERRED) {\n    const v = input[k];\n    if (typeof v === 'string' && v.trim()) {\n      return truncate(k === 'filePath' || k === 'path' ? v.split('/').pop() || v : v);\n    }\n  }\n  for (const v of Object.values(input)) {\n    if (typeof v === 'string' && v.trim()) return truncate(v);\n    if (typeof v === 'number' || typeof v === 'boolean') return String(v);\n  }\n  return '';\n}\n\n/**\n * A short result summary from the output, in assistant voice — e.g. an array of\n * N → \"13 results\", an object with a count, a short string echoed. Returns ''\n * when nothing meaningful can be summarized (the row just reads as done).\n */\nexport function getResultSummary(part: ToolPart): string {\n  const out = part.state.output;\n  if (out == null) return '';\n  if (Array.isArray(out)) {\n    return `${out.length} ${out.length === 1 ? 'result' : 'results'}`;\n  }\n  if (typeof out === 'string') {\n    const t = out.trim();\n    if (!t) return '';\n    return t.length > SUBTITLE_MAX ? truncate(t) : t;\n  }\n  if (typeof out === 'object') {\n    const o = out as Record<string, unknown>;\n    // Common count-ish keys.\n    for (const k of ['count', 'total', 'length']) {\n      if (typeof o[k] === 'number') return `${o[k]} ${(o[k] as number) === 1 ? 'item' : 'items'}`;\n    }\n    // An array nested one level (e.g. { portfolios: [...] }).\n    for (const v of Object.values(o)) {\n      if (Array.isArray(v)) return `${v.length} ${v.length === 1 ? 'result' : 'results'}`;\n    }\n  }\n  return '';\n}\n\nexport function getToolStatus(part: ToolPart, turn: TurnState): ToolStatus {\n  const status = part.state.status;\n  const turnAlive = turn !== 'done' && turn !== 'error';\n  const isError = status === 'output-error';\n  const isSuccess = status === 'output-available';\n  const stillRunning = status === 'input-streaming' || status === 'input-available';\n  const isPending = stillRunning && turnAlive;\n  const isInterrupted = stillRunning && !turnAlive;\n  return { isPending, isError, isSuccess, isInterrupted };\n}\n\n/** Planning verbs for the gap before the first token — warm, assistant-y. */\nexport const PLANNING_VERBS = [\n  'Thinking it through',\n  'One moment',\n  'Looking into it',\n  'Working on it',\n  'Putting it together',\n  'Getting that for you',\n  'On it',\n] as const;\n\nexport function pickPlanningVerb(messageId: string): string {\n  let h = 0;\n  for (let i = 0; i < messageId.length; i++) h = h * 31 + messageId.charCodeAt(i);\n  return PLANNING_VERBS[Math.abs(h) % PLANNING_VERBS.length];\n}\n","'use client';\n\nimport { ChevronRight } from 'lucide-react';\n\n/**\n * Follow-up suggestions as a \"Related\" block — a quiet labeled list of\n * stacked, full-width rows (Perplexity-style), replacing the old horizontally\n * scrolling pill row which truncated questions and hid all but the first\n * suggestion at widget widths.\n *\n * Rendered inside the conversation, attached under the completed assistant\n * reply, so it reads as part of the answer and scrolls away with it. Rows use\n * the same divider/ink ramp as the rest of the widget: muted at rest,\n * full text + a nudged chevron on hover.\n */\nexport function FollowUpSuggestions({\n  suggestions,\n  onSelect,\n}: {\n  suggestions: string[];\n  onSelect: (text: string) => void;\n}) {\n  if (suggestions.length === 0) return null;\n\n  return (\n    <div className=\"mt-4\" data-follow-up-suggestions>\n      <div\n        className=\"px-1 pb-1.5 text-[10px] font-semibold uppercase tracking-[0.1em]\"\n        style={{ color: 'hsl(var(--chat-text-subtle))' }}\n      >\n        Related\n      </div>\n      <div>\n        {suggestions.map((s) => (\n          <button\n            key={s}\n            type=\"button\"\n            onClick={() => onSelect(s)}\n            className=\"group flex w-full cursor-pointer items-center justify-between gap-3 border-t px-1 py-2.5 text-left text-[13px] leading-5 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\"\n            style={{ borderColor: 'hsl(var(--chat-hairline))' }}\n          >\n            <span className=\"min-w-0 text-[hsl(var(--chat-text-muted))] transition-colors group-hover:text-[hsl(var(--chat-text))]\">\n              {s}\n            </span>\n            <ChevronRight\n              className=\"size-3.5 flex-shrink-0 transition-transform duration-150 group-hover:translate-x-0.5\"\n              style={{ color: 'hsl(var(--chat-text-subtle))' }}\n              aria-hidden=\"true\"\n            />\n          </button>\n        ))}\n      </div>\n    </div>\n  );\n}\n","\"use client\";\n\nimport { cn } from \"../utils/cn\";\nimport { type HTMLAttributes } from \"react\";\nimport type { StarterPrompt } from \"../types\";\n\nexport type { StarterPrompt };\n\nexport type StarterMessagesLayout = 'list' | 'grid';\n\nexport type StarterMessagesProps = Omit<HTMLAttributes<HTMLDivElement>, 'onSelect'> & {\n  prompts: StarterPrompt[];\n  onPromptSelect: (prompt: StarterPrompt) => void;\n  /**\n   * How prompts are laid out.\n   * - `'list'` (default): spaced, full-width bordered cards — good for\n   *   descriptive prompts, optionally with a subtitle.\n   * - `'grid'`: a 2-column chip grid — good for short, scannable prompts,\n   *   optionally with an icon.\n   */\n  layout?: StarterMessagesLayout;\n};\n\nexport function StarterMessages({\n  className,\n  prompts,\n  onPromptSelect,\n  layout = 'list',\n  ...props\n}: StarterMessagesProps) {\n  if (prompts.length === 0) return null;\n\n  if (layout === 'grid') {\n    return (\n      <div\n        className={cn(\"mb-3 grid grid-cols-2 gap-2\", className)}\n        {...props}\n      >\n        {prompts.map((prompt, index) => (\n          <StarterMessageItem\n            key={`${prompt.title}-${index}`}\n            prompt={prompt}\n            layout=\"grid\"\n            onClick={() => onPromptSelect(prompt)}\n          />\n        ))}\n      </div>\n    );\n  }\n\n  return (\n    <div className={cn(\"mb-3 grid gap-2\", className)} {...props}>\n      {prompts.map((prompt, index) => (\n        <StarterMessageItem\n          key={`${prompt.title}-${index}`}\n          prompt={prompt}\n          onClick={() => onPromptSelect(prompt)}\n        />\n      ))}\n    </div>\n  );\n}\n\nexport type StarterMessageItemProps = HTMLAttributes<HTMLButtonElement> & {\n  prompt: StarterPrompt;\n  layout?: StarterMessagesLayout;\n};\n\nexport function StarterMessageItem({\n  className,\n  prompt,\n  layout = 'list',\n  ...props\n}: StarterMessageItemProps) {\n  if (layout === 'grid') {\n    return (\n      <button\n        type=\"button\"\n        className={cn(\n          \"h-full text-left px-3 py-2.5 rounded-xl\",\n          \"flex flex-col gap-1\",\n          \"border border-[hsl(var(--chat-border-soft))]\",\n          \"bg-[hsl(var(--chat-background))]\",\n          \"hover:bg-[hsl(var(--chat-surface))] hover:border-[hsl(var(--chat-border))]\",\n          \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\",\n          \"transition-colors duration-150 ease-out\",\n          \"cursor-pointer\",\n          className\n        )}\n        {...props}\n      >\n        {prompt.icon && (\n          <span className=\"text-[hsl(var(--chat-text-muted))] [&_svg]:size-[15px]\">{prompt.icon}</span>\n        )}\n        <span className=\"text-[13px] font-medium leading-snug text-[hsl(var(--chat-text))]\">\n          {prompt.title}\n        </span>\n        {prompt.subtitle && (\n          <span className=\"text-[11.5px] leading-snug text-[hsl(var(--chat-text-faint))]\">\n            {prompt.subtitle}\n          </span>\n        )}\n      </button>\n    );\n  }\n\n  return (\n    <button\n      type=\"button\"\n      className={cn(\n        \"w-full rounded-xl border border-[hsl(var(--chat-border-soft))] bg-[hsl(var(--chat-background))] px-4 py-3 text-left\",\n        \"hover:bg-[hsl(var(--chat-surface))] hover:border-[hsl(var(--chat-border))]\",\n        \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\",\n        \"transition-colors duration-150 ease-out\",\n        \"cursor-pointer\",\n        className\n      )}\n      {...props}\n    >\n      <span className=\"flex items-center gap-3\">\n        {prompt.icon && (\n          <span className=\"shrink-0 text-[hsl(var(--chat-text-muted))] [&_svg]:size-[15px]\">{prompt.icon}</span>\n        )}\n        <span className=\"min-w-0\">\n          <span className=\"block text-[13px] font-medium text-[hsl(var(--chat-text))]\">\n            {prompt.title}\n          </span>\n          {prompt.subtitle && (\n            <span className=\"mt-0.5 block text-[11.5px] text-[hsl(var(--chat-text-faint))]\">\n              {prompt.subtitle}\n            </span>\n          )}\n        </span>\n      </span>\n    </button>\n  );\n}\n","import { Fragment, memo, useMemo } from 'react';\nimport type { UIMessage, ChatStatus } from 'ai';\nimport { cn } from '../utils/cn';\nimport { Message, MessageContent } from './message';\nimport { Response } from './response';\nimport { Source, Sources, SourcesContent, SourcesTrigger } from './sources';\nimport type { CitationSource } from './citation-markers';\nimport { MessageAttachments } from './message-attachments';\nimport { filePartDetails } from '../utils/file-parts';\nimport { MessageActions } from './message-actions';\nimport { AgentTurnTranscript } from './transcript/AgentTurnTranscript';\nimport { getMessagePartRenderer, isCustomMessageDataPart } from '../utils/message-part-renderers';\nimport type { TurnState } from './transcript/types';\nimport type { ActionRenderer, ToolRenderer, FeedbackEvent, MessagePartRenderers } from '../types';\n\n/**\n * One message in the conversation, as its own memoized component.\n *\n * WHY THIS EXISTS — targeted streaming re-renders:\n * The parent re-renders on every throttled streaming tick (the AI SDK swaps the\n * `messages` array reference each tick). Without a per-message boundary, that\n * re-maps and re-renders EVERY message (re-parsing markdown, re-stringifying\n * tool JSON, re-diffing data: image attachments) on each tick — cost scales with\n * conversation length + attachments.\n *\n * The AI SDK reuses old message object references across ticks and replaces ONLY\n * the streaming (last) message with a fresh clone. So a DEFAULT `React.memo`\n * shallow-compare is exactly right: static messages keep their reference and bail\n * out; the streaming message gets a new reference and re-renders every tick.\n *\n * ⚠️ DO NOT add a custom comparator or a content signature (e.g. parts.length /\n * text length). A signature would NOT change while the last text part grows\n * character-by-character, so it would BAIL on the streaming message and FREEZE\n * the bubble mid-token. Default shallow compare on the message object is both\n * simpler and the only safe choice here.\n */\ninterface MessageItemProps {\n  message: UIMessage;\n  isFirst: boolean;\n  isLast: boolean;\n  prevRole?: UIMessage['role'];\n  status: ChatStatus;\n  toolRenderers?: Record<string, ToolRenderer>;\n  actionRenderers?: Record<string, ActionRenderer>;\n  messagePartRenderers?: MessagePartRenderers;\n  onRegenerate?: () => void;\n  onToolApproval?: (approvalId: string, approved: boolean) => void;\n  feedbackEnabled?: boolean;\n  conversationId?: string;\n  feedbackApiBase?: string;\n  feedbackHeaders?: Record<string, string>;\n  /** Credentials mode mirroring the chat transport (cross-origin cookie auth). */\n  feedbackCredentials?: RequestCredentials;\n  onFeedback?: (feedback: FeedbackEvent) => void;\n}\n\ntype SourceUrlPart = {\n  type: 'source-url';\n  sourceId?: string;\n  url: string;\n  title?: string;\n  citationIds?: number[];\n  /** Live-streamed parts carry alias IDs here (the source-url chunk schema is\n   *  strict, so the handler can't put citationIds at the top level). */\n  providerMetadata?: { mordn?: { citationIds?: number[] } };\n};\n\nfunction sourceTitle(part: SourceUrlPart): string {\n  return part.title || part.url;\n}\n\nfunction MessageItemImpl({ message, isFirst, isLast, prevRole, status, toolRenderers, actionRenderers, messagePartRenderers, onRegenerate, onToolApproval, feedbackEnabled, conversationId, feedbackApiBase, feedbackHeaders, feedbackCredentials, onFeedback }: MessageItemProps) {\n  const sourceParts = useMemo(\n    () => (message.parts?.filter((part) => part.type === 'source-url') ?? []) as SourceUrlPart[],\n    [message.parts],\n  );\n  // The same source-url parts, cast to the CitationSource shape the inline\n  // citation chips consume. sourceParts IS the bibliography list; explicit\n  // citationIds preserve the model's original reference mapping through dedupe.\n  // Live-streamed parts carry the alias IDs in providerMetadata (strict chunk\n  // schema); persisted parts carry them at the top level — normalize both.\n  // Memoized on sourceParts so the identity is stable unless the parts change.\n  const citationSources = useMemo(\n    () =>\n      sourceParts.map((part) => ({\n        ...part,\n        citationIds: part.citationIds ?? part.providerMetadata?.mordn?.citationIds,\n      })) as unknown as CitationSource[],\n    [sourceParts],\n  );\n  const fileParts = useMemo(\n    () => message.parts?.filter((part) => part.type === 'file') ?? [],\n    [message.parts],\n  );\n  const attachments = useMemo(\n    () =>\n      fileParts.map(filePartDetails),\n    [fileParts],\n  );\n\n  const isStreamingThisMessage = isLast && message.role === 'assistant' && status !== 'ready';\n  const showActions = message.role === 'assistant' && !isStreamingThisMessage;\n  const showRegenerate = showActions && isLast && status === 'ready';\n  const messageText = useMemo(\n    () =>\n      showActions\n        ? (message.parts ?? [])\n            .filter((p): p is { type: 'text'; text: string } => p.type === 'text')\n            .map((p) => p.text)\n            .join('\\n\\n')\n        : '',\n    [showActions, message.parts],\n  );\n\n  const turnState: TurnState =\n    status === 'error' ? 'error' : isStreamingThisMessage ? 'streaming' : 'done';\n\n  const spacing = isFirst\n    ? undefined\n    : message.role === 'assistant' && prevRole === 'user'\n      ? 'mt-4'\n      : message.role === 'assistant' && prevRole === 'assistant'\n        ? // Assistant-after-assistant is a CONTINUATION of the same visual turn\n          // (multi-step tool runs can split one reply across messages). The full\n          // between-turns mt-6 here read as a huge hole above/below tool rows —\n          // match the within-turn transcript gap instead.\n          'mt-1.5'\n        : 'mt-6';\n\n  return (\n    <div className={cn('group relative', spacing)}>\n      {fileParts.length > 0 && (\n        <div className={cn('flex mb-1', message.role === 'user' ? 'justify-end' : 'justify-start')}>\n          <MessageAttachments attachments={attachments} />\n        </div>\n      )}\n\n      {message.parts ? (\n        message.role === 'assistant' ? (\n          <>\n            <AgentTurnTranscript\n              message={message}\n              isLast={isLast}\n              isStreaming={status === 'streaming'}\n              turn={turnState}\n              toolRenderers={toolRenderers}\n              actionRenderers={actionRenderers}\n              messagePartRenderers={messagePartRenderers}\n              onToolApproval={onToolApproval}\n              sources={citationSources}\n            />\n            {/* Sources bibliography footer (#138). Sits BELOW the answer — the\n               inline citation chips link the prose to these sources, so the list\n               is a reference footer, not a top-of-message callout. Collapsed by\n               default; the count is the quiet affordance. Suppressed while\n               streaming so a half-arrived source list doesn't flash. Replaces\n               the old \"Grounded in N sources\" metadata line (the footer's count\n               carries that signal now, more usefully). */}\n            {!isStreamingThisMessage && sourceParts.length > 0 && (\n              <Sources className=\"mt-4\">\n                <SourcesTrigger count={sourceParts.length} />\n                <SourcesContent>\n                  {sourceParts.map((part, i) => (\n                    <Source\n                      key={`${message.id}-source-${i}`}\n                      href={part.url}\n                      title={sourceTitle(part)}\n                      index={i}\n                    />\n                  ))}\n                </SourcesContent>\n              </Sources>\n            )}\n          </>\n        ) : (\n          <div className=\"space-y-2\">\n            {message.parts.map((part, i) =>\n              part.type === 'text' ? (\n                <Fragment key={`${message.id}-${i}`}>\n                  <Message from=\"user\">\n                    <MessageContent>\n                      <Response>{part.text}</Response>\n                    </MessageContent>\n                  </Message>\n                </Fragment>\n              ) : isCustomMessageDataPart(part) ? (\n                <Fragment key={`${message.id}-${i}`}>\n                  {getMessagePartRenderer(part, messagePartRenderers)?.(part, {\n                    messageId: message.id,\n                    role: message.role,\n                    isStreaming: false,\n                  }) ?? null}\n                </Fragment>\n              ) : null,\n            )}\n          </div>\n        )\n      ) : (\n        <Fragment key={`${message.id}-content`}>\n          <Message from={message.role}>\n            <MessageContent>\n              {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}\n              <Response sources={message.role === 'assistant' ? citationSources : undefined}>\n                {(message as any).content || (message as any).text}\n              </Response>\n            </MessageContent>\n          </Message>\n        </Fragment>\n      )}\n\n      {showActions && (\n        <MessageActions\n          text={messageText}\n          onRegenerate={showRegenerate ? onRegenerate : undefined}\n          alwaysVisible={isLast}\n          feedbackEnabled={feedbackEnabled}\n          messageId={message.id}\n          conversationId={conversationId}\n          feedbackApiBase={feedbackApiBase}\n          feedbackHeaders={feedbackHeaders}\n          feedbackCredentials={feedbackCredentials}\n          onFeedback={onFeedback}\n        />\n      )}\n    </div>\n  );\n}\n\nexport const MessageItem = memo(MessageItemImpl);\n","\"use client\";\n\nimport { cn } from \"../utils/cn\";\nimport { type ComponentProps, memo, useMemo } from \"react\";\nimport { Streamdown, defaultRemarkPlugins } from \"streamdown\";\nimport type { Pluggable } from \"unified\";\nimport { useCodeBlockAutoScroll } from \"../hooks/use-code-scroll\";\nimport { useSmoothText } from \"../hooks/use-smooth-text\";\nimport { CollapsibleCode } from \"./collapsible-code\";\nimport { MarkdownTable } from \"./markdown-table\";\nimport { CitationRef, CitationSourcesProvider, type CitationSource } from \"./citation-markers\";\nimport { remarkCitations } from \"../utils/citation-tokens\";\nimport { ChartCode } from \"../charts/chart-code\";\nimport { isChartFenceLanguage } from \"../charts/chart-spec\";\nimport { MermaidCode, ResponseStreamingContext } from \"./mermaid-block\";\nimport { MERMAID_FENCE_LANGUAGE } from \"../generative/registry\";\n\n// Override Streamdown's element rendering with our own components:\n//   - `code`     → chart fences (`mordn-chart` / `chart`) render the ChartCode\n//     chart renderer (the model emits a JSON ChartSpec in the fence and the\n//     widget draws an inline chart — Seam A of the charts feature); all other\n//     fenced code renders open by default with a ~10-line cap (#232) via\n//     CollapsibleCode; inline code passes through.\n//   - `table`    → MarkdownTable: replaces Streamdown's wrapper (whose Tailwind\n//     classes/control buttons our CSS build never generates) with our own\n//     rounded, scrollable, copyable card.\n//   - `citeRef`  → CitationRef: the model's inline `[ref: N]` / `[N]` tokens\n//     (split into `citeRef` nodes by `remarkCitations` below) render as\n//     superscript chips resolved by preserved source IDs (#138), instead of the literal\n//     \"[ref: 4, ref: 6]\" text the raw tokens would otherwise show.\nfunction codeRenderer(props: { inline?: boolean; className?: string; children?: React.ReactNode; node?: unknown }) {\n  const language = /language-([\\w-]+)/.exec(props.className ?? '')?.[1];\n  if (!props.inline && isChartFenceLanguage(language)) {\n    return <ChartCode {...props} />;\n  }\n  // Diagrams (generative registry: 'diagrams'). Previously mermaid fences fell\n  // through to plain code even though the renderer ships with streamdown.\n  if (!props.inline && language === MERMAID_FENCE_LANGUAGE) {\n    return <MermaidCode {...props} />;\n  }\n  return <CollapsibleCode {...props} />;\n}\n\nconst STREAMDOWN_COMPONENTS = {\n  code: codeRenderer,\n  table: MarkdownTable,\n  citeRef: CitationRef,\n};\n\n// Streamdown's own chain is keyed by name ({ gfm, codeMeta }) rather than an\n// array. Keep the values as the citation-free base; assistant responses opt in\n// by passing a `sources` array, while user messages leave `[1]` untouched.\nconst DEFAULT_REMARK_PLUGINS: Pluggable[] = Object.values(defaultRemarkPlugins);\n\ntype ResponseProps = ComponentProps<typeof Streamdown> & {\n  isStreaming?: boolean;\n  /**\n   * The assistant message's `source-url` parts. Supplying this array explicitly\n   * opts the response into citation-token parsing; omitting it (as user messages\n   * do) leaves `[1]` / `[ref: N]` as literal text. Unmatched assistant refs render\n   * as muted non-linking chips rather than broken links.\n   */\n  sources?: CitationSource[];\n};\n\nexport const Response = memo(\n  ({ className, isStreaming = false, children, sources, ...props }: ResponseProps) => {\n    const containerRef = useCodeBlockAutoScroll(isStreaming);\n\n    // Rate-aware smoothing: reveal the streamed markdown through a buffer that\n    // drains proportionally to its backlog, so coarse/irregular model chunks\n    // read as a smooth flow — fast when the model is fast (never lagging\n    // behind), gentle when it's slow. Only applies while streaming; completed\n    // messages render their full text directly. Non-string children (rare,\n    // defensive) pass through untouched. See use-smooth-text.ts.\n    const rawText = typeof children === \"string\" ? children : \"\";\n    const smoothed = useSmoothText(rawText, isStreaming && rawText.length > 0);\n    const content = typeof children === \"string\" ? smoothed : children;\n\n    // Merge our component overrides with any the caller passed (caller wins), so\n    // a host can still replace `code`/`table`/`citeRef` if it needs to.\n    const { components: callerComponents, remarkPlugins: callerRemarkPlugins, ...rest } = props;\n    const components = { ...STREAMDOWN_COMPONENTS, ...(callerComponents ?? {}) };\n    // Citation parsing is assistant-only by construction: MessageItem passes a\n    // sources array for assistant responses and omits it for user messages. This\n    // prevents user-authored `[1]` text from becoming a citation chip. Caller\n    // plugins remain intact and run after the splitter when citations are enabled.\n    const baseRemarkPlugins: Pluggable[] = callerRemarkPlugins ?? DEFAULT_REMARK_PLUGINS;\n    const remarkPlugins: Pluggable[] = sources !== undefined\n      ? [remarkCitations, ...baseRemarkPlugins]\n      : baseRemarkPlugins;\n\n    // Stable context value: `sources` identity is owned by the parent\n    // (MessageItem memoizes sourceParts on message.parts), so wrapping it here\n    // won't thrash children on every render. useMemo keeps the provider value\n    // stable across re-renders that don't change `sources`.\n    const ctxValue = useMemo(() => sources ?? null, [sources]);\n\n    return (\n      <div ref={containerRef}>\n        <CitationSourcesProvider value={ctxValue}>\n          <ResponseStreamingContext.Provider value={isStreaming}>\n            <Streamdown\n              className={cn(\n                \"size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0\",\n                className\n              )}\n              components={components}\n              remarkPlugins={remarkPlugins}\n              {...rest}\n            >\n              {content}\n            </Streamdown>\n          </ResponseStreamingContext.Provider>\n        </CitationSourcesProvider>\n      </div>\n    );\n  }\n);\n\nResponse.displayName = \"Response\";\n","import { useEffect, useRef } from \"react\";\n\nexport function useCodeBlockAutoScroll(isStreaming: boolean) {\n  const observerRef = useRef<MutationObserver | null>(null);\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    if (!isStreaming || !containerRef.current) {\n      // Clean up observer when not streaming\n      if (observerRef.current) {\n        observerRef.current.disconnect();\n        observerRef.current = null;\n      }\n      return;\n    }\n\n    // Create observer only when streaming starts\n    observerRef.current = new MutationObserver(() => {\n      if (!containerRef.current) return;\n\n      const codeBlocks = containerRef.current.querySelectorAll(\"pre\");\n      codeBlocks.forEach((pre) => {\n        pre.scrollTop = pre.scrollHeight;\n      });\n    });\n\n    // Observe the container for changes\n    observerRef.current.observe(containerRef.current, {\n      childList: true,\n      subtree: true,\n      characterData: true,\n    });\n\n    return () => {\n      if (observerRef.current) {\n        observerRef.current.disconnect();\n      }\n    };\n  }, [isStreaming]);\n\n  return containerRef;\n}\n","import { useEffect, useRef, useState } from \"react\";\n\n/**\n * Rate-aware, paced smoothing buffer for streamed text.\n *\n * THE PROBLEM: the model streams text in coarse, irregular bursts — a chunk,\n * then a gap, then another chunk. Rendering chunks as they land looks \"chunky\";\n * draining them as fast as possible (a naive buffer) just moves the chunkiness\n * to a \"burst → empty → stop → burst\" rhythm, because the buffer races to empty\n * and then has nothing to show until the next chunk arrives.\n *\n * THE FIX — paced reveal with a small cushion: estimate the recent arrival rate\n * and reveal characters at a STEADY speed tracking that rate, deliberately\n * keeping a small reserve of received-but-unshown text. That reserve is spent\n * gliding through the gaps between chunks, so the output is continuous instead\n * of bursty. The price is a small, BOUNDED trailing lag (~a few hundred ms of\n * text) — which self-corrects:\n *\n *   - Cushion too big (model sped up / a big chunk landed) → reveal faster to\n *     pull the lag back under the cap. Never falls far behind.\n *   - Cushion near empty (model paused) → ease off so we don't stall abruptly;\n *     if it genuinely runs dry we simply wait for more (rare with a cushion).\n *\n * When streaming ends (or the text is replaced/shrinks) we snap to the full\n * text immediately — nothing is ever lost or left lagging.\n */\n\n// Tuning (the \"small cushion\" profile).\nconst TARGET_LAG_MS = 220; // aim to keep ~this much text in reserve to glide over gaps\nconst MAX_LAG_MS = 600; // hard cap — above this, sprint to catch up (never lag more)\nconst MIN_CPS = 25; // floor reveal speed (chars/sec) so slow streams still move\nconst MAX_CPS = 1400; // ceiling so a huge backlog reveals fast but not instantly\nconst RATE_SMOOTHING = 0.15; // EMA factor for the arrival-rate estimate (lower = smoother)\n\n/**\n * Whether the user has requested reduced motion. Read once per hook instance\n * (the preference effectively never flips mid-stream). SSR-safe: defaults to\n * `false` when matchMedia is unavailable, so server render === first client\n * render and there's no hydration mismatch.\n */\nfunction prefersReducedMotion(): boolean {\n  if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") {\n    return false;\n  }\n  return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\nexport function useSmoothText(target: string, enabled: boolean): string {\n  // ACCESSIBILITY: the per-character RAF drip below mutates the DOM dozens of\n  // times per second. Inside a live region, screen readers that batch\n  // announcements (NVDA+Chrome, VoiceOver+Safari) sample mid-drip and announce\n  // only a fragment — or nothing. Users who set \"reduce motion\" (commonly SR\n  // users) get the full text immediately instead, so the live region announces\n  // coherent chunks as they arrive from the model. This also disables the\n  // purely-decorative typing animation, which is the documented intent of the\n  // preference. Visual layout and stick-to-bottom are unaffected.\n  const reduceMotion = prefersReducedMotion();\n  const animate = enabled && !reduceMotion;\n\n  const [displayed, setDisplayed] = useState(target);\n\n  const targetRef = useRef(target);\n  const shownLenRef = useRef(target.length);\n  const rafRef = useRef<number | null>(null);\n\n  // Arrival-rate tracking (chars/ms), and a fractional cursor so sub-1-char/frame\n  // speeds still progress smoothly over time.\n  const rateRef = useRef(0); // EMA of arrival rate (chars per ms)\n  const lastTargetLenRef = useRef(target.length);\n  const lastTimeRef = useRef(0);\n  const shownFracRef = useRef(target.length); // fractional reveal cursor\n  // The target string as of the last tick/setup, used to detect identity\n  // changes (see the invariant check inside `tick` below).\n  const prevTargetRef = useRef(target);\n\n  targetRef.current = target;\n\n  useEffect(() => {\n    if (!animate) {\n      if (rafRef.current !== null) {\n        cancelAnimationFrame(rafRef.current);\n        rafRef.current = null;\n      }\n      shownLenRef.current = target.length;\n      shownFracRef.current = target.length;\n      lastTargetLenRef.current = target.length;\n      prevTargetRef.current = target;\n      setDisplayed(target);\n      return;\n    }\n\n    // Fresh stream / reset if the target shrank (component reused for a new msg).\n    if (target.length < shownLenRef.current) {\n      shownLenRef.current = 0;\n      shownFracRef.current = 0;\n    }\n    rateRef.current = 0;\n    lastTargetLenRef.current = target.length;\n    lastTimeRef.current = 0;\n    prevTargetRef.current = target;\n\n    const tick = (now: number) => {\n      const full = targetRef.current;\n\n      // IDENTITY CHECK: reset whenever the target is not a pure append to\n      // what we've already revealed — streaming only ever appends. A shrink\n      // is one case of \"not an append\" and is already handled above at\n      // effect-setup time, but this hook instance can also be recycled for a\n      // DIFFERENT, LONGER message between ticks (e.g. a stable-keyed row\n      // reused by the parent) without the effect itself re-running. In that\n      // case the new target never shrank, so the setup-time check above\n      // can't catch it — without this, the longer target would reveal\n      // starting from the stale cursor and flash the wrong prefix. Compare\n      // against the previously shown prefix (not the full previous target)\n      // so a genuine append — where `full` extends what we've revealed so\n      // far but happens to diverge from `prevTargetRef` further out, e.g.\n      // trailing edits behind the reveal cursor — is not mistaken for a\n      // swap.\n      const prevTarget = prevTargetRef.current;\n      if (full !== prevTarget) {\n        const shownPrefix = prevTarget.slice(0, Math.min(shownLenRef.current, prevTarget.length));\n        if (!full.startsWith(shownPrefix)) {\n          shownLenRef.current = 0;\n          shownFracRef.current = 0;\n        }\n        prevTargetRef.current = full;\n      }\n\n      // dt since last frame (ms). First frame seeds time and bails.\n      if (lastTimeRef.current === 0) {\n        lastTimeRef.current = now;\n        rafRef.current = requestAnimationFrame(tick);\n        return;\n      }\n      const dt = Math.min(100, now - lastTimeRef.current); // clamp dt (tab-switch safety)\n      lastTimeRef.current = now;\n\n      // Update arrival-rate estimate from newly-received text this frame.\n      const arrived = full.length - lastTargetLenRef.current;\n      lastTargetLenRef.current = full.length;\n      if (dt > 0) {\n        const instRate = arrived / dt; // chars per ms this frame\n        rateRef.current =\n          rateRef.current === 0\n            ? instRate\n            : rateRef.current * (1 - RATE_SMOOTHING) + instRate * RATE_SMOOTHING;\n      }\n\n      const shown = shownFracRef.current;\n      const backlog = full.length - shown;\n\n      if (backlog <= 0) {\n        // Caught up; idle but keep the loop alive — more text may arrive.\n        rafRef.current = requestAnimationFrame(tick);\n        return;\n      }\n\n      // How much \"time worth\" of text are we currently behind by?\n      const rate = rateRef.current; // chars/ms\n      const lagMs = rate > 0 ? backlog / rate : TARGET_LAG_MS;\n\n      // Base reveal speed = recent arrival rate (so we track the model), then\n      // nudged by how the cushion compares to target: behind target → speed up,\n      // ahead of target → ease down. Sprint hard if past the hard cap.\n      let cps = rate * 1000; // chars/sec tracking arrival\n      if (lagMs > MAX_LAG_MS) {\n        cps = Math.max(cps, (backlog / (MAX_LAG_MS / 1000)) * 1.5); // sprint to catch up\n      } else if (lagMs > TARGET_LAG_MS) {\n        cps *= 1.25; // a touch faster to trim toward the target cushion\n      } else {\n        cps *= 0.85; // hold back a little to keep the cushion and glide gaps\n      }\n      cps = Math.min(MAX_CPS, Math.max(MIN_CPS, cps));\n\n      const advance = (cps / 1000) * dt; // chars this frame (fractional)\n      const nextFrac = Math.min(full.length, shown + advance);\n      shownFracRef.current = nextFrac;\n\n      const nextLen = Math.floor(nextFrac);\n      if (nextLen !== shownLenRef.current) {\n        shownLenRef.current = nextLen;\n        setDisplayed(full.slice(0, nextLen));\n      }\n\n      rafRef.current = requestAnimationFrame(tick);\n    };\n\n    rafRef.current = requestAnimationFrame(tick);\n    return () => {\n      if (rafRef.current !== null) {\n        cancelAnimationFrame(rafRef.current);\n        rafRef.current = null;\n      }\n    };\n    // Loop reads latest target via ref; only restart when animation toggles.\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [animate]);\n\n  return animate ? displayed : target;\n}\n","\"use client\";\n\n/**\n * CollapsibleCode — a compact renderer for fenced code blocks in assistant\n * messages. OPEN BY DEFAULT with a ~10-line preview: the first lines are\n * visible inline (no click needed to read the code), and anything beyond the\n * cap scrolls inside the body. The header pill (language · N lines · copy)\n * stays, and the chevron collapses the body back to header-only when the user\n * wants it out of the way.\n *\n *     ▾ {} python · 24 lines        [copy]\n *     ┌─────────────────────────────┐\n *     │  line 1                     │\n *     │  line 2                     │  ← first ~10 lines visible\n *     │  …                          │  ← scroll for the rest\n *     └─────────────────────────────┘\n *\n * Inline code (single-backtick) is left untouched — only multi-line fenced\n * blocks render through here.\n *\n * Wired in via Streamdown's `components={{ code: ... }}` override (response.tsx).\n * react-markdown calls the `code` override for BOTH inline and fenced code, so we\n * detect fenced blocks by the `language-*` className (and/or a newline) and pass\n * everything else straight through.\n *\n * Syntax highlighting (Shiki) is a progressive enhancement layered on the body\n * only — the raw `<pre><code>` always renders while (and if ever) highlighting\n * is unavailable. See utils/highlight.ts and the CollapsibleCodeBlock notes\n * below.\n *\n * Design history: an earlier revision was collapsed-by-default (header pill\n * only, body hidden until click). That hid content the reader almost always\n * wants to see and forced an extra click on every block. Open-by-default with a\n * max-height cap is the right call — the cap is what prevents the 80-line wall\n * that collapse-by-default was a workaround for.\n */\n\nimport { useEffect, useRef, useState, type ComponentType, type ReactNode } from \"react\";\nimport {\n  ChevronRightIcon,\n  CheckIcon,\n  CopyIcon,\n} from \"lucide-react\";\nimport { getFileIconByLanguage } from \"./file-icons/file-icon-map\";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"../ui/collapsible\";\nimport { cn } from \"../utils/cn\";\nimport { highlightCode } from \"../utils/highlight\";\n\n/**\n * Language icons come from the shared brand-icon map (ported from jarvis /\n * Crunch): real Python/TypeScript/React/Go glyphs with embedded brand colors —\n * replacing the old lucide \"nearest glyph\" stand-ins (a feather for Python, a\n * coffee cup for Java) that read as bugs. Unknown tags fall back to a generic\n * file icon — never a crash.\n */\nfunction iconForLanguage(language: string): ComponentType<{ className?: string }> {\n  return getFileIconByLanguage(language);\n}\n\nfunction extractText(children: ReactNode): string {\n  if (typeof children === \"string\") return children;\n  if (Array.isArray(children)) return children.map(extractText).join(\"\");\n  if (children && typeof children === \"object\" && \"props\" in children) {\n    return extractText((children as { props?: { children?: ReactNode } }).props?.children);\n  }\n  return \"\";\n}\n\ninterface CodeProps {\n  className?: string;\n  children?: ReactNode;\n  // react-markdown passes `inline` on older versions; newer infer from node.\n  inline?: boolean;\n}\n\nexport function CollapsibleCode({ className, children, inline, ...props }: CodeProps) {\n  const raw = extractText(children);\n  const langMatch = /language-([\\w-]+)/.exec(className ?? \"\");\n  const language = langMatch?.[1] ?? \"\";\n  const isFenced = Boolean(language) || raw.includes(\"\\n\");\n\n  // Inline code (`foo`) — render as-is; only fenced multi-line blocks use the\n  // collapsible renderer.\n  if (inline || !isFenced) {\n    return (\n      <code className={className} {...props}>\n        {children}\n      </code>\n    );\n  }\n\n  return <CollapsibleCodeBlock code={raw.replace(/\\n$/, \"\")} language={language} />;\n}\n\n/**\n * How long to wait after the code stops changing before highlighting. While a\n * response streams, `code` grows token-by-token; re-tokenising on every keystroke\n * would jank and waste work on text that's about to change. We debounce so we\n * only ever highlight settled text.\n */\nconst HIGHLIGHT_DEBOUNCE_MS = 150;\n\nfunction CollapsibleCodeBlock({ code, language }: { code: string; language: string }) {\n  // OPEN BY DEFAULT — the code is visible inline without a click. The body is\n  // capped to ~10 lines (see .chat-code-body in styles.src.css) and scrolls for\n  // the rest, so a long file no longer dumps an 80-line wall into the chat. The\n  // chevron still collapses to header-only if the user wants it out of the way.\n  const [open, setOpen] = useState(true);\n  const [copied, setCopied] = useState(false);\n  const [highlighted, setHighlighted] = useState<string | null>(null);\n  const copyTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n  const lineCount = code.split(\"\\n\").length;\n  const LanguageIcon = iconForLanguage(language);\n\n  // Monotonic generation counter: each highlight attempt captures the current\n  // value and only commits its result if it's still the latest. This drops\n  // stale async results from a still-growing stream (an earlier, shorter code\n  // string resolving after a later one) and from a collapse-then-reopen.\n  const genRef = useRef(0);\n\n  // Highlight the body only when open. Debounced so streaming code is\n  // highlighted once it settles, not on every chunk. Any failure (import\n  // blocked, unknown lang, oversized) yields null → we keep rendering the plain\n  // <pre><code> below. When collapsed, drop highlighted markup so a later reopen\n  // re-highlights the (possibly grown) code afresh.\n  useEffect(() => {\n    if (!open) {\n      setHighlighted(null);\n      return;\n    }\n\n    const gen = ++genRef.current;\n    let cancelled = false;\n    const timer = setTimeout(() => {\n      highlightCode(code, language).then((html) => {\n        // Ignore if this effect was cleaned up, or a newer attempt superseded us.\n        if (cancelled || gen !== genRef.current) return;\n        setHighlighted(html);\n      });\n    }, HIGHLIGHT_DEBOUNCE_MS);\n\n    return () => {\n      cancelled = true;\n      clearTimeout(timer);\n    };\n  }, [open, code, language]);\n\n  useEffect(() => {\n    return () => {\n      if (copyTimerRef.current) clearTimeout(copyTimerRef.current);\n    };\n  }, []);\n\n  const copy = async () => {\n    try {\n      // Always copy the RAW source — never the highlighted markup.\n      await navigator.clipboard.writeText(code);\n      setCopied(true);\n      if (copyTimerRef.current) clearTimeout(copyTimerRef.current);\n      copyTimerRef.current = setTimeout(() => setCopied(false), 1400);\n    } catch {\n      /* clipboard unavailable (e.g. http) — ignore */\n    }\n  };\n\n  return (\n    <Collapsible open={open} onOpenChange={setOpen} className=\"chat-code-collapsible my-2 not-prose\">\n      <div className=\"chat-code-header\">\n        <CollapsibleTrigger className=\"chat-code-trigger\" aria-expanded={open}>\n          <ChevronRightIcon\n            className={cn(\"chat-code-chevron size-3.5\", open && \"chat-code-chevron-open\")}\n          />\n          <LanguageIcon className=\"chat-code-language-icon size-[13px]\" />\n          <span className=\"chat-code-lang\">{language || \"code\"}</span>\n          <span className=\"chat-code-meta\">\n            · {lineCount} line{lineCount === 1 ? \"\" : \"s\"}\n          </span>\n        </CollapsibleTrigger>\n        <button\n          type=\"button\"\n          onClick={copy}\n          className=\"chat-code-copy\"\n          aria-label={copied ? \"Copied\" : \"Copy code\"}\n        >\n          {copied ? <CheckIcon className=\"size-3\" /> : <CopyIcon className=\"size-3\" />}\n          <span>{copied ? \"Copied\" : \"Copy\"}</span>\n        </button>\n      </div>\n      <CollapsibleContent>\n        {highlighted ? (\n          // Shiki's <pre class=\"shiki\"> markup. Safe to inject: Shiki escapes all\n          // token text as it builds the HTML (tokens are <span>s with\n          // text-escaped content), so nothing from `code` can inject markup. The\n          // wrapper carries the chat-code-body chrome (padding/border/surface +\n          // the ~10-line max-height cap); styles.src.css resets .shiki's own\n          // background so the widget surface shows through and the token colours\n          // come from --shiki-light/-dark.\n          <div\n            className=\"chat-code-body\"\n            dangerouslySetInnerHTML={{ __html: highlighted }}\n          />\n        ) : (\n          // Plain fallback: the exact pre/code we've always rendered. Shown while\n          // highlighting is pending/unavailable and whenever it returns null.\n          <pre className=\"chat-code-body\">\n            <code>{code}</code>\n          </pre>\n        )}\n      </CollapsibleContent>\n    </Collapsible>\n  );\n}\n","\"use client\"\n\nimport * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\"\n\nfunction Collapsible({\n  ...props\n}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {\n  return <CollapsiblePrimitive.Root data-slot=\"collapsible\" {...props} />\n}\n\nfunction CollapsibleTrigger({\n  ...props\n}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {\n  return (\n    <CollapsiblePrimitive.CollapsibleTrigger\n      data-slot=\"collapsible-trigger\"\n      {...props}\n    />\n  )\n}\n\nfunction CollapsibleContent({\n  ...props\n}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {\n  return (\n    <CollapsiblePrimitive.CollapsibleContent\n      data-slot=\"collapsible-content\"\n      {...props}\n    />\n  )\n}\n\nexport { Collapsible, CollapsibleTrigger, CollapsibleContent }\n","/**\n * Lazy Shiki highlighter — the ONE code-highlighting engine for the widget.\n *\n * Both code-rendering paths (the prose CollapsibleCodeBlock and the tool-call\n * CodeBlock) call `highlightCode()` here instead of shipping their own colours.\n * `shiki` was already a dependency but sat entirely unused (#37) — 100% of the\n * install cost, 0% of the benefit. This module finally uses it, and does so\n * without forcing that ~1–2 MB onto consumers who never render a code block.\n *\n * DESIGN — progressive enhancement, never a hard dependency:\n * - Zero cost until the first block is actually highlighted. The highlighter is\n *   a lazily-imported, cached singleton — the dynamic `import()` happens on the\n *   first call and never again (the promise is memoised, so concurrent callers\n *   share one load).\n * - EVERY failure degrades to plain text. `highlightCode` returns `null` on any\n *   problem (import failed, unknown language even after retrying as plain\n *   \"text\", oversized input, or a runtime throw). Callers render their existing\n *   plain `<pre><code>` when they get `null`. Highlighting is a nicety; the raw\n *   code always renders.\n * - Dual-theme, token-driven. We render with BOTH `github-light` and\n *   `github-dark` and `defaultColor: false`, so Shiki emits `--shiki-light` /\n *   `--shiki-dark` CSS custom properties on every token instead of baking in a\n *   fixed colour. styles.src.css maps those onto the widget's light/dark scope,\n *   exactly like every other themed surface. Shiki never paints its own\n *   background — the widget's `--chat-*` surfaces own that.\n *\n * SHIKI ↔ SCRIPT-TAG EMBED (see DOCS_CONTRACT §6). The `import()` below uses a\n * STATIC specifier (`\"shiki/bundle/web\"`) so app bundlers (Next / Vite /\n * Turbopack / webpack) resolve and code-split it at build time. The IIFE\n * script-tag embed (a separate PR) marks `shiki`/`shiki/bundle/web` as external,\n * so that literal import fails fast in the browser as a bare specifier — the\n * `catch` then loads Shiki from a CDN URL the embed pins on\n * `globalThis.__MORDN_SHIKI_URL__`. The `@vite-ignore` / `webpackIgnore`\n * comments keep bundlers from trying to resolve that runtime URL at build time.\n */\n\n// Shiki's `codeToHtml` is the only surface we use; typed loosely so we don't\n// pull Shiki's types into the app graph (it's a lazily-loaded, optional dep).\ntype ShikiModule = {\n  codeToHtml: (code: string, options: Record<string, unknown>) => Promise<string>;\n};\n\n/**\n * Cached singleton highlighter load. The dynamic import runs on the first call\n * and the resulting promise is memoised — never re-imported. A rejected load is\n * cached too (so we don't hammer a failing import); callers treat a throw here\n * as \"no highlighting\" and fall back to plain text.\n */\nlet highlighterPromise: Promise<ShikiModule> | null = null;\n\nfunction loadShiki(): Promise<ShikiModule> {\n  if (highlighterPromise) return highlighterPromise;\n\n  highlighterPromise = (async (): Promise<ShikiModule> => {\n    let mod: ShikiModule;\n    try {\n      // Static specifier — app bundlers resolve/split this at build time.\n      mod = (await import(\"shiki/bundle/web\")) as unknown as ShikiModule;\n    } catch {\n      // Bundler left the specifier unresolved (script-tag embed): load from the\n      // CDN URL the embed pins on globalThis. No URL → rethrow so the caller\n      // falls back to plain text.\n      const url = (globalThis as { __MORDN_SHIKI_URL__?: string }).__MORDN_SHIKI_URL__;\n      if (!url) {\n        throw new Error(\"shiki unavailable and no __MORDN_SHIKI_URL__ fallback set\");\n      }\n      mod = (await import(/* @vite-ignore */ /* webpackIgnore: true */ url)) as unknown as ShikiModule;\n    }\n    return mod;\n  })();\n\n  return highlighterPromise;\n}\n\n/**\n * Upper bound on what we hand to Shiki. Highlighting a very large block is slow\n * and pointless (the reader is scrolling, not tokenising) — past this we bail to\n * plain text. Generous enough that normal docs/code snippets always highlight.\n */\nconst MAX_HIGHLIGHT_CHARS = 50_000;\n\n/** The dual themes → drives the `--shiki-light` / `--shiki-dark` CSS vars. */\nconst THEMES = { light: \"github-light\", dark: \"github-dark\" } as const;\n\n/**\n * Highlight `code` in `lang`, returning Shiki's `<pre class=\"shiki\">…</pre>`\n * HTML string — or `null` if it can't (any failure). Callers render plain text\n * on `null`.\n *\n * The returned HTML is safe to `dangerouslySetInnerHTML`: Shiki escapes all\n * token text as it builds the markup (tokens become `<span>`s with\n * text-escaped content), so nothing from the user's `code` can inject markup.\n *\n * @param code The raw source. Copied/rendered verbatim on failure.\n * @param lang A language id (e.g. \"ts\", \"json\", \"python\"). Unknown ids retry\n *             once as plain \"text\"; if even that fails we return `null`.\n * @returns The highlighted HTML, or `null` to signal \"render plain text\".\n */\nexport async function highlightCode(code: string, lang: string): Promise<string | null> {\n  // Oversized → don't even load Shiki; plain text is the right call.\n  if (code.length > MAX_HIGHLIGHT_CHARS) return null;\n\n  let shiki: ShikiModule;\n  try {\n    shiki = await loadShiki();\n  } catch (err) {\n    // Import failed (and no CDN fallback). Silent — highlighting is optional.\n    console.debug(\"[chat-widget] shiki load failed; rendering plain code:\", err);\n    return null;\n  }\n\n  const language = (lang || \"text\").toLowerCase();\n  try {\n    return await shiki.codeToHtml(code, {\n      lang: language,\n      themes: THEMES,\n      // Emit CSS variables (--shiki-light/--shiki-dark) instead of inline fixed\n      // colours, so the widget theme drives token colours per light/dark.\n      defaultColor: false,\n    });\n  } catch {\n    // Most commonly an unknown/unsupported language. Retry once as plain \"text\"\n    // (which is always bundled) so we still get escaped, structured markup.\n    if (language !== \"text\") {\n      try {\n        return await shiki.codeToHtml(code, {\n          lang: \"text\",\n          themes: THEMES,\n          defaultColor: false,\n        });\n      } catch (err) {\n        console.debug(\"[chat-widget] shiki highlight failed; rendering plain code:\", err);\n        return null;\n      }\n    }\n    return null;\n  }\n}\n","\"use client\";\n\n/**\n * MarkdownTable — widget-owned renderer for GFM tables in assistant messages.\n *\n * Wired in via Streamdown's `components={{ table: ... }}` override\n * (response.tsx), which REPLACES Streamdown's own table wrapper. That wrapper\n * ships Tailwind utility classes (`bg-sidebar`, `divide-border`, control\n * buttons) that the widget's CSS build never generates, so tables rendered\n * through it came out half-styled. Here the widget owns the whole thing:\n *\n *   ┌─ .chat-table (rounded card) ────────────┐\n *   │ ┌─ .chat-table-scroll (x-scroll) ─────┐ │   [copy — hover-reveal]\n *   │ │ <table> … GFM content … </table>    │ │\n *   │ └─────────────────────────────────────┘ │\n *   └─────────────────────────────────────────┘\n *\n * Sizing model: the table takes its CONTENT width (`max-content`) and scrolls\n * sideways inside the card, rather than being squeezed into the widget. A chat\n * column is ~380px and a six-column table simply does not fit — compressing it\n * shredded cells one character per line. Columns therefore keep their natural\n * widths and the reader pans; `data-overflow` here drives the edge fades that\n * make that panning discoverable.\n *\n * Visual styling lives in styles.src.css under \"Tables\". Copy serializes the\n * on-screen table to TSV, which pastes cleanly into Excel / Google Sheets /\n * Numbers as real cells.\n */\n\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { CheckIcon, CopyIcon } from \"lucide-react\";\n\ninterface TableProps {\n  children?: ReactNode;\n  className?: string;\n  // react-markdown passes the mdast node to every component override; keep it\n  // out of the DOM spread.\n  node?: unknown;\n}\n\n/** Which edges have more table hiding past them — drives the fade in CSS. */\ntype Overflow = \"none\" | \"start\" | \"end\" | \"both\";\n\nexport function MarkdownTable({ children, node: _node, ...props }: TableProps) {\n  const tableRef = useRef<HTMLTableElement>(null);\n  const scrollRef = useRef<HTMLDivElement>(null);\n  const [copied, setCopied] = useState(false);\n  const [overflow, setOverflow] = useState<Overflow>(\"none\");\n\n  // Keep the edge fades honest: which side is faded depends on where the reader\n  // has scrolled to. Re-measured on scroll, on resize, and as the table grows —\n  // rows stream in one at a time, so the first measurement is never the last.\n  useEffect(() => {\n    const scroller = scrollRef.current;\n    if (!scroller) return;\n\n    const sync = () => {\n      // Sub-pixel layout means scrollLeft rarely hits the bounds exactly.\n      const slack = 1;\n      const max = scroller.scrollWidth - scroller.clientWidth;\n      if (max <= slack) return setOverflow(\"none\");\n      const atStart = scroller.scrollLeft <= slack;\n      const atEnd = scroller.scrollLeft >= max - slack;\n      setOverflow(atStart ? \"end\" : atEnd ? \"start\" : \"both\");\n    };\n\n    sync();\n    scroller.addEventListener(\"scroll\", sync, { passive: true });\n    // ResizeObserver fires on the initial observe, so streamed rows and widget\n    // resizes both land here without a polling loop.\n    const observer = new ResizeObserver(sync);\n    observer.observe(scroller);\n    if (tableRef.current) observer.observe(tableRef.current);\n    return () => {\n      scroller.removeEventListener(\"scroll\", sync);\n      observer.disconnect();\n    };\n  }, []);\n\n  const scrollable = overflow !== \"none\";\n\n  const copy = async () => {\n    const el = tableRef.current;\n    if (!el) return;\n    // Serialize what's actually on screen — one row per <tr>, cells\n    // tab-separated. Tabs inside a cell would split it, so flatten them.\n    const tsv = Array.from(el.querySelectorAll(\"tr\"))\n      .map((tr) =>\n        Array.from(tr.querySelectorAll(\"th, td\"))\n          .map((cell) => (cell.textContent ?? \"\").trim().replace(/\\t+/g, \" \"))\n          .join(\"\\t\"),\n      )\n      .join(\"\\n\");\n    try {\n      await navigator.clipboard.writeText(tsv);\n      setCopied(true);\n      setTimeout(() => setCopied(false), 1500);\n    } catch {\n      /* clipboard unavailable (e.g. http) — ignore */\n    }\n  };\n\n  return (\n    <div className=\"chat-table not-prose\" data-overflow={overflow}>\n      {/* When it overflows the scroll region becomes a labelled, focusable\n          region so keyboard users can pan it — a mouse-only scroller would\n          strand the hidden columns. It stays out of the tab order otherwise. */}\n      <div\n        ref={scrollRef}\n        className=\"chat-table-scroll\"\n        {...(scrollable\n          ? { tabIndex: 0, role: \"region\", \"aria-label\": \"Table, scrollable\" }\n          : {})}\n      >\n        <table ref={tableRef} {...props}>\n          {children}\n        </table>\n      </div>\n      <button\n        type=\"button\"\n        onClick={copy}\n        className=\"chat-table-copy\"\n        // Pins the button visible through the ✓ confirmation, so moving the\n        // pointer off the table doesn't cut the feedback short.\n        data-copied={copied ? \"\" : undefined}\n        aria-label={copied ? \"Copied\" : \"Copy table\"}\n        title=\"Copy table\"\n      >\n        {copied ? <CheckIcon className=\"size-3.5\" /> : <CopyIcon className=\"size-3.5\" />}\n      </button>\n    </div>\n  );\n}\n","\"use client\";\n\n/**\n * Inline citation chips for assistant markdown (#138).\n *\n * `remarkCitations` (utils/citation-tokens.ts) splits the model's `[ref: N]` /\n * `[N]` tokens into `citeRef` mdast nodes during the remark pass. Streamdown then\n * asks our `components.citeRef` override to render each one — that's THIS file.\n * We resolve each number against the source's preserved citationIds (falling\n * back to sourceId/position only when no explicit IDs exist) and render a chip\n * linking to the matching bibliography row. Out-of-range refs render as a\n * muted, non-linking chip so the prose still reads and we never ship a broken\n * href.\n *\n * The context is populated by `Response` from the `source-url` parts threaded\n * down from MessageItem (which already computes them for the Sources card), so\n * the inline chips and bibliography are always backed by the SAME source list;\n * preserved IDs ensure deduplication never changes attribution.\n *\n * SECURITY: citation hrefs come from the AI message stream (the `source-url`\n * parts). We route every href through `safeUrl` (the same guard the Sources card\n * uses) so a `javascript:`/`data:` URL cannot execute on click.\n */\n\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { safeUrl } from \"../utils/url-safety\";\n\n/** A `source-url` part, as produced by the handler's `toSourceParts`. */\nexport interface CitationSource {\n  type: \"source-url\";\n  sourceId?: string;\n  url: string;\n  title?: string;\n  /** Original 1-indexed DOC references represented by a deduplicated source. */\n  citationIds?: number[];\n}\n\n/**\n * Context carrying the message's source-url parts, in Sources-card order. When\n * empty/undefined, citation refs render as plain muted text (no link) — the\n * renderer degrades gracefully instead of crashing or linking to nothing.\n */\nconst CitationSourcesContext = createContext<CitationSource[] | null>(null);\n\nexport const CitationSourcesProvider = CitationSourcesContext.Provider;\n\n/** Read the sources for the current markdown block. */\nexport function useCitationSources(): CitationSource[] | null {\n  return useContext(CitationSourcesContext);\n}\n\n/**\n * Resolve a model citation number without letting source deduplication remap it.\n * Knowledge sources carry every original DOC index in citationIds; provider\n * sources may expose a numeric sourceId. Positional fallback is used only when\n * the message has no explicit IDs at all — a muted miss is safer than linking to\n * the wrong evidence.\n */\nexport function resolveCitationSource(\n  sources: CitationSource[] | null,\n  n: number,\n): CitationSource | undefined {\n  if (!sources) return undefined;\n  const aliasMatch = sources.find((source) => source.citationIds?.includes(n));\n  if (aliasMatch) return aliasMatch;\n  const sourceIdMatch = sources.find((source) => source.sourceId === String(n));\n  if (sourceIdMatch) return sourceIdMatch;\n  if (sources.some((source) => source.citationIds && source.citationIds.length > 0)) {\n    return undefined;\n  }\n  return sources[n - 1];\n}\n\n/**\n * Props stamped onto each `citeRef` element by the remark plugin\n * (data-ref-n / data-ref-raw). react-markdown surfaces them as DOM attributes on\n * the element the component override receives; we read them off `node` (the\n * ExtraProps `node`) to stay source-of-truth rather than re-parsing the DOM.\n */\ninterface CiteRefElementProps {\n  // react-markdown / streamdown pass the hast element on `node`.\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  node?: { properties?: Record<string, unknown> } | undefined;\n  // The element's DOM attributes also arrive as props (data-ref-n etc.), but we\n  // prefer `node.properties` as the canonical source. Kept here for completeness.\n  \"data-ref-n\"?: string;\n  \"data-ref-raw\"?: string;\n  children?: ReactNode;\n}\n\nfunction readRefNumber(props: CiteRefElementProps): number | null {\n  const fromNode = props.node?.properties?.[\"data-ref-n\"];\n  const raw = (typeof fromNode === \"string\" && fromNode) || props[\"data-ref-n\"];\n  if (!raw) return null;\n  const n = parseInt(raw, 10);\n  return Number.isFinite(n) && n >= 1 ? n : null;\n}\n\n/**\n * The `citeRef` component override. Renders one superscript chip linking to the\n * source carrying that reference ID. Used as `components.citeRef` in response.tsx.\n *\n * Layout: a raised, pill-shaped superscript carrying the model's source number.\n * Links open in a new tab with safe rel\n * attrs. Out-of-range refs (N > source count, or no sources in context) render\n * muted and non-interactive so the prose still reads.\n */\nexport function CitationRef({ children, ...props }: CiteRefElementProps) {\n  const n = readRefNumber(props);\n  const sources = useCitationSources();\n\n  // No usable number — render the raw token text so we never silently drop a\n  // citation the model emitted (and so a future format we don't parse yet still\n  // shows up as something, not nothing).\n  if (!n) {\n    const raw = props[\"data-ref-raw\"] ?? props.node?.properties?.[\"data-ref-raw\"];\n    return (\n      <span className=\"chat-cite-ref chat-cite-ref-muted\">\n        {typeof raw === \"string\" ? raw : children ?? \"\"}\n      </span>\n    );\n  }\n\n  // Out of range or no sources in context → muted non-linking chip carrying the\n  // number. Still useful: the user sees a citation was attempted.\n  const source = resolveCitationSource(sources, n);\n  if (!source) {\n    return (\n      <sup className=\"chat-cite-ref chat-cite-ref-muted\" data-ref-n={n}>\n        {n}\n      </sup>\n    );\n  }\n\n  const safeHref = safeUrl(source.url);\n  // A safe-but-non-http href (e.g. kb://) can't be opened — render muted chip,\n  // matching how the Sources card handles a missing href.\n  if (!safeHref) {\n    return (\n      <sup className=\"chat-cite-ref chat-cite-ref-muted\" data-ref-n={n}>\n        {n}\n      </sup>\n    );\n  }\n\n  const title = source.title || source.url;\n  return (\n    <a\n      href={safeHref}\n      target=\"_blank\"\n      rel=\"noopener noreferrer\"\n      title={title}\n      aria-label={`Source ${n}: ${title}`}\n      className={cn(\"chat-cite-ref chat-cite-ref-link\")}\n      data-ref-n={n}\n    >\n      {n}\n    </a>\n  );\n}\n","// URL/HTML safety helpers for model- and user-controlled values.\n//\n// Attachment filenames and URLs (and citation links) originate from the AI\n// message stream, so they are untrusted. These helpers enforce a strict\n// protocol allowlist and HTML-escape any text that must be interpolated into\n// markup, preventing DOM-based XSS (e.g. `javascript:` hrefs or `<script>` in\n// a filename).\n\n// Protocols we consider safe to navigate to or load directly.\nconst SAFE_PROTOCOLS = new Set([\"http:\", \"https:\", \"mailto:\", \"tel:\"]);\n\n// Inline image types allowed for `data:` image URLs (used by image previews).\nconst SAFE_DATA_IMAGE_RE =\n  /^data:image\\/(png|jpe?g|gif|webp|avif|bmp|svg\\+xml|x-icon)(;[\\w=.+-]+)*,/i;\n\n/**\n * Returns the URL if it uses a safe scheme, otherwise `undefined`.\n *\n * Allows http(s)/mailto/tel and `blob:` URLs (same-origin, created locally),\n * plus inline `data:` image URLs. Everything else — notably `javascript:`,\n * `vbscript:`, `file:` and unknown schemes — is rejected. Relative URLs are\n * permitted since they cannot carry a dangerous scheme.\n */\nexport function safeUrl(url: string | undefined | null): string | undefined {\n  if (!url) return undefined;\n  const trimmed = url.trim();\n  if (trimmed === \"\") return undefined;\n\n  // Inline data: images are allowed only for known image media types.\n  if (/^data:/i.test(trimmed)) {\n    return SAFE_DATA_IMAGE_RE.test(trimmed) ? trimmed : undefined;\n  }\n\n  // blob: URLs are created by the app itself (same origin) and are safe.\n  if (/^blob:/i.test(trimmed)) return trimmed;\n\n  // Relative URLs (no scheme) can't smuggle in javascript:/vbscript:.\n  if (!/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) return trimmed;\n\n  try {\n    // Resolve against the current origin to normalize and read the protocol.\n    const base =\n      typeof window !== \"undefined\" ? window.location.href : \"http://localhost\";\n    const parsed = new URL(trimmed, base);\n    return SAFE_PROTOCOLS.has(parsed.protocol) ? trimmed : undefined;\n  } catch {\n    return undefined;\n  }\n}\n\n/** True when the URL is an allowed inline `data:` image. */\nexport function isSafeDataImage(url: string | undefined | null): boolean {\n  return !!url && SAFE_DATA_IMAGE_RE.test(url.trim());\n}\n\n/** HTML-escape a string for safe interpolation into markup. */\nexport function escapeHtml(value: string): string {\n  return value\n    .replace(/&/g, \"&amp;\")\n    .replace(/</g, \"&lt;\")\n    .replace(/>/g, \"&gt;\")\n    .replace(/\"/g, \"&quot;\")\n    .replace(/'/g, \"&#39;\");\n}\n","/**\n * Inline citation-token parsing for the chat renderer (#138).\n *\n * The model emits citation markers inline in assistant prose as either:\n *   - `[ref: N]`          — explicit ref form (used by the docs/RAG system prompt\n *     and the `searchKnowledge` tool's `ref` field).\n *   - `[ref: N, ref: M]`  — comma-separated list inside one bracket.\n *   - `[r: N]` / `[r:N]`  — abbreviated ref form (models shorten \"ref\" to \"r\"\n *     unprompted; observed live on the demo agent).\n *   - `[N]`               — bare numeric form (the auto-retrieve context prompt\n *     says \"cite e.g. [1]\").\n *\n * Without this, those tokens render as the literal strings \"[ref: 4, ref: 6]\" /\n * \"[1]\" — which is the bug: the widget has `source-url` bibliography parts but\n * nothing links the inline text to them. This module turns tokens into `citeRef`\n * mdast element nodes so the component override in response.tsx can render chips.\n *\n * CONTRACT — [ref: N] retains the model's original reference ID. Knowledge\n * source parts carry their pre-dedup DOC indices in citationIds, so duplicate\n * URLs can collapse into one bibliography row without remapping attribution.\n * Unmatched refs render as muted, non-linking chips so the prose still reads and\n * we never ship a confidently wrong or broken href.\n *\n * DEPENDENCY-FREE by design. A naive hand-rolled mdast walker is used instead of\n * `unist-util-visit` to avoid adding a runtime dep and the strict-ESM dir-import\n * crash class that killed `react-syntax-highlighter` in #177. Only mdast `text`\n * nodes are split — code fences and inline code carry their text in `value`, not\n * as `text` children, so a `visit(tree, 'text')` walk never enters them and refs\n * inside code are correctly left as literal text.\n *\n * Pure (no React, no DOM) so it can run in the remark pipeline on the server or\n * client and is trivially unit-testable.\n */\n\n// A minimal mdast node shape — enough to walk and mutate without pulling in\n// `@types/mdast` (which we don't depend on). These are structurally identical to\n// the real mdast nodes react-markdown/streamdown produce.\ninterface MdNode {\n  type: string;\n  value?: string;\n  children?: MdNode[];\n  // Element-only fields (hast/mdast element). `properties` carries the\n  // data-attributes we stamp so the component override can read them.\n  properties?: Record<string, unknown>;\n  data?: { hName?: string; hProperties?: Record<string, unknown>; [k: string]: unknown };\n}\n\n/**\n * One parsed citation ref. `raw` is the original token text (e.g. \"ref: 4\" or\n * \"4\") so a renderer can fall back to it if needed; `n` is the original\n * 1-indexed reference ID the chip resolves.\n */\nexport interface ParsedRef {\n  n: number;\n  raw: string;\n}\n\n/**\n * Regex for the contents INSIDE a bracket that we treat as a citation. Matches\n * either the explicit `ref: N` form (optionally comma-separated, optionally\n * repeated `ref:`) or a bare positive integer. Anchored to the whole bracket\n * inner string so `[2024]` (a year) or `[v2]` (a version) is NOT mistaken for a\n * citation — only brackets whose entire content is ref-numbers qualify.\n *\n *   \"ref: 4\"            → match (one ref)\n *   \"ref: 2, ref: 4\"    → match (two refs)\n *   \"ref: 2, 4\"         → match (two refs — the repeated `ref:` is optional)\n *   \"4\"                 → match (bare)\n *   \"2, 4\"              → match (bare, comma-separated)\n *   \"2024\"              → no match (4-digit year — too large to be a ref index)\n *   \"v2\"                → no match (not numeric)\n *   \"ref: foo\"          → no match (non-numeric)\n *\n * The `ref:` prefix and whitespace are optional per item; items are comma-\n * separated. Numbers are 1–999 (aSources list is never that long; this also\n * excludes years 1000–9999 which would otherwise false-positive as bare refs).\n */\nconst REF_TOKEN_RE = /^(?:r(?:ef)?:\\s*)?([1-9]\\d{0,2})(?:\\s*,\\s*(?:r(?:ef)?:\\s*)?([1-9]\\d{0,2}))*$/i;\n\n/**\n * A bracket that looks like a citation token. We match the whole bracket\n * (including its square brackets) so we can split it out of a text run precisely.\n * Captures the inner content (group 1). Only brackets whose inner content fully\n * matches REF_TOKEN_RE are treated as citations — checked in `parseRefs`.\n */\nconst BRACKET_RE = /\\[((?:r(?:ef)?:\\s*)?[1-9]\\d{0,2}(?:\\s*,\\s*(?:r(?:ef)?:\\s*)?[1-9]\\d{0,2})*)\\]/gi;\n\n/** Upper bound on citation index — guards against a malformed/huge number. */\nconst MAX_REF = 999;\n\n/**\n * Parse the inner content of a citation bracket into refs. Returns null if the\n * inner string is not a valid citation list (so the caller leaves it as text).\n */\nexport function parseRefs(inner: string): ParsedRef[] | null {\n  const trimmed = inner.trim();\n  if (!trimmed) return null;\n  const m = REF_TOKEN_RE.exec(trimmed);\n  if (!m) return null;\n\n  // Re-extract every number from the inner string (the regex above validated the\n  // shape; here we pull all the integers out in order).\n  const nums: number[] = [];\n  const numRe = /([1-9]\\d{0,2})/g;\n  let nm: RegExpExecArray | null;\n  while ((nm = numRe.exec(trimmed)) !== null) {\n    const n = parseInt(nm[1], 10);\n    if (Number.isFinite(n) && n >= 1 && n <= MAX_REF) nums.push(n);\n  }\n  if (nums.length === 0) return null;\n  return nums.map((n) => ({ n, raw: String(n) }));\n}\n\n/**\n * Split a text string into an ordered list of segments: literal text and\n * citation refs. Citations keep their original bracket text in `raw` so a\n * renderer can show \"ref: 4\" if it ever needs to. Pure, no side effects.\n */\nexport type CitationSegment =\n  | { kind: \"text\"; text: string }\n  | { kind: \"refs\"; refs: ParsedRef[]; raw: string };\n\nexport function splitCitations(text: string): CitationSegment[] {\n  if (!text) return [];\n  const out: CitationSegment[] = [];\n  let last = 0;\n  // Reset the global regex state (it's module-level /g).\n  BRACKET_RE.lastIndex = 0;\n  let m: RegExpExecArray | null;\n  while ((m = BRACKET_RE.exec(text)) !== null) {\n    const inner = m[1];\n    const refs = parseRefs(inner);\n    if (!refs) continue; // not a citation — leave for the next text segment\n    if (m.index > last) out.push({ kind: \"text\", text: text.slice(last, m.index) });\n    out.push({ kind: \"refs\", refs, raw: m[0] });\n    last = m.index + m[0].length;\n  }\n  if (last < text.length) out.push({ kind: \"text\", text: text.slice(last) });\n  // If we matched nothing, return a single text segment so callers can fast-path.\n  if (out.length === 0) return [{ kind: \"text\", text }];\n  return out;\n}\n\n/**\n * Tiny hand-rolled mdast walker (no `unist-util-visit` dep). Visits every node\n * in the tree, depth-first, calling `fn` with (node, parent). Mutating\n * `parent.children` (replacing one node with many) is supported via the return\n * value: `fn` may return an array of nodes to REPLACE the current node with, or\n * `undefined` to keep it as-is.\n */\nfunction walk(\n  root: MdNode,\n  fn: (node: MdNode, parent: MdNode | null) => MdNode[] | undefined,\n): void {\n  const stack: { node: MdNode; parent: MdNode | null }[] = [{ node: root, parent: null }];\n  while (stack.length) {\n    const { node, parent } = stack.pop()!;\n    const replacement = fn(node, parent);\n    if (replacement && parent && parent.children) {\n      const idx = parent.children.indexOf(node);\n      if (idx >= 0) parent.children.splice(idx, 1, ...replacement);\n      // Don't descend into the replacement here — its children are already\n      // final (we only split text nodes, which have no children to revisit).\n      continue;\n    }\n    if (node.children) {\n      // Push children in reverse so depth-first order is preserved.\n      for (let i = node.children.length - 1; i >= 0; i--) {\n        stack.push({ node: node.children[i], parent: node });\n      }\n    }\n  }\n}\n\n/**\n * Build a `citeRef` mdast element node for one citation ref. Carries `n` and\n * `raw` as data properties so the `citeRef` component override can read them\n * without re-parsing. `data.hName` preserves the custom element through\n * mdast-util-to-hast; `data.hProperties` carries its attributes to the renderer.\n */\nfunction citeRefNode(ref: ParsedRef): MdNode {\n  return {\n    type: \"citeRef\",\n    properties: { n: ref.n, raw: ref.raw },\n    data: {\n      hName: \"citeRef\",\n      hProperties: { \"data-ref-n\": String(ref.n), \"data-ref-raw\": ref.raw },\n    },\n  };\n}\n\n/**\n * The remark plugin. Walks the mdast tree, splits every `text` node on\n * citation tokens, and replaces each citation with one or more `citeRef`\n * element nodes (one per ref in a `[ref: N, ref: M]` list). Returns the\n * (mutated) tree. No-op when there are no citation tokens, so it's cheap on\n * non-cited answers.\n *\n * Usage: `remarkPlugins={[remarkCitations, ...streamdownDefaults]}` — prepend so\n * it runs before Streamdown's own transforms (it only touches `text` nodes,\n * which are stable across the earlier plugins, so order is not load-bearing, but\n * prepending keeps it out of the way of CJK/math plugins that may rewrite text).\n */\nexport function remarkCitations() {\n  return (tree: MdNode) => {\n    walk(tree, (node, parent) => {\n      if (node.type !== \"text\" || typeof node.value !== \"string\" || !parent || !parent.children) {\n        return undefined;\n      }\n      const segments = splitCitations(node.value);\n      // Fast path: a single text segment with no citations → leave the node alone.\n      if (segments.length === 1 && segments[0].kind === \"text\") return undefined;\n\n      // Replace this text node with the ordered segment nodes.\n      const replacement: MdNode[] = [];\n      for (let i = 0; i < segments.length; i++) {\n        const seg = segments[i];\n        if (seg.kind === \"text\") {\n          // Glue an immediately-following citation chip to the preceding word.\n          // A normal trailing space is a wrap opportunity; swapping only that\n          // final space for NBSP prevents an orphaned chip at the start of a line\n          // without changing splitCitations' public segmentation contract.\n          const nextIsRefs = segments[i + 1]?.kind === \"refs\";\n          const value = nextIsRefs ? seg.text.replace(/ $/, \"\\u00a0\") : seg.text;\n          replacement.push({ type: \"text\", value });\n        } else {\n          for (const ref of seg.refs) replacement.push(citeRefNode(ref));\n        }\n      }\n      return replacement;\n    });\n    return tree;\n  };\n}\n","'use client';\n\n/**\n * ChartBlock — the widget's inline chart card.\n *\n * Owns the card chrome (title, subtitle, legend, provenance line, View-data +\n * Copy-CSV affordances, error card), measures its own width, and dispatches\n * the validated spec to the per-type renderer in chart-renderers.tsx. All\n * colors come from the `--chat-*` token ramp via the `--chat-chart-*` palette,\n * so a chart matches the surface in light/dark/white-label for free.\n *\n * Trust boundary (PRD §3):\n *   - provenance line when the spec declares one (\"Source: <x>\"); unsourced\n *     charts render no label - inside an assistant bubble \"model-generated\"\n *     is a tautology, so only positive provenance carries signal\n *   - a renderer that throws (e.g. a pie that doesn't sum to a whole) is caught\n *     here and rendered as the error card — never a broken/partial chart\n *   - the data table + Copy CSV make the numbers one click away\n */\nimport { useRef, useState, type ReactNode } from 'react';\nimport { CheckIcon, CopyIcon, ChevronDownIcon } from 'lucide-react';\nimport type { ChartSpec } from './chart-spec';\nimport { asSeriesArray } from './chart-spec';\nimport { chartHeight, legendItems, renderChart } from './chart-renderers';\nimport { formatTick } from './chart-geometry';\nimport { useChartWidth } from './use-chart-width';\n\nexport interface ChartBlockProps {\n  spec: ChartSpec;\n  className?: string;\n}\n\nexport function ChartBlock({ spec, className }: ChartBlockProps) {\n  const [showData, setShowData] = useState(false);\n  const [copied, setCopied] = useState(false);\n  const plotRef = useRef<HTMLDivElement | null>(null);\n  const width = useChartWidth(plotRef);\n\n  // Render the chart, catching a thrown honesty error (e.g. a non-whole pie) so\n  // it degrades to the error card rather than crashing the message bubble.\n  let chart: ReactNode;\n  let renderError: string | null = null;\n  try {\n    chart = renderChart(spec, width);\n  } catch (err) {\n    renderError = err instanceof Error ? err.message : String(err);\n    chart = null;\n  }\n\n  const copyCsv = async () => {\n    const serieses = asSeriesArray(spec);\n    // For scatter, export x,y pairs.\n    if (spec.type === 'scatter') {\n      const rows = (spec.scatter ?? []).map((p) => `${p.x},${p.y}${p.label ? `,${csvEscape(p.label)}` : ''}`);\n      const csv = [`x,y${spec.scatter?.[0]?.label ? ',label' : ''}`, ...rows].join('\\n');\n      await writeClipboard(csv);\n      return;\n    }\n    // Single series: label,value. Multi: a header row + one row per category.\n    if (serieses.length === 1) {\n      const s = serieses[0];\n      const csv = [`${csvEscape(spec.xLabel ?? 'label')},${csvEscape(spec.yLabel ?? 'value')}`, ...s.points.map((p) => `${csvEscape(p.label)},${p.value}`)].join('\\n');\n      await writeClipboard(csv);\n      return;\n    }\n    const categories = serieses[0].points.map((p) => p.label);\n    const header = ['category', ...serieses.map((s) => csvEscape(s.name ?? 'series'))].join(',');\n    const rows = categories.map((c) => [csvEscape(c), ...serieses.map((s) => s.points.find((p) => p.label === c)?.value ?? '')].join(','));\n    await writeClipboard([header, ...rows].join('\\n'));\n  };\n\n  const writeClipboard = async (csv: string) => {\n    try {\n      await navigator.clipboard.writeText(csv);\n      setCopied(true);\n      setTimeout(() => setCopied(false), 1500);\n    } catch {\n      /* clipboard unavailable (e.g. http) — ignore */\n    }\n  };\n\n  // Positive provenance only. The old fallback (\"Model-generated\") labeled\n  // every unsourced chart, but inside an assistant bubble that's a tautology -\n  // the signal lives entirely in \"Source: <x>\" being present.\n  const provenance = spec.source ? `Source: ${spec.source}` : null;\n\n  if (renderError) {\n    return <ChartErrorCard error={renderError} rawText={JSON.stringify(spec, null, 2)} className={className} />;\n  }\n\n  const legend = legendItems(spec);\n  const isSparkline = spec.type === 'sparkline';\n\n  return (\n    <div className={`chat-chart not-prose${isSparkline ? ' is-sparkline' : ''} ${className ?? ''}`} role=\"figure\" aria-label={spec.title}>\n      <div className=\"chat-chart-header\">\n        <div className=\"chat-chart-title\">{spec.title}</div>\n        {spec.subtitle ? <div className=\"chat-chart-subtitle\">{spec.subtitle}</div> : null}\n      </div>\n      {legend ? (\n        <ul className=\"chat-chart-legend-row\" aria-label=\"Legend\">\n          {legend.map((item, i) => (\n            <li key={i} className=\"chat-chart-legend\">\n              <span className=\"chat-chart-swatch\" style={{ background: item.color }} />\n              <span>{item.name}</span>\n            </li>\n          ))}\n        </ul>\n      ) : null}\n      {/* The plot measures its own width and reserves its height before the\n          first measurement so the card never jumps when the SVG mounts. */}\n      <div ref={plotRef} className=\"chat-chart-plot\" style={{ minHeight: chartHeight(spec) }}>\n        {chart}\n      </div>\n      <div className=\"chat-chart-footer\">\n        {provenance ? <span className=\"chat-chart-provenance\">{provenance}</span> : <span />}\n        <div className=\"chat-chart-actions\">\n          <button type=\"button\" onClick={() => setShowData((s) => !s)} className=\"chat-chart-toggle\" aria-expanded={showData} aria-label={showData ? 'Hide data' : 'View data'}>\n            <ChevronDownIcon style={{ transform: showData ? 'rotate(180deg)' : undefined }} />\n            <span>{showData ? 'Hide data' : 'View data'}</span>\n          </button>\n          <button type=\"button\" onClick={copyCsv} className=\"chat-chart-toggle\" aria-label={copied ? 'Copied' : 'Copy CSV'}>\n            {copied ? <CheckIcon /> : <CopyIcon />}\n            <span>{copied ? 'Copied' : 'Copy CSV'}</span>\n          </button>\n        </div>\n      </div>\n      {showData ? <DataTable spec={spec} /> : null}\n    </div>\n  );\n}\n\n/** The View-data table — reuses the markdown-table card idiom. Numbers right-align. */\nfunction DataTable({ spec }: { spec: ChartSpec }) {\n  if (spec.type === 'scatter') {\n    return (\n      <div className=\"chat-chart-table\">\n        <table>\n          <thead>\n            <tr>\n              <th className=\"is-num\">{spec.xLabel ?? 'x'}</th>\n              <th className=\"is-num\">{spec.yLabel ?? 'y'}</th>\n              {spec.scatter?.[0]?.label ? <th>Label</th> : null}\n            </tr>\n          </thead>\n          <tbody>\n            {(spec.scatter ?? []).map((p, i) => (\n              <tr key={i}>\n                <td className=\"is-num\">{formatTick(p.x)}</td>\n                <td className=\"is-num\">{formatTick(p.y)}</td>\n                {p.label ? <td>{p.label}</td> : null}\n              </tr>\n            ))}\n          </tbody>\n        </table>\n      </div>\n    );\n  }\n  const serieses = asSeriesArray(spec);\n  if (serieses.length === 1) {\n    const s = serieses[0];\n    return (\n      <div className=\"chat-chart-table\">\n        <table>\n          <thead>\n            <tr>\n              <th>{spec.xLabel ?? 'Label'}</th>\n              <th className=\"is-num\">{spec.yLabel ?? 'Value'}</th>\n            </tr>\n          </thead>\n          <tbody>\n            {s.points.map((p, i) => (\n              <tr key={i}>\n                <td>{p.label}</td>\n                <td className=\"is-num\">{formatTick(p.value)}</td>\n              </tr>\n            ))}\n          </tbody>\n        </table>\n      </div>\n    );\n  }\n  const categories = serieses[0].points.map((p) => p.label);\n  return (\n    <div className=\"chat-chart-table\">\n      <table>\n        <thead>\n          <tr>\n            <th>{spec.xLabel ?? 'Category'}</th>\n            {serieses.map((s, i) => (\n              <th key={i} className=\"is-num\">{s.name ?? `Series ${i + 1}`}</th>\n            ))}\n          </tr>\n        </thead>\n        <tbody>\n          {categories.map((c, ci) => (\n            <tr key={ci}>\n              <td>{c}</td>\n              {serieses.map((s, si) => (\n                <td key={si} className=\"is-num\">{formatTick(s.points.find((p) => p.label === c)?.value ?? 0)}</td>\n              ))}\n            </tr>\n          ))}\n        </tbody>\n      </table>\n    </div>\n  );\n}\n\nexport interface ChartErrorCardProps {\n  error: string;\n  rawText: string;\n  className?: string;\n}\n\nexport function ChartErrorCard({ error, rawText, className }: ChartErrorCardProps) {\n  const [expanded, setExpanded] = useState(false);\n  return (\n    <div className={`chat-chart chat-chart-error ${className ?? ''}`} role=\"alert\">\n      <div className=\"chat-chart-error-head\">This chart couldn't be rendered.</div>\n      <div className=\"chat-chart-error-body\">{error}</div>\n      <button type=\"button\" className=\"chat-chart-toggle\" aria-expanded={expanded} onClick={() => setExpanded((e) => !e)}>\n        <ChevronDownIcon style={{ transform: expanded ? 'rotate(180deg)' : undefined }} />\n        <span>{expanded ? 'Hide raw data' : 'Show raw data'}</span>\n      </button>\n      {expanded ? <pre className=\"chat-chart-error-raw\">{rawText}</pre> : null}\n    </div>\n  );\n}\n\n/** Render a spec-or-error in one call (used by the fence hook + tool renderer). */\nexport function ChartBlockOrError({\n  result,\n  rawText,\n}: {\n  result: { ok: true; spec: ChartSpec } | { ok: false; error: string };\n  rawText: string;\n}): ReactNode {\n  return result.ok ? <ChartBlock spec={result.spec} /> : <ChartErrorCard error={result.error} rawText={rawText} />;\n}\n\n/** RFC 4180 CSV cell escape. */\nfunction csvEscape(s: string): string {\n  if (/[\",\\n\\r]/.test(s)) return `\"${s.replace(/\"/g, '\"\"')}\"`;\n  return s;\n}\n","/**\n * ChartSpec — the declarative, JSON-serializable chart description the widget\n * renders inline in assistant transcripts.\n *\n * v2 widens v1 to a broad, high-quality chart vocabulary while preserving the\n * trust boundary (PRD §3): minimal enough for a model to emit reliably, strict\n * on honesty (finite numbers, required title, bounded points, closed type\n * enum), lenient on unknown fields (forward-compat).\n *\n * Multi-series: `series` accepts either a single ChartSeries (v1 shape, still\n * supported verbatim) or an array. The renderer normalizes to an array\n * internally; a single-series chart needs no array wrapping. Charts that are\n * inherently single-series (pie/donut/sparkline) accept a single `series`.\n *\n * Honesty overrides the model CANNOT set (enforced by the renderer, not the\n * schema, because they're rendering decisions): bar/area y-axis always starts\n * at 0; no dual y-axes (out of scope); pie/donut refused if parts don't sum to\n * ~100% of a stated whole; ordinal single-hue ramp for ranked data, distinct\n * categorical hues only when multiple named series exist. Deliberately absent\n * from the schema so a model can't sneak in a `yMin: 990`.\n *\n * No new runtime deps. zod is already a peer dependency of @mordn/chat-widget\n * (^3.25 || ^4). The schema is written against zod's stable API so both majors\n * accept it.\n */\nimport { z } from 'zod';\n\n/** Schema version. Bumped only on a breaking change to this shape. */\nexport const CHART_SPEC_SCHEMA_VERSION = 2 as const;\n\n/** The chart kinds the renderer supports. Closed — an unknown type is a validation error. */\nexport const CHART_TYPES = [\n  'bar',\n  'horizontal-bar',\n  'line',\n  'area',\n  'multi-line',\n  'stacked-bar',\n  'grouped-bar',\n  'pie',\n  'donut',\n  'scatter',\n  'sparkline',\n] as const;\nexport type ChartType = (typeof CHART_TYPES)[number];\n\n/** Optional semantic color hint (hex). Renderer may honor it; the theme ramp wins otherwise. */\nconst ChartColor = z.string().regex(/^#[0-9a-fA-F]{3,8}$/).optional();\n\n/** A single labelled numeric point. `value` MUST be finite (a chart of NaN is a lie). */\nconst ChartPoint = z.object({\n  label: z.string().min(1),\n  value: z.number().finite(),\n  /** Optional semantic color (hex), mainly for pie/donut slices. Renderer may honor it; the theme ramp wins otherwise. */\n  color: ChartColor,\n});\n\n/**\n * One data series. For categorical charts (bar/line/area) `points` is the\n * measured values. For scatter, `points` carries (x = value, y = label-as-number)\n * — see the scatter renderer for the convention. `color` is a host/model hint\n * the renderer MAY honor, but the honesty ramp wins by default; it's mainly for\n * semantically meaningful colors (e.g. \"this series is the SLA breach line\").\n */\nexport const ChartSeriesSchema = z.object({\n  name: z.string().min(1).optional(),\n  points: z.array(ChartPoint).min(1).max(500),\n  /** Optional semantic color (hex). Renderer honors it when set; otherwise the theme ramp. */\n  color: ChartColor,\n});\nexport type ChartSeries = z.infer<typeof ChartSeriesSchema>;\n\n/** A single-series spec (v1-compatible) OR multi-series. */\nconst SeriesField = z.union([ChartSeriesSchema, z.array(ChartSeriesSchema).min(1).max(12)]);\n\n/** Pie/donut-specific honesty: a whole the slices must sum to (~within tolerance). */\nconst WholeField = z\n  .object({\n    /** The total the slices should sum to. Default 100 (percentages). */\n    total: z.number().finite().positive().default(100),\n    /** Allowed deviation from `total` before the pie is refused (fraction of total). Default 0.02 (2%). */\n    tolerance: z.number().finite().min(0).max(0.1).default(0.02),\n  })\n  .optional();\n\n/** Scatter point: (x, y) pair. `label` is the hover/legend text. */\nconst ScatterPoint = z.object({\n  x: z.number().finite(),\n  y: z.number().finite(),\n  label: z.string().min(1).optional(),\n  color: ChartColor,\n});\n\n/** Stacked/grouped honesty: every series shares the same set of category labels. */\nconst CategoricalSeriesField = z\n  .array(ChartSeriesSchema)\n  .min(1)\n  .max(12)\n  .superRefine((serieses, ctx) => {\n    if (serieses.length < 2) return;\n    const base = new Set(serieses[0].points.map((p) => p.label));\n    serieses.slice(1).forEach((s, i) => {\n      const labels = new Set(s.points.map((p) => p.label));\n      for (const l of base) {\n        if (!labels.has(l)) {\n          ctx.addIssue({\n            code: z.ZodIssueCode.custom,\n            path: [i, 'points'],\n            message: `stacked/grouped series must share category labels; series ${i + 1} is missing \"${l}\"`,\n          });\n        }\n      }\n    });\n  });\n\nexport const ChartSpecSchema = z\n  .object({\n    schemaVersion: z.literal(CHART_SPEC_SCHEMA_VERSION),\n    type: z.enum(CHART_TYPES),\n    title: z.string().min(1),\n    subtitle: z.string().optional(),\n    xLabel: z.string().optional(),\n    yLabel: z.string().optional(),\n    /** Provenance. Absent => \"Model-generated\". Present => \"Source: <source>\". */\n    source: z.string().min(1).optional(),\n    /** Show the legend (multi-series only). Default true when >1 series. */\n    legend: z.boolean().optional(),\n    /** Show value labels on bars/points. Default false (clutter). */\n    valueLabels: z.boolean().optional(),\n    // series: type-dependent. Pie/donut/sparkline => single ChartSeries.\n    //        stacked-bar/grouped-bar => array with shared labels (enforced).\n    //        everything else => single or array.\n    series: SeriesField.optional(),\n    /** Pie/donut only: the whole the slices must sum to. */\n    whole: WholeField,\n    /** Scatter only (replaces `series`). */\n    scatter: z.array(ScatterPoint).min(1).max(500).optional(),\n  })\n  // NOTE: no .passthrough() — z.object STRIPS unknown keys by default, which is\n  // the honesty contract: a model can't sneak `yMin: 990` (or any future axis\n  // override) through to the renderer.\n  .superRefine((spec, ctx) => {\n    // Type-specific field requirements + honesty guards.\n    if (spec.type === 'scatter') {\n      if (!spec.scatter || spec.scatter.length === 0) {\n        ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['scatter'], message: 'scatter charts require a `scatter` array' });\n      }\n    } else if (!spec.series) {\n      // Every non-scatter type charts `series`; scatter is the only shape that\n      // replaces it (making the field optional above so scatter can parse).\n      ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['series'], message: `${spec.type} charts require a \\`series\\`` });\n    } else if (spec.type === 'pie' || spec.type === 'donut') {\n      // Pie/donut: a single series; the whole is checked at render time against\n      // the actual slice sum (the renderer refuses + shows the error card if the\n      // slices don't sum within tolerance of `whole.total`).\n      if (Array.isArray(spec.series)) {\n        ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['series'], message: `${spec.type} charts take a single series, not an array` });\n      }\n    } else if (spec.type === 'stacked-bar' || spec.type === 'grouped-bar') {\n      // These REQUIRE an array (the schema's SeriesField union would also accept\n      // a single object, so enforce the array here). The shared-labels guard\n      // lives on CategoricalSeriesField — but SeriesField doesn't carry it, so\n      // we re-validate here.\n      if (!Array.isArray(spec.series)) {\n        ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['series'], message: `${spec.type} charts require a series array (2+ series)` });\n      } else {\n        const s = spec.series;\n        if (s.length < 2) {\n          ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['series'], message: `${spec.type} charts need at least 2 series` });\n        }\n        const base = new Set(s[0].points.map((p) => p.label));\n        s.slice(1).forEach((ser, i) => {\n          const labels = new Set(ser.points.map((p) => p.label));\n          for (const l of base) {\n            if (!labels.has(l)) {\n              ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['series', i, 'points'], message: `${spec.type} series must share category labels; series ${i + 2} is missing \"${l}\"` });\n            }\n          }\n        });\n      }\n    }\n  });\n\nexport type ChartSpec = z.infer<typeof ChartSpecSchema>;\n\n/**\n * Normalize a spec's `series` field to an array of ChartSeries, regardless of\n * whether the model passed a single object or an array. Single-series charts\n * (pie/donut/sparkline) still get a 1-element array; callers index [0].\n */\nexport function asSeriesArray(spec: ChartSpec): ChartSeries[] {\n  if (spec.series === undefined) return []; // scatter (uses `spec.scatter`) or a spec that failed the series guard\n  return Array.isArray(spec.series) ? spec.series : [spec.series];\n}\n\n/** The fence languages that trigger the chart renderer (Seam A). */\nexport const CHART_FENCE_LANGUAGES = ['mordn-chart', 'chart'] as const;\nexport type ChartFenceLanguage = (typeof CHART_FENCE_LANGUAGES)[number];\n\n/** True if a fenced-block language should render as a chart. */\nexport function isChartFenceLanguage(language: string | undefined): boolean {\n  if (!language) return false;\n  const lower = language.trim().toLowerCase();\n  return (CHART_FENCE_LANGUAGES as readonly string[]).includes(lower);\n}\n\nexport type ChartSpecParseResult =\n  | { ok: true; spec: ChartSpec }\n  | { ok: false; error: string; issues: string[] };\n\nexport function parseChartSpec(text: string): ChartSpecParseResult {\n  let json: unknown;\n  try {\n    json = JSON.parse(text);\n  } catch {\n    return {\n      ok: false,\n      error: 'Chart data is not valid JSON.',\n      issues: ['The fence body could not be parsed as JSON.'],\n    };\n  }\n  const result = ChartSpecSchema.safeParse(json);\n  if (result.success) {\n    return { ok: true, spec: result.data };\n  }\n  const issues = result.error.issues.map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`);\n  return { ok: false, error: 'Chart data did not match the expected shape.', issues };\n}\n\n/** Validate an already-parsed object (for hosts building a spec programmatically). Throws on invalid. */\nexport function validateChartSpec(input: unknown): ChartSpec {\n  return ChartSpecSchema.parse(input);\n}\n","'use client';\n\n/**\n * Chart renderers — one pure-SVG component per ChartType, sharing the pixel\n * frame, scales, and palette in chart-geometry.ts.\n *\n * v3 principles (the \"does this look like a product or a homework plot\" bar):\n *   - real pixels: 11px type and 1px hairlines at every card width\n *   - the value axis of a bar chart INCLUDES zero; with losses the baseline\n *     moves into the plot and negative bars take the negative color\n *   - category labels are thinned, never rotated; the tooltip carries the\n *     full text\n *   - gridlines only, no y-axis line; one baseline hairline\n *   - a real hover tooltip with crosshair / highlight, no native <title>s\n *   - legends live in HTML under the plot (ChartBlock), never inside it\n *\n * No chart library. All colors from the `--chat-*` token ramp via the\n * `--chat-chart-*` palette declared in styles.src.css.\n */\nimport { useId, useState, type MouseEvent, type ReactElement, type ReactNode } from 'react';\nimport type { ChartSpec, ChartSeries } from './chart-spec';\nimport { asSeriesArray } from './chart-spec';\nimport {\n  CARTESIAN_HEIGHT,\n  PIE_HEIGHT,\n  SPARKLINE_HEIGHT,\n  NEGATIVE_COLOR,\n  makeFrame,\n  niceScale,\n  yToPx,\n  xToPx,\n  slotWidth,\n  slotCenter,\n  pointX,\n  planCategoryLabels,\n  formatTick,\n  seriesColors,\n  resolveSeriesColor,\n  trimLabel,\n  barPath,\n  px,\n  type Frame,\n  type Scale,\n} from './chart-geometry';\nimport { ChartTooltip, type TooltipRow, type TooltipState } from './chart-tooltip';\n\nexport interface RendererProps {\n  spec: ChartSpec;\n  /** Container width in CSS px (measured by ChartBlock). */\n  width: number;\n}\n\n/** One legend entry. ChartBlock renders these as HTML under the plot. */\nexport interface LegendItem {\n  name: string;\n  color: string;\n}\n\n// ── shared chrome ─────────────────────────────────────────────────────────────\n\ninterface XLabel {\n  x: number;\n  label: string;\n}\n\n/** Y gridlines + ticks, x baseline + thinned labels, axis titles. */\nfunction AxisChrome({ f, yScale, xLabels, xLabel, yLabel }: { f: Frame; yScale: Scale; xLabels: XLabel[]; xLabel?: string; yLabel?: string }) {\n  const spacing = xLabels.length > 1 ? Math.abs(xLabels[1].x - xLabels[0].x) : f.plotW;\n  const plan = planCategoryLabels(xLabels.map((l) => l.label), spacing);\n  const baseY = f.top + f.plotH;\n  return (\n    <g>\n      {yScale.ticks.map((t) => {\n        const y = yToPx(t, yScale, f);\n        const isBase = Math.abs(y - baseY) < 0.5;\n        return (\n          <g key={t}>\n            {!isBase ? <line x1={f.left} y1={px(y)} x2={f.left + f.plotW} y2={px(y)} className=\"chat-chart-gridline\" /> : null}\n            <text x={f.left - 8} y={y} dy=\"0.35em\" textAnchor=\"end\" className=\"chat-chart-tick\">\n              {formatTick(t)}\n            </text>\n          </g>\n        );\n      })}\n      <line x1={f.left} y1={px(baseY)} x2={f.left + f.plotW} y2={px(baseY)} className=\"chat-chart-axis\" />\n      {xLabels.map((l, i) =>\n        i % plan.every === 0 ? (\n          <text key={i} x={l.x} y={baseY + 16} textAnchor=\"middle\" className=\"chat-chart-tick\">\n            {trimLabel(l.label, plan.maxChars)}\n          </text>\n        ) : null,\n      )}\n      {yLabel ? (\n        <text x={-(f.top + f.plotH / 2)} y={12} transform=\"rotate(-90)\" textAnchor=\"middle\" className=\"chat-chart-axislabel\">\n          {yLabel}\n        </text>\n      ) : null}\n      {xLabel ? (\n        <text x={f.left + f.plotW / 2} y={f.height - 5} textAnchor=\"middle\" className=\"chat-chart-axislabel\">\n          {xLabel}\n        </text>\n      ) : null}\n    </g>\n  );\n}\n\n/** The emphasized zero line, drawn only when the axis crosses zero. */\nfunction ZeroLine({ f, scale }: { f: Frame; scale: Scale }) {\n  if (scale.min >= 0) return null;\n  const y = yToPx(0, scale, f);\n  return <line x1={f.left} y1={px(y)} x2={f.left + f.plotW} y2={px(y)} className=\"chat-chart-zero\" />;\n}\n\n/** Transparent per-category hit targets that drive the hover state. */\nfunction HitSlots({ f, n, onHover, centers }: { f: Frame; n: number; centers: (i: number) => number; onHover: (i: number | null) => void }) {\n  const slot = n > 1 ? Math.abs(centers(1) - centers(0)) : f.plotW;\n  return (\n    <g className=\"chat-chart-hits\">\n      {Array.from({ length: n }, (_, i) => (\n        <rect\n          key={i}\n          x={px(centers(i) - slot / 2)}\n          y={f.top}\n          width={px(Math.max(1, slot))}\n          height={f.plotH}\n          fill=\"transparent\"\n          onMouseEnter={() => onHover(i)}\n          onClick={() => onHover(i)}\n          data-index={i}\n        />\n      ))}\n    </g>\n  );\n}\n\nfunction useHover(): [number | null, (i: number | null) => void] {\n  const [i, setI] = useState<number | null>(null);\n  return [i, setI];\n}\n\nfunction svgProps(f: Frame, title: string) {\n  return {\n    width: f.width,\n    height: f.height,\n    viewBox: `0 0 ${f.width} ${f.height}`,\n    role: 'img' as const,\n    'aria-label': title,\n    className: 'chat-chart-svg',\n  };\n}\n\nfunction seriesRows(serieses: ChartSeries[], colors: string[], i: number): TooltipRow[] {\n  return serieses.map((s, si) => ({\n    swatch: serieses.length > 1 ? colors[si] : undefined,\n    name: serieses.length > 1 ? s.name ?? `Series ${si + 1}` : undefined,\n    value: formatTick(s.points[i]?.value ?? 0),\n  }));\n}\n\n// ── bar ──────────────────────────────────────────────────────────────────────\nexport function BarChart({ spec, width }: RendererProps): ReactElement {\n  const series = asSeriesArray(spec)[0];\n  const points = series.points;\n  const n = points.length;\n  const values = points.map((p) => p.value);\n  const scale = niceScale(Math.min(...values), Math.max(...values), true);\n  const f = makeFrame(width, CARTESIAN_HEIGHT, { yTickLabels: scale.ticks.map(formatTick), hasXLabel: !!spec.xLabel, hasYLabel: !!spec.yLabel });\n  const slot = slotWidth(n, f);\n  const barW = Math.max(4, Math.min(slot * 0.6, 40));\n  const color = resolveSeriesColor(series.color, 0, seriesColors(1));\n  const hasNeg = values.some((v) => v < 0);\n  const zeroY = yToPx(0, scale, f);\n  const [hover, setHover] = useHover();\n  const xLabels = points.map((p, i) => ({ x: slotCenter(i, n, f), label: p.label }));\n\n  let tip: TooltipState | null = null;\n  if (hover !== null && points[hover]) {\n    const v = points[hover].value;\n    tip = { x: slotCenter(hover, n, f), y: Math.min(yToPx(v, scale, f), zeroY), title: points[hover].label, rows: [{ value: formatTick(v) }] };\n  }\n\n  return (\n    <>\n      <svg {...svgProps(f, spec.title)} onMouseLeave={() => setHover(null)}>\n        <title>{spec.title}</title>\n        <AxisChrome f={f} yScale={scale} xLabels={xLabels} xLabel={spec.xLabel} yLabel={spec.yLabel} />\n        <ZeroLine f={f} scale={scale} />\n        {points.map((p, i) => {\n          const cx = slotCenter(i, n, f);\n          const y = yToPx(p.value, scale, f);\n          const top = Math.min(y, zeroY);\n          const h = Math.abs(zeroY - y);\n          const neg = p.value < 0;\n          return (\n            <path\n              key={i}\n              d={barPath(cx - barW / 2, top, barW, Math.max(h, p.value === 0 ? 0 : 1), 3, neg ? 'bottom' : 'top')}\n              className={`chat-chart-bar${hover !== null && hover !== i ? ' is-dim' : ''}`}\n              fill={hasNeg && neg ? NEGATIVE_COLOR : resolveSeriesColor(p.color, 0, [color])}\n            />\n          );\n        })}\n        {spec.valueLabels\n          ? points.map((p, i) => {\n              const y = yToPx(p.value, scale, f);\n              return (\n                <text key={`v${i}`} x={slotCenter(i, n, f)} y={p.value < 0 ? y + 12 : y - 5} textAnchor=\"middle\" className=\"chat-chart-value\">\n                  {formatTick(p.value)}\n                </text>\n              );\n            })\n          : null}\n        <HitSlots f={f} n={n} centers={(i) => slotCenter(i, n, f)} onHover={setHover} />\n      </svg>\n      {tip ? <ChartTooltip tip={tip} width={f.width} /> : null}\n    </>\n  );\n}\n\n// ── horizontal-bar ────────────────────────────────────────────────────────────\nexport function HorizontalBarChart({ spec, width }: RendererProps): ReactElement {\n  const series = asSeriesArray(spec)[0];\n  const points = series.points;\n  const n = points.length;\n  const values = points.map((p) => p.value);\n  const scale = niceScale(Math.min(...values), Math.max(...values), true);\n  const height = Math.max(150, Math.min(440, n * 30 + 40));\n  const labels = points.map((p) => trimLabel(p.label, 18));\n  const f = makeFrame(width, height, { leftLabels: labels, hasXLabel: !!spec.xLabel, hasYLabel: false });\n  const rowH = f.plotH / n;\n  const barH = Math.max(4, Math.min(rowH * 0.62, 26));\n  const color = resolveSeriesColor(series.color, 0, seriesColors(1));\n  const hasNeg = values.some((v) => v < 0);\n  const zeroX = xToPx(0, scale, f);\n  const showValues = spec.valueLabels !== false;\n  const [hover, setHover] = useHover();\n\n  let tip: TooltipState | null = null;\n  if (hover !== null && points[hover]) {\n    const v = points[hover].value;\n    tip = { x: Math.max(xToPx(v, scale, f), zeroX), y: f.top + rowH * hover + rowH / 2, title: points[hover].label, rows: [{ value: formatTick(v) }] };\n  }\n\n  return (\n    <>\n      <svg {...svgProps(f, spec.title)} onMouseLeave={() => setHover(null)}>\n        <title>{spec.title}</title>\n        {scale.ticks.map((t) => {\n          const x = xToPx(t, scale, f);\n          return (\n            <g key={t}>\n              <line x1={px(x)} y1={f.top} x2={px(x)} y2={f.top + f.plotH} className={t === 0 && scale.min < 0 ? 'chat-chart-zero' : 'chat-chart-gridline'} />\n              <text x={x} y={f.top + f.plotH + 16} textAnchor=\"middle\" className=\"chat-chart-tick\">\n                {formatTick(t)}\n              </text>\n            </g>\n          );\n        })}\n        {spec.xLabel ? (\n          <text x={f.left + f.plotW / 2} y={f.height - 5} textAnchor=\"middle\" className=\"chat-chart-axislabel\">\n            {spec.xLabel}\n          </text>\n        ) : null}\n        {points.map((p, i) => {\n          const cy = f.top + rowH * i + rowH / 2;\n          const xv = xToPx(p.value, scale, f);\n          const x0 = Math.min(xv, zeroX);\n          const w = Math.abs(xv - zeroX);\n          const neg = p.value < 0;\n          return (\n            <g key={i} className={hover !== null && hover !== i ? 'is-dim' : undefined}>\n              <text x={f.left - 8} y={cy} dy=\"0.35em\" textAnchor=\"end\" className=\"chat-chart-tick chat-chart-category\">\n                {labels[i]}\n              </text>\n              <path d={barPath(x0, cy - barH / 2, Math.max(w, p.value === 0 ? 0 : 1), barH, 3, neg ? 'left' : 'right')} className=\"chat-chart-bar\" fill={hasNeg && neg ? NEGATIVE_COLOR : resolveSeriesColor(p.color, 0, [color])} />\n              {showValues ? (\n                <text x={neg ? x0 - 6 : x0 + w + 6} y={cy} dy=\"0.35em\" textAnchor={neg ? 'end' : 'start'} className=\"chat-chart-value\">\n                  {formatTick(p.value)}\n                </text>\n              ) : null}\n            </g>\n          );\n        })}\n        <g className=\"chat-chart-hits\">\n          {points.map((_, i) => (\n            <rect key={i} x={0} y={px(f.top + rowH * i)} width={f.width} height={px(rowH)} fill=\"transparent\" onMouseEnter={() => setHover(i)} onClick={() => setHover(i)} data-index={i} />\n          ))}\n        </g>\n      </svg>\n      {tip ? <ChartTooltip tip={tip} width={f.width} /> : null}\n    </>\n  );\n}\n\n// ── line / multi-line / area ──────────────────────────────────────────────────\nexport function LineChart({ spec, width, area = false }: RendererProps & { area?: boolean }): ReactElement {\n  const serieses = asSeriesArray(spec);\n  const longest = serieses.reduce((a, s) => (s.points.length > a.points.length ? s : a), serieses[0]);\n  const n = longest.points.length;\n  const allValues = serieses.flatMap((s) => s.points.map((p) => p.value));\n  const scale = niceScale(Math.min(...allValues), Math.max(...allValues), area);\n  const f = makeFrame(width, CARTESIAN_HEIGHT, { yTickLabels: scale.ticks.map(formatTick), hasXLabel: !!spec.xLabel, hasYLabel: !!spec.yLabel });\n  const colors = seriesColors(serieses.length).map((c, i) => resolveSeriesColor(serieses[i].color, i, [c]));\n  const gradientId = useId();\n  const [hover, setHover] = useHover();\n  const showDots = n <= 24;\n  const xLabels = longest.points.map((p, i) => ({ x: pointX(i, n, f), label: p.label }));\n  const baseY = f.top + f.plotH;\n\n  let tip: TooltipState | null = null;\n  if (hover !== null && longest.points[hover]) {\n    const ys = serieses.map((s) => (s.points[hover] ? yToPx(s.points[hover].value, scale, f) : baseY));\n    tip = { x: pointX(hover, n, f), y: Math.min(...ys), title: longest.points[hover].label, rows: seriesRows(serieses, colors, hover) };\n  }\n\n  return (\n    <>\n      <svg {...svgProps(f, spec.title)} onMouseLeave={() => setHover(null)}>\n        <title>{spec.title}</title>\n        {area ? (\n          <defs>\n            {serieses.map((_, si) => (\n              <linearGradient key={si} id={`${gradientId}-${si}`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n                <stop offset=\"0%\" stopColor={colors[si]} stopOpacity={0.28} />\n                <stop offset=\"100%\" stopColor={colors[si]} stopOpacity={0.02} />\n              </linearGradient>\n            ))}\n          </defs>\n        ) : null}\n        <AxisChrome f={f} yScale={scale} xLabels={xLabels} xLabel={spec.xLabel} yLabel={spec.yLabel} />\n        <ZeroLine f={f} scale={scale} />\n        {hover !== null ? <line x1={px(pointX(hover, n, f))} y1={f.top} x2={px(pointX(hover, n, f))} y2={baseY} className=\"chat-chart-crosshair\" /> : null}\n        {serieses.map((s, si) => {\n          const m = s.points.length;\n          const coords = s.points.map((p, i) => [pointX(i, m, f), yToPx(p.value, scale, f)] as const);\n          const d = coords.map(([x, y], i) => `${i === 0 ? 'M' : 'L'}${px(x)},${px(y)}`).join(' ');\n          const areaD = area && coords.length ? `${d} L${px(coords[coords.length - 1][0])},${px(baseY)} L${px(coords[0][0])},${px(baseY)} Z` : null;\n          return (\n            <g key={si}>\n              {areaD ? <path d={areaD} className=\"chat-chart-area\" fill={`url(#${gradientId}-${si})`} /> : null}\n              <path d={d} className=\"chat-chart-line\" fill=\"none\" stroke={colors[si]} />\n              {coords.map(([x, y], i) => {\n                const active = hover === i;\n                if (!showDots && !active) return null;\n                return <circle key={i} cx={px(x)} cy={px(y)} r={active ? 4.5 : 3} className={`chat-chart-point${active ? ' is-active' : ''}`} fill={colors[si]} />;\n              })}\n              {spec.valueLabels && showDots\n                ? coords.map(([x, y], i) => (\n                    <text key={`v${i}`} x={x} y={y - 8} textAnchor=\"middle\" className=\"chat-chart-value\">\n                      {formatTick(s.points[i].value)}\n                    </text>\n                  ))\n                : null}\n            </g>\n          );\n        })}\n        <HitSlots f={f} n={n} centers={(i) => pointX(i, n, f)} onHover={setHover} />\n      </svg>\n      {tip ? <ChartTooltip tip={tip} width={f.width} /> : null}\n    </>\n  );\n}\n\n// ── stacked-bar ────────────────────────────────────────────────────────────────\nexport function StackedBarChart({ spec, width }: RendererProps): ReactElement {\n  const serieses = asSeriesArray(spec);\n  const categories = serieses[0].points.map((p) => p.label);\n  const n = categories.length;\n  const sums = categories.map((_, i) => serieses.reduce((acc, s) => acc + Math.max(0, s.points[i]?.value ?? 0), 0));\n  const scale = niceScale(0, Math.max(...sums, 0), true);\n  const f = makeFrame(width, CARTESIAN_HEIGHT, { yTickLabels: scale.ticks.map(formatTick), hasXLabel: !!spec.xLabel, hasYLabel: !!spec.yLabel });\n  const colors = seriesColors(serieses.length).map((c, i) => resolveSeriesColor(serieses[i].color, i, [c]));\n  const slot = slotWidth(n, f);\n  const barW = Math.max(4, Math.min(slot * 0.6, 40));\n  const [hover, setHover] = useHover();\n  const xLabels = categories.map((c, i) => ({ x: slotCenter(i, n, f), label: c }));\n\n  let tip: TooltipState | null = null;\n  if (hover !== null && categories[hover] !== undefined) {\n    tip = {\n      x: slotCenter(hover, n, f),\n      y: yToPx(sums[hover], scale, f),\n      title: categories[hover],\n      rows: [...seriesRows(serieses, colors, hover), { name: 'Total', value: formatTick(sums[hover]) }],\n    };\n  }\n\n  return (\n    <>\n      <svg {...svgProps(f, spec.title)} onMouseLeave={() => setHover(null)}>\n        <title>{spec.title}</title>\n        <AxisChrome f={f} yScale={scale} xLabels={xLabels} xLabel={spec.xLabel} yLabel={spec.yLabel} />\n        {categories.map((_, ci) => {\n          const cx = slotCenter(ci, n, f);\n          let acc = 0;\n          const lastIdx = serieses.reduce((last, s, si) => ((s.points[ci]?.value ?? 0) > 0 ? si : last), -1);\n          return (\n            <g key={ci} className={hover !== null && hover !== ci ? 'is-dim' : undefined}>\n              {serieses.map((s, si) => {\n                const v = Math.max(0, s.points[ci]?.value ?? 0);\n                if (v <= 0) return null;\n                const yTop = yToPx(acc + v, scale, f);\n                const yBot = yToPx(acc, scale, f);\n                acc += v;\n                const h = Math.max(1, yBot - yTop);\n                return si === lastIdx ? (\n                  <path key={si} d={barPath(cx - barW / 2, yTop, barW, h, 3, 'top')} className=\"chat-chart-bar\" fill={colors[si]} />\n                ) : (\n                  <rect key={si} x={px(cx - barW / 2)} y={px(yTop)} width={px(barW)} height={px(h)} className=\"chat-chart-bar\" fill={colors[si]} />\n                );\n              })}\n            </g>\n          );\n        })}\n        {spec.valueLabels\n          ? sums.map((sum, i) => (\n              <text key={`v${i}`} x={slotCenter(i, n, f)} y={yToPx(sum, scale, f) - 5} textAnchor=\"middle\" className=\"chat-chart-value\">\n                {formatTick(sum)}\n              </text>\n            ))\n          : null}\n        <HitSlots f={f} n={n} centers={(i) => slotCenter(i, n, f)} onHover={setHover} />\n      </svg>\n      {tip ? <ChartTooltip tip={tip} width={f.width} /> : null}\n    </>\n  );\n}\n\n// ── grouped-bar ────────────────────────────────────────────────────────────────\nexport function GroupedBarChart({ spec, width }: RendererProps): ReactElement {\n  const serieses = asSeriesArray(spec);\n  const categories = serieses[0].points.map((p) => p.label);\n  const n = categories.length;\n  const k = serieses.length;\n  const allValues = serieses.flatMap((s) => s.points.map((p) => p.value));\n  const scale = niceScale(Math.min(...allValues), Math.max(...allValues), true);\n  const f = makeFrame(width, CARTESIAN_HEIGHT, { yTickLabels: scale.ticks.map(formatTick), hasXLabel: !!spec.xLabel, hasYLabel: !!spec.yLabel });\n  const colors = seriesColors(k).map((c, i) => resolveSeriesColor(serieses[i].color, i, [c]));\n  const slot = slotWidth(n, f);\n  const gap = 2;\n  const groupW = Math.min(slot * 0.76, k * 22);\n  const barW = Math.max(3, (groupW - gap * (k - 1)) / k);\n  const hasNeg = allValues.some((v) => v < 0);\n  const zeroY = yToPx(0, scale, f);\n  const [hover, setHover] = useHover();\n  const xLabels = categories.map((c, i) => ({ x: slotCenter(i, n, f), label: c }));\n\n  let tip: TooltipState | null = null;\n  if (hover !== null && categories[hover] !== undefined) {\n    const ys = serieses.map((s) => yToPx(s.points[hover]?.value ?? 0, scale, f));\n    tip = { x: slotCenter(hover, n, f), y: Math.min(...ys, zeroY), title: categories[hover], rows: seriesRows(serieses, colors, hover) };\n  }\n\n  return (\n    <>\n      <svg {...svgProps(f, spec.title)} onMouseLeave={() => setHover(null)}>\n        <title>{spec.title}</title>\n        <AxisChrome f={f} yScale={scale} xLabels={xLabels} xLabel={spec.xLabel} yLabel={spec.yLabel} />\n        <ZeroLine f={f} scale={scale} />\n        {categories.map((_, ci) => {\n          const groupX = slotCenter(ci, n, f) - (barW * k + gap * (k - 1)) / 2;\n          return (\n            <g key={ci} className={hover !== null && hover !== ci ? 'is-dim' : undefined}>\n              {serieses.map((s, si) => {\n                const v = s.points[ci]?.value ?? 0;\n                const y = yToPx(v, scale, f);\n                const neg = v < 0;\n                const x = groupX + si * (barW + gap);\n                return <path key={si} d={barPath(x, Math.min(y, zeroY), barW, Math.max(Math.abs(zeroY - y), v === 0 ? 0 : 1), 2, neg ? 'bottom' : 'top')} className=\"chat-chart-bar\" fill={hasNeg && neg ? NEGATIVE_COLOR : colors[si]} />;\n              })}\n            </g>\n          );\n        })}\n        <HitSlots f={f} n={n} centers={(i) => slotCenter(i, n, f)} onHover={setHover} />\n      </svg>\n      {tip ? <ChartTooltip tip={tip} width={f.width} /> : null}\n    </>\n  );\n}\n\n// ── pie / donut ────────────────────────────────────────────────────────────────\n\n/**\n * Honesty guard: pie/donut slices must sum to ~the declared whole (default 100).\n * A pie that doesn't sum to a whole is the single most misleading chart there is.\n *\n * This is a PLAIN FUNCTION, called by renderChart BEFORE the element is\n * created, and that placement is load-bearing: `renderChart` only *creates*\n * elements, so ChartBlock's try/catch wraps element creation, not the component\n * call. A throw from inside the component body would escape the catch and blank\n * the whole message bubble. Validating here keeps the throw inside the try.\n */\nfunction assertPieSumsToWhole(spec: ChartSpec): void {\n  const points = asSeriesArray(spec)[0].points;\n  const total = points.reduce((acc, p) => acc + p.value, 0);\n  const whole = spec.whole ?? { total: 100, tolerance: 0.02 };\n  const tolerance = whole.total * whole.tolerance;\n  if (Math.abs(total - whole.total) > tolerance) {\n    throw new Error(\n      `The ${spec.type} slices sum to ${formatTick(total)}, which is outside the declared whole of ${formatTick(whole.total)} (±${formatTick(tolerance)}). A pie/donut must represent parts of a single whole.`,\n    );\n  }\n}\n\nexport function PieChart({ spec, width, donut = false }: RendererProps & { donut?: boolean }): ReactElement {\n  const series = asSeriesArray(spec)[0];\n  const points = series.points;\n  const total = points.reduce((acc, p) => acc + p.value, 0);\n  const size = PIE_HEIGHT;\n  const cx = size / 2;\n  const cy = size / 2;\n  const r = size / 2 - 6;\n  const innerR = donut ? r * 0.64 : 0;\n  const colors = seriesColors(Math.max(2, points.length));\n  const [hover, setHover] = useHover();\n  const sideBySide = width >= 420;\n\n  let angle = -Math.PI / 2; // start at 12 o'clock\n  const slices = points.map((p, i) => {\n    const frac = total > 0 ? p.value / total : 0;\n    const sweep = frac * Math.PI * 2;\n    const a0 = angle;\n    const a1 = angle + Math.min(sweep, Math.PI * 2 - 1e-4);\n    angle += sweep;\n    const large = sweep > Math.PI ? 1 : 0;\n    const x0 = cx + r * Math.cos(a0), y0 = cy + r * Math.sin(a0);\n    const x1 = cx + r * Math.cos(a1), y1 = cy + r * Math.sin(a1);\n    const d = donut\n      ? `M${px(x0)},${px(y0)} A${r},${r} 0 ${large} 1 ${px(x1)},${px(y1)} L${px(cx + innerR * Math.cos(a1))},${px(cy + innerR * Math.sin(a1))} A${innerR},${innerR} 0 ${large} 0 ${px(cx + innerR * Math.cos(a0))},${px(cy + innerR * Math.sin(a0))} Z`\n      : `M${cx},${cy} L${px(x0)},${px(y0)} A${r},${r} 0 ${large} 1 ${px(x1)},${px(y1)} Z`;\n    return { d, color: resolveSeriesColor(p.color, i, colors), label: p.label, value: p.value, pct: frac * 100 };\n  });\n\n  const active = hover !== null ? slices[hover] : null;\n\n  return (\n    <div className={`chat-chart-pie${sideBySide ? ' is-side' : ''}`} onMouseLeave={() => setHover(null)}>\n      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} role=\"img\" aria-label={spec.title} className=\"chat-chart-svg\">\n        <title>{spec.title}</title>\n        {slices.map((s, i) => (\n          <path key={i} d={s.d} className={`chat-chart-slice${hover !== null && hover !== i ? ' is-dim' : ''}`} fill={s.color} onMouseEnter={() => setHover(i)} onClick={() => setHover(i)} data-index={i} />\n        ))}\n        {donut ? (\n          <g className=\"chat-chart-donut-center\">\n            <text x={cx} y={cy - 4} textAnchor=\"middle\" className=\"chat-chart-donut-value\">\n              {active ? `${active.pct.toFixed(active.pct < 10 ? 1 : 0)}%` : formatTick(total)}\n            </text>\n            <text x={cx} y={cy + 13} textAnchor=\"middle\" className=\"chat-chart-donut-label\">\n              {active ? trimLabel(active.label, 16) : 'Total'}\n            </text>\n          </g>\n        ) : null}\n      </svg>\n      <ul className=\"chat-chart-pie-list\" aria-label=\"Slices\">\n        {slices.map((s, i) => (\n          <li key={i} className={`chat-chart-legend chat-chart-pie-row${hover === i ? ' is-active' : ''}${hover !== null && hover !== i ? ' is-dim' : ''}`} onMouseEnter={() => setHover(i)} data-index={i}>\n            <span className=\"chat-chart-swatch\" style={{ background: s.color }} />\n            <span className=\"chat-chart-pie-name\">{s.label}</span>\n            <span className=\"chat-chart-pie-value\">{formatTick(s.value)}</span>\n            <span className=\"chat-chart-pie-pct\">{s.pct.toFixed(s.pct < 10 ? 1 : 0)}%</span>\n          </li>\n        ))}\n      </ul>\n    </div>\n  );\n}\n\n// ── scatter ────────────────────────────────────────────────────────────────────\nexport function ScatterChart({ spec, width }: RendererProps): ReactElement {\n  const pts = spec.scatter ?? [];\n  const xs = pts.map((p) => p.x);\n  const ys = pts.map((p) => p.y);\n  const xScale = niceScale(Math.min(...xs), Math.max(...xs), false);\n  const yScale = niceScale(Math.min(...ys), Math.max(...ys), false);\n  const f = makeFrame(width, CARTESIAN_HEIGHT, { yTickLabels: yScale.ticks.map(formatTick), hasXLabel: !!spec.xLabel, hasYLabel: !!spec.yLabel });\n  const color = seriesColors(1)[0];\n  const [hover, setHover] = useHover();\n  const coords = pts.map((p) => [xToPx(p.x, xScale, f), yToPx(p.y, yScale, f)] as const);\n\n  const onMove = (e: MouseEvent<SVGSVGElement>) => {\n    const rect = e.currentTarget.getBoundingClientRect();\n    const mx = e.clientX - rect.left;\n    const my = e.clientY - rect.top;\n    let best: number | null = null;\n    let bestD = 18 * 18;\n    coords.forEach(([x, y], i) => {\n      const d = (x - mx) ** 2 + (y - my) ** 2;\n      if (d < bestD) {\n        bestD = d;\n        best = i;\n      }\n    });\n    setHover(best);\n  };\n\n  let tip: TooltipState | null = null;\n  if (hover !== null && pts[hover]) {\n    const p = pts[hover];\n    tip = { x: coords[hover][0], y: coords[hover][1], title: p.label ?? `Point ${hover + 1}`, rows: [{ name: spec.xLabel ?? 'x', value: formatTick(p.x) }, { name: spec.yLabel ?? 'y', value: formatTick(p.y) }] };\n  }\n\n  return (\n    <>\n      <svg {...svgProps(f, spec.title)} onMouseMove={onMove} onMouseLeave={() => setHover(null)}>\n        <title>{spec.title}</title>\n        <AxisChrome f={f} yScale={yScale} xLabels={xScale.ticks.map((t) => ({ x: xToPx(t, xScale, f), label: formatTick(t) }))} xLabel={spec.xLabel} yLabel={spec.yLabel} />\n        {coords.map(([x, y], i) => (\n          <circle key={i} cx={px(x)} cy={px(y)} r={hover === i ? 6 : 4} className={`chat-chart-point chat-chart-dot${hover === i ? ' is-active' : ''}`} fill={resolveSeriesColor(pts[i].color, 0, [color])} onMouseEnter={() => setHover(i)} data-index={i} />\n        ))}\n      </svg>\n      {tip ? <ChartTooltip tip={tip} width={f.width} /> : null}\n    </>\n  );\n}\n\n// ── sparkline ──────────────────────────────────────────────────────────────────\n/** A tiny inline trend — no axes, just the line and its last value. */\nexport function Sparkline({ spec, width }: RendererProps): ReactElement {\n  const series = asSeriesArray(spec)[0];\n  const points = series.points;\n  const values = points.map((p) => p.value);\n  const min = Math.min(...values);\n  const max = Math.max(...values);\n  const W = Math.max(120, Math.min(width, 260));\n  const H = SPARKLINE_HEIGHT;\n  const pad = 4;\n  const gradientId = useId();\n  const coords = points.map((p, i) => {\n    const x = pad + ((W - pad * 2) / (points.length - 1 || 1)) * i;\n    const t = (p.value - min) / (max - min || 1);\n    const y = pad + (H - pad * 2) * (1 - t);\n    return [x, y] as const;\n  });\n  const d = coords.map(([x, y], i) => `${i === 0 ? 'M' : 'L'}${px(x)},${px(y)}`).join(' ');\n  const areaD = `${d} L${px(coords[coords.length - 1][0])},${H} L${px(coords[0][0])},${H} Z`;\n  const trendUp = values[values.length - 1] >= values[0];\n  const stroke = trendUp ? 'var(--chat-chart-1)' : NEGATIVE_COLOR;\n  const last = coords[coords.length - 1];\n  return (\n    <div className=\"chat-chart-sparkline-row\">\n      <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} role=\"img\" aria-label={spec.title} className=\"chat-chart-svg\">\n        <title>{`${series.name ? `${series.name}: ` : ''}${values.map((v) => formatTick(v)).join(' → ')}`}</title>\n        <defs>\n          <linearGradient id={gradientId} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n            <stop offset=\"0%\" stopColor={stroke} stopOpacity={0.22} />\n            <stop offset=\"100%\" stopColor={stroke} stopOpacity={0} />\n          </linearGradient>\n        </defs>\n        <path d={areaD} fill={`url(#${gradientId})`} className=\"chat-chart-area\" />\n        <path d={d} className=\"chat-chart-sparkline\" fill=\"none\" stroke={stroke} />\n        <circle cx={px(last[0])} cy={px(last[1])} r={3} fill={stroke} className=\"chat-chart-point\" />\n      </svg>\n      <span className=\"chat-chart-sparkline-value\">{formatTick(values[values.length - 1])}</span>\n    </div>\n  );\n}\n\n// ── legend + dispatch ──────────────────────────────────────────────────────────\n\n/** Legend entries for multi-series cartesian charts; null when no legend applies. */\nexport function legendItems(spec: ChartSpec): LegendItem[] | null {\n  if (spec.legend === false) return null;\n  if (spec.type === 'pie' || spec.type === 'donut' || spec.type === 'scatter' || spec.type === 'sparkline') return null;\n  const serieses = asSeriesArray(spec);\n  if (serieses.length < 2) return null;\n  const colors = seriesColors(serieses.length);\n  return serieses.map((s, i) => ({ name: s.name ?? `Series ${i + 1}`, color: resolveSeriesColor(s.color, i, colors) }));\n}\n\n/** Fixed plot height per kind, so the card reserves space before the first measurement. */\nexport function chartHeight(spec: ChartSpec): number {\n  switch (spec.type) {\n    case 'pie':\n    case 'donut':\n      return PIE_HEIGHT;\n    case 'sparkline':\n      return SPARKLINE_HEIGHT;\n    case 'horizontal-bar': {\n      const n = asSeriesArray(spec)[0]?.points.length ?? 1;\n      return Math.max(150, Math.min(440, n * 30 + 40));\n    }\n    default:\n      return CARTESIAN_HEIGHT;\n  }\n}\n\n/** Dispatch a validated spec to its renderer. Throws on a pie that doesn't sum to a whole. */\nexport function renderChart(spec: ChartSpec, width: number): ReactNode {\n  switch (spec.type) {\n    case 'bar': return <BarChart spec={spec} width={width} />;\n    case 'horizontal-bar': return <HorizontalBarChart spec={spec} width={width} />;\n    case 'line': return <LineChart spec={spec} width={width} />;\n    case 'area': return <LineChart spec={spec} width={width} area />;\n    case 'multi-line': return <LineChart spec={spec} width={width} />;\n    case 'stacked-bar': return <StackedBarChart spec={spec} width={width} />;\n    case 'grouped-bar': return <GroupedBarChart spec={spec} width={width} />;\n    // Validate BEFORE creating the element: a throw here is inside ChartBlock's\n    // try/catch and degrades to the error card. A throw from the component body\n    // would escape it (React calls the component after this function returns)\n    // and crash the message bubble.\n    case 'pie': assertPieSumsToWhole(spec); return <PieChart spec={spec} width={width} />;\n    case 'donut': assertPieSumsToWhole(spec); return <PieChart spec={spec} width={width} donut />;\n    case 'scatter': return <ScatterChart spec={spec} width={width} />;\n    case 'sparkline': return <Sparkline spec={spec} width={width} />;\n    default: throw new Error(`Unsupported chart type: ${(spec as { type: string }).type}`);\n  }\n}\n","/**\n * Shared chart geometry + scales + theming helpers.\n *\n * v3 renders at REAL PIXELS. Every chart measures its container width (see\n * use-chart-width.ts) and lays out a `Frame` in CSS pixels, so type is always\n * 11px and hairlines are always 1px — no more SVG text that shrinks with the\n * message column or balloons in a wide panel. The height is fixed per chart\n * kind; the width follows the card.\n *\n * `niceScale` is still the heart of it — a Heckbert nice-numbers axis that\n * snaps to a round step grid. v3 fixes the negative-data case: `forceZero`\n * now means \"the axis INCLUDES zero\", not \"the axis starts at zero\", so a bar\n * chart with losses gets a baseline in the middle of the plot instead of bars\n * drawn below the axis over the tick labels.\n *\n * Honesty rules encoded here (not the schema, so the model can't override):\n *   - bar/area/stacked-bar/grouped-bar: the value axis always includes 0.\n *   - line/multi-line: the axis pads to round steps around the data; it may\n *     touch 0 but never truncates the range to a flattering sliver.\n *   - the scale is always [floor-to-step, ceil-to-step] so ticks are round.\n */\n\n/** Chart heights in CSS px. Widths follow the container. */\nexport const CARTESIAN_HEIGHT = 240;\nexport const PIE_HEIGHT = 220;\nexport const SPARKLINE_HEIGHT = 40;\n/** Width used before the container has been measured (SSR, jsdom). */\nexport const FALLBACK_WIDTH = 560;\nexport const MIN_WIDTH = 220;\n\n/** Type metrics for layout estimates (11px UI sans). */\nexport const FONT_SIZE = 11;\nconst CHAR_W = FONT_SIZE * 0.58;\n\n/** Estimate the rendered width of a label in px (no DOM measurement needed). */\nexport function estimateTextWidth(text: string, size = FONT_SIZE): number {\n  return text.length * size * 0.58;\n}\n\n/** The pixel frame a cartesian chart is laid out in. */\nexport interface Frame {\n  width: number;\n  height: number;\n  left: number;\n  right: number;\n  top: number;\n  bottom: number;\n  plotW: number;\n  plotH: number;\n}\n\nexport interface FrameOptions {\n  /** Tick strings on the left axis — the gutter is sized to the widest one. */\n  yTickLabels?: string[];\n  /** Category strings on the left axis (horizontal bars). */\n  leftLabels?: string[];\n  hasXLabel?: boolean;\n  hasYLabel?: boolean;\n  /** Whether the bottom edge carries tick labels at all. */\n  hasXTicks?: boolean;\n}\n\n/** Build a frame: gutters sized to the labels they hold, never a fixed 52px. */\nexport function makeFrame(width: number, height: number, opts: FrameOptions = {}): Frame {\n  const w = Math.max(MIN_WIDTH, Math.round(width));\n  const labels = [...(opts.yTickLabels ?? []), ...(opts.leftLabels ?? [])];\n  const widest = labels.reduce((m, l) => Math.max(m, estimateTextWidth(l)), 0);\n  const left = Math.round(Math.min(w * 0.4, (labels.length ? widest + 12 : 8) + (opts.hasYLabel ? 18 : 0) + 4));\n  const right = 12;\n  const top = 12;\n  const bottom = (opts.hasXTicks === false ? 8 : 26) + (opts.hasXLabel ? 16 : 0);\n  return { width: w, height, left, right, top, bottom, plotW: Math.max(1, w - left - right), plotH: Math.max(1, height - top - bottom) };\n}\n\n/** A computed axis scale. */\nexport interface Scale {\n  min: number;\n  max: number;\n  step: number;\n  ticks: number[];\n}\n\n/**\n * The nice-scale algorithm (a cleaned-up Nice Numbers / Heckbert). Produces a\n * [min, max] that snaps to a round step and a tick list that spans the data\n * with comfortable padding — never an orphan fractional tick at the baseline.\n *\n * @param dataMin  the minimum data value\n * @param dataMax  the maximum data value\n * @param forceZero  the axis must include 0 (bar/area honesty rule). With\n *                   all-positive data the axis starts at 0; with negatives it\n *                   extends below 0 so the baseline sits inside the plot.\n * @param maxTicks  target tick count (~4-5)\n */\nexport function niceScale(dataMin: number, dataMax: number, forceZero = false, maxTicks = 5): Scale {\n  // Degenerate / single-value data: expand to a unit range so it renders.\n  if (dataMin === dataMax) {\n    if (dataMin === 0) return { min: 0, max: 1, step: 0.25, ticks: [0, 0.25, 0.5, 0.75, 1] };\n    const span = Math.abs(dataMin) * 0.5 || 1;\n    dataMin -= span;\n    dataMax += span;\n  }\n\n  // Honesty: the value axis of a bar/area chart includes 0.\n  if (forceZero) {\n    dataMin = Math.min(0, dataMin);\n    dataMax = Math.max(0, dataMax);\n  }\n\n  const range = niceNum(dataMax - dataMin, false);\n  const step = niceNum(range / Math.max(1, maxTicks - 1), true);\n  const min = Math.floor(dataMin / step + 1e-9) * step;\n  const max = Math.ceil(dataMax / step - 1e-9) * step;\n\n  const ticks: number[] = [];\n  // Start at the floored min, step to the ceiled max. Use a small epsilon to\n  // dodge float drift at the upper bound.\n  for (let v = min; v <= max + step * 1e-6; v += step) {\n    ticks.push(Number(v.toFixed(6)));\n  }\n  return { min: Number(min.toFixed(6)), max: Number(max.toFixed(6)), step, ticks };\n}\n\n/** Heckbert's \"nice number\" — rounds a value to a clean 1/2/5 × 10^n. */\nfunction niceNum(range: number, round: boolean): number {\n  const exponent = Math.floor(Math.log10(range || 1));\n  const fraction = (range || 1) / Math.pow(10, exponent);\n  let niceFraction: number;\n  if (round) {\n    if (fraction < 1.5) niceFraction = 1;\n    else if (fraction < 3) niceFraction = 2;\n    else if (fraction < 7) niceFraction = 5;\n    else niceFraction = 10;\n  } else {\n    if (fraction <= 1) niceFraction = 1;\n    else if (fraction <= 2) niceFraction = 2;\n    else if (fraction <= 5) niceFraction = 5;\n    else niceFraction = 10;\n  }\n  return niceFraction * Math.pow(10, exponent);\n}\n\n/** Map a data value to a y pixel inside the frame. */\nexport function yToPx(value: number, scale: Scale, f: Frame): number {\n  const t = (value - scale.min) / (scale.max - scale.min || 1);\n  return f.top + f.plotH * (1 - t);\n}\n\n/** Map a data value to an x pixel inside the frame (scatter, horizontal bars). */\nexport function xToPx(value: number, scale: Scale, f: Frame): number {\n  const t = (value - scale.min) / (scale.max - scale.min || 1);\n  return f.left + f.plotW * t;\n}\n\n/** Width of one category slot. */\nexport function slotWidth(n: number, f: Frame): number {\n  return f.plotW / Math.max(1, n);\n}\n\n/** Center x of category `i` when categories are slots (bars). */\nexport function slotCenter(i: number, n: number, f: Frame): number {\n  const slot = slotWidth(n, f);\n  return f.left + slot * i + slot / 2;\n}\n\n/** x of point `i` when categories are points along the axis (lines). */\nexport function pointX(i: number, n: number, f: Frame): number {\n  if (n <= 1) return f.left + f.plotW / 2;\n  return f.left + (f.plotW / (n - 1)) * i;\n}\n\n/**\n * Decide which category labels to draw, and how long they may be, so labels\n * never overlap and never rotate. Rotated labels are the tell of a chart that\n * gave up on layout; thinning keeps every drawn label legible and the tooltip\n * carries the full text for the rest.\n *\n * @param spacing  pixels between adjacent label anchors\n */\nexport function planCategoryLabels(labels: string[], spacing: number): { every: number; maxChars: number } {\n  const MIN_SPACING = 40;\n  let every = 1;\n  while (spacing * every < MIN_SPACING && every < labels.length) every++;\n  const room = spacing * every - 8;\n  const maxChars = Math.max(3, Math.min(28, Math.floor(room / CHAR_W)));\n  return { every, maxChars };\n}\n\n/**\n * Format a value compactly: 1200 -> \"1.2k\", 1500000 -> \"1.5M\", 2.5e9 -> \"2.5B\",\n * 0.045 -> \"0.045\". Negative values keep their sign.\n */\nexport function formatTick(n: number): string {\n  const abs = Math.abs(n);\n  const sign = n < 0 ? '-' : '';\n  if (abs >= 1_000_000_000) return `${sign}${trimZeros((abs / 1_000_000_000).toFixed(1))}B`;\n  if (abs >= 1_000_000) return `${sign}${trimZeros((abs / 1_000_000).toFixed(1))}M`;\n  if (abs >= 1_000) return `${sign}${trimZeros((abs / 1_000).toFixed(1))}k`;\n  if (Number.isInteger(n)) return String(n);\n  // Small fractions: trim trailing zeros, cap precision.\n  return String(Number(n.toFixed(3)));\n}\n\nfunction trimZeros(s: string): string {\n  return s.replace(/\\.0$/, '');\n}\n\n/**\n * The chart palette. Series colors are CSS custom properties declared on\n * `.chat-chart` in styles.src.css, so they follow the theme and can be\n * overridden per host (`--chat-chart-1` … `--chat-chart-8`).\n *\n *   - single series: `--chat-chart-1` (= `--chat-primary`) — the honest\n *     ordinal default; a ranked series is one thing, not N categories\n *   - multiple named series: the categorical set. The defaults derive every\n *     hue from the brand primary with `color-mix()`, so a white-label theme\n *     gets a palette that is of-a-piece with its accent for free.\n */\nexport const PALETTE_SIZE = 8;\n\nexport function seriesColors(count: number): string[] {\n  if (count <= 1) return ['var(--chat-chart-1)'];\n  return Array.from({ length: count }, (_, i) => `var(--chat-chart-${(i % PALETTE_SIZE) + 1})`);\n}\n\n/** Color for a value that is below zero (losses, declines). */\nexport const NEGATIVE_COLOR = 'var(--chat-chart-negative)';\n\n/** Resolve a series color: honor a model/host hex hint, else the palette slot. */\nexport function resolveSeriesColor(hint: string | undefined, rampSlot: number, ramp: string[]): string {\n  if (hint && /^#[0-9a-fA-F]{3,8}$/.test(hint)) return hint;\n  return ramp[Math.min(rampSlot, ramp.length - 1)] ?? 'var(--chat-chart-1)';\n}\n\n/** Trim a label to a max length with an ellipsis, for axis ticks. */\nexport function trimLabel(label: string, max = 12): string {\n  return label.length > max ? `${label.slice(0, Math.max(1, max - 1))}…` : label;\n}\n\n/** Round to one decimal for crisp path data. */\nexport function px(n: number): string {\n  return (Math.round(n * 10) / 10).toString();\n}\n\n/**\n * A bar path with radius only on the OUTER end (the end away from the\n * baseline). Rounding both ends makes a bar read as a pill; rounding the\n * baseline end lifts it off the axis.\n */\nexport function barPath(x: number, y: number, w: number, h: number, r: number, side: 'top' | 'bottom' | 'left' | 'right'): string {\n  const rr = Math.max(0, Math.min(r, w / 2, h / 2));\n  if (h <= 0 || w <= 0) return '';\n  const X = px, x2 = x + w, y2 = y + h;\n  switch (side) {\n    case 'top':\n      return `M${X(x)},${X(y2)} V${X(y + rr)} Q${X(x)},${X(y)} ${X(x + rr)},${X(y)} H${X(x2 - rr)} Q${X(x2)},${X(y)} ${X(x2)},${X(y + rr)} V${X(y2)} Z`;\n    case 'bottom':\n      return `M${X(x)},${X(y)} V${X(y2 - rr)} Q${X(x)},${X(y2)} ${X(x + rr)},${X(y2)} H${X(x2 - rr)} Q${X(x2)},${X(y2)} ${X(x2)},${X(y2 - rr)} V${X(y)} Z`;\n    case 'right':\n      return `M${X(x)},${X(y)} H${X(x2 - rr)} Q${X(x2)},${X(y)} ${X(x2)},${X(y + rr)} V${X(y2 - rr)} Q${X(x2)},${X(y2)} ${X(x2 - rr)},${X(y2)} H${X(x)} Z`;\n    case 'left':\n      return `M${X(x2)},${X(y)} H${X(x + rr)} Q${X(x)},${X(y)} ${X(x)},${X(y + rr)} V${X(y2 - rr)} Q${X(x)},${X(y2)} ${X(x + rr)},${X(y2)} H${X(x2)} Z`;\n  }\n}\n","'use client';\n\n/**\n * ChartTooltip — the hover card shared by every chart kind.\n *\n * Renderers own the hit-testing (they know their geometry) and hand this\n * component a `TooltipState`: an anchor point in chart pixels plus the rows to\n * show. The card is plain HTML positioned over the SVG so it can use the\n * widget's type, shadow, and surface tokens, and it flips to stay inside the\n * chart when the anchor is near an edge.\n */\nimport type { ReactElement } from 'react';\n\nexport interface TooltipRow {\n  /** Swatch color (CSS color). Omitted for single-series charts. */\n  swatch?: string;\n  /** Series / slice name. */\n  name?: string;\n  /** The formatted value. */\n  value: string;\n  /** Secondary text after the value (e.g. a percentage). */\n  note?: string;\n}\n\nexport interface TooltipState {\n  /** Anchor in chart pixels. */\n  x: number;\n  y: number;\n  /** Header — usually the category label. */\n  title: string;\n  rows: TooltipRow[];\n}\n\nconst CARD_W = 168;\nconst GAP = 10;\n\nexport function ChartTooltip({ tip, width }: { tip: TooltipState; width: number }): ReactElement {\n  // Prefer the right side of the anchor; flip left when it would clip.\n  const flip = tip.x + GAP + CARD_W > width;\n  const left = flip ? Math.max(0, tip.x - GAP - CARD_W) : tip.x + GAP;\n  return (\n    <div className=\"chat-chart-tooltip\" role=\"presentation\" style={{ left, top: Math.max(0, tip.y - 8), width: CARD_W }}>\n      <div className=\"chat-chart-tooltip-title\">{tip.title}</div>\n      {tip.rows.map((r, i) => (\n        <div key={i} className=\"chat-chart-tooltip-row\">\n          {r.swatch ? <span className=\"chat-chart-swatch\" style={{ background: r.swatch }} /> : null}\n          {r.name ? <span className=\"chat-chart-tooltip-name\">{r.name}</span> : null}\n          <span className=\"chat-chart-tooltip-value\">\n            {r.value}\n            {r.note ? <span className=\"chat-chart-tooltip-note\">{r.note}</span> : null}\n          </span>\n        </div>\n      ))}\n    </div>\n  );\n}\n","'use client';\n\nimport { useEffect, useState, type RefObject } from 'react';\nimport { FALLBACK_WIDTH } from './chart-geometry';\n\n/**\n * Measure the chart container's width in CSS px and follow it as the message\n * column resizes (popup ↔ fullscreen, a sidebar opening, a phone rotating).\n *\n * Charts render at real pixels — 11px type and 1px hairlines at every width —\n * so they need the number, not a scaling viewBox. Before the first measurement\n * (SSR, the very first client paint, jsdom) the fallback width is used, and the\n * first layout pass corrects it before the user can see the difference.\n */\nexport function useChartWidth(ref: RefObject<HTMLElement | null>): number {\n  const [width, setWidth] = useState<number>(FALLBACK_WIDTH);\n\n  useEffect(() => {\n    const el = ref.current;\n    if (!el) return;\n    const measure = () => {\n      const w = el.clientWidth;\n      if (w > 0) setWidth((prev) => (Math.abs(prev - w) < 1 ? prev : w));\n    };\n    measure();\n    if (typeof ResizeObserver === 'undefined') return;\n    const ro = new ResizeObserver(measure);\n    ro.observe(el);\n    return () => ro.disconnect();\n  }, [ref]);\n\n  return width;\n}\n","'use client';\n\nimport { ChartBlockOrError } from './chart-block';\nimport { isChartFenceLanguage, parseChartSpec } from './chart-spec';\n\n/**\n * ChartCode — Seam A fence renderer (PRD §2). Streamdown hands the `code`\n * component the COMPLETE fenced text once the closing backticks arrive, so we\n * only ever see a closed fence — no partial-chart risk. response.tsx routes\n * chart fence languages here; everything else stays CollapsibleCode.\n */\ninterface StreamdownCodeProps {\n  inline?: boolean;\n  className?: string;\n  children?: React.ReactNode;\n  node?: unknown;\n}\n\nfunction fenceLanguage(className: string | undefined): string | undefined {\n  if (!className) return undefined;\n  const m = /language-([\\w-]+)/.exec(className);\n  return m ? m[1] : undefined;\n}\n\nexport function ChartCode({ inline, className, children, node: _node }: StreamdownCodeProps) {\n  if (inline) return <code className={className}>{children}</code>;\n  const language = fenceLanguage(className);\n  if (!isChartFenceLanguage(language)) return <code className={className}>{children}</code>;\n  const rawText = typeof children === 'string' ? children : stringifyChildren(children);\n  const result = parseChartSpec(rawText);\n  return <ChartBlockOrError result={result} rawText={rawText} />;\n}\n\nfunction stringifyChildren(children: React.ReactNode): string {\n  if (children == null) return '';\n  if (typeof children === 'string') return children;\n  if (Array.isArray(children)) return children.map(stringifyChildren).join('');\n  if (typeof children === 'object' && 'props' in children) {\n    return stringifyChildren((children as { props?: { children?: React.ReactNode } }).props?.children);\n  }\n  return String(children);\n}\n","'use client';\n\n/**\n * MermaidCode — fence renderer for `mermaid` blocks (generative registry:\n * 'diagrams'). Unlike ChartCode, Mermaid must not render while its fenced text\n * is still streaming: each render measures live layout and replaces an SVG, so\n * rendering partial source makes the message visibly flutter.\n *\n * The mermaid library (already a streamdown dependency) is imported lazily on\n * first use, so it costs nothing until a diagram actually appears. SECURITY:\n * the fence body is model output — mermaid runs with `securityLevel: 'strict'`\n * (labels sanitized, no script/click handlers) before the produced SVG is\n * injected. A render failure falls back to the plain collapsible code view so\n * the model's output is never silently dropped.\n *\n * CONTAINMENT — why this file is careful about the DOM:\n *\n * mermaid renders by measuring real layout, so it needs a live element. Left to\n * itself it creates one on `document.body` — OUTSIDE `.chat-widget-container`,\n * i.e. in the host page the widget is embedded in. On success it cleans up; on a\n * SYNTAX ERROR it instead paints its \"bomb\" error graphic into that node, throws,\n * and leaves the node behind. The widget's own fallback then renders correctly\n * while the host page is left with a full-width error graphic below its footer —\n * the widget defacing someone else's site with a diagnostic meant for us.\n *\n * Model output is untrusted input to a parser, so invalid diagrams are the\n * expected case, not the exceptional one. Three independent guards, because any\n * one of them alone still leaks in some path:\n *\n *   1. `suppressErrorRendering: true` — mermaid's own switch for \"never insert a\n *      Syntax error diagram into the DOM\". The real fix.\n *   2. `parse(code, { suppressErrors: true })` before rendering — validate first,\n *      so a bad diagram never reaches `render()` at all.\n *   3. An owned, offscreen container passed to `render()` — so anything mermaid\n *      does attach lands in a node this component removes on cleanup, never on\n *      `document.body`.\n */\n\nimport { createContext, useContext, useEffect, useId, useState } from 'react';\nimport { CollapsibleCode } from './collapsible-code';\n\ninterface StreamdownCodeProps {\n  inline?: boolean;\n  className?: string;\n  children?: React.ReactNode;\n  node?: unknown;\n}\n\n// Context reaches MermaidCode even when Streamdown's memo comparator ignores a\n// changed `components` object on the final status-only render.\nexport const ResponseStreamingContext = createContext(false);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet mermaidPromise: Promise<any> | null = null;\nfunction loadMermaid() {\n  mermaidPromise ??= import('mermaid').then((mod) => {\n    const mermaid = mod.default;\n    mermaid.initialize({\n      startOnLoad: false,\n      securityLevel: 'strict',\n      theme: 'neutral',\n      fontFamily: 'inherit',\n      // Guard 1: never let mermaid inject its \"Syntax error\" diagram into the\n      // page. Without this a malformed fence paints a bomb graphic on the HOST\n      // site's body — outside the widget, outside our scoped CSS. We show the\n      // raw code instead, which is more useful to the reader anyway.\n      suppressErrorRendering: true,\n    });\n    return mermaid;\n  });\n  return mermaidPromise;\n}\n\n/**\n * An offscreen element that mermaid may measure and scribble into, owned by the\n * caller so it can be removed unconditionally.\n *\n * It must be IN the document (mermaid measures real layout; a detached node\n * reports zero and diagrams come out mis-sized), so it is hidden rather than\n * unattached: off-viewport, non-interactive, and `aria-hidden` so it never\n * reaches the accessibility tree. `.chat-widget-container` keeps our own scoped\n * styles applying to it.\n */\nfunction createScratchContainer(): HTMLElement {\n  const el = document.createElement('div');\n  el.className = 'chat-widget-container';\n  el.setAttribute('aria-hidden', 'true');\n  el.style.cssText =\n    'position:absolute;left:-99999px;top:0;width:0;height:0;overflow:hidden;pointer-events:none;';\n  document.body.appendChild(el);\n  return el;\n}\n\nfunction stringifyChildren(children: React.ReactNode): string {\n  if (children == null) return '';\n  if (typeof children === 'string') return children;\n  if (Array.isArray(children)) return children.map(stringifyChildren).join('');\n  if (typeof children === 'object' && 'props' in children) {\n    return stringifyChildren((children as { props?: { children?: React.ReactNode } }).props?.children);\n  }\n  return String(children);\n}\n\nfunction MermaidPending() {\n  return (\n    <div className=\"chat-mermaid-pending not-prose\" role=\"status\" aria-label=\"Generating diagram\">\n      <span>Generating diagram</span>\n    </div>\n  );\n}\n\nexport function MermaidCode({ inline, className, children }: StreamdownCodeProps) {\n  const isStreaming = useContext(ResponseStreamingContext);\n\n  useEffect(() => {\n    if (!inline && isStreaming) void loadMermaid().catch(() => undefined);\n  }, [inline, isStreaming]);\n\n  if (inline) return <code className={className}>{children}</code>;\n  const code = (typeof children === 'string' ? children : stringifyChildren(children)).trim();\n\n  // Mermaid measures and rewrites an SVG for every source change. During token\n  // streaming that turns each partial line into a render, collapses the previous\n  // SVG, then inserts a differently sized one — the visible \"flutter\". Keep one\n  // stable placeholder while the fence is changing and render exactly once when\n  // the response settles.\n  if (isStreaming) return <MermaidPending />;\n\n  return <MermaidDiagram code={code} className={className} rawChildren={children} />;\n}\n\nfunction MermaidDiagram({\n  code,\n  className,\n  rawChildren,\n}: {\n  code: string;\n  className?: string;\n  rawChildren?: React.ReactNode;\n}) {\n  // useId can contain characters mermaid's selector handling rejects.\n  const id = useId().replace(/[^a-zA-Z0-9]/g, '');\n  const [svg, setSvg] = useState<string | null>(null);\n  const [failed, setFailed] = useState(false);\n\n  useEffect(() => {\n    let cancelled = false;\n    let scratch: HTMLElement | null = null;\n    setSvg(null);\n    setFailed(false);\n    if (!code) {\n      setFailed(true);\n      return;\n    }\n\n    // Every exit path goes through here, so no scratch node can outlive the\n    // render that created it — not on success, failure, unmount, or a code\n    // change mid-render.\n    const releaseScratch = () => {\n      scratch?.remove();\n      scratch = null;\n    };\n\n    loadMermaid()\n      .then(async (mermaid) => {\n        // Loading may finish after unmount or after streaming resumes. Do not\n        // start even a parse for an effect that has already been cancelled.\n        if (cancelled) return null;\n        // Guard 2: validate before rendering. `suppressErrors` makes this return\n        // false for a bad diagram instead of throwing, so an invalid fence never\n        // reaches render() — the only call that touches the DOM.\n        const valid = await mermaid.parse(code, { suppressErrors: true });\n        if (!valid) throw new Error('invalid mermaid diagram');\n        if (cancelled) return null;\n\n        // Guard 3: give mermaid a node we own. Anything it attaches lands here\n        // rather than on document.body, and releaseScratch() takes it away.\n        scratch = createScratchContainer();\n        return mermaid.render(`mordn-mermaid-${id}`, code, scratch);\n      })\n      .then((result: { svg: string } | null) => {\n        if (!cancelled && result) setSvg(result.svg);\n      })\n      .catch(() => {\n        if (!cancelled) setFailed(true);\n      })\n      .finally(releaseScratch);\n\n    return () => {\n      cancelled = true;\n      releaseScratch();\n    };\n  }, [code, id]);\n\n  // Invalid mermaid (or an empty fence): degrade to the normal code view so\n  // the output is inspectable rather than a broken image or nothing.\n  if (failed) return <CollapsibleCode className={className}>{rawChildren ?? code}</CollapsibleCode>;\n  if (!svg) return <MermaidPending />; // keep the reserved space while parse + render settle\n  return (\n    <div\n      className=\"chat-mermaid not-prose\"\n      role=\"figure\"\n      aria-label=\"Diagram\"\n      // Sanitized by mermaid securityLevel:'strict' before reaching us.\n      dangerouslySetInnerHTML={{ __html: svg }}\n    />\n  );\n}\n","/**\n * Generative component registry — the single source of truth for what the\n * model may emit in a response beyond plain prose, and the vocabulary that\n * teaches it to do so.\n *\n * Each entry pairs:\n *   - `fenceLanguages` — the fence tag(s) the client renderer routes to the\n *     component (response.tsx maps them to React renderers), and\n *   - `prompt` — the steering sentence(s) contributed to EVERY system prompt\n *     (assembled by `buildRenderingSystem`, appended in the server handler).\n *\n * Adding a generative component = add an entry here + a renderer route in\n * response.tsx. The prompt and the renderer can no longer drift apart, which\n * was the failure mode of the previous hardcoded RENDERING_SYSTEM blob (e.g.\n * mermaid fences silently rendering as plain code).\n *\n * Shared module by design: no React, no server-only — imported by both the\n * server handler (prompt assembly) and the client renderer (fence routing).\n */\n\nexport interface GenerativeComponentDef {\n  /** Stable identifier for the component. */\n  name: string;\n  /** Fence languages routed to this component's renderer, if fence-based. */\n  fenceLanguages?: readonly string[];\n  /** Steering sentence(s) contributed to every system prompt. */\n  prompt: string;\n}\n\n/** Fence tag for Mermaid diagrams — referenced by the client fence router. */\nexport const MERMAID_FENCE_LANGUAGE = 'mermaid';\n\nexport const GENERATIVE_COMPONENTS: readonly GenerativeComponentDef[] = [\n  {\n    name: 'tables',\n    prompt:\n      'Present tabular data as GFM pipe tables (`| Col | Col |` with a `| --- |` separator row). ' +\n      'Never draw tables as ASCII or box-drawing art, and never put a table inside a code fence — fences are for code only.',\n  },\n  {\n    name: 'charts',\n    fenceLanguages: ['mordn-chart', 'chart'],\n    // Charts steer (PRD §7): one paragraph. The model gets a hint + a shape,\n    // not a schema dump — keeping the prompt small. The fence language\n    // `mordn-chart` is distinctive enough that a normal `json` fence won't\n    // trigger the chart renderer. The widget validates the body and renders an\n    // error card on any mismatch, so an invalid spec never ships a misleading\n    // partial chart.\n    prompt:\n      'When your answer would benefit from a chart, emit a fenced `mordn-chart` block whose body is a JSON object: { \"schemaVersion\": 2, \"type\": \"bar\"|\"horizontal-bar\"|\"line\"|\"area\"|\"multi-line\"|\"stacked-bar\"|\"grouped-bar\"|\"pie\"|\"donut\"|\"scatter\"|\"sparkline\", \"title\": string, \"subtitle\"?: string, \"xLabel\"?: string, \"yLabel\"?: string, \"source\"?: string, \"legend\"?: boolean, \"valueLabels\"?: boolean, \"series\": { \"name\"?: string, \"points\": [{ \"label\": string, \"value\": number }], \"color\"?: \"#hex\" } | [{ ... }], \"whole\"?: { \"total\": number, \"tolerance\"?: number }, \"scatter\"?: [{ \"x\": number, \"y\": number, \"label\"?: string }] }. ' +\n      'Choose the chart kind to fit the data: bar to compare discrete categories, horizontal-bar when category names are long, line/area for a sequence over an ordered axis, multi-line to compare several series over the same axis, stacked-bar to show parts-of-a-whole across categories, grouped-bar to compare series side-by-side per category, pie/donut ONLY for parts summing to a single whole (set `whole.total`), scatter for two numeric variables, sparkline for a tiny inline trend. ' +\n      'Always start numeric axes at zero for bar/area/stacked-bar. For pie/donut the slices must sum to the declared whole. Only chart data you are confident is accurate; if you are unsure of the numbers, say so in prose instead. Keep categorical charts to at most 20 points and line/scatter to at most 200.',\n  },\n  {\n    name: 'diagrams',\n    fenceLanguages: [MERMAID_FENCE_LANGUAGE],\n    prompt:\n      'When structure or flow is clearer as a diagram (flowcharts, sequence diagrams, state machines, ER models), emit a fenced `mermaid` block containing valid Mermaid syntax and nothing else. ' +\n      'Keep diagrams small (at most ~15 nodes), label the edges that carry meaning, and prefer prose for simple relationships. Only diagram relationships you are confident are accurate.',\n  },\n];\n\n/**\n * Assemble the rendering-system prompt appended to EVERY system prompt\n * (default, hosted, or buildSystemPrompt). It describes the widget's rendering\n * surface, not behavior, so it composes with any operator prompt.\n */\nexport function buildRenderingSystem(): string {\n  return [\n    'Formatting: replies render as GitHub-Flavored Markdown.',\n    ...GENERATIVE_COMPONENTS.map((component) => component.prompt),\n  ].join(' ');\n}\n","\"use client\";\n\nimport {\n  Collapsible,\n  CollapsibleContent,\n  CollapsibleTrigger,\n} from \"../ui/collapsible\";\nimport { cn } from \"../utils/cn\";\nimport { safeUrl } from \"../utils/url-safety\";\nimport { ChevronDownIcon, FileTextIcon } from \"lucide-react\";\nimport { useState, type ComponentProps } from \"react\";\n\nexport type SourcesProps = ComponentProps<\"div\">;\n\n/**\n * Sources bibliography footer (#138). Lives BELOW the assistant answer, not\n * above it: the inline citation chips link the prose to these sources, so the\n * list is a reference footer, not a top-of-message callout. Collapsed by\n * default; the trigger is a quiet uppercase section label (see SourcesTrigger).\n * A hairline anchors it to the answer while each source remains an unboxed row.\n */\nexport const Sources = ({ className, ...props }: SourcesProps) => (\n  <Collapsible\n    className={cn(\"not-prose border-t border-[hsl(var(--chat-hairline))] pt-3 text-xs\", className)}\n    {...props}\n  />\n);\n\nexport type SourcesTriggerProps = ComponentProps<typeof CollapsibleTrigger> & {\n  count: number;\n};\n\n/**\n * The bibliography footer affordance: a quiet, left-aligned uppercase label,\n * not a bordered pill. The count remains visible as metadata and the chevron\n * rotates on open; expanded rows stay unnumbered because inline citation chips\n * already carry the numeric mapping.\n */\nexport const SourcesTrigger = ({\n  className,\n  count,\n  children,\n  ...props\n}: SourcesTriggerProps) => (\n  <CollapsibleTrigger\n    className={cn(\n      \"group/source-trigger flex w-full items-center gap-1.5 rounded-md text-[10px] font-semibold uppercase tracking-[0.1em] transition-colors\",\n      \"text-[hsl(var(--chat-text-subtle))] hover:text-[hsl(var(--chat-text-muted))]\",\n      \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\",\n      className\n    )}\n    {...props}\n  >\n    {children ?? (\n      <>\n        <span>Sources</span>\n        {/* No explicit color: inherit the trigger's, so hover shifts the whole\n            row together (a hardcoded color here froze the count on hover). */}\n        <span className=\"font-medium normal-case tracking-normal\">\n          {count}\n        </span>\n        <ChevronDownIcon\n          className=\"size-2.5 transition-transform duration-150 group-data-[state=open]/source-trigger:rotate-180\"\n          strokeWidth={1.6}\n          aria-hidden=\"true\"\n        />\n      </>\n    )}\n  </CollapsibleTrigger>\n);\n\nexport type SourcesContentProps = ComponentProps<typeof CollapsibleContent>;\n\nexport const SourcesContent = ({\n  className,\n  ...props\n}: SourcesContentProps) => (\n  <CollapsibleContent\n    className={cn(\n      // gap-0: rows tile edge-to-edge so hover targets are contiguous (no dead\n      // zones between links); each row's own py provides the visual rhythm.\n      \"mt-2 grid w-full gap-0\",\n      \"data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-1 data-[state=open]:slide-in-from-top-1 outline-none data-[state=closed]:animate-out data-[state=open]:animate-in\",\n      className\n    )}\n    {...props}\n  />\n);\n\nexport type SourceProps = ComponentProps<\"a\"> & {\n  index?: number;\n};\n\nfunction sourceHost(href: SourceProps[\"href\"]): string | undefined {\n  if (typeof href !== \"string\") return undefined;\n  try {\n    return new URL(href).hostname.replace(/^www\\./, \"\");\n  } catch {\n    return undefined;\n  }\n}\n\n/**\n * Resolve a favicon URL for a source host. The host is already rendered in the\n * bibliography row, so requesting its icon leaks nothing the user can't already\n * see. We use Google's S2 favicon endpoint (a long-stable, widely-used service)\n * which serves a single 16–32px PNG per domain; the browser fetches it directly\n * as a normal <img>, no script/credential exchange. Non-http(s) sources (e.g.\n * kb://) return undefined and fall back to the file glyph.\n */\nfunction sourceFaviconUrls(href: SourceProps[\"href\"]): string[] {\n  if (typeof href !== \"string\") return [];\n  try {\n    const url = new URL(href);\n    if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return [];\n    const host = url.hostname.replace(/^www\\./, \"\");\n    if (!host) return [];\n    return [\n      // The site's own favicon first: S2 only has icons for domains Google has\n      // indexed, and for anything else it 200s with a generic grey globe — so\n      // it can't be the primary source (seen live: every mordn.com row globed).\n      `${url.origin}/favicon.ico`,\n      `https://www.google.com/s2/favicons?domain=${encodeURIComponent(host)}&sz=32`,\n    ];\n  } catch {\n    return [];\n  }\n}\n\n/**\n * The 18px leading slot on a source row. Shows the site favicon when the source\n * is http(s) and the icon loads; falls back to the file glyph on any failure\n * (blocked domain, offline, non-web scheme, network error) so the row never\n * ships a broken-image icon. aria-hidden because the host text beside it already\n * names the source for assistive tech.\n */\nfunction SourceGlyph({ href }: { href: string | undefined }) {\n  // Index into the candidate chain (origin /favicon.ico → S2); onError steps to\n  // the next candidate, and running past the end falls back to the file glyph.\n  const [candidate, setCandidate] = useState(0);\n  const faviconUrls = sourceFaviconUrls(href);\n  const faviconUrl = faviconUrls[candidate];\n  if (!faviconUrl) {\n    return (\n      <span\n        className=\"flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-full bg-[hsl(var(--chat-surface))] text-[hsl(var(--chat-text-faint))]\"\n        aria-hidden=\"true\"\n      >\n        <FileTextIcon className=\"size-3\" />\n      </span>\n    );\n  }\n  return (\n    <img\n      alt=\"\"\n      aria-hidden=\"true\"\n      key={faviconUrl}\n      src={faviconUrl}\n      width={16}\n      height={16}\n      loading=\"lazy\"\n      onError={() => setCandidate((i) => i + 1)}\n      className=\"h-[16px] w-[16px] shrink-0 rounded-full bg-[hsl(var(--chat-surface))] object-contain p-[1px]\"\n    />\n  );\n}\n\nfunction compactTitle(title: SourceProps[\"title\"], href: SourceProps[\"href\"]): string {\n  if (typeof title === \"string\" && title.trim()) {\n    try {\n      const url = new URL(title);\n      return decodeURIComponent(url.hash?.slice(1) || url.pathname.split(\"/\").filter(Boolean).at(-1) || url.hostname);\n    } catch {\n      return title.trim();\n    }\n  }\n  if (typeof href === \"string\") {\n    try {\n      const url = new URL(href);\n      return decodeURIComponent(url.hash?.slice(1) || url.pathname.split(\"/\").filter(Boolean).at(-1) || url.hostname);\n    } catch {\n      return href;\n    }\n  }\n  return \"Source\";\n}\n\nexport const Source = ({ href, title, children, index: _index, className, ...props }: SourceProps) => {\n  // Citation hrefs come from the AI message stream; only allow safe schemes\n  // so a javascript:/data: URL cannot execute on click.\n  const safeHref = safeUrl(href);\n  const host = sourceHost(safeHref);\n  const label = compactTitle(title, safeHref);\n\n  const content = children ?? (\n    <>\n      <SourceGlyph href={safeHref} />\n      <span className={cn(\"truncate text-[12.5px] font-medium text-[hsl(var(--chat-text))]\", host ? \"max-w-[60%]\" : \"min-w-0 flex-1\")}>\n        {label}\n      </span>\n      {host && (\n        <>\n          <span className=\"text-[hsl(var(--chat-text-subtle))]\" aria-hidden=\"true\">·</span>\n          <span className=\"min-w-0 flex-1 truncate font-mono text-[11.5px] text-[hsl(var(--chat-text-faint))]\">\n            {host}\n          </span>\n        </>\n      )}\n    </>\n  );\n\n  if (!safeHref) {\n    return (\n      <span\n        className={cn(\n          \"-mx-2 flex w-auto min-w-0 items-center gap-2 rounded-lg px-2 py-1.5\",\n          \"bg-transparent\",\n          className\n        )}\n      >\n        {content}\n      </span>\n    );\n  }\n\n  return (\n    <a\n      className={cn(\n        \"-mx-2 flex w-auto min-w-0 items-center gap-2 rounded-lg px-2 py-1.5 transition-colors\",\n        \"bg-transparent hover:bg-[hsl(var(--chat-hover-bg))]\",\n        \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\",\n        className\n      )}\n      href={safeHref}\n      rel=\"noopener noreferrer\"\n      target=\"_blank\"\n      {...props}\n    >\n      {content}\n    </a>\n  );\n};\n","import { cn } from \"../utils/cn\";\nimport { isSafeDataImage, safeUrl } from \"../utils/url-safety\";\nimport { describeFile } from \"./file-icons/describe-file\";\n\nexport type MessageAttachment = {\n  filename: string;\n  mediaType: string;\n  url: string;\n  size?: number;\n};\n\nexport type MessageAttachmentsProps = {\n  attachments: MessageAttachment[];\n  className?: string;\n};\n\nfunction formatFileSize(size?: number): string | undefined {\n  if (!size || size <= 0) return undefined;\n  if (size < 1024) return `${size} B`;\n  if (size < 1024 * 1024) return `${Math.round(size / 1024)} KB`;\n  return `${(size / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n// Open the file's URL in a new tab. The filename and URL come from the\n// (untrusted) AI message stream, so both are validated here to prevent\n// DOM-based XSS. http(s)/blob URLs open directly; inline image data: URLs\n// are rendered in a tiny viewer built with safe DOM APIs — the filename is\n// set via the title/alt properties (assigned as text, never parsed as HTML)\n// instead of raw document.write of unescaped values. Disallowed schemes\n// (javascript:, vbscript:, non-image data:, ...) are dropped.\nfunction openAttachment(attachment: MessageAttachment) {\n  const safe = safeUrl(attachment.url);\n  if (!safe) return;\n\n  // Inline image previews: browsers won't navigate to a data: image as a\n  // top-level document, so render it in a minimal viewer page.\n  if (isSafeDataImage(safe)) {\n    const w = window.open(\"\", \"_blank\", \"noopener,noreferrer\");\n    if (!w) return;\n    const doc = w.document;\n    doc.title = attachment.filename; // assigned as text, not parsed as HTML\n    doc.body.style.cssText =\n      \"margin:0;padding:20px;background:#f5f5f5;display:flex;\" +\n      \"justify-content:center;align-items:center;min-height:100vh;\";\n    const img = doc.createElement(\"img\");\n    img.setAttribute(\"src\", safe); // validated as a data:image above\n    img.setAttribute(\"alt\", attachment.filename);\n    img.style.cssText =\n      \"max-width:100%;max-height:100%;object-fit:contain;\" +\n      \"border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.15);\";\n    doc.body.appendChild(img);\n    return;\n  }\n\n  window.open(safe, \"_blank\", \"noopener,noreferrer\");\n}\n\nexport function MessageAttachments({ attachments, className }: MessageAttachmentsProps) {\n  if (!attachments || attachments.length === 0) {\n    return null;\n  }\n\n  return (\n    <div className={cn(\"flex flex-wrap gap-2\", className)}>\n      {attachments.map((attachment, index) => {\n        const isImage = attachment.mediaType.startsWith(\"image/\");\n        const available = !!safeUrl(attachment.url);\n        // Only render the inline preview if the URL passes the protocol\n        // allowlist; otherwise fall back to the (guarded) file button.\n        const safeImageSrc = isImage ? safeUrl(attachment.url) : undefined;\n        if (isImage && safeImageSrc) {\n          return (\n            <div\n              key={`${attachment.url ?? attachment.filename ?? \"att\"}-${index}`}\n              className=\"group relative h-14 w-14 rounded-lg\"\n            >\n              <img\n                src={safeImageSrc}\n                alt={attachment.filename}\n                className=\"size-full rounded-lg object-cover cursor-pointer hover:opacity-80 transition-opacity\"\n                onClick={() => openAttachment(attachment)}\n              />\n            </div>\n          );\n        }\n        const { Icon, label } = describeFile(attachment);\n        const sizeLabel = formatFileSize(attachment.size);\n        return (\n          <button\n            key={`${attachment.url ?? attachment.filename ?? \"att\"}-${index}`}\n            type=\"button\"\n            onClick={() => openAttachment(attachment)}\n            disabled={!available}\n            aria-label={available ? attachment.filename : `${attachment.filename} — unavailable`}\n            className={cn(\n              \"group flex min-h-12 max-w-[240px] cursor-pointer items-center gap-2.5 rounded-[11px] border border-[hsl(var(--chat-border-soft))] bg-[hsl(var(--chat-surface))] px-2.5 text-left transition-colors\",\n              \"hover:bg-[hsl(var(--chat-hover-bg))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\",\n            )}\n          >\n            <span className=\"flex size-[26px] flex-shrink-0 items-center justify-center rounded-[7px] bg-[hsl(var(--chat-primary-tint))] text-[hsl(var(--chat-primary))]\">\n              <Icon className=\"size-4\" />\n            </span>\n            <div className=\"min-w-0 flex flex-col leading-tight\">\n              <span className=\"truncate text-[12.5px] font-medium text-[hsl(var(--chat-text))]\">\n                {attachment.filename}\n              </span>\n              <span className=\"mt-0.5 truncate text-[11px] text-[hsl(var(--chat-text-faint))]\">\n                {available ? label : \"Unavailable\"}{sizeLabel ? ` · ${sizeLabel}` : \"\"}\n              </span>\n            </div>\n          </button>\n        );\n      })}\n    </div>\n  );\n}\n","/**\n * SDK v6 file chunks carry extra display/reference fields in providerMetadata.\n * This is presentation/candidate-reference projection ONLY, never provenance.\n * The server resolves storagePath against the exact-scope managed registry.\n */\nexport function filePartDetails(part: unknown): {\n  filename: string; mediaType: string; url: string; size?: number; storagePath?: string;\n} {\n  const record = (value: unknown): value is Record<string, unknown> =>\n    value !== null && typeof value === 'object' && !Array.isArray(value);\n  const file = record(part) ? part : {};\n  const metadata = record(file.providerMetadata) && record(file.providerMetadata.mordn)\n    && record(file.providerMetadata.mordn.sandboxFile) ? file.providerMetadata.mordn.sandboxFile : {};\n  const filename = file.filename ?? metadata.filename;\n  const size = file.size ?? metadata.size;\n  const storagePath = file.storagePath ?? metadata.storagePath;\n  return {\n    filename: typeof filename === 'string' ? filename : 'unknown',\n    mediaType: typeof file.mediaType === 'string' ? file.mediaType : 'application/octet-stream',\n    url: typeof file.url === 'string' ? file.url : '',\n    ...(typeof size === 'number' && Number.isSafeInteger(size) && size >= 0 ? { size } : {}),\n    ...(typeof storagePath === 'string' && storagePath.length > 0 ? { storagePath } : {}),\n  };\n}\n","\"use client\";\n\n/**\n * Action row rendered under an assistant message. Generic — the host\n * decides which actions to show. Today: copy + regenerate + optional\n * thumbs up/down feedback. Future additions (share, branch, etc.) plug\n * in here without bespoke wiring at every call site.\n *\n * Visibility: subtle row, low-contrast. Hover-darkening on each\n * button. Always shown for the LAST assistant message, hidden for\n * earlier ones unless the consumer overrides via `alwaysVisible`.\n */\n\nimport { useEffect, useRef, useState } from \"react\";\nimport {\n  CheckIcon,\n  CopyIcon,\n  RotateCcwIcon,\n  ThumbsUpIcon,\n  ThumbsDownIcon,\n  SendHorizontalIcon,\n} from \"lucide-react\";\nimport { cn } from \"../utils/cn\";\nimport { submitFeedback } from \"../utils/feedback\";\nimport type { FeedbackEvent } from \"../types\";\n\nexport interface MessageActionsProps {\n  /** Plain-text representation of the message used for copy. */\n  text: string;\n  /** Click handler for regenerate — typically `useChat().regenerate`.\n   *  Pass undefined to hide the button. */\n  onRegenerate?: () => void;\n  /** Disabled state for regenerate (e.g. while a new turn is streaming). */\n  regenerateDisabled?: boolean;\n  /** When true, actions stay visible; otherwise they reveal on hover/focus of\n   *  the parent message (which must be a `group`). Used for the last message. */\n  alwaysVisible?: boolean;\n  className?: string;\n\n  // ── Feedback (thumbs up/down) — all optional, off by default ──────────────\n  /** Show the thumbs up/down control (opt-in via `config.feedback`). */\n  feedbackEnabled?: boolean;\n  /** Id of the assistant message being rated. Required to record feedback. */\n  messageId?: string;\n  /** Active conversation id, threaded through for the feedback payload. */\n  conversationId?: string;\n  /** Widget `apiBase`; passed to `submitFeedback`. Falsy → network call skipped\n   *  (headless / BYO) and only `onFeedback` fires. */\n  feedbackApiBase?: string;\n  /** Generic headers mirroring the chat transport for the\n   *  best-effort feedback POST. */\n  feedbackHeaders?: Record<string, string>;\n  /** Credentials mode mirroring the chat transport (cross-origin cookie auth). */\n  feedbackCredentials?: RequestCredentials;\n  /** Host callback fired on every submission (fires even with no network). */\n  onFeedback?: (feedback: FeedbackEvent) => void;\n}\n\nexport function MessageActions({\n  text,\n  onRegenerate,\n  regenerateDisabled,\n  alwaysVisible,\n  className,\n  feedbackEnabled,\n  messageId,\n  conversationId,\n  feedbackApiBase,\n  feedbackHeaders,\n  feedbackCredentials,\n  onFeedback,\n}: MessageActionsProps) {\n  const [copied, setCopied] = useState(false);\n  // Which thumb is currently selected (null until the user rates). Reflected\n  // via aria-pressed so assistive tech announces the toggle state.\n  const [rating, setRating] = useState<\"up\" | \"down\" | null>(null);\n  // Whether the thumbs-down reason box is open, and its current text.\n  const [showReason, setShowReason] = useState(false);\n  const [reason, setReason] = useState(\"\");\n  // Drives the polite sr-only confirmation after a submission lands.\n  const [submitted, setSubmitted] = useState(false);\n\n  // Timer id for the \"copied\" flash, so a rapid re-copy (or unmount) can\n  // clear the pending reset instead of leaking it.\n  const copyTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n  useEffect(() => {\n    return () => {\n      if (copyTimerRef.current) clearTimeout(copyTimerRef.current);\n    };\n  }, []);\n\n  const handleCopy = async () => {\n    if (!text) return;\n    try {\n      await navigator.clipboard.writeText(text);\n      setCopied(true);\n      if (copyTimerRef.current) clearTimeout(copyTimerRef.current);\n      copyTimerRef.current = setTimeout(() => setCopied(false), 1500);\n    } catch {\n      // Browsers without clipboard access — silently no-op.\n    }\n  };\n\n  // Records a rating: fires the best-effort network POST (skipped when there's\n  // no base URL) AND the host callback. Kept side-effect-safe — submitFeedback\n  // never throws, so a telemetry failure can't break the click.\n  const record = (r: \"up\" | \"down\", withReason?: string) => {\n    if (!feedbackEnabled || !messageId) return;\n    const trimmedReason = withReason && withReason.trim() ? withReason.trim() : undefined;\n    // Best-effort backend record — resolves regardless of outcome; ignore result.\n    void submitFeedback(feedbackApiBase, feedbackHeaders, {\n      conversationId,\n      messageId,\n      rating: r,\n      reason: trimmedReason,\n    }, feedbackCredentials);\n    // Always fire the host callback so BYO / headless hosts still get the event.\n    onFeedback?.({ messageId, conversationId, rating: r, reason: trimmedReason });\n    setSubmitted(true);\n  };\n\n  const handleThumbUp = () => {\n    setRating(\"up\");\n    setShowReason(false);\n    setReason(\"\");\n    record(\"up\");\n  };\n\n  const handleThumbDown = () => {\n    setRating(\"down\");\n    // Reveal the optional reason box. Submitting a bare thumbs-down still\n    // records immediately — the reason is a follow-up refinement, not required.\n    setShowReason(true);\n    record(\"down\");\n  };\n\n  const handleReasonSubmit = () => {\n    if (!reason.trim()) {\n      // Nothing typed — just close the box; the bare down-vote already recorded.\n      setShowReason(false);\n      return;\n    }\n    // Re-record the down-vote now carrying the reason.\n    record(\"down\", reason);\n    setShowReason(false);\n  };\n\n  const showFeedback = feedbackEnabled && !!messageId;\n\n  return (\n    <div\n      className={cn(\n        \"flex flex-col gap-1.5 -ml-1.5 transition-opacity duration-150\",\n        alwaysVisible\n          // LAST message: in-flow (small top margin) so it never overlaps the\n          // composer sitting just below, and ALWAYS visible — the freshest\n          // answer is where copy/regenerate/rate get used, so they shouldn't\n          // need a hover to discover (standard chat-product convention).\n          // NOTE: reverses an earlier hover-reveal decision (\"stray copy icons\n          // under the sources list\"); the tightened sources footer with its\n          // hairline separation reads as a distinct zone now.\n          ? \"mt-1.5\"\n          // Other messages: ABSOLUTELY positioned in the gap below the message so\n          // the hidden row adds NO height (it was inflating the assistant→user\n          // gap). Reveals on hover/focus of the message group.\n          : \"absolute left-0 top-full mt-0.5 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto\",\n        className,\n      )}\n    >\n      <div className=\"flex items-center gap-1\">\n        <ActionButton onClick={handleCopy} ariaLabel=\"Copy message\">\n          {copied ? <CheckIcon className=\"size-3.5\" /> : <CopyIcon className=\"size-3.5\" />}\n        </ActionButton>\n        {onRegenerate && (\n          <ActionButton\n            onClick={onRegenerate}\n            disabled={regenerateDisabled}\n            ariaLabel=\"Regenerate response\"\n          >\n            <RotateCcwIcon className=\"size-3.5\" />\n          </ActionButton>\n        )}\n        {showFeedback && (\n          <>\n            <ActionButton\n              onClick={handleThumbUp}\n              ariaLabel=\"Good response\"\n              pressed={rating === \"up\"}\n            >\n              <ThumbsUpIcon className=\"size-3.5\" />\n            </ActionButton>\n            <ActionButton\n              onClick={handleThumbDown}\n              ariaLabel=\"Bad response\"\n              pressed={rating === \"down\"}\n            >\n              <ThumbsDownIcon className=\"size-3.5\" />\n            </ActionButton>\n          </>\n        )}\n        {/* The icon swap (copy → check) is the visual cue; this polite live\n            region gives screen-reader users the same confirmation. Also\n            announces feedback acknowledgement. */}\n        <span aria-live=\"polite\" className=\"sr-only\">\n          {copied ? \"Copied to clipboard\" : submitted ? \"Thanks for your feedback\" : \"\"}\n        </span>\n      </div>\n\n      {/* Thumbs-down reason box — minimal inline input + submit. Optional:\n          the down-vote is already recorded; this lets the user add detail.\n          Only rendered for the feedback control, and only after a down-vote. */}\n      {showFeedback && showReason && (\n        <form\n          className=\"flex items-center gap-1.5 pl-1.5\"\n          onSubmit={(e) => {\n            e.preventDefault();\n            handleReasonSubmit();\n          }}\n        >\n          <input\n            type=\"text\"\n            value={reason}\n            onChange={(e) => setReason(e.target.value)}\n            // eslint-disable-next-line jsx-a11y/no-autofocus\n            autoFocus\n            placeholder=\"What went wrong? (optional)\"\n            aria-label=\"Feedback reason\"\n            className=\"h-7 min-w-0 max-w-[16rem] flex-1 rounded-[7px] bg-[hsl(var(--chat-surface))] px-2 text-[12px] text-[hsl(var(--chat-text-body))] placeholder:text-[hsl(var(--chat-text-subtle))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\"\n          />\n          <ActionButton onClick={handleReasonSubmit} ariaLabel=\"Submit feedback\">\n            <SendHorizontalIcon className=\"size-3.5\" />\n          </ActionButton>\n        </form>\n      )}\n    </div>\n  );\n}\n\ninterface ActionButtonProps {\n  onClick: () => void;\n  disabled?: boolean;\n  ariaLabel: string;\n  /** Toggle state for feedback buttons — reflected via aria-pressed and a\n   *  subtle background so the selected thumb reads as active. */\n  pressed?: boolean;\n  children: React.ReactNode;\n}\n\nfunction ActionButton({ onClick, disabled, ariaLabel, pressed, children }: ActionButtonProps) {\n  return (\n    <button\n      type=\"button\"\n      onClick={onClick}\n      disabled={disabled}\n      aria-label={ariaLabel}\n      // aria-pressed only when this is a toggle (feedback) button; plain action\n      // buttons (copy/regenerate) leave it undefined so they aren't announced\n      // as toggles.\n      aria-pressed={pressed === undefined ? undefined : pressed}\n      className={cn(\n        \"flex size-[26px] items-center justify-center rounded-[7px] p-0 text-[hsl(var(--chat-text-faint))] transition-colors hover:bg-[hsl(var(--chat-hover-bg))] hover:text-[hsl(var(--chat-text))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)] disabled:cursor-not-allowed disabled:opacity-40\",\n        pressed && \"bg-[hsl(var(--chat-hover-bg))] text-[hsl(var(--chat-text))]\",\n      )}\n    >\n      {children}\n    </button>\n  );\n}\n","/**\n * Message-feedback client util.\n *\n * Posts a thumbs up/down (optionally with a freeform reason) to the hosted\n * backend so product teams can measure answer quality. It reuses the SAME\n * transport the widget already uses for chat: the caller passes the widget's\n * `apiBase` and any generic transport headers `DefaultChatTransport` sends,\n * and this posts to `${base}/v1/feedback` — the\n * same `/v1` hosted-API convention as `/v1/conversations`, `/v1/uploads`, etc.\n * The Next.js handler mounted at `apiBase` forwards it to the hosted service\n * with the server-side `Authorization: Bearer <apiKey>` + `X-Chat-User`\n * (exactly as it does for turns/history) — the browser never holds the secret.\n *\n * Contract: BEST-EFFORT and SILENT. It never throws into the UI and never\n * rejects — network / HTTP errors are swallowed (logged via `console.debug`)\n * so a failed telemetry POST can't break the chat. Feedback is a side signal,\n * not a user-blocking action; the host `onFeedback` callback is the source of\n * truth and always fires regardless of this call's outcome.\n *\n * Degrades cleanly with no network: when the widget is NOT in hosted mode —\n * i.e. `base` is empty/whitespace (headless render or BYO backend that opts out)\n * — the network call is skipped\n * entirely and the caller relies solely on `onFeedback`. This keeps\n * server-rendered / offline usage side-effect-free.\n */\n\n/** Thumbs rating on an assistant message. */\nexport type FeedbackRating = 'up' | 'down';\n\n/** Payload recorded for a single feedback submission. */\nexport interface FeedbackSubmission {\n  /** Active conversation id (the widget's tab / useChat id). Optional: a\n   *  brand-new conversation may not have been persisted server-side yet. */\n  conversationId?: string;\n  /** Id of the assistant message being rated (`UIMessage.id`). */\n  messageId: string;\n  /** Thumbs up or down. */\n  rating: FeedbackRating;\n  /** Optional freeform reason, typically revealed on thumbs-down. */\n  reason?: string;\n}\n\n/**\n * Best-effort POST of feedback to `${base}/v1/feedback`.\n *\n * @param base    The widget's `apiBase` (e.g. `/api/chat`). Falsy/blank → skip\n *                the network call (headless / BYO / unauthenticated).\n * @param headers Generic headers shared with the chat transport. `Content-Type`\n *                is added here so callers don't have to.\n * @param body    The feedback submission.\n * @returns A promise that ALWAYS resolves (never rejects). `true` if the POST\n *          was attempted and the server accepted it (2xx); `false` if the call\n *          was skipped (no base) or the request failed / was rejected.\n */\nexport async function submitFeedback(\n  base: string | undefined,\n  headers: Record<string, string> | undefined,\n  body: FeedbackSubmission,\n  credentials?: RequestCredentials,\n): Promise<boolean> {\n  // Not hosted / no base URL → rely solely on the host `onFeedback` callback.\n  // Trim so an accidental whitespace-only base is treated as absent.\n  const trimmed = (base ?? '').trim();\n  if (!trimmed) return false;\n\n  // Normalise to avoid a double slash when the caller passes a trailing \"/\"\n  // (mirrors the hosted store's `baseUrl.replace(/\\/$/, '')`).\n  const url = `${trimmed.replace(/\\/+$/, '')}/v1/feedback`;\n\n  try {\n    const res = await fetch(url, {\n      method: 'POST',\n      headers: {\n        ...(headers ?? {}),\n        'Content-Type': 'application/json',\n      },\n      // Same credentials mode as every other widget request (cross-origin\n      // cookie-auth deployments; see ChatWidgetProps.requestCredentials).\n      credentials,\n      body: JSON.stringify({\n        conversationId: body.conversationId,\n        messageId: body.messageId,\n        rating: body.rating,\n        // Only send `reason` when non-empty so the payload stays clean.\n        ...(body.reason && body.reason.trim() ? { reason: body.reason.trim() } : {}),\n      }),\n    });\n    if (!res.ok) {\n      // Swallow non-2xx — telemetry must never surface as a UI error.\n      console.debug('[chat-widget] feedback POST rejected:', res.status);\n      return false;\n    }\n    return true;\n  } catch (err) {\n    // Network failure (offline, blocked, CORS, aborted) — best-effort, ignore.\n    console.debug('[chat-widget] feedback POST failed:', err);\n    return false;\n  }\n}\n","import { Fragment, memo, useMemo } from 'react';\nimport type { UIMessage } from 'ai';\nimport { Message, MessageContent } from '../message';\nimport { Response } from '../response';\nimport { AgentToolCall } from './AgentToolCall';\nimport { AgentThinkingTool } from './AgentThinkingTool';\nimport {\n  getResultSummary,\n  getToolStatus,\n  getToolSubtitle,\n  getToolVerb,\n} from './toolRegistry';\nimport { toToolPart, type ToolPart, type TurnState } from './types';\nimport type { ActionRenderer, ToolRenderer, MessageDataPart, MessagePartRenderers } from '../../types';\nimport { getMessagePartRenderer, isCustomMessageDataPart } from '../../utils/message-part-renderers';\nimport { ActionResultCard } from '../action-result-card';\nimport type { CitationSource } from '../citation-markers';\n\n/**\n * Renders one assistant turn as a clean, in-order flow — text, reasoning, and\n * tool calls in the sequence they happened. NO step-grouping / \"N steps\"\n * folding (that's an agent dev-log pattern; an assistant shows its work inline\n * and reassuringly). Each tool is a compact AgentToolCall row; reasoning is the\n * AgentThinkingTool disclosure; the gap before the first token shows a warm\n * planning shimmer.\n */\ninterface AgentTurnTranscriptProps {\n  message: UIMessage;\n  isLast: boolean;\n  isStreaming: boolean;\n  turn: TurnState;\n  toolRenderers?: Record<string, ToolRenderer>;\n  actionRenderers?: Record<string, ActionRenderer>;\n  messagePartRenderers?: MessagePartRenderers;\n  onToolApproval?: (approvalId: string, approved: boolean) => void;\n  /**\n   * The message's source-url parts, in Sources-card order. Threaded down to\n   * `Response` so inline `[ref: N]` chips can resolve preserved source IDs\n   * (#138). Supplying the array also opts assistant text into citation parsing.\n   */\n  sources?: CitationSource[];\n}\n\nconst MUTED = { color: 'hsl(var(--chat-text-muted))' } as const;\n\ntype RenderPart =\n  | { kind: 'text'; id: string; text: string; idx: number }\n  | { kind: 'reasoning'; id: string; text: string; idx: number }\n  | { kind: 'data'; id: string; part: MessageDataPart; idx: number }\n  | { kind: 'tool'; id: string; tool: ToolPart; idx: number };\n\nfunction AgentTurnTranscriptImpl({\n  message,\n  isLast,\n  isStreaming,\n  turn,\n  toolRenderers,\n  actionRenderers,\n  messagePartRenderers,\n  onToolApproval,\n  sources,\n}: AgentTurnTranscriptProps) {\n  const turnId = message.id;\n\n  const flat = useMemo<RenderPart[]>(() => {\n    const out: RenderPart[] = [];\n    (message.parts ?? []).forEach((part, i) => {\n      if (part.type === 'text') {\n        out.push({ kind: 'text', id: `${turnId}-${i}`, text: part.text, idx: i });\n      } else if (part.type === 'reasoning') {\n        out.push({\n          kind: 'reasoning',\n          id: `${turnId}-${i}`,\n          text: (part as { text: string }).text,\n          idx: i,\n        });\n      } else if (part.type.startsWith('tool-') || part.type === 'dynamic-tool') {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        const tp = toToolPart(part as any, `${turnId}-${i}`);\n        out.push({ kind: 'tool', id: tp.id, tool: tp, idx: i });\n      } else if (isCustomMessageDataPart(part) && getMessagePartRenderer(part, messagePartRenderers)) {\n        out.push({ kind: 'data', id: `${turnId}-${i}`, part, idx: i });\n      }\n    });\n    return out;\n  }, [message.parts, turnId, messagePartRenderers]);\n\n  const lastIdx = flat.length - 1;\n  // NOTE: the pre-first-token planning indicator (\"One moment\", …) is rendered\n  // by ChatInterface (showThinking) — it covers the whole gap including before\n  // this assistant message exists, so this component renders nothing extra\n  // for an empty streaming turn.\n\n  return (\n    <div className=\"flex flex-col gap-1.5\" data-assistant-turn-id={turnId}>\n      {flat.map((item, i) => {\n        const isItemLast = i === lastIdx;\n        if (item.kind === 'text') {\n          if (!item.text.trim()) return null;\n          const isTextStreaming = isStreaming && isLast && isItemLast;\n          return (\n            <Fragment key={item.id}>\n              <Message from=\"assistant\">\n                <MessageContent>\n                  <Response isStreaming={isTextStreaming} sources={sources}>\n                    {item.text}\n                  </Response>\n                </MessageContent>\n              </Message>\n            </Fragment>\n          );\n        }\n        if (item.kind === 'reasoning') {\n          const isReasoningStreaming = isStreaming && isLast && isItemLast;\n          return (\n            <AgentThinkingTool\n              key={item.id}\n              text={item.text}\n              turn={turn}\n              isStreaming={isReasoningStreaming}\n            />\n          );\n        }\n        if (item.kind === 'data') {\n          return (\n            <Fragment key={item.id}>\n              {getMessagePartRenderer(item.part, messagePartRenderers)?.(item.part, {\n                messageId: message.id,\n                role: message.role,\n                isStreaming: isStreaming && isLast,\n              }) ?? null}\n            </Fragment>\n          );\n        }\n        // tool\n        const part = item.tool;\n        const custom = toolRenderers?.[part.tool];\n        if (custom) {\n          const rendered = custom({\n            type: `tool-${part.tool}`,\n            toolName: part.tool,\n            toolCallId: part.id,\n            state: part.state.status,\n            input: part.state.input,\n            output: part.state.output,\n            errorText: part.state.errorText,\n          });\n          if (rendered != null) return <Fragment key={item.id}>{rendered}</Fragment>;\n        }\n        // Declarative action card (#166) — runs after full-JSX toolRenderers,\n        // before the default row. Reflects the REAL outcome (success / partial /\n        // error), so a model's confident \"Done!\" can't hide a failed step.\n        const action = actionRenderers?.[part.tool];\n        if (action) {\n          const result = action({\n            type: `tool-${part.tool}`,\n            toolName: part.tool,\n            toolCallId: part.id,\n            state: part.state.status,\n            input: part.state.input,\n            output: part.state.output,\n            errorText: part.state.errorText,\n          });\n          if (result != null) {\n            return (\n              <Fragment key={item.id}>\n                <ActionResultCard {...result} />\n              </Fragment>\n            );\n          }\n        }\n        const status = getToolStatus(part, turn);\n        // Human-in-the-loop: a tool paused awaiting approval shows an explicit\n        // approval card (unless a policy already auto-approved it). The target is\n        // the salient input when available, otherwise the tool name — never a\n        // vague past-tense verb that makes an unapproved action look completed.\n        const awaitingApproval =\n          part.state.status === 'approval-requested' &&\n          !!part.approval &&\n          !part.approval.isAutomatic;\n        const verb = awaitingApproval ? 'Wants to run' : getToolVerb(part.tool, status.isPending);\n        // While running show the input subtitle; once done prefer a result summary.\n        const subtitle = awaitingApproval\n          ? getToolSubtitle(part) || part.tool\n          : status.isPending\n            ? getToolSubtitle(part)\n            : getResultSummary(part) || getToolSubtitle(part);\n        const detail =\n          part.state.output != null\n            ? typeof part.state.output === 'string'\n              ? part.state.output\n              : JSON.stringify(part.state.output, null, 2)\n            : undefined;\n        return (\n          <AgentToolCall\n            key={item.id}\n            verb={verb}\n            subtitle={subtitle}\n            isPending={status.isPending}\n            isError={status.isError}\n            detail={detail}\n            errorText={part.state.errorText}\n            awaitingApproval={awaitingApproval}\n            onApprove={\n              awaitingApproval && onToolApproval && part.approval\n                ? (approved) => onToolApproval(part.approval!.id, approved)\n                : undefined\n            }\n          />\n        );\n      })}\n\n    </div>\n  );\n}\n\nexport const AgentTurnTranscript = memo(AgentTurnTranscriptImpl);\n","import { memo, useState, type ReactNode } from 'react';\nimport { Check, ChevronRight, Loader2, X } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport { CodeBlock } from '../code-block';\nimport { TextShimmer } from './TextShimmer';\n\n/**\n * One assistant tool call, as a single compact row. Reads like \"here's what I\n * did for you\", not a developer work-log:\n *\n *   ⟳ Pulling up your portfolios …        (running — spinner)\n *   ✓ Pulled up your portfolios   13 results        ⌄   (done — check)\n *   ✕ Couldn't search the web                            (error — cross)\n *\n * - a leading status icon: a small spinner while running, a check once done, a\n *   cross on error — explicit and unambiguous\n * - a friendly verb that shimmers while the tool is running, then settles to\n *   past-tense once it completes\n * - a muted subtitle (the salient input) or, once done, a short result summary\n * - an optional hover-revealed chevron that expands the raw payload inline for\n *   the curious — collapsed by default so the row stays clean.\n *\n * Tokens are --chat-*; no card chrome, just a soft hover surface.\n */\ninterface AgentToolCallProps {\n  verb: string;\n  subtitle?: ReactNode;\n  isPending: boolean;\n  isError: boolean;\n  /** Raw payload to reveal on expand (pretty JSON / text). Omitted → no chevron. */\n  detail?: string;\n  /** Error text shown in red when isError. */\n  errorText?: string;\n  /** True when this tool is paused awaiting the end-user's approval. */\n  awaitingApproval?: boolean;\n  /** Approve (true) / deny (false) the paused tool. */\n  onApprove?: (approved: boolean) => void;\n}\n\nconst MUTED = { color: 'hsl(var(--chat-text-muted))' } as const;\nconst SUBTLE = { color: 'hsl(var(--chat-text-subtle))' } as const;\nconst HOVER = { backgroundColor: 'transparent' } as const;\n// Match the jarvis PortfolioHoldingsEditor status colours: green-400 / red-400.\nconst SUCCESS_COLOR = { color: 'hsl(var(--chat-success))' } as const;\nconst ERROR_COLOR = { color: 'hsl(var(--chat-danger))' } as const;\n\nconst APPROVAL_COLOR = { color: 'hsl(var(--chat-warning))' } as const;\n\n/** Leading status icon: amber dot (awaiting approval) → spinner (running) →\n *  green check (done) → red cross (error). */\nfunction StatusIcon({\n  isPending,\n  isError,\n  awaitingApproval,\n}: {\n  isPending: boolean;\n  isError: boolean;\n  awaitingApproval?: boolean;\n}) {\n  if (awaitingApproval) {\n    return (\n      <span\n        className=\"size-[7px] flex-shrink-0 rounded-full\"\n        style={{ backgroundColor: APPROVAL_COLOR.color }}\n        aria-hidden=\"true\"\n      />\n    );\n  }\n  if (isError) {\n    return <X className=\"size-3 flex-shrink-0\" style={ERROR_COLOR} strokeWidth={2.5} aria-hidden=\"true\" />;\n  }\n  if (isPending) {\n    return <Loader2 className=\"size-[11px] flex-shrink-0 animate-spin\" style={SUBTLE} aria-hidden=\"true\" />;\n  }\n  return <Check className=\"size-3 flex-shrink-0\" style={SUCCESS_COLOR} strokeWidth={2.5} aria-hidden=\"true\" />;\n}\n\nfunction AgentToolCallImpl({\n  verb,\n  subtitle,\n  isPending,\n  isError,\n  detail,\n  errorText,\n  awaitingApproval,\n  onApprove,\n}: AgentToolCallProps) {\n  const [expanded, setExpanded] = useState(false);\n  const hasDetail = Boolean((detail && detail.trim()) || errorText);\n  const accessibleStatus = awaitingApproval\n    ? 'Awaiting approval'\n    : isError\n      ? 'Error'\n      : isPending\n        ? 'Running'\n        : 'Completed';\n\n  return (\n    <div\n      className={cn(\n        'group/tool select-text',\n        awaitingApproval &&\n          'rounded-[11px] border border-[hsl(var(--chat-warning)/0.28)] bg-[hsl(var(--chat-warning)/0.055)] px-3 py-2.5',\n      )}\n    >\n      <div\n        className={cn(\n          'flex items-center gap-2 rounded-md py-1 transition-colors',\n          !awaitingApproval && '-mx-2 px-2',\n          hasDetail &&\n            'cursor-pointer hover:bg-[hsl(var(--chat-hover-bg))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]',\n        )}\n        style={HOVER}\n        // Only the rows that actually expand a payload are interactive — expose\n        // them as keyboard-operable disclosures; leave static rows as plain text.\n        role={hasDetail ? 'button' : undefined}\n        tabIndex={hasDetail ? 0 : undefined}\n        aria-expanded={hasDetail ? expanded : undefined}\n        onClick={hasDetail ? () => setExpanded((v) => !v) : undefined}\n        onKeyDown={\n          hasDetail\n            ? (e) => {\n                if (e.key === 'Enter' || e.key === ' ') {\n                  e.preventDefault();\n                  setExpanded((v) => !v);\n                }\n              }\n            : undefined\n        }\n      >\n        {/* Every tool row has a compact status glyph: spinner while running,\n            check/cross when settled, warning dot while awaiting approval. */}\n        <StatusIcon isPending={isPending} isError={isError} awaitingApproval={awaitingApproval} />\n        <span className=\"sr-only\">{accessibleStatus}: </span>\n\n        <div className=\"flex items-baseline gap-1.5 min-w-0 text-[12.5px] leading-5\">\n          {isPending ? (\n            <TextShimmer as=\"span\" className=\"font-semibold whitespace-nowrap flex-shrink-0\">\n              {verb}\n            </TextShimmer>\n          ) : (\n            <span className=\"font-semibold whitespace-nowrap flex-shrink-0\" style={MUTED}>\n              {verb}\n            </span>\n          )}\n          {subtitle && (\n            awaitingApproval ? (\n              <code className=\"truncate rounded-md bg-[hsl(var(--chat-warning)/0.1)] px-1.5 py-0.5 font-mono text-[11.5px] text-[hsl(var(--chat-text))]\">\n                {subtitle}\n              </code>\n            ) : (\n              <span className=\"truncate min-w-0 font-mono text-[11.5px] text-[hsl(var(--chat-text-faint))]\">\n                {subtitle}\n              </span>\n            )\n          )}\n        </div>\n\n        {hasDetail && (\n          <ChevronRight\n            className={cn(\n              'ml-auto w-3.5 h-3.5 flex-shrink-0 transition-all duration-200 ease-out',\n              expanded ? 'rotate-90 opacity-100' : 'opacity-0 group-hover/tool:opacity-100',\n            )}\n            style={SUBTLE}\n          />\n        )}\n      </div>\n\n      {/* Human-in-the-loop: Approve / Deny a paused tool. */}\n      {awaitingApproval && onApprove && (\n        <div className=\"flex items-center gap-2 pt-2\">\n          <button\n            type=\"button\"\n            onClick={() => onApprove(true)}\n            className=\"chat-tool-approve inline-flex min-h-8 items-center rounded-lg px-3 text-[12.5px] font-semibold\"\n          >\n            Allow\n          </button>\n          <button\n            type=\"button\"\n            onClick={() => onApprove(false)}\n            className=\"chat-tool-deny inline-flex min-h-8 items-center rounded-lg px-3 text-[12.5px] font-medium\"\n          >\n            Deny\n          </button>\n        </div>\n      )}\n\n      {expanded && hasDetail && (\n        <div className=\"chat-tool-detail pl-4 pr-2 pt-1 pb-1\">\n          {errorText ? (\n            <div\n              className=\"rounded-md px-2.5 py-1.5 text-xs\"\n              style={{ backgroundColor: 'hsl(var(--chat-danger) / 0.12)', color: 'hsl(var(--chat-danger))' }}\n            >\n              {errorText}\n            </div>\n          ) : (\n            <div\n              className=\"rounded-md overflow-auto max-h-56 scrollbar-hide text-xs\"\n              style={{ backgroundColor: 'hsl(var(--chat-surface))' }}\n            >\n              <CodeBlock code={detail as string} language=\"json\" />\n            </div>\n          )}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport const AgentToolCall = memo(\n  AgentToolCallImpl,\n  (p, n) =>\n    p.verb === n.verb &&\n    p.subtitle === n.subtitle &&\n    p.isPending === n.isPending &&\n    p.isError === n.isError &&\n    p.detail === n.detail &&\n    p.errorText === n.errorText &&\n    p.awaitingApproval === n.awaitingApproval &&\n    p.onApprove === n.onApprove,\n);\n","\"use client\";\n\nimport { Button } from \"../ui/button\";\nimport { cn } from \"../utils/cn\";\nimport { highlightCode } from \"../utils/highlight\";\nimport { CheckIcon, CopyIcon } from \"lucide-react\";\nimport type { ComponentProps, HTMLAttributes, ReactNode } from \"react\";\nimport { createContext, useContext, useEffect, useRef, useState } from \"react\";\n\ntype CodeBlockContextType = {\n  code: string;\n};\n\nconst CodeBlockContext = createContext<CodeBlockContextType>({\n  code: \"\",\n});\n\nexport type CodeBlockProps = HTMLAttributes<HTMLDivElement> & {\n  code: string;\n  /**\n   * Optional language hint. Honored when it names a real language; the generic\n   * `\"json\"` default that tool callers pass is treated as \"unknown\" and verified\n   * against the actual content (see `resolveLanguage`). Still surfaced as the\n   * `data-language` attribute for styling/selection.\n   */\n  language?: string;\n  /** @deprecated No-op — line numbers are not rendered. */\n  showLineNumbers?: boolean;\n  children?: ReactNode;\n};\n\n/**\n * Resolve the language to highlight as, fixing the substance of #5: tool string\n * output was historically force-highlighted as JSON, so a plain-text / Markdown\n * / error-message result got wrapped in JSON coloring and read as garbled.\n *\n * Rule: honor an explicit, specific `language` — but the `\"json\"` that every\n * tool call site passes by default is NOT trustworthy (the string may be plain\n * text). For that case (and when no language is given at all) we look at the\n * content: if it `JSON.parse`s, it's genuinely JSON; otherwise it's plain\n * `\"text\"`. Highlighting itself stays best-effort (unknown langs fall back to\n * plain in the util), so this only needs to get the common case right.\n */\nfunction resolveLanguage(code: string, language: string | undefined): string {\n  const hint = (language ?? \"\").trim().toLowerCase();\n\n  // A specific, non-\"json\" hint is taken at face value.\n  if (hint && hint !== \"json\") return hint;\n\n  // No hint, or the suspect \"json\" default → decide from the content itself.\n  const trimmed = code.trim();\n  if (trimmed) {\n    try {\n      JSON.parse(trimmed);\n      return \"json\";\n    } catch {\n      // Not JSON — render as plain text rather than mis-coloring it as JSON.\n      return \"text\";\n    }\n  }\n  return \"text\";\n}\n\n/**\n * Code block rendered as a theme-tokened `<pre><code>`, now with Shiki syntax\n * highlighting layered on as a progressive enhancement.\n *\n * History: `react-syntax-highlighter` (Prism) was removed in #177 because its\n * `styles/prism` directory import is invalid under strict native-ESM resolution\n * and crashed consumers (Next RSC / Vite / Turbopack) with\n * ERR_UNSUPPORTED_DIR_IMPORT — leaving this block plain. We reintroduce\n * highlighting the ESM-clean way, via the shared lazy Shiki util\n * (`utils/highlight.ts`): it dynamic-imports `shiki/bundle/web` only when a block\n * actually renders and degrades to this plain `<pre><code>` on ANY failure, so\n * no bundler/runtime can break. Colors come from `--shiki-light/-dark` CSS vars\n * mapped onto the widget theme — consistent with the prose CollapsibleCodeBlock.\n *\n * The public API (`CodeBlock`, `CodeBlockCopyButton`, and every prop including\n * the deprecated `showLineNumbers` no-op) is unchanged — it's part of the\n * exported `Tool` surface.\n */\nexport const CodeBlock = ({\n  code,\n  language,\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars -- kept for API compat\n  showLineNumbers: _showLineNumbers,\n  className,\n  children,\n  ...props\n}: CodeBlockProps) => {\n  const [highlighted, setHighlighted] = useState<string | null>(null);\n\n  // The language we actually highlight/label as — resolved from the hint + the\n  // content (#5). Recomputed when either changes.\n  const resolvedLanguage = resolveLanguage(code, language);\n\n  // Highlight best-effort; null (import blocked, unknown lang, oversized, or a\n  // throw) keeps the plain <pre><code> below. Tool payloads are short and not\n  // streamed char-by-char here, so no debounce is needed — but we still guard\n  // against a stale async result committing after code/language changed.\n  useEffect(() => {\n    let cancelled = false;\n    highlightCode(code, resolvedLanguage).then((html) => {\n      if (!cancelled) setHighlighted(html);\n    });\n    return () => {\n      cancelled = true;\n    };\n  }, [code, resolvedLanguage]);\n\n  return (\n    <CodeBlockContext.Provider value={{ code }}>\n      <div\n        className={cn(\n          \"relative w-full overflow-hidden rounded-[10px] border border-[hsl(var(--chat-border-soft))] bg-[hsl(var(--chat-surface))]\",\n          className\n        )}\n        {...props}\n      >\n        <div className=\"relative max-h-56 overflow-y-auto\">\n          {highlighted ? (\n            // Shiki's <pre class=\"shiki\"> markup. Safe to inject: Shiki escapes\n            // all token text while building the HTML, so nothing from `code` can\n            // inject markup. `.shiki`'s background is reset in styles.src.css so\n            // the widget surface shows through; token colors come from the\n            // --shiki-light/-dark CSS vars.\n            <div\n              className=\"code-block-shiki m-0 overflow-x-auto p-3 font-mono text-[12.5px] leading-[1.55]\"\n              data-language={resolvedLanguage}\n              dangerouslySetInnerHTML={{ __html: highlighted }}\n            />\n          ) : (\n            <pre\n              className=\"m-0 overflow-x-auto p-3 font-mono text-[12.5px] leading-[1.55] text-[hsl(var(--chat-text))]\"\n              data-language={resolvedLanguage}\n            >\n              <code className=\"font-mono text-[12.5px]\">{code}</code>\n            </pre>\n          )}\n          {children && (\n            <div className=\"absolute top-2 right-2 flex items-center gap-2\">\n              {children}\n            </div>\n          )}\n        </div>\n      </div>\n    </CodeBlockContext.Provider>\n  );\n};\n\nexport type CodeBlockCopyButtonProps = ComponentProps<typeof Button> & {\n  onCopy?: () => void;\n  onError?: (error: Error) => void;\n  timeout?: number;\n};\n\nexport const CodeBlockCopyButton = ({\n  onCopy,\n  onError,\n  timeout = 2000,\n  children,\n  className,\n  ...props\n}: CodeBlockCopyButtonProps) => {\n  const [isCopied, setIsCopied] = useState(false);\n  const { code } = useContext(CodeBlockContext);\n\n  // Timer id for the \"copied\" flash, so a rapid re-copy (or unmount) can\n  // clear the pending reset instead of leaking it.\n  const copyTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n  useEffect(() => {\n    return () => {\n      if (copyTimerRef.current) clearTimeout(copyTimerRef.current);\n    };\n  }, []);\n\n  const copyToClipboard = async () => {\n    // `navigator.clipboard` is undefined in insecure (http) contexts — common\n    // for internal/enterprise deployments. Optional-chain so the guard returns\n    // cleanly instead of throwing a TypeError on the property access.\n    if (typeof window === \"undefined\" || !navigator.clipboard?.writeText) {\n      onError?.(new Error(\"Clipboard API not available\"));\n      return;\n    }\n\n    try {\n      await navigator.clipboard.writeText(code);\n      setIsCopied(true);\n      onCopy?.();\n      if (copyTimerRef.current) clearTimeout(copyTimerRef.current);\n      copyTimerRef.current = setTimeout(() => setIsCopied(false), timeout);\n    } catch (error) {\n      onError?.(error as Error);\n    }\n  };\n\n  const Icon = isCopied ? CheckIcon : CopyIcon;\n\n  return (\n    <Button\n      className={cn(\"shrink-0\", className)}\n      onClick={copyToClipboard}\n      size=\"icon\"\n      variant=\"ghost\"\n      {...props}\n    >\n      {children ?? <Icon size={14} />}\n    </Button>\n  );\n};\n","import { ChevronRight } from 'lucide-react';\nimport { memo, useEffect, useRef, useState } from 'react';\nimport { cn } from '../../utils/cn';\nimport { Response } from '../response';\nimport { TextShimmer } from './TextShimmer';\nimport type { TurnState } from './types';\n\nconst SCROLL_THRESHOLD = 400;\n\ninterface AgentThinkingToolProps {\n  text: string;\n  turn: TurnState;\n  isStreaming: boolean;\n}\n\nconst SUBTLE = { color: 'hsl(var(--chat-text-subtle))' } as const;\nconst FADE_BG = {\n  backgroundImage: 'linear-gradient(to bottom, hsl(var(--chat-background)), transparent)',\n} as const;\n\nfunction AgentThinkingToolImpl({ text, turn, isStreaming }: AgentThinkingToolProps) {\n  const isActivelyStreaming = turn !== 'done' && turn !== 'error';\n  const isPending = isStreaming && isActivelyStreaming;\n\n  // Open while actively thinking; auto-collapse the moment it settles.\n  const [isExpanded, setIsExpanded] = useState(isPending);\n  const wasPendingRef = useRef(isPending);\n  const scrollRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    if (wasPendingRef.current && !isPending) setIsExpanded(false);\n    wasPendingRef.current = isPending;\n  }, [isPending]);\n\n  const thinkingText = text || '';\n\n  useEffect(() => {\n    if (isPending && isExpanded && scrollRef.current) {\n      scrollRef.current.scrollTop = scrollRef.current.scrollHeight;\n    }\n  }, [thinkingText, isPending, isExpanded]);\n\n  if (!thinkingText && !isPending) return null;\n\n  const longBody = thinkingText.length > SCROLL_THRESHOLD;\n\n  return (\n    <div className=\"select-text\">\n      <div\n        role=\"button\"\n        tabIndex={0}\n        aria-expanded={isExpanded}\n        aria-label={isExpanded ? 'Hide reasoning' : 'Show reasoning'}\n        onClick={() => setIsExpanded((v) => !v)}\n        onKeyDown={(e) => {\n          // A disclosure must be operable by keyboard: Enter and Space toggle it\n          // (Space is preventDefault-ed so the page doesn't scroll).\n          if (e.key === 'Enter' || e.key === ' ') {\n            e.preventDefault();\n            setIsExpanded((v) => !v);\n          }\n        }}\n        className=\"group/think inline-flex items-center gap-1.5 rounded-md py-0.5 cursor-pointer text-[12.5px] leading-5 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\"\n      >\n        {isPending ? (\n          <TextShimmer as=\"span\" className=\"font-medium whitespace-nowrap\">\n            Thinking\n          </TextShimmer>\n        ) : (\n          <span className=\"font-medium whitespace-nowrap transition-colors group-hover/think:text-[hsl(var(--chat-text-muted))]\" style={SUBTLE}>\n            Thought it through\n          </span>\n        )}\n        <ChevronRight\n          className={cn(\n            'h-2.5 w-2.5 flex-shrink-0 transition-transform duration-150 ease-out',\n            isExpanded && 'rotate-90',\n          )}\n          style={SUBTLE}\n          strokeWidth={1.6}\n        />\n      </div>\n\n      {isExpanded && thinkingText && (\n        <div className=\"relative chat-tool-detail ml-2 mt-1 border-l-2 border-[hsl(var(--chat-border))] pl-3\">\n          {isPending && longBody && (\n            <div className=\"absolute inset-x-0 top-0 h-5 z-10 pointer-events-none\" style={FADE_BG} />\n          )}\n          <div\n            ref={scrollRef}\n            className={cn('text-[12.5px] italic leading-relaxed text-[hsl(var(--chat-text-faint))]', isPending && longBody && 'overflow-y-auto scrollbar-hide max-h-28')}\n          >\n            <Response className=\"text-[12.5px]\" isStreaming={isPending}>\n              {thinkingText}\n            </Response>\n            {isPending && <span className=\"chat-caret\" aria-hidden=\"true\" />}\n          </div>\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport const AgentThinkingTool = memo(AgentThinkingToolImpl);\n","import type { ToolPartLike } from '../../types';\n\n/**\n * Lifecycle of the assistant turn this part belongs to. The widget exposes the\n * AI SDK ChatStatus at the message level; we collapse it to three states.\n */\nexport type TurnState = 'streaming' | 'done' | 'error';\n\n/** Normalised tool part: the widget's ToolPartLike adapted to { id, tool, state }. */\nexport interface ToolPart {\n  id: string;\n  tool: string;\n  state: {\n    status: ToolPartLike['state'];\n    input: Record<string, unknown>;\n    output?: unknown;\n    errorText?: string;\n  };\n  /** Carried from the SDK part — set when status is 'approval-requested'. */\n  approval?: { id: string; isAutomatic?: boolean };\n}\n\nexport interface ToolStatus {\n  isPending: boolean;\n  isError: boolean;\n  isSuccess: boolean;\n  isInterrupted: boolean;\n}\n\nexport function toToolPart(raw: ToolPartLike, fallbackId: string): ToolPart {\n  const tool =\n    raw.toolName ?? (raw.type.startsWith('tool-') ? raw.type.slice(5) : raw.type);\n  return {\n    id: raw.toolCallId || fallbackId,\n    tool,\n    state: {\n      status: raw.state,\n      input: (raw.input as Record<string, unknown>) ?? {},\n      output: raw.output,\n      errorText: raw.errorText,\n    },\n    approval: raw.approval,\n  };\n}\n","'use client';\n\n/**\n * ActionResultCard (#166) — a structured, trustworthy summary of what a tool\n * actually did, rendered inline in the message stream instead of as prose or a\n * raw JSON dump.\n */\nimport { cn } from '../utils/cn';\nimport { safeUrl } from '../utils/url-safety';\nimport { AlertTriangle, CheckCircle2, ExternalLinkIcon, Loader2, XCircle } from 'lucide-react';\nimport type { ComponentType } from 'react';\nimport type { ActionResult, ActionResultStatus } from '../types';\n\ntype StatusStyle = {\n  Icon: ComponentType<{ className?: string; style?: object; strokeWidth?: number }>;\n  color: string;\n  tint: string;\n  spin: boolean;\n  label: string;\n};\n\nconst STATUS_STYLES: Record<ActionResultStatus, StatusStyle> = {\n  pending: {\n    Icon: Loader2,\n    color: 'hsl(var(--chat-text-faint))',\n    tint: 'hsl(var(--chat-surface))',\n    spin: true,\n    label: 'Pending',\n  },\n  success: {\n    Icon: CheckCircle2,\n    color: 'hsl(var(--chat-success))',\n    tint: 'hsl(var(--chat-success) / 0.09)',\n    spin: false,\n    label: 'Done',\n  },\n  partial: {\n    Icon: AlertTriangle,\n    color: 'hsl(var(--chat-warning))',\n    tint: 'hsl(var(--chat-warning) / 0.09)',\n    spin: false,\n    label: 'Partial',\n  },\n  error: {\n    Icon: XCircle,\n    color: 'hsl(var(--chat-danger))',\n    tint: 'hsl(var(--chat-danger) / 0.09)',\n    spin: false,\n    label: 'Failed',\n  },\n};\n\nexport interface ActionResultCardProps extends ActionResult {\n  className?: string;\n}\n\nexport function ActionResultCard({\n  status,\n  title,\n  fields,\n  link,\n  note,\n  className,\n}: ActionResultCardProps) {\n  const s = STATUS_STYLES[status] ?? STATUS_STYLES.success;\n  const Icon = s.Icon;\n  const safeHref = link ? safeUrl(link.href) : undefined;\n\n  return (\n    <div\n      className={cn('not-prose my-[14px] w-full overflow-hidden rounded-[14px] border', className)}\n      style={{ borderColor: 'hsl(var(--chat-border-soft))', backgroundColor: 'hsl(var(--chat-background))' }}\n      role=\"status\"\n    >\n      <div className=\"flex items-start gap-3 px-3 py-3\">\n        <span\n          className=\"mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-[9px]\"\n          style={{ backgroundColor: s.tint }}\n          aria-hidden=\"true\"\n        >\n          <Icon\n            className={cn('size-4', s.spin && 'animate-spin')}\n            style={{ color: s.color }}\n            strokeWidth={2.4}\n          />\n        </span>\n        <div className=\"min-w-0 flex-1\">\n          <div className=\"flex min-w-0 flex-wrap items-center gap-2\">\n            <span className=\"min-w-0 truncate text-[13px] font-semibold\" style={{ color: 'hsl(var(--chat-text))' }}>\n              {title}\n            </span>\n            <span\n              className=\"rounded-full border px-1.5 py-0.5 text-[9.5px] font-semibold uppercase tracking-[0.06em]\"\n              style={{ borderColor: s.color, color: s.color }}\n            >\n              {s.label}\n            </span>\n          </div>\n\n          {note && (\n            <div className=\"mt-1 text-[12px] leading-relaxed\" style={{ color: 'hsl(var(--chat-text-muted))' }}>\n              {note}\n            </div>\n          )}\n\n          {fields && fields.length > 0 && (\n            <dl className=\"mt-2 grid gap-1.5\">\n              {fields.map((f, i) => (\n                <div key={i} className=\"grid min-w-0 grid-cols-[80px_1fr] gap-3 rounded-[7px] px-2 py-1\" style={{ backgroundColor: 'hsl(var(--chat-surface))' }}>\n                  <dt className=\"truncate text-[11.5px]\" style={{ color: 'hsl(var(--chat-text-faint))' }}>\n                    {f.label}\n                  </dt>\n                  <dd className=\"min-w-0 truncate font-mono text-[11.5px] font-medium\" style={{ color: 'hsl(var(--chat-text))' }}>\n                    {f.value}\n                  </dd>\n                </div>\n              ))}\n            </dl>\n          )}\n\n          {link &&\n            (safeHref ? (\n              <a\n                href={safeHref}\n                target=\"_blank\"\n                rel=\"noopener noreferrer\"\n                className=\"mt-2 inline-flex items-center gap-1 text-[12px] font-medium underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-text)/0.22)]\"\n                style={{ color: 'hsl(var(--chat-primary))' }}\n              >\n                {link.label}\n                <ExternalLinkIcon className=\"size-3\" aria-hidden=\"true\" />\n              </a>\n            ) : (\n              <span\n                className=\"mt-2 inline-flex text-[12px] font-medium\"\n                style={{ color: 'hsl(var(--chat-text-muted))' }}\n              >\n                {link.label}\n              </span>\n            ))}\n        </div>\n      </div>\n    </div>\n  );\n}\n","'use client';\n\nimport { createContext, useContext, ReactNode } from 'react';\n\ninterface ChatStorageContextValue {\n  /**\n   * Prefix for browser-stored chat keys, derived only from the opaque scope in\n   * the authenticated bootstrap response. `null` disables persistence.\n   */\n  storageKeyPrefix: string | null;\n}\n\nconst ChatStorageContext = createContext<ChatStorageContextValue>({\n  storageKeyPrefix: null,\n});\n\nexport function ChatStorageProvider({\n  children,\n  storageScope,\n}: {\n  children: ReactNode;\n  /** Opaque, server-issued scope from the authenticated bootstrap response. */\n  storageScope?: string | null;\n}) {\n  // Identity never crosses the public client API. The server derives this\n  // opaque value from authenticated identity + the resolved agent.\n  const storageKeyPrefix = storageScope ? encodeURIComponent(storageScope) : null;\n\n  return (\n    <ChatStorageContext.Provider value={{ storageKeyPrefix }}>\n      {children}\n    </ChatStorageContext.Provider>\n  );\n}\n\nexport function useChatStorageKey() {\n  return useContext(ChatStorageContext);\n}\n\n/**\n * Remove chat data this widget persisted in the browser. Call this on sign-out\n * / user switch so a subsequent user on the same browser can never see the\n * previous user's conversation tabs, titles, prompts, or model.\n *\n * - No args → clears every `chat-*` key (safe blanket sign-out clear).\n * - `{ storageScope }` → clears only keys for that server-issued opaque scope.\n *\n * Sweeps BOTH localStorage (tabs, panel state) and sessionStorage (per-tab\n * composer drafts) — the same key scheme is used in both.\n */\nexport function clearChatStorage(opts?: { storageScope?: string }): void {\n  if (typeof window === 'undefined') return;\n\n  const scopedPrefix = opts?.storageScope\n    ? `chat-${encodeURIComponent(opts.storageScope)}-`\n    : null;\n\n  const sweep = (storage: Storage) => {\n    const toRemove: string[] = [];\n    for (let i = 0; i < storage.length; i++) {\n      const key = storage.key(i);\n      if (!key) continue;\n      if (scopedPrefix ? key.startsWith(scopedPrefix) : key.startsWith('chat-')) {\n        toRemove.push(key);\n      }\n    }\n    toRemove.forEach((key) => storage.removeItem(key));\n  };\n\n  try {\n    sweep(window.localStorage);\n  } catch {\n    /* storage unavailable — nothing to clear */\n  }\n  try {\n    sweep(window.sessionStorage);\n  } catch {\n    /* storage unavailable — nothing to clear */\n  }\n}\n","/**\n * Convert a `#rgb` / `#rrggbb` hex color into the space-separated HSL triplet\n * the widget's CSS variables consume (e.g. `\"215 20% 25%\"` — used inside\n * `hsl(var(--chat-primary))`). Returns `null` for anything that is not a\n * valid hex color: theming accepts hex ONLY, and callers must skip invalid\n * values so user typos can never produce broken CSS.\n */\nexport function hexToHslTriplet(value: string): string | null {\n  // Guard non-string input (e.g. a partial theme object with a missing color):\n  // the contract is \"return null for anything not a valid hex\", and a crash on\n  // `undefined.trim()` would break the whole widget render.\n  if (typeof value !== 'string') return null;\n  const trimmed = value.trim();\n  const match = /^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/.exec(trimmed);\n  if (!match) return null;\n  let hex = match[1];\n  if (hex.length === 3) hex = hex.split('').map((c) => c + c).join('');\n  const r = parseInt(hex.substring(0, 2), 16) / 255;\n  const g = parseInt(hex.substring(2, 4), 16) / 255;\n  const b = parseInt(hex.substring(4, 6), 16) / 255;\n  const max = Math.max(r, g, b);\n  const min = Math.min(r, g, b);\n  const l = (max + min) / 2;\n  let h = 0;\n  let sat = 0;\n  if (max !== min) {\n    const d = max - min;\n    sat = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n    if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;\n    else if (max === g) h = ((b - r) / d + 2) / 6;\n    else h = ((r - g) / d + 4) / 6;\n  }\n  const round = (n: number) => Math.round(n * 10) / 10;\n  return `${round(h * 360)} ${round(sat * 100)}% ${round(l * 100)}%`;\n}\n","/**\n * Open triggers (#193) — lets a *docs site's own chrome* open the widget\n * without the host holding a React ref: a keyboard shortcut, plain\n * `data-mordn-chat-*` attribute buttons (works from static/markdown-generated\n * HTML with zero JS), and a `document` CustomEvent API (the same thing a\n * script-tag embed or a non-React theme would dispatch).\n *\n * Design constraint: none of these routes may fork the open/close logic.\n * They all call the exact same `open` / `close` / `toggle` callbacks the\n * caller passes in — which in `ChatWidget.tsx` are thin wrappers around the\n * single `setOpenState` used by the imperative handle. That keeps the\n * controlled-mode `onOpenChange` delegation and `persistState` behaviour\n * identical. Keyboard shortcuts and attribute clicks carry explicit user\n * intent and bypass `allowAutoReopen`; CustomEvents remain programmatic and\n * preserve the imperative API's automatic-reopen gate.\n *\n * Multi-instance note: if a page mounts more than one `<ChatWidget>`, every\n * instance registers its own listeners here, so a shortcut/button/event\n * fires ALL of them. Acceptable for the target use case (one widget per\n * docs site) — documented on `DisplayConfig.keyboardShortcut` rather than\n * solved with cross-instance coordination.\n */\nimport { useEffect, useMemo } from 'react';\n\nexport type OpenTriggerSource = 'user' | 'programmatic';\n\nexport interface OpenTriggerActions {\n  open: (source: OpenTriggerSource) => void;\n  close: () => void;\n  toggle: (source: OpenTriggerSource) => void;\n}\n\ninterface ParsedShortcut {\n  /** `mod` resolved at match-time: metaKey on Mac, ctrlKey elsewhere. */\n  mod: boolean;\n  ctrl: boolean;\n  alt: boolean;\n  shift: boolean;\n  /** Lower-cased non-modifier key, e.g. \"k\", \"/\". */\n  key: string;\n}\n\n/** Parse a `+`-joined combo string once (memoized by the caller). Returns\n * `null` for `false`/empty/malformed input so the caller can skip attaching\n * a listener rather than throw on a typo'd config value. */\nfunction parseShortcut(combo: string | false | undefined): ParsedShortcut | null {\n  if (!combo) return null;\n  const tokens = combo\n    .split('+')\n    .map((t) => t.trim().toLowerCase())\n    .filter(Boolean);\n  if (tokens.length === 0) return null;\n\n  const parsed: ParsedShortcut = { mod: false, ctrl: false, alt: false, shift: false, key: '' };\n  const keyTokens: string[] = [];\n  for (const token of tokens) {\n    switch (token) {\n      case 'mod':\n        parsed.mod = true;\n        break;\n      case 'ctrl':\n      case 'control':\n        parsed.ctrl = true;\n        break;\n      case 'alt':\n      case 'option':\n        parsed.alt = true;\n        break;\n      case 'shift':\n        parsed.shift = true;\n        break;\n      default:\n        // Anything not a recognised modifier token is the key. Only the\n        // LAST such token counts as the key (e.g. \"ctrl+shift+/\" → \"/\");\n        // earlier ones are ignored rather than rejecting the whole combo.\n        keyTokens.push(token);\n    }\n  }\n  const key = keyTokens[keyTokens.length - 1];\n  if (!key) return null; // no key token at all (e.g. \"mod+\") — malformed, ignore\n  parsed.key = key;\n  return parsed;\n}\n\n/** All shortcuts yield to editable surfaces, including modifier combos such\n * as Cmd/Ctrl+I (italic). Check inherited contenteditable, including\n * plaintext-only, without depending on isContentEditable support in jsdom. */\nfunction isTypingTarget(target: EventTarget | null): boolean {\n  if (!(target instanceof Element)) return false;\n  if (target.closest('input, textarea, select')) return true;\n  for (let element: Element | null = target; element; element = element.parentElement) {\n    const editable = element.getAttribute('contenteditable')?.toLowerCase();\n    if (editable === '' || editable === 'true' || editable === 'plaintext-only') return true;\n    if (editable === 'false') return false;\n  }\n  return false;\n}\n\nfunction isMac(): boolean {\n  return typeof navigator !== 'undefined' && /Mac|iPod|iPhone|iPad/.test(navigator.platform);\n}\n\n/** Exact modifier-set match (not \"at least these\") — a combo configured as\n * \"mod+k\" must NOT fire on \"mod+shift+k\", so every modifier the event\n * carries has to be accounted for by the parsed combo. */\nfunction matchesShortcut(e: KeyboardEvent, shortcut: ParsedShortcut): boolean {\n  // `mod` resolves to metaKey on Mac, ctrlKey elsewhere; it stands in for\n  // whichever of ctrlKey/metaKey is the platform's primary modifier, so we\n  // don't separately require ctrlKey/metaKey to be unset on the other axis.\n  const wantMeta = shortcut.mod && isMac();\n  const wantCtrl = shortcut.ctrl || (shortcut.mod && !isMac());\n  if (e.metaKey !== wantMeta) return false;\n  if (e.ctrlKey !== wantCtrl) return false;\n  if (e.altKey !== shortcut.alt) return false;\n  if (e.shiftKey !== shortcut.shift) return false;\n  return e.key.toLowerCase() === shortcut.key;\n}\n\n/**\n * Wires all three open-trigger routes (#193) for one `<ChatWidget>` instance:\n *\n * 1. An optional global keyboard shortcut (`shortcut` — from\n *    `display.keyboardShortcut`). No-op when `shortcut` is `false`/undefined:\n *    nothing is attached, so a widget with no configured shortcut has zero\n *    keydown overhead.\n * 2. A delegated `document` click listener for `data-mordn-chat-open` /\n *    `-toggle` / `-close` — always registered (cheap: one listener, a\n *    `closest()` lookup only on click), so docs themes get button support\n *    for free with no shortcut configured.\n * 3. `document` CustomEvent listeners for `mordn-chat:open` / `:close` /\n *    `:toggle` — always registered, the same routes a script-tag embed or\n *    any other non-React trigger dispatches.\n *\n * All three call back into the SAME `open`/`close`/`toggle` the caller\n * passes — see the module docblock for why that matters.\n */\nexport function useOpenTriggers(shortcut: string | false | undefined, actions: OpenTriggerActions): void {\n  const { open, close, toggle } = actions;\n  const parsedShortcut = useMemo(() => parseShortcut(shortcut), [shortcut]);\n\n  // 1. Keyboard shortcut — only attached when configured.\n  useEffect(() => {\n    if (!parsedShortcut) return;\n    if (typeof window === 'undefined') return;\n\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (e.defaultPrevented || e.isComposing || e.repeat || isTypingTarget(e.target)) return;\n      if (!matchesShortcut(e, parsedShortcut)) return;\n      e.preventDefault();\n      toggle('user');\n    };\n\n    window.addEventListener('keydown', handleKeyDown);\n    return () => window.removeEventListener('keydown', handleKeyDown);\n  }, [parsedShortcut, toggle]);\n\n  // 2. Delegated data-attribute click triggers — always registered (zero-config\n  // for docs themes). `closest()` bails out fast when the click didn't land on\n  // (or inside) a matching element, so an unconfigured widget still pays for\n  // exactly one document listener, no per-render cost.\n  useEffect(() => {\n    if (typeof document === 'undefined') return;\n\n    const handleClick = (e: MouseEvent) => {\n      const target = e.target;\n      if (!(target instanceof Element)) return;\n      if (target.closest('[data-mordn-chat-open]')) {\n        open('user');\n      } else if (target.closest('[data-mordn-chat-toggle]')) {\n        toggle('user');\n      } else if (target.closest('[data-mordn-chat-close]')) {\n        close();\n      }\n    };\n\n    document.addEventListener('click', handleClick);\n    return () => document.removeEventListener('click', handleClick);\n  }, [open, close, toggle]);\n\n  // 3. document CustomEvent API — the programmatic equivalent of the\n  // data-attribute buttons; also what a script-tag embed dispatches\n  // internally to talk to a mounted widget.\n  useEffect(() => {\n    if (typeof document === 'undefined') return;\n\n    const handleOpen = () => open('programmatic');\n    const handleClose = () => close();\n    const handleToggle = () => toggle('programmatic');\n\n    document.addEventListener('mordn-chat:open', handleOpen);\n    document.addEventListener('mordn-chat:close', handleClose);\n    document.addEventListener('mordn-chat:toggle', handleToggle);\n    return () => {\n      document.removeEventListener('mordn-chat:open', handleOpen);\n      document.removeEventListener('mordn-chat:close', handleClose);\n      document.removeEventListener('mordn-chat:toggle', handleToggle);\n    };\n  }, [open, close, toggle]);\n}\n","'use client';\n\n/**\n * Hosted runtime mode — the client half.\n *\n * In server mode the browser talks to the host app's own route, which resolves\n * the user from ITS session; the widget sends nothing about identity. In hosted\n * mode there is no host route: the widget talks to api.mordn.com directly, and\n * identity travels as a token the app's identity provider SIGNED (Supabase Auth,\n * Clerk, Auth0, …), which chat-api verifies against the agent's configured JWKS.\n * The browser still never asserts who it is — it can only present a token\n * somebody else signed.\n *\n * This hook turns `getUserToken` into the `Authorization: Bearer …` header the\n * transport sends, keeps it fresh (identity-provider access tokens expire; we\n * re-ask every few minutes, and `refresh()` lets a host force it), and — only when the host\n * opted into anonymous visitors — supplies the `X-Mordn-Visitor` id, a random\n * value persisted in localStorage that isolates one browser profile from\n * another. It is deliberately NOT sent when a token is available.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nexport const HOSTED_BASE_URL = 'https://api.mordn.com';\nexport const VISITOR_HEADER = 'X-Mordn-Visitor';\nconst VISITOR_STORAGE_KEY = 'mordn:visitor';\n/** Re-ask the host for a token this often (access tokens commonly live ~1h). */\nconst TOKEN_REFRESH_MS = 4 * 60 * 1000;\n\nexport type GetUserToken = () => Promise<string | null | undefined> | string | null | undefined;\n\n/** The apiBase for a publishable key: `${base}/v1/hosted/${key}`. */\nexport function hostedApiBase(publishableKey: string, hostedBaseUrl: string = HOSTED_BASE_URL): string {\n  return `${hostedBaseUrl.replace(/\\/+$/, '')}/v1/hosted/${encodeURIComponent(publishableKey.trim())}`;\n}\n\n/** A fresh visitor id: 32 url-safe chars (chat-api accepts 16–64). */\nexport function newVisitorId(): string {\n  const cryptoObj = typeof globalThis.crypto !== 'undefined' ? globalThis.crypto : undefined;\n  if (cryptoObj?.randomUUID) return cryptoObj.randomUUID().replace(/-/g, '');\n  // Fallback for very old runtimes: still random, still url-safe.\n  let out = '';\n  const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-';\n  for (let i = 0; i < 32; i++) out += alphabet[Math.floor(Math.random() * alphabet.length)];\n  return out;\n}\n\n/** Read-or-create the persisted visitor id. Falls back to a per-session id when storage is unavailable. */\nexport function getOrCreateVisitorId(): string {\n  try {\n    const existing = window.localStorage.getItem(VISITOR_STORAGE_KEY);\n    if (existing && /^[A-Za-z0-9_-]{16,64}$/.test(existing)) return existing;\n    const created = newVisitorId();\n    window.localStorage.setItem(VISITOR_STORAGE_KEY, created);\n    return created;\n  } catch {\n    return newVisitorId();\n  }\n}\n\nexport interface HostedAuthState {\n  /** Headers to merge into every request. Empty when off or resolving a new session. */\n  headers: Record<string, string>;\n  /** False until this session's token resolution settles — bootstrap waits for it. */\n  ready: boolean;\n  /** Re-resolve within the SAME session, retaining its headers while pending. */\n  refresh: () => void;\n  /** Discard current auth and re-resolve after login, logout, or account switch. */\n  reset: () => void;\n  /** Local lifecycle boundary for bootstrap; never identity or a storage scope. */\n  session: object;\n}\n\nexport function useHostedAuth(options: {\n  enabled: boolean;\n  getUserToken?: GetUserToken;\n  anonymous?: boolean;\n  /** Change on auth transitions; callback identity deliberately does not trigger resolution. */\n  sessionKey?: string | number | null;\n}): HostedAuthState {\n  const { enabled, getUserToken, anonymous = false, sessionKey } = options;\n  const [tick, setTick] = useState(0);\n  const [resetTick, setResetTick] = useState(0);\n  const hasGetter = !!getUserToken;\n  // A changed boundary hides old headers/ready in the render itself, before\n  // effect cleanup. Adding/removing a getter and disabling are transitions too.\n  const session = useMemo(() => ({}), [enabled, hasGetter, anonymous, sessionKey, resetTick]);\n  const [resolved, setResolved] = useState<{ session: object; token: string | null } | null>(null);\n  const getTokenRef = useRef(getUserToken);\n  getTokenRef.current = getUserToken;\n  const requestRef = useRef(0);\n\n  const refresh = useCallback(() => {\n    // Invalidate immediately, including promises settling before effect cleanup.\n    requestRef.current += 1;\n    setTick((n) => n + 1);\n  }, []);\n  const reset = useCallback(() => {\n    requestRef.current += 1;\n    setResetTick((n) => n + 1);\n  }, []);\n\n  useEffect(() => {\n    if (!enabled || !hasGetter) {\n      setResolved(null);\n      return;\n    }\n    let cancelled = false;\n    const resolve = async () => {\n      // Intervals can overlap. Only the latest STARTED resolution may commit,\n      // including errors; an older success must not resurrect a logged-out user.\n      const request = ++requestRef.current;\n      const current = () => !cancelled && request === requestRef.current;\n      try {\n        const value = await getTokenRef.current?.();\n        if (current()) setResolved({ session, token: typeof value === 'string' && value.trim() ? value.trim() : null });\n      } catch (error) {\n        if (current()) {\n          console.error('[chat-widget] getUserToken threw; continuing without a user token.', error);\n          setResolved({ session, token: null });\n        }\n      }\n    };\n    void resolve();\n    const interval = window.setInterval(resolve, TOKEN_REFRESH_MS);\n    return () => {\n      cancelled = true;\n      window.clearInterval(interval);\n    };\n  }, [enabled, hasGetter, session, tick]);\n\n  const ready = !enabled || !hasGetter || resolved?.session === session;\n  const token = enabled && hasGetter && resolved?.session === session ? resolved.token : null;\n  const visitorId = useMemo(() => (enabled && anonymous ? getOrCreateVisitorId() : null), [enabled, anonymous]);\n\n  const headers = useMemo(() => {\n    const out: Record<string, string> = {};\n    if (!enabled || !ready) return out;\n    if (token) out.Authorization = `Bearer ${token}`;\n    else if (visitorId) out[VISITOR_HEADER] = visitorId;\n    return out;\n  }, [enabled, ready, token, visitorId]);\n\n  return { headers, ready, refresh, reset, session };\n}\n","import * as React from \"react\"\n\nimport { cn } from \"../utils/cn\"\n\nexport interface InputProps\n  extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n  ({ className, type, ...props }, ref) => {\n    return (\n      <input\n        type={type}\n        className={cn(\n          \"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50\",\n          className\n        )}\n        ref={ref}\n        {...props}\n      />\n    )\n  }\n)\nInput.displayName = \"Input\"\n\nexport { Input }\n","\"use client\"\n\nimport * as React from \"react\"\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\"\nimport { XIcon } from \"lucide-react\"\n\nimport { cn } from \"../utils/cn\"\nimport { useChatPortalContainer } from \"../contexts/chat-portal-context\"\n\nfunction Dialog({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n  return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />\n}\n\nfunction DialogTrigger({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n  return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />\n}\n\nfunction DialogPortal({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n  return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />\n}\n\nfunction DialogClose({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n  return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />\n}\n\nfunction DialogOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n  return (\n    <DialogPrimitive.Overlay\n      data-slot=\"dialog-overlay\"\n      className={cn(\n        \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction DialogContent({\n  className,\n  children,\n  showCloseButton = true,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n  showCloseButton?: boolean\n}) {\n  const container = useChatPortalContainer()\n  return (\n    <DialogPortal data-slot=\"dialog-portal\" container={container ?? undefined}>\n      <DialogOverlay />\n      <DialogPrimitive.Content\n        data-slot=\"dialog-content\"\n        className={cn(\n          \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg\",\n          className\n        )}\n        {...props}\n      >\n        {children}\n        {showCloseButton && (\n          <DialogPrimitive.Close\n            data-slot=\"dialog-close\"\n            className=\"ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\"\n          >\n            <XIcon />\n            <span className=\"sr-only\">Close</span>\n          </DialogPrimitive.Close>\n        )}\n      </DialogPrimitive.Content>\n    </DialogPortal>\n  )\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"dialog-header\"\n      className={cn(\"flex flex-col gap-2 text-center sm:text-left\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"dialog-footer\"\n      className={cn(\n        \"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction DialogTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n  return (\n    <DialogPrimitive.Title\n      data-slot=\"dialog-title\"\n      className={cn(\"text-lg leading-none font-semibold\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction DialogDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n  return (\n    <DialogPrimitive.Description\n      data-slot=\"dialog-description\"\n      className={cn(\"text-muted-foreground text-sm\", className)}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Dialog,\n  DialogClose,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogOverlay,\n  DialogPortal,\n  DialogTitle,\n  DialogTrigger,\n}\n","'use client';\n\nimport {\n  Check,\n  CheckCircle2,\n  ChevronLeft,\n  ChevronRight,\n  ExternalLinkIcon,\n  Loader2,\n  ShieldCheck,\n} from 'lucide-react';\nimport { useRef } from 'react';\nimport type { ComponentProps, FormEvent, ReactNode } from 'react';\nimport { safeUrl } from '../utils/url-safety';\nimport { cn } from '../utils/cn';\nimport type {\n  MordnActionConfig,\n  MordnActionDispatcher,\n  MordnActionPrimitiveProps,\n  MordnEntityItem,\n  MordnStatusStep,\n} from '../actions/types';\n\nfunction dispatchAction(\n  onAction: MordnActionDispatcher | undefined,\n  action: MordnActionConfig | undefined,\n  source: string,\n  values?: Record<string, unknown>,\n) {\n  if (!onAction || !action) return;\n  void onAction({ action, source, values });\n}\n\n/**\n * Deterministic hue from a string — gives each entity a stable accent so a\n * card rail reads as a designed set (varied, but anchored to the theme) even\n * when the host supplies no imagery.\n */\nfunction hashHue(seed: string): number {\n  let h = 0;\n  for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) | 0;\n  return ((h % 360) + 360) % 360;\n}\n\nexport interface ActionButtonProps\n  extends Omit<ComponentProps<'button'>, 'onClick'>,\n    MordnActionPrimitiveProps {\n  label?: string;\n  icon?: ReactNode;\n  variant?: 'primary' | 'secondary' | 'ghost';\n}\n\nexport function ActionButton({\n  action,\n  onAction,\n  disabled,\n  loading,\n  label,\n  icon,\n  variant = 'secondary',\n  className,\n  children,\n  ...props\n}: ActionButtonProps) {\n  const text = label ?? action?.label ?? (typeof children === 'string' ? children : action?.type ?? 'Action');\n  return (\n    <button\n      type=\"button\"\n      className={cn(\n        'inline-flex min-h-8 items-center justify-center gap-1.5 rounded-full border px-3.5 py-1.5 text-[12px] font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.4)] active:scale-[0.97] disabled:pointer-events-none disabled:opacity-50',\n        variant === 'primary' &&\n          'border-transparent bg-[hsl(var(--chat-primary))] text-[hsl(var(--chat-background))] hover:brightness-110',\n        variant === 'secondary' &&\n          'border-[hsl(var(--chat-border))] bg-[hsl(var(--chat-background))] text-[hsl(var(--chat-text))] shadow-sm hover:bg-[hsl(var(--chat-hover-bg))]',\n        variant === 'ghost' &&\n          'border-transparent bg-transparent text-[hsl(var(--chat-text-muted))] hover:bg-[hsl(var(--chat-text)/0.06)] hover:text-[hsl(var(--chat-text))]',\n        className,\n      )}\n      disabled={disabled || loading}\n      aria-busy={loading || undefined}\n      onClick={() => dispatchAction(onAction, action, 'action-button')}\n      {...props}\n    >\n      {loading ? <Loader2 className=\"size-3.5 animate-spin\" aria-hidden=\"true\" /> : icon}\n      <span>{children ?? text}</span>\n    </button>\n  );\n}\n\nexport interface ActionChipsProps extends ComponentProps<'div'> {\n  actions: Array<MordnActionConfig & { label: string }>;\n  onAction?: MordnActionDispatcher;\n  disabled?: boolean;\n}\n\nexport function ActionChips({ actions, onAction, disabled, className, ...props }: ActionChipsProps) {\n  if (!actions.length) return null;\n  return (\n    <div className={cn('not-prose flex flex-wrap gap-1.5', className)} {...props}>\n      {actions.map((action) => (\n        <ActionButton\n          key={`${action.type}:${action.label}`}\n          action={action}\n          onAction={onAction}\n          disabled={disabled}\n          variant=\"secondary\"\n        />\n      ))}\n    </div>\n  );\n}\n\nexport interface EntityCardProps extends ComponentProps<'article'> {\n  item: MordnEntityItem;\n  onAction?: MordnActionDispatcher;\n}\n\nexport function EntityCard({ item, onAction, className, style, ...props }: EntityCardProps) {\n  const image = item.imageUrl ? safeUrl(item.imageUrl) : undefined;\n  const hue = hashHue(item.id);\n\n  return (\n    <article\n      className={cn(\n        'chat-card-lift not-prose overflow-hidden rounded-2xl border bg-[hsl(var(--chat-background))]',\n        className,\n      )}\n      style={{ borderColor: 'hsl(var(--chat-border))', boxShadow: 'var(--chat-shadow-sm)', ...style }}\n      {...props}\n    >\n      {/* Media header: the host's image when given, otherwise a generated\n          accent panel (theme-anchored gradient + oversized glyph) so cards\n          never look bare. Badge and price ride on top as glass chips. */}\n      <div\n        className=\"relative h-[5.5rem] w-full overflow-hidden\"\n        style={\n          image\n            ? undefined\n            : {\n                background: `linear-gradient(135deg, hsl(var(--chat-primary) / 0.9), hsl(${hue} 58% 48%))`,\n              }\n        }\n      >\n        {image ? (\n          <img src={image} alt=\"\" className=\"h-full w-full object-cover\" loading=\"lazy\" />\n        ) : (\n          <>\n            <span\n              aria-hidden=\"true\"\n              className=\"pointer-events-none absolute -bottom-4 -right-1 select-none text-[72px] font-black leading-none text-white/[0.18]\"\n            >\n              {item.title.slice(0, 1)}\n            </span>\n            <div\n              aria-hidden=\"true\"\n              className=\"pointer-events-none absolute inset-0\"\n              style={{ background: 'radial-gradient(120% 90% at 0% 0%, rgb(255 255 255 / 0.22), transparent 55%)' }}\n            />\n          </>\n        )}\n        {item.badge && (\n          <span className=\"absolute left-2 top-2 rounded-full bg-black/35 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-white backdrop-blur-sm\">\n            {item.badge}\n          </span>\n        )}\n        {item.price && (\n          <span className=\"absolute bottom-2 right-2 rounded-full bg-white/90 px-2 py-0.5 text-[12px] font-bold text-gray-900 shadow-sm backdrop-blur-sm\">\n            {item.price}\n          </span>\n        )}\n      </div>\n\n      <div className=\"space-y-2.5 p-3\">\n        <div className=\"min-w-0\">\n          <h3 className=\"truncate text-[13px] font-semibold text-[hsl(var(--chat-text))]\">{item.title}</h3>\n          {item.subtitle && (\n            <p className=\"mt-0.5 line-clamp-2 text-[12px] leading-relaxed text-[hsl(var(--chat-text-muted))]\">\n              {item.subtitle}\n            </p>\n          )}\n        </div>\n\n        {item.description && (\n          <div className=\"text-[12px] leading-relaxed text-[hsl(var(--chat-text-muted))]\">{item.description}</div>\n        )}\n\n        {item.attributes && item.attributes.length > 0 && (\n          <dl\n            className=\"divide-y overflow-hidden rounded-xl border\"\n            style={{ borderColor: 'hsl(var(--chat-border) / 0.8)' }}\n          >\n            {item.attributes.map((attr) => (\n              <div\n                key={attr.label}\n                className=\"flex items-baseline justify-between gap-3 px-2.5 py-1.5\"\n                style={{ borderColor: 'hsl(var(--chat-border) / 0.8)' }}\n              >\n                <dt className=\"shrink-0 text-[11px] text-[hsl(var(--chat-text-subtle))]\">{attr.label}</dt>\n                <dd className=\"min-w-0 truncate text-right text-[11.5px] font-medium text-[hsl(var(--chat-text))]\">\n                  {attr.value}\n                </dd>\n              </div>\n            ))}\n          </dl>\n        )}\n\n        {item.actions && item.actions.length > 0 && (\n          <div className=\"flex flex-wrap gap-1.5 pt-0.5\">\n            {item.actions.map((entityAction) => {\n              const safeHref = safeUrl(entityAction.href);\n              if (safeHref) {\n                return (\n                  <a\n                    key={`${entityAction.label}:${safeHref}`}\n                    href={safeHref}\n                    target=\"_blank\"\n                    rel=\"noopener noreferrer\"\n                    className=\"inline-flex min-h-8 items-center gap-1.5 rounded-full border px-3.5 py-1.5 text-[12px] font-medium text-[hsl(var(--chat-text))] shadow-sm transition-colors hover:bg-[hsl(var(--chat-hover-bg))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.4)]\"\n                    style={{ borderColor: 'hsl(var(--chat-border))' }}\n                  >\n                    {entityAction.label}\n                    <ExternalLinkIcon className=\"size-3\" aria-hidden=\"true\" />\n                  </a>\n                );\n              }\n              return (\n                <ActionButton\n                  key={`${entityAction.label}:${entityAction.action?.type ?? 'action'}`}\n                  label={entityAction.label}\n                  action={entityAction.action}\n                  onAction={onAction}\n                  variant={entityAction.variant === 'primary' ? 'primary' : entityAction.variant === 'ghost' ? 'ghost' : 'secondary'}\n                />\n              );\n            })}\n          </div>\n        )}\n      </div>\n    </article>\n  );\n}\n\nexport interface EntityCarouselProps extends ComponentProps<'div'> {\n  items: MordnEntityItem[];\n  onAction?: MordnActionDispatcher;\n  label?: string;\n}\n\nexport function EntityCarousel({ items, onAction, label, className, ...props }: EntityCarouselProps) {\n  const scrollerRef = useRef<HTMLDivElement>(null);\n  if (!items.length) return null;\n\n  const scrollByCard = (direction: -1 | 1) => {\n    scrollerRef.current?.scrollBy({ left: direction * 276, behavior: 'smooth' });\n  };\n\n  return (\n    <section className={cn('not-prose space-y-2', className)} aria-label={label} {...props}>\n      {(label || items.length > 1) && (\n        <div className=\"flex items-center justify-between gap-2\">\n          {label && <h3 className=\"text-[12px] font-semibold text-[hsl(var(--chat-text))]\">{label}</h3>}\n          {items.length > 1 && (\n            <div className=\"flex gap-1\">\n              <button\n                type=\"button\"\n                aria-label=\"Scroll back\"\n                onClick={() => scrollByCard(-1)}\n                className=\"flex size-6 items-center justify-center rounded-full border text-[hsl(var(--chat-text-muted))] transition-colors hover:bg-[hsl(var(--chat-hover-bg))] hover:text-[hsl(var(--chat-text))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.4)]\"\n                style={{ borderColor: 'hsl(var(--chat-border))' }}\n              >\n                <ChevronLeft className=\"size-3.5\" aria-hidden=\"true\" />\n              </button>\n              <button\n                type=\"button\"\n                aria-label=\"Scroll forward\"\n                onClick={() => scrollByCard(1)}\n                className=\"flex size-6 items-center justify-center rounded-full border text-[hsl(var(--chat-text-muted))] transition-colors hover:bg-[hsl(var(--chat-hover-bg))] hover:text-[hsl(var(--chat-text))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.4)]\"\n                style={{ borderColor: 'hsl(var(--chat-border))' }}\n              >\n                <ChevronRight className=\"size-3.5\" aria-hidden=\"true\" />\n              </button>\n            </div>\n          )}\n        </div>\n      )}\n      <div ref={scrollerRef} className=\"chat-carousel flex snap-x snap-mandatory gap-2.5 overflow-x-auto pb-1 pr-8\">\n        {items.map((item, index) => (\n          <EntityCard\n            key={item.id}\n            item={item}\n            onAction={onAction}\n            className=\"chat-card-in w-[16.5rem] shrink-0 snap-start\"\n            style={{ animationDelay: `${Math.min(index, 5) * 70}ms` }}\n          />\n        ))}\n      </div>\n    </section>\n  );\n}\n\nexport interface ActionFormField {\n  name: string;\n  label: string;\n  type?: 'text' | 'email' | 'tel' | 'date' | 'time' | 'number' | 'textarea';\n  required?: boolean;\n  placeholder?: string;\n  defaultValue?: string;\n}\n\nexport interface ActionFormProps extends Omit<ComponentProps<'form'>, 'action' | 'onSubmit'> {\n  title?: string;\n  description?: string;\n  fields: ActionFormField[];\n  submitLabel?: string;\n  action: MordnActionConfig;\n  onAction?: MordnActionDispatcher;\n}\n\nexport function ActionForm({\n  title,\n  description,\n  fields,\n  submitLabel = 'Submit',\n  action,\n  onAction,\n  className,\n  ...props\n}: ActionFormProps) {\n  function onSubmit(event: FormEvent<HTMLFormElement>) {\n    event.preventDefault();\n    const formData = new FormData(event.currentTarget);\n    const values = Object.fromEntries(formData.entries());\n    dispatchAction(onAction, action, 'action-form', values);\n  }\n\n  return (\n    <form\n      className={cn(\n        'chat-card-in not-prose space-y-3 rounded-2xl border bg-[hsl(var(--chat-background))] p-3.5',\n        className,\n      )}\n      style={{ borderColor: 'hsl(var(--chat-border))', boxShadow: 'var(--chat-shadow-sm)' }}\n      onSubmit={onSubmit}\n      {...props}\n    >\n      {(title || description) && (\n        <div className=\"space-y-1\">\n          {title && <h3 className=\"text-[13px] font-semibold text-[hsl(var(--chat-text))]\">{title}</h3>}\n          {description && <p className=\"text-[12px] leading-relaxed text-[hsl(var(--chat-text-muted))]\">{description}</p>}\n        </div>\n      )}\n      <div className=\"grid gap-2.5\">\n        {fields.map((field) => {\n          const common = {\n            id: field.name,\n            name: field.name,\n            required: field.required,\n            placeholder: field.placeholder,\n            defaultValue: field.defaultValue,\n            className:\n              'min-h-9 rounded-xl border bg-[hsl(var(--chat-surface))] px-3 py-1.5 text-[13px] text-[hsl(var(--chat-text))] placeholder:text-[hsl(var(--chat-text-subtle))] transition-shadow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.35)]',\n            style: { borderColor: 'hsl(var(--chat-border))' },\n          };\n          return (\n            <label key={field.name} className=\"grid gap-1 text-[12px] font-medium text-[hsl(var(--chat-text))]\" htmlFor={field.name}>\n              {field.label}\n              {field.type === 'textarea' ? <textarea {...common} rows={3} /> : <input {...common} type={field.type ?? 'text'} />}\n            </label>\n          );\n        })}\n      </div>\n      <ActionButton action={action} onAction={undefined} variant=\"primary\" type=\"submit\" label={submitLabel}>\n        {submitLabel}\n      </ActionButton>\n    </form>\n  );\n}\n\nexport interface SummaryCardProps extends ComponentProps<'section'> {\n  title: string;\n  description?: ReactNode;\n  rows?: Array<{ label: string; value: ReactNode }>;\n  action?: MordnActionConfig;\n  onAction?: MordnActionDispatcher;\n  actionLabel?: string;\n}\n\n/**\n * Receipt-style summary. Rows render as a hairline-divided ledger; a row whose\n * label reads like a grand total (\"Total\", \"Total due\"…) is automatically\n * emphasised so the number that matters is the one you see first.\n */\nexport function SummaryCard({ title, description, rows, action, onAction, actionLabel, className, ...props }: SummaryCardProps) {\n  return (\n    <section\n      className={cn('chat-card-in not-prose overflow-hidden rounded-2xl border bg-[hsl(var(--chat-background))]', className)}\n      style={{ borderColor: 'hsl(var(--chat-border))', boxShadow: 'var(--chat-shadow-sm)' }}\n      {...props}\n    >\n      <div className=\"flex items-start gap-2.5 p-3\">\n        <span\n          className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full\"\n          style={{ backgroundColor: 'hsl(var(--chat-primary) / 0.12)' }}\n          aria-hidden=\"true\"\n        >\n          <CheckCircle2 className=\"size-4\" style={{ color: 'hsl(var(--chat-primary))' }} strokeWidth={2.2} />\n        </span>\n        <div className=\"min-w-0 flex-1\">\n          <h3 className=\"text-[13px] font-semibold text-[hsl(var(--chat-text))]\">{title}</h3>\n          {description && <div className=\"mt-0.5 text-[12px] leading-relaxed text-[hsl(var(--chat-text-muted))]\">{description}</div>}\n        </div>\n      </div>\n\n      {rows && rows.length > 0 && (\n        <dl\n          className=\"mx-3 mb-3 divide-y overflow-hidden rounded-xl border\"\n          style={{ borderColor: 'hsl(var(--chat-border) / 0.8)' }}\n        >\n          {rows.map((row) => {\n            const isTotal = typeof row.label === 'string' && /^total\\b/i.test(row.label);\n            return (\n              <div\n                key={row.label}\n                className={cn('flex items-baseline justify-between gap-3 px-2.5', isTotal ? 'py-2' : 'py-1.5')}\n                style={{\n                  borderColor: 'hsl(var(--chat-border) / 0.8)',\n                  backgroundColor: isTotal ? 'hsl(var(--chat-primary) / 0.06)' : undefined,\n                }}\n              >\n                <dt className={cn('shrink-0 text-[11px]', isTotal ? 'font-semibold text-[hsl(var(--chat-text))]' : 'text-[hsl(var(--chat-text-subtle))]')}>\n                  {row.label}\n                </dt>\n                <dd className={cn('min-w-0 truncate text-right font-medium text-[hsl(var(--chat-text))]', isTotal ? 'text-[13px] font-bold' : 'text-[11.5px]')}>\n                  {row.value}\n                </dd>\n              </div>\n            );\n          })}\n        </dl>\n      )}\n\n      {action && (\n        <div className=\"px-3 pb-3\">\n          <ActionButton action={action} onAction={onAction} variant=\"primary\" label={actionLabel ?? action.label} />\n        </div>\n      )}\n    </section>\n  );\n}\n\nexport interface ConfirmationCardProps extends ComponentProps<'section'> {\n  title: string;\n  description?: ReactNode;\n  action: MordnActionConfig;\n  onAction?: MordnActionDispatcher;\n  confirmLabel?: string;\n  cancelLabel?: string;\n  onCancel?: () => void;\n}\n\nexport function ConfirmationCard({\n  title,\n  description,\n  action,\n  onAction,\n  confirmLabel = 'Confirm',\n  cancelLabel = 'Cancel',\n  onCancel,\n  className,\n  ...props\n}: ConfirmationCardProps) {\n  return (\n    <section\n      className={cn('chat-card-in not-prose rounded-2xl border bg-[hsl(var(--chat-background))] p-3.5', className)}\n      style={{ borderColor: 'hsl(var(--chat-border))', boxShadow: 'var(--chat-shadow-sm)' }}\n      {...props}\n    >\n      <div className=\"flex gap-2.5\">\n        <span\n          className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full\"\n          style={{ backgroundColor: 'hsl(var(--chat-primary) / 0.12)' }}\n          aria-hidden=\"true\"\n        >\n          <ShieldCheck className=\"size-4\" style={{ color: 'hsl(var(--chat-primary))' }} strokeWidth={2.2} />\n        </span>\n        <div className=\"min-w-0 flex-1 space-y-3\">\n          <div>\n            <h3 className=\"text-[13px] font-semibold text-[hsl(var(--chat-text))]\">{title}</h3>\n            {description && <div className=\"mt-1 text-[12px] leading-relaxed text-[hsl(var(--chat-text-muted))]\">{description}</div>}\n          </div>\n          <div className=\"flex flex-wrap gap-1.5\">\n            <ActionButton action={action} onAction={onAction} variant=\"primary\" label={confirmLabel}>\n              {confirmLabel}\n            </ActionButton>\n            <button\n              type=\"button\"\n              onClick={onCancel}\n              className=\"inline-flex min-h-8 items-center justify-center rounded-full border px-3.5 py-1.5 text-[12px] font-medium text-[hsl(var(--chat-text-muted))] transition-colors hover:bg-[hsl(var(--chat-hover-bg))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.4)]\"\n              style={{ borderColor: 'hsl(var(--chat-border))' }}\n            >\n              {cancelLabel}\n            </button>\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n}\n\nexport interface StatusTrackerProps extends ComponentProps<'ol'> {\n  steps: MordnStatusStep[];\n}\n\n/**\n * Vertical timeline: success-filled markers for completed steps, a compact\n * spinner on the current one, and a quiet connecting rail for at-a-glance progress.\n */\nexport function StatusTracker({ steps, className, ...props }: StatusTrackerProps) {\n  return (\n    <ol\n      className={cn('chat-card-in not-prose rounded-[10px] border bg-[hsl(var(--chat-background))] p-3.5', className)}\n      style={{ borderColor: 'hsl(var(--chat-border-soft))' }}\n      {...props}\n    >\n      {steps.map((step, index) => {\n        const isLast = index === steps.length - 1;\n        const status = step.status ?? 'pending';\n        const statusLabel =\n          status === 'complete'\n            ? 'Completed'\n            : status === 'current'\n              ? 'In progress'\n              : status === 'error'\n                ? 'Error'\n                : 'Pending';\n        return (\n          <li key={step.id} className=\"flex gap-2.5\">\n            {/* Marker + connecting rail */}\n            <span className=\"flex flex-col items-center\" aria-hidden=\"true\">\n              <span\n                className={cn(\n                  'mt-0.5 flex size-3.5 shrink-0 items-center justify-center rounded-full border',\n                )}\n                style={\n                  status === 'complete'\n                    ? { backgroundColor: 'hsl(var(--chat-success))', borderColor: 'hsl(var(--chat-success))' }\n                    : status === 'current'\n                      ? { borderColor: 'hsl(var(--chat-text-faint))', borderWidth: 1.5 }\n                      : status === 'error'\n                        ? { borderColor: 'hsl(var(--chat-danger))', borderWidth: 1.5 }\n                        : { borderColor: 'hsl(var(--chat-border-soft))', borderWidth: 1.5 }\n                }\n              >\n                {status === 'complete' && (\n                  <Check className=\"size-2.5\" style={{ color: 'hsl(var(--chat-background))' }} strokeWidth={3} />\n                )}\n                {status === 'current' && (\n                  <Loader2 className=\"size-2.5 animate-spin text-[hsl(var(--chat-text-faint))]\" />\n                )}\n                {status === 'error' && (\n                  <span className=\"size-1.5 rounded-full\" style={{ backgroundColor: 'hsl(var(--chat-danger))' }} />\n                )}\n              </span>\n              {!isLast && (\n                <span\n                  className=\"w-px flex-1\"\n                  style={{\n                    minHeight: '0.875rem',\n                    backgroundColor:\n                      status === 'complete' ? 'hsl(var(--chat-success) / 0.45)' : 'hsl(var(--chat-border-soft))',\n                  }}\n                />\n              )}\n            </span>\n\n            <span className={cn('min-w-0', !isLast && 'pb-3')}>\n              <span\n                className={cn(\n                  'block text-[13px]',\n                  status === 'current' ? 'font-medium text-[hsl(var(--chat-text))]' : 'font-normal',\n                  status === 'pending' && 'text-[hsl(var(--chat-text-faint))]',\n                  status === 'complete' && 'line-through text-[hsl(var(--chat-text-faint))]',\n                  status === 'error' && 'text-[hsl(var(--chat-danger))]',\n                )}\n              >\n                <span className=\"sr-only\">{statusLabel}: </span>\n                {step.label}\n              </span>\n              {step.description && (\n                <span className=\"block text-[11.5px] text-[hsl(var(--chat-text-faint))]\">{step.description}</span>\n              )}\n            </span>\n          </li>\n        );\n      })}\n    </ol>\n  );\n}\n","import type { MordnTemplateManifest } from './types';\n\nexport const docsAssistantTemplate: MordnTemplateManifest = {\n  id: 'docs-assistant',\n  name: 'Docs Assistant',\n  vertical: 'docs',\n  version: '0.1.0',\n  minWidgetVersion: '0.12.0',\n  description: 'Answer documentation questions with citations, page-aware prompts, gap capture, and setup guidance.',\n  starterPrompts: [\n    { title: 'How do I get started?', subtitle: 'Show the setup path for this product' },\n    { title: 'Ask about this page', subtitle: 'Use the current docs page as context' },\n    { title: 'Show related guides', subtitle: 'Find the next docs pages I should read' },\n  ],\n  promptFragment:\n    'You are a docs assistant. Prefer grounded answers with section citations, be honest when retrieval is weak, and offer setup-oriented next actions.',\n  recommendedKnowledge: ['llms.txt', 'sitemap.xml', 'docs markdown', 'OpenAPI references'],\n  cards: [\n    { type: 'summary-card', label: 'Setup checklist', description: 'Show the user the ordered setup steps and progress.' },\n    { type: 'handoff-card', label: 'Open docs page', description: 'Link the user to the exact cited documentation page.' },\n  ],\n  actions: [\n    {\n      type: 'docs.page.open',\n      label: 'Open docs page',\n      description: 'Open a cited documentation page or anchor.',\n      handler: 'client',\n      risk: 'ui',\n      confirmation: 'none',\n      schema: {\n        type: 'object',\n        required: ['href'],\n        additionalProperties: false,\n        properties: {\n          href: { type: 'string', format: 'uri', title: 'URL' },\n          title: { type: 'string', title: 'Title' },\n        },\n      },\n    },\n    {\n      type: 'docs.question.report_gap',\n      label: 'Report unanswered question',\n      description: 'Capture a docs question that retrieval could not answer confidently.',\n      handler: 'server',\n      risk: 'capture',\n      confirmation: 'none',\n      schema: {\n        type: 'object',\n        required: ['question'],\n        additionalProperties: false,\n        properties: {\n          question: { type: 'string', title: 'Question' },\n          pageUrl: { type: 'string', format: 'uri', title: 'Page URL' },\n        },\n      },\n    },\n  ],\n};\n\nexport const leadCaptureTemplate: MordnTemplateManifest = {\n  id: 'lead-capture',\n  name: 'Lead Capture Assistant',\n  vertical: 'lead-capture',\n  version: '0.1.0',\n  minWidgetVersion: '0.12.0',\n  description: 'Qualify visitors, collect contact details, summarize intent, and hand the lead to the developer’s CRM or webhook.',\n  starterPrompts: [\n    { title: 'Help me choose a plan', subtitle: 'Qualify needs and suggest next steps' },\n    { title: 'Book a demo', subtitle: 'Collect the details sales needs' },\n    { title: 'Talk to someone', subtitle: 'Capture a follow-up request' },\n  ],\n  promptFragment:\n    'You are a concise lead qualification assistant. Ask only for what is needed, summarize before submitting, and never invent availability or pricing promises.',\n  recommendedKnowledge: ['pricing page', 'product overview', 'case studies', 'FAQ', 'sales qualification criteria'],\n  cards: [\n    { type: 'selection-group', label: 'Qualification chips', description: 'Let visitors choose role, use case, timeline, and company size.' },\n    { type: 'action-form', label: 'Lead form', description: 'Collect name, email, company, and message.' },\n    { type: 'summary-card', label: 'Lead summary', description: 'Review the captured lead before submission.' },\n    { type: 'handoff-card', label: 'Sales handoff', description: 'Show what happens next after submission.' },\n  ],\n  actions: [\n    {\n      type: 'lead.capture',\n      label: 'Capture lead',\n      description: 'Submit a qualified lead to the host application or hosted webhook.',\n      handler: 'server',\n      risk: 'capture',\n      confirmation: 'required',\n      schema: {\n        type: 'object',\n        required: ['email', 'message'],\n        additionalProperties: false,\n        properties: {\n          name: { type: 'string', title: 'Name' },\n          email: { type: 'string', format: 'email', title: 'Email', redact: true },\n          company: { type: 'string', title: 'Company' },\n          timeline: { type: 'string', title: 'Timeline' },\n          message: { type: 'string', title: 'Message' },\n        },\n      },\n    },\n  ],\n};\n\nexport const servicesBookingTemplate: MordnTemplateManifest = {\n  id: 'services-booking',\n  name: 'Services Booking Assistant',\n  vertical: 'services-booking',\n  version: '0.1.0',\n  minWidgetVersion: '0.12.0',\n  description: 'Help visitors choose a service, provide intake details, and request an appointment without pretending to own live calendar inventory.',\n  starterPrompts: [\n    { title: 'Find the right service', subtitle: 'Compare services and what they include' },\n    { title: 'Request an appointment', subtitle: 'Share preferred times and contact details' },\n    { title: 'Get a rough estimate', subtitle: 'Answer a few questions first' },\n  ],\n  promptFragment:\n    'You are a service booking assistant. Help the visitor choose a service, collect intake details, and submit a request-to-book unless a real availability action confirms a slot.',\n  recommendedKnowledge: ['services page', 'availability policy', 'pricing guide', 'intake FAQ'],\n  cards: [\n    { type: 'entity-card', label: 'Service card', description: 'Describe a service, duration, price range, and fit.' },\n    { type: 'action-form', label: 'Appointment request form', description: 'Collect preferred time, contact details, and intake notes.' },\n    { type: 'summary-card', label: 'Booking request summary', description: 'Review the request before submission.' },\n    { type: 'status-tracker', label: 'Request status', description: 'Show requested, received, confirmed, or needs follow-up.' },\n  ],\n  actions: [\n    {\n      type: 'services.booking.request',\n      label: 'Request appointment',\n      description: 'Send a request-to-book payload to the host application or hosted webhook.',\n      handler: 'server',\n      risk: 'capture',\n      confirmation: 'required',\n      schema: {\n        type: 'object',\n        required: ['service', 'contact'],\n        additionalProperties: false,\n        properties: {\n          service: { type: 'string', title: 'Service' },\n          preferredTime: { type: 'string', title: 'Preferred time' },\n          contact: { type: 'string', title: 'Contact', redact: true },\n          notes: { type: 'string', title: 'Notes' },\n        },\n      },\n    },\n  ],\n  notes: ['Default template submits a request, not a confirmed booking. Only show confirmed language when the action result says confirmed.'],\n};\n\nexport const restaurantAssistantTemplate: MordnTemplateManifest = {\n  id: 'restaurant-assistant',\n  name: 'Restaurant Assistant',\n  vertical: 'restaurant',\n  version: '0.1.0',\n  minWidgetVersion: '0.12.0',\n  description: 'Answer menu questions, recommend dishes, capture dietary needs, and start reservation or catering requests.',\n  starterPrompts: [\n    { title: 'Recommend something', subtitle: 'Ask for preferences and dietary needs' },\n    { title: 'Can I reserve a table?', subtitle: 'Start a request-to-book flow' },\n    { title: 'Do you have vegan options?', subtitle: 'Search menu and allergen info' },\n  ],\n  promptFragment:\n    'You are a restaurant concierge. Be specific about menu facts, ask about dietary restrictions, and use request-to-book language unless a configured action returns a confirmed reservation.',\n  recommendedKnowledge: ['menu', 'hours', 'allergen guide', 'reservation policy', 'private dining page'],\n  cards: [\n    { type: 'entity-card', label: 'Menu item card', description: 'Show dish, price, dietary badges, and action buttons.' },\n    { type: 'entity-carousel', label: 'Recommendations', description: 'Compare recommended dishes.' },\n    { type: 'action-form', label: 'Reservation request', description: 'Collect party size, date, time, and contact.' },\n  ],\n  actions: [\n    {\n      type: 'restaurant.reservation.request',\n      label: 'Request reservation',\n      description: 'Submit a reservation request or hand off to the restaurant booking system.',\n      handler: 'server',\n      risk: 'capture',\n      confirmation: 'required',\n    },\n    {\n      type: 'restaurant.external.open_ordering',\n      label: 'Open ordering',\n      description: 'Open the restaurant’s existing ordering link.',\n      handler: 'client',\n      risk: 'ui',\n      confirmation: 'none',\n    },\n  ],\n};\n\nexport const ecommerceConciergeTemplate: MordnTemplateManifest = {\n  id: 'ecommerce-concierge',\n  name: 'Ecommerce Concierge',\n  vertical: 'ecommerce',\n  version: '0.1.0',\n  minWidgetVersion: '0.12.0',\n  description: 'Help shoppers find, compare, and choose products with client-owned cart and checkout handoff.',\n  starterPrompts: [\n    { title: 'Help me choose', subtitle: 'Compare products for my needs' },\n    { title: 'Find gifts under a budget', subtitle: 'Search by intent and price' },\n    { title: 'Where is my order?', subtitle: 'Start an order lookup flow' },\n  ],\n  promptFragment:\n    'You are a shopping concierge. Recommend from real catalog data, show tradeoffs, and hand cart or checkout mutations to the host storefront unless a server action is configured.',\n  recommendedKnowledge: ['catalog feed', 'shipping policy', 'returns policy', 'warranty information'],\n  cards: [\n    { type: 'entity-card', label: 'Product card', description: 'Show product image, price, badges, attributes, and action buttons.' },\n    { type: 'selection-group', label: 'Variant selector', description: 'Choose size, color, plan, or bundle.' },\n    { type: 'summary-card', label: 'Cart summary', description: 'Review selected items before checkout handoff.' },\n  ],\n  actions: [\n    { type: 'ecommerce.cart.add', label: 'Add to cart', description: 'Ask the host storefront to add a product variant to cart.', handler: 'client', risk: 'mutation', confirmation: 'recommended' },\n    { type: 'ecommerce.checkout.open', label: 'Open checkout', description: 'Open the host storefront checkout.', handler: 'client', risk: 'ui', confirmation: 'none' },\n    { type: 'ecommerce.order.lookup', label: 'Look up order', description: 'Fetch order status from a server-side handler.', handler: 'server', risk: 'read', confirmation: 'none' },\n  ],\n};\n\nexport const travelPlannerTemplate: MordnTemplateManifest = {\n  id: 'travel-planner',\n  name: 'Travel Planner',\n  vertical: 'travel',\n  version: '0.1.0',\n  minWidgetVersion: '0.12.0',\n  description: 'Plan trips, compare destinations or stays, build itineraries, and request quotes without owning live inventory by default.',\n  starterPrompts: [\n    { title: 'Plan a weekend trip', subtitle: 'Build an itinerary from preferences' },\n    { title: 'Compare hotels', subtitle: 'Show options with tradeoffs' },\n    { title: 'Request a quote', subtitle: 'Capture dates, guests, and preferences' },\n  ],\n  promptFragment:\n    'You are a travel planning assistant. Treat live prices and inventory as unavailable unless a configured action returns them, and prefer quote or handoff flows by default.',\n  recommendedKnowledge: ['destination guides', 'packages', 'hotel inventory export', 'travel policy', 'FAQ'],\n  cards: [\n    { type: 'entity-card', label: 'Destination or hotel card', description: 'Show image, price range, location, amenities, and actions.' },\n    { type: 'status-tracker', label: 'Itinerary timeline', description: 'Show trip stages and selected activities.' },\n    { type: 'summary-card', label: 'Trip summary', description: 'Review trip preferences before quote request.' },\n  ],\n  actions: [\n    { type: 'travel.quote.request', label: 'Request quote', description: 'Send the trip request to the host application or agency webhook.', handler: 'server', risk: 'capture', confirmation: 'required' },\n    { type: 'travel.booking.open', label: 'Open booking', description: 'Hand off to the configured booking page.', handler: 'client', risk: 'ui', confirmation: 'none' },\n  ],\n};\n\nexport const defaultMordnTemplates: MordnTemplateManifest[] = [\n  docsAssistantTemplate,\n  leadCaptureTemplate,\n  servicesBookingTemplate,\n  restaurantAssistantTemplate,\n  ecommerceConciergeTemplate,\n  travelPlannerTemplate,\n];\n\nexport function getMordnTemplate(id: string): MordnTemplateManifest | undefined {\n  return defaultMordnTemplates.find((template) => template.id === id);\n}\n","\"use client\";\n\nimport {\n  Collapsible,\n  CollapsibleContent,\n  CollapsibleTrigger,\n} from \"../ui/collapsible\";\nimport { cn } from \"../utils/cn\";\nimport type { ToolUIPart } from \"ai\";\nimport {\n  CheckIcon,\n  ChevronDownIcon,\n  ClockIcon,\n  Loader2Icon,\n  XIcon,\n} from \"lucide-react\";\nimport type { ComponentProps, ReactElement, ReactNode } from \"react\";\nimport { isValidElement } from \"react\";\nimport { CodeBlock } from \"./code-block\";\n\nexport type ToolProps = ComponentProps<typeof Collapsible>;\n\nexport const Tool = ({ className, ...props }: ToolProps) => (\n  <Collapsible\n    // `group` is required so the ToolHeader chevron's\n    // `group-data-[state=open]:rotate-180` resolves against this collapsible\n    // root — without it the expand/collapse caret never rotated.\n    className={cn(\"group not-prose w-full\", className)}\n    {...props}\n  />\n);\n\nexport type ToolHeaderProps = {\n  title?: string;\n  type: ToolUIPart[\"type\"] | \"dynamic-tool\";\n  /**\n   * Set when the part is a `dynamic-tool` UIPart (MCP / `dynamicTool()`).\n   * For these the `type` is always `\"dynamic-tool\"`, so the actual tool\n   * identity lives in `toolName`. When provided, it wins over the parsed\n   * type fragment so the header shows e.g. `get_financials` instead of\n   * the generic `tool`.\n   */\n  toolName?: string;\n  state: ToolUIPart[\"state\"];\n  className?: string;\n};\n\n// AI SDK v6 added approval-requested / approval-responded / output-denied\n// to the tool state union. Compact status glyphs keep the exported primitive in\n// the same visual language as AgentToolCall — no bordered card, wrench, or badge.\nconst STATUS_LABELS: Record<ToolUIPart[\"state\"], string> = {\n  \"input-streaming\": \"Pending\",\n  \"input-available\": \"Running\",\n  \"output-available\": \"Completed\",\n  \"output-error\": \"Error\",\n  \"approval-requested\": \"Awaiting approval\",\n  \"approval-responded\": \"Approved\",\n  \"output-denied\": \"Denied\",\n};\n\nconst STATUS_ICONS: Record<ToolUIPart[\"state\"], ReactElement> = {\n  \"input-streaming\": <Loader2Icon aria-hidden=\"true\" className=\"size-3 animate-spin text-[hsl(var(--chat-text-faint))]\" />,\n  \"input-available\": <Loader2Icon aria-hidden=\"true\" className=\"size-3 animate-spin text-[hsl(var(--chat-text-faint))]\" />,\n  \"output-available\": <CheckIcon aria-hidden=\"true\" className=\"size-3 text-[hsl(var(--chat-success))]\" strokeWidth={2.5} />,\n  \"output-error\": <XIcon aria-hidden=\"true\" className=\"size-3 text-[hsl(var(--chat-danger))]\" strokeWidth={2.5} />,\n  \"approval-requested\": <ClockIcon aria-hidden=\"true\" className=\"size-3 text-[hsl(var(--chat-warning))]\" />,\n  \"approval-responded\": <CheckIcon aria-hidden=\"true\" className=\"size-3 text-[hsl(var(--chat-warning))]\" strokeWidth={2.5} />,\n  \"output-denied\": <XIcon aria-hidden=\"true\" className=\"size-3 text-[hsl(var(--chat-text-faint))]\" strokeWidth={2.5} />,\n};\n\nexport const ToolHeader = ({\n  className,\n  title,\n  type,\n  toolName,\n  state,\n  ...props\n}: ToolHeaderProps) => (\n  <CollapsibleTrigger\n    className={cn(\n      \"flex w-full items-center gap-2 rounded-md px-2 py-1 text-left transition-colors hover:bg-[hsl(var(--chat-hover-bg))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--chat-primary)/0.28)]\",\n      className\n    )}\n    {...props}\n  >\n    {STATUS_ICONS[state]}\n    <span className=\"sr-only\">{STATUS_LABELS[state]}: </span>\n    <span className=\"min-w-0 flex-1 truncate text-[12.5px] font-semibold text-[hsl(var(--chat-text-muted))]\">\n      {title ?? toolName ?? type.split(\"-\").slice(1).join(\"-\")}\n    </span>\n    <ChevronDownIcon aria-hidden=\"true\" className=\"size-2.5 text-[hsl(var(--chat-text-subtle))] transition-transform duration-150 group-data-[state=open]:rotate-180\" />\n  </CollapsibleTrigger>\n);\n\nexport type ToolContentProps = ComponentProps<typeof CollapsibleContent>;\n\nexport const ToolContent = ({ className, ...props }: ToolContentProps) => (\n  <CollapsibleContent\n    className={cn(\n      \"ml-2 border-l border-[hsl(var(--chat-border-soft))] pl-3 data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-popover-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in\",\n      className\n    )}\n    {...props}\n  />\n);\n\nexport type ToolInputProps = ComponentProps<\"div\"> & {\n  input: ToolUIPart[\"input\"];\n};\n\nexport const ToolInput = ({ className, input, ...props }: ToolInputProps) => (\n  <div className={cn(\"space-y-2 overflow-hidden p-2\", className)} {...props}>\n    <h4 className=\"font-medium text-muted-foreground text-xs uppercase tracking-wide\">\n      Parameters\n    </h4>\n    <div className=\"rounded-md bg-muted/50\">\n      <CodeBlock code={JSON.stringify(input, null, 2)} language=\"json\" />\n    </div>\n  </div>\n);\n\nexport type ToolOutputProps = ComponentProps<\"div\"> & {\n  output: ToolUIPart[\"output\"];\n  errorText: ToolUIPart[\"errorText\"];\n};\n\nexport const ToolOutput = ({\n  className,\n  output,\n  errorText,\n  ...props\n}: ToolOutputProps) => {\n  if (!(output || errorText)) {\n    return null;\n  }\n\n  let Output = <div>{output as ReactNode}</div>;\n\n  if (typeof output === \"object\" && !isValidElement(output)) {\n    Output = (\n      <CodeBlock code={JSON.stringify(output, null, 2)} language=\"json\" />\n    );\n  } else if (typeof output === \"string\") {\n    Output = <CodeBlock code={output} language=\"json\" />;\n  }\n\n  return (\n    <div className={cn(\"space-y-2 p-2\", className)} {...props}>\n      <h4 className=\"font-medium text-muted-foreground text-xs uppercase tracking-wide\">\n        {errorText ? \"Error\" : \"Result\"}\n      </h4>\n      <div\n        className={cn(\n          \"overflow-x-auto rounded-md text-xs [&_table]:w-full\",\n          errorText\n            ? \"bg-destructive/10 text-destructive\"\n            : \"bg-muted/50 text-foreground\"\n        )}\n      >\n        {errorText && <div>{errorText}</div>}\n        {Output}\n      </div>\n    </div>\n  );\n};\n","'use client';\n\n/**\n * chartToolRenderer — Seam B helper (PRD §2, §8). Builds a ToolRenderer that\n * maps a tool's real output to a ChartSpec and renders a ChartBlock. The MORE\n * trusted path: numbers from the host's system, not the model's prose, so the\n * provenance line reads \"Source: ...\" not \"Model-generated\".\n *\n * Only renders on `output-available`; returns null for pending/streaming so the\n * default tool row (with its pending shimmer) shows until the result lands.\n */\nimport type { ReactNode } from 'react';\nimport { ChartBlock, ChartErrorCard } from './chart-block';\nimport { validateChartSpec, type ChartSpec } from './chart-spec';\nimport type { ToolPartLike, ToolRenderer } from '../types';\n\nexport function chartToolRenderer(\n  toolName: string,\n  map: (output: unknown) => ChartSpec,\n): ToolRenderer {\n  return (part: ToolPartLike): ReactNode | null => {\n    if (part.state !== 'output-available') return null;\n    let spec: ChartSpec;\n    try {\n      spec = validateChartSpec(map(part.output));\n    } catch (err) {\n      const message = err instanceof Error ? err.message : String(err);\n      return (\n        <ChartErrorCard\n          error={`The ${toolName} tool returned data that did not map to a valid chart: ${message}`}\n          rawText={safeStringify(part.output)}\n        />\n      );\n    }\n    return <ChartBlock spec={spec} />;\n  };\n}\n\nfunction safeStringify(value: unknown): string {\n  try {\n    return typeof value === 'string' ? value : JSON.stringify(value, null, 2);\n  } catch {\n    return String(value);\n  }\n}\n","import type { ThemeConfig } from './types';\n\nexport interface ThemePreset extends ThemeConfig {\n  /** Display name shown in the playground preset picker. */\n  name: string;\n}\n\n/**\n * Canonical preset themes. The playground renders its preset picker from this\n * list so the widget package stays the single source of truth for what a\n * \"good\" three-color combination looks like. Every preset is just a valid\n * ThemeConfig — there is nothing a preset can do that a hand-picked trio\n * can't.\n */\nexport const THEME_PRESETS: ThemePreset[] = [\n  // Matches the stock palette (same result as omitting `theme`).\n  { name: 'Light', backgroundColor: '#ffffff', textColor: '#262626', primaryColor: '#171717' },\n  { name: 'Dark', backgroundColor: '#171717', textColor: '#ededed', primaryColor: '#fafafa' },\n  { name: 'Midnight', backgroundColor: '#0f172a', textColor: '#e2e8f0', primaryColor: '#60a5fa' },\n  { name: 'Cream', backgroundColor: '#faf7f0', textColor: '#3f3a33', primaryColor: '#b45309' },\n  { name: 'Forest', backgroundColor: '#0c1a14', textColor: '#d7e5dc', primaryColor: '#34d399' },\n  { name: 'Ocean', backgroundColor: '#f0f7fa', textColor: '#1e3a45', primaryColor: '#0369a1' },\n];\n"],"mappings":"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","names":["forwardRef","useCallback","useEffect","useMemo","useRef","useState","jsx","jsx","jsx","cva","jsx","jsxs","FileText","jsx","jsxs","FileText","jsx","jsx","jsx","jsxs","React","createContext","Fragment","useCallback","useContext","useEffect","useState","jsx","jsxs","useState","useEffect","useCallback","jsxs","jsx","React","jsxs","jsx","jsx","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","useState","useRef","useMemo","useEffect","items","useCallback","useCallback","useEffect","useRef","useState","useState","useEffect","useRef","useCallback","Fragment","jsx","jsxs","XIcon","useEffect","useState","jsx","jsxs","recovery","useState","useEffect","XIcon","useState","useEffect","useRef","useMemo","useCallback","PaperclipIcon","XIcon","jsx","jsxs","jsx","TextShimmer","jsx","jsxs","jsx","jsxs","Fragment","memo","useMemo","memo","useMemo","useEffect","useRef","useEffect","useRef","useState","useEffect","useRef","useState","jsx","CollapsibleTrigger","CollapsibleContent","jsx","jsxs","useState","useRef","useEffect","CollapsibleTrigger","CollapsibleContent","useEffect","useRef","useState","CheckIcon","CopyIcon","jsx","jsxs","createContext","useContext","jsx","createContext","useContext","useRef","useState","CheckIcon","CopyIcon","useState","X","jsx","jsxs","Fragment","jsx","jsxs","useState","useEffect","useState","useState","useEffect","jsx","jsxs","useState","useRef","rows","CheckIcon","CopyIcon","jsx","createContext","useContext","useEffect","useId","useState","jsx","createContext","stringifyChildren","useContext","useEffect","useId","useState","jsx","memo","useMemo","ChevronDownIcon","useState","Fragment","jsx","jsxs","CollapsibleTrigger","CollapsibleContent","jsx","jsxs","useEffect","useRef","useState","CheckIcon","CopyIcon","Fragment","jsx","jsxs","useState","useRef","useEffect","CheckIcon","CopyIcon","Fragment","memo","useMemo","memo","useState","ChevronRight","CheckIcon","CopyIcon","createContext","useContext","useEffect","useRef","useState","jsx","jsxs","jsx","jsxs","useState","ChevronRight","memo","ChevronRight","memo","useEffect","useRef","useState","jsx","jsxs","SUBTLE","useState","useRef","useEffect","ChevronRight","memo","Loader2","jsx","jsxs","jsx","useMemo","jsx","Fragment","memo","Fragment","jsx","jsxs","useMemo","memo","createContext","useContext","jsx","jsx","jsxs","PaperclipIcon","useState","useRef","useEffect","useCallback","recovery","id","messages","error","useMemo","XIcon","useEffect","useMemo","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","forwardRef","ChatWidget","useCallback","useState","useMemo","useEffect","useRef","px","React","jsx","XIcon","jsx","jsxs","jsx","jsx","jsxs","XIcon","jsx","Check","CheckCircle2","ChevronRight","ExternalLinkIcon","Loader2","useRef","Fragment","jsx","jsxs","ActionButton","Loader2","ExternalLinkIcon","useRef","ChevronRight","CheckCircle2","Check","CheckIcon","ChevronDownIcon","Loader2Icon","XIcon","jsx","jsxs","Loader2Icon","CheckIcon","XIcon","CollapsibleTrigger","ChevronDownIcon","CollapsibleContent","jsx"]}