@cloudflare/ai-search-snippet 0.0.37 → 0.0.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.d.ts +231 -11
- package/dist/search-snippet.es.js +650 -325
- package/dist/search-snippet.es.js.map +1 -1
- package/dist/search-snippet.umd.js +117 -125
- package/dist/search-snippet.umd.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-snippet.es.js","sources":["../src/utils/loading-messages.ts","../src/utils/index.ts","../src/api/ai-search.ts","../src/constants.ts","../src/styles/chat.ts","../src/styles/theme.ts","../src/utils/markdown.ts","../src/components/chat-view.ts","../src/components/chat-bubble-snippet.ts","../src/components/chat-page-snippet.ts","../src/styles/search.ts","../src/components/search-bar-snippet.ts","../src/styles/modal.ts","../src/components/search-modal-snippet.ts"],"sourcesContent":["/**\n * Loading messages that cycle during search/streaming operations\n */\n\nexport const LOADING_MESSAGES = [\n 'Searching...',\n 'Digging through results...',\n 'Scanning the knowledge base...',\n 'Finding the best matches...',\n 'Sifting through the data...',\n 'Almost there...',\n 'Looking far and wide...',\n 'Connecting the dots...',\n 'Rummaging through pages...',\n 'Hunting down answers...',\n];\n\n/** Interval in ms between loading message changes */\nexport const LOADING_MESSAGE_INTERVAL_MS = 2500;\n","/**\n * Utility functions for the Search Snippet Library\n */\n\nimport { AISearchClient } from '../api/ai-search.ts';\n\nexport { LOADING_MESSAGE_INTERVAL_MS, LOADING_MESSAGES } from './loading-messages.ts';\n\n/**\n * Debounce function to limit API calls\n */\nexport type DebouncedFn<T extends (...args: unknown[]) => unknown> = ((\n ...args: Parameters<T>\n) => void) & { cancel: () => void };\n\nexport function debounce<T extends (...args: unknown[]) => unknown>(\n func: T,\n wait: number\n): DebouncedFn<T> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n\n function executedFunction(...args: Parameters<T>) {\n clearTimeout(timeout);\n timeout = setTimeout(() => {\n func(...args);\n }, wait);\n }\n\n executedFunction.cancel = () => clearTimeout(timeout);\n\n return executedFunction;\n}\n\n/**\n * Sanitize HTML to prevent XSS attacks\n */\nexport function sanitizeHTML(html: string): string {\n const div = document.createElement('div');\n div.textContent = html;\n return div.innerHTML;\n}\n\n/**\n * Escape HTML entities\n */\nexport function escapeHTML(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n}\n\n/**\n * Decode percent-encoded URLs for display\n */\nexport function formatDisplayUrl(url: string): string {\n try {\n return decodeURI(url);\n } catch {\n return url;\n }\n}\n\n/**\n * Decode HTML entities (e.g., & -> &, & -> &)\n */\nexport function decodeHTMLEntities(text: string): string {\n const doc = new DOMParser().parseFromString(text, 'text/html');\n return doc.documentElement.textContent || '';\n}\n\n/**\n * Format timestamp to readable date\n */\nexport function formatTimestamp(timestamp: number): string {\n const date = new Date(timestamp);\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n\n // Less than a minute\n if (diff < 60000) {\n return 'Just now';\n }\n\n // Less than an hour\n if (diff < 3600000) {\n const minutes = Math.floor(diff / 60000);\n return `${minutes} ${minutes === 1 ? 'minute' : 'minutes'} ago`;\n }\n\n // Less than a day\n if (diff < 86400000) {\n const hours = Math.floor(diff / 3600000);\n return `${hours} ${hours === 1 ? 'hour' : 'hours'} ago`;\n }\n\n // Format as date\n return date.toLocaleString(undefined, {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\nexport function formatDate(timestamp: number): string {\n return new Date(timestamp).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n });\n}\n\n/**\n * Generate unique ID\n */\nexport function generateId(prefix = 'id'): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n}\n\n/**\n * Parse attributes from element\n */\nexport function parseAttribute(value: string | null, defaultValue: string): string {\n return value !== null ? value : defaultValue;\n}\n\nexport function parseBooleanAttribute(value: string | null, defaultValue: boolean): boolean {\n if (value === null) return defaultValue;\n return value === 'true' || value === '';\n}\n\nexport function parseNumberAttribute(value: string | null, defaultValue: number): number {\n if (value === null) return defaultValue;\n const parsed = Number.parseInt(value, 10);\n return Number.isNaN(parsed) ? defaultValue : parsed;\n}\n\n/**\n * Create custom event\n */\nexport function createCustomEvent<T>(name: string, detail: T): CustomEvent<T> {\n return new CustomEvent(name, {\n detail,\n bubbles: true,\n composed: true,\n cancelable: true,\n });\n}\n\n/**\n * Create API client\n */\nexport function createClient(apiUrl: string): AISearchClient {\n if (!apiUrl) {\n throw new Error('API URL is required');\n }\n\n return new AISearchClient(apiUrl);\n}\n","/**\n * NLWeb API Client\n * Handles all API communication with retry logic, streaming support, and request cancellation\n */\n\nimport type {\n AISearchAPIResponse,\n ChatOptions,\n ChatTextResponse,\n ChatTypes,\n RequestState,\n SearchError,\n SearchOptions,\n SearchRequestOptions,\n SearchResult,\n} from '../types/index.ts';\nimport { decodeHTMLEntities } from '../utils/index.ts';\n\ntype RequestOperation = 'ai-search' | 'search' | 'chat/completions';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction deepMergeRecords(\n ...records: Array<Record<string, unknown> | undefined>\n): Record<string, unknown> {\n const merged: Record<string, unknown> = {};\n\n for (const record of records) {\n if (!record) {\n continue;\n }\n\n for (const [key, value] of Object.entries(record)) {\n const currentValue = merged[key];\n\n if (isRecord(currentValue) && isRecord(value)) {\n merged[key] = deepMergeRecords(currentValue, value);\n } else {\n merged[key] = value;\n }\n }\n }\n\n return merged;\n}\n\nfunction buildRequestUrl(\n endpoint: string,\n queryParams: SearchRequestOptions['queryParams'] | undefined\n): string {\n if (!isRecord(queryParams)) {\n return endpoint;\n }\n\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(queryParams)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n searchParams.append(key, String(value));\n }\n\n const query = searchParams.toString();\n\n if (!query) {\n return endpoint;\n }\n\n const hashIndex = endpoint.indexOf('#');\n const path = hashIndex === -1 ? endpoint : endpoint.slice(0, hashIndex);\n const hash = hashIndex === -1 ? '' : endpoint.slice(hashIndex);\n const separator = path.includes('?') ? '&' : '?';\n\n return `${path}${separator}${query}${hash}`;\n}\n\nfunction normalizeHeaders(\n headers: SearchRequestOptions['headers'] | undefined\n): Record<string, string> {\n if (!isRecord(headers)) {\n return {};\n }\n\n const normalizedHeaders: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n normalizedHeaders[key] = String(value);\n }\n\n return normalizedHeaders;\n}\n\nfunction normalizeBody(\n body: SearchRequestOptions['body'] | undefined\n): Record<string, unknown> | undefined {\n return isRecord(body) ? body : undefined;\n}\n\nexport class AISearchClient {\n activeRequests: Map<string, RequestState> = new Map();\n baseUrl: string;\n\n constructor(baseUrl: string) {\n this.baseUrl = baseUrl.replace(/\\/$/, ''); // Remove trailing slash\n }\n\n private request(\n body: Record<string, unknown>,\n operation: RequestOperation,\n signal?: AbortSignal,\n requestOptions?: SearchRequestOptions\n ): Promise<Response> {\n const sourceHeader = operation === 'search' ? 'snippet-search' : 'snippet-chat-completions';\n const url = buildRequestUrl(`${this.baseUrl}/${operation}`, requestOptions?.queryParams);\n\n return fetch(url, {\n method: 'POST',\n body: JSON.stringify(deepMergeRecords(normalizeBody(requestOptions?.body), body)),\n headers: {\n ...normalizeHeaders(requestOptions?.headers),\n 'Content-Type': 'application/json',\n Accept: body.stream ? 'text/event-stream' : 'application/json',\n 'cf-ai-search-source': sourceHeader,\n },\n signal,\n });\n }\n\n /**\n * Performs a search query with optional streaming\n */\n async search(query: string, options: Omit<SearchOptions, 'query'> = {}): Promise<SearchResult[]> {\n const requestId = this.generateRequestId();\n const controller = new AbortController();\n const signal = options.signal || controller.signal;\n\n this.registerRequest(requestId, controller);\n\n try {\n const response = await this.request(\n {\n messages: [{ role: 'user', content: query }],\n stream: false,\n ai_search_options: {\n retrieval: {\n metadata_only: true,\n max_num_results: options.maxResults ?? 30,\n },\n },\n },\n 'search',\n signal,\n options.request\n );\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n if (!response.body) {\n throw new Error('Response body is empty');\n }\n const result: AISearchAPIResponse = await response.json();\n if (result.success && result.result) {\n return result.result.chunks.map(\n (chunk) =>\n ({\n type: 'result',\n id: chunk.id,\n title: decodeHTMLEntities(chunk.item.metadata?.title),\n description: chunk.item.metadata?.description\n ? decodeHTMLEntities(chunk.item.metadata?.description)\n : '',\n timestamp: chunk.item.timestamp ?? undefined,\n url: chunk.item.key,\n image: chunk.item.metadata?.image || undefined,\n metadata: {\n ...(chunk.item.metadata as unknown as Record<string, unknown>),\n instance_id: chunk.instance_id,\n },\n }) satisfies SearchResult\n );\n }\n\n if (result.success === false) {\n // @ts-expect-error need to check this\n throw new Error(result.error);\n }\n throw new Error('Unknown error');\n } finally {\n this.unregisterRequest(requestId);\n }\n }\n\n async *searchStream(\n query: string,\n options: Omit<SearchOptions, 'query'> = {}\n ): AsyncGenerator<SearchResult | SearchError, void, undefined> {\n const requestId = this.generateRequestId();\n const controller = new AbortController();\n const signal = options.signal || controller.signal;\n\n this.registerRequest(requestId, controller);\n\n const response = await this.request(\n {\n messages: [{ role: 'user', content: query }],\n stream: true,\n ...(options.maxResults !== undefined && {\n max_num_results: options.maxResults,\n }),\n },\n 'ai-search',\n signal,\n options.request\n );\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n if (!response.body) {\n throw new Error('Response body is empty');\n }\n\n let chunks = '';\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n const chunk = decoder.decode(value, { stream: true });\n chunks += chunk;\n }\n\n const result: string = chunks\n .replaceAll('data: ', '')\n .trim()\n .split('\\n\\n')\n .map((chunk) => {\n return JSON.parse(chunk) as { response: string };\n })\n .map((chunk) => chunk.response)\n .join('');\n\n yield {\n type: 'result',\n id: '',\n title: '',\n description: result,\n url: '',\n metadata: {},\n };\n }\n\n async *chat(query: string, options?: ChatOptions): AsyncGenerator<ChatTypes, void, undefined> {\n const controller = new AbortController();\n const signal = options?.signal || controller.signal;\n // const prevQueries: string[] = JSON.parse(localStorage.getItem('prevQueries') || '[]');\n // prevQueries.push(query);\n // localStorage.setItem('prevQueries', JSON.stringify(prevQueries));\n const response = await this.request(\n {\n messages: [{ role: 'user', content: query }],\n stream: false,\n },\n 'chat/completions',\n signal\n );\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n if (!response.body) {\n throw new Error('Response body is empty');\n }\n const result = (await response.json()) as {\n choices: {\n message: {\n content: string;\n };\n }[];\n };\n\n yield {\n type: 'text',\n message: result.choices.map((choice) => choice.message.content).join(''),\n } satisfies ChatTextResponse;\n\n // for (const item of result.data) {\n // yield {\n // type: 'result',\n // id: item.filename,\n // title: item.filename,\n // description: item.content.text,\n // url: item.filename,\n // metadata: item.attributes\n // ,\n // } satisfies ChatResult;\n // }\n\n return;\n }\n\n /**\n * Cancels an active request by ID\n */\n cancelRequest(requestId: string): void {\n const request = this.activeRequests.get(requestId);\n if (request) {\n request.controller.abort();\n this.unregisterRequest(requestId);\n }\n }\n\n /**\n * Cancels all active requests\n */\n cancelAllRequests(): void {\n for (const [requestId] of this.activeRequests) {\n this.cancelRequest(requestId);\n }\n }\n\n /**\n * Register an active request\n */\n private registerRequest(id: string, controller: AbortController): void {\n this.activeRequests.set(id, {\n id,\n controller,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Unregister a completed request\n */\n private unregisterRequest(id: string): void {\n this.activeRequests.delete(id);\n }\n\n /**\n * Generate unique request ID\n */\n private generateRequestId(): string {\n return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n}\n","/**\n * Cloudflare AI Search branding constants\n */\n\nexport const CLOUDFLARE_LOGO_SVG = `<svg width=\"32\" height=\"10\" viewBox=\"0 0 412 186\" xmlns=\"http://www.w3.org/2000/svg\" aria-label=\"Cloudflare\" role=\"img\">\n <path fill=\"#f38020\" d=\"m280.8395,183.31456c11,-26 -4,-38 -19,-38l-148,-2c-4,0 -4,-6 1,-7l150,-2c17,-1 37,-15 43,-33c0,0 10,-21 9,-24a97,97 0 0 0 -187,-11c-38,-25 -78,9 -69,46c-48,3 -65,46 -60,72c0,1 1,2 3,2l274,0c1,0 3,-1 3,-3z\"/>\n <path fill=\"#faae40\" d=\"m330.8395,81.31456c-4,0 -6,-1 -7,1l-5,21c-5,16 3,30 20,31l32,2c4,0 4,6 -1,7l-33,1c-36,4 -46,39 -46,39c0,2 0,3 2,3l113,0l3,-2a81,81 0 0 0 -78,-103\"/>\n</svg>`;\n\nexport const CLOUDFLARE_SEARCH_URL = 'https://workers.cloudflare.com/product/ai-search';\n\nexport const POWERED_BY_BRANDING = `Powered by <a href=\"${CLOUDFLARE_SEARCH_URL}\" target=\"_blank\" rel=\"noopener noreferrer\">Cloudflare AI Search ${CLOUDFLARE_LOGO_SVG}</a>`;\n","/**\n * Chat mode specific styles\n */\n\nexport const chatStyles = `\n/* Chat container */\n.chat-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow-y: auto;\n}\n\n/* Messages area */\n.chat-messages {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: var(--search-snippet-spacing-md);\n display: flex;\n flex-direction: column;\n gap: var(--search-snippet-spacing-md);\n}\n\n.chat-messages::-webkit-scrollbar {\n width: 8px;\n}\n\n.chat-messages::-webkit-scrollbar-track {\n background: var(--search-snippet-surface);\n}\n\n.chat-messages::-webkit-scrollbar-thumb {\n background: var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n}\n\n.chat-messages::-webkit-scrollbar-thumb:hover {\n background: var(--search-snippet-text-secondary);\n}\n\n/* Message */\n.chat-message {\n display: flex;\n gap: var(--search-snippet-spacing-sm);\n max-width: 85%;\n animation: slideIn var(--search-snippet-animation-duration) ease-out;\n}\n\n@keyframes slideIn {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.chat-message-user {\n align-self: flex-end;\n flex-direction: row-reverse;\n}\n\n.chat-message-assistant {\n align-self: flex-start;\n}\n\n.chat-message-system {\n align-self: center;\n max-width: 100%;\n}\n\n/* Message avatar */\n.chat-message-avatar {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: var(--search-snippet-font-size-sm);\n font-weight: var(--search-snippet-font-weight-bold);\n background: var(--search-snippet-primary-color);\n color: white;\n}\n\n.chat-message-assistant .chat-message-avatar {\n background: var(--search-snippet-surface);\n color: var(--search-snippet-text-color);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n/* Message content */\n.chat-message-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: var(--search-snippet-spacing-xs);\n max-width: 100%;\n}\n\n.chat-message-content ol, .chat-message-content ul {\n margin-inline-start: 16px;\n}\n\n.chat-message-content ol li, .chat-message-content ul li {\n padding-inline-start: 0;\n}\n\n.chat-message-bubble {\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n border-radius: var(--search-snippet-border-radius);\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.chat-message-user .chat-message-bubble {\n background: var(--search-snippet-user-message-bg);\n color: var(--search-snippet-user-message-text);\n border-top-right-radius: var(--search-snippet-spacing-xs);\n}\n\n.chat-message-assistant .chat-message-bubble {\n background: var(--search-snippet-assistant-message-bg);\n color: var(--search-snippet-assistant-message-text);\n border-top-left-radius: var(--search-snippet-spacing-xs);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n.chat-message-system .chat-message-bubble {\n background: var(--search-snippet-system-message-bg);\n color: var(--search-snippet-system-message-text);\n text-align: center;\n font-size: var(--search-snippet-font-size-sm);\n padding: var(--search-snippet-spacing-xs) var(--search-snippet-spacing-md);\n}\n\n.chat-message-text {\n font-size: var(--search-snippet-font-size-base);\n line-height: 1.5;\n white-space: wrap;\n}\n.chat-message-text li{\n padding-inline-start: var(--search-snippet-spacing-md);\n}\n\n.chat-message-metadata {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n}\n\n.chat-message-user .chat-message-metadata {\n justify-content: flex-end;\n}\n\n.chat-message-time {\n opacity: 0.7;\n}\n\n/* Streaming indicator */\n.chat-streaming {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-xs);\n}\n\n.chat-streaming-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: currentColor;\n animation: pulse 1.4s ease-in-out infinite;\n}\n\n.chat-streaming-dot:nth-child(2) {\n animation-delay: 0.2s;\n}\n\n.chat-streaming-dot:nth-child(3) {\n animation-delay: 0.4s;\n}\n\n@keyframes pulse {\n 0%, 80%, 100% {\n opacity: 0.3;\n transform: scale(0.8);\n }\n 40% {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n.chat-streaming .loading-text {\n margin-left: var(--search-snippet-spacing-xs);\n}\n\n/* Input area */\n.chat-input-area {\n padding: var(--search-snippet-spacing-md);\n border-top: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n background: var(--search-snippet-surface);\n}\n\n.chat-input-wrapper {\n display: flex;\n gap: var(--search-snippet-spacing-sm);\n align-items: flex-end;\n}\n\n.chat-input {\n flex: 1;\n min-height: var(--search-snippet-input-height);\n max-height: 120px;\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n line-height: var(--search-snippet-line-height);\n color: var(--search-snippet-text-color);\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n outline: none;\n resize: vertical;\n transition: var(--search-snippet-transition);\n}\n\n.chat-input:focus {\n border-color: var(--search-snippet-primary-color);\n box-shadow: 0 0 0 3px var(--search-snippet-focus-ring);\n}\n\n.chat-input::placeholder {\n color: var(--search-snippet-text-secondary);\n}\n\n.chat-input:disabled {\n background: var(--search-snippet-surface);\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.chat-send-button {\n flex-shrink: 0;\n height: var(--search-snippet-input-height);\n padding: 0 var(--search-snippet-spacing-lg);\n}\n\n.chat-send-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* Empty chat state */\n.chat-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--search-snippet-spacing-xxl);\n gap: var(--search-snippet-spacing-md);\n color: var(--search-snippet-text-secondary);\n text-align: center;\n height: 100%;\n}\n\n.chat-empty-icon {\n width: 64px;\n height: 64px;\n opacity: 0.5;\n}\n\n.chat-empty-title {\n font-size: var(--search-snippet-font-size-lg);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n}\n\n.chat-empty-description {\n font-size: var(--search-snippet-font-size-sm);\n}\n\n/* Code blocks in messages */\n.chat-message-bubble pre {\n background: var(--search-snippet-surface);\n padding: var(--search-snippet-spacing-sm);\n border-radius: var(--search-snippet-border-radius);\n overflow-x: auto;\n font-family: var(--search-snippet-font-family-mono);\n font-size: var(--search-snippet-font-size-sm);\n margin: var(--search-snippet-spacing-xs) 0;\n}\n\n.chat-message-bubble code {\n font-family: var(--search-snippet-font-family-mono);\n font-size: 0.9em;\n background: var(--search-snippet-surface);\n padding: 2px 4px;\n border-radius: var(--search-snippet-border-radius);\n}\n\n.chat-message-bubble pre code {\n background: none;\n padding: 0;\n}\n\n/* Links in messages */\n.chat-message-bubble a {\n color: var(--search-snippet-primary-color);\n text-decoration: underline;\n}\n\n.chat-message-bubble a:hover {\n text-decoration: none;\n}\n`;\n","/**\n * CSS Theme with comprehensive CSS custom properties\n */\n\nexport const baseStyles = `\n:host {\n /* Colors - Light Mode */\n --search-snippet-primary-color: #2563eb;\n --search-snippet-primary-hover: #0f51dfff;\n --search-snippet-background: #ffffff;\n --search-snippet-surface: #f8f9fa;\n --search-snippet-text-color: #212529;\n --search-snippet-text-secondary: #6c757d;\n --search-snippet-text-description: #495057;\n --search-snippet-border-color: #dee2e6;\n --search-snippet-hover-background: #f1f3f5;\n --search-snippet-focus-ring: #0066cc40;\n --search-snippet-error-color: #dc3545;\n --search-snippet-error-background: #f8d7da;\n --search-snippet-success-color: #28a745;\n --search-snippet-success-background: #d4edda;\n --search-snippet-warning-color: #ffc107;\n --search-snippet-warning-background: #fff3cd;\n \n /* Message Colors */\n --search-snippet-user-message-bg: #0066cc;\n --search-snippet-user-message-text: #ffffff;\n --search-snippet-assistant-message-bg: #f1f3f5;\n --search-snippet-assistant-message-text: #212529;\n --search-snippet-system-message-bg: #fff3cd;\n --search-snippet-system-message-text: #856404;\n \n /* Typography */\n --search-snippet-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', \n 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', \n 'Segoe UI Emoji', 'Segoe UI Symbol';\n --search-snippet-font-family-mono: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;\n --search-snippet-font-size-base: 14px;\n --search-snippet-font-size-sm: 12px;\n --search-snippet-font-size-lg: 16px;\n --search-snippet-font-size-xl: 18px;\n --search-snippet-line-height: 1.5;\n --search-snippet-font-weight-normal: 400;\n --search-snippet-font-weight-medium: 500;\n --search-snippet-font-weight-bold: 600;\n \n /* Spacing */\n --search-snippet-spacing-xs: 4px;\n --search-snippet-spacing-sm: 8px;\n --search-snippet-spacing-md: 12px;\n --search-snippet-spacing-lg: 16px;\n --search-snippet-spacing-xl: 24px;\n --search-snippet-spacing-xxl: 32px;\n \n /* Sizing */\n --search-snippet-width: 100%;\n --search-snippet-max-width: 100%;\n --search-snippet-min-width: 320px;\n --search-snippet-max-height: 600px;\n --search-snippet-input-height: 44px;\n --search-snippet-button-height: 36px;\n --search-snippet-icon-size: 20px;\n \n /* Border */\n --search-snippet-border-width: 1px;\n --search-snippet-border-radius: 18px;\n \n /* Shadows */\n --search-snippet-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n --search-snippet-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n --search-snippet-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);\n --search-snippet-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.2);\n --search-snippet-shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06);\n \n /* Animation */\n --search-snippet-transition-fast: 150ms ease;\n --search-snippet-transition: 200ms ease;\n --search-snippet-transition-slow: 300ms ease;\n --search-snippet-animation-duration: 0.2s;\n \n /* Z-index */\n --search-snippet-z-dropdown: 1000;\n --search-snippet-z-modal: 1050;\n --search-snippet-z-popover: 1060;\n --search-snippet-z-tooltip: 1070;\n \n /* Layout */\n display: block;\n width: var(--search-snippet-width);\n max-width: var(--search-snippet-max-width);\n min-width: var(--search-snippet-min-width);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n line-height: var(--search-snippet-line-height);\n color: var(--search-snippet-text-color);\n\n\n /* Search */\n --search-snippet-icon-size: 20px;\n --search-snippet-icon-margin-left: 6px;\n --search-snippet-result-item-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n\n /* Chat Bubble */\n --chat-bubble-button-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);\n --chat-bubble-window-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);\n --chat-bubble-button-size: 60px;\n --chat-bubble-button-radius: 50%;\n --chat-bubble-button-icon-size: 28px;\n --chat-bubble-button-icon-color: white;\n --chat-bubble-button-bottom: 20px;\n --chat-bubble-button-right: 20px;\n --chat-bubble-button-z-index: 9999;\n --chat-bubble-position: fixed;\n\n\n}\n\n:host(:not([theme=\"dark\"])) {\n /* Colors - Light Mode */\n --search-snippet-primary-color: #2563eb;\n --search-snippet-primary-hover: #0f51dfff;\n --search-snippet-background: #ffffff;\n --search-snippet-surface: #f8f9fa;\n --search-snippet-text-color: #212529;\n --search-snippet-text-secondary: #6c757d;\n --search-snippet-text-description: #495057;\n --search-snippet-border-color: #dee2e6;\n --search-snippet-hover-background: #f1f3f5;\n --search-snippet-focus-ring: #0066cc40;\n --search-snippet-error-color: #dc3545;\n --search-snippet-error-background: #f8d7da;\n --search-snippet-success-color: #28a745;\n --search-snippet-success-background: #d4edda;\n --search-snippet-warning-color: #ffc107;\n --search-snippet-warning-background: #fff3cd;\n \n /* Message Colors */\n --search-snippet-user-message-bg: #0066cc;\n --search-snippet-user-message-text: #ffffff;\n --search-snippet-assistant-message-bg: #f1f3f5;\n --search-snippet-assistant-message-text: #212529;\n --search-snippet-system-message-bg: #fff3cd;\n --search-snippet-system-message-text: #856404;\n}\n\n/* Dark Mode */\n@media (prefers-color-scheme: dark) {\n :host(:not([theme=\"light\"])) {\n --search-snippet-primary-color: #2563eb;\n --search-snippet-primary-hover: #0f51dfff;\n --search-snippet-background: #1a1b1e;\n --search-snippet-surface: #25262b;\n --search-snippet-text-color: #c1c2c5;\n --search-snippet-text-secondary: #909296;\n --search-snippet-text-description: #adb5bd;\n --search-snippet-border-color: #373a40;\n --search-snippet-hover-background: #2c2e33;\n --search-snippet-focus-ring: #4dabf740;\n --search-snippet-error-color: #ff6b6b;\n --search-snippet-error-background: #3d1f1f;\n --search-snippet-success-color: #51cf66;\n --search-snippet-success-background: #1f3d24;\n --search-snippet-warning-color: #ffd43b;\n --search-snippet-warning-background: #3d3419;\n \n --search-snippet-user-message-bg: #4dabf7;\n --search-snippet-user-message-text: #1a1b1e;\n --search-snippet-assistant-message-bg: #2c2e33;\n --search-snippet-assistant-message-text: #c1c2c5;\n --search-snippet-system-message-bg: #3d3419;\n --search-snippet-system-message-text: #ffd43b;\n color-scheme: dark;\n }\n}\n\n/* Auto theme support */\n:host([theme=\"light\"]) {\n color-scheme: light;\n}\n\n\n/* Base reset */\n* {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n/* Container */\n.container {\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n box-shadow: var(--search-snippet-shadow);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n/* Header */\n.header {\n padding: var(--search-snippet-spacing-md);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n background: var(--search-snippet-surface);\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--search-snippet-spacing-md);\n}\n\n.header-title {\n font-size: var(--search-snippet-font-size-lg);\n font-weight: var(--search-snippet-font-weight-bold);\n color: var(--search-snippet-text-color);\n}\n\n/* Input */\n.input-wrapper {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n}\n\n.input {\n width: 100%;\n height: var(--search-snippet-input-height);\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n line-height: var(--search-snippet-line-height);\n color: var(--search-snippet-text-color);\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n outline: none;\n transition: var(--search-snippet-transition);\n}\n\n.input:focus {\n border-color: var(--search-snippet-primary-color);\n box-shadow: 0 0 0 3px var(--search-snippet-focus-ring);\n}\n\n.input::placeholder {\n color: var(--search-snippet-text-secondary);\n}\n\n.input:disabled {\n background: var(--search-snippet-surface);\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n/* Button */\n.button {\n height: var(--search-snippet-button-height);\n padding: 0 var(--search-snippet-spacing-lg);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: #ffffff;\n background: var(--search-snippet-primary-color);\n border: none;\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n outline: none;\n transition: var(--search-snippet-transition);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-sm);\n white-space: nowrap;\n}\n\n.button:hover:not(:disabled) {\n background: var(--search-snippet-primary-hover);\n}\n\n.button:focus-visible {\n box-shadow: 0 0 0 3px var(--search-snippet-focus-ring);\n}\n\n.button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.button-secondary {\n background: var(--search-snippet-surface);\n color: var(--search-snippet-text-color);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n.button-secondary:hover:not(:disabled) {\n background: var(--search-snippet-hover-background);\n}\n\n/* Content area */\n.content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: var(--search-snippet-spacing-md);\n}\n\n/* Scrollbar styling */\n.content::-webkit-scrollbar {\n width: 8px;\n}\n\n.content::-webkit-scrollbar-track {\n background: var(--search-snippet-surface);\n}\n\n.content::-webkit-scrollbar-thumb {\n background: var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n}\n\n.content::-webkit-scrollbar-thumb:hover {\n background: var(--search-snippet-text-secondary);\n}\n\n/* Loading spinner */\n.loading {\n display: inline-block;\n width: var(--search-snippet-icon-size);\n height: var(--search-snippet-icon-size);\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: spin 0.6s linear infinite;\n}\n\n@keyframes spin {\n to { transform: rotate(360deg); }\n}\n\n/* Loading message animation */\n@keyframes loading-message-in {\n from {\n opacity: 0;\n transform: translateY(8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.loading-text {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n}\n\n.loading-text-animate {\n animation: loading-message-in 0.3s ease-out;\n}\n\n/* Error message */\n.error {\n padding: var(--search-snippet-spacing-md);\n color: var(--search-snippet-error-color);\n background: var(--search-snippet-error-background);\n border-radius: var(--search-snippet-border-radius);\n font-size: var(--search-snippet-font-size-sm);\n}\n\n/* Empty state */\n.empty {\n padding: var(--search-snippet-spacing-xl);\n text-align: center;\n color: var(--search-snippet-text-secondary);\n}\n\n/* Accessibility */\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n}\n\n/* Focus visible polyfill */\n.focus-visible:focus {\n outline: 2px solid var(--search-snippet-primary-color);\n outline-offset: 2px;\n}\n\n/* Powered by branding - block style (for sidebars) */\n.powered-by {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-xs);\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n background: var(--search-snippet-surface);\n border-top: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n margin-top: auto;\n flex-shrink: 0;\n}\n\n.powered-by svg {\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n}\n\n.powered-by a,\n.powered-by-inline a {\n color: var(--search-snippet-text-secondary);\n text-decoration: none;\n transition: color var(--search-snippet-transition-fast);\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.powered-by a:hover,\n.powered-by-inline a:hover {\n color: var(--search-snippet-primary-color);\n}\n\n/* Powered by branding - inline style (for headers/subtle placement) */\n.powered-by-inline {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n padding: var(--search-snippet-spacing-xs) 0;\n text-align: center;\n}\n`;\n","/**\n * Converts markdown text to HTML\n * Supports: headers, bold, italic, links, lists, code blocks, inline code, blockquotes, and horizontal rules\n */\nexport function markdownToHtml(markdown: string): string {\n let html = markdown;\n\n // Escape HTML characters first to prevent XSS\n html = escapeHtml(html);\n\n // Process code blocks first (to protect from other transformations)\n html = html.replace(/```([\\s\\S]*?)```/g, (_, code) => `<pre><code>${code.trim()}</code></pre>`);\n\n // Split into lines for block-level processing\n const lines = html.split('\\n');\n const processedLines: string[] = [];\n let inList = false;\n let listType = '';\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Headers (h1-h6)\n const headerMatch = line.match(/^(#{1,6})\\s+(.+)$/);\n if (headerMatch) {\n const level = headerMatch[1].length;\n const content = headerMatch[2];\n processedLines.push(`<h${level}>${processInlineMarkdown(content)}</h${level}>`);\n continue;\n }\n\n // Horizontal rule\n if (line.match(/^---+$/)) {\n processedLines.push('<hr />');\n continue;\n }\n\n // Blockquote\n if (line.match(/^>\\s+/)) {\n const content = line.replace(/^>\\s+/, '');\n processedLines.push(`<blockquote>${processInlineMarkdown(content)}</blockquote>`);\n continue;\n }\n\n // Unordered list\n const ulMatch = line.match(/^[-*]\\s+(.+)$/);\n if (ulMatch) {\n if (!inList || listType !== 'ul') {\n if (inList) processedLines.push(`</${listType}>`);\n processedLines.push('<ul>');\n inList = true;\n listType = 'ul';\n }\n processedLines.push(`<li>${processInlineMarkdown(ulMatch[1])}</li>`);\n continue;\n }\n\n // Ordered list\n const olMatch = line.match(/^\\d+\\.\\s+(.+)$/);\n if (olMatch) {\n if (!inList || listType !== 'ol') {\n if (inList) processedLines.push(`</${listType}>`);\n processedLines.push('<ol>');\n inList = true;\n listType = 'ol';\n }\n processedLines.push(`<li>${processInlineMarkdown(olMatch[1])}</li>`);\n continue;\n }\n\n // Close list if we're no longer in one\n if (inList) {\n processedLines.push(`</${listType}>`);\n inList = false;\n listType = '';\n }\n\n // Empty line\n if (line.trim() === '') {\n processedLines.push('<br />');\n continue;\n }\n\n // Regular paragraph\n processedLines.push(`<p>${processInlineMarkdown(line)}</p>`);\n }\n\n // Close any open list\n if (inList) {\n processedLines.push(`</${listType}>`);\n }\n\n return processedLines.join('\\n');\n}\n\n/**\n * Process inline markdown elements (bold, italic, links, inline code)\n */\nfunction processInlineMarkdown(text: string): string {\n let result = text;\n\n // Inline code (before other inline elements)\n result = result.replace(/`([^`]+)`/g, '<code>$1</code>');\n\n // Bold and italic (***text***)\n result = result.replace(/\\*\\*\\*(.+?)\\*\\*\\*/g, '<strong><em>$1</em></strong>');\n result = result.replace(/___(.+?)___/g, '<strong><em>$1</em></strong>');\n\n // Bold (**text** or __text__)\n result = result.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>');\n result = result.replace(/__(.+?)__/g, '<strong>$1</strong>');\n\n // Italic (*text* or _text_)\n result = result.replace(/\\*(.+?)\\*/g, '<em>$1</em>');\n result = result.replace(/_(.+?)_/g, '<em>$1</em>');\n\n // Links [text](url)\n result = result.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n '<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>'\n );\n\n return result;\n}\n\n/**\n * Escape HTML characters to prevent XSS\n */\nfunction escapeHtml(text: string): string {\n const htmlEntities: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n };\n\n return text.replace(/[&<>\"']/g, (char) => htmlEntities[char] || char);\n}\n","/**\n * ChatView Component\n * Handles chat interface with streaming support\n */\n\nimport type { AISearchClient } from '../api/ai-search.ts';\nimport type { SearchSnippetProps } from '../types/index.ts';\nimport {\n createCustomEvent,\n escapeHTML,\n formatTimestamp,\n generateId,\n LOADING_MESSAGE_INTERVAL_MS,\n LOADING_MESSAGES,\n} from '../utils/index.ts';\nimport { markdownToHtml } from '../utils/markdown.ts';\nexport interface Message {\n id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n timestamp: number;\n metadata?: Record<string, unknown>;\n}\nexport class ChatView {\n private container: HTMLElement;\n private client: AISearchClient;\n private props: SearchSnippetProps;\n private inputElement: HTMLTextAreaElement | null = null;\n private messagesContainer: HTMLElement | null = null;\n private sendButton: HTMLButtonElement | null = null;\n private messages: Message[] = [];\n private isStreaming = false;\n private currentStreamingMessageId: string | null = null;\n private loadingMessageInterval: ReturnType<typeof setInterval> | null = null;\n private loadingMessageIndex = 0;\n\n // Event handler references for cleanup\n private handleInputResize: ((e: Event) => void) | null = null;\n private handleInputKeydown: ((e: KeyboardEvent) => void) | null = null;\n private handleSendClick: (() => void) | null = null;\n\n constructor(container: HTMLElement, client: AISearchClient, props: SearchSnippetProps) {\n this.container = container;\n this.client = client;\n this.props = props;\n\n this.render();\n this.attachEventListeners();\n }\n\n /**\n * Render the chat interface\n */\n private render(): void {\n this.container.innerHTML = `\n <div class=\"chat-container\">\n <div class=\"chat-messages\">\n <div class=\"chat-empty\">\n <svg class=\"chat-empty-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n <div class=\"chat-empty-title\">Start a Conversation</div>\n <div class=\"chat-empty-description\">\n Send a message to begin chatting\n </div>\n </div>\n </div>\n <div class=\"chat-input-area\">\n <div class=\"chat-input-wrapper\">\n <textarea\n class=\"chat-input\"\n placeholder=\"${escapeHTML(this.props.placeholder || 'Type a message...')}\"\n aria-label=\"Chat message input\"\n style=\"height: 40px;\"\n rows=\"1\"\n ></textarea>\n <button class=\"button chat-send-button\" aria-label=\"Send message\">\n <span>Send</span>\n </button>\n </div>\n </div>\n </div>\n `;\n\n this.messagesContainer = this.container.querySelector('.chat-messages');\n this.inputElement = this.container.querySelector('.chat-input');\n this.sendButton = this.container.querySelector('.chat-send-button');\n }\n\n /**\n * Attach event listeners\n */\n private attachEventListeners(): void {\n if (!this.inputElement || !this.sendButton) return;\n\n // Auto-resize textarea\n this.handleInputResize = (e: Event) => {\n const target = e.target as HTMLTextAreaElement;\n target.style.height = 'auto';\n target.style.height = `${target.scrollHeight}px`;\n };\n this.inputElement.addEventListener('input', this.handleInputResize);\n\n // Enter to send (Shift+Enter for new line)\n this.handleInputKeydown = (e: KeyboardEvent) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n this.handleSendMessage();\n }\n };\n this.inputElement.addEventListener('keydown', this.handleInputKeydown);\n\n // Send button click\n this.handleSendClick = () => {\n this.handleSendMessage();\n };\n this.sendButton.addEventListener('click', this.handleSendClick);\n }\n\n /**\n * Handle send message\n */\n private async handleSendMessage(): Promise<void> {\n if (!this.inputElement || this.isStreaming) return;\n\n const content = this.inputElement.value.trim();\n if (content.length === 0) return;\n\n // Clear input\n this.inputElement.value = '';\n this.inputElement.style.height = 'auto';\n\n // Send message\n await this.sendMessage(content);\n }\n\n /**\n * Send a message\n */\n public async sendMessage(content: string): Promise<void> {\n // Add user message\n const userMessage: Message = {\n id: generateId('msg'),\n role: 'user',\n content,\n timestamp: Date.now(),\n };\n\n this.addMessage(userMessage);\n this.renderMessages(true);\n this.setStreamingState(true);\n\n // Create placeholder for assistant response\n const assistantMessageId = generateId('msg');\n const assistantMessage: Message = {\n id: assistantMessageId,\n role: 'assistant',\n content: '',\n timestamp: Date.now(),\n };\n\n this.addMessage(assistantMessage);\n this.currentStreamingMessageId = assistantMessageId;\n this.renderMessages(true);\n\n try {\n // Stream the response\n const stream = this.client.chat(content);\n\n let fullContent = '';\n\n for await (const chunk of stream) {\n if (chunk.type === 'text' && chunk.message) {\n fullContent += chunk.message;\n this.updateStreamingMessage(assistantMessageId, fullContent);\n } else if (chunk.type === 'error') {\n this.showErrorInMessage(assistantMessageId, chunk.message || 'Unknown error');\n break;\n }\n // else if (chunk.type === 'done') {\n // break;\n // }\n }\n\n // Update final message\n const messageIndex = this.messages.findIndex((m) => m.id === assistantMessageId);\n if (messageIndex !== -1) {\n this.messages[messageIndex].content = fullContent;\n }\n\n // Emit message event\n this.container.dispatchEvent(createCustomEvent('message', { message: assistantMessage }));\n } catch (error) {\n this.showErrorInMessage(assistantMessageId, (error as Error).message);\n\n // Emit error event\n this.container.dispatchEvent(\n createCustomEvent('error', {\n error: {\n message: (error as Error).message,\n code: 'CHAT_ERROR',\n },\n })\n );\n } finally {\n this.setStreamingState(false);\n this.renderMessages();\n this.currentStreamingMessageId = null;\n }\n }\n\n /**\n * Add a message to the chat\n */\n private addMessage(message: Message): void {\n this.messages.push(message);\n this.renderMessages();\n }\n\n /**\n * Update streaming message content\n */\n private updateStreamingMessage(messageId: string, content: string): void {\n const messageIndex = this.messages.findIndex((m) => m.id === messageId);\n if (messageIndex !== -1) {\n this.messages[messageIndex].content = content;\n this.renderMessages(true);\n }\n }\n\n /**\n * Show error in message\n */\n private showErrorInMessage(messageId: string, error: string): void {\n const messageIndex = this.messages.findIndex((m) => m.id === messageId);\n if (messageIndex !== -1) {\n this.messages[messageIndex].content = `Error: ${error}`;\n this.renderMessages();\n }\n }\n\n /**\n * Render all messages\n */\n private renderMessages(isStreaming = false): void {\n if (!this.messagesContainer) return;\n\n if (this.messages.length === 0) {\n this.messagesContainer.innerHTML = `\n <div class=\"chat-empty\">\n <svg class=\"chat-empty-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n <div class=\"chat-empty-title\">Start a Conversation</div>\n <div class=\"chat-empty-description\">\n Send a message to begin chatting\n </div>\n </div>\n `;\n return;\n }\n\n const messagesHTML = this.messages\n .map((message) =>\n this.renderMessage(message, isStreaming && message.id === this.currentStreamingMessageId)\n )\n .join('');\n\n this.messagesContainer.innerHTML = messagesHTML;\n\n // Scroll to bottom\n this.scrollToBottom();\n }\n\n /**\n * Render a single message\n */\n private renderMessage(message: Message, isStreaming = false): string {\n const roleClass = `chat-message-${message.role}`;\n const avatar = message.role === 'user' ? 'U' : 'AI';\n\n return `\n <div class=\"chat-message ${roleClass}\">\n <div class=\"chat-message-avatar\">${avatar}</div>\n <div class=\"chat-message-content\">\n <div class=\"chat-message-bubble\">\n ${message.content ? `<div class=\"chat-message-text\">${markdownToHtml(message.content)}</div>` : ''}\n ${isStreaming ? `<div class=\"chat-streaming\"><span class=\"chat-streaming-dot\"></span><span class=\"chat-streaming-dot\"></span><span class=\"chat-streaming-dot\"></span><span class=\"loading-text\">${LOADING_MESSAGES[this.loadingMessageIndex]}</span></div>` : ''}\n </div>\n <div class=\"chat-message-metadata\">\n <span class=\"chat-message-time\">${formatTimestamp(message.timestamp)}</span>\n </div>\n </div>\n </div>\n `;\n }\n\n /**\n * Scroll to bottom of messages\n */\n private scrollToBottom(): void {\n if (!this.messagesContainer) return;\n\n requestAnimationFrame(() => {\n if (this.messagesContainer) {\n this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;\n }\n });\n }\n\n /**\n * Set streaming state\n */\n private setStreamingState(streaming: boolean): void {\n this.isStreaming = streaming;\n\n if (this.inputElement) {\n this.inputElement.disabled = streaming;\n }\n\n if (this.sendButton) {\n this.sendButton.disabled = streaming;\n this.sendButton.innerHTML = streaming ? '<div class=\"loading\"></div>' : '<span>Send</span>';\n }\n\n if (streaming) {\n this.startLoadingMessages();\n } else {\n this.clearLoadingMessages();\n }\n }\n\n private startLoadingMessages(): void {\n this.loadingMessageIndex = Math.floor(Math.random() * LOADING_MESSAGES.length);\n this.loadingMessageInterval = setInterval(() => {\n this.loadingMessageIndex = (this.loadingMessageIndex + 1) % LOADING_MESSAGES.length;\n if (this.isStreaming) {\n this.renderMessages(true);\n }\n }, LOADING_MESSAGE_INTERVAL_MS);\n }\n\n private clearLoadingMessages(): void {\n if (this.loadingMessageInterval) {\n clearInterval(this.loadingMessageInterval);\n this.loadingMessageInterval = null;\n }\n }\n\n /**\n * Get all messages\n */\n public getMessages(): Message[] {\n return [...this.messages];\n }\n\n /**\n * Clear all messages\n */\n public clearMessages(): void {\n this.messages = [];\n this.renderMessages();\n }\n\n /**\n * Set messages (for restoring history)\n */\n public setMessages(messages: Message[]): void {\n this.messages = [...messages];\n this.renderMessages();\n }\n\n /**\n * Destroy and cleanup\n */\n public destroy(): void {\n this.clearLoadingMessages();\n\n if (this.isStreaming) {\n this.client.cancelAllRequests();\n }\n\n // Remove event listeners\n if (this.inputElement) {\n if (this.handleInputResize) {\n this.inputElement.removeEventListener('input', this.handleInputResize);\n }\n if (this.handleInputKeydown) {\n this.inputElement.removeEventListener('keydown', this.handleInputKeydown);\n }\n }\n\n if (this.sendButton && this.handleSendClick) {\n this.sendButton.removeEventListener('click', this.handleSendClick);\n }\n\n // Clear handler references\n this.handleInputResize = null;\n this.handleInputKeydown = null;\n this.handleSendClick = null;\n }\n}\n","/**\n * Chat Bubble Snippet\n * A floating chat widget that expands from a bubble button\n * Fixed position in bottom-right corner\n */\n\nimport type { AISearchClient } from '../api/ai-search.ts';\nimport { POWERED_BY_BRANDING } from '../constants.ts';\nimport { chatStyles } from '../styles/chat.ts';\nimport { baseStyles } from '../styles/theme.ts';\nimport type { SearchSnippetProps } from '../types/index.ts';\nimport {\n createClient,\n createCustomEvent,\n parseAttribute,\n parseBooleanAttribute,\n} from '../utils/index.ts';\nimport type { Message } from './chat-view.ts';\nimport { ChatView } from './chat-view.ts';\n\nconst COMPONENT_NAME = 'chat-bubble-snippet';\n\nexport class ChatBubbleSnippet extends HTMLElement {\n private shadow: ShadowRoot;\n private client: AISearchClient | null = null;\n private chatView: ChatView | null = null;\n private container: HTMLElement | null = null;\n private isExpanded = false;\n private isMinimized = false;\n\n // Event handler references for cleanup\n private handleBubbleClick: (() => void) | null = null;\n private handleCloseClick: (() => void) | null = null;\n private handleMinimizeClick: (() => void) | null = null;\n private handleClearClick: (() => void) | null = null;\n\n static get observedAttributes() {\n return ['api-url', 'placeholder', 'theme', 'hide-branding'] as const;\n }\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n this.render();\n this.initializeClient();\n this.dispatchEvent(createCustomEvent('ready', undefined));\n }\n\n disconnectedCallback(): void {\n this.cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'api-url') {\n this.initializeClient();\n } else if (name === 'theme') {\n // Theme changes are handled automatically by CSS :host([theme]) selectors\n this.updateTheme(newValue);\n }\n }\n\n private getProps(): SearchSnippetProps {\n return {\n apiUrl: parseAttribute(this.getAttribute('api-url'), ''),\n placeholder: parseAttribute(this.getAttribute('placeholder'), 'Type a message...'),\n theme: parseAttribute(this.getAttribute('theme'), 'auto') as 'light' | 'dark' | 'auto',\n hideBranding: parseBooleanAttribute(this.getAttribute('hide-branding'), false),\n };\n }\n\n private initializeClient(): void {\n const props = this.getProps();\n\n if (!props.apiUrl) {\n console.error('ChatBubbleSnippet: api-url attribute is required');\n this.client = null;\n return;\n }\n\n try {\n this.client = createClient(props.apiUrl);\n } catch (error) {\n console.error('ChatBubbleSnippet:', error);\n }\n }\n\n private render(): void {\n const style = document.createElement('style');\n style.textContent = `${baseStyles}\\n${chatStyles}\\n${this.getBubbleStyles()}`;\n\n this.container = document.createElement('div');\n this.container.className = 'chat-bubble-widget';\n this.container.innerHTML = this.getBaseHTML();\n\n this.shadow.innerHTML = '';\n this.shadow.appendChild(style);\n this.shadow.appendChild(this.container);\n\n this.attachEventListeners();\n }\n\n private getBubbleStyles(): string {\n return `\n .chat-bubble-widget {\n position: var(--chat-bubble-position);\n bottom: var(--chat-bubble-button-bottom);\n right: var(--chat-bubble-button-right);\n z-index: var(--chat-bubble-button-z-index);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n }\n\n .bubble-button {\n width: var(--chat-bubble-button-size);\n height: var(--chat-bubble-button-size);\n border-radius: var(--chat-bubble-button-radius);\n background: var(--search-snippet-primary-color);\n border: none;\n cursor: pointer;\n box-shadow: var(--chat-bubble-button-shadow);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.3s ease;\n position: relative;\n }\n\n .bubble-button:hover {\n background: var(--search-snippet-primary-hover);\n transform: scale(1.05);\n }\n\n .bubble-button svg {\n width: var(--chat-bubble-button-icon-size);\n height: var(--chat-bubble-button-icon-size);\n color: var(--chat-bubble-button-icon-color);\n }\n\n .bubble-button.hidden {\n opacity: 0;\n pointer-events: none;\n transform: scale(0);\n }\n\n .chat-window {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 380px;\n height: 500px;\n background: var(--search-snippet-background);\n border-radius: var(--search-snippet-border-radius);\n box-shadow: var(--chat-bubble-window-shadow);\n display: flex;\n flex-direction: column;\n opacity: 0;\n transform: scale(0.8) translateY(20px);\n transform-origin: bottom right;\n transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);\n pointer-events: none;\n overflow: hidden;\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n }\n\n .chat-window.expanded {\n opacity: 1;\n transform: scale(1) translateY(0);\n pointer-events: auto;\n }\n\n .chat-window.minimized {\n height: 58px;\n overflow: hidden;\n }\n\n .chat-header {\n background: var(--search-snippet-surface);\n padding: var(--search-snippet-spacing-md);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-shrink: 0;\n }\n\n .chat-header-title {\n font-weight: var(--search-snippet-font-weight-bold);\n color: var(--search-snippet-text-color);\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n font-size: var(--search-snippet-font-size-lg);\n }\n\n .chat-header-title svg {\n width: 20px;\n height: 20px;\n }\n\n .chat-header-actions {\n display: flex;\n gap: var(--search-snippet-spacing-xs);\n }\n\n .icon-button {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background var(--search-snippet-transition-fast);\n color: var(--search-snippet-text-color);\n }\n\n .icon-button:hover {\n background: var(--search-snippet-hover-background);\n }\n\n .icon-button svg {\n width: 18px;\n height: 18px;\n }\n\n .chat-content {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n @media (max-width: 480px) {\n .chat-window {\n width: calc(100vw - 40px);\n max-width: 400px;\n }\n }\n `;\n }\n\n private getBaseHTML(): string {\n const props = this.getProps();\n const brandingHTML = props.hideBranding\n ? ''\n : `<div class=\"powered-by\">${POWERED_BY_BRANDING}</div>`;\n\n return `\n <button class=\"bubble-button\" aria-label=\"Open chat\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n </button>\n <div class=\"chat-window\">\n <div class=\"chat-header\">\n <div class=\"chat-header-title\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n <span>Chat</span>\n </div>\n <div class=\"chat-header-actions\">\n <button class=\"icon-button clear-button\" aria-label=\"Clear history\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"3 6 5 6 21 6\"></polyline>\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path>\n </svg>\n </button>\n <button class=\"icon-button minimize-button\" aria-label=\"Minimize\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\n </svg>\n </button>\n <button class=\"icon-button close-button\" aria-label=\"Close\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </div>\n </div>\n <div class=\"chat-content\"></div>\n ${brandingHTML}\n </div>\n `;\n }\n\n private attachEventListeners(): void {\n const bubbleButton = this.shadow.querySelector('.bubble-button');\n const closeButton = this.shadow.querySelector('.close-button');\n const minimizeButton = this.shadow.querySelector('.minimize-button');\n const clearButton = this.shadow.querySelector('.clear-button');\n\n this.handleBubbleClick = () => this.toggleChat();\n this.handleCloseClick = () => this.closeChat();\n this.handleMinimizeClick = () => this.toggleMinimize();\n this.handleClearClick = () => this.clearChat();\n\n bubbleButton?.addEventListener('click', this.handleBubbleClick);\n closeButton?.addEventListener('click', this.handleCloseClick);\n minimizeButton?.addEventListener('click', this.handleMinimizeClick);\n clearButton?.addEventListener('click', this.handleClearClick);\n }\n\n private removeEventListeners(): void {\n const bubbleButton = this.shadow.querySelector('.bubble-button');\n const closeButton = this.shadow.querySelector('.close-button');\n const minimizeButton = this.shadow.querySelector('.minimize-button');\n const clearButton = this.shadow.querySelector('.clear-button');\n\n if (this.handleBubbleClick) {\n bubbleButton?.removeEventListener('click', this.handleBubbleClick);\n }\n if (this.handleCloseClick) {\n closeButton?.removeEventListener('click', this.handleCloseClick);\n }\n if (this.handleMinimizeClick) {\n minimizeButton?.removeEventListener('click', this.handleMinimizeClick);\n }\n if (this.handleClearClick) {\n clearButton?.removeEventListener('click', this.handleClearClick);\n }\n\n // Clear handler references\n this.handleBubbleClick = null;\n this.handleCloseClick = null;\n this.handleMinimizeClick = null;\n this.handleClearClick = null;\n }\n\n private toggleChat(): void {\n this.isExpanded = !this.isExpanded;\n const bubbleButton = this.shadow.querySelector('.bubble-button');\n const chatWindow = this.shadow.querySelector('.chat-window');\n\n if (this.isExpanded) {\n bubbleButton?.classList.add('hidden');\n chatWindow?.classList.add('expanded');\n this.initializeChatView();\n } else {\n bubbleButton?.classList.remove('hidden');\n chatWindow?.classList.remove('expanded');\n }\n }\n\n private closeChat(): void {\n this.isExpanded = false;\n this.isMinimized = false;\n const bubbleButton = this.shadow.querySelector('.bubble-button');\n const chatWindow = this.shadow.querySelector('.chat-window');\n\n bubbleButton?.classList.remove('hidden');\n chatWindow?.classList.remove('expanded', 'minimized');\n }\n\n private toggleMinimize(): void {\n this.isMinimized = !this.isMinimized;\n const chatWindow = this.shadow.querySelector('.chat-window');\n\n if (this.isMinimized) {\n chatWindow?.classList.add('minimized');\n } else {\n chatWindow?.classList.remove('minimized');\n }\n }\n\n private initializeChatView(): void {\n if (this.chatView) return;\n\n const chatContent = this.shadow.querySelector('.chat-content') as HTMLElement;\n if (!chatContent) return;\n\n if (!this.client) {\n chatContent.innerHTML = `\n <div style=\"padding: 16px; color: var(--search-snippet-error-color, #ef4444); font-family: var(--search-snippet-font-family, sans-serif); font-size: var(--search-snippet-font-size-base, 14px);\">\n <strong>Error:</strong> The <code>api-url</code> attribute is required. Please provide a valid API URL.\n </div>\n `;\n return;\n }\n\n const props = this.getProps();\n this.chatView = new ChatView(chatContent, this.client, props);\n }\n\n private updateTheme(theme: string | null): void {\n // CSS :host([theme]) selectors handle theming automatically\n // For 'auto' mode, remove the attribute to let @media (prefers-color-scheme) work\n const validTheme = theme === 'light' || theme === 'dark' ? theme : null;\n\n if (\n validTheme === null &&\n this.hasAttribute('theme') &&\n this.getAttribute('theme') !== 'auto'\n ) {\n this.removeAttribute('theme');\n }\n }\n\n private cleanup(): void {\n this.removeEventListeners();\n\n if (this.client) {\n this.client.cancelAllRequests();\n }\n\n if (this.chatView) {\n this.chatView.destroy();\n }\n }\n\n // Public API\n public clearChat(): void {\n this.chatView?.clearMessages();\n }\n\n public async sendMessage(content: string): Promise<void> {\n if (this.chatView) {\n await this.chatView.sendMessage(content);\n }\n }\n\n public getMessages(): Message[] {\n return this.chatView?.getMessages() || [];\n }\n}\n\n// Register the custom element\nif (!customElements.get(COMPONENT_NAME)) {\n customElements.define(COMPONENT_NAME, ChatBubbleSnippet);\n}\n","/**\n * Chat Page Snippet\n * A full-page chat interface with history support\n */\n\nimport type { AISearchClient } from '../api/ai-search.ts';\nimport { POWERED_BY_BRANDING } from '../constants.ts';\nimport { chatStyles } from '../styles/chat.ts';\nimport { baseStyles } from '../styles/theme.ts';\nimport type { SearchSnippetProps } from '../types/index.ts';\nimport {\n createClient,\n createCustomEvent,\n parseAttribute,\n parseBooleanAttribute,\n} from '../utils/index.ts';\nimport type { Message } from './chat-view.ts';\nimport { ChatView } from './chat-view.ts';\n\nconst COMPONENT_NAME = 'chat-page-snippet';\nconst STORAGE_KEY = 'chat-page-sessions';\n\ninterface ChatSession {\n id: string;\n title: string;\n messages: Message[];\n createdAt: number;\n updatedAt: number;\n}\n\nexport class ChatPageSnippet extends HTMLElement {\n private shadow: ShadowRoot;\n private client: AISearchClient | null = null;\n private chatView: ChatView | null = null;\n private container: HTMLElement | null = null;\n private sessions: ChatSession[] = [];\n private currentSessionId: string | null = null;\n private sidebarCollapsed = false;\n\n // Event handler references for cleanup\n private handleClearClick: (() => void) | null = null;\n private handleNewChatClick: (() => void) | null = null;\n private handleToggleSidebarClick: (() => void) | null = null;\n private handleChatListClick: ((e: Event) => void) | null = null;\n private handleMessageEvent: (() => void) | null = null;\n\n static get observedAttributes() {\n return ['api-url', 'placeholder', 'theme', 'hide-branding'] as const;\n }\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n this.loadSessions();\n }\n\n connectedCallback(): void {\n this.render();\n this.initializeClient();\n this.setupView();\n this.dispatchEvent(createCustomEvent('ready', undefined));\n }\n\n disconnectedCallback(): void {\n this.saveCurrentSession();\n this.cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'api-url') {\n this.initializeClient();\n this.setupView();\n } else if (name === 'theme') {\n // Theme changes are handled automatically by CSS :host([theme]) selectors\n this.updateTheme(newValue);\n }\n }\n\n private getProps(): SearchSnippetProps {\n return {\n apiUrl: parseAttribute(this.getAttribute('api-url'), ''),\n placeholder: parseAttribute(this.getAttribute('placeholder'), 'Type a message...'),\n theme: parseAttribute(this.getAttribute('theme'), 'auto') as 'light' | 'dark' | 'auto',\n hideBranding: parseBooleanAttribute(this.getAttribute('hide-branding'), false),\n };\n }\n\n private initializeClient(): void {\n const props = this.getProps();\n\n if (!props.apiUrl) {\n console.error('ChatPageSnippet: api-url attribute is required');\n this.client = null;\n return;\n }\n\n try {\n this.client = createClient(props.apiUrl);\n } catch (error) {\n console.error('ChatPageSnippet:', error);\n }\n }\n\n private render(): void {\n const style = document.createElement('style');\n style.textContent = `${baseStyles}\\n${chatStyles}\\n${this.getPageStyles()}`;\n\n this.container = document.createElement('div');\n this.container.className = 'chat-page-container';\n this.container.innerHTML = this.getBaseHTML();\n\n this.shadow.innerHTML = '';\n this.shadow.appendChild(style);\n this.shadow.appendChild(this.container);\n\n this.attachEventListeners();\n }\n\n private getPageStyles(): string {\n return `\n :host {\n display: block;\n width: 100%;\n height: 100vh;\n }\n\n .chat-page-container {\n display: flex;\n height: 100%;\n background: var(--search-snippet-background);\n }\n\n /* Sidebar styles */\n .chat-sidebar {\n width: 280px;\n min-width: 280px;\n background: var(--search-snippet-surface);\n border-right: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n display: flex;\n flex-direction: column;\n transition: var(--search-snippet-transition);\n overflow: hidden;\n }\n\n .chat-sidebar.collapsed {\n width: 0;\n min-width: 0;\n border-right: none;\n }\n\n .sidebar-header {\n padding: var(--search-snippet-spacing-lg);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-shrink: 0;\n height: 69px;\n }\n\n .sidebar-title {\n font-size: var(--search-snippet-font-size-lg);\n font-weight: var(--search-snippet-font-weight-bold);\n color: var(--search-snippet-text-color);\n }\n\n .new-chat-button {\n width: 100%;\n height: var(--search-snippet-button-height);\n margin: var(--search-snippet-spacing-md) var(--search-snippet-spacing-lg);\n padding: 0 var(--search-snippet-spacing-lg);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: #fff;\n background: var(--search-snippet-primary-color);\n border: none;\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n outline: none;\n transition: var(--search-snippet-transition);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-sm);\n box-sizing: border-box;\n width: calc(100% - var(--search-snippet-spacing-lg) * 2);\n }\n\n .new-chat-button:hover {\n opacity: 0.9;\n }\n\n .new-chat-button svg {\n width: 16px;\n height: 16px;\n }\n\n .chat-list {\n flex: 1;\n overflow-y: auto;\n padding: var(--search-snippet-spacing-sm);\n }\n\n .chat-list-item {\n display: flex;\n align-items: center;\n padding: var(--search-snippet-spacing-md) var(--search-snippet-spacing-lg);\n margin-bottom: var(--search-snippet-spacing-xs);\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n transition: var(--search-snippet-transition);\n gap: var(--search-snippet-spacing-sm);\n }\n\n .chat-list-item:hover {\n background: var(--search-snippet-hover-background);\n }\n\n .chat-list-item.active {\n background: var(--search-snippet-hover-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n }\n\n .chat-list-item-content {\n flex: 1;\n min-width: 0;\n }\n\n .chat-list-item-title {\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .chat-list-item-date {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n margin-top: 2px;\n }\n\n .chat-list-item-delete {\n opacity: 0;\n background: none;\n border: none;\n padding: var(--search-snippet-spacing-xs);\n cursor: pointer;\n color: var(--search-snippet-text-secondary);\n border-radius: var(--search-snippet-border-radius-sm);\n transition: var(--search-snippet-transition);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .chat-list-item:hover .chat-list-item-delete {\n opacity: 1;\n }\n\n .chat-list-item-delete:hover {\n background: var(--search-snippet-error-background, rgba(239, 68, 68, 0.1));\n color: var(--search-snippet-error-color, #ef4444);\n }\n\n .chat-list-item-delete svg {\n width: 14px;\n height: 14px;\n }\n\n .chat-list-empty {\n padding: var(--search-snippet-spacing-xl);\n text-align: center;\n color: var(--search-snippet-text-secondary);\n font-size: var(--search-snippet-font-size-sm);\n }\n\n /* Main content area */\n .chat-main {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-width: 0;\n }\n\n .chat-page-header {\n background: var(--search-snippet-surface);\n padding: var(--search-snippet-spacing-lg);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-shrink: 0;\n }\n\n .chat-page-header-left {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-md);\n }\n\n .toggle-sidebar-button {\n width: 36px;\n height: 36px;\n padding: 0;\n font-family: var(--search-snippet-font-family);\n color: var(--search-snippet-text-color);\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n outline: none;\n transition: var(--search-snippet-transition);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n\n .toggle-sidebar-button:hover {\n background: var(--search-snippet-hover-background);\n }\n\n .toggle-sidebar-button svg {\n width: 18px;\n height: 18px;\n }\n\n .chat-page-header-title {\n font-size: var(--search-snippet-font-size-xl);\n font-weight: var(--search-snippet-font-weight-bold);\n color: var(--search-snippet-text-color);\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-md);\n }\n\n .chat-page-header-title svg {\n width: 28px;\n height: 28px;\n }\n\n .chat-page-header-actions {\n display: flex;\n gap: var(--search-snippet-spacing-sm);\n }\n\n .header-button {\n height: var(--search-snippet-button-height);\n padding: 0 var(--search-snippet-spacing-lg);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n outline: none;\n transition: var(--search-snippet-transition);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-sm);\n }\n\n .header-button:hover {\n background: var(--search-snippet-hover-background);\n }\n\n .header-button svg {\n width: 16px;\n height: 16px;\n }\n\n .chat-page-content {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n width: 100%;\n }\n\n .container {\n border: none;\n box-shadow: none;\n height: 100%;\n width: 100%;\n background: var(--search-snippet-background);\n border-radius: 0;\n }\n `;\n }\n\n private getBaseHTML(): string {\n const props = this.getProps();\n const brandingHTML = props.hideBranding\n ? ''\n : `<div class=\"powered-by\">${POWERED_BY_BRANDING}</div>`;\n\n return `\n <div class=\"chat-sidebar\">\n <div class=\"sidebar-header\">\n <span class=\"sidebar-title\">History</span>\n </div>\n <button class=\"new-chat-button\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M12 5v14M5 12h14\"></path>\n </svg>\n New Chat\n </button>\n <div class=\"chat-list\"></div>\n ${brandingHTML}\n </div>\n <div class=\"chat-main\">\n <div class=\"chat-page-header\">\n <div class=\"chat-page-header-left\">\n <button class=\"toggle-sidebar-button\" title=\"Toggle sidebar\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M3 12h18M3 6h18M3 18h18\"></path>\n </svg>\n </button>\n <div class=\"chat-page-header-title\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n <span>Chat</span>\n </div>\n </div>\n <div class=\"chat-page-header-actions\">\n <button class=\"header-button clear-button\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path>\n </svg>\n Clear Chat\n </button>\n </div>\n </div>\n <div class=\"chat-page-content\">\n <div class=\"container\"></div>\n </div>\n </div>\n `;\n }\n\n private attachEventListeners(): void {\n const clearButton = this.shadow.querySelector('.clear-button');\n const newChatButton = this.shadow.querySelector('.new-chat-button');\n const toggleSidebarButton = this.shadow.querySelector('.toggle-sidebar-button');\n const chatList = this.shadow.querySelector('.chat-list');\n\n this.handleClearClick = () => this.clearCurrentChat();\n this.handleNewChatClick = () => this.createNewChat();\n this.handleToggleSidebarClick = () => this.toggleSidebar();\n this.handleChatListClick = (e: Event) => this.onChatListClick(e);\n\n clearButton?.addEventListener('click', this.handleClearClick);\n newChatButton?.addEventListener('click', this.handleNewChatClick);\n toggleSidebarButton?.addEventListener('click', this.handleToggleSidebarClick);\n chatList?.addEventListener('click', this.handleChatListClick);\n }\n\n private removeEventListeners(): void {\n const clearButton = this.shadow.querySelector('.clear-button');\n const newChatButton = this.shadow.querySelector('.new-chat-button');\n const toggleSidebarButton = this.shadow.querySelector('.toggle-sidebar-button');\n const chatList = this.shadow.querySelector('.chat-list');\n const chatContent = this.shadow.querySelector('.container') as HTMLElement;\n\n if (this.handleClearClick) {\n clearButton?.removeEventListener('click', this.handleClearClick);\n }\n if (this.handleNewChatClick) {\n newChatButton?.removeEventListener('click', this.handleNewChatClick);\n }\n if (this.handleToggleSidebarClick) {\n toggleSidebarButton?.removeEventListener('click', this.handleToggleSidebarClick);\n }\n if (this.handleChatListClick) {\n chatList?.removeEventListener('click', this.handleChatListClick);\n }\n if (this.handleMessageEvent && chatContent) {\n chatContent.removeEventListener('message', this.handleMessageEvent);\n }\n\n // Clear handler references\n this.handleClearClick = null;\n this.handleNewChatClick = null;\n this.handleToggleSidebarClick = null;\n this.handleChatListClick = null;\n this.handleMessageEvent = null;\n }\n\n private setupView(): void {\n const chatContent = this.shadow.querySelector('.container') as HTMLElement;\n\n if (!this.client) {\n if (chatContent) {\n chatContent.innerHTML = `\n <div style=\"padding: 16px; color: var(--search-snippet-error-color, #ef4444); font-family: var(--search-snippet-font-family, sans-serif); font-size: var(--search-snippet-font-size-base, 14px);\">\n <strong>Error:</strong> The <code>api-url</code> attribute is required. Please provide a valid API URL.\n </div>\n `;\n }\n return;\n }\n\n if (!chatContent) return;\n\n const props = this.getProps();\n this.chatView = new ChatView(chatContent, this.client, props);\n\n // Load current session or create new one\n if (this.sessions.length === 0) {\n this.createNewChat();\n } else {\n // Load the most recent session\n const lastSession = this.sessions[0];\n this.switchToSession(lastSession.id);\n }\n\n // Listen for new messages to save session\n this.handleMessageEvent = () => {\n this.saveCurrentSession();\n this.updateSessionTitle();\n this.renderChatList();\n };\n chatContent.addEventListener('message', this.handleMessageEvent);\n\n this.renderChatList();\n }\n\n private generateSessionId(): string {\n return `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n }\n\n private loadSessions(): void {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) {\n this.sessions = JSON.parse(stored);\n // Sort by updatedAt descending\n this.sessions.sort((a, b) => b.updatedAt - a.updatedAt);\n }\n } catch (error) {\n console.error('Failed to load chat sessions:', error);\n }\n }\n\n private saveSessions(): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(this.sessions));\n } catch (error) {\n console.error('Failed to save chat sessions:', error);\n }\n }\n\n private saveCurrentSession(): void {\n if (!this.currentSessionId || !this.chatView) return;\n\n const sessionIndex = this.sessions.findIndex((s) => s.id === this.currentSessionId);\n if (sessionIndex !== -1) {\n this.sessions[sessionIndex].messages = this.chatView.getMessages();\n this.sessions[sessionIndex].updatedAt = Date.now();\n this.saveSessions();\n }\n }\n\n private updateSessionTitle(): void {\n if (!this.currentSessionId) return;\n\n const session = this.sessions.find((s) => s.id === this.currentSessionId);\n if (session && session.messages.length > 0 && session.title === 'New Chat') {\n const firstUserMessage = session.messages.find((m) => m.role === 'user');\n if (firstUserMessage) {\n session.title =\n firstUserMessage.content.slice(0, 50) +\n (firstUserMessage.content.length > 50 ? '...' : '');\n this.saveSessions();\n }\n }\n }\n\n private createNewChat(): void {\n // Save current session first\n this.saveCurrentSession();\n\n const newSession: ChatSession = {\n id: this.generateSessionId(),\n title: 'New Chat',\n messages: [],\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n this.sessions.unshift(newSession);\n this.currentSessionId = newSession.id;\n this.saveSessions();\n\n // Clear the chat view\n this.chatView?.clearMessages();\n this.renderChatList();\n }\n\n private switchToSession(sessionId: string): void {\n if (sessionId === this.currentSessionId) return;\n\n // Save current session first\n this.saveCurrentSession();\n\n const session = this.sessions.find((s) => s.id === sessionId);\n if (session && this.chatView) {\n this.currentSessionId = sessionId;\n this.chatView.setMessages(session.messages);\n this.renderChatList();\n }\n }\n\n private deleteSession(sessionId: string): void {\n const sessionIndex = this.sessions.findIndex((s) => s.id === sessionId);\n if (sessionIndex === -1) return;\n\n this.sessions.splice(sessionIndex, 1);\n this.saveSessions();\n\n // If we deleted the current session, switch to another or create new\n if (sessionId === this.currentSessionId) {\n if (this.sessions.length > 0) {\n this.switchToSession(this.sessions[0].id);\n } else {\n this.createNewChat();\n }\n }\n\n this.renderChatList();\n }\n\n private clearCurrentChat(): void {\n if (!this.currentSessionId) return;\n\n const session = this.sessions.find((s) => s.id === this.currentSessionId);\n if (session) {\n session.messages = [];\n session.title = 'New Chat';\n session.updatedAt = Date.now();\n this.saveSessions();\n }\n\n this.chatView?.clearMessages();\n this.renderChatList();\n }\n\n private toggleSidebar(): void {\n this.sidebarCollapsed = !this.sidebarCollapsed;\n const sidebar = this.shadow.querySelector('.chat-sidebar');\n sidebar?.classList.toggle('collapsed', this.sidebarCollapsed);\n }\n\n private onChatListClick(e: Event): void {\n const target = e.target as HTMLElement;\n\n // Handle delete button click\n const deleteButton = target.closest('.chat-list-item-delete');\n if (deleteButton) {\n e.stopPropagation();\n const sessionId = deleteButton.getAttribute('data-session-id');\n if (sessionId) {\n this.deleteSession(sessionId);\n }\n return;\n }\n\n // Handle chat item click\n const chatItem = target.closest('.chat-list-item');\n if (chatItem) {\n const sessionId = chatItem.getAttribute('data-session-id');\n if (sessionId) {\n this.switchToSession(sessionId);\n }\n }\n }\n\n private renderChatList(): void {\n const chatList = this.shadow.querySelector('.chat-list');\n if (!chatList) return;\n\n if (this.sessions.length === 0) {\n chatList.innerHTML = '<div class=\"chat-list-empty\">No chats yet</div>';\n return;\n }\n\n chatList.innerHTML = this.sessions.map((session) => this.renderChatListItem(session)).join('');\n }\n\n private renderChatListItem(session: ChatSession): string {\n const isActive = session.id === this.currentSessionId;\n const date = this.formatDate(session.updatedAt);\n\n return `\n <div class=\"chat-list-item ${isActive ? 'active' : ''}\" data-session-id=\"${session.id}\">\n <div class=\"chat-list-item-content\">\n <div class=\"chat-list-item-title\">${this.escapeHTML(session.title)}</div>\n <div class=\"chat-list-item-date\">${date}</div>\n </div>\n <button class=\"chat-list-item-delete\" data-session-id=\"${session.id}\" title=\"Delete chat\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path>\n </svg>\n </button>\n </div>\n `;\n }\n\n private formatDate(timestamp: number): string {\n const date = new Date(timestamp);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) {\n return date.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n } else if (diffDays === 1) {\n return 'Yesterday';\n } else if (diffDays < 7) {\n return date.toLocaleDateString(undefined, { weekday: 'long' });\n } else {\n return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n }\n\n private escapeHTML(str: string): string {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n }\n\n private updateTheme(theme: string | null): void {\n // CSS :host([theme]) selectors handle theming automatically\n // For 'auto' mode, remove the attribute to let @media (prefers-color-scheme) work\n const validTheme = theme === 'light' || theme === 'dark' ? theme : null;\n\n if (\n validTheme === null &&\n this.hasAttribute('theme') &&\n this.getAttribute('theme') !== 'auto'\n ) {\n this.removeAttribute('theme');\n }\n }\n\n private cleanup(): void {\n this.removeEventListeners();\n\n if (this.client) {\n this.client.cancelAllRequests();\n }\n\n if (this.chatView) {\n this.chatView.destroy();\n }\n }\n\n // Public API\n public clearChat(): void {\n this.clearCurrentChat();\n }\n\n public async sendMessage(content: string): Promise<void> {\n if (this.chatView) {\n await this.chatView.sendMessage(content);\n this.saveCurrentSession();\n }\n }\n\n public getMessages(): Message[] {\n return this.chatView?.getMessages() || [];\n }\n\n public getSessions(): ChatSession[] {\n return [...this.sessions];\n }\n\n public getCurrentSession(): ChatSession | null {\n return this.sessions.find((s) => s.id === this.currentSessionId) || null;\n }\n}\n\n// Register the custom element\nif (!customElements.get(COMPONENT_NAME)) {\n customElements.define(COMPONENT_NAME, ChatPageSnippet);\n}\n","/**\n * Search mode specific styles\n */\n\nexport const searchStyles = `\n/* Search view states */\n.search-view {\n transition: var(--search-snippet-transition-slow);\n background: var(--search-snippet-background);\n border-radius: var(--search-snippet-border-radius);\n padding: 0px;\n}\n\n.search-view-collapsed {\n max-height: 60px;\n}\n\n.search-view-expanded {\n max-height: var(--search-snippet-max-height);\n}\n\n\n.search-icon {\n width: var(--search-snippet-icon-size);\n height: var(--search-snippet-icon-size);\n margin-left: var(--search-snippet-icon-margin-left);\n color: var(--search-snippet-text-color);\n}\n\n/* Search input wrapper */\n.search-input-wrapper {\n display: grid;\n grid-template-columns: auto 1fr auto;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n overflow: hidden;\n transition: max-width var(--search-snippet-transition-slow), \n opacity var(--search-snippet-transition);\n padding: var(--search-snippet-spacing-sm);\n border-radius: var(--search-snippet-border-radius);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n\n\n.search-input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n color: var(--search-snippet-text-color);\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n box-shadow: none;\n padding: 0;\n}\n\n.search-input::placeholder {\n color: var(--search-snippet-text-secondary);\n}\n\n.search-view:has(.search-input:not(:placeholder-shown)) .search-input-wrapper, .search-view:has(.search-input:not(:placeholder-shown)) {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.search-view:focus-within {\n border-color: var(--search-snippet-primary-color);\n box-shadow: inset 0 0 0 3px var(--search-snippet-focus-ring);\n}\n\n.search-view:has(.search-input:not(:placeholder-shown)) .search-content {\n max-height: 600px;\n opacity: 1;\n overflow-y: auto;\n padding: 8px;\n}\n\n.search-submit-button {\n flex-shrink: 0;\n \n border-radius: max(var(--search-snippet-button-min-border-radius, 4px), calc(var(--search-snippet-border-radius) - var(--search-snippet-spacing-sm)))\n}\n\n/* Search content */\n.search-content {\n max-height: 0;\n opacity: 0;\n transition: max-height var(--search-snippet-transition-slow),\n opacity var(--search-snippet-transition);\n position: absolute;\n width: 100%;\n background: var(--search-snippet-background);\n border-bottom-left-radius: var(--search-snippet-border-radius);\n border-bottom-right-radius: var(--search-snippet-border-radius);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-top: none;\n}\n\n.search-content::-webkit-scrollbar {\n width: 8px;\n height: 100px;\n}\n\n.search-content::-webkit-scrollbar-track {\n background: var(--search-snippet-surface);\n \n}\n\n.search-content::-webkit-scrollbar-thumb {\n background: var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n}\n\n.search-content::-webkit-scrollbar-thumb:hover {\n background: var(--search-snippet-text-secondary);\n}\n\n.container {\n overflow: unset;\n position: relative;\n border: none;\n}\n\n.container:has(.search-input:not(:placeholder-shown)) {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n\n/* Override header for search mode */\n\n/* Search results */\n.search-results {\n display: flex;\n flex-direction: column;\n gap: var(--search-snippet-spacing-sm);\n}\n\na.search-result-item {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: var(--search-snippet-spacing-md);\n padding: var(--search-snippet-spacing-md);\n background: var(--search-snippet-surface);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n transition: var(--search-snippet-transition);\n text-decoration: none;\n color: inherit;\n}\n\n/* Image thumbnail container */\n.search-result-image-container {\n flex-shrink: 0;\n width: 64px;\n height: 64px;\n border-radius: calc(var(--search-snippet-border-radius) - 4px);\n overflow: hidden;\n position: relative;\n}\n\n.search-result-image {\n width: 100%;\n height: 100%;\n object-fit: contain;\n opacity: 0;\n transition: opacity var(--search-snippet-transition);\n}\n\n.search-result-image.loaded {\n opacity: 1;\n}\n\n/* Loading shimmer */\n.search-result-image-loading {\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 90deg,\n var(--search-snippet-surface) 25%,\n var(--search-snippet-border-color) 50%,\n var(--search-snippet-surface) 75%\n );\n background-size: 200% 100%;\n animation: search-image-shimmer 1.5s infinite;\n}\n\n@keyframes search-image-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* Placeholder icon */\n.search-result-image-placeholder {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--search-snippet-text-secondary);\n opacity: 0.5;\n}\n\n.search-result-image-placeholder svg {\n width: 24px;\n height: 24px;\n}\n\n/* Content wrapper */\n.search-result-content {\n flex: 1;\n min-width: 0;\n}\n\na.search-result-item:hover {\n background: var(--search-snippet-hover-background);\n border-color: var(--search-snippet-primary-color);\n transform: translateY(-1px);\n box-shadow: var(--search-snippet-result-item-shadow);\n}\n\na.search-result-item:focus-visible {\n outline: 2px solid var(--search-snippet-primary-color);\n outline-offset: 2px;\n}\n\n.search-result-title {\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n margin-bottom: var(--search-snippet-spacing-xs);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.search-result-snippet {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-description);\n line-height: 1.6;\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.search-result-metadata {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n margin-top: var(--search-snippet-spacing-xs);\n min-width: 0;\n}\n\n.search-result-url {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-primary-color);\n text-decoration: none;\n display: block;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.search-result-url-empty {\n visibility: hidden;\n}\n\n.search-result-date {\n font-size: 12px;\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-secondary);\n text-align: right;\n flex-shrink: 0;\n}\n\n.search-result-url:hover {\n text-decoration: underline;\n}\n\n/* Search header */\n.search-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: var(--search-snippet-spacing-md);\n padding-bottom: var(--search-snippet-spacing-sm);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n.search-count {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n}\n\n/* Search footer */\n.search-footer {\n padding: var(--search-snippet-spacing-md);\n padding-bottom: var(--search-snippet-spacing-xs);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-sm);\n}\n\n/* See more link */\n.search-see-more {\n display: inline-flex;\n align-items: center;\n gap: var(--search-snippet-spacing-xs);\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-primary-color);\n text-decoration: none;\n font-weight: var(--search-snippet-font-weight-medium);\n transition: color var(--search-snippet-transition-fast);\n}\n\n.search-see-more:hover {\n text-decoration: underline;\n}\n\n/* Loading state for search */\n.search-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--search-snippet-spacing-xxl);\n gap: var(--search-snippet-spacing-md);\n color: var(--search-snippet-text-secondary);\n}\n\n/* Empty search state */\n.search-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--search-snippet-spacing-xxl);\n gap: var(--search-snippet-spacing-md);\n color: var(--search-snippet-text-secondary);\n text-align: center;\n}\n\n.search-empty-icon {\n width: 64px;\n height: 64px;\n opacity: 0.5;\n}\n\n.search-empty-title {\n font-size: var(--search-snippet-font-size-lg);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n}\n\n.search-empty-description {\n font-size: var(--search-snippet-font-size-sm);\n}\n\n/* Highlight matching text */\n.search-highlight {\n background: var(--search-snippet-warning-background);\n color: var(--search-snippet-warning-color);\n padding: 1px 2px;\n border-radius: 2px;\n font-weight: var(--search-snippet-font-weight-medium);\n}\n`;\n","/**\n * Search Bar Snippet\n * A search bar with results display\n */\n\nimport type { AISearchClient } from '../api/ai-search.ts';\nimport { POWERED_BY_BRANDING } from '../constants.ts';\nimport { searchStyles } from '../styles/search.ts';\nimport { baseStyles } from '../styles/theme.ts';\nimport type { SearchRequestOptions, SearchResult, SearchSnippetProps } from '../types/index.ts';\nimport {\n createClient,\n createCustomEvent,\n debounce,\n escapeHTML,\n formatDate,\n formatDisplayUrl,\n LOADING_MESSAGE_INTERVAL_MS,\n LOADING_MESSAGES,\n parseAttribute,\n parseBooleanAttribute,\n parseNumberAttribute,\n} from '../utils/index.ts';\n\nconst COMPONENT_NAME = 'search-bar-snippet';\nconst DEFAULT_DISPLAY_RESULTS = 10;\nconst REQUEST_MAX_RESULTS = 50;\n\nexport class SearchBarSnippet extends HTMLElement {\n private shadow: ShadowRoot;\n private client: AISearchClient | null = null;\n private container: HTMLElement | null = null;\n private inputElement: HTMLInputElement | null = null;\n private resultsContainer: HTMLElement | null = null;\n private searchButton: HTMLButtonElement | null = null;\n private debouncedSearch: ((query: string) => void) | null = null;\n private currentSearchController: AbortController | null = null;\n private loadingMessageInterval: ReturnType<typeof setInterval> | null = null;\n private loadingMessageIndex = 0;\n\n // Event handler references for cleanup\n private handleInputChange: ((e: Event) => void) | null = null;\n private handleInputKeydownEnter: ((e: KeyboardEvent) => void) | null = null;\n private handleInputKeydownEscape: ((e: KeyboardEvent) => void) | null = null;\n private handleSearchButtonClick: (() => void) | null = null;\n\n static get observedAttributes() {\n return [\n 'api-url',\n 'placeholder',\n 'max-results',\n 'debounce-ms',\n 'theme',\n 'hide-branding',\n 'show-url',\n 'show-date',\n 'hide-thumbnails',\n 'see-more',\n 'request-options',\n ] as const;\n }\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n this.initializeClient();\n this.render();\n this.dispatchEvent(createCustomEvent('ready', undefined));\n }\n\n disconnectedCallback(): void {\n this.cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'api-url') {\n this.initializeClient();\n } else if (name === 'theme') {\n // Theme changes are handled automatically by CSS :host([theme]) selectors\n // But we trigger this to ensure any dynamic updates are applied\n this.updateTheme(newValue);\n }\n }\n\n private getProps(): SearchSnippetProps {\n return {\n apiUrl: parseAttribute(this.getAttribute('api-url'), ''),\n placeholder: parseAttribute(this.getAttribute('placeholder'), 'Search...'),\n maxResults: parseNumberAttribute(this.getAttribute('max-results'), 10),\n debounceMs: parseNumberAttribute(this.getAttribute('debounce-ms'), 300),\n theme: parseAttribute(this.getAttribute('theme'), 'auto') as 'light' | 'dark' | 'auto',\n hideBranding: parseBooleanAttribute(this.getAttribute('hide-branding'), false),\n showUrl: parseBooleanAttribute(this.getAttribute('show-url'), false),\n showDate: parseBooleanAttribute(this.getAttribute('show-date'), false),\n hideThumbnails: parseBooleanAttribute(this.getAttribute('hide-thumbnails'), false),\n seeMore: parseAttribute(this.getAttribute('see-more'), ''),\n };\n }\n\n private getRequestOptions(): SearchRequestOptions | undefined {\n const rawRequestOptions = this.getAttribute('request-options');\n\n if (!rawRequestOptions) {\n return undefined;\n }\n\n try {\n const parsedRequestOptions = JSON.parse(rawRequestOptions) as unknown;\n\n if (\n parsedRequestOptions === null ||\n typeof parsedRequestOptions !== 'object' ||\n Array.isArray(parsedRequestOptions)\n ) {\n throw new Error('request-options must be a JSON object');\n }\n\n return parsedRequestOptions as SearchRequestOptions;\n } catch (error) {\n console.error('SearchBarSnippet: invalid request-options attribute', error);\n return undefined;\n }\n }\n\n private initializeClient(): void {\n const props = this.getProps();\n\n if (!props.apiUrl) {\n console.error('SearchBarSnippet: api-url attribute is required');\n this.client = null;\n this.showMissingApiUrlError();\n return;\n }\n\n try {\n this.client = createClient(props.apiUrl);\n } catch (error) {\n console.error('SearchBarSnippet:', error);\n }\n }\n\n private render(): void {\n const props = this.getProps();\n\n // Create debounced search function\n const searchFn = (query: string) => this.performSearch(query);\n this.debouncedSearch = debounce(\n searchFn as (...args: unknown[]) => unknown,\n props.debounceMs || 400\n ) as (query: string) => void;\n\n const style = document.createElement('style');\n style.textContent = `${baseStyles}\\n${searchStyles}`;\n\n this.container = document.createElement('div');\n this.container.className = 'container';\n this.container.innerHTML = `\n <div class=\"search-view\"> \n <div class=\"search-input-wrapper\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"search-icon\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg>\n <input\n type=\"text\"\n name=\"search-input\"\n class=\"search-input\"\n placeholder=\"${escapeHTML(props.placeholder || 'Search...')}\"\n aria-label=\"Search input\"\n autocomplete=\"off\"\n />\n <button class=\"button search-submit-button\" aria-label=\"Search\">\n <span>Search</span>\n </button>\n </div>\n <div class=\"search-content\">\n <div class=\"search-results-wrapper\">\n <!-- Results will be inserted here -->\n </div>\n </div>\n </div>\n `;\n\n this.shadow.innerHTML = '';\n this.shadow.appendChild(style);\n this.shadow.appendChild(this.container);\n\n // Get references to elements\n this.inputElement = this.container.querySelector('.search-input');\n this.resultsContainer = this.container.querySelector('.search-results-wrapper');\n this.searchButton = this.container.querySelector('.search-submit-button');\n\n this.attachEventListeners();\n\n // Show error immediately if api-url was missing when the component was connected\n if (!this.client) {\n this.showMissingApiUrlError();\n }\n }\n\n private attachEventListeners(): void {\n if (!this.inputElement) return;\n\n // Input event for real-time search\n this.handleInputChange = (e: Event) => {\n const target = e.target as HTMLInputElement;\n const query = target.value.trim();\n\n if (query.length > 0 && this.debouncedSearch) {\n this.debouncedSearch(query);\n } else {\n this.showEmptyState();\n }\n };\n this.inputElement.addEventListener('input', this.handleInputChange);\n\n // Enter key to search immediately\n this.handleInputKeydownEnter = (e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n const query = (e.target as HTMLInputElement).value.trim();\n if (query.length > 0) {\n this.performSearch(query);\n }\n }\n };\n this.inputElement.addEventListener('keydown', this.handleInputKeydownEnter);\n\n this.handleInputKeydownEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && this.inputElement) {\n this.inputElement.value = '';\n }\n };\n window.addEventListener('keydown', this.handleInputKeydownEscape);\n\n // Search button click\n if (this.searchButton) {\n this.handleSearchButtonClick = () => {\n const query = this.inputElement?.value.trim() || '';\n if (query.length > 0) {\n this.performSearch(query);\n }\n };\n this.searchButton.addEventListener('click', this.handleSearchButtonClick);\n }\n }\n\n private async performSearch(query: string): Promise<void> {\n if (!this.client) {\n this.showMissingApiUrlError();\n return;\n }\n\n // Cancel any existing request before starting a new one\n if (this.currentSearchController) {\n this.currentSearchController.abort();\n this.currentSearchController = null;\n }\n\n // Create new controller for this request\n this.currentSearchController = new AbortController();\n this.showLoadingState();\n\n try {\n const results = await this.client.search(query, {\n signal: this.currentSearchController.signal,\n maxResults: REQUEST_MAX_RESULTS,\n request: this.getRequestOptions(),\n });\n const props = this.getProps();\n const visibleResults = results.slice(0, props.maxResults || DEFAULT_DISPLAY_RESULTS);\n this.displayResults(visibleResults, query, results.length);\n } catch (error) {\n // Don't show error state for cancelled requests\n if ((error as Error).name === 'AbortError') {\n return;\n }\n this.showErrorState((error as Error).message);\n } finally {\n this.currentSearchController = null;\n }\n }\n\n private displayResults(\n results: SearchResult[],\n query: string,\n totalResults = results.length\n ): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n\n if (results.length === 0) {\n this.showNoResultsState(query);\n return;\n }\n const props = this.getProps();\n const brandingHTML = props.hideBranding\n ? ''\n : `<div class=\"powered-by-inline\">${POWERED_BY_BRANDING}</div>`;\n const hasMoreResults = totalResults > results.length;\n const resultsCountLabel = hasMoreResults\n ? `Showing ${results.length} of ${totalResults} results`\n : `Found ${totalResults} result${totalResults === 1 ? '' : 's'}`;\n\n const seeMoreHTML =\n props.seeMore && hasMoreResults\n ? `<div class=\"search-footer\">\n <a href=\"${escapeHTML(props.seeMore + encodeURIComponent(query))}\" class=\"search-see-more\">\n <span>See more results</span>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/></svg>\n </a>\n </div>`\n : '';\n\n const resultsHTML = `\n <div class=\"search-header\">\n <div class=\"search-count\">\n ${resultsCountLabel}\n </div>\n ${brandingHTML}\n </div>\n <div class=\"search-results\">\n ${results.map((result) => this.renderResult(result)).join('')}\n </div>\n ${seeMoreHTML}\n `;\n\n this.resultsContainer.innerHTML = resultsHTML;\n\n // Attach click handlers to results\n this.attachResultHandlers();\n }\n\n private renderResult(result: SearchResult): string {\n const props = this.getProps();\n const imageHTML = props.hideThumbnails\n ? ''\n : this.renderResultImage(result.image, result.title);\n const href = result.url ? escapeHTML(result.url) : '#';\n const displayUrl = result.url ? escapeHTML(formatDisplayUrl(result.url)) : '';\n const timestampHTML =\n props.showDate && result.timestamp !== undefined\n ? `<div class=\"search-result-date\">${escapeHTML(formatDate(result.timestamp))}</div>`\n : '';\n const metadataHTML =\n (props.showUrl && result.url) || timestampHTML\n ? `<div class=\"search-result-metadata\">\n ${props.showUrl && result.url ? `<span class=\"search-result-url\">${displayUrl}</span>` : '<span class=\"search-result-url search-result-url-empty\"></span>'}\n ${timestampHTML}\n </div>`\n : '';\n\n return `\n <a href=\"${href}\" class=\"search-result-item\" data-result-id=\"${escapeHTML(result.url || '')}\">\n ${imageHTML}\n <div class=\"search-result-content\">\n <div class=\"search-result-title\">${escapeHTML(result.title || '')}</div>\n <div class=\"search-result-snippet\">${escapeHTML(result.description || '')}</div>\n ${metadataHTML}\n </div>\n </a>\n `;\n }\n\n private renderResultImage(imageUrl: string | undefined, alt: string): string {\n const placeholderSVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"/><polyline points=\"10 9 9 9 8 9\"/></svg>`;\n\n if (!imageUrl) {\n return `\n <div class=\"search-result-image-container\">\n <div class=\"search-result-image-placeholder\">${placeholderSVG}</div>\n </div>\n `;\n }\n\n return `\n <div class=\"search-result-image-container\">\n <div class=\"search-result-image-loading\"></div>\n <div class=\"search-result-image-placeholder\" style=\"display: none;\">${placeholderSVG}</div>\n <img \n class=\"search-result-image\" \n src=\"${escapeHTML(imageUrl)}\" \n alt=\"${escapeHTML(alt)}\"\n loading=\"lazy\"\n />\n </div>\n `;\n }\n\n private attachResultHandlers(): void {\n const resultItems = this.container?.querySelectorAll('.search-result-item');\n if (!resultItems) return;\n\n // Handle clicks on results without URLs (prevent default anchor behavior)\n for (const item of resultItems) {\n const href = item.getAttribute('href');\n if (href === '#') {\n item.addEventListener('click', (e) => {\n e.preventDefault();\n });\n }\n }\n\n // Image load/error handlers\n const images = this.container?.querySelectorAll('.search-result-image');\n images?.forEach((img) => {\n img.addEventListener('load', () => {\n img.classList.add('loaded');\n const container = img.closest('.search-result-image-container');\n container?.querySelector('.search-result-image-loading')?.remove();\n });\n\n img.addEventListener('error', () => {\n const container = img.closest('.search-result-image-container');\n container?.querySelector('.search-result-image-loading')?.remove();\n const placeholder = container?.querySelector(\n '.search-result-image-placeholder'\n ) as HTMLElement;\n if (placeholder) placeholder.style.display = 'flex';\n (img as HTMLElement).style.display = 'none';\n });\n });\n }\n\n private showLoadingState(): void {\n if (!this.resultsContainer) return;\n\n this.clearLoadingInterval();\n this.loadingMessageIndex = Math.floor(Math.random() * LOADING_MESSAGES.length);\n\n this.resultsContainer.innerHTML = `\n <div class=\"search-loading\">\n <div class=\"loading\" aria-label=\"Loading\"></div>\n <div class=\"loading-text loading-text-animate\">${LOADING_MESSAGES[this.loadingMessageIndex]}</div>\n </div>\n `;\n\n this.startLoadingInterval();\n }\n\n private startLoadingInterval(): void {\n this.loadingMessageInterval = setInterval(() => {\n this.loadingMessageIndex = (this.loadingMessageIndex + 1) % LOADING_MESSAGES.length;\n const textEl = this.resultsContainer?.querySelector('.loading-text');\n if (textEl) {\n textEl.classList.remove('loading-text-animate');\n void (textEl as HTMLElement).offsetWidth;\n textEl.textContent = LOADING_MESSAGES[this.loadingMessageIndex];\n textEl.classList.add('loading-text-animate');\n }\n }, LOADING_MESSAGE_INTERVAL_MS);\n }\n\n private clearLoadingInterval(): void {\n if (this.loadingMessageInterval) {\n clearInterval(this.loadingMessageInterval);\n this.loadingMessageInterval = null;\n }\n }\n\n private showEmptyState(): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n\n this.resultsContainer.innerHTML = `\n <div class=\"search-empty\">\n <svg class=\"search-empty-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <path d=\"m21 21-4.35-4.35\"></path>\n </svg>\n <div class=\"search-empty-title\">Start Searching</div>\n <div class=\"search-empty-description\">\n Enter a query to search for results\n </div>\n </div>\n `;\n }\n\n private showNoResultsState(query: string): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n\n this.resultsContainer.innerHTML = `\n <div class=\"search-empty\">\n <svg class=\"search-empty-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n </svg>\n <div class=\"search-empty-title\">No Results Found</div>\n <div class=\"search-empty-description\">\n No results found for \"${escapeHTML(query)}\"\n </div>\n </div>\n `;\n }\n\n private showErrorState(message: string): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n\n this.resultsContainer.innerHTML = `\n <div class=\"error\">\n <strong>Error:</strong> ${escapeHTML(message)}\n </div>\n `;\n }\n\n private showMissingApiUrlError(): void {\n if (this.resultsContainer) {\n this.showErrorState('The api-url attribute is required. Please provide a valid API URL.');\n }\n }\n\n private updateTheme(theme: string | null): void {\n // CSS custom properties via :host([theme]) selectors handle the actual theming\n // This method is here for any additional theme-related logic if needed\n const validTheme = theme === 'light' || theme === 'dark' || theme === 'auto' ? theme : 'auto';\n\n // Ensure the attribute is set on the host for CSS selectors\n if (validTheme === 'auto') {\n // Let the @media (prefers-color-scheme) handle it\n this.removeAttribute('theme');\n } else {\n this.setAttribute('theme', validTheme);\n }\n }\n\n private cleanup(): void {\n this.clearLoadingInterval();\n\n // Cancel any in-flight search request\n if (this.currentSearchController) {\n this.currentSearchController.abort();\n this.currentSearchController = null;\n }\n\n if (this.client) {\n this.client.cancelAllRequests();\n }\n\n // Remove event listeners\n if (this.inputElement) {\n if (this.handleInputChange) {\n this.inputElement.removeEventListener('input', this.handleInputChange);\n }\n if (this.handleInputKeydownEnter) {\n this.inputElement.removeEventListener('keydown', this.handleInputKeydownEnter);\n }\n if (this.handleInputKeydownEscape) {\n window.removeEventListener('keydown', this.handleInputKeydownEscape);\n }\n }\n\n if (this.searchButton && this.handleSearchButtonClick) {\n this.searchButton.removeEventListener('click', this.handleSearchButtonClick);\n }\n\n // Clear handler references\n this.handleInputChange = null;\n this.handleInputKeydownEnter = null;\n this.handleInputKeydownEscape = null;\n this.handleSearchButtonClick = null;\n }\n\n // Public API\n public async search(query: string): Promise<void> {\n await this.performSearch(query);\n }\n}\n\n// Register the custom element\nif (!customElements.get(COMPONENT_NAME)) {\n customElements.define(COMPONENT_NAME, SearchBarSnippet);\n}\n","/**\n * Modal search combobox specific styles\n */\n\nexport const modalStyles = `\n/* Modal backdrop */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n z-index: var(--search-snippet-z-modal);\n opacity: 0;\n visibility: hidden;\n transition: opacity var(--search-snippet-transition), visibility var(--search-snippet-transition);\n}\n\n.modal-backdrop.open {\n opacity: 1;\n visibility: visible;\n}\n\n/* Modal container */\n.modal-container {\n position: fixed;\n top: 15%;\n left: 50%;\n transform: translateX(-50%) scale(0.95);\n width: 90%;\n max-width: 600px;\n max-height: 70vh;\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n box-shadow: var(--search-snippet-shadow-lg);\n z-index: calc(var(--search-snippet-z-modal) + 1);\n display: flex;\n flex-direction: column;\n opacity: 0;\n visibility: hidden;\n transition: opacity var(--search-snippet-transition), \n visibility var(--search-snippet-transition),\n transform var(--search-snippet-transition);\n}\n\n.modal-container.open {\n opacity: 1;\n visibility: visible;\n transform: translateX(-50%) scale(1);\n}\n\n/* Modal header with search input */\n.modal-header {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n padding: var(--search-snippet-spacing-md);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n.modal-search-icon {\n width: var(--search-snippet-icon-size);\n height: var(--search-snippet-icon-size);\n color: var(--search-snippet-text-secondary);\n flex-shrink: 0;\n}\n\n.modal-search-input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n color: var(--search-snippet-text-color);\n font-size: var(--search-snippet-font-size-lg);\n font-family: var(--search-snippet-font-family);\n font-weight: var(--search-snippet-font-weight-normal);\n padding: var(--search-snippet-spacing-xs) 0;\n}\n\n.modal-search-input::placeholder {\n color: var(--search-snippet-text-secondary);\n}\n\n.modal-shortcut-hint {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-xs);\n color: var(--search-snippet-text-secondary);\n font-size: var(--search-snippet-font-size-sm);\n flex-shrink: 0;\n}\n\n.modal-kbd {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 22px;\n padding: 0 var(--search-snippet-spacing-xs);\n background: var(--search-snippet-surface);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: 4px;\n font-size: var(--search-snippet-font-size-sm);\n font-family: var(--search-snippet-font-family);\n color: var(--search-snippet-text-secondary);\n}\n\n/* Modal content (results area) */\n.modal-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: var(--search-snippet-spacing-sm);\n}\n\n.modal-content::-webkit-scrollbar {\n width: 8px;\n}\n\n.modal-content::-webkit-scrollbar-track {\n background: var(--search-snippet-surface);\n}\n\n.modal-content::-webkit-scrollbar-thumb {\n background: var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n}\n\n.modal-content::-webkit-scrollbar-thumb:hover {\n background: var(--search-snippet-text-secondary);\n}\n\n/* Results list */\n.modal-results {\n display: flex;\n flex-direction: column;\n gap: var(--search-snippet-spacing-xs);\n}\n\na.modal-result-item {\n padding: var(--search-snippet-spacing-md);\n background: transparent;\n border: var(--search-snippet-border-width) solid transparent;\n border-radius: calc(var(--search-snippet-border-radius) - 4px);\n cursor: pointer;\n transition: var(--search-snippet-transition-fast);\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: var(--search-snippet-spacing-md);\n text-decoration: none;\n color: inherit;\n}\n\n/* Image thumbnail container */\n.modal-result-image-container {\n flex-shrink: 0;\n width: 48px;\n height: 48px;\n border-radius: 6px;\n overflow: hidden;\n position: relative;\n}\n\n.modal-result-image {\n width: 100%;\n height: 100%;\n object-fit: contain;\n opacity: 0;\n transition: opacity var(--search-snippet-transition);\n}\n\n.modal-result-image.loaded {\n opacity: 1;\n}\n\n/* Loading shimmer */\n.modal-result-image-loading {\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 90deg,\n var(--search-snippet-surface) 25%,\n var(--search-snippet-border-color) 50%,\n var(--search-snippet-surface) 75%\n );\n background-size: 200% 100%;\n animation: modal-image-shimmer 1.5s infinite;\n}\n\n@keyframes modal-image-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* Placeholder icon */\n.modal-result-image-placeholder {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--search-snippet-text-secondary);\n opacity: 0.5;\n}\n\n.modal-result-image-placeholder svg {\n width: 20px;\n height: 20px;\n}\n\n/* Content wrapper */\n.modal-result-content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: var(--search-snippet-spacing-xs);\n}\n\na.modal-result-item:hover,\na.modal-result-item.active {\n background: var(--search-snippet-hover-background);\n border-color: var(--search-snippet-border-color);\n}\n\na.modal-result-item.active {\n border-color: var(--search-snippet-primary-color);\n background: var(--search-snippet-focus-ring);\n}\n\na.modal-result-item:focus-visible {\n outline: 2px solid var(--search-snippet-primary-color);\n outline-offset: -2px;\n}\n\n.modal-result-title {\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.modal-result-description {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-description);\n line-height: 1.5;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.modal-result-metadata {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n min-width: 0;\n}\n\n.modal-result-url {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-primary-color);\n text-decoration: none;\n display: block;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.modal-result-url-empty {\n visibility: hidden;\n}\n\n.modal-result-date {\n font-size: 12px;\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-secondary);\n text-align: right;\n flex-shrink: 0;\n}\n\n.modal-result-url:hover {\n text-decoration: underline;\n}\n\n/* Result group header */\n.modal-group-header {\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n font-size: var(--search-snippet-font-size-sm);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n/* Loading state */\n.modal-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--search-snippet-spacing-xxl);\n gap: var(--search-snippet-spacing-md);\n color: var(--search-snippet-text-secondary);\n}\n\n/* Empty state */\n.modal-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--search-snippet-spacing-xxl);\n gap: var(--search-snippet-spacing-md);\n color: var(--search-snippet-text-secondary);\n text-align: center;\n}\n\n.modal-empty-icon {\n width: 48px;\n height: 48px;\n opacity: 0.5;\n}\n\n.modal-empty-title {\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n}\n\n.modal-empty-description {\n font-size: var(--search-snippet-font-size-sm);\n}\n\n/* Footer */\n.modal-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n border-top: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n background: var(--search-snippet-surface);\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n border-radius: 0 0 var(--search-snippet-border-radius) var(--search-snippet-border-radius);\n}\n\n.modal-footer-hints {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-md);\n}\n\n.modal-footer-hint {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-xs);\n}\n\n.modal-footer-hint .modal-kbd {\n min-width: 20px;\n height: 20px;\n font-size: 11px;\n}\n\n/* Results count */\n.modal-results-count {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n}\n\n/* Powered by in modal footer */\n.modal-footer .powered-by-inline {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n}\n\n.modal-footer .powered-by-inline a {\n color: var(--search-snippet-text-secondary);\n text-decoration: none;\n transition: color var(--search-snippet-transition-fast);\n}\n\n.modal-footer .powered-by-inline a:hover {\n color: var(--search-snippet-primary-color);\n}\n\n/* See more link */\n.modal-see-more {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-xs);\n padding: var(--search-snippet-spacing-md);\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-primary-color);\n text-decoration: none;\n font-weight: var(--search-snippet-font-weight-medium);\n transition: background var(--search-snippet-transition-fast);\n padding-bottom: var(--search-snippet-spacing-xs);\n}\n\n.modal-see-more:hover {\n background: var(--search-snippet-hover);\n text-decoration: underline;\n}\n\n/* Responsive adjustments */\n@media (max-width: 640px) {\n .modal-container {\n top: 10%;\n width: 95%;\n max-height: 80vh;\n }\n\n .modal-footer-hints {\n display: none;\n }\n}\n\n/* Animation for modal open */\n@keyframes modal-slide-in {\n from {\n opacity: 0;\n transform: translateX(-50%) scale(0.95) translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) scale(1) translateY(0);\n }\n}\n\n.modal-container.open {\n animation: modal-slide-in var(--search-snippet-transition) ease-out;\n}\n`;\n","/**\n * Search Modal Snippet\n * A modal combobox search component with keyboard navigation\n * Opens with Cmd/Ctrl+K shortcut by default\n */\n\nimport type { AISearchClient } from '../api/ai-search.ts';\nimport { POWERED_BY_BRANDING } from '../constants.ts';\nimport { modalStyles } from '../styles/modal.ts';\nimport { baseStyles } from '../styles/theme.ts';\nimport type { SearchRequestOptions, SearchResult, SearchSnippetProps } from '../types/index.ts';\nimport {\n createClient,\n createCustomEvent,\n debounce,\n escapeHTML,\n formatDate,\n formatDisplayUrl,\n LOADING_MESSAGE_INTERVAL_MS,\n LOADING_MESSAGES,\n parseAttribute,\n parseBooleanAttribute,\n parseNumberAttribute,\n} from '../utils/index.ts';\n\nconst COMPONENT_NAME = 'search-modal-snippet';\nconst DEFAULT_DISPLAY_RESULTS = 10;\nconst REQUEST_MAX_RESULTS = 50;\n\nexport interface SearchModalProps extends SearchSnippetProps {\n /** Keyboard shortcut key (default: 'k') */\n shortcut?: string;\n /** Whether to use meta key (Cmd on Mac) or ctrl key */\n useMetaKey?: boolean;\n}\n\nexport class SearchModalSnippet extends HTMLElement {\n private shadow: ShadowRoot;\n private client: AISearchClient | null = null;\n private backdrop: HTMLElement | null = null;\n private modal: HTMLElement | null = null;\n private inputElement: HTMLInputElement | null = null;\n private resultsContainer: HTMLElement | null = null;\n private footerCount: HTMLElement | null = null;\n private isOpen = false;\n private results: SearchResult[] = [];\n private activeIndex = -1;\n private debouncedSearch: (((query: string) => void) & { cancel: () => void }) | null = null;\n private currentSearchController: AbortController | null = null;\n private loadingMessageInterval: ReturnType<typeof setInterval> | null = null;\n private loadingMessageIndex = 0;\n\n // Event handler references for cleanup\n private handleGlobalKeydown: ((e: KeyboardEvent) => void) | null = null;\n private handleInputChange: ((e: Event) => void) | null = null;\n private handleInputKeydown: ((e: KeyboardEvent) => void) | null = null;\n private handleBackdropClick: ((e: MouseEvent) => void) | null = null;\n\n // Scroll lock state\n private savedBodyStyles: {\n overflow: string;\n position: string;\n top: string;\n width: string;\n scrollbarGutter: string;\n } | null = null;\n private savedHtmlOverflow: string | null = null;\n\n static get observedAttributes() {\n return [\n 'api-url',\n 'placeholder',\n 'max-results',\n 'theme',\n 'shortcut',\n 'use-meta-key',\n 'debounce-ms',\n 'hide-branding',\n 'show-url',\n 'show-date',\n 'hide-thumbnails',\n 'see-more',\n 'request-options',\n ] as const;\n }\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n this.initializeClient();\n this.render();\n this.attachGlobalKeyboardShortcut();\n this.dispatchEvent(createCustomEvent('ready', undefined));\n }\n\n disconnectedCallback(): void {\n this.cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'api-url') {\n this.initializeClient();\n } else if (name === 'theme') {\n this.updateTheme(newValue);\n }\n }\n\n private getProps(): SearchModalProps {\n return {\n apiUrl: parseAttribute(this.getAttribute('api-url'), ''),\n placeholder: parseAttribute(this.getAttribute('placeholder'), 'Search...'),\n maxResults: parseNumberAttribute(this.getAttribute('max-results'), 10),\n debounceMs: parseNumberAttribute(this.getAttribute('debounce-ms'), 300),\n theme: parseAttribute(this.getAttribute('theme'), 'auto') as 'light' | 'dark' | 'auto',\n shortcut: parseAttribute(this.getAttribute('shortcut'), 'k'),\n useMetaKey: this.getAttribute('use-meta-key') !== 'false',\n hideBranding: parseBooleanAttribute(this.getAttribute('hide-branding'), false),\n showUrl: parseBooleanAttribute(this.getAttribute('show-url'), false),\n showDate: parseBooleanAttribute(this.getAttribute('show-date'), false),\n hideThumbnails: parseBooleanAttribute(this.getAttribute('hide-thumbnails'), false),\n seeMore: parseAttribute(this.getAttribute('see-more'), ''),\n };\n }\n\n private getRequestOptions(): SearchRequestOptions | undefined {\n const rawRequestOptions = this.getAttribute('request-options');\n\n if (!rawRequestOptions) {\n return undefined;\n }\n\n try {\n const parsedRequestOptions = JSON.parse(rawRequestOptions) as unknown;\n\n if (\n parsedRequestOptions === null ||\n typeof parsedRequestOptions !== 'object' ||\n Array.isArray(parsedRequestOptions)\n ) {\n throw new Error('request-options must be a JSON object');\n }\n\n return parsedRequestOptions as SearchRequestOptions;\n } catch (error) {\n console.error('SearchModalSnippet: invalid request-options attribute', error);\n return undefined;\n }\n }\n\n private initializeClient(): void {\n const props = this.getProps();\n\n if (!props.apiUrl) {\n console.error('SearchModalSnippet: api-url attribute is required');\n this.client = null;\n this.showMissingApiUrlError();\n return;\n }\n\n try {\n this.client = createClient(props.apiUrl);\n } catch (error) {\n console.error('SearchModalSnippet:', error);\n }\n }\n\n private render(): void {\n const props = this.getProps();\n\n // Create debounced search function\n const searchFn = (query: string) => this.performSearch(query);\n this.debouncedSearch = debounce(\n searchFn as (...args: unknown[]) => unknown,\n props.debounceMs || 300\n );\n\n const style = document.createElement('style');\n style.textContent = `${baseStyles}\\n${modalStyles}`;\n\n const brandingHTML = props.hideBranding\n ? ''\n : `<div class=\"powered-by-inline\">${POWERED_BY_BRANDING}</div>`;\n\n const container = document.createElement('div');\n container.innerHTML = `\n <div class=\"modal-backdrop\" role=\"presentation\"></div>\n <div class=\"modal-container\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"modal-title\">\n <div class=\"modal-header\">\n <svg class=\"modal-search-icon\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 -960 960 960\" fill=\"currentColor\">\n <path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/>\n </svg>\n <input\n type=\"text\"\n class=\"modal-search-input\"\n placeholder=\"${escapeHTML(props.placeholder || 'Search...')}\"\n aria-label=\"Search\"\n aria-autocomplete=\"list\"\n aria-controls=\"modal-results-list\"\n aria-expanded=\"false\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n </div>\n <div class=\"modal-content\">\n <div class=\"modal-results\" id=\"modal-results-list\" role=\"listbox\" aria-label=\"Search results\">\n ${this.renderEmptyState()}\n </div>\n </div>\n <div class=\"modal-footer\">\n <div class=\"modal-footer-hints\">\n <div class=\"modal-footer-hint\">\n <kbd class=\"modal-kbd\">↑</kbd>\n <kbd class=\"modal-kbd\">↓</kbd>\n <span>Navigate</span>\n </div>\n <div class=\"modal-footer-hint\">\n <kbd class=\"modal-kbd\">↵</kbd>\n <span>Select</span>\n </div>\n <div class=\"modal-footer-hint\">\n <kbd class=\"modal-kbd\">Esc</kbd>\n <span>Close</span>\n </div>\n </div>\n ${brandingHTML}\n </div>\n </div>\n `;\n\n this.shadow.innerHTML = '';\n this.shadow.appendChild(style);\n this.shadow.appendChild(container);\n\n // Get references to elements\n this.backdrop = this.shadow.querySelector('.modal-backdrop');\n this.modal = this.shadow.querySelector('.modal-container');\n this.inputElement = this.shadow.querySelector('.modal-search-input');\n this.resultsContainer = this.shadow.querySelector('.modal-results');\n this.footerCount = this.shadow.querySelector('.modal-results-count');\n\n this.attachEventListeners();\n\n // Show error immediately if api-url was missing when the component was connected\n if (!this.client) {\n this.showMissingApiUrlError();\n }\n }\n\n private attachGlobalKeyboardShortcut(): void {\n const props = this.getProps();\n const shortcutKey = props.shortcut?.toLowerCase() || 'k';\n\n this.handleGlobalKeydown = (e: KeyboardEvent) => {\n // Check for shortcut to open modal\n const modifierPressed = props.useMetaKey ? e.metaKey || e.ctrlKey : e.ctrlKey;\n\n if (modifierPressed && e.key.toLowerCase() === shortcutKey && !this.isOpen) {\n e.preventDefault();\n this.open();\n }\n };\n\n document.addEventListener('keydown', this.handleGlobalKeydown);\n }\n\n private attachEventListeners(): void {\n if (!this.inputElement || !this.backdrop) return;\n\n // Input change event\n this.handleInputChange = (e: Event) => {\n const target = e.target as HTMLInputElement;\n const query = target.value.trim();\n\n if (query.length > 0 && this.debouncedSearch) {\n this.debouncedSearch(query);\n } else {\n this.debouncedSearch?.cancel();\n this.currentSearchController?.abort();\n this.results = [];\n this.activeIndex = -1;\n this.showEmptyState();\n }\n };\n this.inputElement.addEventListener('input', this.handleInputChange);\n\n // Keyboard navigation\n this.handleInputKeydown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n this.navigateResults(1);\n break;\n case 'ArrowUp':\n e.preventDefault();\n this.navigateResults(-1);\n break;\n case 'Enter':\n e.preventDefault();\n this.selectActiveResult();\n break;\n case 'Escape':\n e.preventDefault();\n this.close();\n break;\n }\n };\n this.inputElement.addEventListener('keydown', this.handleInputKeydown);\n\n // Backdrop click to close\n this.handleBackdropClick = (e: MouseEvent) => {\n if (e.target === this.backdrop) {\n this.close();\n }\n };\n this.backdrop.addEventListener('click', this.handleBackdropClick);\n }\n\n private navigateResults(direction: number): void {\n if (this.results.length === 0) return;\n\n const newIndex = this.activeIndex + direction;\n\n if (newIndex < 0) {\n this.activeIndex = this.results.length - 1;\n } else if (newIndex >= this.results.length) {\n this.activeIndex = 0;\n } else {\n this.activeIndex = newIndex;\n }\n\n this.updateActiveResult();\n }\n\n private updateActiveResult(): void {\n const items = this.resultsContainer?.querySelectorAll('.modal-result-item');\n if (!items) return;\n\n items.forEach((item, index) => {\n if (index === this.activeIndex) {\n item.classList.add('active');\n item.setAttribute('aria-selected', 'true');\n // Scroll into view if needed\n (item as HTMLElement).scrollIntoView({ block: 'nearest' });\n } else {\n item.classList.remove('active');\n item.setAttribute('aria-selected', 'false');\n }\n });\n\n // Update aria-activedescendant\n if (this.inputElement && this.activeIndex >= 0) {\n this.inputElement.setAttribute('aria-activedescendant', `result-${this.activeIndex}`);\n } else if (this.inputElement) {\n this.inputElement.removeAttribute('aria-activedescendant');\n }\n }\n\n private selectActiveResult(): void {\n if (this.activeIndex < 0 || this.activeIndex >= this.results.length) {\n // If no result selected but there's a query, perform immediate search\n const query = this.inputElement?.value.trim();\n if (query && query.length > 0) {\n this.performSearch(query);\n }\n return;\n }\n\n const result = this.results[this.activeIndex];\n this.dispatchEvent(\n createCustomEvent('result-select', {\n result,\n index: this.activeIndex,\n })\n );\n\n // Navigate to URL - click the active link element to trigger navigation\n const activeItem = this.resultsContainer?.querySelector(\n `.modal-result-item[data-index=\"${this.activeIndex}\"]`\n ) as HTMLAnchorElement | null;\n\n if (activeItem && result.url) {\n activeItem.click();\n }\n\n this.close();\n }\n\n private async performSearch(query: string): Promise<void> {\n if (!this.client) {\n this.showMissingApiUrlError();\n return;\n }\n\n // Cancel any existing request before starting a new one\n if (this.currentSearchController) {\n this.currentSearchController.abort();\n this.currentSearchController = null;\n }\n\n // Create new controller for this request\n this.currentSearchController = new AbortController();\n this.showLoadingState();\n\n try {\n const results = await this.client.search(query, {\n signal: this.currentSearchController.signal,\n maxResults: REQUEST_MAX_RESULTS,\n request: this.getRequestOptions(),\n });\n const props = this.getProps();\n this.results = results.slice(0, props.maxResults || DEFAULT_DISPLAY_RESULTS);\n this.activeIndex = this.results.length > 0 ? 0 : -1;\n this.displayResults(this.results, query, results.length);\n } catch (error) {\n // Don't show error state for cancelled requests\n if ((error as Error).name === 'AbortError') {\n return;\n }\n this.showErrorState((error as Error).message);\n } finally {\n this.currentSearchController = null;\n }\n }\n\n private displayResults(\n results: SearchResult[],\n query: string,\n totalResults = results.length\n ): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n\n if (results.length === 0) {\n this.showNoResultsState(query);\n return;\n }\n\n const props = this.getProps();\n const resultsHTML = results.map((result, index) => this.renderResult(result, index)).join('');\n const hasMoreResults = totalResults > results.length;\n const resultsCountLabel = hasMoreResults\n ? `Showing ${results.length} of ${totalResults} results`\n : `${totalResults} result${totalResults === 1 ? '' : 's'}`;\n const seeMoreHTML =\n props.seeMore && hasMoreResults\n ? `<a href=\"${escapeHTML(props.seeMore + encodeURIComponent(query))}\" class=\"modal-see-more\">\n <span>See more results</span>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/></svg>\n </a>`\n : '';\n\n this.resultsContainer.innerHTML = resultsHTML + seeMoreHTML;\n\n // Update footer count\n if (this.footerCount) {\n this.footerCount.textContent = resultsCountLabel;\n }\n\n // Update aria-expanded\n if (this.inputElement) {\n this.inputElement.setAttribute('aria-expanded', 'true');\n }\n\n // Attach click handlers\n this.attachResultHandlers();\n\n // Update active state\n this.updateActiveResult();\n }\n\n private renderResult(result: SearchResult, index: number): string {\n const props = this.getProps();\n const imageHTML = props.hideThumbnails\n ? ''\n : this.renderResultImage(result.image, result.title);\n const href = result.url ? escapeHTML(result.url) : '#';\n const displayUrl = result.url ? escapeHTML(formatDisplayUrl(result.url)) : '';\n const timestampHTML =\n props.showDate && result.timestamp !== undefined\n ? `<div class=\"modal-result-date\">${escapeHTML(formatDate(result.timestamp))}</div>`\n : '';\n const metadataHTML =\n (props.showUrl && result.url) || timestampHTML\n ? `<div class=\"modal-result-metadata\">\n ${props.showUrl && result.url ? `<span class=\"modal-result-url\">${displayUrl}</span>` : '<span class=\"modal-result-url modal-result-url-empty\"></span>'}\n ${timestampHTML}\n </div>`\n : '';\n\n return `\n <a \n href=\"${href}\"\n class=\"modal-result-item${index === this.activeIndex ? ' active' : ''}\" \n role=\"option\" \n id=\"result-${index}\"\n aria-selected=\"${index === this.activeIndex}\"\n tabindex=\"-1\"\n data-index=\"${index}\"\n data-url=\"${escapeHTML(result.url || '')}\"\n >\n ${imageHTML}\n <div class=\"modal-result-content\">\n <div class=\"modal-result-title\">${escapeHTML(result.title || '')}</div>\n ${result.description ? `<div class=\"modal-result-description\">${escapeHTML(result.description)}</div>` : ''}\n ${metadataHTML}\n </div>\n </a>\n `;\n }\n\n private renderResultImage(imageUrl: string | undefined, alt: string): string {\n const placeholderSVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"/><polyline points=\"10 9 9 9 8 9\"/></svg>`;\n\n if (!imageUrl) {\n return `\n <div class=\"modal-result-image-container\">\n <div class=\"modal-result-image-placeholder\">${placeholderSVG}</div>\n </div>\n `;\n }\n\n return `\n <div class=\"modal-result-image-container\">\n <div class=\"modal-result-image-loading\"></div>\n <div class=\"modal-result-image-placeholder\" style=\"display: none;\">${placeholderSVG}</div>\n <img \n class=\"modal-result-image\" \n src=\"${escapeHTML(imageUrl)}\" \n alt=\"${escapeHTML(alt)}\"\n loading=\"lazy\"\n />\n </div>\n `;\n }\n\n private attachResultHandlers(): void {\n const items = this.resultsContainer?.querySelectorAll('.modal-result-item');\n if (!items) return;\n\n items.forEach((item, index) => {\n // Handle clicks on results without URLs (prevent default anchor behavior)\n const href = item.getAttribute('href');\n if (href === '#') {\n item.addEventListener('click', (e) => {\n e.preventDefault();\n });\n }\n\n item.addEventListener('mouseenter', () => {\n this.activeIndex = index;\n this.updateActiveResult();\n });\n });\n\n // Image load/error handlers\n const images = this.resultsContainer?.querySelectorAll('.modal-result-image');\n images?.forEach((img) => {\n img.addEventListener('load', () => {\n img.classList.add('loaded');\n const container = img.closest('.modal-result-image-container');\n container?.querySelector('.modal-result-image-loading')?.remove();\n });\n\n img.addEventListener('error', () => {\n const container = img.closest('.modal-result-image-container');\n container?.querySelector('.modal-result-image-loading')?.remove();\n const placeholder = container?.querySelector(\n '.modal-result-image-placeholder'\n ) as HTMLElement;\n if (placeholder) placeholder.style.display = 'flex';\n (img as HTMLElement).style.display = 'none';\n });\n });\n }\n\n private renderEmptyState(): string {\n return `\n <div class=\"modal-empty\">\n <svg class=\"modal-empty-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <path d=\"m21 21-4.35-4.35\"></path>\n </svg>\n <div class=\"modal-empty-description\">Start typing to search</div>\n </div>\n `;\n }\n\n private showEmptyState(): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n this.resultsContainer.innerHTML = this.renderEmptyState();\n\n if (this.footerCount) {\n this.footerCount.textContent = '';\n }\n\n if (this.inputElement) {\n this.inputElement.setAttribute('aria-expanded', 'false');\n }\n }\n\n private showLoadingState(): void {\n if (!this.resultsContainer) return;\n\n this.clearLoadingInterval();\n this.loadingMessageIndex = Math.floor(Math.random() * LOADING_MESSAGES.length);\n\n this.resultsContainer.innerHTML = `\n <div class=\"modal-loading\">\n <div class=\"loading\" aria-label=\"Loading\"></div>\n <div class=\"loading-text loading-text-animate\">${LOADING_MESSAGES[this.loadingMessageIndex]}</div>\n </div>\n `;\n\n if (this.footerCount) {\n this.footerCount.textContent = LOADING_MESSAGES[this.loadingMessageIndex];\n }\n\n this.startLoadingInterval();\n }\n\n private startLoadingInterval(): void {\n this.loadingMessageInterval = setInterval(() => {\n this.loadingMessageIndex = (this.loadingMessageIndex + 1) % LOADING_MESSAGES.length;\n const textEl = this.resultsContainer?.querySelector('.loading-text');\n if (textEl) {\n textEl.classList.remove('loading-text-animate');\n void (textEl as HTMLElement).offsetWidth;\n textEl.textContent = LOADING_MESSAGES[this.loadingMessageIndex];\n textEl.classList.add('loading-text-animate');\n }\n if (this.footerCount) {\n this.footerCount.textContent = LOADING_MESSAGES[this.loadingMessageIndex];\n }\n }, LOADING_MESSAGE_INTERVAL_MS);\n }\n\n private clearLoadingInterval(): void {\n if (this.loadingMessageInterval) {\n clearInterval(this.loadingMessageInterval);\n this.loadingMessageInterval = null;\n }\n }\n\n private showNoResultsState(query: string): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n\n this.resultsContainer.innerHTML = `\n <div class=\"modal-empty\">\n <svg class=\"modal-empty-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n </svg>\n <div class=\"modal-empty-title\">No results found</div>\n <div class=\"modal-empty-description\">No results for \"${escapeHTML(query)}\"</div>\n </div>\n `;\n\n if (this.footerCount) {\n this.footerCount.textContent = '0 results';\n }\n\n if (this.inputElement) {\n this.inputElement.setAttribute('aria-expanded', 'false');\n }\n }\n\n private showErrorState(message: string): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n\n this.resultsContainer.innerHTML = `\n <div class=\"error\">\n <strong>Error:</strong> ${escapeHTML(message)}\n </div>\n `;\n\n if (this.footerCount) {\n this.footerCount.textContent = 'Error';\n }\n }\n\n private showMissingApiUrlError(): void {\n if (this.resultsContainer) {\n this.showErrorState('The api-url attribute is required. Please provide a valid API URL.');\n }\n }\n\n private updateTheme(theme: string | null): void {\n const validTheme = theme === 'light' || theme === 'dark' || theme === 'auto' ? theme : 'auto';\n\n if (validTheme === 'auto') {\n this.removeAttribute('theme');\n } else {\n this.setAttribute('theme', validTheme);\n }\n }\n\n private lockBodyScroll(): void {\n // Save current body styles\n const scrollY = window.scrollY;\n this.savedBodyStyles = {\n overflow: document.body.style.overflow,\n position: document.body.style.position,\n top: document.body.style.top,\n width: document.body.style.width,\n scrollbarGutter: document.body.style.scrollbarGutter,\n };\n\n this.savedHtmlOverflow = document.documentElement.style.overflow;\n\n // Apply scroll lock styles to both html and body for cross-browser support\n document.body.style.scrollbarGutter = 'stable';\n document.documentElement.style.overflow = 'hidden';\n document.body.style.overflow = 'hidden';\n document.body.style.position = 'fixed';\n document.body.style.top = `-${scrollY}px`;\n document.body.style.width = '100%';\n }\n\n private unlockBodyScroll(): void {\n if (!this.savedBodyStyles) return;\n\n // Get the scroll position from the top style\n const scrollY = Math.abs(Number.parseInt(document.body.style.top || '0', 10));\n\n // Restore original styles\n document.documentElement.style.overflow = this.savedHtmlOverflow || '';\n document.body.style.overflow = this.savedBodyStyles.overflow;\n document.body.style.position = this.savedBodyStyles.position;\n document.body.style.top = this.savedBodyStyles.top;\n document.body.style.width = this.savedBodyStyles.width;\n document.body.style.scrollbarGutter = this.savedBodyStyles.scrollbarGutter || '';\n\n // Restore scroll position\n window.scrollTo(0, scrollY);\n\n this.savedBodyStyles = null;\n this.savedHtmlOverflow = null;\n }\n\n private cleanup(): void {\n this.clearLoadingInterval();\n\n // Cancel any in-flight search request\n if (this.currentSearchController) {\n this.currentSearchController.abort();\n this.currentSearchController = null;\n }\n\n // Remove global keyboard listener\n if (this.handleGlobalKeydown) {\n document.removeEventListener('keydown', this.handleGlobalKeydown);\n this.handleGlobalKeydown = null;\n }\n\n // Remove element event listeners\n if (this.inputElement) {\n if (this.handleInputChange) {\n this.inputElement.removeEventListener('input', this.handleInputChange);\n }\n if (this.handleInputKeydown) {\n this.inputElement.removeEventListener('keydown', this.handleInputKeydown);\n }\n }\n\n if (this.backdrop && this.handleBackdropClick) {\n this.backdrop.removeEventListener('click', this.handleBackdropClick);\n }\n\n // Clear handler references\n this.handleInputChange = null;\n this.handleInputKeydown = null;\n this.handleBackdropClick = null;\n\n // Cancel any pending requests\n if (this.client) {\n this.client.cancelAllRequests();\n }\n }\n\n // Public API\n\n /**\n * Open the search modal\n */\n public open(): void {\n if (this.isOpen) return;\n\n this.isOpen = true;\n this.backdrop?.classList.add('open');\n this.modal?.classList.add('open');\n\n // Focus input after animation completes\n // Use double rAF to ensure DOM has updated and transitions have started\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n this.inputElement?.focus();\n });\n });\n\n // Prevent body scroll (save current styles to restore later)\n this.lockBodyScroll();\n\n this.dispatchEvent(createCustomEvent('open', undefined));\n }\n\n /**\n * Close the search modal\n */\n public close(): void {\n if (!this.isOpen) return;\n\n this.isOpen = false;\n this.backdrop?.classList.remove('open');\n this.modal?.classList.remove('open');\n\n // Clear state\n if (this.inputElement) {\n this.inputElement.value = '';\n }\n this.results = [];\n this.activeIndex = -1;\n this.showEmptyState();\n\n // Restore body scroll\n this.unlockBodyScroll();\n\n this.dispatchEvent(createCustomEvent('close', undefined));\n }\n\n /**\n * Toggle the search modal open/closed\n */\n public toggle(): void {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * Perform a search programmatically\n */\n public async search(query: string): Promise<void> {\n if (!this.isOpen) {\n this.open();\n }\n\n if (this.inputElement) {\n this.inputElement.value = query;\n }\n\n await this.performSearch(query);\n }\n\n /**\n * Get current search results\n */\n public getResults(): SearchResult[] {\n return [...this.results];\n }\n\n /**\n * Check if modal is currently open\n */\n public isModalOpen(): boolean {\n return this.isOpen;\n }\n}\n\n// Register the custom element\nif (!customElements.get(COMPONENT_NAME)) {\n customElements.define(COMPONENT_NAME, SearchModalSnippet);\n}\n"],"names":["LOADING_MESSAGES","debounce","func","wait","timeout","executedFunction","args","escapeHTML","text","div","formatDisplayUrl","url","decodeHTMLEntities","formatTimestamp","timestamp","date","diff","minutes","hours","formatDate","generateId","prefix","parseAttribute","value","defaultValue","parseBooleanAttribute","parseNumberAttribute","parsed","createCustomEvent","name","detail","createClient","apiUrl","AISearchClient","isRecord","deepMergeRecords","records","merged","record","key","currentValue","buildRequestUrl","endpoint","queryParams","searchParams","query","hashIndex","path","hash","separator","normalizeHeaders","headers","normalizedHeaders","normalizeBody","body","baseUrl","__publicField","operation","signal","requestOptions","sourceHeader","options","requestId","controller","response","result","chunk","chunks","reader","decoder","done","choice","request","id","CLOUDFLARE_LOGO_SVG","CLOUDFLARE_SEARCH_URL","POWERED_BY_BRANDING","chatStyles","baseStyles","markdownToHtml","markdown","html","escapeHtml","_","code","lines","processedLines","inList","listType","i","line","headerMatch","level","content","processInlineMarkdown","ulMatch","olMatch","htmlEntities","char","ChatView","container","client","props","e","target","userMessage","assistantMessageId","assistantMessage","stream","fullContent","messageIndex","m","error","message","messageId","isStreaming","messagesHTML","roleClass","avatar","streaming","messages","COMPONENT_NAME","ChatBubbleSnippet","oldValue","newValue","style","bubbleButton","closeButton","minimizeButton","clearButton","chatWindow","chatContent","theme","STORAGE_KEY","ChatPageSnippet","newChatButton","toggleSidebarButton","chatList","lastSession","stored","a","b","sessionIndex","s","session","firstUserMessage","newSession","sessionId","deleteButton","chatItem","isActive","diffMs","diffDays","str","searchStyles","DEFAULT_DISPLAY_RESULTS","REQUEST_MAX_RESULTS","SearchBarSnippet","rawRequestOptions","parsedRequestOptions","searchFn","results","visibleResults","totalResults","brandingHTML","hasMoreResults","resultsCountLabel","seeMoreHTML","resultsHTML","imageHTML","href","displayUrl","timestampHTML","metadataHTML","imageUrl","alt","placeholderSVG","resultItems","item","img","placeholder","textEl","validTheme","modalStyles","SearchModalSnippet","shortcutKey","direction","newIndex","items","index","activeItem","scrollY"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GCAbC,IAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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"}
|
|
1
|
+
{"version":3,"file":"search-snippet.es.js","sources":["../src/i18n/defaults.ts","../src/i18n/index.ts","../src/utils/loading-messages.ts","../src/utils/index.ts","../src/api/ai-search.ts","../src/constants.ts","../src/styles/chat.ts","../src/styles/theme.ts","../src/utils/markdown.ts","../src/components/chat-view.ts","../src/components/chat-bubble-snippet.ts","../src/components/chat-page-snippet.ts","../src/styles/search.ts","../src/components/search-bar-snippet.ts","../src/styles/modal.ts","../src/components/search-modal-snippet.ts"],"sourcesContent":["/**\n * Default English translations for all components.\n *\n * Keys are flat camelCase. Strings with `{name}` tokens are interpolated with\n * `interpolate()` at render time. Singular/plural forms use separate keys.\n */\n\nimport type { Translations } from './index.ts';\n\nexport const DEFAULT_TRANSLATIONS: Required<Translations> = {\n // Shared\n loadingAriaLabel: 'Loading',\n errorPrefix: 'Error:',\n missingApiUrlError: 'The api-url attribute is required. Please provide a valid API URL.',\n poweredBy: 'Powered by',\n poweredByLinkLabel: 'Cloudflare AI Search',\n\n // Search (shared between bar and modal)\n placeholder: 'Search...',\n searchButtonLabel: 'Search',\n searchInputAriaLabel: 'Search input',\n searchResultsAriaLabel: 'Search results',\n emptyStateTitle: 'Start Searching',\n emptyStateDescription: 'Enter a query to search for results',\n modalEmptyStateDescription: 'Start typing to search',\n noResultsTitle: 'No Results Found',\n noResultsDescription: 'No results found for \"{query}\"',\n modalNoResultsTitle: 'No results found',\n modalNoResultsDescription: 'No results for \"{query}\"',\n resultsCount: 'Found {n} result',\n resultsCountPlural: 'Found {n} results',\n resultsCountOverflow: 'Showing {n} of {total} results',\n modalResultsCount: '{n} result',\n modalResultsCountPlural: '{n} results',\n modalResultsCountZero: '0 results',\n modalResultsCountError: 'Error',\n seeMoreResults: 'See more results',\n\n // Modal-only\n navigateHint: 'Navigate',\n selectHint: 'Select',\n closeHint: 'Close',\n\n // Chat (shared between bubble, page, and chat view)\n chatTitle: 'Chat',\n chatPlaceholder: 'Type a message...',\n chatInputAriaLabel: 'Chat message input',\n sendButtonLabel: 'Send',\n sendButtonAriaLabel: 'Send message',\n chatEmptyTitle: 'Start a Conversation',\n chatEmptyDescription: 'Send a message to begin chatting',\n userAvatar: 'U',\n assistantAvatar: 'AI',\n unknownError: 'Unknown error',\n\n // Chat bubble\n openChatAriaLabel: 'Open chat',\n clearHistoryAriaLabel: 'Clear history',\n minimizeAriaLabel: 'Minimize',\n closeAriaLabel: 'Close',\n\n // Chat page\n historyTitle: 'History',\n newChatButton: 'New Chat',\n clearChatButton: 'Clear Chat',\n toggleSidebarTitle: 'Toggle sidebar',\n deleteChatTitle: 'Delete chat',\n noChatsYet: 'No chats yet',\n yesterday: 'Yesterday',\n\n // Relative timestamps (formatTimestamp)\n justNow: 'Just now',\n minuteAgo: '{n} minute ago',\n minutesAgo: '{n} minutes ago',\n hourAgo: '{n} hour ago',\n hoursAgo: '{n} hours ago',\n\n // Cycling loading messages\n loadingMessages: [\n 'Searching...',\n 'Digging through results...',\n 'Scanning the knowledge base...',\n 'Finding the best matches...',\n 'Sifting through the data...',\n 'Almost there...',\n 'Looking far and wide...',\n 'Connecting the dots...',\n 'Rummaging through pages...',\n 'Hunting down answers...',\n ],\n};\n","/**\n * Translation utilities for component user-facing strings.\n *\n * Users override any subset of translations via the `translations` attribute\n * (JSON string) or property (plain object). Missing keys fall back to the\n * built-in English defaults.\n *\n * @example\n * ```html\n * <search-bar-snippet translations='{\"placeholder\":\"Busca aqu\\u00ed...\"}'></search-bar-snippet>\n * ```\n *\n * @example\n * ```ts\n * element.translations = { placeholder: 'Busca aquí...' };\n * ```\n */\n\nimport { DEFAULT_TRANSLATIONS } from './defaults.ts';\n\n/**\n * All user-facing strings rendered by the snippet components.\n *\n * All keys are optional; unspecified keys fall back to English defaults.\n * Strings can contain `{name}` tokens that are interpolated at render time.\n */\nexport interface Translations {\n // Shared\n /** Aria label for loading spinners. Default: \"Loading\" */\n loadingAriaLabel?: string;\n /** Bold prefix for error messages. Default: \"Error:\" */\n errorPrefix?: string;\n /** Message shown when the `api-url` attribute is missing. */\n missingApiUrlError?: string;\n /** Branding prefix before the product link. Default: \"Powered by\" */\n poweredBy?: string;\n /** Branding link label. Default: \"Cloudflare AI Search\" */\n poweredByLinkLabel?: string;\n\n // Search\n /** Search input placeholder text. */\n placeholder?: string;\n /** Search submit button text and aria-label. */\n searchButtonLabel?: string;\n /** Aria-label for the search input on the bar variant. */\n searchInputAriaLabel?: string;\n /** Aria-label for the modal results list. */\n searchResultsAriaLabel?: string;\n /** Title shown before a user enters a query (bar variant). */\n emptyStateTitle?: string;\n /** Description shown before a user enters a query (bar variant). */\n emptyStateDescription?: string;\n /** Description shown before a user enters a query (modal variant). */\n modalEmptyStateDescription?: string;\n /** Title shown when a search returns no results (bar variant). */\n noResultsTitle?: string;\n /** Description shown when a search returns no results (bar variant). Supports `{query}`. */\n noResultsDescription?: string;\n /** Title shown when a search returns no results (modal variant). */\n modalNoResultsTitle?: string;\n /** Description shown when a search returns no results (modal variant). Supports `{query}`. */\n modalNoResultsDescription?: string;\n /** Bar results count when exactly 1 result. Supports `{n}`. */\n resultsCount?: string;\n /** Bar results count when multiple results. Supports `{n}`. */\n resultsCountPlural?: string;\n /** Bar/modal results count when truncated. Supports `{n}` and `{total}`. */\n resultsCountOverflow?: string;\n /** Modal footer results count when exactly 1 result. Supports `{n}`. */\n modalResultsCount?: string;\n /** Modal footer results count when multiple results. Supports `{n}`. */\n modalResultsCountPlural?: string;\n /** Modal footer count shown with the zero-results state. */\n modalResultsCountZero?: string;\n /** Modal footer text shown with the error state. */\n modalResultsCountError?: string;\n /** Label for the \"see more\" link when `see-more` is configured. */\n seeMoreResults?: string;\n\n // Modal-only\n /** Modal footer hint next to the ↑ ↓ keys. */\n navigateHint?: string;\n /** Modal footer hint next to the ↵ key. */\n selectHint?: string;\n /** Modal footer hint next to the Esc key. */\n closeHint?: string;\n\n // Chat\n /** Chat header title. */\n chatTitle?: string;\n /** Chat input placeholder text. */\n chatPlaceholder?: string;\n /** Aria-label for the chat textarea. */\n chatInputAriaLabel?: string;\n /** Chat send button text. */\n sendButtonLabel?: string;\n /** Chat send button aria-label. */\n sendButtonAriaLabel?: string;\n /** Empty chat state title. */\n chatEmptyTitle?: string;\n /** Empty chat state description. */\n chatEmptyDescription?: string;\n /** User message avatar text. Default: \"U\" */\n userAvatar?: string;\n /** Assistant message avatar text. Default: \"AI\" */\n assistantAvatar?: string;\n /** Fallback for chat errors with no message. */\n unknownError?: string;\n\n // Chat bubble\n /** Aria-label for the floating chat bubble button. */\n openChatAriaLabel?: string;\n /** Aria-label for the clear-history icon button. */\n clearHistoryAriaLabel?: string;\n /** Aria-label for the minimize icon button. */\n minimizeAriaLabel?: string;\n /** Aria-label for the close icon button. */\n closeAriaLabel?: string;\n\n // Chat page\n /** Sidebar heading on the chat-page variant. */\n historyTitle?: string;\n /** New-chat button label. */\n newChatButton?: string;\n /** Clear-chat header button label. */\n clearChatButton?: string;\n /** Tooltip for the sidebar toggle button. */\n toggleSidebarTitle?: string;\n /** Tooltip for a per-session delete button. */\n deleteChatTitle?: string;\n /** Empty sessions list message. */\n noChatsYet?: string;\n /** Label for \"one day ago\" in the sessions list. */\n yesterday?: string;\n\n // Relative timestamps (formatTimestamp)\n /** Relative timestamp for < 1 minute ago. */\n justNow?: string;\n /** Relative timestamp for exactly 1 minute ago. Supports `{n}`. */\n minuteAgo?: string;\n /** Relative timestamp for 2-59 minutes ago. Supports `{n}`. */\n minutesAgo?: string;\n /** Relative timestamp for exactly 1 hour ago. Supports `{n}`. */\n hourAgo?: string;\n /** Relative timestamp for 2-23 hours ago. Supports `{n}`. */\n hoursAgo?: string;\n\n /** Cycling loading messages shown during search/streaming. Provide the full array to override. */\n loadingMessages?: string[];\n}\n\n/**\n * Merge user-provided translations with built-in defaults.\n *\n * Performs a shallow merge so any omitted keys fall back to English. If\n * `loadingMessages` is provided, it fully replaces the default array.\n */\nexport function mergeTranslations(user?: Translations | null): Required<Translations> {\n if (!user || typeof user !== 'object') {\n return DEFAULT_TRANSLATIONS;\n }\n\n const merged = { ...DEFAULT_TRANSLATIONS } as Required<Translations>;\n for (const key of Object.keys(user) as (keyof Translations)[]) {\n const value = user[key];\n if (value === undefined || value === null) continue;\n\n if (key === 'loadingMessages') {\n if (Array.isArray(value) && value.length > 0) {\n merged.loadingMessages = value.filter((m): m is string => typeof m === 'string');\n if (merged.loadingMessages.length === 0) {\n merged.loadingMessages = DEFAULT_TRANSLATIONS.loadingMessages;\n }\n }\n continue;\n }\n\n if (typeof value === 'string') {\n (merged as Record<string, unknown>)[key] = value;\n }\n }\n\n return merged;\n}\n\n/**\n * Replace `{name}` tokens in a template with values from `vars`.\n *\n * Unknown tokens are left untouched. Values are coerced to strings.\n */\nexport function interpolate(template: string, vars: Record<string, string | number> = {}): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, name) => {\n if (Object.hasOwn(vars, name)) {\n return String(vars[name]);\n }\n return match;\n });\n}\n\n/**\n * Parse the `translations` HTML attribute (a JSON string) into an object.\n *\n * Returns `null` if the attribute is missing or invalid. Logs a warning\n * (prefixed with `componentName`) when JSON is malformed.\n */\nexport function parseTranslationsAttribute(\n raw: string | null,\n componentName: string\n): Translations | null {\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('translations must be a JSON object');\n }\n return parsed as Translations;\n } catch (error) {\n console.error(`${componentName}: invalid translations attribute`, error);\n return null;\n }\n}\n\nexport { DEFAULT_TRANSLATIONS } from './defaults.ts';\n","/**\n * Loading messages that cycle during search/streaming operations\n */\n\nexport const LOADING_MESSAGES = [\n 'Searching...',\n 'Digging through results...',\n 'Scanning the knowledge base...',\n 'Finding the best matches...',\n 'Sifting through the data...',\n 'Almost there...',\n 'Looking far and wide...',\n 'Connecting the dots...',\n 'Rummaging through pages...',\n 'Hunting down answers...',\n];\n\n/** Interval in ms between loading message changes */\nexport const LOADING_MESSAGE_INTERVAL_MS = 2500;\n","/**\n * Utility functions for the Search Snippet Library\n */\n\nimport { AISearchClient } from '../api/ai-search.ts';\nimport { interpolate, mergeTranslations, type Translations } from '../i18n/index.ts';\n\nexport { LOADING_MESSAGE_INTERVAL_MS, LOADING_MESSAGES } from './loading-messages.ts';\n\n/**\n * Debounce function to limit API calls\n */\nexport type DebouncedFn<T extends (...args: unknown[]) => unknown> = ((\n ...args: Parameters<T>\n) => void) & { cancel: () => void };\n\nexport function debounce<T extends (...args: unknown[]) => unknown>(\n func: T,\n wait: number\n): DebouncedFn<T> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n\n function executedFunction(...args: Parameters<T>) {\n clearTimeout(timeout);\n timeout = setTimeout(() => {\n func(...args);\n }, wait);\n }\n\n executedFunction.cancel = () => clearTimeout(timeout);\n\n return executedFunction;\n}\n\n/**\n * Sanitize HTML to prevent XSS attacks\n */\nexport function sanitizeHTML(html: string): string {\n const div = document.createElement('div');\n div.textContent = html;\n return div.innerHTML;\n}\n\n/**\n * Escape HTML entities\n */\nexport function escapeHTML(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n}\n\n/**\n * Decode percent-encoded URLs for display\n */\nexport function formatDisplayUrl(url: string): string {\n try {\n return decodeURI(url);\n } catch {\n return url;\n }\n}\n\n/**\n * Decode HTML entities (e.g., & -> &, & -> &)\n */\nexport function decodeHTMLEntities(text: string): string {\n const doc = new DOMParser().parseFromString(text, 'text/html');\n return doc.documentElement.textContent || '';\n}\n\n/**\n * Format timestamp to readable date.\n *\n * Accepts an optional `Translations` map (or a `Required<Translations>`\n * already merged with defaults) so relative-time strings can be localized.\n * Falls back to built-in English if no translations are provided.\n */\nexport function formatTimestamp(timestamp: number, translations?: Translations): string {\n const t = mergeTranslations(translations);\n const date = new Date(timestamp);\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n\n // Less than a minute\n if (diff < 60000) {\n return t.justNow;\n }\n\n // Less than an hour\n if (diff < 3600000) {\n const minutes = Math.floor(diff / 60000);\n const template = minutes === 1 ? t.minuteAgo : t.minutesAgo;\n return interpolate(template, { n: minutes });\n }\n\n // Less than a day\n if (diff < 86400000) {\n const hours = Math.floor(diff / 3600000);\n const template = hours === 1 ? t.hourAgo : t.hoursAgo;\n return interpolate(template, { n: hours });\n }\n\n // Format as date\n return date.toLocaleString(undefined, {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\nexport function formatDate(timestamp: number): string {\n return new Date(timestamp).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n });\n}\n\n/**\n * Generate unique ID\n */\nexport function generateId(prefix = 'id'): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n}\n\n/**\n * Parse attributes from element\n */\nexport function parseAttribute(value: string | null, defaultValue: string): string {\n return value !== null ? value : defaultValue;\n}\n\nexport function parseBooleanAttribute(value: string | null, defaultValue: boolean): boolean {\n if (value === null) return defaultValue;\n return value === 'true' || value === '';\n}\n\nexport function parseNumberAttribute(value: string | null, defaultValue: number): number {\n if (value === null) return defaultValue;\n const parsed = Number.parseInt(value, 10);\n return Number.isNaN(parsed) ? defaultValue : parsed;\n}\n\n/**\n * Create custom event\n */\nexport function createCustomEvent<T>(name: string, detail: T): CustomEvent<T> {\n return new CustomEvent(name, {\n detail,\n bubbles: true,\n composed: true,\n cancelable: true,\n });\n}\n\n/**\n * Create API client\n */\nexport function createClient(apiUrl: string): AISearchClient {\n if (!apiUrl) {\n throw new Error('API URL is required');\n }\n\n return new AISearchClient(apiUrl);\n}\n","/**\n * NLWeb API Client\n * Handles all API communication with retry logic, streaming support, and request cancellation\n */\n\nimport type {\n AISearchAPIResponse,\n ChatOptions,\n ChatTextResponse,\n ChatTypes,\n RequestState,\n SearchError,\n SearchOptions,\n SearchRequestOptions,\n SearchResult,\n} from '../types/index.ts';\nimport { decodeHTMLEntities } from '../utils/index.ts';\n\ntype RequestOperation = 'ai-search' | 'search' | 'chat/completions';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction deepMergeRecords(\n ...records: Array<Record<string, unknown> | undefined>\n): Record<string, unknown> {\n const merged: Record<string, unknown> = {};\n\n for (const record of records) {\n if (!record) {\n continue;\n }\n\n for (const [key, value] of Object.entries(record)) {\n const currentValue = merged[key];\n\n if (isRecord(currentValue) && isRecord(value)) {\n merged[key] = deepMergeRecords(currentValue, value);\n } else {\n merged[key] = value;\n }\n }\n }\n\n return merged;\n}\n\nfunction buildRequestUrl(\n endpoint: string,\n queryParams: SearchRequestOptions['queryParams'] | undefined\n): string {\n if (!isRecord(queryParams)) {\n return endpoint;\n }\n\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(queryParams)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n searchParams.append(key, String(value));\n }\n\n const query = searchParams.toString();\n\n if (!query) {\n return endpoint;\n }\n\n const hashIndex = endpoint.indexOf('#');\n const path = hashIndex === -1 ? endpoint : endpoint.slice(0, hashIndex);\n const hash = hashIndex === -1 ? '' : endpoint.slice(hashIndex);\n const separator = path.includes('?') ? '&' : '?';\n\n return `${path}${separator}${query}${hash}`;\n}\n\nfunction normalizeHeaders(\n headers: SearchRequestOptions['headers'] | undefined\n): Record<string, string> {\n if (!isRecord(headers)) {\n return {};\n }\n\n const normalizedHeaders: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n normalizedHeaders[key] = String(value);\n }\n\n return normalizedHeaders;\n}\n\nfunction normalizeBody(\n body: SearchRequestOptions['body'] | undefined\n): Record<string, unknown> | undefined {\n return isRecord(body) ? body : undefined;\n}\n\nexport class AISearchClient {\n activeRequests: Map<string, RequestState> = new Map();\n baseUrl: string;\n\n constructor(baseUrl: string) {\n this.baseUrl = baseUrl.replace(/\\/$/, ''); // Remove trailing slash\n }\n\n private request(\n body: Record<string, unknown>,\n operation: RequestOperation,\n signal?: AbortSignal,\n requestOptions?: SearchRequestOptions\n ): Promise<Response> {\n const sourceHeader = operation === 'search' ? 'snippet-search' : 'snippet-chat-completions';\n const url = buildRequestUrl(`${this.baseUrl}/${operation}`, requestOptions?.queryParams);\n\n return fetch(url, {\n method: 'POST',\n body: JSON.stringify(deepMergeRecords(normalizeBody(requestOptions?.body), body)),\n headers: {\n ...normalizeHeaders(requestOptions?.headers),\n 'Content-Type': 'application/json',\n Accept: body.stream ? 'text/event-stream' : 'application/json',\n 'cf-ai-search-source': sourceHeader,\n },\n signal,\n });\n }\n\n /**\n * Performs a search query with optional streaming\n */\n async search(query: string, options: Omit<SearchOptions, 'query'> = {}): Promise<SearchResult[]> {\n const requestId = this.generateRequestId();\n const controller = new AbortController();\n const signal = options.signal || controller.signal;\n\n this.registerRequest(requestId, controller);\n\n try {\n const response = await this.request(\n {\n messages: [{ role: 'user', content: query }],\n stream: false,\n ai_search_options: {\n retrieval: {\n metadata_only: true,\n max_num_results: options.maxResults ?? 30,\n },\n },\n },\n 'search',\n signal,\n options.request\n );\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n if (!response.body) {\n throw new Error('Response body is empty');\n }\n const result: AISearchAPIResponse = await response.json();\n if (result.success && result.result) {\n return result.result.chunks.map(\n (chunk) =>\n ({\n type: 'result',\n id: chunk.id,\n title: decodeHTMLEntities(chunk.item.metadata?.title),\n description: chunk.item.metadata?.description\n ? decodeHTMLEntities(chunk.item.metadata?.description)\n : '',\n timestamp: chunk.item.timestamp ?? undefined,\n url: chunk.item.key,\n image: chunk.item.metadata?.image || undefined,\n metadata: {\n ...(chunk.item.metadata as unknown as Record<string, unknown>),\n instance_id: chunk.instance_id,\n },\n }) satisfies SearchResult\n );\n }\n\n if (result.success === false) {\n // @ts-expect-error need to check this\n throw new Error(result.error);\n }\n throw new Error('Unknown error');\n } finally {\n this.unregisterRequest(requestId);\n }\n }\n\n async *searchStream(\n query: string,\n options: Omit<SearchOptions, 'query'> = {}\n ): AsyncGenerator<SearchResult | SearchError, void, undefined> {\n const requestId = this.generateRequestId();\n const controller = new AbortController();\n const signal = options.signal || controller.signal;\n\n this.registerRequest(requestId, controller);\n\n const response = await this.request(\n {\n messages: [{ role: 'user', content: query }],\n stream: true,\n ...(options.maxResults !== undefined && {\n max_num_results: options.maxResults,\n }),\n },\n 'ai-search',\n signal,\n options.request\n );\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n if (!response.body) {\n throw new Error('Response body is empty');\n }\n\n let chunks = '';\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n const chunk = decoder.decode(value, { stream: true });\n chunks += chunk;\n }\n\n const result: string = chunks\n .replaceAll('data: ', '')\n .trim()\n .split('\\n\\n')\n .map((chunk) => {\n return JSON.parse(chunk) as { response: string };\n })\n .map((chunk) => chunk.response)\n .join('');\n\n yield {\n type: 'result',\n id: '',\n title: '',\n description: result,\n url: '',\n metadata: {},\n };\n }\n\n async *chat(query: string, options?: ChatOptions): AsyncGenerator<ChatTypes, void, undefined> {\n const controller = new AbortController();\n const signal = options?.signal || controller.signal;\n // const prevQueries: string[] = JSON.parse(localStorage.getItem('prevQueries') || '[]');\n // prevQueries.push(query);\n // localStorage.setItem('prevQueries', JSON.stringify(prevQueries));\n const response = await this.request(\n {\n messages: [{ role: 'user', content: query }],\n stream: false,\n },\n 'chat/completions',\n signal\n );\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n if (!response.body) {\n throw new Error('Response body is empty');\n }\n const result = (await response.json()) as {\n choices: {\n message: {\n content: string;\n };\n }[];\n };\n\n yield {\n type: 'text',\n message: result.choices.map((choice) => choice.message.content).join(''),\n } satisfies ChatTextResponse;\n\n // for (const item of result.data) {\n // yield {\n // type: 'result',\n // id: item.filename,\n // title: item.filename,\n // description: item.content.text,\n // url: item.filename,\n // metadata: item.attributes\n // ,\n // } satisfies ChatResult;\n // }\n\n return;\n }\n\n /**\n * Cancels an active request by ID\n */\n cancelRequest(requestId: string): void {\n const request = this.activeRequests.get(requestId);\n if (request) {\n request.controller.abort();\n this.unregisterRequest(requestId);\n }\n }\n\n /**\n * Cancels all active requests\n */\n cancelAllRequests(): void {\n for (const [requestId] of this.activeRequests) {\n this.cancelRequest(requestId);\n }\n }\n\n /**\n * Register an active request\n */\n private registerRequest(id: string, controller: AbortController): void {\n this.activeRequests.set(id, {\n id,\n controller,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Unregister a completed request\n */\n private unregisterRequest(id: string): void {\n this.activeRequests.delete(id);\n }\n\n /**\n * Generate unique request ID\n */\n private generateRequestId(): string {\n return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n}\n","/**\n * Cloudflare AI Search branding constants\n */\n\nexport const CLOUDFLARE_LOGO_SVG = `<svg width=\"32\" height=\"10\" viewBox=\"0 0 412 186\" xmlns=\"http://www.w3.org/2000/svg\" aria-label=\"Cloudflare\" role=\"img\">\n <path fill=\"#f38020\" d=\"m280.8395,183.31456c11,-26 -4,-38 -19,-38l-148,-2c-4,0 -4,-6 1,-7l150,-2c17,-1 37,-15 43,-33c0,0 10,-21 9,-24a97,97 0 0 0 -187,-11c-38,-25 -78,9 -69,46c-48,3 -65,46 -60,72c0,1 1,2 3,2l274,0c1,0 3,-1 3,-3z\"/>\n <path fill=\"#faae40\" d=\"m330.8395,81.31456c-4,0 -6,-1 -7,1l-5,21c-5,16 3,30 20,31l32,2c4,0 4,6 -1,7l-33,1c-36,4 -46,39 -46,39c0,2 0,3 2,3l113,0l3,-2a81,81 0 0 0 -78,-103\"/>\n</svg>`;\n\nexport const CLOUDFLARE_SEARCH_URL = 'https://workers.cloudflare.com/product/ai-search';\n\nexport const POWERED_BY_BRANDING = `Powered by <a href=\"${CLOUDFLARE_SEARCH_URL}\" target=\"_blank\" rel=\"noopener noreferrer\">Cloudflare AI Search ${CLOUDFLARE_LOGO_SVG}</a>`;\n","/**\n * Chat mode specific styles\n */\n\nexport const chatStyles = `\n/* Chat container */\n.chat-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow-y: auto;\n}\n\n/* Messages area */\n.chat-messages {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: var(--search-snippet-spacing-md);\n display: flex;\n flex-direction: column;\n gap: var(--search-snippet-spacing-md);\n}\n\n.chat-messages::-webkit-scrollbar {\n width: 8px;\n}\n\n.chat-messages::-webkit-scrollbar-track {\n background: var(--search-snippet-surface);\n}\n\n.chat-messages::-webkit-scrollbar-thumb {\n background: var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n}\n\n.chat-messages::-webkit-scrollbar-thumb:hover {\n background: var(--search-snippet-text-secondary);\n}\n\n/* Message */\n.chat-message {\n display: flex;\n gap: var(--search-snippet-spacing-sm);\n max-width: 85%;\n animation: slideIn var(--search-snippet-animation-duration) ease-out;\n}\n\n@keyframes slideIn {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.chat-message-user {\n align-self: flex-end;\n flex-direction: row-reverse;\n}\n\n.chat-message-assistant {\n align-self: flex-start;\n}\n\n.chat-message-system {\n align-self: center;\n max-width: 100%;\n}\n\n/* Message avatar */\n.chat-message-avatar {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: var(--search-snippet-font-size-sm);\n font-weight: var(--search-snippet-font-weight-bold);\n background: var(--search-snippet-primary-color);\n color: white;\n}\n\n.chat-message-assistant .chat-message-avatar {\n background: var(--search-snippet-surface);\n color: var(--search-snippet-text-color);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n/* Message content */\n.chat-message-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: var(--search-snippet-spacing-xs);\n max-width: 100%;\n}\n\n.chat-message-content ol, .chat-message-content ul {\n margin-inline-start: 16px;\n}\n\n.chat-message-content ol li, .chat-message-content ul li {\n padding-inline-start: 0;\n}\n\n.chat-message-bubble {\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n border-radius: var(--search-snippet-border-radius);\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.chat-message-user .chat-message-bubble {\n background: var(--search-snippet-user-message-bg);\n color: var(--search-snippet-user-message-text);\n border-top-right-radius: var(--search-snippet-spacing-xs);\n}\n\n.chat-message-assistant .chat-message-bubble {\n background: var(--search-snippet-assistant-message-bg);\n color: var(--search-snippet-assistant-message-text);\n border-top-left-radius: var(--search-snippet-spacing-xs);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n.chat-message-system .chat-message-bubble {\n background: var(--search-snippet-system-message-bg);\n color: var(--search-snippet-system-message-text);\n text-align: center;\n font-size: var(--search-snippet-font-size-sm);\n padding: var(--search-snippet-spacing-xs) var(--search-snippet-spacing-md);\n}\n\n.chat-message-text {\n font-size: var(--search-snippet-font-size-base);\n line-height: 1.5;\n white-space: wrap;\n}\n.chat-message-text li{\n padding-inline-start: var(--search-snippet-spacing-md);\n}\n\n.chat-message-metadata {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n}\n\n.chat-message-user .chat-message-metadata {\n justify-content: flex-end;\n}\n\n.chat-message-time {\n opacity: 0.7;\n}\n\n/* Streaming indicator */\n.chat-streaming {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-xs);\n}\n\n.chat-streaming-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: currentColor;\n animation: pulse 1.4s ease-in-out infinite;\n}\n\n.chat-streaming-dot:nth-child(2) {\n animation-delay: 0.2s;\n}\n\n.chat-streaming-dot:nth-child(3) {\n animation-delay: 0.4s;\n}\n\n@keyframes pulse {\n 0%, 80%, 100% {\n opacity: 0.3;\n transform: scale(0.8);\n }\n 40% {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n.chat-streaming .loading-text {\n margin-left: var(--search-snippet-spacing-xs);\n}\n\n/* Input area */\n.chat-input-area {\n padding: var(--search-snippet-spacing-md);\n border-top: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n background: var(--search-snippet-surface);\n}\n\n.chat-input-wrapper {\n display: flex;\n gap: var(--search-snippet-spacing-sm);\n align-items: flex-end;\n}\n\n.chat-input {\n flex: 1;\n min-height: var(--search-snippet-input-height);\n max-height: 120px;\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n line-height: var(--search-snippet-line-height);\n color: var(--search-snippet-text-color);\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n outline: none;\n resize: vertical;\n transition: var(--search-snippet-transition);\n}\n\n.chat-input:focus {\n border-color: var(--search-snippet-primary-color);\n box-shadow: 0 0 0 3px var(--search-snippet-focus-ring);\n}\n\n.chat-input::placeholder {\n color: var(--search-snippet-text-secondary);\n}\n\n.chat-input:disabled {\n background: var(--search-snippet-surface);\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.chat-send-button {\n flex-shrink: 0;\n height: var(--search-snippet-input-height);\n padding: 0 var(--search-snippet-spacing-lg);\n}\n\n.chat-send-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* Empty chat state */\n.chat-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--search-snippet-spacing-xxl);\n gap: var(--search-snippet-spacing-md);\n color: var(--search-snippet-text-secondary);\n text-align: center;\n height: 100%;\n}\n\n.chat-empty-icon {\n width: 64px;\n height: 64px;\n opacity: 0.5;\n}\n\n.chat-empty-title {\n font-size: var(--search-snippet-font-size-lg);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n}\n\n.chat-empty-description {\n font-size: var(--search-snippet-font-size-sm);\n}\n\n/* Code blocks in messages */\n.chat-message-bubble pre {\n background: var(--search-snippet-surface);\n padding: var(--search-snippet-spacing-sm);\n border-radius: var(--search-snippet-border-radius);\n overflow-x: auto;\n font-family: var(--search-snippet-font-family-mono);\n font-size: var(--search-snippet-font-size-sm);\n margin: var(--search-snippet-spacing-xs) 0;\n}\n\n.chat-message-bubble code {\n font-family: var(--search-snippet-font-family-mono);\n font-size: 0.9em;\n background: var(--search-snippet-surface);\n padding: 2px 4px;\n border-radius: var(--search-snippet-border-radius);\n}\n\n.chat-message-bubble pre code {\n background: none;\n padding: 0;\n}\n\n/* Links in messages */\n.chat-message-bubble a {\n color: var(--search-snippet-primary-color);\n text-decoration: underline;\n}\n\n.chat-message-bubble a:hover {\n text-decoration: none;\n}\n`;\n","/**\n * CSS Theme with comprehensive CSS custom properties\n */\n\nexport const baseStyles = `\n:host {\n /* Colors - Light Mode */\n --search-snippet-primary-color: #2563eb;\n --search-snippet-primary-hover: #0f51dfff;\n --search-snippet-background: #ffffff;\n --search-snippet-surface: #f8f9fa;\n --search-snippet-text-color: #212529;\n --search-snippet-text-secondary: #6c757d;\n --search-snippet-text-description: #495057;\n --search-snippet-border-color: #dee2e6;\n --search-snippet-hover-background: #f1f3f5;\n --search-snippet-focus-ring: #0066cc40;\n --search-snippet-error-color: #dc3545;\n --search-snippet-error-background: #f8d7da;\n --search-snippet-success-color: #28a745;\n --search-snippet-success-background: #d4edda;\n --search-snippet-warning-color: #ffc107;\n --search-snippet-warning-background: #fff3cd;\n \n /* Message Colors */\n --search-snippet-user-message-bg: #0066cc;\n --search-snippet-user-message-text: #ffffff;\n --search-snippet-assistant-message-bg: #f1f3f5;\n --search-snippet-assistant-message-text: #212529;\n --search-snippet-system-message-bg: #fff3cd;\n --search-snippet-system-message-text: #856404;\n \n /* Typography */\n --search-snippet-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', \n 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', \n 'Segoe UI Emoji', 'Segoe UI Symbol';\n --search-snippet-font-family-mono: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;\n --search-snippet-font-size-base: 14px;\n --search-snippet-font-size-sm: 12px;\n --search-snippet-font-size-lg: 16px;\n --search-snippet-font-size-xl: 18px;\n --search-snippet-line-height: 1.5;\n --search-snippet-font-weight-normal: 400;\n --search-snippet-font-weight-medium: 500;\n --search-snippet-font-weight-bold: 600;\n \n /* Spacing */\n --search-snippet-spacing-xs: 4px;\n --search-snippet-spacing-sm: 8px;\n --search-snippet-spacing-md: 12px;\n --search-snippet-spacing-lg: 16px;\n --search-snippet-spacing-xl: 24px;\n --search-snippet-spacing-xxl: 32px;\n \n /* Sizing */\n --search-snippet-width: 100%;\n --search-snippet-max-width: 100%;\n --search-snippet-min-width: 320px;\n --search-snippet-max-height: 600px;\n --search-snippet-input-height: 44px;\n --search-snippet-button-height: 36px;\n --search-snippet-icon-size: 20px;\n \n /* Border */\n --search-snippet-border-width: 1px;\n --search-snippet-border-radius: 18px;\n \n /* Shadows */\n --search-snippet-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n --search-snippet-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n --search-snippet-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);\n --search-snippet-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.2);\n --search-snippet-shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06);\n \n /* Animation */\n --search-snippet-transition-fast: 150ms ease;\n --search-snippet-transition: 200ms ease;\n --search-snippet-transition-slow: 300ms ease;\n --search-snippet-animation-duration: 0.2s;\n \n /* Z-index */\n --search-snippet-z-dropdown: 1000;\n --search-snippet-z-modal: 1050;\n --search-snippet-z-popover: 1060;\n --search-snippet-z-tooltip: 1070;\n \n /* Layout */\n display: block;\n width: var(--search-snippet-width);\n max-width: var(--search-snippet-max-width);\n min-width: var(--search-snippet-min-width);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n line-height: var(--search-snippet-line-height);\n color: var(--search-snippet-text-color);\n\n\n /* Search */\n --search-snippet-icon-size: 20px;\n --search-snippet-icon-margin-left: 6px;\n --search-snippet-result-item-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n\n /* Chat Bubble */\n --chat-bubble-button-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);\n --chat-bubble-window-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);\n --chat-bubble-button-size: 60px;\n --chat-bubble-button-radius: 50%;\n --chat-bubble-button-icon-size: 28px;\n --chat-bubble-button-icon-color: white;\n --chat-bubble-button-bottom: 20px;\n --chat-bubble-button-right: 20px;\n --chat-bubble-button-z-index: 9999;\n --chat-bubble-position: fixed;\n\n\n}\n\n:host(:not([theme=\"dark\"])) {\n /* Colors - Light Mode */\n --search-snippet-primary-color: #2563eb;\n --search-snippet-primary-hover: #0f51dfff;\n --search-snippet-background: #ffffff;\n --search-snippet-surface: #f8f9fa;\n --search-snippet-text-color: #212529;\n --search-snippet-text-secondary: #6c757d;\n --search-snippet-text-description: #495057;\n --search-snippet-border-color: #dee2e6;\n --search-snippet-hover-background: #f1f3f5;\n --search-snippet-focus-ring: #0066cc40;\n --search-snippet-error-color: #dc3545;\n --search-snippet-error-background: #f8d7da;\n --search-snippet-success-color: #28a745;\n --search-snippet-success-background: #d4edda;\n --search-snippet-warning-color: #ffc107;\n --search-snippet-warning-background: #fff3cd;\n \n /* Message Colors */\n --search-snippet-user-message-bg: #0066cc;\n --search-snippet-user-message-text: #ffffff;\n --search-snippet-assistant-message-bg: #f1f3f5;\n --search-snippet-assistant-message-text: #212529;\n --search-snippet-system-message-bg: #fff3cd;\n --search-snippet-system-message-text: #856404;\n}\n\n/* Dark Mode */\n@media (prefers-color-scheme: dark) {\n :host(:not([theme=\"light\"])) {\n --search-snippet-primary-color: #2563eb;\n --search-snippet-primary-hover: #0f51dfff;\n --search-snippet-background: #1a1b1e;\n --search-snippet-surface: #25262b;\n --search-snippet-text-color: #c1c2c5;\n --search-snippet-text-secondary: #909296;\n --search-snippet-text-description: #adb5bd;\n --search-snippet-border-color: #373a40;\n --search-snippet-hover-background: #2c2e33;\n --search-snippet-focus-ring: #4dabf740;\n --search-snippet-error-color: #ff6b6b;\n --search-snippet-error-background: #3d1f1f;\n --search-snippet-success-color: #51cf66;\n --search-snippet-success-background: #1f3d24;\n --search-snippet-warning-color: #ffd43b;\n --search-snippet-warning-background: #3d3419;\n \n --search-snippet-user-message-bg: #4dabf7;\n --search-snippet-user-message-text: #1a1b1e;\n --search-snippet-assistant-message-bg: #2c2e33;\n --search-snippet-assistant-message-text: #c1c2c5;\n --search-snippet-system-message-bg: #3d3419;\n --search-snippet-system-message-text: #ffd43b;\n color-scheme: dark;\n }\n}\n\n/* Auto theme support */\n:host([theme=\"light\"]) {\n color-scheme: light;\n}\n\n\n/* Base reset */\n* {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n/* Container */\n.container {\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n box-shadow: var(--search-snippet-shadow);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n/* Header */\n.header {\n padding: var(--search-snippet-spacing-md);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n background: var(--search-snippet-surface);\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--search-snippet-spacing-md);\n}\n\n.header-title {\n font-size: var(--search-snippet-font-size-lg);\n font-weight: var(--search-snippet-font-weight-bold);\n color: var(--search-snippet-text-color);\n}\n\n/* Input */\n.input-wrapper {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n}\n\n.input {\n width: 100%;\n height: var(--search-snippet-input-height);\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n line-height: var(--search-snippet-line-height);\n color: var(--search-snippet-text-color);\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n outline: none;\n transition: var(--search-snippet-transition);\n}\n\n.input:focus {\n border-color: var(--search-snippet-primary-color);\n box-shadow: 0 0 0 3px var(--search-snippet-focus-ring);\n}\n\n.input::placeholder {\n color: var(--search-snippet-text-secondary);\n}\n\n.input:disabled {\n background: var(--search-snippet-surface);\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n/* Button */\n.button {\n height: var(--search-snippet-button-height);\n padding: 0 var(--search-snippet-spacing-lg);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: #ffffff;\n background: var(--search-snippet-primary-color);\n border: none;\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n outline: none;\n transition: var(--search-snippet-transition);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-sm);\n white-space: nowrap;\n}\n\n.button:hover:not(:disabled) {\n background: var(--search-snippet-primary-hover);\n}\n\n.button:focus-visible {\n box-shadow: 0 0 0 3px var(--search-snippet-focus-ring);\n}\n\n.button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.button-secondary {\n background: var(--search-snippet-surface);\n color: var(--search-snippet-text-color);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n.button-secondary:hover:not(:disabled) {\n background: var(--search-snippet-hover-background);\n}\n\n/* Content area */\n.content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: var(--search-snippet-spacing-md);\n}\n\n/* Scrollbar styling */\n.content::-webkit-scrollbar {\n width: 8px;\n}\n\n.content::-webkit-scrollbar-track {\n background: var(--search-snippet-surface);\n}\n\n.content::-webkit-scrollbar-thumb {\n background: var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n}\n\n.content::-webkit-scrollbar-thumb:hover {\n background: var(--search-snippet-text-secondary);\n}\n\n/* Loading spinner */\n.loading {\n display: inline-block;\n width: var(--search-snippet-icon-size);\n height: var(--search-snippet-icon-size);\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: spin 0.6s linear infinite;\n}\n\n@keyframes spin {\n to { transform: rotate(360deg); }\n}\n\n/* Loading message animation */\n@keyframes loading-message-in {\n from {\n opacity: 0;\n transform: translateY(8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.loading-text {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n}\n\n.loading-text-animate {\n animation: loading-message-in 0.3s ease-out;\n}\n\n/* Error message */\n.error {\n padding: var(--search-snippet-spacing-md);\n color: var(--search-snippet-error-color);\n background: var(--search-snippet-error-background);\n border-radius: var(--search-snippet-border-radius);\n font-size: var(--search-snippet-font-size-sm);\n}\n\n/* Empty state */\n.empty {\n padding: var(--search-snippet-spacing-xl);\n text-align: center;\n color: var(--search-snippet-text-secondary);\n}\n\n/* Accessibility */\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n}\n\n/* Focus visible polyfill */\n.focus-visible:focus {\n outline: 2px solid var(--search-snippet-primary-color);\n outline-offset: 2px;\n}\n\n/* Powered by branding - block style (for sidebars) */\n.powered-by {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-xs);\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n background: var(--search-snippet-surface);\n border-top: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n margin-top: auto;\n flex-shrink: 0;\n}\n\n.powered-by svg {\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n}\n\n.powered-by a,\n.powered-by-inline a {\n color: var(--search-snippet-text-secondary);\n text-decoration: none;\n transition: color var(--search-snippet-transition-fast);\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.powered-by a:hover,\n.powered-by-inline a:hover {\n color: var(--search-snippet-primary-color);\n}\n\n/* Powered by branding - inline style (for headers/subtle placement) */\n.powered-by-inline {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n padding: var(--search-snippet-spacing-xs) 0;\n text-align: center;\n}\n`;\n","/**\n * Converts markdown text to HTML\n * Supports: headers, bold, italic, links, lists, code blocks, inline code, blockquotes, and horizontal rules\n */\nexport function markdownToHtml(markdown: string): string {\n let html = markdown;\n\n // Escape HTML characters first to prevent XSS\n html = escapeHtml(html);\n\n // Process code blocks first (to protect from other transformations)\n html = html.replace(/```([\\s\\S]*?)```/g, (_, code) => `<pre><code>${code.trim()}</code></pre>`);\n\n // Split into lines for block-level processing\n const lines = html.split('\\n');\n const processedLines: string[] = [];\n let inList = false;\n let listType = '';\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Headers (h1-h6)\n const headerMatch = line.match(/^(#{1,6})\\s+(.+)$/);\n if (headerMatch) {\n const level = headerMatch[1].length;\n const content = headerMatch[2];\n processedLines.push(`<h${level}>${processInlineMarkdown(content)}</h${level}>`);\n continue;\n }\n\n // Horizontal rule\n if (line.match(/^---+$/)) {\n processedLines.push('<hr />');\n continue;\n }\n\n // Blockquote\n if (line.match(/^>\\s+/)) {\n const content = line.replace(/^>\\s+/, '');\n processedLines.push(`<blockquote>${processInlineMarkdown(content)}</blockquote>`);\n continue;\n }\n\n // Unordered list\n const ulMatch = line.match(/^[-*]\\s+(.+)$/);\n if (ulMatch) {\n if (!inList || listType !== 'ul') {\n if (inList) processedLines.push(`</${listType}>`);\n processedLines.push('<ul>');\n inList = true;\n listType = 'ul';\n }\n processedLines.push(`<li>${processInlineMarkdown(ulMatch[1])}</li>`);\n continue;\n }\n\n // Ordered list\n const olMatch = line.match(/^\\d+\\.\\s+(.+)$/);\n if (olMatch) {\n if (!inList || listType !== 'ol') {\n if (inList) processedLines.push(`</${listType}>`);\n processedLines.push('<ol>');\n inList = true;\n listType = 'ol';\n }\n processedLines.push(`<li>${processInlineMarkdown(olMatch[1])}</li>`);\n continue;\n }\n\n // Close list if we're no longer in one\n if (inList) {\n processedLines.push(`</${listType}>`);\n inList = false;\n listType = '';\n }\n\n // Empty line\n if (line.trim() === '') {\n processedLines.push('<br />');\n continue;\n }\n\n // Regular paragraph\n processedLines.push(`<p>${processInlineMarkdown(line)}</p>`);\n }\n\n // Close any open list\n if (inList) {\n processedLines.push(`</${listType}>`);\n }\n\n return processedLines.join('\\n');\n}\n\n/**\n * Process inline markdown elements (bold, italic, links, inline code)\n */\nfunction processInlineMarkdown(text: string): string {\n let result = text;\n\n // Inline code (before other inline elements)\n result = result.replace(/`([^`]+)`/g, '<code>$1</code>');\n\n // Bold and italic (***text***)\n result = result.replace(/\\*\\*\\*(.+?)\\*\\*\\*/g, '<strong><em>$1</em></strong>');\n result = result.replace(/___(.+?)___/g, '<strong><em>$1</em></strong>');\n\n // Bold (**text** or __text__)\n result = result.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>');\n result = result.replace(/__(.+?)__/g, '<strong>$1</strong>');\n\n // Italic (*text* or _text_)\n result = result.replace(/\\*(.+?)\\*/g, '<em>$1</em>');\n result = result.replace(/_(.+?)_/g, '<em>$1</em>');\n\n // Links [text](url)\n result = result.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n '<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>'\n );\n\n return result;\n}\n\n/**\n * Escape HTML characters to prevent XSS\n */\nfunction escapeHtml(text: string): string {\n const htmlEntities: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n };\n\n return text.replace(/[&<>\"']/g, (char) => htmlEntities[char] || char);\n}\n","/**\n * ChatView Component\n * Handles chat interface with streaming support\n */\n\nimport type { AISearchClient } from '../api/ai-search.ts';\nimport { mergeTranslations } from '../i18n/index.ts';\nimport type { SearchSnippetProps } from '../types/index.ts';\nimport {\n createCustomEvent,\n escapeHTML,\n formatTimestamp,\n generateId,\n LOADING_MESSAGE_INTERVAL_MS,\n} from '../utils/index.ts';\nimport { markdownToHtml } from '../utils/markdown.ts';\nexport interface Message {\n id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n timestamp: number;\n metadata?: Record<string, unknown>;\n}\nexport class ChatView {\n private container: HTMLElement;\n private client: AISearchClient;\n private props: SearchSnippetProps;\n private translations: ReturnType<typeof mergeTranslations>;\n private inputElement: HTMLTextAreaElement | null = null;\n private messagesContainer: HTMLElement | null = null;\n private sendButton: HTMLButtonElement | null = null;\n private messages: Message[] = [];\n private isStreaming = false;\n private currentStreamingMessageId: string | null = null;\n private loadingMessageInterval: ReturnType<typeof setInterval> | null = null;\n private loadingMessageIndex = 0;\n\n // Event handler references for cleanup\n private handleInputResize: ((e: Event) => void) | null = null;\n private handleInputKeydown: ((e: KeyboardEvent) => void) | null = null;\n private handleSendClick: (() => void) | null = null;\n\n constructor(container: HTMLElement, client: AISearchClient, props: SearchSnippetProps) {\n this.container = container;\n this.client = client;\n this.props = props;\n this.translations = mergeTranslations(props.translations);\n\n this.render();\n this.attachEventListeners();\n }\n\n /**\n * Render the chat interface\n */\n private render(): void {\n const t = this.translations;\n this.container.innerHTML = `\n <div class=\"chat-container\">\n <div class=\"chat-messages\">\n ${this.renderEmptyStateHTML()}\n </div>\n <div class=\"chat-input-area\">\n <div class=\"chat-input-wrapper\">\n <textarea\n class=\"chat-input\"\n placeholder=\"${escapeHTML(this.props.placeholder || t.chatPlaceholder)}\"\n aria-label=\"${escapeHTML(t.chatInputAriaLabel)}\"\n style=\"height: 40px;\"\n rows=\"1\"\n ></textarea>\n <button class=\"button chat-send-button\" aria-label=\"${escapeHTML(t.sendButtonAriaLabel)}\">\n <span>${escapeHTML(t.sendButtonLabel)}</span>\n </button>\n </div>\n </div>\n </div>\n `;\n\n this.messagesContainer = this.container.querySelector('.chat-messages');\n this.inputElement = this.container.querySelector('.chat-input');\n this.sendButton = this.container.querySelector('.chat-send-button');\n }\n\n private renderEmptyStateHTML(): string {\n const t = this.translations;\n return `\n <div class=\"chat-empty\">\n <svg class=\"chat-empty-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n <div class=\"chat-empty-title\">${escapeHTML(t.chatEmptyTitle)}</div>\n <div class=\"chat-empty-description\">\n ${escapeHTML(t.chatEmptyDescription)}\n </div>\n </div>\n `;\n }\n\n /**\n * Attach event listeners\n */\n private attachEventListeners(): void {\n if (!this.inputElement || !this.sendButton) return;\n\n // Auto-resize textarea\n this.handleInputResize = (e: Event) => {\n const target = e.target as HTMLTextAreaElement;\n target.style.height = 'auto';\n target.style.height = `${target.scrollHeight}px`;\n };\n this.inputElement.addEventListener('input', this.handleInputResize);\n\n // Enter to send (Shift+Enter for new line)\n this.handleInputKeydown = (e: KeyboardEvent) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n this.handleSendMessage();\n }\n };\n this.inputElement.addEventListener('keydown', this.handleInputKeydown);\n\n // Send button click\n this.handleSendClick = () => {\n this.handleSendMessage();\n };\n this.sendButton.addEventListener('click', this.handleSendClick);\n }\n\n /**\n * Handle send message\n */\n private async handleSendMessage(): Promise<void> {\n if (!this.inputElement || this.isStreaming) return;\n\n const content = this.inputElement.value.trim();\n if (content.length === 0) return;\n\n // Clear input\n this.inputElement.value = '';\n this.inputElement.style.height = 'auto';\n\n // Send message\n await this.sendMessage(content);\n }\n\n /**\n * Send a message\n */\n public async sendMessage(content: string): Promise<void> {\n // Add user message\n const userMessage: Message = {\n id: generateId('msg'),\n role: 'user',\n content,\n timestamp: Date.now(),\n };\n\n this.addMessage(userMessage);\n this.renderMessages(true);\n this.setStreamingState(true);\n\n // Create placeholder for assistant response\n const assistantMessageId = generateId('msg');\n const assistantMessage: Message = {\n id: assistantMessageId,\n role: 'assistant',\n content: '',\n timestamp: Date.now(),\n };\n\n this.addMessage(assistantMessage);\n this.currentStreamingMessageId = assistantMessageId;\n this.renderMessages(true);\n\n try {\n // Stream the response\n const stream = this.client.chat(content);\n\n let fullContent = '';\n\n for await (const chunk of stream) {\n if (chunk.type === 'text' && chunk.message) {\n fullContent += chunk.message;\n this.updateStreamingMessage(assistantMessageId, fullContent);\n } else if (chunk.type === 'error') {\n this.showErrorInMessage(\n assistantMessageId,\n chunk.message || this.translations.unknownError\n );\n break;\n }\n // else if (chunk.type === 'done') {\n // break;\n // }\n }\n\n // Update final message\n const messageIndex = this.messages.findIndex((m) => m.id === assistantMessageId);\n if (messageIndex !== -1) {\n this.messages[messageIndex].content = fullContent;\n }\n\n // Emit message event\n this.container.dispatchEvent(createCustomEvent('message', { message: assistantMessage }));\n } catch (error) {\n this.showErrorInMessage(assistantMessageId, (error as Error).message);\n\n // Emit error event\n this.container.dispatchEvent(\n createCustomEvent('error', {\n error: {\n message: (error as Error).message,\n code: 'CHAT_ERROR',\n },\n })\n );\n } finally {\n this.setStreamingState(false);\n this.renderMessages();\n this.currentStreamingMessageId = null;\n }\n }\n\n /**\n * Add a message to the chat\n */\n private addMessage(message: Message): void {\n this.messages.push(message);\n this.renderMessages();\n }\n\n /**\n * Update streaming message content\n */\n private updateStreamingMessage(messageId: string, content: string): void {\n const messageIndex = this.messages.findIndex((m) => m.id === messageId);\n if (messageIndex !== -1) {\n this.messages[messageIndex].content = content;\n this.renderMessages(true);\n }\n }\n\n /**\n * Show error in message\n */\n private showErrorInMessage(messageId: string, error: string): void {\n const messageIndex = this.messages.findIndex((m) => m.id === messageId);\n if (messageIndex !== -1) {\n this.messages[messageIndex].content = `${this.translations.errorPrefix} ${error}`;\n this.renderMessages();\n }\n }\n\n /**\n * Render all messages\n */\n private renderMessages(isStreaming = false): void {\n if (!this.messagesContainer) return;\n\n if (this.messages.length === 0) {\n this.messagesContainer.innerHTML = this.renderEmptyStateHTML();\n return;\n }\n\n const messagesHTML = this.messages\n .map((message) =>\n this.renderMessage(message, isStreaming && message.id === this.currentStreamingMessageId)\n )\n .join('');\n\n this.messagesContainer.innerHTML = messagesHTML;\n\n // Scroll to bottom\n this.scrollToBottom();\n }\n\n /**\n * Render a single message\n */\n private renderMessage(message: Message, isStreaming = false): string {\n const t = this.translations;\n const roleClass = `chat-message-${message.role}`;\n const avatar = message.role === 'user' ? t.userAvatar : t.assistantAvatar;\n const loadingMessage = t.loadingMessages[this.loadingMessageIndex] ?? '';\n\n return `\n <div class=\"chat-message ${roleClass}\">\n <div class=\"chat-message-avatar\">${escapeHTML(avatar)}</div>\n <div class=\"chat-message-content\">\n <div class=\"chat-message-bubble\">\n ${message.content ? `<div class=\"chat-message-text\">${markdownToHtml(message.content)}</div>` : ''}\n ${isStreaming ? `<div class=\"chat-streaming\"><span class=\"chat-streaming-dot\"></span><span class=\"chat-streaming-dot\"></span><span class=\"chat-streaming-dot\"></span><span class=\"loading-text\">${escapeHTML(loadingMessage)}</span></div>` : ''}\n </div>\n <div class=\"chat-message-metadata\">\n <span class=\"chat-message-time\">${escapeHTML(formatTimestamp(message.timestamp, this.translations))}</span>\n </div>\n </div>\n </div>\n `;\n }\n\n /**\n * Scroll to bottom of messages\n */\n private scrollToBottom(): void {\n if (!this.messagesContainer) return;\n\n requestAnimationFrame(() => {\n if (this.messagesContainer) {\n this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;\n }\n });\n }\n\n /**\n * Set streaming state\n */\n private setStreamingState(streaming: boolean): void {\n this.isStreaming = streaming;\n\n if (this.inputElement) {\n this.inputElement.disabled = streaming;\n }\n\n if (this.sendButton) {\n this.sendButton.disabled = streaming;\n this.sendButton.innerHTML = streaming\n ? '<div class=\"loading\"></div>'\n : `<span>${escapeHTML(this.translations.sendButtonLabel)}</span>`;\n }\n\n if (streaming) {\n this.startLoadingMessages();\n } else {\n this.clearLoadingMessages();\n }\n }\n\n private startLoadingMessages(): void {\n // Guard against double-starting (e.g. setStreamingState(true) called twice\n // via setProps during an active stream).\n this.clearLoadingMessages();\n const messages = this.translations.loadingMessages;\n this.loadingMessageIndex = Math.floor(Math.random() * messages.length);\n this.loadingMessageInterval = setInterval(() => {\n const current = this.translations.loadingMessages;\n this.loadingMessageIndex = (this.loadingMessageIndex + 1) % current.length;\n if (this.isStreaming) {\n this.renderMessages(true);\n }\n }, LOADING_MESSAGE_INTERVAL_MS);\n }\n\n private clearLoadingMessages(): void {\n if (this.loadingMessageInterval) {\n clearInterval(this.loadingMessageInterval);\n this.loadingMessageInterval = null;\n }\n }\n\n /**\n * Get all messages\n */\n public getMessages(): Message[] {\n return [...this.messages];\n }\n\n /**\n * Clear all messages\n */\n public clearMessages(): void {\n this.messages = [];\n this.renderMessages();\n }\n\n /**\n * Set messages (for restoring history)\n */\n public setMessages(messages: Message[]): void {\n this.messages = [...messages];\n this.renderMessages();\n }\n\n /**\n * Update the props (e.g. placeholder / translations) and re-render.\n *\n * Safe to call at any time: existing messages and streaming state are\n * preserved; listeners on the old DOM are removed and re-attached to the\n * newly rendered elements.\n */\n public setProps(props: SearchSnippetProps): void {\n this.props = props;\n this.translations = mergeTranslations(props.translations);\n this.detachEventListeners();\n this.render();\n this.attachEventListeners();\n this.renderMessages(this.isStreaming);\n // Re-apply streaming UI state (disabled input, spinner button, loading\n // messages) since render() reset the DOM to its idle state.\n if (this.isStreaming) {\n this.setStreamingState(true);\n }\n }\n\n private detachEventListeners(): void {\n if (this.inputElement) {\n if (this.handleInputResize) {\n this.inputElement.removeEventListener('input', this.handleInputResize);\n }\n if (this.handleInputKeydown) {\n this.inputElement.removeEventListener('keydown', this.handleInputKeydown);\n }\n }\n if (this.sendButton && this.handleSendClick) {\n this.sendButton.removeEventListener('click', this.handleSendClick);\n }\n this.handleInputResize = null;\n this.handleInputKeydown = null;\n this.handleSendClick = null;\n }\n\n /**\n * Destroy and cleanup\n */\n public destroy(): void {\n this.clearLoadingMessages();\n\n if (this.isStreaming) {\n this.client.cancelAllRequests();\n }\n\n // Remove event listeners\n if (this.inputElement) {\n if (this.handleInputResize) {\n this.inputElement.removeEventListener('input', this.handleInputResize);\n }\n if (this.handleInputKeydown) {\n this.inputElement.removeEventListener('keydown', this.handleInputKeydown);\n }\n }\n\n if (this.sendButton && this.handleSendClick) {\n this.sendButton.removeEventListener('click', this.handleSendClick);\n }\n\n // Clear handler references\n this.handleInputResize = null;\n this.handleInputKeydown = null;\n this.handleSendClick = null;\n }\n}\n","/**\n * Chat Bubble Snippet\n * A floating chat widget that expands from a bubble button\n * Fixed position in bottom-right corner\n */\n\nimport type { AISearchClient } from '../api/ai-search.ts';\nimport { POWERED_BY_BRANDING } from '../constants.ts';\nimport { mergeTranslations, parseTranslationsAttribute, type Translations } from '../i18n/index.ts';\nimport { chatStyles } from '../styles/chat.ts';\nimport { baseStyles } from '../styles/theme.ts';\nimport type { SearchSnippetProps } from '../types/index.ts';\nimport {\n createClient,\n createCustomEvent,\n escapeHTML,\n parseAttribute,\n parseBooleanAttribute,\n} from '../utils/index.ts';\nimport type { Message } from './chat-view.ts';\nimport { ChatView } from './chat-view.ts';\n\nconst COMPONENT_NAME = 'chat-bubble-snippet';\n\nexport class ChatBubbleSnippet extends HTMLElement {\n private shadow: ShadowRoot;\n private client: AISearchClient | null = null;\n private chatView: ChatView | null = null;\n private container: HTMLElement | null = null;\n private isExpanded = false;\n private isMinimized = false;\n private translationsOverride: Translations | null = null;\n private resolvedTranslations = mergeTranslations(null);\n\n // Event handler references for cleanup\n private handleBubbleClick: (() => void) | null = null;\n private handleCloseClick: (() => void) | null = null;\n private handleMinimizeClick: (() => void) | null = null;\n private handleClearClick: (() => void) | null = null;\n\n static get observedAttributes() {\n return ['api-url', 'placeholder', 'theme', 'hide-branding', 'translations'] as const;\n }\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n this.syncTranslationsFromAttribute();\n this.render();\n this.initializeClient();\n this.dispatchEvent(createCustomEvent('ready', undefined));\n }\n\n disconnectedCallback(): void {\n this.cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'api-url') {\n this.initializeClient();\n } else if (name === 'theme') {\n // Theme changes are handled automatically by CSS :host([theme]) selectors\n this.updateTheme(newValue);\n } else if (name === 'translations') {\n this.syncTranslationsFromAttribute();\n if (this.isConnected) {\n this.rerenderAfterTranslationsChange();\n }\n }\n }\n\n /**\n * Get the current translations object.\n */\n public get translations(): Translations | null {\n return this.translationsOverride;\n }\n\n /**\n * Override any user-facing string. Omitted keys fall back to English defaults.\n */\n public set translations(value: Translations | null | undefined) {\n this.translationsOverride = value ?? null;\n this.resolvedTranslations = mergeTranslations(this.translationsOverride);\n if (this.isConnected) {\n this.rerenderAfterTranslationsChange();\n }\n }\n\n private syncTranslationsFromAttribute(): void {\n if (this.translationsOverride) {\n this.resolvedTranslations = mergeTranslations(this.translationsOverride);\n return;\n }\n const parsed = parseTranslationsAttribute(\n this.getAttribute('translations'),\n 'ChatBubbleSnippet'\n );\n this.resolvedTranslations = mergeTranslations(parsed);\n }\n\n private rerenderAfterTranslationsChange(): void {\n // Preserve expanded/minimized state across re-render. Also preserve the\n // existing ChatView (and thus any in-flight stream) by re-parenting its\n // container into the new shell rather than destroying it.\n const wasExpanded = this.isExpanded;\n const wasMinimized = this.isMinimized;\n this.removeEventListeners();\n\n const previousChatContent = this.chatView\n ? (this.shadow.querySelector('.chat-content') as HTMLElement | null)\n : null;\n if (previousChatContent?.parentNode) {\n previousChatContent.parentNode.removeChild(previousChatContent);\n }\n\n this.render();\n\n if (wasExpanded) {\n this.shadow.querySelector('.bubble-button')?.classList.add('hidden');\n this.shadow.querySelector('.chat-window')?.classList.add('expanded');\n if (wasMinimized) {\n this.shadow.querySelector('.chat-window')?.classList.add('minimized');\n }\n }\n\n const chatWindow = this.shadow.querySelector('.chat-window');\n if (this.chatView && previousChatContent && chatWindow) {\n const placeholder = chatWindow.querySelector('.chat-content');\n if (placeholder) {\n chatWindow.replaceChild(previousChatContent, placeholder);\n } else {\n chatWindow.appendChild(previousChatContent);\n }\n this.chatView.setProps(this.getProps());\n } else if (wasExpanded) {\n // No pre-existing view (e.g. missing api-url); render the fresh one.\n this.initializeChatView();\n }\n }\n\n private getProps(): SearchSnippetProps {\n const t = this.resolvedTranslations;\n return {\n apiUrl: parseAttribute(this.getAttribute('api-url'), ''),\n placeholder: parseAttribute(this.getAttribute('placeholder'), t.chatPlaceholder),\n theme: parseAttribute(this.getAttribute('theme'), 'auto') as 'light' | 'dark' | 'auto',\n hideBranding: parseBooleanAttribute(this.getAttribute('hide-branding'), false),\n translations: this.translationsOverride ?? undefined,\n };\n }\n\n private initializeClient(): void {\n const props = this.getProps();\n\n if (!props.apiUrl) {\n console.error('ChatBubbleSnippet: api-url attribute is required');\n this.client = null;\n return;\n }\n\n try {\n this.client = createClient(props.apiUrl);\n } catch (error) {\n console.error('ChatBubbleSnippet:', error);\n }\n }\n\n private render(): void {\n const style = document.createElement('style');\n style.textContent = `${baseStyles}\\n${chatStyles}\\n${this.getBubbleStyles()}`;\n\n this.container = document.createElement('div');\n this.container.className = 'chat-bubble-widget';\n this.container.innerHTML = this.getBaseHTML();\n\n this.shadow.innerHTML = '';\n this.shadow.appendChild(style);\n this.shadow.appendChild(this.container);\n\n this.attachEventListeners();\n }\n\n private getBubbleStyles(): string {\n return `\n .chat-bubble-widget {\n position: var(--chat-bubble-position);\n bottom: var(--chat-bubble-button-bottom);\n right: var(--chat-bubble-button-right);\n z-index: var(--chat-bubble-button-z-index);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n }\n\n .bubble-button {\n width: var(--chat-bubble-button-size);\n height: var(--chat-bubble-button-size);\n border-radius: var(--chat-bubble-button-radius);\n background: var(--search-snippet-primary-color);\n border: none;\n cursor: pointer;\n box-shadow: var(--chat-bubble-button-shadow);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.3s ease;\n position: relative;\n }\n\n .bubble-button:hover {\n background: var(--search-snippet-primary-hover);\n transform: scale(1.05);\n }\n\n .bubble-button svg {\n width: var(--chat-bubble-button-icon-size);\n height: var(--chat-bubble-button-icon-size);\n color: var(--chat-bubble-button-icon-color);\n }\n\n .bubble-button.hidden {\n opacity: 0;\n pointer-events: none;\n transform: scale(0);\n }\n\n .chat-window {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 380px;\n height: 500px;\n background: var(--search-snippet-background);\n border-radius: var(--search-snippet-border-radius);\n box-shadow: var(--chat-bubble-window-shadow);\n display: flex;\n flex-direction: column;\n opacity: 0;\n transform: scale(0.8) translateY(20px);\n transform-origin: bottom right;\n transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);\n pointer-events: none;\n overflow: hidden;\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n }\n\n .chat-window.expanded {\n opacity: 1;\n transform: scale(1) translateY(0);\n pointer-events: auto;\n }\n\n .chat-window.minimized {\n height: 58px;\n overflow: hidden;\n }\n\n .chat-header {\n background: var(--search-snippet-surface);\n padding: var(--search-snippet-spacing-md);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-shrink: 0;\n }\n\n .chat-header-title {\n font-weight: var(--search-snippet-font-weight-bold);\n color: var(--search-snippet-text-color);\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n font-size: var(--search-snippet-font-size-lg);\n }\n\n .chat-header-title svg {\n width: 20px;\n height: 20px;\n }\n\n .chat-header-actions {\n display: flex;\n gap: var(--search-snippet-spacing-xs);\n }\n\n .icon-button {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background var(--search-snippet-transition-fast);\n color: var(--search-snippet-text-color);\n }\n\n .icon-button:hover {\n background: var(--search-snippet-hover-background);\n }\n\n .icon-button svg {\n width: 18px;\n height: 18px;\n }\n\n .chat-content {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n @media (max-width: 480px) {\n .chat-window {\n width: calc(100vw - 40px);\n max-width: 400px;\n }\n }\n `;\n }\n\n private getBaseHTML(): string {\n const props = this.getProps();\n const t = this.resolvedTranslations;\n const brandingHTML = props.hideBranding\n ? ''\n : `<div class=\"powered-by\">${POWERED_BY_BRANDING}</div>`;\n\n return `\n <button class=\"bubble-button\" aria-label=\"${escapeHTML(t.openChatAriaLabel)}\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n </button>\n <div class=\"chat-window\">\n <div class=\"chat-header\">\n <div class=\"chat-header-title\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n <span>${escapeHTML(t.chatTitle)}</span>\n </div>\n <div class=\"chat-header-actions\">\n <button class=\"icon-button clear-button\" aria-label=\"${escapeHTML(t.clearHistoryAriaLabel)}\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"3 6 5 6 21 6\"></polyline>\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path>\n </svg>\n </button>\n <button class=\"icon-button minimize-button\" aria-label=\"${escapeHTML(t.minimizeAriaLabel)}\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\n </svg>\n </button>\n <button class=\"icon-button close-button\" aria-label=\"${escapeHTML(t.closeAriaLabel)}\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </div>\n </div>\n <div class=\"chat-content\"></div>\n ${brandingHTML}\n </div>\n `;\n }\n\n private attachEventListeners(): void {\n const bubbleButton = this.shadow.querySelector('.bubble-button');\n const closeButton = this.shadow.querySelector('.close-button');\n const minimizeButton = this.shadow.querySelector('.minimize-button');\n const clearButton = this.shadow.querySelector('.clear-button');\n\n this.handleBubbleClick = () => this.toggleChat();\n this.handleCloseClick = () => this.closeChat();\n this.handleMinimizeClick = () => this.toggleMinimize();\n this.handleClearClick = () => this.clearChat();\n\n bubbleButton?.addEventListener('click', this.handleBubbleClick);\n closeButton?.addEventListener('click', this.handleCloseClick);\n minimizeButton?.addEventListener('click', this.handleMinimizeClick);\n clearButton?.addEventListener('click', this.handleClearClick);\n }\n\n private removeEventListeners(): void {\n const bubbleButton = this.shadow.querySelector('.bubble-button');\n const closeButton = this.shadow.querySelector('.close-button');\n const minimizeButton = this.shadow.querySelector('.minimize-button');\n const clearButton = this.shadow.querySelector('.clear-button');\n\n if (this.handleBubbleClick) {\n bubbleButton?.removeEventListener('click', this.handleBubbleClick);\n }\n if (this.handleCloseClick) {\n closeButton?.removeEventListener('click', this.handleCloseClick);\n }\n if (this.handleMinimizeClick) {\n minimizeButton?.removeEventListener('click', this.handleMinimizeClick);\n }\n if (this.handleClearClick) {\n clearButton?.removeEventListener('click', this.handleClearClick);\n }\n\n // Clear handler references\n this.handleBubbleClick = null;\n this.handleCloseClick = null;\n this.handleMinimizeClick = null;\n this.handleClearClick = null;\n }\n\n private toggleChat(): void {\n this.isExpanded = !this.isExpanded;\n const bubbleButton = this.shadow.querySelector('.bubble-button');\n const chatWindow = this.shadow.querySelector('.chat-window');\n\n if (this.isExpanded) {\n bubbleButton?.classList.add('hidden');\n chatWindow?.classList.add('expanded');\n this.initializeChatView();\n } else {\n bubbleButton?.classList.remove('hidden');\n chatWindow?.classList.remove('expanded');\n }\n }\n\n private closeChat(): void {\n this.isExpanded = false;\n this.isMinimized = false;\n const bubbleButton = this.shadow.querySelector('.bubble-button');\n const chatWindow = this.shadow.querySelector('.chat-window');\n\n bubbleButton?.classList.remove('hidden');\n chatWindow?.classList.remove('expanded', 'minimized');\n }\n\n private toggleMinimize(): void {\n this.isMinimized = !this.isMinimized;\n const chatWindow = this.shadow.querySelector('.chat-window');\n\n if (this.isMinimized) {\n chatWindow?.classList.add('minimized');\n } else {\n chatWindow?.classList.remove('minimized');\n }\n }\n\n private initializeChatView(): void {\n if (this.chatView) return;\n\n const chatContent = this.shadow.querySelector('.chat-content') as HTMLElement;\n if (!chatContent) return;\n\n if (!this.client) {\n const t = this.resolvedTranslations;\n chatContent.innerHTML = `\n <div style=\"padding: 16px; color: var(--search-snippet-error-color, #ef4444); font-family: var(--search-snippet-font-family, sans-serif); font-size: var(--search-snippet-font-size-base, 14px);\">\n <strong>${escapeHTML(t.errorPrefix)}</strong> ${escapeHTML(t.missingApiUrlError)}\n </div>\n `;\n return;\n }\n\n const props = this.getProps();\n this.chatView = new ChatView(chatContent, this.client, props);\n }\n\n private updateTheme(theme: string | null): void {\n // CSS :host([theme]) selectors handle theming automatically\n // For 'auto' mode, remove the attribute to let @media (prefers-color-scheme) work\n const validTheme = theme === 'light' || theme === 'dark' ? theme : null;\n\n if (\n validTheme === null &&\n this.hasAttribute('theme') &&\n this.getAttribute('theme') !== 'auto'\n ) {\n this.removeAttribute('theme');\n }\n }\n\n private cleanup(): void {\n this.removeEventListeners();\n\n if (this.client) {\n this.client.cancelAllRequests();\n }\n\n if (this.chatView) {\n this.chatView.destroy();\n }\n }\n\n // Public API\n public clearChat(): void {\n this.chatView?.clearMessages();\n }\n\n public async sendMessage(content: string): Promise<void> {\n if (this.chatView) {\n await this.chatView.sendMessage(content);\n }\n }\n\n public getMessages(): Message[] {\n return this.chatView?.getMessages() || [];\n }\n}\n\n// Register the custom element\nif (!customElements.get(COMPONENT_NAME)) {\n customElements.define(COMPONENT_NAME, ChatBubbleSnippet);\n}\n","/**\n * Chat Page Snippet\n * A full-page chat interface with history support\n */\n\nimport type { AISearchClient } from '../api/ai-search.ts';\nimport { POWERED_BY_BRANDING } from '../constants.ts';\nimport { mergeTranslations, parseTranslationsAttribute, type Translations } from '../i18n/index.ts';\nimport { chatStyles } from '../styles/chat.ts';\nimport { baseStyles } from '../styles/theme.ts';\nimport type { SearchSnippetProps } from '../types/index.ts';\nimport {\n createClient,\n createCustomEvent,\n escapeHTML as escapeHTMLUtil,\n parseAttribute,\n parseBooleanAttribute,\n} from '../utils/index.ts';\nimport type { Message } from './chat-view.ts';\nimport { ChatView } from './chat-view.ts';\n\nconst COMPONENT_NAME = 'chat-page-snippet';\nconst STORAGE_KEY = 'chat-page-sessions';\n\ninterface ChatSession {\n id: string;\n title: string;\n messages: Message[];\n createdAt: number;\n updatedAt: number;\n /**\n * True while the session still carries the default (auto-generated) title.\n * Set to false once auto-titled from the first user message, or explicitly\n * renamed. Absent on sessions persisted before this field existed; those\n * are treated as having a default title iff the title string still matches\n * the current `newChatButton` translation (legacy behavior).\n */\n titleIsDefault?: boolean;\n}\n\nexport class ChatPageSnippet extends HTMLElement {\n private shadow: ShadowRoot;\n private client: AISearchClient | null = null;\n private chatView: ChatView | null = null;\n private container: HTMLElement | null = null;\n private sessions: ChatSession[] = [];\n private currentSessionId: string | null = null;\n private sidebarCollapsed = false;\n private translationsOverride: Translations | null = null;\n private resolvedTranslations = mergeTranslations(null);\n\n // Event handler references for cleanup\n private handleClearClick: (() => void) | null = null;\n private handleNewChatClick: (() => void) | null = null;\n private handleToggleSidebarClick: (() => void) | null = null;\n private handleChatListClick: ((e: Event) => void) | null = null;\n private handleMessageEvent: (() => void) | null = null;\n\n static get observedAttributes() {\n return ['api-url', 'placeholder', 'theme', 'hide-branding', 'translations'] as const;\n }\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n this.loadSessions();\n }\n\n connectedCallback(): void {\n this.syncTranslationsFromAttribute();\n this.render();\n this.initializeClient();\n this.setupView();\n this.dispatchEvent(createCustomEvent('ready', undefined));\n }\n\n disconnectedCallback(): void {\n this.saveCurrentSession();\n this.cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'api-url') {\n this.initializeClient();\n this.setupView();\n } else if (name === 'theme') {\n // Theme changes are handled automatically by CSS :host([theme]) selectors\n this.updateTheme(newValue);\n } else if (name === 'translations') {\n this.syncTranslationsFromAttribute();\n if (this.isConnected) {\n this.rerenderAfterTranslationsChange();\n }\n }\n }\n\n /**\n * Get the current translations object.\n */\n public get translations(): Translations | null {\n return this.translationsOverride;\n }\n\n /**\n * Override any user-facing string. Omitted keys fall back to English defaults.\n */\n public set translations(value: Translations | null | undefined) {\n this.translationsOverride = value ?? null;\n this.resolvedTranslations = mergeTranslations(this.translationsOverride);\n this.refreshDefaultSessionTitles();\n if (this.isConnected) {\n this.rerenderAfterTranslationsChange();\n }\n }\n\n private syncTranslationsFromAttribute(): void {\n if (this.translationsOverride) {\n this.resolvedTranslations = mergeTranslations(this.translationsOverride);\n this.refreshDefaultSessionTitles();\n return;\n }\n const parsed = parseTranslationsAttribute(this.getAttribute('translations'), 'ChatPageSnippet');\n this.resolvedTranslations = mergeTranslations(parsed);\n this.refreshDefaultSessionTitles();\n }\n\n /**\n * Replace the stored title of any still-default-titled session with the\n * current `newChatButton` translation, so the sidebar reflects the active\n * language after a translations change.\n */\n private refreshDefaultSessionTitles(): void {\n if (this.sessions.length === 0) return;\n const current = this.resolvedTranslations.newChatButton;\n let changed = false;\n for (const session of this.sessions) {\n if (session.titleIsDefault && session.title !== current) {\n session.title = current;\n changed = true;\n }\n }\n if (changed) this.saveSessions();\n }\n\n private rerenderAfterTranslationsChange(): void {\n // Re-render the sidebar + header shell so their strings update. We take\n // care to preserve the existing ChatView (and thus any in-flight stream\n // and streaming UI state) by re-parenting its container into the new\n // shell rather than destroying the view.\n this.removeEventListeners();\n\n // Detach the existing chat container from the old shell so render() does\n // not discard it. If no chat view exists yet (e.g. missing api-url),\n // fall through to a plain re-render.\n const previousChatContent = this.chatView\n ? (this.shadow.querySelector('.container') as HTMLElement | null)\n : null;\n if (previousChatContent?.parentNode) {\n previousChatContent.parentNode.removeChild(previousChatContent);\n }\n\n this.render();\n this.attachEventListeners();\n this.renderChatList();\n\n const newChatSlot = this.shadow.querySelector('.chat-page-content') as HTMLElement | null;\n if (this.chatView && previousChatContent && newChatSlot) {\n // Replace the freshly-rendered empty `.container` with the preserved one.\n const placeholder = newChatSlot.querySelector('.container');\n if (placeholder) {\n newChatSlot.replaceChild(previousChatContent, placeholder);\n } else {\n newChatSlot.appendChild(previousChatContent);\n }\n // Update translations/placeholder on the live view.\n this.chatView.setProps(this.getProps());\n // Re-wire the message listener on the (preserved) container.\n this.handleMessageEvent = () => {\n this.saveCurrentSession();\n this.updateSessionTitle();\n this.renderChatList();\n };\n previousChatContent.addEventListener('message', this.handleMessageEvent);\n }\n }\n\n private getProps(): SearchSnippetProps {\n const t = this.resolvedTranslations;\n return {\n apiUrl: parseAttribute(this.getAttribute('api-url'), ''),\n placeholder: parseAttribute(this.getAttribute('placeholder'), t.chatPlaceholder),\n theme: parseAttribute(this.getAttribute('theme'), 'auto') as 'light' | 'dark' | 'auto',\n hideBranding: parseBooleanAttribute(this.getAttribute('hide-branding'), false),\n translations: this.translationsOverride ?? undefined,\n };\n }\n\n private initializeClient(): void {\n const props = this.getProps();\n\n if (!props.apiUrl) {\n console.error('ChatPageSnippet: api-url attribute is required');\n this.client = null;\n return;\n }\n\n try {\n this.client = createClient(props.apiUrl);\n } catch (error) {\n console.error('ChatPageSnippet:', error);\n }\n }\n\n private render(): void {\n const style = document.createElement('style');\n style.textContent = `${baseStyles}\\n${chatStyles}\\n${this.getPageStyles()}`;\n\n this.container = document.createElement('div');\n this.container.className = 'chat-page-container';\n this.container.innerHTML = this.getBaseHTML();\n\n this.shadow.innerHTML = '';\n this.shadow.appendChild(style);\n this.shadow.appendChild(this.container);\n\n this.attachEventListeners();\n }\n\n private getPageStyles(): string {\n return `\n :host {\n display: block;\n width: 100%;\n height: 100vh;\n }\n\n .chat-page-container {\n display: flex;\n height: 100%;\n background: var(--search-snippet-background);\n }\n\n /* Sidebar styles */\n .chat-sidebar {\n width: 280px;\n min-width: 280px;\n background: var(--search-snippet-surface);\n border-right: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n display: flex;\n flex-direction: column;\n transition: var(--search-snippet-transition);\n overflow: hidden;\n }\n\n .chat-sidebar.collapsed {\n width: 0;\n min-width: 0;\n border-right: none;\n }\n\n .sidebar-header {\n padding: var(--search-snippet-spacing-lg);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-shrink: 0;\n height: 69px;\n }\n\n .sidebar-title {\n font-size: var(--search-snippet-font-size-lg);\n font-weight: var(--search-snippet-font-weight-bold);\n color: var(--search-snippet-text-color);\n }\n\n .new-chat-button {\n width: 100%;\n height: var(--search-snippet-button-height);\n margin: var(--search-snippet-spacing-md) var(--search-snippet-spacing-lg);\n padding: 0 var(--search-snippet-spacing-lg);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: #fff;\n background: var(--search-snippet-primary-color);\n border: none;\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n outline: none;\n transition: var(--search-snippet-transition);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-sm);\n box-sizing: border-box;\n width: calc(100% - var(--search-snippet-spacing-lg) * 2);\n }\n\n .new-chat-button:hover {\n opacity: 0.9;\n }\n\n .new-chat-button svg {\n width: 16px;\n height: 16px;\n }\n\n .chat-list {\n flex: 1;\n overflow-y: auto;\n padding: var(--search-snippet-spacing-sm);\n }\n\n .chat-list-item {\n display: flex;\n align-items: center;\n padding: var(--search-snippet-spacing-md) var(--search-snippet-spacing-lg);\n margin-bottom: var(--search-snippet-spacing-xs);\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n transition: var(--search-snippet-transition);\n gap: var(--search-snippet-spacing-sm);\n }\n\n .chat-list-item:hover {\n background: var(--search-snippet-hover-background);\n }\n\n .chat-list-item.active {\n background: var(--search-snippet-hover-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n }\n\n .chat-list-item-content {\n flex: 1;\n min-width: 0;\n }\n\n .chat-list-item-title {\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .chat-list-item-date {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n margin-top: 2px;\n }\n\n .chat-list-item-delete {\n opacity: 0;\n background: none;\n border: none;\n padding: var(--search-snippet-spacing-xs);\n cursor: pointer;\n color: var(--search-snippet-text-secondary);\n border-radius: var(--search-snippet-border-radius-sm);\n transition: var(--search-snippet-transition);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .chat-list-item:hover .chat-list-item-delete {\n opacity: 1;\n }\n\n .chat-list-item-delete:hover {\n background: var(--search-snippet-error-background, rgba(239, 68, 68, 0.1));\n color: var(--search-snippet-error-color, #ef4444);\n }\n\n .chat-list-item-delete svg {\n width: 14px;\n height: 14px;\n }\n\n .chat-list-empty {\n padding: var(--search-snippet-spacing-xl);\n text-align: center;\n color: var(--search-snippet-text-secondary);\n font-size: var(--search-snippet-font-size-sm);\n }\n\n /* Main content area */\n .chat-main {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-width: 0;\n }\n\n .chat-page-header {\n background: var(--search-snippet-surface);\n padding: var(--search-snippet-spacing-lg);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-shrink: 0;\n }\n\n .chat-page-header-left {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-md);\n }\n\n .toggle-sidebar-button {\n width: 36px;\n height: 36px;\n padding: 0;\n font-family: var(--search-snippet-font-family);\n color: var(--search-snippet-text-color);\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n outline: none;\n transition: var(--search-snippet-transition);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n\n .toggle-sidebar-button:hover {\n background: var(--search-snippet-hover-background);\n }\n\n .toggle-sidebar-button svg {\n width: 18px;\n height: 18px;\n }\n\n .chat-page-header-title {\n font-size: var(--search-snippet-font-size-xl);\n font-weight: var(--search-snippet-font-weight-bold);\n color: var(--search-snippet-text-color);\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-md);\n }\n\n .chat-page-header-title svg {\n width: 28px;\n height: 28px;\n }\n\n .chat-page-header-actions {\n display: flex;\n gap: var(--search-snippet-spacing-sm);\n }\n\n .header-button {\n height: var(--search-snippet-button-height);\n padding: 0 var(--search-snippet-spacing-lg);\n font-family: var(--search-snippet-font-family);\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n outline: none;\n transition: var(--search-snippet-transition);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-sm);\n }\n\n .header-button:hover {\n background: var(--search-snippet-hover-background);\n }\n\n .header-button svg {\n width: 16px;\n height: 16px;\n }\n\n .chat-page-content {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n width: 100%;\n }\n\n .container {\n border: none;\n box-shadow: none;\n height: 100%;\n width: 100%;\n background: var(--search-snippet-background);\n border-radius: 0;\n }\n `;\n }\n\n private getBaseHTML(): string {\n const props = this.getProps();\n const t = this.resolvedTranslations;\n const brandingHTML = props.hideBranding\n ? ''\n : `<div class=\"powered-by\">${POWERED_BY_BRANDING}</div>`;\n\n return `\n <div class=\"chat-sidebar\">\n <div class=\"sidebar-header\">\n <span class=\"sidebar-title\">${escapeHTMLUtil(t.historyTitle)}</span>\n </div>\n <button class=\"new-chat-button\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M12 5v14M5 12h14\"></path>\n </svg>\n ${escapeHTMLUtil(t.newChatButton)}\n </button>\n <div class=\"chat-list\"></div>\n ${brandingHTML}\n </div>\n <div class=\"chat-main\">\n <div class=\"chat-page-header\">\n <div class=\"chat-page-header-left\">\n <button class=\"toggle-sidebar-button\" title=\"${escapeHTMLUtil(t.toggleSidebarTitle)}\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M3 12h18M3 6h18M3 18h18\"></path>\n </svg>\n </button>\n <div class=\"chat-page-header-title\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n <span>${escapeHTMLUtil(t.chatTitle)}</span>\n </div>\n </div>\n <div class=\"chat-page-header-actions\">\n <button class=\"header-button clear-button\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path>\n </svg>\n ${escapeHTMLUtil(t.clearChatButton)}\n </button>\n </div>\n </div>\n <div class=\"chat-page-content\">\n <div class=\"container\"></div>\n </div>\n </div>\n `;\n }\n\n private attachEventListeners(): void {\n const clearButton = this.shadow.querySelector('.clear-button');\n const newChatButton = this.shadow.querySelector('.new-chat-button');\n const toggleSidebarButton = this.shadow.querySelector('.toggle-sidebar-button');\n const chatList = this.shadow.querySelector('.chat-list');\n\n this.handleClearClick = () => this.clearCurrentChat();\n this.handleNewChatClick = () => this.createNewChat();\n this.handleToggleSidebarClick = () => this.toggleSidebar();\n this.handleChatListClick = (e: Event) => this.onChatListClick(e);\n\n clearButton?.addEventListener('click', this.handleClearClick);\n newChatButton?.addEventListener('click', this.handleNewChatClick);\n toggleSidebarButton?.addEventListener('click', this.handleToggleSidebarClick);\n chatList?.addEventListener('click', this.handleChatListClick);\n }\n\n private removeEventListeners(): void {\n const clearButton = this.shadow.querySelector('.clear-button');\n const newChatButton = this.shadow.querySelector('.new-chat-button');\n const toggleSidebarButton = this.shadow.querySelector('.toggle-sidebar-button');\n const chatList = this.shadow.querySelector('.chat-list');\n const chatContent = this.shadow.querySelector('.container') as HTMLElement;\n\n if (this.handleClearClick) {\n clearButton?.removeEventListener('click', this.handleClearClick);\n }\n if (this.handleNewChatClick) {\n newChatButton?.removeEventListener('click', this.handleNewChatClick);\n }\n if (this.handleToggleSidebarClick) {\n toggleSidebarButton?.removeEventListener('click', this.handleToggleSidebarClick);\n }\n if (this.handleChatListClick) {\n chatList?.removeEventListener('click', this.handleChatListClick);\n }\n if (this.handleMessageEvent && chatContent) {\n chatContent.removeEventListener('message', this.handleMessageEvent);\n }\n\n // Clear handler references\n this.handleClearClick = null;\n this.handleNewChatClick = null;\n this.handleToggleSidebarClick = null;\n this.handleChatListClick = null;\n this.handleMessageEvent = null;\n }\n\n private setupView(): void {\n const chatContent = this.shadow.querySelector('.container') as HTMLElement;\n\n if (!this.client) {\n if (chatContent) {\n const t = this.resolvedTranslations;\n chatContent.innerHTML = `\n <div style=\"padding: 16px; color: var(--search-snippet-error-color, #ef4444); font-family: var(--search-snippet-font-family, sans-serif); font-size: var(--search-snippet-font-size-base, 14px);\">\n <strong>${escapeHTMLUtil(t.errorPrefix)}</strong> ${escapeHTMLUtil(t.missingApiUrlError)}\n </div>\n `;\n }\n return;\n }\n\n if (!chatContent) return;\n\n const props = this.getProps();\n this.chatView = new ChatView(chatContent, this.client, props);\n\n // Load current session or create new one\n if (this.sessions.length === 0) {\n this.createNewChat();\n } else {\n // Load the most recent session\n const lastSession = this.sessions[0];\n this.switchToSession(lastSession.id);\n }\n\n // Listen for new messages to save session\n this.handleMessageEvent = () => {\n this.saveCurrentSession();\n this.updateSessionTitle();\n this.renderChatList();\n };\n chatContent.addEventListener('message', this.handleMessageEvent);\n\n this.renderChatList();\n }\n\n private generateSessionId(): string {\n return `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n }\n\n private loadSessions(): void {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) {\n this.sessions = JSON.parse(stored);\n // Sort by updatedAt descending\n this.sessions.sort((a, b) => b.updatedAt - a.updatedAt);\n }\n } catch (error) {\n console.error('Failed to load chat sessions:', error);\n }\n }\n\n private saveSessions(): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(this.sessions));\n } catch (error) {\n console.error('Failed to save chat sessions:', error);\n }\n }\n\n private saveCurrentSession(): void {\n if (!this.currentSessionId || !this.chatView) return;\n\n const sessionIndex = this.sessions.findIndex((s) => s.id === this.currentSessionId);\n if (sessionIndex !== -1) {\n this.sessions[sessionIndex].messages = this.chatView.getMessages();\n this.sessions[sessionIndex].updatedAt = Date.now();\n this.saveSessions();\n }\n }\n\n private updateSessionTitle(): void {\n if (!this.currentSessionId) return;\n\n const session = this.sessions.find((s) => s.id === this.currentSessionId);\n if (!session || session.messages.length === 0) return;\n\n // New sessions created with this code set `titleIsDefault`. For legacy\n // sessions persisted before that field existed, fall back to comparing\n // against the current translation so behavior is unchanged in the common\n // case where the language hasn't shifted since the session was created.\n const hasDefaultTitle =\n session.titleIsDefault ?? session.title === this.resolvedTranslations.newChatButton;\n if (!hasDefaultTitle) return;\n\n const firstUserMessage = session.messages.find((m) => m.role === 'user');\n if (firstUserMessage) {\n session.title =\n firstUserMessage.content.slice(0, 50) + (firstUserMessage.content.length > 50 ? '...' : '');\n session.titleIsDefault = false;\n this.saveSessions();\n }\n }\n\n private createNewChat(): void {\n // Save current session first\n this.saveCurrentSession();\n\n const newSession: ChatSession = {\n id: this.generateSessionId(),\n title: this.resolvedTranslations.newChatButton,\n messages: [],\n createdAt: Date.now(),\n updatedAt: Date.now(),\n titleIsDefault: true,\n };\n\n this.sessions.unshift(newSession);\n this.currentSessionId = newSession.id;\n this.saveSessions();\n\n // Clear the chat view\n this.chatView?.clearMessages();\n this.renderChatList();\n }\n\n private switchToSession(sessionId: string): void {\n if (sessionId === this.currentSessionId) return;\n\n // Save current session first\n this.saveCurrentSession();\n\n const session = this.sessions.find((s) => s.id === sessionId);\n if (session && this.chatView) {\n this.currentSessionId = sessionId;\n this.chatView.setMessages(session.messages);\n this.renderChatList();\n }\n }\n\n private deleteSession(sessionId: string): void {\n const sessionIndex = this.sessions.findIndex((s) => s.id === sessionId);\n if (sessionIndex === -1) return;\n\n this.sessions.splice(sessionIndex, 1);\n this.saveSessions();\n\n // If we deleted the current session, switch to another or create new\n if (sessionId === this.currentSessionId) {\n if (this.sessions.length > 0) {\n this.switchToSession(this.sessions[0].id);\n } else {\n this.createNewChat();\n }\n }\n\n this.renderChatList();\n }\n\n private clearCurrentChat(): void {\n if (!this.currentSessionId) return;\n\n const session = this.sessions.find((s) => s.id === this.currentSessionId);\n if (session) {\n session.messages = [];\n session.title = this.resolvedTranslations.newChatButton;\n session.titleIsDefault = true;\n session.updatedAt = Date.now();\n this.saveSessions();\n }\n\n this.chatView?.clearMessages();\n this.renderChatList();\n }\n\n private toggleSidebar(): void {\n this.sidebarCollapsed = !this.sidebarCollapsed;\n const sidebar = this.shadow.querySelector('.chat-sidebar');\n sidebar?.classList.toggle('collapsed', this.sidebarCollapsed);\n }\n\n private onChatListClick(e: Event): void {\n const target = e.target as HTMLElement;\n\n // Handle delete button click\n const deleteButton = target.closest('.chat-list-item-delete');\n if (deleteButton) {\n e.stopPropagation();\n const sessionId = deleteButton.getAttribute('data-session-id');\n if (sessionId) {\n this.deleteSession(sessionId);\n }\n return;\n }\n\n // Handle chat item click\n const chatItem = target.closest('.chat-list-item');\n if (chatItem) {\n const sessionId = chatItem.getAttribute('data-session-id');\n if (sessionId) {\n this.switchToSession(sessionId);\n }\n }\n }\n\n private renderChatList(): void {\n const chatList = this.shadow.querySelector('.chat-list');\n if (!chatList) return;\n\n const t = this.resolvedTranslations;\n if (this.sessions.length === 0) {\n chatList.innerHTML = `<div class=\"chat-list-empty\">${this.escapeHTML(t.noChatsYet)}</div>`;\n return;\n }\n\n chatList.innerHTML = this.sessions.map((session) => this.renderChatListItem(session)).join('');\n }\n\n private renderChatListItem(session: ChatSession): string {\n const isActive = session.id === this.currentSessionId;\n const date = this.formatDate(session.updatedAt);\n const deleteTitle = this.resolvedTranslations.deleteChatTitle;\n\n return `\n <div class=\"chat-list-item ${isActive ? 'active' : ''}\" data-session-id=\"${session.id}\">\n <div class=\"chat-list-item-content\">\n <div class=\"chat-list-item-title\">${this.escapeHTML(session.title)}</div>\n <div class=\"chat-list-item-date\">${date}</div>\n </div>\n <button class=\"chat-list-item-delete\" data-session-id=\"${session.id}\" title=\"${this.escapeHTML(deleteTitle)}\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path>\n </svg>\n </button>\n </div>\n `;\n }\n\n private formatDate(timestamp: number): string {\n const date = new Date(timestamp);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) {\n return date.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n } else if (diffDays === 1) {\n return this.resolvedTranslations.yesterday;\n } else if (diffDays < 7) {\n return date.toLocaleDateString(undefined, { weekday: 'long' });\n } else {\n return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n }\n\n private escapeHTML(str: string): string {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n }\n\n private updateTheme(theme: string | null): void {\n // CSS :host([theme]) selectors handle theming automatically\n // For 'auto' mode, remove the attribute to let @media (prefers-color-scheme) work\n const validTheme = theme === 'light' || theme === 'dark' ? theme : null;\n\n if (\n validTheme === null &&\n this.hasAttribute('theme') &&\n this.getAttribute('theme') !== 'auto'\n ) {\n this.removeAttribute('theme');\n }\n }\n\n private cleanup(): void {\n this.removeEventListeners();\n\n if (this.client) {\n this.client.cancelAllRequests();\n }\n\n if (this.chatView) {\n this.chatView.destroy();\n }\n }\n\n // Public API\n public clearChat(): void {\n this.clearCurrentChat();\n }\n\n public async sendMessage(content: string): Promise<void> {\n if (this.chatView) {\n await this.chatView.sendMessage(content);\n this.saveCurrentSession();\n }\n }\n\n public getMessages(): Message[] {\n return this.chatView?.getMessages() || [];\n }\n\n public getSessions(): ChatSession[] {\n return [...this.sessions];\n }\n\n public getCurrentSession(): ChatSession | null {\n return this.sessions.find((s) => s.id === this.currentSessionId) || null;\n }\n}\n\n// Register the custom element\nif (!customElements.get(COMPONENT_NAME)) {\n customElements.define(COMPONENT_NAME, ChatPageSnippet);\n}\n","/**\n * Search mode specific styles\n */\n\nexport const searchStyles = `\n/* Search view states */\n.search-view {\n transition: var(--search-snippet-transition-slow);\n background: var(--search-snippet-background);\n border-radius: var(--search-snippet-border-radius);\n padding: 0px;\n}\n\n.search-view-collapsed {\n max-height: 60px;\n}\n\n.search-view-expanded {\n max-height: var(--search-snippet-max-height);\n}\n\n\n.search-icon {\n width: var(--search-snippet-icon-size);\n height: var(--search-snippet-icon-size);\n margin-left: var(--search-snippet-icon-margin-left);\n color: var(--search-snippet-text-color);\n}\n\n/* Search input wrapper */\n.search-input-wrapper {\n display: grid;\n grid-template-columns: auto 1fr auto;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n overflow: hidden;\n transition: max-width var(--search-snippet-transition-slow), \n opacity var(--search-snippet-transition);\n padding: var(--search-snippet-spacing-sm);\n border-radius: var(--search-snippet-border-radius);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n\n\n.search-input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n color: var(--search-snippet-text-color);\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n box-shadow: none;\n padding: 0;\n}\n\n.search-input::placeholder {\n color: var(--search-snippet-text-secondary);\n}\n\n.search-view:has(.search-input:not(:placeholder-shown)) .search-input-wrapper, .search-view:has(.search-input:not(:placeholder-shown)) {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.search-view:focus-within {\n border-color: var(--search-snippet-primary-color);\n box-shadow: inset 0 0 0 3px var(--search-snippet-focus-ring);\n}\n\n.search-view:has(.search-input:not(:placeholder-shown)) .search-content {\n max-height: 600px;\n opacity: 1;\n overflow-y: auto;\n padding: 8px;\n}\n\n.search-submit-button {\n flex-shrink: 0;\n \n border-radius: max(var(--search-snippet-button-min-border-radius, 4px), calc(var(--search-snippet-border-radius) - var(--search-snippet-spacing-sm)))\n}\n\n/* Search content */\n.search-content {\n max-height: 0;\n opacity: 0;\n transition: max-height var(--search-snippet-transition-slow),\n opacity var(--search-snippet-transition);\n position: absolute;\n width: 100%;\n background: var(--search-snippet-background);\n border-bottom-left-radius: var(--search-snippet-border-radius);\n border-bottom-right-radius: var(--search-snippet-border-radius);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-top: none;\n}\n\n.search-content::-webkit-scrollbar {\n width: 8px;\n height: 100px;\n}\n\n.search-content::-webkit-scrollbar-track {\n background: var(--search-snippet-surface);\n \n}\n\n.search-content::-webkit-scrollbar-thumb {\n background: var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n}\n\n.search-content::-webkit-scrollbar-thumb:hover {\n background: var(--search-snippet-text-secondary);\n}\n\n.container {\n overflow: unset;\n position: relative;\n border: none;\n}\n\n.container:has(.search-input:not(:placeholder-shown)) {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n\n/* Override header for search mode */\n\n/* Search results */\n.search-results {\n display: flex;\n flex-direction: column;\n gap: var(--search-snippet-spacing-sm);\n}\n\na.search-result-item {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: var(--search-snippet-spacing-md);\n padding: var(--search-snippet-spacing-md);\n background: var(--search-snippet-surface);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n cursor: pointer;\n transition: var(--search-snippet-transition);\n text-decoration: none;\n color: inherit;\n}\n\n/* Image thumbnail container */\n.search-result-image-container {\n flex-shrink: 0;\n width: 64px;\n height: 64px;\n border-radius: calc(var(--search-snippet-border-radius) - 4px);\n overflow: hidden;\n position: relative;\n}\n\n.search-result-image {\n width: 100%;\n height: 100%;\n object-fit: contain;\n opacity: 0;\n transition: opacity var(--search-snippet-transition);\n}\n\n.search-result-image.loaded {\n opacity: 1;\n}\n\n/* Loading shimmer */\n.search-result-image-loading {\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 90deg,\n var(--search-snippet-surface) 25%,\n var(--search-snippet-border-color) 50%,\n var(--search-snippet-surface) 75%\n );\n background-size: 200% 100%;\n animation: search-image-shimmer 1.5s infinite;\n}\n\n@keyframes search-image-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* Placeholder icon */\n.search-result-image-placeholder {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--search-snippet-text-secondary);\n opacity: 0.5;\n}\n\n.search-result-image-placeholder svg {\n width: 24px;\n height: 24px;\n}\n\n/* Content wrapper */\n.search-result-content {\n flex: 1;\n min-width: 0;\n}\n\na.search-result-item:hover {\n background: var(--search-snippet-hover-background);\n border-color: var(--search-snippet-primary-color);\n transform: translateY(-1px);\n box-shadow: var(--search-snippet-result-item-shadow);\n}\n\na.search-result-item:focus-visible {\n outline: 2px solid var(--search-snippet-primary-color);\n outline-offset: 2px;\n}\n\n.search-result-title {\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n margin-bottom: var(--search-snippet-spacing-xs);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.search-result-snippet {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-description);\n line-height: 1.6;\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.search-result-metadata {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n margin-top: var(--search-snippet-spacing-xs);\n min-width: 0;\n}\n\n.search-result-url {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-primary-color);\n text-decoration: none;\n display: block;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.search-result-url-empty {\n visibility: hidden;\n}\n\n.search-result-date {\n font-size: 12px;\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-secondary);\n text-align: right;\n flex-shrink: 0;\n}\n\n.search-result-url:hover {\n text-decoration: underline;\n}\n\n/* Search header */\n.search-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: var(--search-snippet-spacing-md);\n padding-bottom: var(--search-snippet-spacing-sm);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n.search-count {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n}\n\n/* Search footer */\n.search-footer {\n padding: var(--search-snippet-spacing-md);\n padding-bottom: var(--search-snippet-spacing-xs);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-sm);\n}\n\n/* See more link */\n.search-see-more {\n display: inline-flex;\n align-items: center;\n gap: var(--search-snippet-spacing-xs);\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-primary-color);\n text-decoration: none;\n font-weight: var(--search-snippet-font-weight-medium);\n transition: color var(--search-snippet-transition-fast);\n}\n\n.search-see-more:hover {\n text-decoration: underline;\n}\n\n/* Loading state for search */\n.search-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--search-snippet-spacing-xxl);\n gap: var(--search-snippet-spacing-md);\n color: var(--search-snippet-text-secondary);\n}\n\n/* Empty search state */\n.search-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--search-snippet-spacing-xxl);\n gap: var(--search-snippet-spacing-md);\n color: var(--search-snippet-text-secondary);\n text-align: center;\n}\n\n.search-empty-icon {\n width: 64px;\n height: 64px;\n opacity: 0.5;\n}\n\n.search-empty-title {\n font-size: var(--search-snippet-font-size-lg);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n}\n\n.search-empty-description {\n font-size: var(--search-snippet-font-size-sm);\n}\n\n/* Highlight matching text */\n.search-highlight {\n background: var(--search-snippet-warning-background);\n color: var(--search-snippet-warning-color);\n padding: 1px 2px;\n border-radius: 2px;\n font-weight: var(--search-snippet-font-weight-medium);\n}\n`;\n","/**\n * Search Bar Snippet\n * A search bar with results display\n */\n\nimport type { AISearchClient } from '../api/ai-search.ts';\nimport { POWERED_BY_BRANDING } from '../constants.ts';\nimport {\n interpolate,\n mergeTranslations,\n parseTranslationsAttribute,\n type Translations,\n} from '../i18n/index.ts';\nimport { searchStyles } from '../styles/search.ts';\nimport { baseStyles } from '../styles/theme.ts';\nimport type { SearchRequestOptions, SearchResult, SearchSnippetProps } from '../types/index.ts';\nimport {\n createClient,\n createCustomEvent,\n debounce,\n escapeHTML,\n formatDate,\n formatDisplayUrl,\n LOADING_MESSAGE_INTERVAL_MS,\n parseAttribute,\n parseBooleanAttribute,\n parseNumberAttribute,\n} from '../utils/index.ts';\n\nconst COMPONENT_NAME = 'search-bar-snippet';\nconst DEFAULT_RENDER_RESULTS = 10;\nconst DEFAULT_REQUEST_MAX_RESULTS = 50;\n\nexport class SearchBarSnippet extends HTMLElement {\n private shadow: ShadowRoot;\n private client: AISearchClient | null = null;\n private container: HTMLElement | null = null;\n private inputElement: HTMLInputElement | null = null;\n private resultsContainer: HTMLElement | null = null;\n private searchButton: HTMLButtonElement | null = null;\n private debouncedSearch: ((query: string) => void) | null = null;\n private currentSearchController: AbortController | null = null;\n private loadingMessageInterval: ReturnType<typeof setInterval> | null = null;\n private loadingMessageIndex = 0;\n private translationsOverride: Translations | null = null;\n private resolvedTranslations = mergeTranslations(null);\n\n // Event handler references for cleanup\n private handleInputChange: ((e: Event) => void) | null = null;\n private handleInputKeydownEnter: ((e: KeyboardEvent) => void) | null = null;\n private handleInputKeydownEscape: ((e: KeyboardEvent) => void) | null = null;\n private handleSearchButtonClick: (() => void) | null = null;\n\n static get observedAttributes() {\n return [\n 'api-url',\n 'placeholder',\n 'max-results',\n 'max-render-results',\n 'debounce-ms',\n 'theme',\n 'hide-branding',\n 'show-url',\n 'show-date',\n 'hide-thumbnails',\n 'see-more',\n 'request-options',\n 'translations',\n ] as const;\n }\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n this.syncTranslationsFromAttribute();\n this.initializeClient();\n this.render();\n this.dispatchEvent(createCustomEvent('ready', undefined));\n }\n\n disconnectedCallback(): void {\n this.cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'api-url') {\n this.initializeClient();\n } else if (name === 'theme') {\n // Theme changes are handled automatically by CSS :host([theme]) selectors\n // But we trigger this to ensure any dynamic updates are applied\n this.updateTheme(newValue);\n } else if (name === 'translations') {\n this.syncTranslationsFromAttribute();\n if (this.isConnected) {\n this.rerender();\n }\n }\n }\n\n /**\n * Get the current translations object. Mirrors the property getter.\n */\n public get translations(): Translations | null {\n return this.translationsOverride;\n }\n\n /**\n * Override any user-facing string. Omitted keys fall back to English defaults.\n */\n public set translations(value: Translations | null | undefined) {\n this.translationsOverride = value ?? null;\n this.resolvedTranslations = mergeTranslations(this.translationsOverride);\n if (this.isConnected) {\n this.rerender();\n }\n }\n\n /**\n * Re-render preserving the current query and re-running the search so\n * results remain visible after a translations change at runtime.\n */\n private rerender(): void {\n const previousQuery = this.inputElement?.value ?? '';\n this.render();\n if (previousQuery && this.inputElement) {\n this.inputElement.value = previousQuery;\n // Re-run immediately so the results area isn't left in the empty state.\n if (previousQuery.trim().length > 0) {\n this.performSearch(previousQuery.trim());\n }\n }\n }\n\n private syncTranslationsFromAttribute(): void {\n // If a property was set imperatively, it takes precedence over the attribute.\n if (this.translationsOverride) {\n this.resolvedTranslations = mergeTranslations(this.translationsOverride);\n return;\n }\n const parsed = parseTranslationsAttribute(\n this.getAttribute('translations'),\n 'SearchBarSnippet'\n );\n this.resolvedTranslations = mergeTranslations(parsed);\n }\n\n private getProps(): SearchSnippetProps {\n const t = this.resolvedTranslations;\n return {\n apiUrl: parseAttribute(this.getAttribute('api-url'), ''),\n placeholder: parseAttribute(this.getAttribute('placeholder'), t.placeholder),\n maxResults: parseNumberAttribute(\n this.getAttribute('max-results'),\n DEFAULT_REQUEST_MAX_RESULTS\n ),\n maxRenderResults: parseNumberAttribute(\n this.getAttribute('max-render-results'),\n DEFAULT_RENDER_RESULTS\n ),\n debounceMs: parseNumberAttribute(this.getAttribute('debounce-ms'), 300),\n theme: parseAttribute(this.getAttribute('theme'), 'auto') as 'light' | 'dark' | 'auto',\n hideBranding: parseBooleanAttribute(this.getAttribute('hide-branding'), false),\n showUrl: parseBooleanAttribute(this.getAttribute('show-url'), false),\n showDate: parseBooleanAttribute(this.getAttribute('show-date'), false),\n hideThumbnails: parseBooleanAttribute(this.getAttribute('hide-thumbnails'), false),\n seeMore: parseAttribute(this.getAttribute('see-more'), ''),\n translations: this.translationsOverride ?? undefined,\n };\n }\n\n private getRequestOptions(): SearchRequestOptions | undefined {\n const rawRequestOptions = this.getAttribute('request-options');\n\n if (!rawRequestOptions) {\n return undefined;\n }\n\n try {\n const parsedRequestOptions = JSON.parse(rawRequestOptions) as unknown;\n\n if (\n parsedRequestOptions === null ||\n typeof parsedRequestOptions !== 'object' ||\n Array.isArray(parsedRequestOptions)\n ) {\n throw new Error('request-options must be a JSON object');\n }\n\n return parsedRequestOptions as SearchRequestOptions;\n } catch (error) {\n console.error('SearchBarSnippet: invalid request-options attribute', error);\n return undefined;\n }\n }\n\n private initializeClient(): void {\n const props = this.getProps();\n\n if (!props.apiUrl) {\n console.error('SearchBarSnippet: api-url attribute is required');\n this.client = null;\n this.showMissingApiUrlError();\n return;\n }\n\n try {\n this.client = createClient(props.apiUrl);\n } catch (error) {\n console.error('SearchBarSnippet:', error);\n }\n }\n\n private render(): void {\n const props = this.getProps();\n const t = this.resolvedTranslations;\n\n // Create debounced search function\n const searchFn = (query: string) => this.performSearch(query);\n this.debouncedSearch = debounce(\n searchFn as (...args: unknown[]) => unknown,\n props.debounceMs || 400\n ) as (query: string) => void;\n\n const style = document.createElement('style');\n style.textContent = `${baseStyles}\\n${searchStyles}`;\n\n this.container = document.createElement('div');\n this.container.className = 'container';\n this.container.innerHTML = `\n <div class=\"search-view\"> \n <div class=\"search-input-wrapper\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"search-icon\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg>\n <input\n type=\"text\"\n name=\"search-input\"\n class=\"search-input\"\n placeholder=\"${escapeHTML(props.placeholder || t.placeholder)}\"\n aria-label=\"${escapeHTML(t.searchInputAriaLabel)}\"\n autocomplete=\"off\"\n />\n <button class=\"button search-submit-button\" aria-label=\"${escapeHTML(t.searchButtonLabel)}\">\n <span>${escapeHTML(t.searchButtonLabel)}</span>\n </button>\n </div>\n <div class=\"search-content\">\n <div class=\"search-results-wrapper\">\n <!-- Results will be inserted here -->\n </div>\n </div>\n </div>\n `;\n\n this.shadow.innerHTML = '';\n this.shadow.appendChild(style);\n this.shadow.appendChild(this.container);\n\n // Get references to elements\n this.inputElement = this.container.querySelector('.search-input');\n this.resultsContainer = this.container.querySelector('.search-results-wrapper');\n this.searchButton = this.container.querySelector('.search-submit-button');\n\n this.attachEventListeners();\n\n // Show error immediately if api-url was missing when the component was connected\n if (!this.client) {\n this.showMissingApiUrlError();\n }\n }\n\n private attachEventListeners(): void {\n if (!this.inputElement) return;\n\n // Input event for real-time search\n this.handleInputChange = (e: Event) => {\n const target = e.target as HTMLInputElement;\n const query = target.value.trim();\n\n if (query.length > 0 && this.debouncedSearch) {\n this.debouncedSearch(query);\n } else {\n this.showEmptyState();\n }\n };\n this.inputElement.addEventListener('input', this.handleInputChange);\n\n // Enter key to search immediately\n this.handleInputKeydownEnter = (e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n const query = (e.target as HTMLInputElement).value.trim();\n if (query.length > 0) {\n this.performSearch(query);\n }\n }\n };\n this.inputElement.addEventListener('keydown', this.handleInputKeydownEnter);\n\n this.handleInputKeydownEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && this.inputElement) {\n this.inputElement.value = '';\n }\n };\n window.addEventListener('keydown', this.handleInputKeydownEscape);\n\n // Search button click\n if (this.searchButton) {\n this.handleSearchButtonClick = () => {\n const query = this.inputElement?.value.trim() || '';\n if (query.length > 0) {\n this.performSearch(query);\n }\n };\n this.searchButton.addEventListener('click', this.handleSearchButtonClick);\n }\n }\n\n private async performSearch(query: string): Promise<void> {\n if (!this.client) {\n this.showMissingApiUrlError();\n return;\n }\n\n // Cancel any existing request before starting a new one\n if (this.currentSearchController) {\n this.currentSearchController.abort();\n this.currentSearchController = null;\n }\n\n // Create new controller for this request\n this.currentSearchController = new AbortController();\n this.showLoadingState();\n\n try {\n const props = this.getProps();\n const results = await this.client.search(query, {\n signal: this.currentSearchController.signal,\n maxResults: props.maxResults || DEFAULT_REQUEST_MAX_RESULTS,\n request: this.getRequestOptions(),\n });\n const visibleResults = results.slice(0, props.maxRenderResults || DEFAULT_RENDER_RESULTS);\n this.displayResults(visibleResults, query, results.length);\n } catch (error) {\n // Don't show error state for cancelled requests\n if ((error as Error).name === 'AbortError') {\n return;\n }\n this.showErrorState((error as Error).message);\n } finally {\n this.currentSearchController = null;\n }\n }\n\n private displayResults(\n results: SearchResult[],\n query: string,\n totalResults = results.length\n ): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n\n if (results.length === 0) {\n this.showNoResultsState(query);\n return;\n }\n const props = this.getProps();\n const t = this.resolvedTranslations;\n const brandingHTML = props.hideBranding\n ? ''\n : `<div class=\"powered-by-inline\">${POWERED_BY_BRANDING}</div>`;\n const hasMoreResults = totalResults > results.length;\n const resultsCountLabel = hasMoreResults\n ? interpolate(t.resultsCountOverflow, { n: results.length, total: totalResults })\n : interpolate(totalResults === 1 ? t.resultsCount : t.resultsCountPlural, {\n n: totalResults,\n });\n\n const seeMoreHTML =\n props.seeMore && hasMoreResults\n ? `<div class=\"search-footer\">\n <a href=\"${escapeHTML(props.seeMore + encodeURIComponent(query))}\" class=\"search-see-more\">\n <span>${escapeHTML(t.seeMoreResults)}</span>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/></svg>\n </a>\n </div>`\n : '';\n\n const resultsHTML = `\n <div class=\"search-header\">\n <div class=\"search-count\">\n ${escapeHTML(resultsCountLabel)}\n </div>\n ${brandingHTML}\n </div>\n <div class=\"search-results\">\n ${results.map((result) => this.renderResult(result)).join('')}\n </div>\n ${seeMoreHTML}\n `;\n\n this.resultsContainer.innerHTML = resultsHTML;\n\n // Attach click handlers to results\n this.attachResultHandlers();\n }\n\n private renderResult(result: SearchResult): string {\n const props = this.getProps();\n const imageHTML = props.hideThumbnails\n ? ''\n : this.renderResultImage(result.image, result.title);\n const href = result.url ? escapeHTML(result.url) : '#';\n const displayUrl = result.url ? escapeHTML(formatDisplayUrl(result.url)) : '';\n const timestampHTML =\n props.showDate && result.timestamp !== undefined\n ? `<div class=\"search-result-date\">${escapeHTML(formatDate(result.timestamp))}</div>`\n : '';\n const metadataHTML =\n (props.showUrl && result.url) || timestampHTML\n ? `<div class=\"search-result-metadata\">\n ${props.showUrl && result.url ? `<span class=\"search-result-url\">${displayUrl}</span>` : '<span class=\"search-result-url search-result-url-empty\"></span>'}\n ${timestampHTML}\n </div>`\n : '';\n\n return `\n <a href=\"${href}\" class=\"search-result-item\" data-result-id=\"${escapeHTML(result.url || '')}\">\n ${imageHTML}\n <div class=\"search-result-content\">\n <div class=\"search-result-title\">${escapeHTML(result.title || '')}</div>\n <div class=\"search-result-snippet\">${escapeHTML(result.description || '')}</div>\n ${metadataHTML}\n </div>\n </a>\n `;\n }\n\n private renderResultImage(imageUrl: string | undefined, alt: string): string {\n const placeholderSVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"/><polyline points=\"10 9 9 9 8 9\"/></svg>`;\n\n if (!imageUrl) {\n return `\n <div class=\"search-result-image-container\">\n <div class=\"search-result-image-placeholder\">${placeholderSVG}</div>\n </div>\n `;\n }\n\n return `\n <div class=\"search-result-image-container\">\n <div class=\"search-result-image-loading\"></div>\n <div class=\"search-result-image-placeholder\" style=\"display: none;\">${placeholderSVG}</div>\n <img \n class=\"search-result-image\" \n src=\"${escapeHTML(imageUrl)}\" \n alt=\"${escapeHTML(alt)}\"\n loading=\"lazy\"\n />\n </div>\n `;\n }\n\n private attachResultHandlers(): void {\n const resultItems = this.container?.querySelectorAll('.search-result-item');\n if (!resultItems) return;\n\n // Handle clicks on results without URLs (prevent default anchor behavior)\n for (const item of resultItems) {\n const href = item.getAttribute('href');\n if (href === '#') {\n item.addEventListener('click', (e) => {\n e.preventDefault();\n });\n }\n }\n\n // Image load/error handlers\n const images = this.container?.querySelectorAll('.search-result-image');\n images?.forEach((img) => {\n img.addEventListener('load', () => {\n img.classList.add('loaded');\n const container = img.closest('.search-result-image-container');\n container?.querySelector('.search-result-image-loading')?.remove();\n });\n\n img.addEventListener('error', () => {\n const container = img.closest('.search-result-image-container');\n container?.querySelector('.search-result-image-loading')?.remove();\n const placeholder = container?.querySelector(\n '.search-result-image-placeholder'\n ) as HTMLElement;\n if (placeholder) placeholder.style.display = 'flex';\n (img as HTMLElement).style.display = 'none';\n });\n });\n }\n\n private showLoadingState(): void {\n if (!this.resultsContainer) return;\n\n this.clearLoadingInterval();\n const messages = this.resolvedTranslations.loadingMessages;\n this.loadingMessageIndex = Math.floor(Math.random() * messages.length);\n const t = this.resolvedTranslations;\n\n this.resultsContainer.innerHTML = `\n <div class=\"search-loading\">\n <div class=\"loading\" aria-label=\"${escapeHTML(t.loadingAriaLabel)}\"></div>\n <div class=\"loading-text loading-text-animate\">${escapeHTML(messages[this.loadingMessageIndex])}</div>\n </div>\n `;\n\n this.startLoadingInterval();\n }\n\n private startLoadingInterval(): void {\n this.loadingMessageInterval = setInterval(() => {\n const messages = this.resolvedTranslations.loadingMessages;\n this.loadingMessageIndex = (this.loadingMessageIndex + 1) % messages.length;\n const textEl = this.resultsContainer?.querySelector('.loading-text');\n if (textEl) {\n textEl.classList.remove('loading-text-animate');\n void (textEl as HTMLElement).offsetWidth;\n textEl.textContent = messages[this.loadingMessageIndex];\n textEl.classList.add('loading-text-animate');\n }\n }, LOADING_MESSAGE_INTERVAL_MS);\n }\n\n private clearLoadingInterval(): void {\n if (this.loadingMessageInterval) {\n clearInterval(this.loadingMessageInterval);\n this.loadingMessageInterval = null;\n }\n }\n\n private showEmptyState(): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n const t = this.resolvedTranslations;\n\n this.resultsContainer.innerHTML = `\n <div class=\"search-empty\">\n <svg class=\"search-empty-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <path d=\"m21 21-4.35-4.35\"></path>\n </svg>\n <div class=\"search-empty-title\">${escapeHTML(t.emptyStateTitle)}</div>\n <div class=\"search-empty-description\">\n ${escapeHTML(t.emptyStateDescription)}\n </div>\n </div>\n `;\n }\n\n private showNoResultsState(query: string): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n const t = this.resolvedTranslations;\n\n this.resultsContainer.innerHTML = `\n <div class=\"search-empty\">\n <svg class=\"search-empty-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n </svg>\n <div class=\"search-empty-title\">${escapeHTML(t.noResultsTitle)}</div>\n <div class=\"search-empty-description\">\n ${escapeHTML(interpolate(t.noResultsDescription, { query }))}\n </div>\n </div>\n `;\n }\n\n private showErrorState(message: string): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n const t = this.resolvedTranslations;\n\n this.resultsContainer.innerHTML = `\n <div class=\"error\">\n <strong>${escapeHTML(t.errorPrefix)}</strong> ${escapeHTML(message)}\n </div>\n `;\n }\n\n private showMissingApiUrlError(): void {\n if (this.resultsContainer) {\n this.showErrorState(this.resolvedTranslations.missingApiUrlError);\n }\n }\n\n private updateTheme(theme: string | null): void {\n // CSS custom properties via :host([theme]) selectors handle the actual theming\n // This method is here for any additional theme-related logic if needed\n const validTheme = theme === 'light' || theme === 'dark' || theme === 'auto' ? theme : 'auto';\n\n // Ensure the attribute is set on the host for CSS selectors\n if (validTheme === 'auto') {\n // Let the @media (prefers-color-scheme) handle it\n this.removeAttribute('theme');\n } else {\n this.setAttribute('theme', validTheme);\n }\n }\n\n private cleanup(): void {\n this.clearLoadingInterval();\n\n // Cancel any in-flight search request\n if (this.currentSearchController) {\n this.currentSearchController.abort();\n this.currentSearchController = null;\n }\n\n if (this.client) {\n this.client.cancelAllRequests();\n }\n\n // Remove event listeners\n if (this.inputElement) {\n if (this.handleInputChange) {\n this.inputElement.removeEventListener('input', this.handleInputChange);\n }\n if (this.handleInputKeydownEnter) {\n this.inputElement.removeEventListener('keydown', this.handleInputKeydownEnter);\n }\n if (this.handleInputKeydownEscape) {\n window.removeEventListener('keydown', this.handleInputKeydownEscape);\n }\n }\n\n if (this.searchButton && this.handleSearchButtonClick) {\n this.searchButton.removeEventListener('click', this.handleSearchButtonClick);\n }\n\n // Clear handler references\n this.handleInputChange = null;\n this.handleInputKeydownEnter = null;\n this.handleInputKeydownEscape = null;\n this.handleSearchButtonClick = null;\n }\n\n // Public API\n public async search(query: string): Promise<void> {\n await this.performSearch(query);\n }\n}\n\n// Register the custom element\nif (!customElements.get(COMPONENT_NAME)) {\n customElements.define(COMPONENT_NAME, SearchBarSnippet);\n}\n","/**\n * Modal search combobox specific styles\n */\n\nexport const modalStyles = `\n/* Modal backdrop */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n z-index: var(--search-snippet-z-modal);\n opacity: 0;\n visibility: hidden;\n transition: opacity var(--search-snippet-transition), visibility var(--search-snippet-transition);\n}\n\n.modal-backdrop.open {\n opacity: 1;\n visibility: visible;\n}\n\n/* Modal container */\n.modal-container {\n position: fixed;\n top: 15%;\n left: 50%;\n transform: translateX(-50%) scale(0.95);\n width: 90%;\n max-width: 600px;\n max-height: 70vh;\n background: var(--search-snippet-background);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n box-shadow: var(--search-snippet-shadow-lg);\n z-index: calc(var(--search-snippet-z-modal) + 1);\n display: flex;\n flex-direction: column;\n opacity: 0;\n visibility: hidden;\n transition: opacity var(--search-snippet-transition), \n visibility var(--search-snippet-transition),\n transform var(--search-snippet-transition);\n}\n\n.modal-container.open {\n opacity: 1;\n visibility: visible;\n transform: translateX(-50%) scale(1);\n}\n\n/* Modal header with search input */\n.modal-header {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n padding: var(--search-snippet-spacing-md);\n border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n}\n\n.modal-search-icon {\n width: var(--search-snippet-icon-size);\n height: var(--search-snippet-icon-size);\n color: var(--search-snippet-text-secondary);\n flex-shrink: 0;\n}\n\n.modal-search-input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n color: var(--search-snippet-text-color);\n font-size: var(--search-snippet-font-size-lg);\n font-family: var(--search-snippet-font-family);\n font-weight: var(--search-snippet-font-weight-normal);\n padding: var(--search-snippet-spacing-xs) 0;\n}\n\n.modal-search-input::placeholder {\n color: var(--search-snippet-text-secondary);\n}\n\n.modal-shortcut-hint {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-xs);\n color: var(--search-snippet-text-secondary);\n font-size: var(--search-snippet-font-size-sm);\n flex-shrink: 0;\n}\n\n.modal-kbd {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 22px;\n padding: 0 var(--search-snippet-spacing-xs);\n background: var(--search-snippet-surface);\n border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n border-radius: 4px;\n font-size: var(--search-snippet-font-size-sm);\n font-family: var(--search-snippet-font-family);\n color: var(--search-snippet-text-secondary);\n}\n\n/* Modal content (results area) */\n.modal-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: var(--search-snippet-spacing-sm);\n}\n\n.modal-content::-webkit-scrollbar {\n width: 8px;\n}\n\n.modal-content::-webkit-scrollbar-track {\n background: var(--search-snippet-surface);\n}\n\n.modal-content::-webkit-scrollbar-thumb {\n background: var(--search-snippet-border-color);\n border-radius: var(--search-snippet-border-radius);\n}\n\n.modal-content::-webkit-scrollbar-thumb:hover {\n background: var(--search-snippet-text-secondary);\n}\n\n/* Results list */\n.modal-results {\n display: flex;\n flex-direction: column;\n gap: var(--search-snippet-spacing-xs);\n}\n\na.modal-result-item {\n padding: var(--search-snippet-spacing-md);\n background: transparent;\n border: var(--search-snippet-border-width) solid transparent;\n border-radius: calc(var(--search-snippet-border-radius) - 4px);\n cursor: pointer;\n transition: var(--search-snippet-transition-fast);\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: var(--search-snippet-spacing-md);\n text-decoration: none;\n color: inherit;\n}\n\n/* Image thumbnail container */\n.modal-result-image-container {\n flex-shrink: 0;\n width: 48px;\n height: 48px;\n border-radius: 6px;\n overflow: hidden;\n position: relative;\n}\n\n.modal-result-image {\n width: 100%;\n height: 100%;\n object-fit: contain;\n opacity: 0;\n transition: opacity var(--search-snippet-transition);\n}\n\n.modal-result-image.loaded {\n opacity: 1;\n}\n\n/* Loading shimmer */\n.modal-result-image-loading {\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 90deg,\n var(--search-snippet-surface) 25%,\n var(--search-snippet-border-color) 50%,\n var(--search-snippet-surface) 75%\n );\n background-size: 200% 100%;\n animation: modal-image-shimmer 1.5s infinite;\n}\n\n@keyframes modal-image-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* Placeholder icon */\n.modal-result-image-placeholder {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--search-snippet-text-secondary);\n opacity: 0.5;\n}\n\n.modal-result-image-placeholder svg {\n width: 20px;\n height: 20px;\n}\n\n/* Content wrapper */\n.modal-result-content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: var(--search-snippet-spacing-xs);\n}\n\na.modal-result-item:hover,\na.modal-result-item.active {\n background: var(--search-snippet-hover-background);\n border-color: var(--search-snippet-border-color);\n}\n\na.modal-result-item.active {\n border-color: var(--search-snippet-primary-color);\n background: var(--search-snippet-focus-ring);\n}\n\na.modal-result-item:focus-visible {\n outline: 2px solid var(--search-snippet-primary-color);\n outline-offset: -2px;\n}\n\n.modal-result-title {\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.modal-result-description {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-description);\n line-height: 1.5;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.modal-result-metadata {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-sm);\n min-width: 0;\n}\n\n.modal-result-url {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-primary-color);\n text-decoration: none;\n display: block;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.modal-result-url-empty {\n visibility: hidden;\n}\n\n.modal-result-date {\n font-size: 12px;\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-secondary);\n text-align: right;\n flex-shrink: 0;\n}\n\n.modal-result-url:hover {\n text-decoration: underline;\n}\n\n/* Result group header */\n.modal-group-header {\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n font-size: var(--search-snippet-font-size-sm);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n/* Loading state */\n.modal-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--search-snippet-spacing-xxl);\n gap: var(--search-snippet-spacing-md);\n color: var(--search-snippet-text-secondary);\n}\n\n/* Empty state */\n.modal-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--search-snippet-spacing-xxl);\n gap: var(--search-snippet-spacing-md);\n color: var(--search-snippet-text-secondary);\n text-align: center;\n}\n\n.modal-empty-icon {\n width: 48px;\n height: 48px;\n opacity: 0.5;\n}\n\n.modal-empty-title {\n font-size: var(--search-snippet-font-size-base);\n font-weight: var(--search-snippet-font-weight-medium);\n color: var(--search-snippet-text-color);\n}\n\n.modal-empty-description {\n font-size: var(--search-snippet-font-size-sm);\n}\n\n/* Footer */\n.modal-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md);\n border-top: var(--search-snippet-border-width) solid var(--search-snippet-border-color);\n background: var(--search-snippet-surface);\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n border-radius: 0 0 var(--search-snippet-border-radius) var(--search-snippet-border-radius);\n}\n\n.modal-footer-hints {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-md);\n}\n\n.modal-footer-hint {\n display: flex;\n align-items: center;\n gap: var(--search-snippet-spacing-xs);\n}\n\n.modal-footer-hint .modal-kbd {\n min-width: 20px;\n height: 20px;\n font-size: 11px;\n}\n\n/* Results count */\n.modal-results-count {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n}\n\n/* Powered by in modal footer */\n.modal-footer .powered-by-inline {\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-text-secondary);\n}\n\n.modal-footer .powered-by-inline a {\n color: var(--search-snippet-text-secondary);\n text-decoration: none;\n transition: color var(--search-snippet-transition-fast);\n}\n\n.modal-footer .powered-by-inline a:hover {\n color: var(--search-snippet-primary-color);\n}\n\n/* See more link */\n.modal-see-more {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--search-snippet-spacing-xs);\n padding: var(--search-snippet-spacing-md);\n font-size: var(--search-snippet-font-size-sm);\n color: var(--search-snippet-primary-color);\n text-decoration: none;\n font-weight: var(--search-snippet-font-weight-medium);\n transition: background var(--search-snippet-transition-fast);\n padding-bottom: var(--search-snippet-spacing-xs);\n}\n\n.modal-see-more:hover {\n background: var(--search-snippet-hover);\n text-decoration: underline;\n}\n\n/* Responsive adjustments */\n@media (max-width: 640px) {\n .modal-container {\n top: 10%;\n width: 95%;\n max-height: 80vh;\n }\n\n .modal-footer-hints {\n display: none;\n }\n}\n\n/* Animation for modal open */\n@keyframes modal-slide-in {\n from {\n opacity: 0;\n transform: translateX(-50%) scale(0.95) translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) scale(1) translateY(0);\n }\n}\n\n.modal-container.open {\n animation: modal-slide-in var(--search-snippet-transition) ease-out;\n}\n`;\n","/**\n * Search Modal Snippet\n * A modal combobox search component with keyboard navigation\n * Opens with Cmd/Ctrl+K shortcut by default\n */\n\nimport type { AISearchClient } from '../api/ai-search.ts';\nimport { POWERED_BY_BRANDING } from '../constants.ts';\nimport {\n interpolate,\n mergeTranslations,\n parseTranslationsAttribute,\n type Translations,\n} from '../i18n/index.ts';\nimport { modalStyles } from '../styles/modal.ts';\nimport { baseStyles } from '../styles/theme.ts';\nimport type { SearchRequestOptions, SearchResult, SearchSnippetProps } from '../types/index.ts';\nimport {\n createClient,\n createCustomEvent,\n debounce,\n escapeHTML,\n formatDate,\n formatDisplayUrl,\n LOADING_MESSAGE_INTERVAL_MS,\n parseAttribute,\n parseBooleanAttribute,\n parseNumberAttribute,\n} from '../utils/index.ts';\n\nconst COMPONENT_NAME = 'search-modal-snippet';\nconst DEFAULT_RENDER_RESULTS = 10;\nconst DEFAULT_REQUEST_MAX_RESULTS = 50;\n\nexport interface SearchModalProps extends SearchSnippetProps {\n /** Keyboard shortcut key (default: 'k') */\n shortcut?: string;\n /** Whether to use meta key (Cmd on Mac) or ctrl key */\n useMetaKey?: boolean;\n}\n\nexport class SearchModalSnippet extends HTMLElement {\n private shadow: ShadowRoot;\n private client: AISearchClient | null = null;\n private backdrop: HTMLElement | null = null;\n private modal: HTMLElement | null = null;\n private inputElement: HTMLInputElement | null = null;\n private resultsContainer: HTMLElement | null = null;\n private footerCount: HTMLElement | null = null;\n private isOpen = false;\n private results: SearchResult[] = [];\n private activeIndex = -1;\n private debouncedSearch: (((query: string) => void) & { cancel: () => void }) | null = null;\n private currentSearchController: AbortController | null = null;\n private loadingMessageInterval: ReturnType<typeof setInterval> | null = null;\n private loadingMessageIndex = 0;\n private translationsOverride: Translations | null = null;\n private resolvedTranslations = mergeTranslations(null);\n\n // Event handler references for cleanup\n private handleGlobalKeydown: ((e: KeyboardEvent) => void) | null = null;\n private handleInputChange: ((e: Event) => void) | null = null;\n private handleInputKeydown: ((e: KeyboardEvent) => void) | null = null;\n private handleBackdropClick: ((e: MouseEvent) => void) | null = null;\n\n // Scroll lock state\n private savedBodyStyles: {\n overflow: string;\n position: string;\n top: string;\n width: string;\n scrollbarGutter: string;\n } | null = null;\n private savedHtmlOverflow: string | null = null;\n\n static get observedAttributes() {\n return [\n 'api-url',\n 'placeholder',\n 'max-results',\n 'max-render-results',\n 'theme',\n 'shortcut',\n 'use-meta-key',\n 'debounce-ms',\n 'hide-branding',\n 'show-url',\n 'show-date',\n 'hide-thumbnails',\n 'see-more',\n 'request-options',\n 'translations',\n ] as const;\n }\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n this.syncTranslationsFromAttribute();\n this.initializeClient();\n this.render();\n this.attachGlobalKeyboardShortcut();\n this.dispatchEvent(createCustomEvent('ready', undefined));\n }\n\n disconnectedCallback(): void {\n this.cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'api-url') {\n this.initializeClient();\n } else if (name === 'theme') {\n this.updateTheme(newValue);\n } else if (name === 'translations') {\n this.syncTranslationsFromAttribute();\n if (this.isConnected) {\n this.rerender();\n }\n }\n }\n\n /**\n * Get the current translations object.\n */\n public get translations(): Translations | null {\n return this.translationsOverride;\n }\n\n /**\n * Override any user-facing string. Omitted keys fall back to English defaults.\n */\n public set translations(value: Translations | null | undefined) {\n this.translationsOverride = value ?? null;\n this.resolvedTranslations = mergeTranslations(this.translationsOverride);\n if (this.isConnected) {\n this.rerender();\n }\n }\n\n /**\n * Re-render while preserving open state and the current query. Results are\n * re-fetched so the list reflects the updated translation strings around\n * them (counts, footer hints, etc.). Selection resets to none — the same\n * behavior as the immediate post-search state.\n */\n private rerender(): void {\n const wasOpen = this.isOpen;\n const previousQuery = this.inputElement?.value ?? '';\n // render() replaces the DOM but does not touch isOpen, so flip it to\n // false so open() will re-apply the `.open` class on the new elements.\n // Skip the scroll-lock side effects since they are already in place.\n this.isOpen = false;\n this.render();\n if (wasOpen) {\n this.isOpen = true;\n this.backdrop?.classList.add('open');\n this.modal?.classList.add('open');\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n this.inputElement?.focus();\n });\n });\n }\n if (previousQuery && this.inputElement) {\n this.inputElement.value = previousQuery;\n if (previousQuery.trim().length > 0) {\n this.performSearch(previousQuery.trim());\n }\n }\n }\n\n private syncTranslationsFromAttribute(): void {\n if (this.translationsOverride) {\n this.resolvedTranslations = mergeTranslations(this.translationsOverride);\n return;\n }\n const parsed = parseTranslationsAttribute(\n this.getAttribute('translations'),\n 'SearchModalSnippet'\n );\n this.resolvedTranslations = mergeTranslations(parsed);\n }\n\n private getProps(): SearchModalProps {\n const t = this.resolvedTranslations;\n return {\n apiUrl: parseAttribute(this.getAttribute('api-url'), ''),\n placeholder: parseAttribute(this.getAttribute('placeholder'), t.placeholder),\n maxResults: parseNumberAttribute(\n this.getAttribute('max-results'),\n DEFAULT_REQUEST_MAX_RESULTS\n ),\n maxRenderResults: parseNumberAttribute(\n this.getAttribute('max-render-results'),\n DEFAULT_RENDER_RESULTS\n ),\n debounceMs: parseNumberAttribute(this.getAttribute('debounce-ms'), 300),\n theme: parseAttribute(this.getAttribute('theme'), 'auto') as 'light' | 'dark' | 'auto',\n shortcut: parseAttribute(this.getAttribute('shortcut'), 'k'),\n useMetaKey: this.getAttribute('use-meta-key') !== 'false',\n hideBranding: parseBooleanAttribute(this.getAttribute('hide-branding'), false),\n showUrl: parseBooleanAttribute(this.getAttribute('show-url'), false),\n showDate: parseBooleanAttribute(this.getAttribute('show-date'), false),\n hideThumbnails: parseBooleanAttribute(this.getAttribute('hide-thumbnails'), false),\n seeMore: parseAttribute(this.getAttribute('see-more'), ''),\n translations: this.translationsOverride ?? undefined,\n };\n }\n\n private getRequestOptions(): SearchRequestOptions | undefined {\n const rawRequestOptions = this.getAttribute('request-options');\n\n if (!rawRequestOptions) {\n return undefined;\n }\n\n try {\n const parsedRequestOptions = JSON.parse(rawRequestOptions) as unknown;\n\n if (\n parsedRequestOptions === null ||\n typeof parsedRequestOptions !== 'object' ||\n Array.isArray(parsedRequestOptions)\n ) {\n throw new Error('request-options must be a JSON object');\n }\n\n return parsedRequestOptions as SearchRequestOptions;\n } catch (error) {\n console.error('SearchModalSnippet: invalid request-options attribute', error);\n return undefined;\n }\n }\n\n private initializeClient(): void {\n const props = this.getProps();\n\n if (!props.apiUrl) {\n console.error('SearchModalSnippet: api-url attribute is required');\n this.client = null;\n this.showMissingApiUrlError();\n return;\n }\n\n try {\n this.client = createClient(props.apiUrl);\n } catch (error) {\n console.error('SearchModalSnippet:', error);\n }\n }\n\n private render(): void {\n const props = this.getProps();\n const t = this.resolvedTranslations;\n\n // Create debounced search function\n const searchFn = (query: string) => this.performSearch(query);\n this.debouncedSearch = debounce(\n searchFn as (...args: unknown[]) => unknown,\n props.debounceMs || 300\n );\n\n const style = document.createElement('style');\n style.textContent = `${baseStyles}\\n${modalStyles}`;\n\n const brandingHTML = props.hideBranding\n ? ''\n : `<div class=\"powered-by-inline\">${POWERED_BY_BRANDING}</div>`;\n\n const container = document.createElement('div');\n container.innerHTML = `\n <div class=\"modal-backdrop\" role=\"presentation\"></div>\n <div class=\"modal-container\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"modal-title\">\n <div class=\"modal-header\">\n <svg class=\"modal-search-icon\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 -960 960 960\" fill=\"currentColor\">\n <path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/>\n </svg>\n <input\n type=\"text\"\n class=\"modal-search-input\"\n placeholder=\"${escapeHTML(props.placeholder || t.placeholder)}\"\n aria-label=\"${escapeHTML(t.searchButtonLabel)}\"\n aria-autocomplete=\"list\"\n aria-controls=\"modal-results-list\"\n aria-expanded=\"false\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n </div>\n <div class=\"modal-content\">\n <div class=\"modal-results\" id=\"modal-results-list\" role=\"listbox\" aria-label=\"${escapeHTML(t.searchResultsAriaLabel)}\">\n ${this.renderEmptyState()}\n </div>\n </div>\n <div class=\"modal-footer\">\n <div class=\"modal-footer-hints\">\n <div class=\"modal-footer-hint\">\n <kbd class=\"modal-kbd\">↑</kbd>\n <kbd class=\"modal-kbd\">↓</kbd>\n <span>${escapeHTML(t.navigateHint)}</span>\n </div>\n <div class=\"modal-footer-hint\">\n <kbd class=\"modal-kbd\">↵</kbd>\n <span>${escapeHTML(t.selectHint)}</span>\n </div>\n <div class=\"modal-footer-hint\">\n <kbd class=\"modal-kbd\">Esc</kbd>\n <span>${escapeHTML(t.closeHint)}</span>\n </div>\n </div>\n ${brandingHTML}\n </div>\n </div>\n `;\n\n this.shadow.innerHTML = '';\n this.shadow.appendChild(style);\n this.shadow.appendChild(container);\n\n // Get references to elements\n this.backdrop = this.shadow.querySelector('.modal-backdrop');\n this.modal = this.shadow.querySelector('.modal-container');\n this.inputElement = this.shadow.querySelector('.modal-search-input');\n this.resultsContainer = this.shadow.querySelector('.modal-results');\n this.footerCount = this.shadow.querySelector('.modal-results-count');\n\n this.attachEventListeners();\n\n // Show error immediately if api-url was missing when the component was connected\n if (!this.client) {\n this.showMissingApiUrlError();\n }\n }\n\n private attachGlobalKeyboardShortcut(): void {\n const props = this.getProps();\n const shortcutKey = props.shortcut?.toLowerCase() || 'k';\n\n this.handleGlobalKeydown = (e: KeyboardEvent) => {\n // Check for shortcut to open modal\n const modifierPressed = props.useMetaKey ? e.metaKey || e.ctrlKey : e.ctrlKey;\n\n if (modifierPressed && e.key.toLowerCase() === shortcutKey && !this.isOpen) {\n e.preventDefault();\n this.open();\n }\n };\n\n document.addEventListener('keydown', this.handleGlobalKeydown);\n }\n\n private attachEventListeners(): void {\n if (!this.inputElement || !this.backdrop) return;\n\n // Input change event\n this.handleInputChange = (e: Event) => {\n const target = e.target as HTMLInputElement;\n const query = target.value.trim();\n\n if (query.length > 0 && this.debouncedSearch) {\n this.debouncedSearch(query);\n } else {\n this.debouncedSearch?.cancel();\n this.currentSearchController?.abort();\n this.results = [];\n this.activeIndex = -1;\n this.showEmptyState();\n }\n };\n this.inputElement.addEventListener('input', this.handleInputChange);\n\n // Keyboard navigation\n this.handleInputKeydown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n this.navigateResults(1);\n break;\n case 'ArrowUp':\n e.preventDefault();\n this.navigateResults(-1);\n break;\n case 'Enter':\n e.preventDefault();\n this.selectActiveResult();\n break;\n case 'Escape':\n e.preventDefault();\n this.close();\n break;\n }\n };\n this.inputElement.addEventListener('keydown', this.handleInputKeydown);\n\n // Backdrop click to close\n this.handleBackdropClick = (e: MouseEvent) => {\n if (e.target === this.backdrop) {\n this.close();\n }\n };\n this.backdrop.addEventListener('click', this.handleBackdropClick);\n }\n\n private navigateResults(direction: number): void {\n if (this.results.length === 0) return;\n\n const newIndex = this.activeIndex + direction;\n\n if (newIndex < 0) {\n this.activeIndex = this.results.length - 1;\n } else if (newIndex >= this.results.length) {\n this.activeIndex = 0;\n } else {\n this.activeIndex = newIndex;\n }\n\n this.updateActiveResult();\n }\n\n private updateActiveResult(): void {\n const items = this.resultsContainer?.querySelectorAll('.modal-result-item');\n if (!items) return;\n\n items.forEach((item, index) => {\n if (index === this.activeIndex) {\n item.classList.add('active');\n item.setAttribute('aria-selected', 'true');\n // Scroll into view if needed\n (item as HTMLElement).scrollIntoView({ block: 'nearest' });\n } else {\n item.classList.remove('active');\n item.setAttribute('aria-selected', 'false');\n }\n });\n\n // Update aria-activedescendant\n if (this.inputElement && this.activeIndex >= 0) {\n this.inputElement.setAttribute('aria-activedescendant', `result-${this.activeIndex}`);\n } else if (this.inputElement) {\n this.inputElement.removeAttribute('aria-activedescendant');\n }\n }\n\n private selectActiveResult(): void {\n if (this.activeIndex < 0 || this.activeIndex >= this.results.length) {\n // If no result selected but there's a query, perform immediate search\n const query = this.inputElement?.value.trim();\n if (query && query.length > 0) {\n this.performSearch(query);\n }\n return;\n }\n\n const result = this.results[this.activeIndex];\n this.dispatchEvent(\n createCustomEvent('result-select', {\n result,\n index: this.activeIndex,\n })\n );\n\n // Navigate to URL - click the active link element to trigger navigation\n const activeItem = this.resultsContainer?.querySelector(\n `.modal-result-item[data-index=\"${this.activeIndex}\"]`\n ) as HTMLAnchorElement | null;\n\n if (activeItem && result.url) {\n activeItem.click();\n }\n\n this.close();\n }\n\n private async performSearch(query: string): Promise<void> {\n if (!this.client) {\n this.showMissingApiUrlError();\n return;\n }\n\n // Cancel any existing request before starting a new one\n if (this.currentSearchController) {\n this.currentSearchController.abort();\n this.currentSearchController = null;\n }\n\n // Create new controller for this request\n this.currentSearchController = new AbortController();\n this.showLoadingState();\n\n try {\n const props = this.getProps();\n const results = await this.client.search(query, {\n signal: this.currentSearchController.signal,\n maxResults: props.maxResults || DEFAULT_REQUEST_MAX_RESULTS,\n request: this.getRequestOptions(),\n });\n this.results = results.slice(0, props.maxRenderResults || DEFAULT_RENDER_RESULTS);\n this.activeIndex = this.results.length > 0 ? 0 : -1;\n this.displayResults(this.results, query, results.length);\n } catch (error) {\n // Don't show error state for cancelled requests\n if ((error as Error).name === 'AbortError') {\n return;\n }\n this.showErrorState((error as Error).message);\n } finally {\n this.currentSearchController = null;\n }\n }\n\n private displayResults(\n results: SearchResult[],\n query: string,\n totalResults = results.length\n ): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n\n if (results.length === 0) {\n this.showNoResultsState(query);\n return;\n }\n\n const props = this.getProps();\n const t = this.resolvedTranslations;\n const resultsHTML = results.map((result, index) => this.renderResult(result, index)).join('');\n const hasMoreResults = totalResults > results.length;\n const resultsCountLabel = hasMoreResults\n ? interpolate(t.resultsCountOverflow, { n: results.length, total: totalResults })\n : interpolate(totalResults === 1 ? t.modalResultsCount : t.modalResultsCountPlural, {\n n: totalResults,\n });\n const seeMoreHTML =\n props.seeMore && hasMoreResults\n ? `<a href=\"${escapeHTML(props.seeMore + encodeURIComponent(query))}\" class=\"modal-see-more\">\n <span>${escapeHTML(t.seeMoreResults)}</span>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/></svg>\n </a>`\n : '';\n\n this.resultsContainer.innerHTML = resultsHTML + seeMoreHTML;\n\n // Update footer count\n if (this.footerCount) {\n this.footerCount.textContent = resultsCountLabel;\n }\n\n // Update aria-expanded\n if (this.inputElement) {\n this.inputElement.setAttribute('aria-expanded', 'true');\n }\n\n // Attach click handlers\n this.attachResultHandlers();\n\n // Update active state\n this.updateActiveResult();\n }\n\n private renderResult(result: SearchResult, index: number): string {\n const props = this.getProps();\n const imageHTML = props.hideThumbnails\n ? ''\n : this.renderResultImage(result.image, result.title);\n const href = result.url ? escapeHTML(result.url) : '#';\n const displayUrl = result.url ? escapeHTML(formatDisplayUrl(result.url)) : '';\n const timestampHTML =\n props.showDate && result.timestamp !== undefined\n ? `<div class=\"modal-result-date\">${escapeHTML(formatDate(result.timestamp))}</div>`\n : '';\n const metadataHTML =\n (props.showUrl && result.url) || timestampHTML\n ? `<div class=\"modal-result-metadata\">\n ${props.showUrl && result.url ? `<span class=\"modal-result-url\">${displayUrl}</span>` : '<span class=\"modal-result-url modal-result-url-empty\"></span>'}\n ${timestampHTML}\n </div>`\n : '';\n\n return `\n <a \n href=\"${href}\"\n class=\"modal-result-item${index === this.activeIndex ? ' active' : ''}\" \n role=\"option\" \n id=\"result-${index}\"\n aria-selected=\"${index === this.activeIndex}\"\n tabindex=\"-1\"\n data-index=\"${index}\"\n data-url=\"${escapeHTML(result.url || '')}\"\n >\n ${imageHTML}\n <div class=\"modal-result-content\">\n <div class=\"modal-result-title\">${escapeHTML(result.title || '')}</div>\n ${result.description ? `<div class=\"modal-result-description\">${escapeHTML(result.description)}</div>` : ''}\n ${metadataHTML}\n </div>\n </a>\n `;\n }\n\n private renderResultImage(imageUrl: string | undefined, alt: string): string {\n const placeholderSVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"/><polyline points=\"10 9 9 9 8 9\"/></svg>`;\n\n if (!imageUrl) {\n return `\n <div class=\"modal-result-image-container\">\n <div class=\"modal-result-image-placeholder\">${placeholderSVG}</div>\n </div>\n `;\n }\n\n return `\n <div class=\"modal-result-image-container\">\n <div class=\"modal-result-image-loading\"></div>\n <div class=\"modal-result-image-placeholder\" style=\"display: none;\">${placeholderSVG}</div>\n <img \n class=\"modal-result-image\" \n src=\"${escapeHTML(imageUrl)}\" \n alt=\"${escapeHTML(alt)}\"\n loading=\"lazy\"\n />\n </div>\n `;\n }\n\n private attachResultHandlers(): void {\n const items = this.resultsContainer?.querySelectorAll('.modal-result-item');\n if (!items) return;\n\n items.forEach((item, index) => {\n // Handle clicks on results without URLs (prevent default anchor behavior)\n const href = item.getAttribute('href');\n if (href === '#') {\n item.addEventListener('click', (e) => {\n e.preventDefault();\n });\n }\n\n item.addEventListener('mouseenter', () => {\n this.activeIndex = index;\n this.updateActiveResult();\n });\n });\n\n // Image load/error handlers\n const images = this.resultsContainer?.querySelectorAll('.modal-result-image');\n images?.forEach((img) => {\n img.addEventListener('load', () => {\n img.classList.add('loaded');\n const container = img.closest('.modal-result-image-container');\n container?.querySelector('.modal-result-image-loading')?.remove();\n });\n\n img.addEventListener('error', () => {\n const container = img.closest('.modal-result-image-container');\n container?.querySelector('.modal-result-image-loading')?.remove();\n const placeholder = container?.querySelector(\n '.modal-result-image-placeholder'\n ) as HTMLElement;\n if (placeholder) placeholder.style.display = 'flex';\n (img as HTMLElement).style.display = 'none';\n });\n });\n }\n\n private renderEmptyState(): string {\n const t = this.resolvedTranslations;\n return `\n <div class=\"modal-empty\">\n <svg class=\"modal-empty-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <path d=\"m21 21-4.35-4.35\"></path>\n </svg>\n <div class=\"modal-empty-description\">${escapeHTML(t.modalEmptyStateDescription)}</div>\n </div>\n `;\n }\n\n private showEmptyState(): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n this.resultsContainer.innerHTML = this.renderEmptyState();\n\n if (this.footerCount) {\n this.footerCount.textContent = '';\n }\n\n if (this.inputElement) {\n this.inputElement.setAttribute('aria-expanded', 'false');\n }\n }\n\n private showLoadingState(): void {\n if (!this.resultsContainer) return;\n\n this.clearLoadingInterval();\n const messages = this.resolvedTranslations.loadingMessages;\n const t = this.resolvedTranslations;\n this.loadingMessageIndex = Math.floor(Math.random() * messages.length);\n\n this.resultsContainer.innerHTML = `\n <div class=\"modal-loading\">\n <div class=\"loading\" aria-label=\"${escapeHTML(t.loadingAriaLabel)}\"></div>\n <div class=\"loading-text loading-text-animate\">${escapeHTML(messages[this.loadingMessageIndex])}</div>\n </div>\n `;\n\n if (this.footerCount) {\n this.footerCount.textContent = messages[this.loadingMessageIndex];\n }\n\n this.startLoadingInterval();\n }\n\n private startLoadingInterval(): void {\n this.loadingMessageInterval = setInterval(() => {\n const messages = this.resolvedTranslations.loadingMessages;\n this.loadingMessageIndex = (this.loadingMessageIndex + 1) % messages.length;\n const textEl = this.resultsContainer?.querySelector('.loading-text');\n if (textEl) {\n textEl.classList.remove('loading-text-animate');\n void (textEl as HTMLElement).offsetWidth;\n textEl.textContent = messages[this.loadingMessageIndex];\n textEl.classList.add('loading-text-animate');\n }\n if (this.footerCount) {\n this.footerCount.textContent = messages[this.loadingMessageIndex];\n }\n }, LOADING_MESSAGE_INTERVAL_MS);\n }\n\n private clearLoadingInterval(): void {\n if (this.loadingMessageInterval) {\n clearInterval(this.loadingMessageInterval);\n this.loadingMessageInterval = null;\n }\n }\n\n private showNoResultsState(query: string): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n const t = this.resolvedTranslations;\n\n this.resultsContainer.innerHTML = `\n <div class=\"modal-empty\">\n <svg class=\"modal-empty-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n </svg>\n <div class=\"modal-empty-title\">${escapeHTML(t.modalNoResultsTitle)}</div>\n <div class=\"modal-empty-description\">${escapeHTML(interpolate(t.modalNoResultsDescription, { query }))}</div>\n </div>\n `;\n\n if (this.footerCount) {\n this.footerCount.textContent = t.modalResultsCountZero;\n }\n\n if (this.inputElement) {\n this.inputElement.setAttribute('aria-expanded', 'false');\n }\n }\n\n private showErrorState(message: string): void {\n this.clearLoadingInterval();\n if (!this.resultsContainer) return;\n const t = this.resolvedTranslations;\n\n this.resultsContainer.innerHTML = `\n <div class=\"error\">\n <strong>${escapeHTML(t.errorPrefix)}</strong> ${escapeHTML(message)}\n </div>\n `;\n\n if (this.footerCount) {\n this.footerCount.textContent = t.modalResultsCountError;\n }\n }\n\n private showMissingApiUrlError(): void {\n if (this.resultsContainer) {\n this.showErrorState(this.resolvedTranslations.missingApiUrlError);\n }\n }\n\n private updateTheme(theme: string | null): void {\n const validTheme = theme === 'light' || theme === 'dark' || theme === 'auto' ? theme : 'auto';\n\n if (validTheme === 'auto') {\n this.removeAttribute('theme');\n } else {\n this.setAttribute('theme', validTheme);\n }\n }\n\n private lockBodyScroll(): void {\n // Save current body styles\n const scrollY = window.scrollY;\n this.savedBodyStyles = {\n overflow: document.body.style.overflow,\n position: document.body.style.position,\n top: document.body.style.top,\n width: document.body.style.width,\n scrollbarGutter: document.body.style.scrollbarGutter,\n };\n\n this.savedHtmlOverflow = document.documentElement.style.overflow;\n\n // Apply scroll lock styles to both html and body for cross-browser support\n document.body.style.scrollbarGutter = 'stable';\n document.documentElement.style.overflow = 'hidden';\n document.body.style.overflow = 'hidden';\n document.body.style.position = 'fixed';\n document.body.style.top = `-${scrollY}px`;\n document.body.style.width = '100%';\n }\n\n private unlockBodyScroll(): void {\n if (!this.savedBodyStyles) return;\n\n // Get the scroll position from the top style\n const scrollY = Math.abs(Number.parseInt(document.body.style.top || '0', 10));\n\n // Restore original styles\n document.documentElement.style.overflow = this.savedHtmlOverflow || '';\n document.body.style.overflow = this.savedBodyStyles.overflow;\n document.body.style.position = this.savedBodyStyles.position;\n document.body.style.top = this.savedBodyStyles.top;\n document.body.style.width = this.savedBodyStyles.width;\n document.body.style.scrollbarGutter = this.savedBodyStyles.scrollbarGutter || '';\n\n // Restore scroll position\n window.scrollTo(0, scrollY);\n\n this.savedBodyStyles = null;\n this.savedHtmlOverflow = null;\n }\n\n private cleanup(): void {\n this.clearLoadingInterval();\n\n // Cancel any in-flight search request\n if (this.currentSearchController) {\n this.currentSearchController.abort();\n this.currentSearchController = null;\n }\n\n // Remove global keyboard listener\n if (this.handleGlobalKeydown) {\n document.removeEventListener('keydown', this.handleGlobalKeydown);\n this.handleGlobalKeydown = null;\n }\n\n // Remove element event listeners\n if (this.inputElement) {\n if (this.handleInputChange) {\n this.inputElement.removeEventListener('input', this.handleInputChange);\n }\n if (this.handleInputKeydown) {\n this.inputElement.removeEventListener('keydown', this.handleInputKeydown);\n }\n }\n\n if (this.backdrop && this.handleBackdropClick) {\n this.backdrop.removeEventListener('click', this.handleBackdropClick);\n }\n\n // Clear handler references\n this.handleInputChange = null;\n this.handleInputKeydown = null;\n this.handleBackdropClick = null;\n\n // Cancel any pending requests\n if (this.client) {\n this.client.cancelAllRequests();\n }\n }\n\n // Public API\n\n /**\n * Open the search modal\n */\n public open(): void {\n if (this.isOpen) return;\n\n this.isOpen = true;\n this.backdrop?.classList.add('open');\n this.modal?.classList.add('open');\n\n // Focus input after animation completes\n // Use double rAF to ensure DOM has updated and transitions have started\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n this.inputElement?.focus();\n });\n });\n\n // Prevent body scroll (save current styles to restore later)\n this.lockBodyScroll();\n\n this.dispatchEvent(createCustomEvent('open', undefined));\n }\n\n /**\n * Close the search modal\n */\n public close(): void {\n if (!this.isOpen) return;\n\n this.isOpen = false;\n this.backdrop?.classList.remove('open');\n this.modal?.classList.remove('open');\n\n // Clear state\n if (this.inputElement) {\n this.inputElement.value = '';\n }\n this.results = [];\n this.activeIndex = -1;\n this.showEmptyState();\n\n // Restore body scroll\n this.unlockBodyScroll();\n\n this.dispatchEvent(createCustomEvent('close', undefined));\n }\n\n /**\n * Toggle the search modal open/closed\n */\n public toggle(): void {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * Perform a search programmatically\n */\n public async search(query: string): Promise<void> {\n if (!this.isOpen) {\n this.open();\n }\n\n if (this.inputElement) {\n this.inputElement.value = query;\n }\n\n await this.performSearch(query);\n }\n\n /**\n * Get current search results\n */\n public getResults(): SearchResult[] {\n return [...this.results];\n }\n\n /**\n * Check if modal is currently open\n */\n public isModalOpen(): boolean {\n return this.isOpen;\n }\n}\n\n// Register the custom element\nif (!customElements.get(COMPONENT_NAME)) {\n customElements.define(COMPONENT_NAME, SearchModalSnippet);\n}\n"],"names":["DEFAULT_TRANSLATIONS","mergeTranslations","user","merged","key","value","m","interpolate","template","vars","match","name","parseTranslationsAttribute","raw","componentName","parsed","error","LOADING_MESSAGE_INTERVAL_MS","debounce","func","wait","timeout","executedFunction","args","escapeHTML","text","div","formatDisplayUrl","url","decodeHTMLEntities","formatTimestamp","timestamp","translations","t","date","diff","minutes","hours","formatDate","generateId","prefix","parseAttribute","defaultValue","parseBooleanAttribute","parseNumberAttribute","createCustomEvent","detail","createClient","apiUrl","AISearchClient","isRecord","deepMergeRecords","records","record","currentValue","buildRequestUrl","endpoint","queryParams","searchParams","query","hashIndex","path","hash","separator","normalizeHeaders","headers","normalizedHeaders","normalizeBody","body","baseUrl","__publicField","operation","signal","requestOptions","sourceHeader","options","requestId","controller","response","result","chunk","chunks","reader","decoder","done","choice","request","id","CLOUDFLARE_LOGO_SVG","CLOUDFLARE_SEARCH_URL","POWERED_BY_BRANDING","chatStyles","baseStyles","markdownToHtml","markdown","html","escapeHtml","_","code","lines","processedLines","inList","listType","i","line","headerMatch","level","content","processInlineMarkdown","ulMatch","olMatch","htmlEntities","char","ChatView","container","client","props","e","target","userMessage","assistantMessageId","assistantMessage","stream","fullContent","messageIndex","message","messageId","isStreaming","messagesHTML","roleClass","avatar","loadingMessage","streaming","messages","current","COMPONENT_NAME","ChatBubbleSnippet","oldValue","newValue","wasExpanded","wasMinimized","previousChatContent","chatWindow","placeholder","style","brandingHTML","bubbleButton","closeButton","minimizeButton","clearButton","chatContent","theme","STORAGE_KEY","ChatPageSnippet","changed","session","newChatSlot","escapeHTMLUtil","newChatButton","toggleSidebarButton","chatList","lastSession","stored","a","b","sessionIndex","s","firstUserMessage","newSession","sessionId","deleteButton","chatItem","isActive","deleteTitle","diffMs","diffDays","str","searchStyles","DEFAULT_RENDER_RESULTS","DEFAULT_REQUEST_MAX_RESULTS","SearchBarSnippet","previousQuery","rawRequestOptions","parsedRequestOptions","searchFn","results","visibleResults","totalResults","hasMoreResults","resultsCountLabel","seeMoreHTML","resultsHTML","imageHTML","href","displayUrl","timestampHTML","metadataHTML","imageUrl","alt","placeholderSVG","resultItems","item","img","textEl","validTheme","modalStyles","SearchModalSnippet","wasOpen","shortcutKey","direction","newIndex","items","index","activeItem","scrollY"],"mappings":"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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GCAbC,IAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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wB;AAC9B,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GC0BrBtE,IAAiB,wBACjB2C,IAAy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"}
|