@chatwidgetai/chat-widget 0.3.0 → 0.3.6

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.
Files changed (37) hide show
  1. package/dist/ai-chat-widget.umd.js +1903 -437
  2. package/dist/ai-chat-widget.umd.js.map +1 -1
  3. package/dist/api/client.d.ts +11 -2
  4. package/dist/api/client.d.ts.map +1 -1
  5. package/dist/components/ChatWidget.d.ts +2 -1
  6. package/dist/components/ChatWidget.d.ts.map +1 -1
  7. package/dist/components/ChatWindow.d.ts +1 -1
  8. package/dist/components/ChatWindow.d.ts.map +1 -1
  9. package/dist/components/DataPolicyView.d.ts +14 -0
  10. package/dist/components/DataPolicyView.d.ts.map +1 -0
  11. package/dist/hooks/useChat/action-handler.d.ts +6 -0
  12. package/dist/hooks/useChat/action-handler.d.ts.map +1 -0
  13. package/dist/hooks/useChat/action-lifecycle.d.ts +19 -0
  14. package/dist/hooks/useChat/action-lifecycle.d.ts.map +1 -0
  15. package/dist/hooks/useChat/error-utils.d.ts +7 -0
  16. package/dist/hooks/useChat/error-utils.d.ts.map +1 -0
  17. package/dist/hooks/{useChat.d.ts → useChat/index.d.ts} +4 -2
  18. package/dist/hooks/useChat/index.d.ts.map +1 -0
  19. package/dist/hooks/useChat/message-hydration.d.ts +4 -0
  20. package/dist/hooks/useChat/message-hydration.d.ts.map +1 -0
  21. package/dist/hooks/useChat/stream-handlers.d.ts +27 -0
  22. package/dist/hooks/useChat/stream-handlers.d.ts.map +1 -0
  23. package/dist/hooks/useChat/stream-state.d.ts +8 -0
  24. package/dist/hooks/useChat/stream-state.d.ts.map +1 -0
  25. package/dist/hooks/useChat/types.d.ts +26 -0
  26. package/dist/hooks/useChat/types.d.ts.map +1 -0
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.esm.js +1904 -438
  30. package/dist/index.esm.js.map +1 -1
  31. package/dist/index.js +1904 -437
  32. package/dist/index.js.map +1 -1
  33. package/dist/types/index.d.ts +22 -0
  34. package/dist/types/index.d.ts.map +1 -1
  35. package/dist/utils/sse-parser.d.ts.map +1 -1
  36. package/package.json +7 -3
  37. package/dist/hooks/useChat.d.ts.map +0 -1
package/dist/index.esm.js CHANGED
@@ -8,11 +8,14 @@ async function* parseSSEStream(response, validator) {
8
8
  const reader = response.body.getReader();
9
9
  const decoder = new TextDecoder();
10
10
  let buffer = "";
11
+ let eventCount = 0;
11
12
  try {
12
13
  while (true) {
13
14
  const { done, value } = await reader.read();
14
- if (done)
15
+ if (done) {
16
+ console.log(`[SSE Parser] Stream ended normally after ${eventCount} events`);
15
17
  break;
18
+ }
16
19
  buffer += decoder.decode(value, { stream: true });
17
20
  const chunks = buffer.split("\n\n");
18
21
  buffer = chunks.pop() || "";
@@ -24,6 +27,7 @@ async function* parseSSEStream(response, validator) {
24
27
  const data = JSON.parse(line.slice(6));
25
28
  if (validator) {
26
29
  if (validator(data)) {
30
+ eventCount++;
27
31
  yield data;
28
32
  }
29
33
  else {
@@ -31,6 +35,7 @@ async function* parseSSEStream(response, validator) {
31
35
  }
32
36
  }
33
37
  else {
38
+ eventCount++;
34
39
  yield data;
35
40
  }
36
41
  }
@@ -43,6 +48,10 @@ async function* parseSSEStream(response, validator) {
43
48
  }
44
49
  }
45
50
  }
51
+ catch (error) {
52
+ console.error(`[SSE Parser] Stream error after ${eventCount} events:`, error);
53
+ throw error;
54
+ }
46
55
  finally {
47
56
  reader.releaseLock();
48
57
  }
@@ -176,7 +185,7 @@ class WidgetApiClient {
176
185
  const result = await response.json();
177
186
  return result.file;
178
187
  }
179
- async *sendAgentMessageStream(conversationId, message, fileIds) {
188
+ async *sendAgentMessageStream(conversationId, message, fileIds, signal) {
180
189
  const headers = {
181
190
  'Content-Type': 'application/json',
182
191
  };
@@ -192,6 +201,7 @@ class WidgetApiClient {
192
201
  fileIds,
193
202
  timeZone: this.getTimeZone(),
194
203
  }),
204
+ signal,
195
205
  });
196
206
  if (!response.ok) {
197
207
  throw await buildApiError(response, 'Failed to send agent message');
@@ -200,7 +210,7 @@ class WidgetApiClient {
200
210
  return typeof data === 'object' && data !== null && 'type' in data;
201
211
  });
202
212
  }
203
- async *continueAgentMessageStream(conversationId, toolCallId, state) {
213
+ async *continueAgentMessageStream(conversationId, toolCallId, state, signal) {
204
214
  const headers = {
205
215
  'Content-Type': 'application/json',
206
216
  };
@@ -216,6 +226,7 @@ class WidgetApiClient {
216
226
  state,
217
227
  timeZone: this.getTimeZone(),
218
228
  }),
229
+ signal,
219
230
  });
220
231
  if (!response.ok) {
221
232
  throw await buildApiError(response, 'Failed to continue agent');
@@ -224,6 +235,33 @@ class WidgetApiClient {
224
235
  return typeof data === 'object' && data !== null && 'type' in data;
225
236
  });
226
237
  }
238
+ async *dismissAgentMessageStream(conversationId, toolCallId, signal) {
239
+ const headers = {
240
+ 'Content-Type': 'application/json',
241
+ };
242
+ if (this.config.currentRoute) {
243
+ headers['X-Current-Route'] = this.config.currentRoute;
244
+ }
245
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/dismiss`, {
246
+ method: 'POST',
247
+ headers,
248
+ body: JSON.stringify({
249
+ conversationId: conversationId,
250
+ toolCallId,
251
+ reason: "user",
252
+ }),
253
+ signal,
254
+ });
255
+ if (response.status === 204) {
256
+ return;
257
+ }
258
+ if (!response.ok) {
259
+ throw await buildApiError(response, 'Failed to dismiss action');
260
+ }
261
+ yield* parseSSEStream(response, (data) => {
262
+ return typeof data === 'object' && data !== null && 'type' in data;
263
+ });
264
+ }
227
265
  /**
228
266
  * Submit feedback for a message
229
267
  */
@@ -286,6 +324,27 @@ class WidgetApiClient {
286
324
  return [];
287
325
  }
288
326
  }
327
+ /**
328
+ * Create a demo conversation with preset messages
329
+ * Used when demo animation completes to persist the demo conversation to the database
330
+ */
331
+ async createDemoConversation(userMessage, assistantMessage) {
332
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/demo-conversation`, {
333
+ method: 'POST',
334
+ headers: {
335
+ 'Content-Type': 'application/json',
336
+ },
337
+ body: JSON.stringify({
338
+ userMessage,
339
+ assistantMessage,
340
+ timeZone: this.getTimeZone(),
341
+ }),
342
+ });
343
+ if (!response.ok) {
344
+ throw await buildApiError(response, 'Failed to create demo conversation');
345
+ }
346
+ return response.json();
347
+ }
289
348
  /**
290
349
  * Validate widget access
291
350
  */
@@ -27116,22 +27175,19 @@ function ScrollButton({ onClick, visible, className = '' }) {
27116
27175
  const formatToolName = (name) => {
27117
27176
  return name
27118
27177
  .replace(/^(action_|tool_)/, '')
27178
+ .replace(/-/g, '_')
27119
27179
  .split('_')
27120
27180
  .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
27121
27181
  .join(' ');
27122
27182
  };
27123
- const GearIcon = ({ spinning = false }) => (jsxs("svg", { className: `ai-chat-tool-gear ${spinning ? 'spinning' : ''}`, width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M12 20a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z" }), jsx("path", { d: "M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z" }), jsx("path", { d: "M12 2v2" }), jsx("path", { d: "M12 22v-2" }), jsx("path", { d: "m17 20.66-1-1.73" }), jsx("path", { d: "M11 10.27 7 3.34" }), jsx("path", { d: "m20.66 17-1.73-1" }), jsx("path", { d: "m3.34 7 1.73 1" }), jsx("path", { d: "M14 12h8" }), jsx("path", { d: "M2 12h2" }), jsx("path", { d: "m20.66 7-1.73 1" }), jsx("path", { d: "m3.34 17 1.73-1" }), jsx("path", { d: "m17 3.34-1 1.73" }), jsx("path", { d: "m11 13.73-4 6.93" })] }));
27124
- const CheckIcon$2 = () => (jsx("svg", { className: "ai-chat-tool-check", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "20 6 9 17 4 12" }) }));
27125
- const ErrorIcon = () => (jsx("svg", { className: "ai-chat-tool-error", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }));
27126
27183
  function ToolIndicator({ badges, className = '' }) {
27127
- const isAnyLoading = badges.some(b => b.status === 'loading');
27128
- return (jsxs("div", { className: `ai-chat-tool-row ${className}`, children: [jsx(GearIcon, { spinning: isAnyLoading }), jsx("div", { className: "ai-chat-tool-badges", children: badges.map((badge) => (jsxs("div", { className: `ai-chat-tool-badge ${badge.status}`, children: [badge.status !== 'loading' && (badge.status === 'error' ? jsx(ErrorIcon, {}) : jsx(CheckIcon$2, {})), jsx("span", { className: "tool-name", children: formatToolName(badge.name) })] }, badge.id))) })] }));
27184
+ return (jsx("div", { className: `ai-chat-tool-row ${className}`, children: jsx("div", { className: "ai-chat-tool-badges", children: badges.map((badge) => (jsx("div", { className: `ai-chat-tool-badge ${badge.status}`, children: jsx("span", { className: "tool-name", children: formatToolName(badge.name) }) }, badge.id))) }) }));
27129
27185
  }
27130
27186
 
27131
27187
  // SVG Icon components
27132
27188
  const ThumbsUpIcon = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3" }) }));
27133
27189
  const ThumbsDownIcon = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" }) }));
27134
- const CheckIcon$1 = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "20 6 9 17 4 12" }) }));
27190
+ const CheckIcon$2 = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "20 6 9 17 4 12" }) }));
27135
27191
  const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
27136
27192
  const [isSubmitting, setIsSubmitting] = useState(false);
27137
27193
  const [submitted, setSubmitted] = useState(false);
@@ -27152,10 +27208,10 @@ const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
27152
27208
  setIsSubmitting(false);
27153
27209
  }
27154
27210
  };
27155
- return (jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsx(ThumbsUpIcon, {}) }), jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'negative' ? 'active' : ''}`, onClick: () => handleFeedback('negative'), disabled: isDisabled, "aria-label": "Not helpful", title: "This was not helpful", children: jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsx("span", { className: "ai-chat-feedback-checkmark", children: jsx(CheckIcon$1, {}) }), jsx("span", { className: "ai-chat-feedback-text", children: "Thanks for feedback" })] }))] }));
27211
+ return (jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsx(ThumbsUpIcon, {}) }), jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'negative' ? 'active' : ''}`, onClick: () => handleFeedback('negative'), disabled: isDisabled, "aria-label": "Not helpful", title: "This was not helpful", children: jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsx("span", { className: "ai-chat-feedback-checkmark", children: jsx(CheckIcon$2, {}) }), jsx("span", { className: "ai-chat-feedback-text", children: "Thanks for feedback" })] }))] }));
27156
27212
  };
27157
27213
 
27158
- const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, getActionRenderer, accentColor, }) => {
27214
+ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, }) => {
27159
27215
  const formatTime = (timestamp) => {
27160
27216
  const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;
27161
27217
  return date.toLocaleTimeString('en-US', {
@@ -27175,15 +27231,15 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedb
27175
27231
  return null;
27176
27232
  }
27177
27233
  // AI message rendering
27234
+ // Note: Actions are rendered by ToolMessageGroup for tool messages, not here
27178
27235
  if (isAssistant) {
27179
27236
  const aiContent = message.message.content || '';
27180
27237
  const hasContent = aiContent.trim().length > 0;
27181
27238
  if (!hasContent)
27182
27239
  return null;
27183
- const actionRenderer = message.action && getActionRenderer
27184
- ? getActionRenderer(message.action.implementation)
27185
- : undefined;
27186
- return (jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsxs("div", { className: "ai-chat-message-content", children: [isError && (jsxs("div", { className: "ai-chat-error-indicator", children: [jsx("span", { className: "error-icon", children: "\u26A0\uFE0F" }), jsx("span", { className: "error-text", children: "Error" })] })), jsx(Markdown, { remarkPlugins: [remarkGfm], children: aiContent })] }), actionRenderer && message.action && actionRenderer(message, accentColor), showTimestamp && (jsxs("div", { className: "ai-chat-message-meta", children: [jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
27240
+ return (jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsx("div", { className: "ai-chat-message-content", children: jsx(Markdown, { remarkPlugins: [remarkGfm], components: {
27241
+ table: ({ children, ...props }) => (jsx("div", { className: "table-wrapper", children: jsx("div", { className: "table-scroll", children: jsx("table", { ...props, children: children }) }) })),
27242
+ }, children: aiContent }) }), showTimestamp && (jsxs("div", { className: "ai-chat-message-meta", children: [jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
27187
27243
  }
27188
27244
  // System message rendering
27189
27245
  if (isSystem) {
@@ -27197,35 +27253,86 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedb
27197
27253
  return null;
27198
27254
  };
27199
27255
 
27200
- const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor }) => {
27201
- const actionMessages = messages.filter(message => message.action);
27256
+ // Centralized action state logic
27257
+ function isActionComplete(state) {
27258
+ if (!state)
27259
+ return false;
27260
+ const TERMINAL_STATUSES = [
27261
+ 'completed', 'booked', 'scheduled', 'cancelled', 'failed', 'error',
27262
+ 'displaying', 'clicked', 'contacted', 'submitted', 'sent'
27263
+ ];
27264
+ const status = state.status;
27265
+ if (typeof status === 'string' && TERMINAL_STATUSES.includes(status)) {
27266
+ return true;
27267
+ }
27268
+ // For non-halting actions (query_contact_directory, etc.) with results/success
27269
+ if (!status && (state.success !== undefined || state.results !== undefined)) {
27270
+ return true;
27271
+ }
27272
+ return false;
27273
+ }
27274
+ function isActionLoading(message) {
27275
+ if (!message.action)
27276
+ return false;
27277
+ if (message.action.done)
27278
+ return false;
27279
+ if (message.isStreaming)
27280
+ return true;
27281
+ const state = message.action.state;
27282
+ return !isActionComplete(state);
27283
+ }
27284
+ const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant, onActionDismiss, }) => {
27285
+ const visibleMessages = messages.filter(message => !message.action?.hidden);
27286
+ const actionMessages = visibleMessages.filter(message => message.action);
27287
+ // Debug logging
27288
+ console.log('[DEBUG ToolMessageGroup] ========================================');
27289
+ console.log('[DEBUG ToolMessageGroup] Total messages:', messages.length);
27290
+ console.log('[DEBUG ToolMessageGroup] Messages with action:', actionMessages.length);
27291
+ console.log('[DEBUG ToolMessageGroup] hasGetActionRenderer:', !!getActionRenderer);
27292
+ messages.forEach((msg, i) => {
27293
+ console.log(`[DEBUG ToolMessageGroup] Message ${i}:`, {
27294
+ id: msg.id,
27295
+ role: msg.message.role,
27296
+ hasAction: !!msg.action,
27297
+ actionImpl: msg.action?.implementation,
27298
+ toolExecuting: msg.toolExecuting,
27299
+ });
27300
+ });
27301
+ actionMessages.forEach((msg, i) => {
27302
+ const impl = msg.action?.implementation || '';
27303
+ const renderer = getActionRenderer?.(impl);
27304
+ console.log(`[DEBUG ToolMessageGroup] Action ${i}:`, {
27305
+ implementation: impl,
27306
+ hasRenderer: !!renderer,
27307
+ rendererType: renderer ? typeof renderer : 'undefined',
27308
+ state: msg.action?.state,
27309
+ });
27310
+ });
27202
27311
  // If tool indicator is hidden AND there are no action cards to render, don't render anything
27203
- // This prevents empty wrapper divs that cause layout jumping
27204
27312
  if (!showToolIndicator && actionMessages.length === 0) {
27205
27313
  return null;
27206
27314
  }
27207
- const badges = messages.map((message) => {
27315
+ const badges = visibleMessages.map((message) => {
27208
27316
  const toolName = message.toolExecuting || message.message.name || 'Tool';
27209
27317
  const hasError = message.isError || false;
27210
- const actionState = message.action?.state;
27211
- const actionStatus = actionState?.status;
27212
- const terminalStatuses = ['completed', 'booked', 'scheduled', 'failed', 'cancelled', 'displaying', 'clicked'];
27213
- const isTerminalStatus = actionStatus && terminalStatuses.includes(actionStatus);
27214
- const isDone = message.action ? (message.action.done ?? isTerminalStatus ?? false) : !message.isStreaming;
27215
- const isLoading = !isDone;
27318
+ const loading = isActionLoading(message);
27216
27319
  return {
27217
27320
  id: message.id,
27218
27321
  name: toolName,
27219
- status: isLoading ? 'loading' : hasError ? 'error' : 'completed',
27322
+ status: loading ? 'loading' : hasError ? 'error' : 'completed',
27220
27323
  };
27221
27324
  });
27222
27325
  return (jsxs("div", { className: "ai-chat-message tool", children: [showToolIndicator && jsx(ToolIndicator, { badges: badges }), actionMessages.map((message) => {
27223
- if (!message.action || !getActionRenderer)
27326
+ if (!message.action || !getActionRenderer) {
27327
+ console.log('[ToolMessageGroup] Skipping - no action or renderer:', { hasAction: !!message.action, hasGetRenderer: !!getActionRenderer });
27224
27328
  return null;
27329
+ }
27225
27330
  const renderer = getActionRenderer(message.action.implementation);
27226
- if (!renderer)
27331
+ if (!renderer) {
27332
+ console.log('[ToolMessageGroup] No renderer for:', message.action.implementation);
27227
27333
  return null;
27228
- return (jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor) }, `action-${message.id}`));
27334
+ }
27335
+ return (jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant, onActionDismiss) }, `action-${message.id}`));
27229
27336
  })] }));
27230
27337
  };
27231
27338
 
@@ -27287,12 +27394,17 @@ const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, acce
27287
27394
  };
27288
27395
 
27289
27396
  const MessageList = (props) => {
27290
- const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onFeedback, onScrollStateChange, getActionRenderer, } = props;
27397
+ const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onActionDismiss, onFeedback, onScrollStateChange, getActionRenderer, variant, } = props;
27291
27398
  const containerRef = useRef(null);
27292
27399
  const messagesEndRef = useRef(null);
27293
27400
  const [showScrollButton, setShowScrollButton] = useState(false);
27294
27401
  const prevMessageCountRef = useRef(0);
27295
- const hasActiveAction = useMemo(() => messages.some(msg => msg.action?.state?.status && !['completed', 'booked', 'failed'].includes(msg.action.state.status)), [messages]);
27402
+ const visibleMessages = useMemo(() => messages.filter((message) => !message.action?.hidden), [messages]);
27403
+ const hasActiveAction = useMemo(() => {
27404
+ // Find the last tool message and check if its action is still active (not done)
27405
+ const lastToolMsg = [...visibleMessages].reverse().find(msg => msg.message.role === 'tool');
27406
+ return lastToolMsg?.action && lastToolMsg.action.done !== true;
27407
+ }, [visibleMessages]);
27296
27408
  const checkScrollPosition = useCallback(() => {
27297
27409
  const c = containerRef.current;
27298
27410
  if (!c)
@@ -27315,7 +27427,7 @@ const MessageList = (props) => {
27315
27427
  const c = containerRef.current;
27316
27428
  if (!c)
27317
27429
  return;
27318
- const count = messages.length;
27430
+ const count = visibleMessages.length;
27319
27431
  const isNew = count > prevMessageCountRef.current;
27320
27432
  prevMessageCountRef.current = count;
27321
27433
  if (count === 0) {
@@ -27326,17 +27438,33 @@ const MessageList = (props) => {
27326
27438
  messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
27327
27439
  }
27328
27440
  checkScrollPosition();
27329
- }, [messages, isTyping, checkScrollPosition]);
27441
+ }, [visibleMessages, isTyping, checkScrollPosition]);
27330
27442
  const groupedMessages = useMemo(() => {
27443
+ console.log('[DEBUG MessageList] ========================================');
27444
+ console.log('[DEBUG MessageList] Processing messages:', visibleMessages.length);
27445
+ visibleMessages.forEach((m, i) => {
27446
+ console.log(`[DEBUG MessageList] Message ${i}:`, {
27447
+ id: m.id,
27448
+ role: m.message.role,
27449
+ hasAction: !!m.action,
27450
+ actionImpl: m.action?.implementation,
27451
+ content: (m.message.content || '').substring(0, 50),
27452
+ });
27453
+ });
27331
27454
  const result = [];
27332
27455
  let toolGroup = [];
27333
- const flush = () => { if (toolGroup.length) {
27334
- result.push({ type: 'tool-group', messages: [...toolGroup] });
27335
- toolGroup = [];
27336
- } };
27337
- for (const m of messages) {
27338
- if (m.message.role === 'tool')
27456
+ const flush = () => {
27457
+ if (toolGroup.length) {
27458
+ console.log('[DEBUG MessageList] Flushing tool group with', toolGroup.length, 'messages');
27459
+ result.push({ type: 'tool-group', messages: [...toolGroup] });
27460
+ toolGroup = [];
27461
+ }
27462
+ };
27463
+ for (const m of visibleMessages) {
27464
+ if (m.message.role === 'tool') {
27465
+ console.log('[DEBUG MessageList] Adding to tool group:', m.id);
27339
27466
  toolGroup.push(m);
27467
+ }
27340
27468
  else if (m.message.role === 'user') {
27341
27469
  flush();
27342
27470
  result.push({ type: 'message', message: m });
@@ -27348,6 +27476,7 @@ const MessageList = (props) => {
27348
27476
  flush();
27349
27477
  result.push({ type: 'message', message: m });
27350
27478
  }
27479
+ // Don't flush on empty assistant messages - let tools continue grouping
27351
27480
  }
27352
27481
  else {
27353
27482
  flush();
@@ -27355,18 +27484,27 @@ const MessageList = (props) => {
27355
27484
  }
27356
27485
  }
27357
27486
  flush();
27487
+ console.log('[DEBUG MessageList] Final grouped result:', result.length, 'items');
27488
+ result.forEach((item, i) => {
27489
+ if (item.type === 'tool-group') {
27490
+ console.log(`[DEBUG MessageList] Group ${i}: tool-group with ${item.messages.length} messages`);
27491
+ }
27492
+ else {
27493
+ console.log(`[DEBUG MessageList] Group ${i}: message (${item.message.message.role})`);
27494
+ }
27495
+ });
27358
27496
  return result;
27359
- }, [messages]);
27360
- const hasSuggestions = messages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
27497
+ }, [visibleMessages]);
27498
+ const hasSuggestions = visibleMessages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
27361
27499
  const showWelcome = welcomeTitle || welcomeMessage || hasSuggestions;
27362
27500
  return (jsxs("div", { ref: containerRef, className: "ai-chat-messages", role: "log", "aria-live": "polite", children: [showWelcome && (jsxs("div", { className: "ai-chat-welcome", children: [welcomeTitle && jsx("div", { className: "ai-chat-welcome-title", children: welcomeTitle }), welcomeMessage && jsx("div", { className: "ai-chat-welcome-text", children: welcomeMessage }), hasSuggestions && jsx(SuggestedQuestions, { questions: suggestedQuestions, onQuestionClick: onSuggestedQuestionClick })] })), groupedMessages.map((item, i) => {
27363
27501
  if (item.type === 'tool-group') {
27364
- return jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor }, `tg-${i}`);
27502
+ return (jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant, onActionDismiss: onActionDismiss }, `tg-${i}`));
27365
27503
  }
27366
27504
  const isLast = i === groupedMessages.length - 1;
27367
27505
  const hasFollowUp = item.message.message.role === 'assistant' && item.message.suggestions?.length && isLast && !isTyping;
27368
27506
  return (jsxs(React.Fragment, { children: [jsx(Message, { message: item.message, showTimestamp: showTimestamps, onFeedback: onFeedback, getActionRenderer: getActionRenderer, accentColor: accentColor }), hasFollowUp && onSuggestedQuestionClick && jsx(FollowUpSuggestions, { suggestions: item.message.suggestions, onQuestionClick: onSuggestedQuestionClick, onActionClick: onActionClick, accentColor: accentColor })] }, item.message.id));
27369
- }), isTyping && showTypingIndicator && !hasActiveAction && messages.length > 0 && jsx(TypingIndicator, {}), jsx("div", { ref: messagesEndRef })] }));
27507
+ }), isTyping && showTypingIndicator && !hasActiveAction && visibleMessages.length > 0 && jsx(TypingIndicator, {}), jsx("div", { ref: messagesEndRef })] }));
27370
27508
  };
27371
27509
 
27372
27510
  const ALLOWED_EXTENSIONS = ['.pdf', '.doc', '.docx', '.txt', '.md', '.csv'];
@@ -27380,7 +27518,7 @@ const formatFileSize = (bytes) => {
27380
27518
  return (bytes / 1024).toFixed(1) + ' KB';
27381
27519
  return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
27382
27520
  };
27383
- const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, }) => {
27521
+ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, showDataPolicy = true, onDataPolicyClick, }) => {
27384
27522
  const [value, setValue] = useState('');
27385
27523
  const [selectedFiles, setSelectedFiles] = useState([]);
27386
27524
  const textareaRef = useRef(null);
@@ -27415,10 +27553,14 @@ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled =
27415
27553
  }
27416
27554
  };
27417
27555
  const canSend = value.trim() || selectedFiles.length > 0;
27418
- return (jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxs("div", { className: "ai-chat-file-item", children: [jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxs("div", { className: "ai-chat-file-info", children: [jsx("span", { className: "ai-chat-file-name", children: file.name }), jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxs(Fragment, { children: [jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) }) })] })), jsx("textarea", { ref: textareaRef, className: "ai-chat-input", value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 2, wrap: "soft", "aria-label": "Message input" }), jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsx("path", { d: "M12 19V5" }), jsx("path", { d: "M5 12l7-7 7 7" })] }) })] })] }));
27556
+ return (jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxs("div", { className: "ai-chat-file-item", children: [jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxs("div", { className: "ai-chat-file-info", children: [jsx("span", { className: "ai-chat-file-name", children: file.name }), jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxs(Fragment, { children: [jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) }) })] })), jsx("textarea", { ref: textareaRef, className: "ai-chat-input", value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 2, wrap: "soft", "aria-label": "Message input" }), jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsx("path", { d: "M12 19V5" }), jsx("path", { d: "M5 12l7-7 7 7" })] }) })] }), showDataPolicy && (jsxs("div", { className: "ai-chat-data-policy", children: [jsx("span", { children: "AI-generated responses may be inaccurate." }), onDataPolicyClick && (jsxs(Fragment, { children: [' ', jsx("button", { type: "button", className: "ai-chat-data-policy-link", onClick: onDataPolicyClick, children: "Privacy Notice" })] }))] }))] }));
27419
27557
  };
27420
27558
 
27421
- function groupSlotsByDate(slots) {
27559
+ const CloseButton = ({ onClick, className = "", ariaLabel = "Close", }) => {
27560
+ return (jsx("button", { type: "button", className: `ai-chat-action-close-btn ${className}`, onClick: onClick, "aria-label": ariaLabel, children: jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsx("path", { d: "M1 1L13 13M1 13L13 1" }) }) }));
27561
+ };
27562
+
27563
+ function groupSlotsByDate$1(slots) {
27422
27564
  const grouped = new Map();
27423
27565
  for (const slot of slots) {
27424
27566
  if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
@@ -27432,7 +27574,7 @@ function groupSlotsByDate(slots) {
27432
27574
  }
27433
27575
  return grouped;
27434
27576
  }
27435
- function formatDate(dateStr) {
27577
+ function formatDate$1(dateStr) {
27436
27578
  try {
27437
27579
  const date = new Date(dateStr);
27438
27580
  return new Intl.DateTimeFormat("en-US", {
@@ -27445,19 +27587,19 @@ function formatDate(dateStr) {
27445
27587
  return dateStr;
27446
27588
  }
27447
27589
  }
27448
- function CalendarIcon() {
27590
+ function CalendarIcon$1() {
27449
27591
  return (jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsx("path", { fillRule: "evenodd", d: "M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z", clipRule: "evenodd" }) }));
27450
27592
  }
27451
- function CheckIcon() {
27593
+ function CheckIcon$1() {
27452
27594
  return (jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }));
27453
27595
  }
27454
- function ExternalLinkIcon$1() {
27596
+ function ExternalLinkIcon$2() {
27455
27597
  return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsx("polyline", { points: "15 3 21 3 21 9" }), jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
27456
27598
  }
27457
- function Skeleton({ width, height, borderRadius = '4px' }) {
27599
+ function Skeleton$2({ width, height, borderRadius = '4px' }) {
27458
27600
  return (jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
27459
27601
  }
27460
- function GoogleCalendarCard({ action, onComplete, accentColor, className = '' }) {
27602
+ function GoogleCalendarCard({ action, onComplete, onDismiss, accentColor, className = '' }) {
27461
27603
  const state = action.state;
27462
27604
  const rawSlots = state.availableSlots;
27463
27605
  const availableSlots = Array.isArray(rawSlots)
@@ -27471,13 +27613,12 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
27471
27613
  : [];
27472
27614
  const allowTopic = state.allowTopic !== false;
27473
27615
  const isBooked = state.status === "booked";
27474
- const slotsByDate = groupSlotsByDate(availableSlots);
27616
+ const slotsByDate = groupSlotsByDate$1(availableSlots);
27475
27617
  const dates = Array.from(slotsByDate.keys()).sort();
27476
27618
  const [selectedDate, setSelectedDate] = useState(dates[0] ?? "");
27477
27619
  const [selectedSlot, setSelectedSlot] = useState(null);
27478
27620
  const [topic, setTopic] = useState("");
27479
27621
  const [error, setError] = useState(null);
27480
- const [isSubmitting, setIsSubmitting] = useState(false);
27481
27622
  const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
27482
27623
  const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
27483
27624
  const onConfirm = () => {
@@ -27490,8 +27631,252 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
27490
27631
  return;
27491
27632
  }
27492
27633
  setError(null);
27634
+ onComplete?.(action.toolCallId, {
27635
+ ...action.state,
27636
+ selectedSlot: {
27637
+ startTime: selectedSlot.startTime,
27638
+ endTime: selectedSlot.endTime,
27639
+ },
27640
+ topic: allowTopic ? topic.trim() : null,
27641
+ });
27642
+ };
27643
+ const handleDismiss = () => {
27644
+ onDismiss?.(action.toolCallId);
27645
+ };
27646
+ // Booked state
27647
+ if (isBooked) {
27648
+ const bookedSlot = state.selectedSlot;
27649
+ const bookedTopic = state.topic;
27650
+ const eventLink = state.bookedEventLink;
27651
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsx(CheckIcon$1, {}) }), "Appointment Confirmed"] }), jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), eventLink && (jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Google Calendar", jsx(ExternalLinkIcon$2, {})] }))] })] }));
27652
+ }
27653
+ // Skeleton loading state - show when waiting for backend after user confirms
27654
+ const isWaitingForBackend = !action.done && state.selectedSlot && !isBooked;
27655
+ if (isWaitingForBackend) {
27656
+ return (jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsx(Skeleton$2, { width: "28px", height: "28px", borderRadius: "50%" }), jsx(Skeleton$2, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton$2, { width: "60px", height: "12px", borderRadius: "4px" }), jsx(Skeleton$2, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton$2, { width: "50px", height: "12px", borderRadius: "4px" }), jsx(Skeleton$2, { width: "200px", height: "18px", borderRadius: "4px" })] }), jsx(Skeleton$2, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
27657
+ }
27658
+ // Booking form
27659
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ai-chat-google-calendar ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon$1, {}), "Schedule an Appointment", onDismiss && (jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsx("input", { id: `topic-${action.toolCallId}`, type: "text", className: "ai-chat-action-input", placeholder: "e.g., Product Demo", value: topic, onChange: (e) => setTopic(e.target.value) })] })), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
27660
+ setSelectedDate(date);
27661
+ setSelectedSlot(null);
27662
+ }, children: formatDate$1(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsx("button", { type: "button", className: `ai-chat-action-time-btn ${selectedSlot?.startTime === slot.startTime ? "active" : ""}`, onClick: () => setSelectedSlot(slot), children: slot.displayTime || new Date(slot.startTime).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }, slot.startTime))) })] })), error && jsx("div", { className: "ai-chat-action-error", children: error }), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: onConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
27663
+ }
27664
+
27665
+ function groupSlotsByDate(slots) {
27666
+ const grouped = new Map();
27667
+ for (const slot of slots) {
27668
+ if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
27669
+ continue;
27670
+ }
27671
+ const date = slot.startTime.slice(0, 10);
27672
+ if (!grouped.has(date)) {
27673
+ grouped.set(date, []);
27674
+ }
27675
+ grouped.get(date).push(slot);
27676
+ }
27677
+ return grouped;
27678
+ }
27679
+ function formatDate(dateStr) {
27680
+ try {
27681
+ const date = new Date(dateStr);
27682
+ return new Intl.DateTimeFormat("en-US", {
27683
+ weekday: "short",
27684
+ month: "short",
27685
+ day: "numeric",
27686
+ }).format(date);
27687
+ }
27688
+ catch {
27689
+ return dateStr;
27690
+ }
27691
+ }
27692
+ function CalendarIcon() {
27693
+ return (jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsx("path", { fillRule: "evenodd", d: "M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z", clipRule: "evenodd" }) }));
27694
+ }
27695
+ function MailIcon() {
27696
+ return (jsxs("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: [jsx("path", { d: "M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z" }), jsx("path", { d: "M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z" })] }));
27697
+ }
27698
+ function CheckIcon() {
27699
+ return (jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }));
27700
+ }
27701
+ function ErrorIcon() {
27702
+ return (jsx("svg", { className: "ai-chat-action-icon-error", viewBox: "0 0 20 20", fill: "currentColor", children: jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }) }));
27703
+ }
27704
+ function ExternalLinkIcon$1() {
27705
+ return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsx("polyline", { points: "15 3 21 3 21 9" }), jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
27706
+ }
27707
+ function Skeleton$1({ width, height, borderRadius = '4px' }) {
27708
+ return (jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
27709
+ }
27710
+ function PinInputGroup$1({ values, onChange, disabled }) {
27711
+ const inputRefs = useRef([]);
27712
+ const handleChange = (index, value) => {
27713
+ // Only allow digits
27714
+ const digit = value.replace(/[^0-9]/g, '');
27715
+ const newValues = [...values];
27716
+ newValues[index] = digit.slice(-1);
27717
+ onChange(newValues);
27718
+ // Auto-focus next input
27719
+ if (digit && index < 5) {
27720
+ inputRefs.current[index + 1]?.focus();
27721
+ }
27722
+ };
27723
+ const handleKeyDown = (index, e) => {
27724
+ if (e.key === 'Backspace' && !values[index] && index > 0) {
27725
+ inputRefs.current[index - 1]?.focus();
27726
+ }
27727
+ };
27728
+ const handlePaste = (e) => {
27729
+ e.preventDefault();
27730
+ const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, 6);
27731
+ const newValues = pastedData.split('').concat(Array(6 - pastedData.length).fill(''));
27732
+ onChange(newValues);
27733
+ // Focus the next empty input or the last one
27734
+ const nextIndex = Math.min(pastedData.length, 5);
27735
+ inputRefs.current[nextIndex]?.focus();
27736
+ };
27737
+ return (jsx("div", { className: "ai-chat-pin-input-group", children: values.map((value, index) => (jsx("input", { ref: (el) => {
27738
+ inputRefs.current[index] = el;
27739
+ }, type: "text", inputMode: "numeric", maxLength: 1, className: "ai-chat-pin-input", value: value, onChange: (e) => handleChange(index, e.target.value), onKeyDown: (e) => handleKeyDown(index, e), onPaste: handlePaste, disabled: disabled, autoFocus: index === 0 }, index))) }));
27740
+ }
27741
+ function MicrosoftCalendarCard({ action, onComplete, onDismiss, accentColor, className = '' }) {
27742
+ const state = action.state;
27743
+ const phase = state.phase || "awaiting_email";
27744
+ const allowTopic = state.allowTopic !== false;
27745
+ const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
27746
+ const handleDismiss = () => {
27747
+ onDismiss?.(action.toolCallId);
27748
+ };
27749
+ const showCloseButton = Boolean(onDismiss);
27750
+ // Debug: Log state changes
27751
+ const prevStateRef = useRef(null);
27752
+ useEffect(() => {
27753
+ if (JSON.stringify(prevStateRef.current) !== JSON.stringify(state)) {
27754
+ console.log('[MicrosoftCalendarCard] State updated:', {
27755
+ phase: state.phase,
27756
+ hasError: !!state.errorMessage,
27757
+ error: state.errorMessage,
27758
+ slotsCount: state.availableSlots?.length || 0
27759
+ });
27760
+ prevStateRef.current = state;
27761
+ }
27762
+ }, [state]);
27763
+ // Email phase state
27764
+ const [email, setEmail] = useState("");
27765
+ const [emailError, setEmailError] = useState(null);
27766
+ // OTP phase state
27767
+ const [otpValues, setOtpValues] = useState(Array(6).fill(''));
27768
+ const [otpError, setOtpError] = useState(null);
27769
+ // Loading states
27770
+ const [isSubmitting, setIsSubmitting] = useState(false);
27771
+ // Reset loading state when phase changes (backend has responded)
27772
+ // Use useEffect for reliable re-rendering
27773
+ useEffect(() => {
27774
+ console.log('[MicrosoftCalendarCard] Phase changed to:', phase);
27775
+ setIsSubmitting(false);
27776
+ // Clear errors when transitioning to new phase
27777
+ if (phase === "awaiting_email") {
27778
+ setEmailError(null);
27779
+ setOtpError(null);
27780
+ setSelectionError(null);
27781
+ }
27782
+ else if (phase === "awaiting_otp") {
27783
+ setOtpError(state.errorMessage || null);
27784
+ setEmailError(null);
27785
+ setSelectionError(null);
27786
+ // Clear OTP input for fresh attempt
27787
+ setOtpValues(Array(6).fill(''));
27788
+ }
27789
+ else if (phase === "awaiting_options") {
27790
+ setEmailError(null);
27791
+ setOtpError(null);
27792
+ setSelectionError(null);
27793
+ }
27794
+ else if (phase === "awaiting_booking") {
27795
+ setSelectionError(state.errorMessage || null);
27796
+ setEmailError(null);
27797
+ setOtpError(null);
27798
+ }
27799
+ else if (phase === "booked" || phase === "cancelled" || phase === "error") {
27800
+ setEmailError(null);
27801
+ setOtpError(null);
27802
+ setSelectionError(null);
27803
+ setSelectedId(null); // Reset selection
27804
+ }
27805
+ }, [phase, state.errorMessage]);
27806
+ // Selection phase state
27807
+ const rawSlots = state.availableSlots;
27808
+ const availableSlots = Array.isArray(rawSlots)
27809
+ ? rawSlots.filter((slot) => slot !== null &&
27810
+ slot !== undefined &&
27811
+ typeof slot === "object" &&
27812
+ "startTime" in slot &&
27813
+ "endTime" in slot &&
27814
+ typeof slot.startTime === "string" &&
27815
+ typeof slot.endTime === "string")
27816
+ : [];
27817
+ const slotsByDate = groupSlotsByDate(availableSlots);
27818
+ const dates = Array.from(slotsByDate.keys()).sort();
27819
+ const [selectedDate, setSelectedDate] = useState(dates[0] ?? "");
27820
+ const [selectedSlot, setSelectedSlot] = useState(null);
27821
+ const [topic, setTopic] = useState("");
27822
+ const [selectionError, setSelectionError] = useState(null);
27823
+ // Cancellation phase state
27824
+ const [selectedId, setSelectedId] = useState(null);
27825
+ const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
27826
+ // Phase 1: Email Input
27827
+ const handleEmailSubmit = () => {
27828
+ const trimmedEmail = email.trim();
27829
+ if (!trimmedEmail) {
27830
+ setEmailError("Please enter your email address");
27831
+ return;
27832
+ }
27833
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmedEmail)) {
27834
+ setEmailError("Please enter a valid email address");
27835
+ return;
27836
+ }
27837
+ setEmailError(null);
27838
+ setIsSubmitting(true);
27839
+ console.log('[MicrosoftCalendarCard] Submitting email:', trimmedEmail);
27840
+ setTimeout(() => {
27841
+ onComplete?.(action.toolCallId, {
27842
+ ...action.state,
27843
+ email: trimmedEmail,
27844
+ });
27845
+ }, 50);
27846
+ };
27847
+ // Phase 2: OTP Verification
27848
+ const handleOtpSubmit = () => {
27849
+ const otpCode = otpValues.join('');
27850
+ if (otpCode.length !== 6) {
27851
+ setOtpError("Please enter the 6-digit code");
27852
+ return;
27853
+ }
27854
+ setOtpError(null);
27855
+ setIsSubmitting(true);
27856
+ console.log('[MicrosoftCalendarCard] Submitting OTP code');
27857
+ setTimeout(() => {
27858
+ onComplete?.(action.toolCallId, {
27859
+ ...action.state,
27860
+ otpCode,
27861
+ });
27862
+ }, 50);
27863
+ };
27864
+ // Phase 3: Appointment Selection
27865
+ const handleAppointmentConfirm = () => {
27866
+ if (!selectedSlot) {
27867
+ setSelectionError("Please select a time slot");
27868
+ return;
27869
+ }
27870
+ if (allowTopic && !topic.trim()) {
27871
+ setSelectionError("Please enter a meeting topic");
27872
+ return;
27873
+ }
27874
+ setSelectionError(null);
27493
27875
  setIsSubmitting(true);
27494
- // Small delay to ensure UI updates
27876
+ console.log('[MicrosoftCalendarCard] Confirming appointment:', {
27877
+ slot: selectedSlot,
27878
+ topic: topic.trim()
27879
+ });
27495
27880
  setTimeout(() => {
27496
27881
  onComplete?.(action.toolCallId, {
27497
27882
  ...action.state,
@@ -27503,22 +27888,149 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
27503
27888
  });
27504
27889
  }, 50);
27505
27890
  };
27506
- // Booked state
27507
- if (isBooked) {
27891
+ // Handle "Use different email" button
27892
+ const handleUseDifferentEmail = () => {
27893
+ setEmail("");
27894
+ setEmailError(null);
27895
+ setOtpValues(Array(6).fill(''));
27896
+ setOtpError(null);
27897
+ onComplete?.(action.toolCallId, {
27898
+ phase: "awaiting_email",
27899
+ email: null,
27900
+ otpVerified: false,
27901
+ otpAttempts: 0,
27902
+ availableSlots: [],
27903
+ selectedSlot: null,
27904
+ topic: null,
27905
+ bookedEventId: null,
27906
+ bookedEventLink: null,
27907
+ allowTopic,
27908
+ errorMessage: null,
27909
+ });
27910
+ };
27911
+ // Phase 5: Booked Confirmation
27912
+ if (phase === "booked") {
27508
27913
  const bookedSlot = state.selectedSlot;
27509
27914
  const bookedTopic = state.topic;
27510
27915
  const eventLink = state.bookedEventLink;
27511
- return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsx(CheckIcon, {}) }), "Appointment Confirmed"] }), jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), eventLink && (jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Google Calendar", jsx(ExternalLinkIcon$1, {})] }))] })] }));
27512
- }
27513
- // Skeleton loading state
27916
+ const bookedEmail = state.email;
27917
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsx(CheckIcon, {}) }), "Appointment Confirmed"] }), jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), bookedEmail && (jsxs("div", { className: "ai-chat-action-hint", children: ["A calendar invitation has been sent to ", bookedEmail] })), eventLink && (jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Outlook Calendar", jsx(ExternalLinkIcon$1, {})] }))] })] }));
27918
+ }
27919
+ // Phase 6: Cancelled Confirmation
27920
+ if (phase === "cancelled") {
27921
+ const cancelledSubject = state.cancelledEventSubject;
27922
+ const userEmail = state.email;
27923
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsx(CheckIcon, {}) }), "Appointment Cancelled"] }), jsxs("div", { className: "ai-chat-action-body", children: [cancelledSubject && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "CANCELLED" }), jsx("span", { className: "ai-chat-action-value-large", children: cancelledSubject })] })), userEmail && (jsxs("div", { className: "ai-chat-action-hint", children: ["A cancellation notice has been sent to ", userEmail] }))] })] }));
27924
+ }
27925
+ // Error State
27926
+ if (phase === "error") {
27927
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-error ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(ErrorIcon, {}), "Error"] }), jsxs("div", { className: "ai-chat-action-body", children: [jsx("div", { className: "ai-chat-action-error-message", children: state.errorMessage || "An error occurred. Please try again." }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
27928
+ setEmail("");
27929
+ setEmailError(null);
27930
+ setOtpValues(Array(6).fill(''));
27931
+ setOtpError(null);
27932
+ onComplete?.(action.toolCallId, {
27933
+ phase: "awaiting_email",
27934
+ email: null,
27935
+ otpVerified: false,
27936
+ otpAttempts: 0,
27937
+ availableSlots: [],
27938
+ selectedSlot: null,
27939
+ topic: null,
27940
+ bookedEventId: null,
27941
+ bookedEventLink: null,
27942
+ allowTopic,
27943
+ errorMessage: null,
27944
+ });
27945
+ }, children: "Start Over" })] })] }));
27946
+ }
27947
+ // Loading State
27514
27948
  if (isSubmitting) {
27515
- return (jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton, { width: "50px", height: "12px", borderRadius: "4px" }), jsx(Skeleton, { width: "200px", height: "18px", borderRadius: "4px" })] }), jsx(Skeleton, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
27516
- }
27517
- // Booking form
27518
- return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Schedule an Appointment"] }), jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsx("input", { id: `topic-${action.toolCallId}`, type: "text", className: "ai-chat-action-input", placeholder: "e.g., Product Demo", value: topic, onChange: (e) => setTopic(e.target.value) })] })), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
27519
- setSelectedDate(date);
27520
- setSelectedSlot(null);
27521
- }, children: formatDate(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsx("button", { type: "button", className: `ai-chat-action-time-btn ${selectedSlot?.startTime === slot.startTime ? "active" : ""}`, onClick: () => setSelectedSlot(slot), children: slot.displayTime || new Date(slot.startTime).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }, slot.startTime))) })] })), error && jsx("div", { className: "ai-chat-action-error", children: error }), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: onConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
27949
+ return (jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsx(Skeleton$1, { width: "28px", height: "28px", borderRadius: "50%" }), jsx(Skeleton$1, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton$1, { width: "60px", height: "12px", borderRadius: "4px" }), jsx(Skeleton$1, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsx(Skeleton$1, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
27950
+ }
27951
+ // Phase 1: Email Input
27952
+ if (phase === "awaiting_email") {
27953
+ const displayError = state.errorMessage || emailError;
27954
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Schedule an Appointment", showCloseButton && (jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxs("div", { className: "ai-chat-action-body", children: [jsx("div", { className: "ai-chat-action-hint", children: "We'll send a verification code to your email" }), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `email-${action.toolCallId}`, className: "ai-chat-action-label", children: "Email Address" }), jsx("input", { id: `email-${action.toolCallId}`, type: "email", className: "ai-chat-action-input", placeholder: "your@email.com", value: email, onChange: (e) => {
27955
+ setEmail(e.target.value);
27956
+ setEmailError(null);
27957
+ }, onKeyPress: (e) => {
27958
+ if (e.key === 'Enter') {
27959
+ handleEmailSubmit();
27960
+ }
27961
+ }, autoFocus: true })] }), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleEmailSubmit, children: "Continue" })] })] }));
27962
+ }
27963
+ // Phase 2: OTP Input
27964
+ if (phase === "awaiting_otp") {
27965
+ const displayError = state.errorMessage || otpError;
27966
+ const userEmail = state.email;
27967
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(MailIcon, {}), "Verify Your Email", showCloseButton && (jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxs("div", { className: "ai-chat-action-body", children: [jsxs("div", { className: "ai-chat-action-hint", children: ["We sent a 6-digit code to ", jsx("strong", { children: userEmail })] }), jsx(PinInputGroup$1, { values: otpValues, onChange: (newValues) => {
27968
+ setOtpValues(newValues);
27969
+ setOtpError(null);
27970
+ // Auto-submit when all 6 digits are entered
27971
+ if (newValues.every(v => v.length === 1)) {
27972
+ console.log('[MicrosoftCalendarCard] Auto-submitting OTP (all 6 digits entered)');
27973
+ setIsSubmitting(true);
27974
+ const code = newValues.join('');
27975
+ setTimeout(() => {
27976
+ onComplete?.(action.toolCallId, {
27977
+ ...action.state,
27978
+ otpCode: code,
27979
+ });
27980
+ }, 100);
27981
+ }
27982
+ }, disabled: isSubmitting }), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleOtpSubmit, disabled: otpValues.join('').length !== 6, children: "Verify Code" }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: handleUseDifferentEmail, children: "Use different email" })] })] }));
27983
+ }
27984
+ // Phase 3: Options Menu (with inline cancel buttons and confirmation)
27985
+ if (phase === "awaiting_options") {
27986
+ const userAppointments = state.userAppointments || [];
27987
+ const maxAppointments = state.maxAppointmentsPerUser || 3;
27988
+ const appointmentCount = userAppointments.length;
27989
+ const canBook = appointmentCount < maxAppointments;
27990
+ const hasAppointments = appointmentCount > 0;
27991
+ const displayError = state.errorMessage || selectionError;
27992
+ // If confirming cancellation, show confirmation dialog
27993
+ if (selectedId) {
27994
+ const appointmentToCancel = userAppointments.find(appt => appt.id === selectedId);
27995
+ if (!appointmentToCancel) {
27996
+ setSelectedId(null); // Reset if appointment not found
27997
+ }
27998
+ else {
27999
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Confirm Cancellation", showCloseButton && (jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxs("div", { className: "ai-chat-action-body", children: [jsx("div", { className: "ai-chat-action-hint", children: "Are you sure you want to cancel this appointment?" }), jsx("div", { className: "ai-chat-action-appointment-item", style: { marginBottom: '16px' }, children: jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsx("div", { className: "ai-chat-action-appointment-subject", children: appointmentToCancel.subject }), jsx("div", { className: "ai-chat-action-appointment-time", children: appointmentToCancel.displayTime })] }) }), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxs("div", { className: "ai-chat-action-button-group", children: [jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
28000
+ setIsSubmitting(true);
28001
+ onComplete?.(action.toolCallId, {
28002
+ ...action.state,
28003
+ selectedOption: "cancel",
28004
+ selectedAppointmentId: selectedId,
28005
+ });
28006
+ }, disabled: isSubmitting, children: isSubmitting ? 'Cancelling...' : 'Confirm Cancellation' }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
28007
+ setSelectedId(null);
28008
+ setSelectionError(null);
28009
+ }, disabled: isSubmitting, children: "Go Back" })] })] })] }));
28010
+ }
28011
+ }
28012
+ // Normal view with inline cancel buttons
28013
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Manage Your Appointments", showCloseButton && (jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxs("div", { className: "ai-chat-action-body", children: [jsxs("div", { className: "ai-chat-action-hint", children: ["You have ", appointmentCount, " active appointment", appointmentCount !== 1 ? 's' : '', canBook && ` (${maxAppointments - appointmentCount} slot${maxAppointments - appointmentCount !== 1 ? 's' : ''} remaining)`] }), hasAppointments && (jsxs("div", { className: "ai-chat-action-appointment-list", children: [jsx("div", { className: "ai-chat-action-label", children: "Your Upcoming Appointments" }), userAppointments.map((appt) => (jsxs("div", { className: "ai-chat-action-appointment-item", children: [jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsx("div", { className: "ai-chat-action-appointment-subject", children: appt.subject }), jsx("div", { className: "ai-chat-action-appointment-time", children: appt.displayTime })] }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
28014
+ setSelectedId(appt.id);
28015
+ setSelectionError(null);
28016
+ }, children: "Cancel" })] }, appt.id)))] })), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), canBook && (jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
28017
+ setIsSubmitting(true);
28018
+ onComplete?.(action.toolCallId, {
28019
+ ...action.state,
28020
+ selectedOption: "book",
28021
+ });
28022
+ }, disabled: isSubmitting, children: isSubmitting ? 'Loading...' : 'Book New Appointment' })), !canBook && !hasAppointments && (jsx("div", { className: "ai-chat-action-hint", children: "No appointments found." }))] })] }));
28023
+ }
28024
+ // Phase 4: Appointment Selection (Booking)
28025
+ if (phase === "awaiting_booking") {
28026
+ const displayError = state.errorMessage || selectionError;
28027
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Select Appointment Time", showCloseButton && (jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsx("input", { id: `topic-${action.toolCallId}`, type: "text", className: "ai-chat-action-input", placeholder: "e.g., Product Demo", value: topic, onChange: (e) => setTopic(e.target.value) })] })), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
28028
+ setSelectedDate(date);
28029
+ setSelectedSlot(null);
28030
+ }, children: formatDate(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsx("button", { type: "button", className: `ai-chat-action-time-btn ${selectedSlot?.startTime === slot.startTime ? "active" : ""}`, onClick: () => setSelectedSlot(slot), children: slot.displayTime || new Date(slot.startTime).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }, slot.startTime))) })] })), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleAppointmentConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
28031
+ }
28032
+ // Fallback
28033
+ return null;
27522
28034
  }
27523
28035
 
27524
28036
  function truncate(text, maxLength) {
@@ -27529,17 +28041,30 @@ function truncate(text, maxLength) {
27529
28041
  function ExternalLinkIcon() {
27530
28042
  return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsx("polyline", { points: "15 3 21 3 21 9" }), jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
27531
28043
  }
28044
+ function SingleLinkPreview({ link, onLinkClick, accentColor }) {
28045
+ const domain = (() => {
28046
+ if (!link.url)
28047
+ return '';
28048
+ try {
28049
+ return new URL(link.url).hostname.replace('www.', '');
28050
+ }
28051
+ catch {
28052
+ return link.url;
28053
+ }
28054
+ })();
28055
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28056
+ return (jsxs("div", { className: "ai-chat-action-card ai-chat-link-preview", onClick: onLinkClick, style: style, role: "link", tabIndex: 0, onKeyDown: (e) => e.key === 'Enter' && onLinkClick(), children: [link.image && (jsx("div", { className: "ai-chat-link-preview__image", children: jsx("img", { src: link.image, alt: link.title, onError: (e) => {
28057
+ e.currentTarget.parentElement.style.display = 'none';
28058
+ } }) })), jsxs("div", { className: "ai-chat-link-preview__content", children: [jsxs("div", { className: "ai-chat-link-preview__site", children: [link.favicon && (jsx("img", { src: link.favicon, alt: "", className: "ai-chat-link-preview__favicon", onError: (e) => {
28059
+ e.currentTarget.style.display = 'none';
28060
+ } })), jsx("span", { className: "ai-chat-link-preview__domain", children: link.siteName || domain })] }), jsx("h4", { className: "ai-chat-link-preview__title", children: link.title }), link.description && (jsx("p", { className: "ai-chat-link-preview__description", children: truncate(link.description, 120) }))] }), jsx("div", { className: "ai-chat-link-preview__arrow", children: jsx(ExternalLinkIcon, {}) })] }));
28061
+ }
27532
28062
  function LinkPreviewCard({ action, onComplete, accentColor }) {
27533
28063
  const rawState = action.state;
27534
28064
  const hasCompletedRef = useRef(false);
27535
28065
  // Provide safe defaults if state is missing
27536
28066
  const state = {
27537
- url: rawState?.url || '',
27538
- title: rawState?.title || 'Link',
27539
- description: rawState?.description,
27540
- image: rawState?.image,
27541
- siteName: rawState?.siteName,
27542
- favicon: rawState?.favicon,
28067
+ links: rawState?.links || [],
27543
28068
  context: rawState?.context,
27544
28069
  status: rawState?.status || 'displaying',
27545
28070
  error: rawState?.error,
@@ -27547,34 +28072,29 @@ function LinkPreviewCard({ action, onComplete, accentColor }) {
27547
28072
  const isError = state.status === 'error';
27548
28073
  // Auto-complete on mount so AI can continue generating text response
27549
28074
  useEffect(() => {
27550
- if (!action.done && !hasCompletedRef.current && onComplete && state.url) {
28075
+ if (!action.done && !hasCompletedRef.current && onComplete && state.links.length > 0) {
27551
28076
  hasCompletedRef.current = true;
27552
28077
  // Signal completion immediately - the card is displayed, AI can continue
27553
28078
  onComplete(action.toolCallId, { ...state, status: 'displaying' });
27554
28079
  }
27555
28080
  }, [action.done, action.toolCallId, onComplete, state]);
27556
- const handleClick = () => {
27557
- if (state.url) {
27558
- window.open(state.url, '_blank', 'noopener,noreferrer');
28081
+ const handleLinkClick = (url) => {
28082
+ if (url) {
28083
+ window.open(url, '_blank', 'noopener,noreferrer');
27559
28084
  }
27560
28085
  onComplete?.(action.toolCallId, { ...state, status: 'clicked' });
27561
28086
  };
27562
- const domain = (() => {
27563
- if (!state.url)
27564
- return '';
27565
- try {
27566
- return new URL(state.url).hostname.replace('www.', '');
27567
- }
27568
- catch {
27569
- return state.url;
27570
- }
27571
- })();
27572
- const style = accentColor ? { '--action-accent': accentColor } : undefined;
27573
- return (jsxs("div", { className: `ai-chat-link-preview ${isError ? 'ai-chat-link-preview--error' : ''}`, onClick: handleClick, style: style, role: "link", tabIndex: 0, onKeyDown: (e) => e.key === 'Enter' && handleClick(), children: [state.image && !isError && (jsx("div", { className: "ai-chat-link-preview__image", children: jsx("img", { src: state.image, alt: state.title, onError: (e) => {
27574
- e.currentTarget.parentElement.style.display = 'none';
27575
- } }) })), jsxs("div", { className: "ai-chat-link-preview__content", children: [jsxs("div", { className: "ai-chat-link-preview__site", children: [state.favicon && (jsx("img", { src: state.favicon, alt: "", className: "ai-chat-link-preview__favicon", onError: (e) => {
27576
- e.currentTarget.style.display = 'none';
27577
- } })), jsx("span", { className: "ai-chat-link-preview__domain", children: state.siteName || domain })] }), jsx("h4", { className: "ai-chat-link-preview__title", children: state.title }), state.description && (jsx("p", { className: "ai-chat-link-preview__description", children: truncate(state.description, 120) })), state.context && (jsx("p", { className: "ai-chat-link-preview__context", children: state.context })), isError && state.error && (jsx("p", { className: "ai-chat-link-preview__error-text", children: state.error }))] }), jsx("div", { className: "ai-chat-link-preview__arrow", children: jsx(ExternalLinkIcon, {}) })] }));
28087
+ if (isError) {
28088
+ return (jsx("div", { className: "ai-chat-action-card ai-chat-link-preview ai-chat-link-preview--error", children: jsx("div", { className: "ai-chat-link-preview__content", children: jsx("p", { className: "ai-chat-link-preview__error-text", children: state.error || 'Failed to load preview' }) }) }));
28089
+ }
28090
+ if (state.links.length === 0) {
28091
+ return null;
28092
+ }
28093
+ return (jsxs("div", { className: "ai-chat-link-preview-container", children: [state.context && (jsx("p", { className: "ai-chat-link-preview__context", style: { marginBottom: '8px', fontSize: '0.9em', color: 'var(--ai-chat-fg-muted)' }, children: state.context })), jsx("div", { className: "ai-chat-link-preview-grid", style: {
28094
+ display: 'grid',
28095
+ gridTemplateColumns: state.links.length === 1 ? '1fr' : state.links.length === 2 ? 'repeat(2, 1fr)' : 'repeat(3, 1fr)',
28096
+ gap: '12px',
28097
+ }, children: state.links.map((link, index) => (jsx(SingleLinkPreview, { link: link, onLinkClick: () => handleLinkClick(link.url), accentColor: accentColor }, index))) })] }));
27578
28098
  }
27579
28099
 
27580
28100
  function PlayIcon() {
@@ -27640,7 +28160,7 @@ function VideoPlayerCard({ action, onComplete, accentColor }) {
27640
28160
  return src;
27641
28161
  }
27642
28162
  };
27643
- return (jsxs("div", { className: "ai-chat-video-player", style: style, children: [state.title && (jsx("div", { className: "ai-chat-video-player__header", children: jsx("span", { className: "ai-chat-video-player__title", children: state.title }) })), jsx("div", { className: "ai-chat-video-player__container", children: isError ? (jsx("div", { className: "ai-chat-video-player__error", children: jsx("span", { children: state.error || 'Could not load video' }) })) : !isPlaying && state.thumbnailUrl ? (jsxs("div", { className: "ai-chat-video-player__thumbnail", onClick: handlePlay, children: [jsx("img", { src: state.thumbnailUrl, alt: state.title || 'Video thumbnail' }), jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsx(PlayIcon, {}) }), jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : !isPlaying ? (jsxs("div", { className: "ai-chat-video-player__placeholder", onClick: handlePlay, children: [jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsx(PlayIcon, {}) }), jsx("span", { className: "ai-chat-video-player__click-text", children: "Click to play" }), jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : state.provider === 'direct' ? (jsx("video", { src: state.embedUrl, controls: true, autoPlay: true, className: "ai-chat-video-player__video" })) : (jsx("iframe", { src: getEmbedSrc(), className: "ai-chat-video-player__iframe", allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share", allowFullScreen: true, title: state.title || 'Video player' })) }), state.context && (jsx("div", { className: "ai-chat-video-player__context", children: state.context }))] }));
28163
+ return (jsxs("div", { className: "ai-chat-action-card ai-chat-video-player", style: style, children: [jsx("div", { className: "ai-chat-video-player__container", children: isError ? (jsx("div", { className: "ai-chat-video-player__error", children: jsx("span", { children: state.error || 'Could not load video' }) })) : !isPlaying && state.thumbnailUrl ? (jsxs("div", { className: "ai-chat-video-player__thumbnail", onClick: handlePlay, children: [jsx("img", { src: state.thumbnailUrl, alt: state.title || 'Video thumbnail' }), jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsx(PlayIcon, {}) }), jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : !isPlaying ? (jsxs("div", { className: "ai-chat-video-player__placeholder", onClick: handlePlay, children: [jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsx(PlayIcon, {}) }), jsx("span", { className: "ai-chat-video-player__click-text", children: "Click to play" }), jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : state.provider === 'direct' ? (jsx("video", { src: state.embedUrl, controls: true, autoPlay: true, className: "ai-chat-video-player__video" })) : (jsx("iframe", { src: getEmbedSrc(), className: "ai-chat-video-player__iframe", allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share", allowFullScreen: true, title: state.title || 'Video player' })) }), state.context && (jsx("div", { className: "ai-chat-video-player__context", children: state.context }))] }));
27644
28164
  }
27645
28165
 
27646
28166
  function MapPinIcon() {
@@ -27701,7 +28221,9 @@ function LocationItem({ location, settings, accentColor, onDirections, showMap =
27701
28221
  }
27702
28222
  };
27703
28223
  const style = accentColor ? { '--action-accent': accentColor } : undefined;
27704
- return (jsxs("div", { className: `ai-chat-location-card ${compact ? 'ai-chat-location-card--compact' : ''}`, style: style, children: [showMap && !compact && settings.showMap !== false && (jsx("div", { className: "ai-chat-location-card__map", style: { height: mapHeight }, children: jsx("iframe", { src: getMapEmbedUrl(), allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade", title: `Map of ${location.name}` }) })), jsxs("div", { className: "ai-chat-location-card__content", children: [jsxs("div", { className: "ai-chat-location-card__header", children: [jsx("h4", { className: "ai-chat-location-card__name", children: location.name }), location.type && (jsx("span", { className: "ai-chat-location-card__type", children: location.type })), openStatus !== null && (jsx("span", { className: `ai-chat-location-card__status ai-chat-location-card__status--${openStatus ? 'open' : 'closed'}`, children: openStatus ? 'Open' : 'Closed' }))] }), jsxs("p", { className: "ai-chat-location-card__address", children: [jsx(MapPinIcon, {}), location.address] }), location.description && (jsx("p", { className: "ai-chat-location-card__description", children: location.description })), settings.showHours !== false && location.hours && location.hours.length > 0 && (jsx(HoursDisplay, { hours: location.hours, compact: compact })), settings.showPhone !== false && location.phone && (jsxs("button", { type: "button", className: "ai-chat-location-card__phone", onClick: handleCall, children: [jsx(PhoneIcon, {}), location.phone] })), jsxs("div", { className: "ai-chat-location-card__actions", children: [settings.showDirectionsButton !== false && (jsxs("button", { type: "button", className: "ai-chat-location-card__button", style: accentColor ? { backgroundColor: accentColor } : undefined, onClick: onDirections, children: [jsx(NavigationIcon, {}), compact ? 'Directions' : 'Get Directions'] })), !compact && location.website && (jsxs("a", { href: location.website, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-location-card__link", children: [jsx(GlobeIcon, {}), "Website"] }))] })] })] }));
28224
+ // Use smaller map height in compact mode
28225
+ const effectiveMapHeight = compact ? Math.min(mapHeight, 140) : mapHeight;
28226
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-location-card ${compact ? 'ai-chat-location-card--compact' : ''}`, style: style, children: [showMap && settings.showMap !== false && (jsx("div", { className: "ai-chat-location-card__map", style: { height: effectiveMapHeight }, children: jsx("iframe", { src: getMapEmbedUrl(), allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade", title: `Map of ${location.name}` }) })), jsxs("div", { className: "ai-chat-location-card__content", children: [jsxs("div", { className: "ai-chat-location-card__header", children: [jsx("h4", { className: "ai-chat-location-card__name", children: location.name }), location.type && (jsx("span", { className: "ai-chat-location-card__type", children: location.type })), openStatus !== null && (jsx("span", { className: `ai-chat-location-card__status ai-chat-location-card__status--${openStatus ? 'open' : 'closed'}`, children: openStatus ? 'Open' : 'Closed' }))] }), jsxs("p", { className: "ai-chat-location-card__address", children: [jsx(MapPinIcon, {}), location.address] }), location.description && (jsx("p", { className: "ai-chat-location-card__description", children: location.description })), settings.showHours !== false && location.hours && location.hours.length > 0 && (jsx(HoursDisplay, { hours: location.hours, compact: compact })), settings.showPhone !== false && location.phone && (jsxs("button", { type: "button", className: "ai-chat-location-card__phone", onClick: handleCall, children: [jsx(PhoneIcon, {}), location.phone] })), jsxs("div", { className: "ai-chat-location-card__actions", children: [settings.showDirectionsButton !== false && (jsxs("button", { type: "button", className: "ai-chat-location-card__button", style: accentColor ? { backgroundColor: accentColor } : undefined, onClick: onDirections, children: [jsx(NavigationIcon, {}), compact ? 'Directions' : 'Get Directions'] })), !compact && location.website && (jsxs("a", { href: location.website, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-location-card__link", children: [jsx(GlobeIcon, {}), "Website"] }))] })] })] }));
27705
28227
  }
27706
28228
  function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
27707
28229
  const rawState = action.state;
@@ -27735,40 +28257,443 @@ function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
27735
28257
  if (isSingleLocation) {
27736
28258
  return (jsx(LocationItem, { location: locations[0], settings: settings, accentColor: accentColor, onDirections: () => handleDirections(locations[0]), showMap: true }));
27737
28259
  }
27738
- return (jsxs("div", { className: `ai-chat-location-card-list ai-chat-location-card-list--${layout}`, children: [jsxs("div", { className: "ai-chat-location-card-list__header", children: [jsx(MapPinIcon, {}), jsxs("span", { children: [locations.length, " Locations"] })] }), layout === 'stack' && (jsx("div", { className: "ai-chat-location-card-list__stack", style: {
27739
- gridTemplateColumns: `repeat(${stackColumns}, minmax(0, 1fr))`,
27740
- }, children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: settings.showMap !== false, compact: locations.length > 2 }, location.id))) })), layout === 'grid' && (jsx("div", { className: "ai-chat-location-card-list__grid", children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: false, compact: true }, location.id))) })), layout === 'carousel' && (jsx("div", { className: "ai-chat-location-card-list__carousel", children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: true, compact: false }, location.id))) }))] }));
28260
+ return (jsxs("div", { className: `ai-chat-location-card-list ai-chat-location-card-list--${layout}`, children: [jsxs("div", { className: "ai-chat-location-card-list__header", children: [jsx(MapPinIcon, {}), jsxs("span", { children: [locations.length, " Locations"] })] }), layout === 'stack' && (jsx("div", { className: `ai-chat-location-card-list__stack ai-chat-location-card-list__stack--cols-${stackColumns}`, children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: settings.showMap !== false, compact: locations.length > 2 }, location.id))) })), layout === 'grid' && (jsx("div", { className: "ai-chat-location-card-list__grid", children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: false, compact: true }, location.id))) })), layout === 'carousel' && (jsx("div", { className: "ai-chat-location-card-list__carousel", children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: true, compact: false }, location.id))) }))] }));
27741
28261
  }
27742
28262
 
27743
- const pendingResolvers = new Map();
27744
- const resumeCallbacks = new Map();
27745
- const frontendActionHandlers = {};
27746
- const actionRenderers = {};
27747
- function getFrontendActionHandler(implementation) {
27748
- return frontendActionHandlers[implementation];
28263
+ function UsersIcon() {
28264
+ return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }), jsx("circle", { cx: "9", cy: "7", r: "4" }), jsx("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87" }), jsx("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })] }));
27749
28265
  }
27750
- function getActionRenderer(implementation) {
27751
- return actionRenderers[implementation];
27752
- }
27753
- function getActionPrompt(implementation) {
27754
- if (implementation === "google-calendar-appointment") {
27755
- return "Select a date to continue.";
28266
+ const AVATAR_COLORS = [
28267
+ { bg: '#E8F5E9', text: '#2E7D32' }, // Green
28268
+ { bg: '#E3F2FD', text: '#1565C0' }, // Blue
28269
+ { bg: '#FFF3E0', text: '#E65100' }, // Orange
28270
+ { bg: '#F3E5F5', text: '#7B1FA2' }, // Purple
28271
+ { bg: '#FFEBEE', text: '#C62828' }, // Red
28272
+ { bg: '#E0F7FA', text: '#00838F' }, // Cyan
28273
+ { bg: '#FFF8E1', text: '#F9A825' }, // Amber
28274
+ { bg: '#FCE4EC', text: '#AD1457' }, // Pink
28275
+ ];
28276
+ function getInitials(name) {
28277
+ const parts = name.trim().split(/\s+/);
28278
+ if (parts.length === 1) {
28279
+ return parts[0].substring(0, 2).toUpperCase();
27756
28280
  }
27757
- return "Action input required.";
27758
- }
27759
- function waitForActionState(toolCallId) {
27760
- return new Promise((resolve) => {
27761
- pendingResolvers.set(toolCallId, resolve);
27762
- });
28281
+ return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
27763
28282
  }
27764
- function resolveActionState(toolCallId, state) {
27765
- const resolver = pendingResolvers.get(toolCallId);
27766
- if (resolver) {
27767
- pendingResolvers.delete(toolCallId);
27768
- resolver(state);
27769
- return;
28283
+ function getColorFromName(name) {
28284
+ let hash = 0;
28285
+ for (let i = 0; i < name.length; i++) {
28286
+ hash = name.charCodeAt(i) + ((hash << 5) - hash);
27770
28287
  }
27771
- const resumeCallback = resumeCallbacks.get(toolCallId);
28288
+ return AVATAR_COLORS[Math.abs(hash) % AVATAR_COLORS.length];
28289
+ }
28290
+ function ContactItem({ contact, settings, accentColor, onEmail, onPhone, compact = false, layout = 'vertical', }) {
28291
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28292
+ const layoutClass = layout === 'horizontal'
28293
+ ? 'ai-chat-contact-card--horizontal'
28294
+ : 'ai-chat-contact-card--vertical';
28295
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-contact-card ${layoutClass} ${compact ? 'ai-chat-contact-card--compact' : ''}`, style: style, children: [jsxs("div", { className: "ai-chat-contact-card__image-section", children: [contact.profilePictureUrl ? (jsx("img", { src: contact.profilePictureUrl, alt: contact.name, className: "ai-chat-contact-card__image", onError: (e) => {
28296
+ e.currentTarget.style.display = 'none';
28297
+ const placeholder = e.currentTarget.parentElement?.querySelector('.ai-chat-contact-card__initials');
28298
+ if (placeholder) {
28299
+ placeholder.style.display = 'flex';
28300
+ }
28301
+ } })) : null, (() => {
28302
+ const colors = getColorFromName(contact.name);
28303
+ return (jsx("div", { className: "ai-chat-contact-card__initials", style: {
28304
+ display: contact.profilePictureUrl ? 'none' : 'flex',
28305
+ backgroundColor: colors.bg,
28306
+ color: colors.text,
28307
+ }, children: getInitials(contact.name) }));
28308
+ })()] }), jsxs("div", { className: "ai-chat-contact-card__info", children: [jsx("h4", { className: "ai-chat-contact-card__name", children: contact.name }), settings.showRole !== false && contact.role && (jsx("p", { className: "ai-chat-contact-card__role", children: contact.role })), jsxs("div", { className: "ai-chat-contact-card__details", children: [settings.showEmail !== false && contact.email && (jsx("a", { href: `mailto:${contact.email}`, className: "ai-chat-contact-card__detail", onClick: onEmail, children: contact.email })), settings.showPhone !== false && contact.phone && (jsx("a", { href: `tel:${contact.phone}`, className: "ai-chat-contact-card__detail", onClick: onPhone, children: contact.phone }))] }), settings.showResponsibilities !== false && contact.responsibilities && contact.responsibilities.length > 0 && !compact && (jsxs("div", { className: "ai-chat-contact-card__responsibilities", children: [contact.responsibilities.slice(0, 3).map((resp, idx) => (jsx("span", { className: "ai-chat-contact-card__responsibility-tag", children: resp }, idx))), contact.responsibilities.length > 3 && (jsxs("span", { className: "ai-chat-contact-card__responsibility-more", children: ["+", contact.responsibilities.length - 3, " more"] }))] }))] })] }));
28309
+ }
28310
+ function ContactCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28311
+ const rawState = action.state;
28312
+ const hasCompletedRef = useRef(false);
28313
+ const state = {
28314
+ contacts: rawState?.contacts || [],
28315
+ settings: rawState?.settings || {},
28316
+ query: rawState?.query,
28317
+ status: rawState?.status || 'displaying',
28318
+ };
28319
+ const { contacts, settings } = state;
28320
+ const isSingleContact = contacts.length === 1;
28321
+ const stackColumns = Math.min(Math.max(contacts.length, 1), maxColumns);
28322
+ useEffect(() => {
28323
+ if (!action.done && !hasCompletedRef.current && onComplete) {
28324
+ hasCompletedRef.current = true;
28325
+ onComplete(action.toolCallId, { ...state, status: 'displaying' });
28326
+ }
28327
+ }, [action.done, action.toolCallId, onComplete, state]);
28328
+ const handleContact = () => {
28329
+ onComplete?.(action.toolCallId, { ...state, status: 'contacted' });
28330
+ };
28331
+ if (contacts.length === 0) {
28332
+ return (jsxs("div", { className: "ai-chat-contact-card ai-chat-contact-card--empty", children: [jsx("div", { className: "ai-chat-contact-card__empty-icon", children: jsx(UsersIcon, {}) }), jsxs("p", { className: "ai-chat-contact-card__empty-text", children: ["No contacts found", state.query ? ` for "${state.query}"` : ''] })] }));
28333
+ }
28334
+ if (isSingleContact) {
28335
+ return (jsx(ContactItem, { contact: contacts[0], settings: settings, accentColor: accentColor, onEmail: handleContact, onPhone: handleContact, layout: settings.layout || 'horizontal' }));
28336
+ }
28337
+ const isWidget = maxColumns === 1;
28338
+ const stackClassName = isWidget
28339
+ ? 'ai-chat-contact-card-list__stack ai-chat-contact-card-list__stack--widget'
28340
+ : 'ai-chat-contact-card-list__stack';
28341
+ return (jsxs("div", { className: "ai-chat-contact-card-list", style: { containerType: 'inline-size' }, children: [jsxs("div", { className: "ai-chat-contact-card-list__header", children: [jsx(UsersIcon, {}), jsxs("span", { children: [contacts.length, " Contacts"] })] }), jsx("div", { className: stackClassName, style: isWidget ? undefined : {
28342
+ gridTemplateColumns: `repeat(${stackColumns}, minmax(0, 1fr))`,
28343
+ }, children: contacts.map((contact) => (jsx(ContactItem, { contact: contact, settings: settings, accentColor: accentColor, onEmail: handleContact, onPhone: handleContact, compact: true, layout: settings.layout || 'vertical' }, contact.id))) })] }));
28344
+ }
28345
+
28346
+ function FormCard({ action, onComplete, onDismiss, accentColor }) {
28347
+ const state = action.state;
28348
+ const [currentStep, setCurrentStep] = useState(0);
28349
+ const [answers, setAnswers] = useState({});
28350
+ const [isSubmitting, setIsSubmitting] = useState(false);
28351
+ const questions = state.questions || [];
28352
+ const currentQuestion = questions[currentStep];
28353
+ const totalQuestions = questions.length;
28354
+ const handleAnswerChange = (questionId, value) => {
28355
+ setAnswers((prev) => ({ ...prev, [questionId]: value }));
28356
+ };
28357
+ const handleNext = () => {
28358
+ if (currentStep < totalQuestions - 1) {
28359
+ setCurrentStep((prev) => prev + 1);
28360
+ }
28361
+ };
28362
+ const handlePrev = () => {
28363
+ if (currentStep > 0) {
28364
+ setCurrentStep((prev) => prev - 1);
28365
+ }
28366
+ };
28367
+ const handleSubmit = () => {
28368
+ if (!onComplete)
28369
+ return;
28370
+ setIsSubmitting(true);
28371
+ const formattedAnswers = Object.entries(answers).map(([questionId, value]) => ({
28372
+ questionId,
28373
+ value,
28374
+ }));
28375
+ onComplete(action.toolCallId, {
28376
+ ...state,
28377
+ status: 'submitted',
28378
+ answers: formattedAnswers,
28379
+ });
28380
+ };
28381
+ const handleSkip = () => {
28382
+ if (!onComplete || !state.settings.allowSkip)
28383
+ return;
28384
+ onComplete(action.toolCallId, {
28385
+ ...state,
28386
+ status: 'skipped',
28387
+ });
28388
+ };
28389
+ const isCurrentAnswered = () => {
28390
+ if (!currentQuestion)
28391
+ return false;
28392
+ const answer = answers[currentQuestion.id];
28393
+ if (!answer)
28394
+ return !currentQuestion.required;
28395
+ if (Array.isArray(answer))
28396
+ return answer.length > 0 || !currentQuestion.required;
28397
+ return answer.trim() !== '' || !currentQuestion.required;
28398
+ };
28399
+ const canSubmit = () => {
28400
+ return questions.every((q) => {
28401
+ const answer = answers[q.id];
28402
+ if (!q.required)
28403
+ return true;
28404
+ if (!answer)
28405
+ return false;
28406
+ if (Array.isArray(answer))
28407
+ return answer.length > 0;
28408
+ return answer.trim() !== '';
28409
+ });
28410
+ };
28411
+ const handleDismiss = () => {
28412
+ onDismiss?.(action.toolCallId);
28413
+ };
28414
+ // Error state
28415
+ if (state.status === 'error') {
28416
+ return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--error", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\u26A0\uFE0F" }), jsx("span", { className: "ai-chat-form-card__title", children: "Form Error" })] }), jsx("p", { className: "ai-chat-form-card__error", children: state.error || 'Could not load form' })] }));
28417
+ }
28418
+ // Submitted state
28419
+ if (state.status === 'submitted' || action.done) {
28420
+ return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--submitted", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\u2713" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsx("p", { className: "ai-chat-form-card__success", children: state.settings.successMessage || 'Thank you for your response!' })] }));
28421
+ }
28422
+ // Skipped state
28423
+ if (state.status === 'skipped') {
28424
+ return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--skipped", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\u21B7" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsx("p", { className: "ai-chat-form-card__skipped-text", children: "Form skipped" })] }));
28425
+ }
28426
+ // No questions
28427
+ if (totalQuestions === 0) {
28428
+ return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--empty", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\uD83D\uDCCB" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsx("p", { className: "ai-chat-form-card__empty-text", children: "This form has no questions." })] }));
28429
+ }
28430
+ const showCloseButton = state.status === "displaying" && !action.done && Boolean(onDismiss);
28431
+ return (jsxs("div", { className: `ai-chat-form-card${showCloseButton ? " ai-chat-form-card--closable" : ""}`, children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\uD83D\uDCCB" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title }), showCloseButton && (jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Close form" }))] }), state.description && (jsx("p", { className: "ai-chat-form-card__description", children: state.description })), state.context && (jsx("p", { className: "ai-chat-form-card__context", children: state.context })), state.settings.showProgress && (jsxs("div", { className: "ai-chat-form-card__progress", children: [jsx("div", { className: "ai-chat-form-card__progress-bar", style: {
28432
+ width: `${((currentStep + 1) / totalQuestions) * 100}%`,
28433
+ backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
28434
+ } }), jsxs("span", { className: "ai-chat-form-card__progress-text", children: [currentStep + 1, " of ", totalQuestions] })] })), jsxs("div", { className: "ai-chat-form-card__question", children: [jsxs("p", { className: "ai-chat-form-card__question-text", children: [currentQuestion.text, currentQuestion.required && jsx("span", { className: "ai-chat-form-card__required", children: "*" })] }), jsxs("div", { className: "ai-chat-form-card__answer", children: [currentQuestion.type === 'text' && (jsx("textarea", { className: "ai-chat-form-card__textarea", placeholder: currentQuestion.placeholder || 'Type your answer...', value: answers[currentQuestion.id] || '', onChange: (e) => handleAnswerChange(currentQuestion.id, e.target.value), rows: 3 })), currentQuestion.type === 'single_choice' && currentQuestion.options && (jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => (jsxs("label", { className: "ai-chat-form-card__option", children: [jsx("input", { type: "radio", name: currentQuestion.id, value: option.value, checked: answers[currentQuestion.id] === option.value, onChange: () => handleAnswerChange(currentQuestion.id, option.value) }), jsx("span", { className: "ai-chat-form-card__option-text", children: option.text })] }, option.id))) })), currentQuestion.type === 'multiple_choice' && currentQuestion.options && (jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => {
28435
+ const currentAnswers = answers[currentQuestion.id] || [];
28436
+ const isChecked = currentAnswers.includes(option.value);
28437
+ return (jsxs("label", { className: "ai-chat-form-card__option", children: [jsx("input", { type: "checkbox", value: option.value, checked: isChecked, onChange: () => {
28438
+ const newAnswers = isChecked
28439
+ ? currentAnswers.filter((v) => v !== option.value)
28440
+ : [...currentAnswers, option.value];
28441
+ handleAnswerChange(currentQuestion.id, newAnswers);
28442
+ } }), jsx("span", { className: "ai-chat-form-card__option-text", children: option.text })] }, option.id));
28443
+ }) })), currentQuestion.type === 'rating' && (jsx("div", { className: "ai-chat-form-card__rating", children: Array.from({ length: (currentQuestion.maxRating || 5) - (currentQuestion.minRating || 1) + 1 }, (_, i) => (currentQuestion.minRating || 1) + i).map((rating) => (jsx("button", { type: "button", className: `ai-chat-form-card__rating-btn ${answers[currentQuestion.id] === String(rating) ? 'ai-chat-form-card__rating-btn--selected' : ''}`, onClick: () => handleAnswerChange(currentQuestion.id, String(rating)), style: {
28444
+ borderColor: answers[currentQuestion.id] === String(rating)
28445
+ ? (accentColor || 'var(--ai-chat-accent-color, #3b82f6)')
28446
+ : undefined,
28447
+ backgroundColor: answers[currentQuestion.id] === String(rating)
28448
+ ? (accentColor || 'var(--ai-chat-accent-color, #3b82f6)')
28449
+ : undefined,
28450
+ }, children: rating }, rating))) }))] })] }), jsxs("div", { className: "ai-chat-form-card__actions", children: [currentStep > 0 && (jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--secondary", onClick: handlePrev, children: "Back" })), state.settings.allowSkip && currentStep === 0 && (jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--ghost", onClick: handleSkip, children: "Skip" })), jsx("div", { className: "ai-chat-form-card__actions-spacer" }), currentStep < totalQuestions - 1 ? (jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--primary", onClick: handleNext, disabled: !isCurrentAnswered(), style: {
28451
+ backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
28452
+ }, children: "Next" })) : (jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--primary", onClick: handleSubmit, disabled: !canSubmit() || isSubmitting, style: {
28453
+ backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
28454
+ }, children: isSubmitting ? 'Submitting...' : (state.settings.submitButtonText || 'Submit') }))] })] }));
28455
+ }
28456
+
28457
+ function Skeleton({ width, height, borderRadius = '4px' }) {
28458
+ return (jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
28459
+ }
28460
+ function PinInputGroup({ values, onChange, disabled }) {
28461
+ const inputRefs = useRef([]);
28462
+ const handleChange = (index, value) => {
28463
+ // Only allow digits
28464
+ const digit = value.replace(/[^0-9]/g, '');
28465
+ const newValues = [...values];
28466
+ newValues[index] = digit.slice(-1);
28467
+ onChange(newValues);
28468
+ // Auto-focus next input
28469
+ if (digit && index < 5) {
28470
+ inputRefs.current[index + 1]?.focus();
28471
+ }
28472
+ };
28473
+ const handleKeyDown = (index, e) => {
28474
+ if (e.key === 'Backspace' && !values[index] && index > 0) {
28475
+ inputRefs.current[index - 1]?.focus();
28476
+ }
28477
+ };
28478
+ const handlePaste = (e) => {
28479
+ e.preventDefault();
28480
+ const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, 6);
28481
+ const newValues = pastedData.split('').concat(Array(6 - pastedData.length).fill(''));
28482
+ onChange(newValues);
28483
+ // Focus the next empty input or the last one
28484
+ const nextIndex = Math.min(pastedData.length, 5);
28485
+ inputRefs.current[nextIndex]?.focus();
28486
+ };
28487
+ return (jsx("div", { className: "ai-chat-pin-input-group", children: values.map((value, index) => (jsx("input", { ref: (el) => {
28488
+ inputRefs.current[index] = el;
28489
+ }, type: "text", inputMode: "numeric", maxLength: 1, className: "ai-chat-pin-input", value: value, onChange: (e) => handleChange(index, e.target.value), onKeyDown: (e) => handleKeyDown(index, e), onPaste: handlePaste, disabled: disabled, autoFocus: index === 0 }, index))) }));
28490
+ }
28491
+ function BookContactAppointmentCard({ action, onComplete, accentColor }) {
28492
+ const state = action.state;
28493
+ const [emailInput, setEmailInput] = useState('');
28494
+ const [otpValues, setOtpValues] = useState(Array(6).fill(''));
28495
+ const [subjectInput, setSubjectInput] = useState(state.subject || '');
28496
+ const [isSubmitting, setIsSubmitting] = useState(false);
28497
+ const [emailError, setEmailError] = useState(null);
28498
+ const [otpError, setOtpError] = useState(null);
28499
+ const phase = state.phase || 'awaiting_email';
28500
+ const handleSubmit = (newState, delay = 50) => {
28501
+ if (!onComplete)
28502
+ return;
28503
+ setIsSubmitting(true);
28504
+ setTimeout(() => {
28505
+ onComplete(action.toolCallId, { ...state, ...newState, errorMessage: null });
28506
+ }, delay);
28507
+ };
28508
+ useEffect(() => {
28509
+ setIsSubmitting(false);
28510
+ if (phase === 'awaiting_email') {
28511
+ setEmailError(null);
28512
+ setOtpError(null);
28513
+ }
28514
+ else if (phase === 'awaiting_otp') {
28515
+ setOtpError(state.errorMessage || null);
28516
+ setEmailError(null);
28517
+ setOtpValues(Array(6).fill(''));
28518
+ if (state.email) {
28519
+ setEmailInput(state.email);
28520
+ }
28521
+ }
28522
+ else {
28523
+ setEmailError(null);
28524
+ setOtpError(null);
28525
+ }
28526
+ }, [phase, state.errorMessage]);
28527
+ const isWaitingForBackend = !action.done && Boolean(state.confirmed) && phase === 'awaiting_confirmation';
28528
+ const renderSkeleton = () => (jsx("div", { className: "ai-chat-booking-card", children: jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsx(Skeleton, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
28529
+ const handleEmailSubmit = () => {
28530
+ const trimmedEmail = emailInput.trim();
28531
+ if (!trimmedEmail) {
28532
+ setEmailError('Please enter your email address');
28533
+ return;
28534
+ }
28535
+ setEmailError(null);
28536
+ setEmailInput(trimmedEmail);
28537
+ handleSubmit({ email: trimmedEmail });
28538
+ };
28539
+ const handleOtpSubmit = () => {
28540
+ const code = otpValues.join('');
28541
+ if (code.length !== 6) {
28542
+ setOtpError('Please enter the 6-digit code');
28543
+ return;
28544
+ }
28545
+ setOtpError(null);
28546
+ const resolvedEmail = state.email || emailInput.trim() || null;
28547
+ handleSubmit({ otpCode: code, email: resolvedEmail });
28548
+ };
28549
+ // ========================================
28550
+ // Terminal States
28551
+ // ========================================
28552
+ if (phase === 'booked') {
28553
+ return (jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--success", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2713" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Booked" })] }), state.bookedTeamsLink && (jsxs("div", { className: "ai-chat-booking-card__content", children: [jsx("p", { className: "ai-chat-booking-card__success-text", children: "Your appointment has been confirmed. You can join via Microsoft Teams." }), jsx("a", { href: state.bookedTeamsLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__link", style: { color: accentColor }, children: "Join Teams Meeting \u2192" })] }))] }));
28554
+ }
28555
+ if (phase === 'pending_approval') {
28556
+ return (jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--pending", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\u23F3" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Awaiting Approval" })] }), jsx("div", { className: "ai-chat-booking-card__content", children: jsx("p", { className: "ai-chat-booking-card__pending-text", children: "Your appointment request has been sent and is awaiting approval from the contact." }) })] }));
28557
+ }
28558
+ if (phase === 'cancelled') {
28559
+ return (jsx("div", { className: "ai-chat-booking-card ai-chat-booking-card--cancelled", children: jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2715" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Cancelled" })] }) }));
28560
+ }
28561
+ if (phase === 'error') {
28562
+ return (jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--error", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\u26A0\uFE0F" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Booking Error" })] }), state.errorMessage && (jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage }))] }));
28563
+ }
28564
+ if (isSubmitting || isWaitingForBackend) {
28565
+ return renderSkeleton();
28566
+ }
28567
+ // ========================================
28568
+ // Phase: Email Collection
28569
+ // ========================================
28570
+ if (phase === 'awaiting_email') {
28571
+ const displayError = emailError || state.errorMessage;
28572
+ return (jsxs("div", { className: "ai-chat-booking-card", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCE7" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Enter Your Email" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [jsx("p", { className: "ai-chat-booking-card__description", children: "Please enter your email address to start the booking process." }), displayError && (jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), jsx("input", { type: "email", className: "ai-chat-booking-card__input", placeholder: "your@email.com", value: emailInput, onChange: (e) => {
28573
+ setEmailInput(e.target.value);
28574
+ setEmailError(null);
28575
+ }, onKeyDown: (e) => {
28576
+ if (e.key === 'Enter') {
28577
+ handleEmailSubmit();
28578
+ }
28579
+ } }), jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleEmailSubmit, disabled: !emailInput.trim(), style: {
28580
+ backgroundColor: accentColor || undefined,
28581
+ borderColor: accentColor || undefined,
28582
+ }, children: "Continue" })] })] }));
28583
+ }
28584
+ // ========================================
28585
+ // Phase: OTP Verification
28586
+ // ========================================
28587
+ if (phase === 'awaiting_otp') {
28588
+ const displayError = otpError || state.errorMessage;
28589
+ return (jsxs("div", { className: "ai-chat-booking-card", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDD10" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Verify Your Email" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxs("p", { className: "ai-chat-booking-card__description", children: ["Enter the verification code sent to ", jsx("strong", { children: state.email })] }), jsx(PinInputGroup, { values: otpValues, onChange: (newValues) => {
28590
+ setOtpValues(newValues);
28591
+ setOtpError(null);
28592
+ if (newValues.every((value) => value.length === 1) && !isSubmitting) {
28593
+ const resolvedEmail = state.email || emailInput.trim() || null;
28594
+ handleSubmit({ otpCode: newValues.join(''), email: resolvedEmail }, 100);
28595
+ }
28596
+ }, disabled: isSubmitting }), displayError && (jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleOtpSubmit, disabled: otpValues.join('').length !== 6, style: {
28597
+ backgroundColor: accentColor || undefined,
28598
+ borderColor: accentColor || undefined,
28599
+ }, children: "Verify" })] })] }));
28600
+ }
28601
+ // ========================================
28602
+ // Phase: Contact Selection
28603
+ // ========================================
28604
+ if (phase === 'awaiting_contact_selection') {
28605
+ return (jsxs("div", { className: "ai-chat-booking-card", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDC65" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Select a Contact" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), state.bookableContacts.length === 0 ? (jsx("p", { className: "ai-chat-booking-card__empty", children: "No contacts available for booking." })) : (jsx("div", { className: "ai-chat-booking-card__grid", children: state.bookableContacts.map((contact) => (jsxs("button", { className: `ai-chat-booking-card__contact ${state.selectedContactId === contact.id ? 'ai-chat-booking-card__contact--selected' : ''}`, onClick: () => handleSubmit({ selectedContactId: contact.id }), style: {
28606
+ borderColor: state.selectedContactId === contact.id
28607
+ ? accentColor || undefined
28608
+ : undefined,
28609
+ backgroundColor: state.selectedContactId === contact.id
28610
+ ? `${accentColor || '#3b82f6'}15`
28611
+ : undefined,
28612
+ }, children: [jsx("div", { className: "ai-chat-booking-card__contact-name", children: contact.name }), contact.role && (jsx("div", { className: "ai-chat-booking-card__contact-role", children: contact.role }))] }, contact.id))) }))] })] }));
28613
+ }
28614
+ // ========================================
28615
+ // Phase: Options Selection
28616
+ // ========================================
28617
+ if (phase === 'awaiting_options') {
28618
+ const selectedContact = state.bookableContacts.find((c) => c.id === state.selectedContactId);
28619
+ return (jsxs("div", { className: "ai-chat-booking-card", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCC5" }), jsxs("span", { className: "ai-chat-booking-card__title", children: ["Book with ", selectedContact?.name] })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), jsxs("div", { className: "ai-chat-booking-card__options", children: [jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: () => handleSubmit({ selectedOption: 'book_new' }), children: [jsx("span", { className: "ai-chat-booking-card__option-icon", children: "\u2795" }), jsx("span", { className: "ai-chat-booking-card__option-text", children: "Book New Appointment" })] }), state.userAppointments.length > 0 && (jsxs(Fragment, { children: [jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: () => handleSubmit({ selectedOption: 'view_existing' }), children: [jsx("span", { className: "ai-chat-booking-card__option-icon", children: "\uD83D\uDCCB" }), jsx("span", { className: "ai-chat-booking-card__option-text", children: "View Appointments" })] }), jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: () => handleSubmit({ selectedOption: 'cancel_existing' }), children: [jsx("span", { className: "ai-chat-booking-card__option-icon", children: "\u2715" }), jsx("span", { className: "ai-chat-booking-card__option-text", children: "Cancel Appointment" })] })] }))] })] })] }));
28620
+ }
28621
+ // ========================================
28622
+ // Phase: View Existing Appointments
28623
+ // ========================================
28624
+ if (state.phase === 'awaiting_options' && state.selectedOption === 'view_existing') {
28625
+ return (jsxs("div", { className: "ai-chat-booking-card", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCCB" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Your Appointments" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [state.userAppointments.length === 0 ? (jsx("p", { className: "ai-chat-booking-card__empty", children: "You have no appointments yet." })) : (jsx("div", { className: "ai-chat-booking-card__appointments", children: state.userAppointments.map((apt) => (jsxs("div", { className: "ai-chat-booking-card__appointment", children: [jsxs("div", { className: "ai-chat-booking-card__appointment-header", children: [jsx("span", { className: "ai-chat-booking-card__appointment-subject", children: apt.subject }), jsx("span", { className: `ai-chat-booking-card__appointment-status ai-chat-booking-card__appointment-status--${apt.status}`, children: apt.status })] }), jsx("div", { className: "ai-chat-booking-card__appointment-time", children: apt.displayTime }), jsxs("div", { className: "ai-chat-booking-card__appointment-contact", children: ["with ", apt.contactName] }), apt.teamsLink && (jsx("a", { href: apt.teamsLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__link", style: { color: accentColor }, children: "Join Teams Meeting \u2192" }))] }, apt.id))) })), jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: () => handleSubmit({ selectedOption: undefined }), children: "Back" })] })] }));
28626
+ }
28627
+ // ========================================
28628
+ // Phase: Cancel Appointment
28629
+ // ========================================
28630
+ if (state.phase === 'awaiting_options' && state.selectedOption === 'cancel_existing') {
28631
+ const activeAppointments = state.userAppointments.filter((a) => a.status !== 'cancelled' && a.status !== 'declined');
28632
+ return (jsxs("div", { className: "ai-chat-booking-card", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2715" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Cancel Appointment" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), activeAppointments.length === 0 ? (jsxs(Fragment, { children: [jsx("p", { className: "ai-chat-booking-card__empty", children: "No active appointments to cancel." }), jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: () => handleSubmit({ selectedOption: undefined }), children: "Back" })] })) : (jsx("div", { className: "ai-chat-booking-card__appointments", children: activeAppointments.map((apt) => (jsxs("div", { className: "ai-chat-booking-card__appointment", children: [jsx("div", { className: "ai-chat-booking-card__appointment-header", children: jsx("span", { className: "ai-chat-booking-card__appointment-subject", children: apt.subject }) }), jsx("div", { className: "ai-chat-booking-card__appointment-time", children: apt.displayTime }), jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--danger", onClick: () => handleSubmit({ selectedAppointmentId: apt.id, confirmCancel: true }), children: "Cancel This Appointment" })] }, apt.id))) }))] })] }));
28633
+ }
28634
+ // ========================================
28635
+ // Phase: Slot Selection
28636
+ // ========================================
28637
+ if (phase === 'awaiting_slot_selection') {
28638
+ const groupedSlots = state.availableSlots.reduce((acc, slot) => {
28639
+ if (!acc[slot.displayDate]) {
28640
+ acc[slot.displayDate] = [];
28641
+ }
28642
+ acc[slot.displayDate].push(slot);
28643
+ return acc;
28644
+ }, {});
28645
+ return (jsxs("div", { className: "ai-chat-booking-card", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDD50" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Select a Time Slot" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxs("p", { className: "ai-chat-booking-card__description", children: ["Available times in ", state.timeZone] }), state.errorMessage && (jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), Object.entries(groupedSlots).map(([date, slots]) => (jsxs("div", { className: "ai-chat-booking-card__date-group", children: [jsx("div", { className: "ai-chat-booking-card__date-header", children: date }), jsx("div", { className: "ai-chat-booking-card__slots", children: slots.map((slot, idx) => {
28646
+ const isSelected = state.selectedSlot?.startTime === slot.startTime &&
28647
+ state.selectedSlot?.endTime === slot.endTime;
28648
+ return (jsx("button", { className: `ai-chat-booking-card__slot ${isSelected ? 'ai-chat-booking-card__slot--selected' : ''}`, onClick: () => handleSubmit({
28649
+ selectedSlot: { startTime: slot.startTime, endTime: slot.endTime },
28650
+ }), style: {
28651
+ borderColor: isSelected ? accentColor || undefined : undefined,
28652
+ backgroundColor: isSelected ? `${accentColor || '#3b82f6'}15` : undefined,
28653
+ }, children: slot.displayTime }, `${slot.startTime}-${idx}`));
28654
+ }) })] }, date))), state.availableSlots.length === 0 && (jsx("p", { className: "ai-chat-booking-card__empty", children: "No available time slots." }))] })] }));
28655
+ }
28656
+ // ========================================
28657
+ // Phase: Confirmation
28658
+ // ========================================
28659
+ if (phase === 'awaiting_confirmation') {
28660
+ const selectedContact = state.bookableContacts.find((c) => c.id === state.selectedContactId);
28661
+ const selectedSlot = state.availableSlots.find((s) => s.startTime === state.selectedSlot?.startTime && s.endTime === state.selectedSlot?.endTime);
28662
+ return (jsxs("div", { className: "ai-chat-booking-card", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2713" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Confirm Booking" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), jsxs("div", { className: "ai-chat-booking-card__summary", children: [jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Contact:" }), jsx("span", { className: "ai-chat-booking-card__summary-value", children: selectedContact?.name })] }), jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Date:" }), jsx("span", { className: "ai-chat-booking-card__summary-value", children: selectedSlot?.displayDate })] }), jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Time:" }), jsx("span", { className: "ai-chat-booking-card__summary-value", children: selectedSlot?.displayTime })] })] }), state.allowCustomSubject && (jsxs(Fragment, { children: [jsx("label", { className: "ai-chat-booking-card__label", children: "Subject (optional):" }), jsx("input", { type: "text", className: "ai-chat-booking-card__input", placeholder: "Meeting subject", value: subjectInput, onChange: (e) => setSubjectInput(e.target.value) })] })), jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: () => handleSubmit({
28663
+ subject: state.allowCustomSubject ? subjectInput || undefined : undefined,
28664
+ confirmed: true,
28665
+ }), style: {
28666
+ backgroundColor: accentColor || undefined,
28667
+ borderColor: accentColor || undefined,
28668
+ }, children: "Confirm Booking" })] })] }));
28669
+ }
28670
+ // Fallback for unknown states
28671
+ return (jsxs("div", { className: "ai-chat-booking-card", children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCC5" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Booking" })] }), jsx("div", { className: "ai-chat-booking-card__content", children: jsx("p", { className: "ai-chat-booking-card__description", children: "Loading booking options..." }) })] }));
28672
+ }
28673
+
28674
+ const pendingResolvers = new Map();
28675
+ const resumeCallbacks = new Map();
28676
+ const frontendActionHandlers = {};
28677
+ const actionRenderers = {};
28678
+ function getFrontendActionHandler(implementation) {
28679
+ return frontendActionHandlers[implementation];
28680
+ }
28681
+ function getActionRenderer(implementation) {
28682
+ return actionRenderers[implementation];
28683
+ }
28684
+ function waitForActionState(toolCallId) {
28685
+ return new Promise((resolve) => {
28686
+ pendingResolvers.set(toolCallId, resolve);
28687
+ });
28688
+ }
28689
+ function resolveActionState(toolCallId, state) {
28690
+ const resolver = pendingResolvers.get(toolCallId);
28691
+ if (resolver) {
28692
+ pendingResolvers.delete(toolCallId);
28693
+ resolver(state);
28694
+ return;
28695
+ }
28696
+ const resumeCallback = resumeCallbacks.get(toolCallId);
27772
28697
  if (resumeCallback) {
27773
28698
  resumeCallback(state).catch((error) => {
27774
28699
  console.error("[Action] Failed to resume action:", error);
@@ -27796,13 +28721,19 @@ function registerGoogleCalendarAction() {
27796
28721
  // Register the handler
27797
28722
  registerGoogleCalendarHandler();
27798
28723
  // Register the renderer
27799
- actionRenderers["google-calendar-appointment"] = (message) => {
28724
+ actionRenderers["google-calendar-appointment"] = (message, accentColor, _variant, onActionDismiss) => {
27800
28725
  const action = message.action;
27801
28726
  if (!action)
27802
28727
  return null;
27803
28728
  const handleComplete = (toolCallId, newState) => {
27804
28729
  resolveActionState(toolCallId, newState);
27805
28730
  };
28731
+ const handleDismiss = onActionDismiss
28732
+ ? (toolCallId) => {
28733
+ resolveActionState(toolCallId, { __dismissed: true });
28734
+ onActionDismiss(toolCallId);
28735
+ }
28736
+ : undefined;
27806
28737
  return (jsx(GoogleCalendarCard, { action: {
27807
28738
  implementation: action.implementation,
27808
28739
  toolCallId: action.toolCallId,
@@ -27810,7 +28741,45 @@ function registerGoogleCalendarAction() {
27810
28741
  input: action.input,
27811
28742
  state: action.state,
27812
28743
  done: action.done ?? false,
27813
- }, onComplete: handleComplete }));
28744
+ }, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
28745
+ };
28746
+ }
28747
+
28748
+ function registerMicrosoftCalendarHandler() {
28749
+ frontendActionHandlers["microsoft-calendar-appointment"] = async (_input, _state, context) => {
28750
+ return waitForActionState(context.toolCallId);
28751
+ };
28752
+ }
28753
+
28754
+ /**
28755
+ * Register microsoft-calendar-appointment action handler and renderer.
28756
+ * Called by initializeActionHandlers to prevent tree-shaking.
28757
+ */
28758
+ function registerMicrosoftCalendarAction() {
28759
+ // Register the handler
28760
+ registerMicrosoftCalendarHandler();
28761
+ // Register the renderer
28762
+ actionRenderers["microsoft-calendar-appointment"] = (message, accentColor, _variant, onActionDismiss) => {
28763
+ const action = message.action;
28764
+ if (!action)
28765
+ return null;
28766
+ const handleComplete = (toolCallId, newState) => {
28767
+ resolveActionState(toolCallId, newState);
28768
+ };
28769
+ const handleDismiss = onActionDismiss
28770
+ ? (toolCallId) => {
28771
+ resolveActionState(toolCallId, { __dismissed: true });
28772
+ onActionDismiss(toolCallId);
28773
+ }
28774
+ : undefined;
28775
+ return (jsx(MicrosoftCalendarCard, { action: {
28776
+ implementation: action.implementation,
28777
+ toolCallId: action.toolCallId,
28778
+ actionId: action.actionId,
28779
+ input: action.input,
28780
+ state: action.state,
28781
+ done: action.done ?? false,
28782
+ }, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
27814
28783
  };
27815
28784
  }
27816
28785
 
@@ -27824,7 +28793,7 @@ function registerLinkPreviewAction() {
27824
28793
  return { ...state, status: "displaying" };
27825
28794
  };
27826
28795
  // Renderer - displays the link preview card
27827
- actionRenderers["link-preview"] = (message) => {
28796
+ actionRenderers["link-preview"] = (message, accentColor) => {
27828
28797
  const action = message.action;
27829
28798
  if (!action)
27830
28799
  return null;
@@ -27842,7 +28811,7 @@ function registerLinkPreviewAction() {
27842
28811
  input: action.input,
27843
28812
  state: action.state,
27844
28813
  done: isDone,
27845
- }, onComplete: handleComplete }));
28814
+ }, onComplete: handleComplete, accentColor: accentColor }));
27846
28815
  };
27847
28816
  }
27848
28817
 
@@ -27856,7 +28825,7 @@ function registerVideoPlayerAction() {
27856
28825
  return { ...state, status: "displaying" };
27857
28826
  };
27858
28827
  // Renderer - displays the embedded video player card
27859
- actionRenderers["video-player"] = (message) => {
28828
+ actionRenderers["video-player"] = (message, accentColor) => {
27860
28829
  const action = message.action;
27861
28830
  if (!action)
27862
28831
  return null;
@@ -27874,7 +28843,7 @@ function registerVideoPlayerAction() {
27874
28843
  input: action.input,
27875
28844
  state: action.state,
27876
28845
  done: isDone,
27877
- }, onComplete: handleComplete }));
28846
+ }, onComplete: handleComplete, accentColor: accentColor }));
27878
28847
  };
27879
28848
  }
27880
28849
 
@@ -27888,7 +28857,7 @@ function registerLocationCardAction() {
27888
28857
  return { ...state, status: "displaying" };
27889
28858
  };
27890
28859
  // Renderer - displays the location card
27891
- actionRenderers["location-card"] = (message, accentColor) => {
28860
+ actionRenderers["location-card"] = (message, accentColor, variant) => {
27892
28861
  const action = message.action;
27893
28862
  if (!action)
27894
28863
  return null;
@@ -27906,7 +28875,134 @@ function registerLocationCardAction() {
27906
28875
  input: action.input,
27907
28876
  state: action.state,
27908
28877
  done: isDone,
27909
- }, onComplete: handleComplete, accentColor: accentColor, maxColumns: 1 }));
28878
+ }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28879
+ };
28880
+ }
28881
+
28882
+ function registerContactCardAction() {
28883
+ // Handler - auto-completes immediately since no user input is needed
28884
+ frontendActionHandlers['contact-card'] = async (_input, state, _context) => {
28885
+ return { ...state, status: 'displaying' };
28886
+ };
28887
+ // Renderer - displays the contact card
28888
+ actionRenderers['contact-card'] = (message, accentColor, variant) => {
28889
+ const action = message.action;
28890
+ if (!action)
28891
+ return null;
28892
+ const handleComplete = (toolCallId, newState) => {
28893
+ resolveActionState(toolCallId, newState);
28894
+ };
28895
+ // Check if action state indicates it's already complete
28896
+ const state = action.state;
28897
+ const status = state?.status;
28898
+ const isDone = action.done || status === 'displaying' || status === 'contacted';
28899
+ return (jsx(ContactCard, { action: {
28900
+ implementation: action.implementation,
28901
+ toolCallId: action.toolCallId,
28902
+ actionId: action.actionId,
28903
+ input: action.input,
28904
+ state: action.state,
28905
+ done: isDone,
28906
+ }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28907
+ };
28908
+ }
28909
+
28910
+ function registerQueryContactDirectoryAction() {
28911
+ // Handler - auto-completes immediately since no user input is needed
28912
+ frontendActionHandlers['query-contact-directory'] = async (_input, state, _context) => {
28913
+ return { ...state, status: 'displaying' };
28914
+ };
28915
+ // Renderer - displays the contact card with search results
28916
+ actionRenderers['query-contact-directory'] = (message, accentColor, variant) => {
28917
+ const action = message.action;
28918
+ if (!action)
28919
+ return null;
28920
+ // Handle completion - triggers agent to continue with text response
28921
+ const handleComplete = (toolCallId, newState) => {
28922
+ resolveActionState(toolCallId, newState);
28923
+ };
28924
+ // Check if action state indicates it's already complete
28925
+ const state = action.state;
28926
+ const status = state?.status;
28927
+ const isDone = action.done || status === 'displaying' || status === 'contacted';
28928
+ return (jsx(ContactCard, { action: {
28929
+ implementation: action.implementation,
28930
+ toolCallId: action.toolCallId,
28931
+ actionId: action.actionId,
28932
+ input: action.input,
28933
+ state: action.state,
28934
+ done: isDone,
28935
+ }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28936
+ };
28937
+ }
28938
+
28939
+ function registerDisplayFormAction() {
28940
+ // Handler - handles form submission and state updates
28941
+ frontendActionHandlers['display-form'] = async (_input, _state, context) => {
28942
+ return waitForActionState(context.toolCallId);
28943
+ };
28944
+ // Renderer - displays the form card
28945
+ actionRenderers['display-form'] = (message, accentColor, variant, onActionDismiss) => {
28946
+ const action = message.action;
28947
+ if (!action)
28948
+ return null;
28949
+ const handleComplete = (toolCallId, newState) => {
28950
+ resolveActionState(toolCallId, newState);
28951
+ };
28952
+ const handleDismiss = onActionDismiss
28953
+ ? (toolCallId) => {
28954
+ resolveActionState(toolCallId, { __dismissed: true });
28955
+ onActionDismiss(toolCallId);
28956
+ }
28957
+ : undefined;
28958
+ // Check if action state indicates it's already complete
28959
+ const state = action.state;
28960
+ const status = state?.status;
28961
+ const isDone = action.done || status === 'completed' || status === 'submitted';
28962
+ return (jsx(FormCard, { action: {
28963
+ implementation: action.implementation,
28964
+ toolCallId: action.toolCallId,
28965
+ actionId: action.actionId,
28966
+ input: action.input,
28967
+ state: action.state,
28968
+ done: isDone,
28969
+ }, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
28970
+ };
28971
+ }
28972
+
28973
+ /**
28974
+ * Book Contact Appointment Handler
28975
+ * Frontend action handler that waits for action completion
28976
+ */
28977
+ function registerBookContactAppointmentHandler() {
28978
+ frontendActionHandlers["book-contact-appointment"] = async (_input, _state, context) => {
28979
+ return waitForActionState(context.toolCallId);
28980
+ };
28981
+ }
28982
+
28983
+ /**
28984
+ * Register book-contact-appointment action handler and renderer.
28985
+ * Called by initializeActionHandlers to prevent tree-shaking.
28986
+ */
28987
+ function registerBookContactAppointmentAction() {
28988
+ // Register the handler
28989
+ registerBookContactAppointmentHandler();
28990
+ // Register the renderer
28991
+ actionRenderers['book-contact-appointment'] = (message, accentColor) => {
28992
+ const action = message.action;
28993
+ if (!action)
28994
+ return null;
28995
+ const handleComplete = (toolCallId, newState) => {
28996
+ resolveActionState(toolCallId, newState);
28997
+ };
28998
+ return (jsx(BookContactAppointmentCard, { action: {
28999
+ implementation: action.implementation,
29000
+ toolCallId: action.toolCallId,
29001
+ actionId: action.actionId,
29002
+ input: action.input,
29003
+ state: action.state,
29004
+ done: action.done ?? false,
29005
+ }, onComplete: handleComplete, accentColor: accentColor }));
27910
29006
  };
27911
29007
  }
27912
29008
 
@@ -27923,9 +29019,14 @@ function initializeActionHandlers() {
27923
29019
  initialized = true;
27924
29020
  // Explicitly call each registration function to prevent tree-shaking
27925
29021
  registerGoogleCalendarAction();
29022
+ registerMicrosoftCalendarAction();
27926
29023
  registerLinkPreviewAction();
27927
29024
  registerVideoPlayerAction();
27928
29025
  registerLocationCardAction();
29026
+ registerQueryContactDirectoryAction();
29027
+ registerContactCardAction();
29028
+ registerDisplayFormAction();
29029
+ registerBookContactAppointmentAction();
27929
29030
  }
27930
29031
 
27931
29032
  /**
@@ -28145,12 +29246,6 @@ function isStorageAvailable() {
28145
29246
  }
28146
29247
  }
28147
29248
 
28148
- /**
28149
- * useChat Hook
28150
- * Main state management for chat functionality
28151
- */
28152
- // Initialize action handlers immediately to prevent tree-shaking
28153
- initializeActionHandlers();
28154
29249
  function hydrateToolNames(messages) {
28155
29250
  const toolCallNameById = new Map();
28156
29251
  for (const entry of messages) {
@@ -28194,118 +29289,78 @@ function hydrateToolNames(messages) {
28194
29289
  };
28195
29290
  });
28196
29291
  }
28197
- function hydrateActionContent(messages) {
28198
- return messages.map((entry) => {
28199
- if (entry.message.role !== "assistant" || !entry.action) {
28200
- return entry;
28201
- }
28202
- const content = typeof entry.message.content === "string" ? entry.message.content : "";
28203
- if (content.trim().length > 0) {
28204
- return entry;
28205
- }
28206
- return {
28207
- ...entry,
28208
- message: { ...entry.message, content: getActionPrompt(entry.action.implementation) },
28209
- };
28210
- });
29292
+ function hydrateMessages(messages) {
29293
+ const visibleMessages = messages.filter((message) => !message.action?.hidden);
29294
+ return hydrateToolNames(visibleMessages);
28211
29295
  }
28212
- function hydrateActionDoneStatus(messages) {
28213
- return messages.map((entry) => {
28214
- if (!entry.action) {
28215
- return entry;
28216
- }
28217
- // If action already marked done, skip
28218
- if (entry.action.done) {
28219
- return entry;
29296
+
29297
+ function deriveErrorInfo(error) {
29298
+ if (error instanceof ApiError) {
29299
+ const retryAfterSeconds = typeof error.retryAfterMs === 'number'
29300
+ ? Math.max(1, Math.ceil(error.retryAfterMs / 1000))
29301
+ : undefined;
29302
+ const lowerMessage = (error.message || '').toLowerCase();
29303
+ let message;
29304
+ switch (error.status) {
29305
+ case 429: {
29306
+ const isPerUser = lowerMessage.includes('user');
29307
+ const base = isPerUser
29308
+ ? 'You have reached the per-user rate limit.'
29309
+ : 'This widget has received too many requests.';
29310
+ if (retryAfterSeconds) {
29311
+ message = `${base} Please wait ${retryAfterSeconds} second${retryAfterSeconds === 1 ? '' : 's'} before trying again.`;
29312
+ }
29313
+ else {
29314
+ message = `${base} Please wait a moment and try again.`;
29315
+ }
29316
+ break;
29317
+ }
29318
+ case 401:
29319
+ message = 'Authentication failed. Please refresh the page or verify your API key.';
29320
+ break;
29321
+ case 403:
29322
+ message = 'Access to this widget is restricted. Please contact the site owner if you believe this is an error.';
29323
+ break;
29324
+ case 404:
29325
+ if (lowerMessage.includes('not active')) {
29326
+ message = 'This widget is currently inactive. Please contact the site owner.';
29327
+ }
29328
+ else {
29329
+ message = 'We could not find this widget. It may have been removed.';
29330
+ }
29331
+ break;
29332
+ default:
29333
+ if (error.status >= 500) {
29334
+ message = 'The server encountered an error. Please try again shortly.';
29335
+ }
29336
+ else if (error.status > 0) {
29337
+ message = error.message || 'Something went wrong. Please try again.';
29338
+ }
29339
+ else {
29340
+ message = error.message || 'Unable to connect to the server. Please check your internet connection.';
29341
+ }
28220
29342
  }
28221
- // Check if action state indicates completion
28222
- const state = entry.action.state;
28223
- if (!state) {
28224
- return entry;
29343
+ return { message, retryAfterSeconds, status: error.status };
29344
+ }
29345
+ if (error instanceof Error) {
29346
+ const lower = error.message.toLowerCase();
29347
+ if (lower.includes('network')) {
29348
+ return { message: 'Unable to connect to the server. Please check your internet connection.' };
28225
29349
  }
28226
- // Link-preview: done if status is "displaying" or "clicked"
28227
- if (entry.action.implementation === "link-preview") {
28228
- const status = state.status;
28229
- if (status === "displaying" || status === "clicked") {
28230
- return {
28231
- ...entry,
28232
- action: { ...entry.action, done: true },
28233
- };
28234
- }
29350
+ if (lower.includes('timeout')) {
29351
+ return { message: 'The request timed out. Please try again.' };
28235
29352
  }
28236
- // Google Calendar: done if status indicates completion
28237
- if (entry.action.implementation === "google-calendar-appointment") {
28238
- const status = state.status;
28239
- if (status === "booked" || status === "cancelled" || status === "error") {
28240
- return {
28241
- ...entry,
28242
- action: { ...entry.action, done: true },
28243
- };
28244
- }
29353
+ if (lower.includes('unauthorized') || lower.includes('401')) {
29354
+ return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
28245
29355
  }
28246
- return entry;
28247
- });
28248
- }
28249
- function hydrateMessages(messages) {
28250
- return hydrateActionDoneStatus(hydrateActionContent(hydrateToolNames(messages)));
28251
- }
28252
- function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate) {
28253
- // Find all incomplete actions and register resume callbacks
28254
- for (const message of messages) {
28255
- if (message.action && !message.action.done) {
28256
- const toolCallId = message.action.toolCallId;
28257
- const toolName = message.message.name || message.toolExecuting || "tool";
28258
- registerActionResumeCallback(toolCallId, async (newState) => {
28259
- // When user interacts with the action after reload, continue the stream
28260
- try {
28261
- // Update the action message with the new state
28262
- setState(prev => ({
28263
- ...prev,
28264
- messages: prev.messages.map(m => m.action?.toolCallId === toolCallId
28265
- ? {
28266
- ...m,
28267
- action: m.action ? { ...m.action, state: newState } : undefined,
28268
- }
28269
- : m),
28270
- isTyping: true,
28271
- }));
28272
- const streamState = createStreamState();
28273
- // Continue the agent stream with the new state
28274
- for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
28275
- if (event.type === "done") {
28276
- finalizeToolMessage(streamState, setState, toolCallId, toolName);
28277
- streamState.sources = event.sources;
28278
- streamState.toolCallToActionId = event.tool_call_to_action_id;
28279
- finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
28280
- continue;
28281
- }
28282
- if (event.type === "error") {
28283
- const errorMessage = {
28284
- id: generateMessageId(),
28285
- message: {
28286
- role: "assistant",
28287
- content: "Sorry, an error occurred. Please try again later.",
28288
- },
28289
- timestamp: new Date().toISOString(),
28290
- sources: [],
28291
- isError: true,
28292
- };
28293
- upsertMessage(setState, errorMessage, false);
28294
- setState(prev => ({ ...prev, isTyping: false }));
28295
- return;
28296
- }
28297
- handleStreamEvent(event, streamState, onMessageUpdate, setState);
28298
- }
28299
- setState(prev => ({ ...prev, isTyping: false }));
28300
- }
28301
- catch (error) {
28302
- console.error("[Action Resume] Failed to continue stream:", error);
28303
- setState(prev => ({ ...prev, isTyping: false }));
28304
- }
28305
- });
29356
+ if (lower.includes('internal server error') || lower.includes('500')) {
29357
+ return { message: 'The server encountered an error. Please try again shortly.' };
28306
29358
  }
29359
+ return { message: error.message || 'Something went wrong. Please try again.' };
28307
29360
  }
29361
+ return { message: 'Something went wrong. Please try again.' };
28308
29362
  }
29363
+
28309
29364
  function createStreamState() {
28310
29365
  return {
28311
29366
  currentContent: "",
@@ -28314,6 +29369,7 @@ function createStreamState() {
28314
29369
  newMessageIds: new Set(),
28315
29370
  sources: [],
28316
29371
  toolCallToActionId: {},
29372
+ requestId: generateMessageId(),
28317
29373
  };
28318
29374
  }
28319
29375
  function upsertMessage(setState, message, isTyping) {
@@ -28349,15 +29405,40 @@ function finalizeStreamMessages(setState, messageIds, sources, toolCallToActionI
28349
29405
  return msg;
28350
29406
  }
28351
29407
  // Attach suggestions only to the last assistant message
28352
- if (index === lastAssistantIndex && suggestions && suggestions.length > 0) {
28353
- return { ...msg, sources, toolCallToActionId, suggestions };
28354
- }
28355
- return { ...msg, sources, toolCallToActionId };
29408
+ const withSuggestions = index === lastAssistantIndex && suggestions && suggestions.length > 0
29409
+ ? { suggestions }
29410
+ : {};
29411
+ return { ...msg, sources, toolCallToActionId, ...withSuggestions };
28356
29412
  }),
28357
29413
  isTyping: false,
28358
29414
  };
28359
29415
  });
28360
29416
  }
29417
+ function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
29418
+ setState(prev => {
29419
+ const messages = prev.messages.map((entry) => {
29420
+ const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
29421
+ if (!matchesToolCall) {
29422
+ return entry;
29423
+ }
29424
+ const existingName = entry.message.name || toolName;
29425
+ return {
29426
+ ...entry,
29427
+ message: {
29428
+ role: "tool",
29429
+ content: typeof entry.message.content === "string" ? entry.message.content : "",
29430
+ tool_call_id: toolCallId,
29431
+ name: existingName,
29432
+ },
29433
+ isStreaming: false,
29434
+ toolExecuting: existingName,
29435
+ };
29436
+ });
29437
+ return { ...prev, messages, isTyping: false, isLoading: false };
29438
+ });
29439
+ streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
29440
+ }
29441
+
28361
29442
  function handleContentEvent(event, streamState, onMessageUpdate, setState) {
28362
29443
  streamState.currentContent += event.content;
28363
29444
  const assistantMessage = {
@@ -28404,8 +29485,6 @@ function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
28404
29485
  }
28405
29486
  function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
28406
29487
  streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
28407
- // Update state and mark action as done in a single setState call
28408
- // Keep isTyping: true because the agent may continue generating content after tool completion
28409
29488
  setState(prev => {
28410
29489
  const messages = prev.messages.map((msg) => {
28411
29490
  const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
@@ -28413,7 +29492,27 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
28413
29492
  return msg;
28414
29493
  }
28415
29494
  const existingName = msg.message.name || event.tool_name;
28416
- return {
29495
+ let action = msg.action;
29496
+ if (event.action_id && event.implementation) {
29497
+ action = {
29498
+ ...action,
29499
+ implementation: event.implementation,
29500
+ toolCallId: event.tool_call_id,
29501
+ actionId: event.action_id,
29502
+ input: (event.input || {}),
29503
+ state: (event.state || {}),
29504
+ done: event.done,
29505
+ };
29506
+ }
29507
+ else if (action) {
29508
+ action = {
29509
+ ...action,
29510
+ input: event.input ? event.input : action.input,
29511
+ state: event.state ? event.state : action.state,
29512
+ done: event.done,
29513
+ };
29514
+ }
29515
+ const updatedMsg = {
28417
29516
  ...msg,
28418
29517
  message: {
28419
29518
  role: "tool",
@@ -28423,14 +29522,10 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
28423
29522
  },
28424
29523
  isStreaming: false,
28425
29524
  toolExecuting: existingName,
28426
- action: msg.action ? {
28427
- ...msg.action,
28428
- state: event.state || msg.action.state,
28429
- done: true, // Mark action as completed
28430
- } : undefined,
29525
+ action,
28431
29526
  };
29527
+ return updatedMsg;
28432
29528
  });
28433
- // Keep typing indicator visible - it will be hidden by done/finalizeStreamMessages
28434
29529
  return { ...prev, messages, isTyping: true, isLoading: false };
28435
29530
  });
28436
29531
  }
@@ -28462,34 +29557,6 @@ function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
28462
29557
  return { ...prev, messages, isTyping: true, isLoading: false };
28463
29558
  });
28464
29559
  }
28465
- function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
28466
- setState(prev => {
28467
- const messages = prev.messages.map((entry) => {
28468
- const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
28469
- if (!matchesToolCall) {
28470
- return entry;
28471
- }
28472
- const existingName = entry.message.name || toolName;
28473
- return {
28474
- ...entry,
28475
- message: {
28476
- role: "tool",
28477
- content: typeof entry.message.content === "string" ? entry.message.content : "",
28478
- tool_call_id: toolCallId,
28479
- name: existingName,
28480
- },
28481
- isStreaming: false,
28482
- toolExecuting: existingName,
28483
- action: entry.action ? {
28484
- ...entry.action,
28485
- done: true, // Mark action as completed
28486
- } : undefined,
28487
- };
28488
- });
28489
- return { ...prev, messages, isTyping: false, isLoading: false };
28490
- });
28491
- streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
28492
- }
28493
29560
  function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
28494
29561
  streamState.sources = event.sources;
28495
29562
  streamState.toolCallToActionId = event.tool_call_to_action_id;
@@ -28548,6 +29615,10 @@ function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
28548
29615
  console.warn('[Chat] Unknown event type:', event.type);
28549
29616
  }
28550
29617
  }
29618
+
29619
+ function isDismissedState(state) {
29620
+ return Boolean(state.__dismissed);
29621
+ }
28551
29622
  async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
28552
29623
  let pendingEvent = initialEvent;
28553
29624
  while (pendingEvent) {
@@ -28574,7 +29645,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28574
29645
  actionId: pendingEvent.action_id,
28575
29646
  input: pendingEvent.input,
28576
29647
  state: pendingEvent.state,
28577
- done: false, // Action not yet completed
29648
+ done: pendingEvent.done ?? false,
28578
29649
  },
28579
29650
  };
28580
29651
  if (streamState.activeToolCallCount === 0) {
@@ -28588,7 +29659,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28588
29659
  id: generateMessageId(),
28589
29660
  message: {
28590
29661
  role: "assistant",
28591
- content: "Sorry, an error occurred. Please try again later.",
29662
+ content: "Sorry, an error occurred.",
28592
29663
  },
28593
29664
  timestamp: new Date().toISOString(),
28594
29665
  sources: [],
@@ -28612,7 +29683,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28612
29683
  console.error("[Widget] Frontend action failed:", error);
28613
29684
  const errorMessageEntry = {
28614
29685
  id: generateMessageId(),
28615
- message: { role: "assistant", content: "Sorry, an error occurred. Please try again later." },
29686
+ message: { role: "assistant", content: "Sorry, an error occurred." },
28616
29687
  timestamp: new Date().toISOString(),
28617
29688
  sources: [],
28618
29689
  isError: true,
@@ -28622,16 +29693,17 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28622
29693
  return;
28623
29694
  }
28624
29695
  pendingEvent = null;
28625
- const updatedToolMessage = {
28626
- ...toolMessage,
28627
- action: toolMessage.action
28628
- ? {
28629
- ...toolMessage.action,
28630
- state: nextState,
28631
- }
28632
- : undefined,
28633
- };
28634
- upsertMessage(setState, updatedToolMessage, true);
29696
+ const dismissed = isDismissedState(nextState);
29697
+ if (!dismissed) {
29698
+ const updatedToolMessage = {
29699
+ ...toolMessage,
29700
+ action: toolMessage.action ? { ...toolMessage.action, state: nextState } : toolMessage.action,
29701
+ };
29702
+ upsertMessage(setState, updatedToolMessage, true);
29703
+ }
29704
+ if (dismissed) {
29705
+ return;
29706
+ }
28635
29707
  let streamEnded = false;
28636
29708
  for await (const event of client.continueAgentMessageStream(conversationId, resumeToolCallId, nextState)) {
28637
29709
  if (event.type === "action_request") {
@@ -28639,22 +29711,20 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28639
29711
  break;
28640
29712
  }
28641
29713
  if (event.type === "done") {
28642
- // Don't extract and update state from done event - the state was already
28643
- // updated by tool_end event or by the user's frontend action.
29714
+ // Finalize tool message and stream messages
28644
29715
  finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
28645
- // Handle the done event but skip the tool finalization part since we already did it
28646
29716
  streamState.sources = event.sources;
28647
29717
  streamState.toolCallToActionId = event.tool_call_to_action_id;
28648
29718
  finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
28649
29719
  streamEnded = true;
28650
- continue; // Skip handleStreamEvent for done events to avoid state conflicts
29720
+ continue;
28651
29721
  }
28652
29722
  if (event.type === "error") {
28653
29723
  const errorMessage = {
28654
29724
  id: generateMessageId(),
28655
29725
  message: {
28656
29726
  role: "assistant",
28657
- content: "Sorry, an error occurred. Please try again later.",
29727
+ content: "Sorry, an error occurred.",
28658
29728
  },
28659
29729
  timestamp: new Date().toISOString(),
28660
29730
  sources: [],
@@ -28665,73 +29735,83 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28665
29735
  }
28666
29736
  handleStreamEvent(event, streamState, onMessageUpdate, setState);
28667
29737
  }
28668
- // If stream ended without a done event (e.g., only tool_end was sent), finalize the tool message
29738
+ // If stream ended without a done event, finalize the tool message
28669
29739
  if (!streamEnded && !pendingEvent) {
28670
29740
  finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
28671
29741
  }
28672
29742
  }
28673
29743
  }
28674
- function deriveErrorInfo(error) {
28675
- if (error instanceof ApiError) {
28676
- const retryAfterSeconds = typeof error.retryAfterMs === 'number'
28677
- ? Math.max(1, Math.ceil(error.retryAfterMs / 1000))
28678
- : undefined;
28679
- const lowerMessage = (error.message || '').toLowerCase();
28680
- let message;
28681
- switch (error.status) {
28682
- case 429: {
28683
- const isPerUser = lowerMessage.includes('user');
28684
- const base = isPerUser
28685
- ? 'You have reached the per-user rate limit.'
28686
- : 'This widget has received too many requests.';
28687
- if (retryAfterSeconds) {
28688
- message = `${base} Please wait ${retryAfterSeconds} second${retryAfterSeconds === 1 ? '' : 's'} before trying again.`;
28689
- }
28690
- else {
28691
- message = `${base} Please wait a moment and try again.`;
28692
- }
28693
- break;
28694
- }
28695
- case 401:
28696
- message = 'Authentication failed. Please refresh the page or verify your API key.';
28697
- break;
28698
- case 403:
28699
- message = 'Access to this widget is restricted. Please contact the site owner if you believe this is an error.';
28700
- break;
28701
- case 404:
28702
- message = 'We could not find this widget. It may have been removed.';
28703
- break;
28704
- default:
28705
- if (error.status >= 500) {
28706
- message = 'The server encountered an error. Please try again shortly.';
28707
- }
28708
- else if (error.status > 0) {
28709
- message = error.message || 'Something went wrong. Please try again.';
29744
+ function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate, createStreamState, registerCallback) {
29745
+ // Find all incomplete actions and register resume callbacks
29746
+ for (const message of messages) {
29747
+ if (message.action && !message.action.done && !message.action.hidden) {
29748
+ const toolCallId = message.action.toolCallId;
29749
+ const toolName = message.message.name || message.toolExecuting || "tool";
29750
+ registerCallback(toolCallId, async (newState) => {
29751
+ // When user interacts with the action after reload, continue the stream
29752
+ try {
29753
+ // Update the action message with the new state and check completion
29754
+ if (isDismissedState(newState)) {
29755
+ setState(prev => ({ ...prev, isTyping: false }));
29756
+ return;
29757
+ }
29758
+ setState(prev => ({
29759
+ ...prev,
29760
+ messages: prev.messages.map(m => {
29761
+ if (m.action?.toolCallId !== toolCallId) {
29762
+ return m;
29763
+ }
29764
+ if (!m.action) {
29765
+ return m;
29766
+ }
29767
+ return { ...m, action: { ...m.action, state: newState } };
29768
+ }),
29769
+ isTyping: true,
29770
+ }));
29771
+ const streamState = createStreamState();
29772
+ // Continue the agent stream with the new state
29773
+ for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
29774
+ if (event.type === "done") {
29775
+ finalizeToolMessage(streamState, setState, toolCallId, toolName);
29776
+ streamState.sources = event.sources;
29777
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
29778
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
29779
+ continue;
29780
+ }
29781
+ if (event.type === "error") {
29782
+ const errorMessage = {
29783
+ id: generateMessageId(),
29784
+ message: {
29785
+ role: "assistant",
29786
+ content: "Sorry, an error occurred. Please try again later.",
29787
+ },
29788
+ timestamp: new Date().toISOString(),
29789
+ sources: [],
29790
+ isError: true,
29791
+ };
29792
+ upsertMessage(setState, errorMessage, false);
29793
+ setState(prev => ({ ...prev, isTyping: false }));
29794
+ return;
29795
+ }
29796
+ handleStreamEvent(event, streamState, onMessageUpdate, setState);
29797
+ }
29798
+ setState(prev => ({ ...prev, isTyping: false }));
28710
29799
  }
28711
- else {
28712
- message = error.message || 'Unable to connect to the server. Please check your internet connection.';
29800
+ catch (error) {
29801
+ console.error("[Action Resume] Failed to continue stream:", error);
29802
+ setState(prev => ({ ...prev, isTyping: false }));
28713
29803
  }
29804
+ });
28714
29805
  }
28715
- return { message, retryAfterSeconds, status: error.status };
28716
- }
28717
- if (error instanceof Error) {
28718
- const lower = error.message.toLowerCase();
28719
- if (lower.includes('network')) {
28720
- return { message: 'Unable to connect to the server. Please check your internet connection.' };
28721
- }
28722
- if (lower.includes('timeout')) {
28723
- return { message: 'The request timed out. Please try again.' };
28724
- }
28725
- if (lower.includes('unauthorized') || lower.includes('401')) {
28726
- return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
28727
- }
28728
- if (lower.includes('internal server error') || lower.includes('500')) {
28729
- return { message: 'The server encountered an error. Please try again shortly.' };
28730
- }
28731
- return { message: error.message || 'Something went wrong. Please try again.' };
28732
29806
  }
28733
- return { message: 'Something went wrong. Please try again.' };
28734
29807
  }
29808
+
29809
+ /**
29810
+ * useChat Hook
29811
+ * Main state management for chat functionality
29812
+ */
29813
+ // Initialize action handlers immediately to prevent tree-shaking
29814
+ initializeActionHandlers();
28735
29815
  function useChat(options) {
28736
29816
  const { widgetId, apiUrl, currentRoute, onMessage, onError, skipInitialization = false, } = options;
28737
29817
  const [state, setState] = useState({
@@ -28740,27 +29820,24 @@ function useChat(options) {
28740
29820
  isLoading: false,
28741
29821
  isTyping: false,
28742
29822
  error: null,
28743
- conversationId: '', // Will be set after loading conversation
29823
+ conversationId: '',
28744
29824
  config: null,
28745
29825
  });
28746
29826
  const stateRef = useRef(state);
28747
29827
  useEffect(() => {
28748
29828
  stateRef.current = state;
28749
29829
  }, [state]);
28750
- // Chat history state
28751
29830
  const [conversations, setConversations] = useState([]);
28752
- // Stream cancellation and rate limiting
28753
29831
  const abortControllerRef = useRef(null);
29832
+ const currentRequestIdRef = useRef(null);
28754
29833
  const lastNewChatTimeRef = useRef(0);
28755
- const NEW_CHAT_COOLDOWN_MS = 5000; // 2 second cooldown between new chats
29834
+ const NEW_CHAT_COOLDOWN_MS = 5000;
28756
29835
  const apiClient = useRef(new WidgetApiClient({ widgetId, apiUrl, currentRoute }));
28757
- // Update API client when currentRoute changes
28758
29836
  useEffect(() => {
28759
29837
  apiClient.current = new WidgetApiClient({ widgetId, apiUrl, currentRoute });
28760
29838
  }, [widgetId, apiUrl, currentRoute]);
28761
29839
  // Load configuration on mount and hydrate with existing conversation if available
28762
29840
  useEffect(() => {
28763
- // Skip initialization in preview mode
28764
29841
  if (skipInitialization) {
28765
29842
  return;
28766
29843
  }
@@ -28797,7 +29874,7 @@ function useChat(options) {
28797
29874
  }));
28798
29875
  // Setup resume callbacks for incomplete actions
28799
29876
  if (conversationId) {
28800
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }));
29877
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
28801
29878
  }
28802
29879
  }
28803
29880
  catch (error) {
@@ -28814,14 +29891,13 @@ function useChat(options) {
28814
29891
  initialize();
28815
29892
  return () => {
28816
29893
  isMounted = false;
28817
- // Cleanup resume callbacks
28818
29894
  state.messages.forEach(message => {
28819
29895
  if (message.action?.toolCallId) {
28820
29896
  unregisterActionResumeCallback(message.action.toolCallId);
28821
29897
  }
28822
29898
  });
28823
29899
  };
28824
- }, [widgetId, apiUrl, onError]);
29900
+ }, [widgetId, apiUrl, onError, skipInitialization]);
28825
29901
  // Save conversation when messages change
28826
29902
  useEffect(() => {
28827
29903
  const persistConversation = state.config?.settings.persistConversation ?? true;
@@ -28837,19 +29913,15 @@ function useChat(options) {
28837
29913
  const hasFiles = !!files && files.length > 0;
28838
29914
  if (!trimmedContent && !hasFiles)
28839
29915
  return;
28840
- // Block parallel streams - don't allow sending while already streaming
28841
29916
  if (stateRef.current.isTyping) {
28842
29917
  console.warn('[Widget] Cannot send message while streaming is in progress');
28843
29918
  return;
28844
29919
  }
28845
- // Cancel any existing stream before starting new one
28846
29920
  if (abortControllerRef.current) {
28847
29921
  abortControllerRef.current.abort();
28848
29922
  abortControllerRef.current = null;
28849
29923
  }
28850
- // Create new abort controller for this stream
28851
29924
  abortControllerRef.current = new AbortController();
28852
- // Strip [EXECUTE_ACTION:...] prefix from displayed message (but keep for API)
28853
29925
  const displayContent = trimmedContent.replace(/^\[EXECUTE_ACTION:[^\]]+\]\s*/, '');
28854
29926
  const userMessage = {
28855
29927
  id: generateMessageId(),
@@ -28860,12 +29932,11 @@ function useChat(options) {
28860
29932
  timestamp: new Date().toISOString(),
28861
29933
  sources: [],
28862
29934
  };
28863
- // Add user message immediately
28864
29935
  setState(prev => ({
28865
29936
  ...prev,
28866
29937
  messages: [...prev.messages, userMessage],
28867
- isLoading: false, // Don't show loading, will show typing when stream starts
28868
- isTyping: true, // Show typing indicator immediately
29938
+ isLoading: false,
29939
+ isTyping: true,
28869
29940
  error: null,
28870
29941
  }));
28871
29942
  onMessage?.(userMessage);
@@ -28905,26 +29976,27 @@ function useChat(options) {
28905
29976
  }
28906
29977
  catch (uploadError) {
28907
29978
  console.error('Failed to upload file:', uploadError);
28908
- // Continue with other files
28909
29979
  }
28910
29980
  }
28911
29981
  }
28912
- // Stream the response
28913
29982
  let lastStreamedMessage = null;
28914
29983
  const streamState = createStreamState();
28915
- // Capture the abort controller and conversation ID for this specific stream
29984
+ currentRequestIdRef.current = streamState.requestId;
28916
29985
  const currentAbortController = abortControllerRef.current;
28917
29986
  const streamConversationId = conversationId;
28918
- const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds);
29987
+ const streamRequestId = streamState.requestId;
29988
+ const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds, currentAbortController?.signal);
28919
29989
  for await (const event of stream) {
28920
- // Check if stream was aborted or conversation changed
28921
- if (currentAbortController?.signal.aborted || stateRef.current.conversationId !== streamConversationId) {
28922
- console.log('[Widget] Stream aborted or conversation changed, stopping event processing');
29990
+ if (currentAbortController?.signal.aborted ||
29991
+ stateRef.current.conversationId !== streamConversationId ||
29992
+ currentRequestIdRef.current !== streamRequestId) {
29993
+ console.log('[Widget] Stream aborted, conversation changed, or superseded by new request');
28923
29994
  break;
28924
29995
  }
28925
29996
  if (event.type === "action_request") {
28926
- // Check again before expensive operation
28927
- if (currentAbortController?.signal.aborted || stateRef.current.conversationId !== streamConversationId) {
29997
+ if (currentAbortController?.signal.aborted ||
29998
+ stateRef.current.conversationId !== streamConversationId ||
29999
+ currentRequestIdRef.current !== streamRequestId) {
28928
30000
  break;
28929
30001
  }
28930
30002
  await handleActionLoop(apiClient.current, event, streamState, (message) => {
@@ -28936,30 +30008,26 @@ function useChat(options) {
28936
30008
  lastStreamedMessage = message;
28937
30009
  }, setState);
28938
30010
  }
28939
- // Only finalize if this stream wasn't aborted
28940
- if (currentAbortController?.signal.aborted || stateRef.current.conversationId !== streamConversationId) {
28941
- console.log('[Widget] Stream was aborted, skipping finalization');
30011
+ if (currentAbortController?.signal.aborted ||
30012
+ stateRef.current.conversationId !== streamConversationId ||
30013
+ currentRequestIdRef.current !== streamRequestId) {
30014
+ console.log('[Widget] Stream was aborted or superseded, skipping finalization');
28942
30015
  return;
28943
30016
  }
28944
- // Stream completed - finalize state
28945
30017
  setState(prev => ({
28946
30018
  ...prev,
28947
30019
  isLoading: false,
28948
30020
  isTyping: false,
28949
30021
  }));
28950
- // Notify about final message
28951
30022
  if (lastStreamedMessage) {
28952
30023
  onMessage?.(lastStreamedMessage);
28953
30024
  }
28954
- // Generate follow-up suggestions asynchronously
28955
30025
  const enableFollowUps = state.config?.settings.enableFollowUpSuggestions !== false;
28956
30026
  const actionIds = state.config?.actions || [];
28957
30027
  if (enableFollowUps) {
28958
- // Don't await - let it run in background
28959
30028
  apiClient.current.generateFollowUps(stateRef.current.messages, actionIds)
28960
30029
  .then(suggestions => {
28961
30030
  if (suggestions.length > 0) {
28962
- // Attach suggestions to the last assistant message
28963
30031
  setState(prev => {
28964
30032
  const messages = [...prev.messages];
28965
30033
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -28988,7 +30056,7 @@ function useChat(options) {
28988
30056
  },
28989
30057
  timestamp: new Date().toISOString(),
28990
30058
  sources: [],
28991
- isError: !fallbackMessage, // Only mark as error if using default message
30059
+ isError: !fallbackMessage,
28992
30060
  };
28993
30061
  setState(prev => ({
28994
30062
  ...prev,
@@ -29000,9 +30068,6 @@ function useChat(options) {
29000
30068
  onError?.(err);
29001
30069
  }
29002
30070
  }, [state.conversationId, state.config, state.messages, onMessage, onError]);
29003
- /**
29004
- * Clear all messages
29005
- */
29006
30071
  const clearMessages = useCallback(() => {
29007
30072
  setState(prev => ({
29008
30073
  ...prev,
@@ -29015,9 +30080,6 @@ function useChat(options) {
29015
30080
  clearConversation(widgetId);
29016
30081
  }
29017
30082
  }, [widgetId, state.config?.settings.persistConversation]);
29018
- /**
29019
- * Submit feedback for a message
29020
- */
29021
30083
  const submitFeedback = useCallback(async (messageId, feedback) => {
29022
30084
  try {
29023
30085
  const message = state.messages.find(msg => msg.id === messageId);
@@ -29027,7 +30089,6 @@ function useChat(options) {
29027
30089
  : undefined;
29028
30090
  console.log('Submitting feedback:', { conversationId: state.conversationId, messageId, feedback });
29029
30091
  await apiClient.current.submitFeedback(state.conversationId, messageId, feedback, meta);
29030
- // Update message with feedback
29031
30092
  setState(prev => ({
29032
30093
  ...prev,
29033
30094
  messages: prev.messages.map(msg => msg.id === messageId
@@ -29042,9 +30103,51 @@ function useChat(options) {
29042
30103
  onError?.(err);
29043
30104
  }
29044
30105
  }, [state.conversationId, onError]);
29045
- /**
29046
- * Load conversation history list from localStorage
29047
- */
30106
+ const dismissAction = useCallback(async (toolCallId) => {
30107
+ if (!toolCallId)
30108
+ return;
30109
+ const dismissedAt = new Date().toISOString();
30110
+ setState(prev => ({
30111
+ ...prev,
30112
+ messages: prev.messages.map((message) => {
30113
+ if (message.action?.toolCallId !== toolCallId) {
30114
+ return message;
30115
+ }
30116
+ if (!message.action) {
30117
+ return message;
30118
+ }
30119
+ return {
30120
+ ...message,
30121
+ action: {
30122
+ ...message.action,
30123
+ hidden: true,
30124
+ dismissedAt,
30125
+ dismissedBy: "user",
30126
+ done: true,
30127
+ },
30128
+ };
30129
+ }),
30130
+ isTyping: true,
30131
+ isLoading: false,
30132
+ }));
30133
+ unregisterActionResumeCallback(toolCallId);
30134
+ const conversationId = stateRef.current.conversationId;
30135
+ if (!conversationId) {
30136
+ setState(prev => ({ ...prev, isTyping: false }));
30137
+ return;
30138
+ }
30139
+ try {
30140
+ const streamState = createStreamState();
30141
+ for await (const event of apiClient.current.dismissAgentMessageStream(conversationId, toolCallId)) {
30142
+ handleStreamEvent(event, streamState, onMessage ?? (() => { }), setState);
30143
+ }
30144
+ setState(prev => ({ ...prev, isTyping: false, isLoading: false }));
30145
+ }
30146
+ catch (error) {
30147
+ console.error("[Widget] dismissAction error:", error);
30148
+ setState(prev => ({ ...prev, isTyping: false, isLoading: false }));
30149
+ }
30150
+ }, [onMessage]);
29048
30151
  const loadConversations = useCallback(() => {
29049
30152
  const persistConversation = state.config?.settings.persistConversation ?? true;
29050
30153
  if (!persistConversation || !isStorageAvailable()) {
@@ -29061,13 +30164,11 @@ function useChat(options) {
29061
30164
  })));
29062
30165
  }, [widgetId, state.config?.settings.persistConversation]);
29063
30166
  const switchConversation = useCallback(async (conversationId) => {
29064
- // Cancel any active stream before switching conversations
29065
30167
  if (abortControllerRef.current) {
29066
30168
  abortControllerRef.current.abort();
29067
30169
  abortControllerRef.current = null;
29068
30170
  }
29069
30171
  const persistConversation = state.config?.settings.persistConversation ?? true;
29070
- // First try to load from localStorage
29071
30172
  if (persistConversation && isStorageAvailable()) {
29072
30173
  const stored = loadConversationById(widgetId, conversationId);
29073
30174
  if (stored) {
@@ -29086,7 +30187,6 @@ function useChat(options) {
29086
30187
  try {
29087
30188
  const conversation = await apiClient.current.getOrCreateConversation(conversationId);
29088
30189
  const hydratedMessages = hydrateMessages(conversation.messages);
29089
- // Clear old resume callbacks
29090
30190
  state.messages.forEach(message => {
29091
30191
  if (message.action?.toolCallId) {
29092
30192
  unregisterActionResumeCallback(message.action.toolCallId);
@@ -29098,9 +30198,7 @@ function useChat(options) {
29098
30198
  messages: hydratedMessages,
29099
30199
  isLoading: false,
29100
30200
  }));
29101
- // Setup new resume callbacks
29102
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }));
29103
- // Save to local storage
30201
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
29104
30202
  if (persistConversation && isStorageAvailable()) {
29105
30203
  saveConversation(widgetId, conversation.id, hydratedMessages);
29106
30204
  }
@@ -29111,19 +30209,16 @@ function useChat(options) {
29111
30209
  }
29112
30210
  }, [widgetId, state.config?.settings.persistConversation]);
29113
30211
  const startNewConversation = useCallback(() => {
29114
- // Rate limiting - prevent spamming new chats
29115
30212
  const now = Date.now();
29116
30213
  if (now - lastNewChatTimeRef.current < NEW_CHAT_COOLDOWN_MS) {
29117
30214
  console.warn('[Widget] New chat rate limited - please wait');
29118
30215
  return;
29119
30216
  }
29120
30217
  lastNewChatTimeRef.current = now;
29121
- // Cancel any active stream before starting new conversation
29122
30218
  if (abortControllerRef.current) {
29123
30219
  abortControllerRef.current.abort();
29124
30220
  abortControllerRef.current = null;
29125
30221
  }
29126
- // Reset typing state if stream was active
29127
30222
  setState(prev => ({
29128
30223
  ...prev,
29129
30224
  messages: [],
@@ -29142,11 +30237,8 @@ function useChat(options) {
29142
30237
  if (!persistConversation || !isStorageAvailable()) {
29143
30238
  return;
29144
30239
  }
29145
- // Delete from storage
29146
30240
  deleteConversation(widgetId, conversationId);
29147
- // Update local state
29148
30241
  setConversations(prev => prev.filter(c => c.id !== conversationId));
29149
- // If we deleted the current conversation, clear it
29150
30242
  if (state.conversationId === conversationId) {
29151
30243
  setState(prev => ({
29152
30244
  ...prev,
@@ -29156,6 +30248,43 @@ function useChat(options) {
29156
30248
  }));
29157
30249
  }
29158
30250
  }, [widgetId, state.config?.settings.persistConversation, state.conversationId]);
30251
+ const createDemoConversation = useCallback(async (userMessage, assistantMessage) => {
30252
+ try {
30253
+ const result = await apiClient.current.createDemoConversation(userMessage, assistantMessage);
30254
+ if (result.success && result.id) {
30255
+ // Update state with the new conversation ID
30256
+ setState(prev => ({
30257
+ ...prev,
30258
+ conversationId: result.id,
30259
+ }));
30260
+ // Save to local storage if persistence is enabled
30261
+ const persistConversation = state.config?.settings.persistConversation ?? true;
30262
+ if (persistConversation && isStorageAvailable()) {
30263
+ const demoMessages = [
30264
+ {
30265
+ id: generateMessageId(),
30266
+ message: { role: 'user', content: userMessage },
30267
+ timestamp: new Date().toISOString(),
30268
+ sources: [],
30269
+ },
30270
+ {
30271
+ id: generateMessageId(),
30272
+ message: { role: 'assistant', content: assistantMessage },
30273
+ timestamp: new Date(Date.now() + 1000).toISOString(),
30274
+ sources: [],
30275
+ },
30276
+ ];
30277
+ saveConversation(widgetId, result.id, demoMessages);
30278
+ }
30279
+ return result.id;
30280
+ }
30281
+ return null;
30282
+ }
30283
+ catch (error) {
30284
+ console.error('[useChat] Failed to create demo conversation:', error);
30285
+ return null;
30286
+ }
30287
+ }, [widgetId, state.config?.settings.persistConversation]);
29159
30288
  return {
29160
30289
  messages: state.messages,
29161
30290
  isLoading: state.isLoading,
@@ -29166,20 +30295,29 @@ function useChat(options) {
29166
30295
  sendMessage,
29167
30296
  clearMessages,
29168
30297
  submitFeedback,
29169
- // Chat history features
30298
+ dismissAction,
29170
30299
  conversations,
29171
30300
  loadConversations,
29172
30301
  switchConversation,
29173
30302
  startNewConversation,
29174
30303
  deleteConversation: deleteConversation$1,
30304
+ createDemoConversation,
29175
30305
  };
29176
30306
  }
29177
30307
 
30308
+ const DataPolicyView = ({ config, widgetName, }) => {
30309
+ const headerTitle = widgetName || config?.appearance?.headerTitle || 'AI Assistant';
30310
+ const hasFileUpload = config?.settings?.enableFileUpload ?? false;
30311
+ const persistsConversation = config?.settings?.persistConversation ?? true;
30312
+ return (jsx("div", { className: "ai-chat-data-policy-view", children: jsxs("div", { className: "ai-chat-data-policy-content", children: [jsx("div", { className: "ai-chat-data-policy-intro", children: jsxs("p", { children: ["This privacy notice informs you pursuant to Art. 13 GDPR about how ", jsx("strong", { children: headerTitle }), " processes data when you use this chat. Please note that the specific scope of processing depends on the operator of this website/application (the controller) and on the respective activated functions."] }) }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Controller / Contact" }), jsx("p", { children: "The controller within the meaning of Art. 4 No. 7 GDPR is the operator of this website/application. The contact details (and, if applicable, the contact details of a data protection officer) can be found in the privacy policy or in the legal notice of the website into which this chat widget is embedded." })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Processed Data" }), jsxs("p", { children: ["The chat processes the following categories of data. ", jsx("strong", { children: "Chat Content" }), " comprises messages (text) and, if applicable, context information that you provide in the chat. This content is processed to generate responses and provide the conversation."] }), hasFileUpload && (jsxs("p", { children: [jsx("strong", { children: "Uploaded Files" }), " that you transmit to the chat are processed to handle your request. Processing may include extracting text or information."] })), jsxs("p", { children: [jsx("strong", { children: "Technical Usage Data" }), " includes timestamps, session or request information, as well as technical metadata required for operation, security (abuse prevention), and error analysis."] }), jsx("p", { children: "Please do not enter special categories of personal data (e.g., health data), passwords, credit card or bank data, or confidential business secrets in the chat. AI-generated responses may be inaccurate and should be checked independently before use." })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Purposes and Legal Bases" }), jsxs("p", { children: [jsx("strong", { children: "Provision of the chat and answering of inquiries" }), " is based on Art. 6 Para. 1 lit. b GDPR, insofar as contractual or pre-contractual measures apply; otherwise on Art. 6 Para. 1 lit. f GDPR (legitimate interest in efficient communication and support)."] }), jsxs("p", { children: [jsx("strong", { children: "Quality assurance, operation and security" }), " are based on Art. 6 Para. 1 lit. f GDPR, for example for stability, abuse detection, and troubleshooting."] }), jsxs("p", { children: [jsx("strong", { children: "Consent-based processing" }), " may occur if the operator provides for this (Art. 6 Para. 1 lit. a GDPR)."] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Recipients and Processors" }), jsxs("p", { children: [jsx("strong", { children: "Hosting/IT Service Providers" }), " may be used by the operator for hosting, logging, monitoring, and infrastructure."] }), jsxs("p", { children: [jsx("strong", { children: "AI Service Providers" }), " may receive chat content to generate responses. Where required, this is done on the basis of a data processing agreement (Art. 28 GDPR)."] }), jsxs("p", { children: [jsx("strong", { children: "Third-Country Transfer" }), " may occur if recipients are located outside the EU/EEA. In this case, appropriate safeguards (e.g., EU Standard Contractual Clauses) are used where required."] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Retention Period" }), persistsConversation ? (jsxs("p", { children: [jsx("strong", { children: "Chat History" }), " may be stored to continue the conversation across multiple sessions."] })) : (jsxs("p", { children: [jsx("strong", { children: "Chat History" }), " is not permanently stored and ends when the chat is closed."] })), hasFileUpload && (jsxs("p", { children: [jsx("strong", { children: "Files" }), " are processed only as long as necessary to handle the request and are then deleted, unless longer retention is legally required."] })), jsxs("p", { children: [jsx("strong", { children: "Technical Logs" }), " may be stored for a limited period to ensure secure operation."] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Your Rights (Data Subject Rights)" }), jsx("p", { children: "You have the following rights under the GDPR: Right to Information (Art. 15), Right to Rectification (Art. 16), Right to Erasure (Art. 17) and Restriction of Processing (Art. 18), Right to Data Portability (Art. 20), Right to Objection to processing based on legitimate interests (Art. 21), and Right to Complain to a supervisory authority (Art. 77)." }), jsx("p", { children: "Note: Without clear identification features, the operator may not be able to assign individual chat histories to a person. For inquiries, please contact the operator of this website/application." })] })] }) }));
30313
+ };
30314
+
29178
30315
  const MenuIcon = () => (jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "4", y1: "10", x2: "20", y2: "10" }), jsx("line", { x1: "10", y1: "14", x2: "20", y2: "14" })] }));
29179
30316
  const PlusIcon = () => (jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })] }));
29180
30317
  const TrashIcon = () => (jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M3 6h18" }), jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }), jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })] }));
29181
30318
  const CloseIcon = () => (jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }));
29182
- const ChatWindow = ({ messages, isLoading, isTyping, error, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick,
30319
+ const BackIcon = () => (jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M19 12H5" }), jsx("path", { d: "M12 19l-7-7 7-7" })] }));
30320
+ const ChatWindow = ({ messages, isLoading, isTyping, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick, onActionDismiss,
29183
30321
  // Chat history props (only active when persistConversation is true)
29184
30322
  conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
29185
30323
  // Override props for live preview
@@ -29196,6 +30334,8 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
29196
30334
  const inputPlaceholder = placeholderOverride ?? appearance?.placeholder ?? 'Ask me anything...';
29197
30335
  // Track if history panel is open
29198
30336
  const [showHistory, setShowHistory] = useState(false);
30337
+ // Track if data policy view is open
30338
+ const [showDataPolicy, setShowDataPolicy] = useState(false);
29199
30339
  // Scroll button state (managed by MessageList)
29200
30340
  const [showScrollButton, setShowScrollButton] = useState(false);
29201
30341
  const [scrollToBottom, setScrollToBottom] = useState(null);
@@ -29205,6 +30345,13 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
29205
30345
  }, []);
29206
30346
  // History exit animation when starting a new chat from overview
29207
30347
  const [isHistoryExiting, setIsHistoryExiting] = useState(false);
30348
+ // Handle data policy click
30349
+ const handleDataPolicyClick = useCallback(() => {
30350
+ setShowDataPolicy(true);
30351
+ }, []);
30352
+ const handleDataPolicyBack = useCallback(() => {
30353
+ setShowDataPolicy(false);
30354
+ }, []);
29208
30355
  // Load conversations when history panel opens
29209
30356
  const handleOpenHistory = () => {
29210
30357
  setShowHistory(true);
@@ -29252,10 +30399,22 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
29252
30399
  // The backend will detect and trigger the action based on the message
29253
30400
  onSendMessage(question);
29254
30401
  };
29255
- return (jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''}`, children: showHistory ? (jsxs(Fragment, { children: [jsx("div", { className: "ai-chat-title", children: headerTitle }), jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsx(PlusIcon, {}) })] })) : (jsxs(Fragment, { children: [jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxs("div", { className: "ai-chat-header-actions", children: [canShowHistory && (jsx("button", { className: "ai-chat-header-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsx(MenuIcon, {}) })), jsx("button", { className: "ai-chat-close-button header-close-button", onClick: _onClose, "aria-label": "Close chat", children: jsx(CloseIcon, {}) })] })] })) }), showHistory ? (jsxs("div", { className: "ai-chat-history-panel", children: [conversations.length === 0 ? (jsx("div", { className: "ai-chat-history-empty", children: "No previous conversations" })) : (jsx("div", { className: `ai-chat-history-list ${isHistoryExiting ? 'exiting' : ''}`, children: conversations.map((conv) => (jsx("div", { className: `ai-chat-history-item ${conv.id === currentConversationId ? 'active' : ''}`, onClick: () => handleSelectConversation(conv.id), children: jsxs("div", { className: "ai-chat-history-item-content", children: [jsx("div", { className: "ai-chat-history-item-preview", children: conv.preview }), onDeleteConversation && (jsx("button", { className: "ai-chat-history-item-delete", onClick: (e) => {
30402
+ return (jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''} ${showDataPolicy ? 'is-data-policy' : ''}`, children: showDataPolicy ? (jsxs(Fragment, { children: [jsx("button", { className: "ai-chat-header-button", onClick: handleDataPolicyBack, "aria-label": "Back to chat", children: jsx(BackIcon, {}) }), jsx("div", { className: "ai-chat-title", children: "Privacy Notice" })] })) : showHistory ? (jsxs(Fragment, { children: [jsx("div", { className: "ai-chat-title", children: headerTitle }), jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsx(PlusIcon, {}) })] })) : (jsxs(Fragment, { children: [jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxs("div", { className: "ai-chat-header-actions", children: [canShowHistory && (jsx("button", { className: "ai-chat-header-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsx(MenuIcon, {}) })), jsx("button", { className: "ai-chat-close-button header-close-button", onClick: _onClose, "aria-label": "Close chat", children: jsx(CloseIcon, {}) })] })] })) }), showDataPolicy ? (jsx(DataPolicyView, { config: config, onBack: handleDataPolicyBack, widgetName: headerTitle })) : showHistory ? (
30403
+ /* History Panel */
30404
+ jsxs("div", { className: "ai-chat-history-panel", children: [conversations.length === 0 ? (jsx("div", { className: "ai-chat-history-empty", children: "No previous conversations" })) : (jsx("div", { className: `ai-chat-history-list ${isHistoryExiting ? 'exiting' : ''}`, children: conversations.map((conv) => (jsx("div", { className: `ai-chat-history-item ${conv.id === currentConversationId ? 'active' : ''}`, onClick: () => handleSelectConversation(conv.id), children: jsxs("div", { className: "ai-chat-history-item-content", children: [jsx("div", { className: "ai-chat-history-item-preview", children: conv.preview }), onDeleteConversation && (jsx("button", { className: "ai-chat-history-item-delete", onClick: (e) => {
29256
30405
  e.stopPropagation();
29257
30406
  onDeleteConversation(conv.id);
29258
- }, "aria-label": "Delete conversation", children: jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload })] })) : (jsxs(Fragment, { children: [error && (jsx("div", { className: "ai-chat-error", role: "alert", children: error })), maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), jsx(MessageList, { messages: messages, isTyping: isTyping, showTypingIndicator: settings?.showTypingIndicator, showTimestamps: settings?.showTimestamps, showToolCalls: settings?.showToolCalls, enableFeedback: settings?.enableFeedback, welcomeTitle: welcomeTitle || 'Welcome Message', welcomeMessage: welcomeMessage, suggestedQuestions: suggestedQuestionsOverride ?? settings?.suggestedQuestions, accentColor: appearance?.primaryColor, onSuggestedQuestionClick: handleQuestionClick, onActionClick: onActionClick, onFeedback: onFeedback, onScrollStateChange: handleScrollStateChange, getActionRenderer: getActionRenderer }), jsx(ScrollButton, { onClick: () => scrollToBottom?.(), visible: showScrollButton }), jsx(MessageInput, { onSend: onSendMessage, placeholder: isLimitReached ? 'Message limit reached' : (isTyping ? 'Waiting for response...' : inputPlaceholder), disabled: isLoading || isTyping || isLimitReached, enableFileUpload: settings?.enableFileUpload })] }))] }));
30407
+ }, "aria-label": "Delete conversation", children: jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick })] })) : (jsxs(Fragment, { children: [maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), (() => {
30408
+ console.log('[DEBUG ChatWindow] Rendering MessageList with', messages.length, 'messages');
30409
+ messages.forEach((m, i) => {
30410
+ console.log(`[DEBUG ChatWindow] msg ${i}:`, { role: m.message.role, hasAction: !!m.action, impl: m.action?.implementation });
30411
+ });
30412
+ console.log('[DEBUG ChatWindow] getActionRenderer available:', !!getActionRenderer);
30413
+ if (getActionRenderer) {
30414
+ console.log('[DEBUG ChatWindow] Testing renderer for query-contact-directory:', !!getActionRenderer('query-contact-directory'));
30415
+ }
30416
+ return null;
30417
+ })(), jsx(MessageList, { messages: messages, isTyping: isTyping, showTypingIndicator: settings?.showTypingIndicator, showTimestamps: settings?.showTimestamps, showToolCalls: settings?.showToolCalls, enableFeedback: settings?.enableFeedback, welcomeTitle: welcomeTitle || 'Welcome Message', welcomeMessage: welcomeMessage, suggestedQuestions: suggestedQuestionsOverride ?? settings?.suggestedQuestions, accentColor: appearance?.primaryColor, onSuggestedQuestionClick: handleQuestionClick, onActionClick: onActionClick, onActionDismiss: onActionDismiss, onFeedback: onFeedback, onScrollStateChange: handleScrollStateChange, getActionRenderer: getActionRenderer }), settings?.showDataPolicy && (jsxs("div", { className: "ai-chat-page-disclaimer", children: [jsx("span", { children: "AI-generated responses may be inaccurate." }), jsx("button", { type: "button", className: "ai-chat-page-disclaimer-link", onClick: handleDataPolicyClick, children: "Privacy Notice" })] })), jsx(ScrollButton, { onClick: () => scrollToBottom?.(), visible: showScrollButton }), jsx(MessageInput, { onSend: onSendMessage, placeholder: isLimitReached ? 'Message limit reached' : (isTyping ? 'Waiting for response...' : inputPlaceholder), disabled: isLoading || isTyping || isLimitReached, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick })] }))] }));
29259
30418
  };
29260
30419
 
29261
30420
  /**
@@ -29661,7 +30820,7 @@ function styleInject(css, ref) {
29661
30820
  if ( ref === void 0 ) ref = {};
29662
30821
  var insertAt = ref.insertAt;
29663
30822
 
29664
- if (typeof document === 'undefined') { return; }
30823
+ if (!css || typeof document === 'undefined') { return; }
29665
30824
 
29666
30825
  var head = document.head || document.getElementsByTagName('head')[0];
29667
30826
  var style = document.createElement('style');
@@ -29684,7 +30843,10 @@ function styleInject(css, ref) {
29684
30843
  }
29685
30844
  }
29686
30845
 
29687
- var css_248z = ".ai-chat-message{animation:ai-chat-message-appear .2s var(--chat-ease-bounce);max-width:85%}.ai-chat-message-content{border-radius:var(--chat-radius-bubble,14px);font-size:var(--chat-text-md,15px);line-height:var(--chat-line-relaxed,1.6);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-message.user .ai-chat-message-content{background:var(--chat-user-bg,#f4f3f0);border-bottom-right-radius:var(--chat-radius-sm,4px);color:var(--chat-user-text,#000)}.ai-chat-message.assistant .ai-chat-message-content{background:var(--chat-assistant-bg,transparent);color:var(--chat-assistant-text,#000)}.ai-chat-message-timestamp{color:var(--chat-text-muted,#71717a);font-size:var(--chat-text-xs,12px);margin-top:var(--chat-space-xs,4px);padding:0 var(--chat-space-xs,4px)}.ai-chat-message.streaming .ai-chat-message-content:after{animation:ai-chat-cursor-blink .8s infinite;content:\"▋\";margin-left:2px;opacity:.7}@keyframes ai-chat-message-appear{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-cursor-blink{0%,50%{opacity:1}51%,to{opacity:0}}.ai-chat-message.fullpage .ai-chat-message-content{font-size:var(--chat-text-lg,18px);padding:var(--chat-space-md,16px) var(--chat-space-lg,24px)}.ai-chat-typing{gap:var(--chat-space-xs,4px);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-typing-dot{background:var(--chat-text-muted,#71717a)}.ai-chat-tool-gear{color:var(--text-primary,#3e3e3e)}.ai-chat-tool-gear.spinning{animation:ai-chat-spin 1.5s linear infinite}.ai-chat-tool-badge{border-radius:8px}.ai-chat-tool-badge.loading{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-tool-badge.error{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-tool-check{color:#22c55e;flex-shrink:0}.ai-chat-tool-error{color:#ef4444;flex-shrink:0}.ai-chat-tool-badge .tool-name{max-width:150px;overflow:hidden;text-overflow:ellipsis}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear{color:#fff}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-badge.error,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge.error,.dark .ai-chat-tool-badge.error,[data-theme=dark] .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}.chakra-ui-dark .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.chakra-ui-dark .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.chakra-ui-dark .ai-chat-tool-badge.error,html.dark .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}@keyframes ai-chat-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.ai-chat-action-skeleton-item{animation:ai-chat-skeleton-pulse 1.5s ease-in-out infinite;background:var(--bg-secondary,#e5e7eb)}.ai-chat-widget.dark .ai-chat-action-skeleton-item,.chakra-ui-dark .ai-chat-action-skeleton-item,.dark .ai-chat-action-skeleton-item,[data-theme=dark] .ai-chat-action-skeleton-item{background:hsla(0,0%,100%,.1)}.ai-chat-action-skeleton-content{display:flex;flex-direction:column;gap:16px}.ai-chat-action-skeleton-header{align-items:center;display:flex;gap:10px}.ai-chat-action-skeleton-box{background:rgba(0,0,0,.08);border-radius:10px;display:flex;flex-direction:column;gap:8px;padding:14px}.ai-chat-widget.dark .ai-chat-action-skeleton-box,.chakra-ui-dark .ai-chat-action-skeleton-box,.dark .ai-chat-action-skeleton-box,[data-theme=dark] .ai-chat-action-skeleton-box{background:rgba(0,0,0,.25)}.ai-chat-action-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border:none;border-radius:var(--radius-lg,12px);box-sizing:border-box;margin-top:var(--space-sm,8px);max-width:100%;padding:var(--space-md,16px);transition:all var(--duration-normal,.25s) ease;width:100%}.ai-chat-widget.dark .ai-chat-action-card,.chakra-ui-dark .ai-chat-action-card,.dark .ai-chat-action-card,[data-theme=dark] .ai-chat-action-card{background:var(--bg-secondary,#3a3a3a)}.ai-chat-action-booked{background:var(--bg-secondary,#f4f4f4);border:none}.ai-chat-widget.dark .ai-chat-action-booked,.chakra-ui-dark .ai-chat-action-booked,.dark .ai-chat-action-booked,[data-theme=dark] .ai-chat-action-booked{background:var(--bg-secondary,#3a3a3a)}.ai-chat-action-header{align-items:center;color:var(--text-primary,#3e3e3e);display:flex;font-size:var(--text-md,15px);font-weight:var(--font-weight-semibold,600);gap:var(--space-sm,8px);margin-bottom:var(--space-md,16px)}.ai-chat-widget.dark .ai-chat-action-header,.chakra-ui-dark .ai-chat-action-header,.dark .ai-chat-action-header,[data-theme=dark] .ai-chat-action-header{color:var(--text-primary,#fff)}.ai-chat-action-icon{color:var(--action-accent,var(--primary-color,#3b82f6));flex-shrink:0;height:20px;width:20px}.ai-chat-action-success-icon-wrapper{align-items:center;background:var(--action-accent,var(--primary-color,#22c55e));border-radius:50%;color:#fff;display:flex;flex-shrink:0;height:24px;justify-content:center;width:24px}.ai-chat-action-icon-success{color:currentColor;height:14px;width:14px}.ai-chat-action-detail-box{background:var(--bg-primary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-md,8px);display:flex;flex-direction:column;gap:4px;padding:12px 16px}.ai-chat-widget.dark .ai-chat-action-detail-box,.chakra-ui-dark .ai-chat-action-detail-box,.dark .ai-chat-action-detail-box,[data-theme=dark] .ai-chat-action-detail-box{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.05)}.ai-chat-action-label-small{color:var(--text-muted,#71717a);font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.ai-chat-action-value-large{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:500}.ai-chat-widget.dark .ai-chat-action-value-large,.chakra-ui-dark .ai-chat-action-value-large,.dark .ai-chat-action-value-large,[data-theme=dark] .ai-chat-action-value-large{color:#fff}.ai-chat-action-link-button{align-items:center;background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;box-sizing:border-box;color:#fff;display:flex;font-size:14px;font-weight:600;gap:6px;justify-content:center;margin-top:8px;padding:12px;text-decoration:none;transition:all .2s ease;width:100%}.ai-chat-action-link-button:hover{opacity:.9;transform:translateY(-1px)}.ai-chat-action-body{display:flex;flex-direction:column;gap:var(--space-md,16px)}.ai-chat-action-field{display:flex;flex-direction:column;gap:var(--space-xs,6px)}.ai-chat-action-label{color:var(--text-secondary,#6b7280);font-size:var(--text-sm,13px);font-weight:var(--font-weight-medium,500)}.ai-chat-widget.dark .ai-chat-action-label,.chakra-ui-dark .ai-chat-action-label,.dark .ai-chat-action-label,[data-theme=dark] .ai-chat-action-label{color:var(--text-secondary,#a1a1aa)}.ai-chat-action-input{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);font-size:var(--text-sm,13px);outline:none;padding:10px 12px;transition:border-color .2s ease,box-shadow .2s ease}.ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-action-input::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-action-input,.chakra-ui-dark .ai-chat-action-input,.dark .ai-chat-action-input,[data-theme=dark] .ai-chat-action-input{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-input:focus,.chakra-ui-dark .ai-chat-action-input:focus,.dark .ai-chat-action-input:focus,[data-theme=dark] .ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-action-date-grid{display:grid;gap:var(--space-xs,6px);grid-template-columns:repeat(auto-fill,minmax(90px,1fr))}.ai-chat-action-date-btn{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;font-size:var(--text-xs,12px);font-weight:var(--font-weight-medium,500);padding:8px 10px;text-align:center;transition:all .15s ease}.ai-chat-action-date-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-date-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-action-date-btn,.chakra-ui-dark .ai-chat-action-date-btn,.dark .ai-chat-action-date-btn,[data-theme=dark] .ai-chat-action-date-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-date-btn:hover,.chakra-ui-dark .ai-chat-action-date-btn:hover,.dark .ai-chat-action-date-btn:hover,[data-theme=dark] .ai-chat-action-date-btn:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-action-date-btn.active,.chakra-ui-dark .ai-chat-action-date-btn.active,.dark .ai-chat-action-date-btn.active,[data-theme=dark] .ai-chat-action-date-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-action-time-grid{display:grid;gap:var(--space-xs,6px);grid-template-columns:repeat(auto-fill,minmax(100px,1fr))}.ai-chat-action-time-btn{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;font-size:var(--text-xs,12px);font-weight:var(--font-weight-medium,500);padding:8px 10px;text-align:center;transition:all .15s ease}.ai-chat-action-time-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-time-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-action-time-btn,.chakra-ui-dark .ai-chat-action-time-btn,.dark .ai-chat-action-time-btn,[data-theme=dark] .ai-chat-action-time-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-time-btn:hover,.chakra-ui-dark .ai-chat-action-time-btn:hover,.dark .ai-chat-action-time-btn:hover,[data-theme=dark] .ai-chat-action-time-btn:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-action-time-btn.active,.chakra-ui-dark .ai-chat-action-time-btn.active,.dark .ai-chat-action-time-btn.active,[data-theme=dark] .ai-chat-action-time-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-action-button{background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;color:#fff;cursor:pointer;font-size:var(--text-sm,13px);font-weight:var(--font-weight-semibold,600);padding:12px 16px;transition:all .2s ease;width:100%}.ai-chat-action-button:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}.ai-chat-action-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-action-error{background:rgba(239,68,68,.1);border-radius:var(--radius-md,8px);color:#dc2626;font-size:var(--text-sm,13px);padding:10px 12px}.ai-chat-widget.dark .ai-chat-action-error,.chakra-ui-dark .ai-chat-action-error,.dark .ai-chat-action-error,[data-theme=dark] .ai-chat-action-error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-action-hint{color:var(--text-muted,#9ca3af);font-size:var(--text-sm,13px);padding:var(--space-sm,8px);text-align:center}.ai-chat-link-preview{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-lg,12px);cursor:pointer;display:flex;flex-direction:column;margin-top:var(--space-sm,8px);overflow:hidden;position:relative;transition:border-color .2s,box-shadow .2s,transform .2s}.ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 8px rgba(0,0,0,.1);transform:translateY(-1px)}.ai-chat-link-preview:focus{border-color:var(--action-accent);box-shadow:0 0 0 2px rgba(59,130,246,.2);outline:none}.ai-chat-widget.dark .ai-chat-link-preview,.chakra-ui-dark .ai-chat-link-preview,.dark .ai-chat-link-preview,[data-theme=dark] .ai-chat-link-preview{background:var(--bg-secondary,#3a3a3a);border-color:hsla(0,0%,100%,.08)}.ai-chat-widget.dark .ai-chat-link-preview:hover,.chakra-ui-dark .ai-chat-link-preview:hover,.dark .ai-chat-link-preview:hover,[data-theme=dark] .ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 12px rgba(0,0,0,.3)}.ai-chat-link-preview__image{aspect-ratio:1.91/1;background:var(--bg-muted,#e5e7eb);overflow:hidden;width:100%}.ai-chat-widget.dark .ai-chat-link-preview__image,.chakra-ui-dark .ai-chat-link-preview__image,.dark .ai-chat-link-preview__image,[data-theme=dark] .ai-chat-link-preview__image{background:hsla(0,0%,100%,.05)}.ai-chat-link-preview__image img{height:100%;object-fit:cover;width:100%}.ai-chat-link-preview__content{flex:1;padding:12px}.ai-chat-link-preview__site{align-items:center;display:flex;gap:6px;margin-bottom:6px}.ai-chat-link-preview__favicon{border-radius:2px;flex-shrink:0;height:16px;width:16px}.ai-chat-link-preview__domain{color:var(--text-muted,#71717a);font-size:12px;letter-spacing:.5px;overflow:hidden;text-overflow:ellipsis;text-transform:uppercase;white-space:nowrap}.ai-chat-link-preview__title{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-primary,#3e3e3e);display:-webkit-box;font-size:15px;font-weight:600;line-height:1.3;margin:0 0 4px;overflow:hidden}.ai-chat-widget.dark .ai-chat-link-preview__title,.chakra-ui-dark .ai-chat-link-preview__title,.dark .ai-chat-link-preview__title,[data-theme=dark] .ai-chat-link-preview__title{color:#fff}.ai-chat-link-preview__description{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-muted,#71717a);display:-webkit-box;font-size:13px;line-height:1.4;margin:0;overflow:hidden}.ai-chat-link-preview__context{border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin:8px 0 0;padding-top:8px}.ai-chat-widget.dark .ai-chat-link-preview__context,.chakra-ui-dark .ai-chat-link-preview__context,.dark .ai-chat-link-preview__context,[data-theme=dark] .ai-chat-link-preview__context{border-color:hsla(0,0%,100%,.08)}.ai-chat-link-preview__arrow{align-items:center;background:var(--bg-primary,#fff);border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.1);color:var(--text-muted,#71717a);display:flex;height:28px;justify-content:center;opacity:0;position:absolute;right:12px;top:12px;transition:opacity .2s,background .2s;width:28px}.ai-chat-link-preview:hover .ai-chat-link-preview__arrow{opacity:1}.ai-chat-widget.dark .ai-chat-link-preview__arrow,.chakra-ui-dark .ai-chat-link-preview__arrow,.dark .ai-chat-link-preview__arrow,[data-theme=dark] .ai-chat-link-preview__arrow{background:hsla(0,0%,100%,.1);color:#fff}.ai-chat-link-preview--error{border-color:rgba(239,68,68,.3)}.ai-chat-link-preview--error:hover{border-color:rgba(239,68,68,.5)}.ai-chat-link-preview__error-text{color:#dc2626;font-size:12px;margin:4px 0 0}.ai-chat-widget.dark .ai-chat-link-preview__error-text,.chakra-ui-dark .ai-chat-link-preview__error-text,.dark .ai-chat-link-preview__error-text,[data-theme=dark] .ai-chat-link-preview__error-text{color:#fca5a5}.ai-chat-video-player{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border-radius:var(--radius-lg,12px);display:flex;flex-direction:column;margin-top:var(--space-sm,8px);overflow:hidden}.ai-chat-widget.dark .ai-chat-video-player,.chakra-ui-dark .ai-chat-video-player,.dark .ai-chat-video-player,[data-theme=dark] .ai-chat-video-player{background:var(--bg-secondary,#3a3a3a)}.ai-chat-video-player__header{align-items:center;color:var(--action-accent,var(--primary-color,#3b82f6));display:flex;gap:8px;padding:12px 12px 8px}.ai-chat-video-player__title{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:600}.ai-chat-widget.dark .ai-chat-video-player__title,.chakra-ui-dark .ai-chat-video-player__title,.dark .ai-chat-video-player__title,[data-theme=dark] .ai-chat-video-player__title{color:#fff}.ai-chat-video-player__container{aspect-ratio:16/9;background:#000;position:relative;width:100%}.ai-chat-video-player__thumbnail{cursor:pointer;height:100%;position:relative;width:100%}.ai-chat-video-player__thumbnail img{height:100%;object-fit:cover;width:100%}.ai-chat-video-player__placeholder{align-items:center;background:linear-gradient(135deg,#1a1a2e,#16213e);cursor:pointer;display:flex;flex-direction:column;gap:8px;height:100%;justify-content:center;position:relative;width:100%}.ai-chat-video-player__click-text{color:hsla(0,0%,100%,.7);font-size:13px}.ai-chat-video-player__play-btn{align-items:center;background:rgba(0,0,0,.7);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:64px;justify-content:center;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s,transform .2s;width:64px}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn{left:auto;position:relative;top:auto;transform:none}.ai-chat-video-player__play-btn:hover{background:rgba(0,0,0,.9);transform:translate(-50%,-50%) scale(1.05)}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn:hover{transform:scale(1.05)}.ai-chat-video-player__provider-badge{background:rgba(0,0,0,.8);border-radius:4px;bottom:8px;color:#fff;font-size:11px;font-weight:600;letter-spacing:.5px;padding:4px 8px;position:absolute;right:8px;text-transform:uppercase}.ai-chat-video-player__iframe,.ai-chat-video-player__video{border:none;height:100%;left:0;position:absolute;top:0;width:100%}.ai-chat-video-player__error{align-items:center;background:rgba(239,68,68,.1);color:#dc2626;display:flex;font-size:13px;height:100%;justify-content:center;padding:16px;text-align:center;width:100%}.ai-chat-widget.dark .ai-chat-video-player__error,.chakra-ui-dark .ai-chat-video-player__error,.dark .ai-chat-video-player__error,[data-theme=dark] .ai-chat-video-player__error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-video-player__context{border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-muted,#71717a);font-size:12px;font-style:italic;padding:10px 12px}.ai-chat-widget.dark .ai-chat-video-player__context,.chakra-ui-dark .ai-chat-video-player__context,.dark .ai-chat-video-player__context,[data-theme=dark] .ai-chat-video-player__context{border-color:hsla(0,0%,100%,.08)}.ai-chat-location-card{background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:12px;overflow:hidden}.ai-chat-widget.dark .ai-chat-location-card,.chakra-ui-dark .ai-chat-location-card,.dark .ai-chat-location-card,[data-theme=dark] .ai-chat-location-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-location-card--compact{border-radius:10px}.ai-chat-location-card--error{color:var(--text-muted,#71717a);padding:16px;text-align:center}.ai-chat-location-card__map{background:var(--bg-muted,#f4f4f5);position:relative;width:100%}.ai-chat-widget.dark .ai-chat-location-card__map,.chakra-ui-dark .ai-chat-location-card__map,.dark .ai-chat-location-card__map,[data-theme=dark] .ai-chat-location-card__map{background:rgba(0,0,0,.2)}.ai-chat-location-card__map iframe{border:none;display:block;height:100%;width:100%}.ai-chat-location-card__content{padding:14px}.ai-chat-location-card--compact .ai-chat-location-card__content{padding:12px}.ai-chat-location-card__header{align-items:center;display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.ai-chat-location-card__name{color:var(--text-primary,#18181b);flex:1;font-size:16px;font-weight:600;margin:0;min-width:0}.ai-chat-widget.dark .ai-chat-location-card__name,.chakra-ui-dark .ai-chat-location-card__name,.dark .ai-chat-location-card__name,[data-theme=dark] .ai-chat-location-card__name{color:#fff}.ai-chat-location-card--compact .ai-chat-location-card__name{font-size:14px}.ai-chat-location-card__type{background:var(--bg-muted,#f4f4f5);border-radius:10px;color:var(--text-muted,#71717a);font-size:11px;font-weight:500;letter-spacing:.5px;padding:2px 8px;text-transform:uppercase}.ai-chat-widget.dark .ai-chat-location-card__type,.chakra-ui-dark .ai-chat-location-card__type,.dark .ai-chat-location-card__type,[data-theme=dark] .ai-chat-location-card__type{background:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.7)}.ai-chat-location-card__status{border-radius:12px;font-size:12px;font-weight:500;padding:2px 8px}.ai-chat-location-card__status--open{background:#dcfce7;color:#16a34a}.ai-chat-location-card__status--closed{background:#fef2f2;color:#dc2626}.ai-chat-widget.dark .ai-chat-location-card__status--open,.chakra-ui-dark .ai-chat-location-card__status--open,.dark .ai-chat-location-card__status--open,[data-theme=dark] .ai-chat-location-card__status--open{background:rgba(34,197,94,.2);color:#4ade80}.ai-chat-widget.dark .ai-chat-location-card__status--closed,.chakra-ui-dark .ai-chat-location-card__status--closed,.dark .ai-chat-location-card__status--closed,[data-theme=dark] .ai-chat-location-card__status--closed{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-location-card__address{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__address svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__hours{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;margin-bottom:8px}.ai-chat-location-card__hours svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__hours-list{flex:1}.ai-chat-location-card__hours-toggle{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;font:inherit;gap:4px;padding:0}.ai-chat-location-card__hours-toggle:hover{text-decoration:underline}.ai-chat-location-card__hours-full{list-style:none;margin:8px 0 0;padding:0}.ai-chat-location-card__hours-full li{display:flex;font-size:12px;justify-content:space-between;padding:4px 0}.ai-chat-location-card__hours-today{color:var(--text-primary,#18181b);font-weight:600}.ai-chat-widget.dark .ai-chat-location-card__hours-today,.chakra-ui-dark .ai-chat-location-card__hours-today,.dark .ai-chat-location-card__hours-today,[data-theme=dark] .ai-chat-location-card__hours-today{color:#fff}.ai-chat-location-card__phone{align-items:center;background:none;border:none;color:var(--action-accent,#3b82f6);cursor:pointer;display:flex;font-size:13px;gap:6px;margin-bottom:12px;padding:0}.ai-chat-location-card__phone:hover{text-decoration:underline}.ai-chat-location-card__actions{display:flex;gap:8px;justify-content:flex-start;width:100%}.ai-chat-location-card__button{align-items:center;background:var(--action-accent,#3b82f6);border:none;border-radius:20px;color:#fff;cursor:pointer;display:flex;flex:1;font-size:13px;font-weight:500;gap:6px;justify-content:center;padding:10px 16px;transition:opacity .2s}.ai-chat-location-card__button:hover{opacity:.9}.ai-chat-location-card--compact .ai-chat-location-card__button{font-size:12px;padding:8px 12px}.ai-chat-location-card__link{align-items:center;background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:20px;color:var(--text-primary,#18181b);display:flex;font-size:13px;gap:6px;padding:10px 16px;text-decoration:none;transition:border-color .2s}.ai-chat-widget.dark .ai-chat-location-card__link,.chakra-ui-dark .ai-chat-location-card__link,.dark .ai-chat-location-card__link,[data-theme=dark] .ai-chat-location-card__link{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-location-card__link:hover{border-color:var(--action-accent,#3b82f6)}.ai-chat-location-card-list{display:flex;flex-direction:column;gap:8px}.ai-chat-location-card-list__header{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:13px;font-weight:500;gap:6px;margin-bottom:4px;padding:0 4px}.ai-chat-location-card-list__stack{display:grid;gap:12px;grid-template-columns:repeat(3,minmax(0,1fr))}@media (max-width:1200px){.ai-chat-location-card-list__stack{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:768px){.ai-chat-location-card-list__stack{grid-template-columns:1fr}}@media (max-width:520px){.ai-chat-location-card-list__stack{grid-template-columns:1fr!important}}@media (min-width:521px) and (max-width:900px){.ai-chat-location-card-list__stack{grid-template-columns:repeat(2,minmax(0,1fr))!important}}.ai-chat-location-card-list__grid{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}@media (max-width:400px){.ai-chat-location-card-list__grid{grid-template-columns:1fr}}.ai-chat-location-card-list__carousel{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;scroll-snap-type:x mandatory;scrollbar-width:none}.ai-chat-location-card-list__carousel::-webkit-scrollbar{display:none}.ai-chat-location-card-list__carousel>.ai-chat-location-card{flex:0 0 280px;scroll-snap-align:start}.ai-chat-widget,.chat-ui{--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--radius-2xl:18px;--radius-pill:9999px;--radius-window-top:22px;--radius-window-bottom:44px;--radius-window-gutter:16px;--radius-chat-bubble:14px;--radius-preset-badge:13px;--radius-history-item:14px;--radius-action-badge:8px;--radius-input:62px;--space-xs:4px;--space-sm:8px;--space-md:16px;--space-lg:24px;--space-xl:32px;--text-xs:12px;--text-sm:14px;--text-md:15px;--text-lg:18px;--text-xl:22px;--text-2xl:28px;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--line-height-tight:1.3;--line-height-normal:1.4;--line-height-relaxed:1.6;--bg-primary:#fff;--bg-secondary:#f4f4f4;--bg-tertiary:#e5e7eb;--bg-hover:#e5e7eb;--text-primary:#3e3e3e;--text-secondary:#000;--text-muted:#71717a;--text-placeholder:#a1a1aa;--border-default:#d3d3d3;--border-subtle:#e5e7eb;--border-muted:#f4f4f5;--user-bg:#f4f3f0;--user-text:#000;--user-bg-hover:#e8e7e4;--agent-bg:transparent;--agent-text:#000;--input-bg:#f4f4f4;--input-border:#d3d3d3;--input-text:#000;--btn-primary-bg:#151515;--btn-primary-text:#f4f4f4;--btn-secondary-bg:transparent;--btn-secondary-text:#71717a;--spring-bounce:cubic-bezier(0.34,1.56,0.64,1);--spring-smooth:cubic-bezier(0.4,0,0.2,1);--spring-snappy:cubic-bezier(0.2,0,0,1);--duration-fast:0.15s;--duration-normal:0.25s;--duration-slow:0.35s;--shadow-sm:0 1px 2px rgba(0,0,0,.05);--shadow-md:0 2px 8px rgba(0,0,0,.1);--shadow-lg:0 4px 16px rgba(0,0,0,.12);--shadow-window:0px 0px 15px 9px rgba(0,0,0,.1);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03)}.ai-chat-widget.dark,.chat-ui.dark{--bg-primary:#282625;--bg-secondary:#4a4846;--bg-tertiary:#484848;--bg-hover:#484848;--text-primary:#fff;--text-secondary:#fff;--text-muted:#a1a1aa;--text-placeholder:#71717a;--border-default:#5d5b5b;--border-subtle:#5d5b5b;--border-muted:#5d5b5b;--user-bg:#484848;--user-text:#fff;--user-bg-hover:#5a5a5a;--agent-bg:transparent;--agent-text:#fff;--input-bg:#4a4846;--input-border:#5d5b5b;--input-text:#fff;--btn-primary-bg:#fff;--btn-primary-text:#312f2d;--btn-secondary-bg:transparent;--btn-secondary-text:#a1a1aa;--shadow-window:0px 0px 15px 9px rgba(0,0,0,.2);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03);--shadow-input:0px 0px 10px rgba(0,0,0,.15)}.ai-chat-widget,.chat-ui{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.ai-chat-widget-container{font-size:var(--text-sm);line-height:1.5;position:fixed;z-index:9999}.ai-chat-widget-container.bottom-right{bottom:20px;right:20px}.ai-chat-widget-container.bottom-left{bottom:20px;left:20px}.ai-chat-widget-container.top-right{right:20px;top:20px}.ai-chat-widget-container.top-left{left:20px;top:20px}@keyframes ai-chat-window-open{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes ai-chat-window-close{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.9) translateY(20px)}}@keyframes ai-chat-message-slide-in{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-welcome-fade-in{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-typing-pulse{0%,60%,to{opacity:.4;transform:translateY(0) scale(1)}30%{opacity:1;transform:translateY(-4px) scale(1.1)}}@keyframes ai-chat-gear-spin{to{transform:rotate(1turn)}}@keyframes ai-chat-tool-active{0%,to{background:var(--bg-secondary);opacity:1}50%{background:var(--bg-tertiary);opacity:1}}@keyframes ai-chat-feedback-morph{0%{opacity:.5;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes ai-chat-checkmark-pop{0%{opacity:0;transform:scale(0) rotate(-45deg)}50%{transform:scale(1.3) rotate(0deg)}to{opacity:1;transform:scale(1) rotate(0deg)}}@keyframes ai-chat-history-exit{to{opacity:0;transform:translateY(-18px)}}@keyframes ai-chat-tool-gradient{0%{background-position:200% 0}to{background-position:-200% 0}}@media (max-width:480px){.ai-chat-widget-container.is-open{height:100vh!important;inset:0!important;width:100vw!important}.ai-chat-widget-container.is-open .ai-chat-window{animation:none!important;border-radius:0!important;height:100%!important;inset:0!important;max-height:100%!important;max-width:100%!important;position:absolute!important;width:100%!important}.ai-chat-widget-container.is-open .ai-chat-button{display:none!important;visibility:hidden!important}.ai-chat-header{padding-top:max(16px,env(safe-area-inset-top))}.ai-chat-input-container{padding-bottom:max(20px,env(safe-area-inset-bottom))}}.ai-chat-window{animation:ai-chat-window-open var(--duration-slow,.35s) var(--spring-bounce);background:var(--bg-primary,#fff);border:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) var(--radius-window-bottom,44px) var(--radius-window-bottom,44px);box-shadow:var(--shadow-window,0 0 15px 5px rgba(0,0,0,.08));display:flex;flex-direction:column;overflow:hidden;position:absolute;transform-origin:bottom right;z-index:2}.ai-chat-widget.dark .ai-chat-window{background:var(--bg-primary,#282625);border-color:var(--border-default,#5d5b5b);border-width:.7px}.ai-chat-window.closing{animation:ai-chat-window-close var(--duration-normal) var(--spring-smooth) forwards}.ai-chat-window.size-small{height:500px;width:380px}.ai-chat-window.size-medium,.ai-chat-window.size-small{max-height:calc(100vh - 100px);max-width:calc(100vw - 40px)}.ai-chat-window.size-medium{height:600px;width:420px}.ai-chat-window.size-large{height:700px;max-height:calc(100vh - 100px);max-width:calc(100vw - 40px);width:480px}.ai-chat-widget-container.bottom-right .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);right:0}.ai-chat-widget-container.bottom-left .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);left:0}.ai-chat-widget-container.top-right .ai-chat-window{right:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-widget-container.top-left .ai-chat-window{left:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-header{align-items:center;background:var(--bg-primary,#fff);border-bottom:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) 0 0;display:flex;justify-content:space-between;padding:18px var(--space-md,16px);position:relative;z-index:10}.ai-chat-widget.dark .ai-chat-header{background:var(--bg-primary,#282625);border-bottom-color:var(--border-default,#5d5b5b);border-bottom-width:.7px}.ai-chat-header.is-history{padding-left:var(--space-md)}.ai-chat-header.is-history .ai-chat-title{flex:1;min-width:0;overflow:hidden;padding-right:var(--space-lg);text-overflow:ellipsis;white-space:nowrap}.ai-chat-header-content{align-items:center;display:flex;flex:1;gap:var(--space-lg)}.ai-chat-header-actions{align-items:center;display:flex;gap:var(--space-sm)}.ai-chat-logo{border-radius:10px;height:36px;object-fit:cover;width:36px}.ai-chat-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-xl,22px);font-weight:var(--font-weight-bold,700);letter-spacing:-.02em}.ai-chat-widget.dark .ai-chat-title{color:var(--text-primary,#fff)}.ai-chat-close-button,.ai-chat-header-button{align-items:center;background:transparent;border:none;border-radius:var(--radius-md);color:var(--text-muted);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:32px}.ai-chat-close-button:hover,.ai-chat-header-button:hover{color:var(--text-primary)}.ai-chat-close-button:active,.ai-chat-header-button:active{transform:scale(.95)}.ai-chat-close-button svg,.ai-chat-header-button svg{height:22px;width:22px}.ai-chat-button{align-items:center;background:var(--button-color,var(--btn-primary-bg));border:1px solid var(--border-default,#d3d3d3);border-radius:50%;box-shadow:var(--shadow-button,0 0 15px 9px rgba(0,0,0,.03));color:var(--button-icon-color,var(--btn-primary-text));cursor:pointer;display:flex;height:var(--button-size,56px);justify-content:center;overflow:hidden;position:relative;transition:opacity var(--duration-fast) ease;width:var(--button-size,56px);z-index:1}.ai-chat-button:hover{opacity:.9}.ai-chat-button:active{opacity:.8}.ai-chat-button-svg{height:50%;min-height:24px;min-width:24px;transition:transform var(--duration-fast) ease;width:50%}.ai-chat-button.is-open .ai-chat-button-svg{transform:rotate(0deg)}.ai-chat-button-icon{font-size:1.5em;line-height:1}.ai-chat-input-container{background:linear-gradient(to bottom,transparent 0,var(--bg-primary,#fff) 50%,var(--bg-primary,#fff) 100%);bottom:0;left:0;padding-top:30px;position:absolute;right:0;z-index:10}.ai-chat-widget.dark .ai-chat-input-container{background:linear-gradient(to bottom,transparent 0,var(--bg-primary,#282625) 50%,var(--bg-primary,#282625) 100%)}.ai-chat-input-container.separate{padding:0 var(--radius-window-gutter,16px) var(--radius-window-gutter,16px);padding-top:30px}.ai-chat-input-wrapper{align-items:flex-end;background:var(--input-bg,#f4f4f4);border:1px solid var(--input-border,#d3d3d3);border-radius:var(--radius-input,62px);box-sizing:border-box;display:flex;gap:0;height:52px;overflow:hidden;padding:6px 6px 6px 16px;position:relative;transition:all var(--duration-fast,.15s) ease;z-index:5}.ai-chat-input-wrapper.multiline{border-radius:14px!important;min-height:64px;padding:10px 10px 10px 14px}.ai-chat-widget.dark .ai-chat-input-wrapper{background:var(--input-bg,#4a4846);border-color:var(--input-border,#5d5b5b);border-width:.7px;box-shadow:var(--shadow-input,0 0 10px rgba(0,0,0,.15))}.ai-chat-input-wrapper:focus-within{border-color:var(--text-muted,#a1a1aa)}.ai-chat-input{word-wrap:break-word!important;background:transparent!important;border:none!important;border-radius:0!important;box-shadow:none!important;box-sizing:border-box!important;color:var(--input-text,#000)!important;flex:1!important;font-family:inherit!important;font-size:var(--text-md,15px)!important;height:40px!important;line-height:20px!important;margin:0!important;max-height:40px!important;min-height:40px!important;min-width:0!important;outline:none!important;overflow-wrap:anywhere!important;overflow-x:hidden!important;overflow-y:auto!important;padding:10px var(--space-sm,8px)!important;resize:none!important;white-space:pre-wrap!important;width:0!important;word-break:break-word!important}.ai-chat-widget.dark .ai-chat-input{color:var(--input-text,#fff)}.ai-chat-input::placeholder{color:var(--text-placeholder,#a1a1aa)}.ai-chat-widget.dark .ai-chat-input::placeholder{color:var(--text-placeholder,#52525b)}.ai-chat-file-button{align-items:center;align-self:center;background:transparent;border:none;color:var(--text-placeholder);cursor:pointer;display:flex;flex-shrink:0;height:28px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:28px}.ai-chat-file-button:hover{color:var(--text-secondary)}.ai-chat-file-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-send-button{align-items:center;align-self:center;background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));border:none;border-radius:50%;color:var(--button-icon-color,var(--btn-primary-text,#f4f4f4));cursor:pointer;display:flex;flex-shrink:0;height:40px;justify-content:center;min-height:40px;min-width:40px;padding:0;transition:all var(--duration-fast,.15s) ease;width:40px}.ai-chat-widget.dark .ai-chat-send-button{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));color:var(--button-icon-color,var(--btn-primary-text,#f4f4f4))}.ai-chat-widget.dark .ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button:hover:not(:disabled){opacity:.8}.ai-chat-send-button:active:not(:disabled){transform:scale(.95)}.ai-chat-send-button:disabled{cursor:not-allowed;opacity:.3}.ai-chat-file-list{display:flex;flex-wrap:wrap;gap:var(--space-sm);padding:var(--space-sm) var(--space-sm)}.ai-chat-file-item{align-items:center;background:rgba(0,0,0,.05);border-radius:6px;display:flex;font-size:var(--text-xs);gap:var(--space-sm);padding:6px 10px}.ai-chat-file-extension{background:var(--btn-primary-bg);border-radius:3px;color:var(--btn-primary-text);display:inline-block;font-size:10px;font-weight:var(--font-weight-semibold);min-width:40px;padding:2px 6px;text-align:center;text-transform:uppercase}.ai-chat-file-info{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.ai-chat-file-name{font-weight:var(--font-weight-medium);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-file-size{color:var(--text-muted);font-size:10px;opacity:.7}.ai-chat-file-remove{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;justify-content:center;opacity:.5;padding:var(--space-xs);transition:opacity var(--duration-fast) ease}.ai-chat-file-remove:hover{opacity:1}.ai-chat-messages{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;align-items:stretch;background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;gap:var(--space-md,16px);justify-content:flex-start;overflow-x:hidden;overflow-y:auto;padding:var(--space-lg,24px) var(--space-md,16px) 100px;position:relative;scroll-behavior:smooth;scrollbar-width:none}.ai-chat-widget.dark .ai-chat-messages{background:var(--bg-primary,#18181b)}.ai-chat-messages::-webkit-scrollbar{display:none}.ai-chat-message{animation:ai-chat-message-slide-in .2s var(--spring-bounce);display:flex;flex-direction:column;max-width:90%}.ai-chat-message.user{align-items:flex-end;align-self:flex-end}.ai-chat-message.assistant{align-items:flex-start;align-self:flex-start;max-width:100%}.ai-chat-message.tool{align-self:flex-start;margin:0 -16px;max-width:100%;padding:0;width:calc(100% + 32px)}.ai-chat-message-content{word-wrap:break-word;border-radius:18px;font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);overflow-wrap:break-word;padding:8px 14px}.ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#f4f3f0);border-radius:18px;color:var(--user-text,#000)}.ai-chat-widget.dark .ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#484848);color:var(--user-text,#fff)}.ai-chat-message.assistant .ai-chat-message-content{background:var(--agent-bg,transparent);color:var(--agent-text,#000);padding:0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content{color:var(--agent-text,#fff)}.ai-chat-message-timestamp{color:var(--text-muted,#71717a);font-size:var(--text-xs,12px);margin-top:var(--space-xs,4px);padding:0 var(--space-xs,4px)}.ai-chat-welcome{animation:ai-chat-welcome-fade-in .3s var(--spring-smooth);display:flex;flex-direction:column;gap:var(--space-md,16px);padding:var(--space-lg,24px) 0}.ai-chat-welcome-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-2xl,28px);font-weight:var(--font-weight-bold,700);line-height:var(--line-height-tight,1.3)}.ai-chat-widget.dark .ai-chat-welcome-title{color:var(--text-primary,#fff)}.ai-chat-welcome-text{color:var(--text-secondary,#000);font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);max-width:100%}.ai-chat-widget.dark .ai-chat-welcome-text{color:var(--text-secondary,#fff)}.ai-chat-typing{align-items:center;display:flex;gap:var(--space-xs,4px);padding:var(--space-sm,8px) var(--space-md,16px)}.ai-chat-typing-dot{animation:ai-chat-typing-bounce 1.4s ease-in-out infinite both;background:var(--text-muted,#71717a);border-radius:50%;height:8px;width:8px}.ai-chat-typing-dot:first-child{animation-delay:-.32s}.ai-chat-typing-dot:nth-child(2){animation-delay:-.16s}.ai-chat-typing-dot:nth-child(3){animation-delay:0s}@keyframes ai-chat-typing-bounce{0%,80%,to{opacity:.4;transform:scale(.6)}40%{opacity:1;transform:scale(1)}}.ai-chat-scroll-button{align-items:center;background:var(--bg-secondary,#f4f4f5);border:1px solid var(--border-subtle,rgba(0,0,0,.1));border-radius:50%;bottom:80px;box-shadow:0 2px 8px rgba(0,0,0,.1);color:var(--text-secondary,#71717a);cursor:pointer;display:flex;height:36px;justify-content:center;left:50%;opacity:0;pointer-events:none;position:absolute;transform:translateX(-50%);transition:background .15s ease,box-shadow .15s ease,opacity .15s ease,visibility .15s ease;visibility:hidden;width:36px;z-index:15}.ai-chat-scroll-button.visible{opacity:1;pointer-events:auto;visibility:visible}.ai-chat-scroll-button:hover{background:var(--bg-tertiary,#e4e4e7);box-shadow:0 4px 12px rgba(0,0,0,.15)}.ai-chat-scroll-button:active{background:var(--bg-tertiary,#d4d4d8)}.ai-chat-widget.dark .ai-chat-scroll-button{background:var(--bg-secondary,#3f3f46);border-color:var(--border-subtle,hsla(0,0%,100%,.1));box-shadow:0 2px 8px rgba(0,0,0,.3);color:var(--text-secondary,#a1a1aa)}.ai-chat-widget.dark .ai-chat-scroll-button:hover{background:var(--bg-tertiary,#52525b);box-shadow:0 4px 12px rgba(0,0,0,.4)}.ai-chat-error{background:var(--bg-secondary);border-radius:var(--radius-chat-bubble);color:var(--text-primary);font-size:var(--text-md);margin:0 auto;padding:10px var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content p{margin:0 0 var(--space-sm) 0}.ai-chat-message.assistant .ai-chat-message-content p:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content ol,.ai-chat-message.assistant .ai-chat-message-content ul{margin:var(--space-sm) 0;padding-left:var(--space-lg)}.ai-chat-message.assistant .ai-chat-message-content li{margin-bottom:var(--space-xs)}.ai-chat-message.assistant .ai-chat-message-content code{background:rgba(0,0,0,.05);border-radius:var(--radius-sm);font-family:SF Mono,Monaco,Cascadia Code,monospace;font-size:.9em;padding:2px 6px}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content code{background:hsla(0,0%,100%,.1)}.ai-chat-message.assistant .ai-chat-message-content pre{background:rgba(0,0,0,.05);border-radius:var(--radius-md);margin:var(--space-sm) 0;overflow-x:auto;padding:var(--space-sm)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content pre{background:hsla(0,0%,100%,.05)}.ai-chat-message.assistant .ai-chat-message-content pre code{background:transparent;padding:0}.ai-chat-message.assistant .ai-chat-message-content a{color:var(--btn-primary-bg);text-decoration:underline}.ai-chat-message.assistant .ai-chat-message-content strong{font-weight:var(--font-weight-semibold)}.ai-chat-message.assistant .ai-chat-message-content blockquote{border-left:3px solid var(--border-default);color:var(--text-muted);margin:var(--space-sm) 0;padding-left:var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content hr{border:none;border-top:1px solid var(--border-subtle,rgba(0,0,0,.1));margin:var(--space-lg,24px) 0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content hr{border-top-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content table{border-collapse:collapse;font-size:var(--text-sm);margin:var(--space-sm) 0;width:100%}.ai-chat-message.assistant .ai-chat-message-content td,.ai-chat-message.assistant .ai-chat-message-content th{border:1px solid var(--border-subtle);padding:var(--space-sm);text-align:left}.ai-chat-message.assistant .ai-chat-message-content th{font-weight:var(--font-weight-semibold);white-space:nowrap}.ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:rgba(0,0,0,.02)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:hsla(0,0%,100%,.03)}.ai-chat-suggested-questions{align-self:flex-end;margin:0;padding:16px 0 0;width:100%}.ai-chat-suggested-questions-list{align-items:center;display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.ai-chat-suggested-question{align-items:center;background:transparent;border:1px solid var(--border-default,#d4d4d8);border-radius:var(--radius-preset-badge,18px);color:var(--text-primary,#18181b);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:background .15s ease,border-color .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-widget.dark .ai-chat-suggested-question{background:transparent;border-color:var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}.ai-chat-suggested-question-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-suggested-question:hover{background:var(--bg-hover,#f4f4f5);border-color:var(--border-default,#d4d4d8)}.ai-chat-widget.dark .ai-chat-suggested-question:hover{background:var(--bg-hover,#3f3f46);border-color:var(--border-subtle,#52525b)}.ai-chat-suggested-question:active{transform:scale(.98)}.ai-chat-suggested-question.action-type{border:none}.ai-chat-suggested-question.action-type,.ai-chat-widget.dark .ai-chat-suggested-question.action-type{background:var(--primary-color,var(--button-color,#ef4444));color:var(--button-icon-color,#fff)}.ai-chat-suggested-question.action-type:hover{background:var(--primary-color,var(--button-color,#ef4444));opacity:.9}.ai-chat-suggested-question-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-suggested-question:not(.action-type) .ai-chat-suggested-question-icon{display:none}.ai-chat-follow-up-suggestions{box-sizing:border-box;margin:0;padding:8px 16px 0;width:100%}.ai-chat-follow-up-list{align-items:flex-end;display:flex;flex-direction:column;gap:6px}.ai-chat-follow-up-item{align-items:center;border:none;border-radius:var(--radius-preset-badge,18px);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:opacity .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-follow-up-item,.ai-chat-widget.dark .ai-chat-follow-up-item{background:var(--primary-color,var(--button-color,#07f));color:var(--button-icon-color,#fff)}.ai-chat-follow-up-item:hover{opacity:.9}.ai-chat-follow-up-item:active{transform:scale(.98)}.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-default,#d4d4d8);color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type,.dark .ai-chat-follow-up-item.question-type,[data-theme=dark] .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}}.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#f4f4f5);opacity:1}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type:hover,.dark .ai-chat-follow-up-item.question-type:hover,[data-theme=dark] .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}}.ai-chat-follow-up-item.action-type{background:var(--primary-color,var(--button-color,#07f));border:none;color:var(--button-icon-color,#fff)}.ai-chat-follow-up-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-follow-up-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-feedback-buttons{align-items:center;display:flex;gap:var(--space-xs)}.ai-chat-feedback{align-items:center;display:inline-flex;gap:0;height:20px}.ai-chat-feedback-button{align-items:center;background:transparent!important;border:none;border-radius:var(--radius-sm);color:var(--text-placeholder);cursor:pointer;display:flex;font-size:var(--text-sm);height:20px;justify-content:center;padding:var(--space-xs);transition:all var(--duration-fast) var(--spring-bounce)}.ai-chat-feedback-button:hover:not(:disabled){background:none!important;color:var(--text-secondary)}.ai-chat-feedback-button:active:not(:disabled){transform:scale(.9)}.ai-chat-feedback-button:disabled{cursor:not-allowed;opacity:.4}.ai-chat-feedback-button.active{background:none!important;color:var(--text-primary)}.ai-chat-feedback.submitted{align-items:center;animation:ai-chat-feedback-morph .3s var(--spring-bounce);gap:var(--space-xs)}.ai-chat-feedback-message{align-items:center;display:flex;gap:4px;margin-left:var(--space-xxs)}.ai-chat-feedback-checkmark{animation:ai-chat-checkmark-pop .3s var(--spring-bounce);color:#10b981;font-size:var(--text-md);font-weight:700}.ai-chat-feedback-text{color:#10b981;font-size:var(--text-xs);font-weight:var(--font-weight-medium)}.ai-chat-history-panel{background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;overflow:hidden}.ai-chat-widget.dark .ai-chat-history-panel{background:var(--bg-primary,#18181b)}.ai-chat-history-empty,.ai-chat-history-loading{align-items:center;color:var(--text-muted);display:flex;flex:1;font-size:var(--text-sm);justify-content:center;padding:var(--space-lg);text-align:center}.ai-chat-history-list{-ms-overflow-style:none;display:flex;flex:1;flex-direction:column;gap:var(--space-sm);overflow-y:auto;padding:var(--space-xs) var(--space-md) 120px;scrollbar-width:none}.ai-chat-history-list::-webkit-scrollbar{display:none}.ai-chat-history-list.exiting{animation:ai-chat-history-exit .22s var(--spring-smooth) forwards}.ai-chat-history-item{align-items:center;background:var(--user-bg,#f4f4f5);border-radius:var(--radius-history-item,15px);display:flex;flex:0 0 auto;flex-direction:row;height:var(--history-item-height,36px);margin:0;overflow:hidden;transition:background var(--duration-fast,.15s) ease;width:100%}.ai-chat-history-item-content{align-items:center;background:transparent;border:none;cursor:pointer;display:flex;flex:1;flex-direction:row;height:100%;min-width:0;padding:0 var(--space-xs,4px) 0 var(--space-md,16px);text-align:left}.ai-chat-widget.dark .ai-chat-history-item{background:var(--user-bg,#27272a)}.ai-chat-history-item:hover{background:var(--user-bg-hover,#e5e7eb)}.ai-chat-widget.dark .ai-chat-history-item:hover{background:var(--user-bg-hover,#3f3f46)}.ai-chat-history-item.active{background:var(--user-bg-hover,#e5e7eb)}.ai-chat-widget.dark .ai-chat-history-item.active{background:var(--user-bg-hover,#3f3f46)}.ai-chat-history-item-preview{color:var(--text-primary,#18181b);flex:1;font-size:var(--text-sm,14px);font-weight:var(--font-weight-medium,500);line-height:var(--line-height-normal,1.4);margin-bottom:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-widget.dark .ai-chat-history-item-preview{color:var(--text-primary,#fafafa)}.ai-chat-history-item.active .ai-chat-history-item-preview{font-weight:var(--font-weight-medium)}.ai-chat-history-item-meta{display:none}.ai-chat-history-item-delete{align-items:center;background:transparent;border:none;border-radius:var(--radius-sm,6px);color:var(--text-muted,#71717a);cursor:pointer;display:flex;flex-shrink:0;height:24px;justify-content:center;margin-left:auto;margin-right:var(--space-xs,4px);opacity:0;transition:opacity var(--duration-fast,.15s) ease,background var(--duration-fast,.15s) ease,color var(--duration-fast,.15s) ease;width:24px}.ai-chat-history-item-delete svg{height:14px;width:14px}.ai-chat-history-item:hover .ai-chat-history-item-delete{opacity:1}.ai-chat-history-item-delete:hover{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-widget.dark .ai-chat-history-item-delete:hover{background:rgba(239,68,68,.2);color:#f87171}.ai-chat-tool-row{align-items:center;display:flex;gap:10px;margin:2px 0;padding:0 16px}.ai-chat-tool-gear{color:#1f2937;flex-shrink:0;height:20px;width:20px}.ai-chat-tool-gear.spinning{animation:ai-chat-gear-spin 1.5s linear infinite}.ai-chat-tool-badges{align-items:center;display:flex;flex-wrap:wrap;gap:8px}.ai-chat-tool-badge{align-items:center;background:#e5e7eb;border:1px solid #d1d5db;border-radius:var(--radius-action-badge,8px);color:#1f2937;display:inline-flex;font-size:12px;font-weight:500;gap:4px;line-height:1.2;padding:5px 12px;transition:all .2s ease;white-space:nowrap}.ai-chat-tool-badge.loading{animation:ai-chat-tool-gradient 2s linear infinite;background:linear-gradient(90deg,var(--tool-loading-bg-1,#e0e0e0) 0,var(--tool-loading-bg-2,#f0f0f0) 25%,var(--tool-loading-bg-3,#fff) 50%,var(--tool-loading-bg-2,#f0f0f0) 75%,var(--tool-loading-bg-1,#e0e0e0) 100%);background-size:200% 100%;color:var(--tool-loading-text,#1a1a1a);position:relative}.ai-chat-widget:not(.dark) .ai-chat-tool-badge.loading{--tool-loading-bg-1:#2a2a2a;--tool-loading-bg-2:#3a3a3a;--tool-loading-bg-3:#4a4a4a;--tool-loading-text:#fff}.ai-chat-tool-badge.completed{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.chakra-ui-dark .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.chakra-ui-dark .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.ai-chat-tool-badge.error{background:var(--tool-error-bg,rgba(239,68,68,.15));color:var(--tool-error-text,#ef4444)}.ai-chat-tool-badge .ai-chat-tool-check{color:#fff;flex-shrink:0}.ai-chat-tool-badge .ai-chat-tool-error{color:#ef4444;flex-shrink:0}.tool-name{font-weight:500;line-height:1.2;white-space:nowrap}.ai-chat-tool-action{box-sizing:border-box;padding:0 16px;width:100%}";
30846
+ var css_248z$1 = ".ai-chat-message{animation:ai-chat-message-appear .2s var(--chat-ease-bounce);max-width:85%}.ai-chat-message-content{border-radius:var(--chat-radius-bubble,14px);font-size:var(--chat-text-md,15px);line-height:var(--chat-line-relaxed,1.6);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-message.user .ai-chat-message-content{background:var(--chat-user-bg,#f4f3f0);border-bottom-right-radius:var(--chat-radius-sm,4px);color:var(--chat-user-text,#000)}.ai-chat-message.assistant .ai-chat-message-content{background:var(--chat-assistant-bg,transparent);color:var(--chat-assistant-text,#000)}.ai-chat-message-timestamp{color:var(--chat-text-muted,#71717a);font-size:var(--chat-text-xs,12px);margin-top:var(--chat-space-xs,4px);padding:0 var(--chat-space-xs,4px)}.ai-chat-message.streaming .ai-chat-message-content:after{animation:ai-chat-cursor-blink .8s infinite;content:\"▋\";margin-left:2px;opacity:.7}@keyframes ai-chat-message-appear{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-cursor-blink{0%,50%{opacity:1}51%,to{opacity:0}}.ai-chat-message.fullpage .ai-chat-message-content{font-size:var(--chat-text-lg,18px);padding:var(--chat-space-md,16px) var(--chat-space-lg,24px)}.ai-chat-typing{gap:var(--chat-space-xs,4px);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-typing-dot{background:var(--chat-text-muted,#71717a)}.ai-chat-tool-row{padding:0 16px}.ai-chat-tool-gear{color:var(--text-primary,#3e3e3e)}.ai-chat-tool-badge{border-radius:8px}.ai-chat-tool-badge.loading{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-tool-badge.error{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-tool-check{color:#22c55e;flex-shrink:0}.ai-chat-tool-error{color:#ef4444;flex-shrink:0}.ai-chat-tool-badge .tool-name{max-width:150px;overflow:hidden;text-overflow:ellipsis}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear{color:#fff}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-badge.error,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge.error,.dark .ai-chat-tool-badge.error,[data-theme=dark] .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}.chakra-ui-dark .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.chakra-ui-dark .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.chakra-ui-dark .ai-chat-tool-badge.error,html.dark .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}.ai-chat-pin-input-group{align-items:center;display:flex;flex-wrap:nowrap;gap:8px;justify-content:center;margin:4px 0 8px}.ai-chat-pin-input{align-items:center;appearance:none;background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);box-sizing:border-box;color:var(--text-primary,#3e3e3e);display:inline-flex;flex:0 0 42px;font-family:inherit;font-size:18px;font-weight:600;height:46px;justify-content:center;line-height:1;max-width:42px;min-width:42px;outline:none;padding:0;text-align:center;transition:border-color .2s ease,box-shadow .2s ease;width:42px}.ai-chat-pin-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-pin-input:disabled{cursor:not-allowed;opacity:.6}.ai-chat-widget.dark .ai-chat-pin-input,.chakra-ui-dark .ai-chat-pin-input,.dark .ai-chat-pin-input,[data-theme=dark] .ai-chat-pin-input{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-pin-input:focus,.chakra-ui-dark .ai-chat-pin-input:focus,.dark .ai-chat-pin-input:focus,[data-theme=dark] .ai-chat-pin-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-action-button-secondary{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:9999px;color:var(--text-secondary,#6b7280);cursor:pointer;font-size:var(--text-sm,13px);font-weight:var(--font-weight-medium,500);padding:10px 16px;transition:all .2s ease;width:100%}.ai-chat-action-button-secondary:hover:not(:disabled){background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6));color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-button-secondary:disabled{cursor:not-allowed;opacity:.5}.ai-chat-widget.dark .ai-chat-action-button-secondary,.chakra-ui-dark .ai-chat-action-button-secondary,.dark .ai-chat-action-button-secondary,[data-theme=dark] .ai-chat-action-button-secondary{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#e5e7eb}.ai-chat-widget.dark .ai-chat-action-button-secondary:hover:not(:disabled),.chakra-ui-dark .ai-chat-action-button-secondary:hover:not(:disabled),.dark .ai-chat-action-button-secondary:hover:not(:disabled),[data-theme=dark] .ai-chat-action-button-secondary:hover:not(:disabled){background:rgba(59,130,246,.2);border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-action-appointment-list,.ai-chat-action-button-group{display:flex;flex-direction:column;gap:8px}.ai-chat-action-appointment-item{align-items:center;background:var(--bg-primary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-md,8px);display:flex;gap:12px;justify-content:space-between;padding:10px 12px}.ai-chat-widget.dark .ai-chat-action-appointment-item,.chakra-ui-dark .ai-chat-action-appointment-item,.dark .ai-chat-action-appointment-item,[data-theme=dark] .ai-chat-action-appointment-item{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.08)}.ai-chat-action-appointment-info{display:flex;flex-direction:column;gap:2px;min-width:0}.ai-chat-action-appointment-subject{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-widget.dark .ai-chat-action-appointment-subject,.chakra-ui-dark .ai-chat-action-appointment-subject,.dark .ai-chat-action-appointment-subject,[data-theme=dark] .ai-chat-action-appointment-subject{color:#fff}.ai-chat-action-appointment-time{color:var(--text-muted,#71717a);font-size:12px}.ai-chat-action-appointment-item .ai-chat-action-button-secondary{font-size:12px;padding:6px 12px;width:auto}.ai-chat-action-error-message{background:rgba(239,68,68,.1);border-radius:var(--radius-md,8px);color:#dc2626;font-size:var(--text-sm,13px);padding:12px}.ai-chat-widget.dark .ai-chat-action-error-message,.chakra-ui-dark .ai-chat-action-error-message,.dark .ai-chat-action-error-message,[data-theme=dark] .ai-chat-action-error-message{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-widget,.chat-ui{--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--radius-2xl:18px;--radius-pill:9999px;--radius-window-top:22px;--radius-window-bottom:44px;--radius-window-gutter:16px;--radius-chat-bubble:14px;--radius-preset-badge:13px;--radius-history-item:14px;--radius-action-badge:8px;--radius-input:62px;--space-xs:4px;--space-sm:8px;--space-md:16px;--space-lg:24px;--space-xl:32px;--text-xs:12px;--text-sm:14px;--text-md:15px;--text-lg:18px;--text-xl:22px;--text-2xl:28px;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--line-height-tight:1.3;--line-height-normal:1.4;--line-height-relaxed:1.6;--bg-primary:#fff;--bg-secondary:#f4f4f4;--bg-tertiary:#e5e7eb;--bg-hover:#e5e7eb;--text-primary:#3e3e3e;--text-secondary:#000;--text-muted:#71717a;--text-placeholder:#a1a1aa;--border-default:#d3d3d3;--border-subtle:#e5e7eb;--border-muted:#f4f4f5;--user-bg:#f4f3f0;--user-text:#000;--user-bg-hover:#e8e7e4;--agent-bg:transparent;--agent-text:#000;--input-bg:#f4f4f4;--input-border:#d3d3d3;--input-text:#000;--btn-primary-bg:#151515;--btn-primary-text:#f4f4f4;--btn-secondary-bg:transparent;--btn-secondary-text:#71717a;--spring-bounce:cubic-bezier(0.34,1.56,0.64,1);--spring-smooth:cubic-bezier(0.4,0,0.2,1);--spring-snappy:cubic-bezier(0.2,0,0,1);--duration-fast:0.15s;--duration-normal:0.25s;--duration-slow:0.35s;--shadow-sm:0 1px 2px rgba(0,0,0,.05);--shadow-md:0 2px 8px rgba(0,0,0,.1);--shadow-lg:0 4px 16px rgba(0,0,0,.12);--shadow-window:0px 0px 15px 9px rgba(0,0,0,.1);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03)}.ai-chat-widget.dark,.chat-ui.dark{--bg-primary:#282625;--bg-secondary:#4a4846;--bg-tertiary:#484848;--bg-hover:#484848;--text-primary:#fff;--text-secondary:#fff;--text-muted:#a1a1aa;--text-placeholder:#71717a;--border-default:#5d5b5b;--border-subtle:#5d5b5b;--border-muted:#5d5b5b;--user-bg:#484848;--user-text:#fff;--user-bg-hover:#5a5a5a;--agent-bg:transparent;--agent-text:#fff;--input-bg:#4a4846;--input-border:#5d5b5b;--input-text:#fff;--btn-primary-bg:#fff;--btn-primary-text:#312f2d;--btn-secondary-bg:transparent;--btn-secondary-text:#a1a1aa;--shadow-window:0px 0px 15px 9px rgba(0,0,0,.2);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03);--shadow-input:0px 0px 10px rgba(0,0,0,.15)}.ai-chat-widget,.chat-ui{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.ai-chat-widget-container{font-size:var(--text-sm);line-height:1.5;position:fixed;z-index:var(--widget-z-index,2147483647)}.ai-chat-widget-container.bottom-right{bottom:20px;right:20px}.ai-chat-widget-container.bottom-left{bottom:20px;left:20px}.ai-chat-widget-container.top-right{right:20px;top:20px}.ai-chat-widget-container.top-left{left:20px;top:20px}.ai-chat-widget-container.container-mode{position:absolute}@keyframes ai-chat-window-open{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes ai-chat-window-close{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.9) translateY(20px)}}@keyframes ai-chat-message-slide-in{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-welcome-fade-in{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-typing-pulse{0%,60%,to{opacity:.4;transform:translateY(0) scale(1)}30%{opacity:1;transform:translateY(-4px) scale(1.1)}}@keyframes ai-chat-gear-spin{to{transform:rotate(1turn)}}@keyframes ai-chat-tool-active{0%,to{background:var(--bg-secondary);opacity:1}50%{background:var(--bg-tertiary);opacity:1}}@keyframes ai-chat-feedback-morph{0%{opacity:.5;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes ai-chat-checkmark-pop{0%{opacity:0;transform:scale(0) rotate(-45deg)}50%{transform:scale(1.3) rotate(0deg)}to{opacity:1;transform:scale(1) rotate(0deg)}}@keyframes ai-chat-history-exit{to{opacity:0;transform:translateY(-18px)}}@keyframes ai-chat-tool-gradient{0%{background-position:200% 0}to{background-position:-200% 0}}.ai-chat-window{animation:ai-chat-window-open var(--duration-slow,.35s) var(--spring-bounce);background:var(--bg-primary,#fff);border:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) var(--radius-window-bottom,44px) var(--radius-window-bottom,44px);box-shadow:var(--shadow-window,0 0 15px 5px rgba(0,0,0,.08));display:flex;flex-direction:column;overflow:hidden;position:absolute;transform-origin:bottom right;z-index:2}.ai-chat-widget.dark .ai-chat-window{background:var(--bg-primary,#282625);border-color:var(--border-default,#5d5b5b);border-width:.7px}.ai-chat-window.closing{animation:ai-chat-window-close var(--duration-normal) var(--spring-smooth) forwards}.ai-chat-window.size-small{height:500px;width:380px}.ai-chat-window.size-medium,.ai-chat-window.size-small{max-height:calc(100vh - 100px);max-width:calc(100vw - 40px)}.ai-chat-window.size-medium{height:600px;width:420px}.ai-chat-window.size-large{height:700px;max-height:calc(100vh - 100px);max-width:calc(100vw - 40px);width:480px}.ai-chat-widget-container.bottom-right .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);right:0}.ai-chat-widget-container.bottom-left .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);left:0}.ai-chat-widget-container.top-right .ai-chat-window{right:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-widget-container.top-left .ai-chat-window{left:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-header{align-items:center;background:var(--bg-primary,#fff);border-bottom:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) 0 0;display:flex;justify-content:space-between;padding:12px var(--space-md,16px);position:relative;z-index:10}.ai-chat-widget.dark .ai-chat-header{background:var(--bg-primary,#282625);border-bottom-color:var(--border-default,#5d5b5b);border-bottom-width:.7px}.ai-chat-header.is-history{padding-left:var(--space-md)}.ai-chat-header.is-history .ai-chat-title{flex:1;min-width:0;overflow:hidden;padding-right:var(--space-lg);text-overflow:ellipsis;white-space:nowrap}.ai-chat-header-content{align-items:center;display:flex;flex:1;gap:var(--space-lg)}.ai-chat-header-actions{align-items:center;display:flex;gap:var(--space-sm)}.ai-chat-logo{border-radius:10px;height:36px;object-fit:cover;width:36px}.ai-chat-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-xl,22px);font-weight:var(--font-weight-bold,700);letter-spacing:-.02em}.ai-chat-widget.dark .ai-chat-title{color:var(--text-primary,#fff)}.ai-chat-close-button,.ai-chat-header-button{align-items:center;background:transparent;border:none;border-radius:var(--radius-md);color:var(--text-muted);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:32px}.ai-chat-close-button:hover,.ai-chat-header-button:hover{color:var(--text-primary)}.ai-chat-close-button:active,.ai-chat-header-button:active{transform:scale(.95)}.ai-chat-close-button svg,.ai-chat-header-button svg{height:22px;width:22px}.ai-chat-button{align-items:center;background:var(--button-color,var(--btn-primary-bg));border:1px solid var(--border-default,#d3d3d3);border-radius:50%;box-shadow:var(--shadow-button,0 0 15px 9px rgba(0,0,0,.03));color:var(--button-icon-color,var(--btn-primary-text));cursor:pointer;display:flex;height:var(--button-size,56px);justify-content:center;overflow:hidden;position:relative;transition:transform var(--duration-fast) ease;width:var(--button-size,56px);z-index:1}.ai-chat-button:hover{transform:scale(1.05)}.ai-chat-button:active{transform:scale(.98)}.ai-chat-button-svg{height:50%;min-height:24px;min-width:24px;transition:transform var(--duration-fast) ease;width:50%}.ai-chat-button.is-open .ai-chat-button-svg{transform:rotate(0deg)}.ai-chat-button-icon{font-size:1.5em;line-height:1}.ai-chat-welcome-bubble{animation:ai-chat-bubble-fade-in .3s ease-out;background:var(--button-color,var(--btn-primary-bg,#07f));border:none;border-radius:16px;box-shadow:none;box-sizing:border-box;color:var(--button-icon-color,var(--btn-primary-text,#fff));cursor:pointer;font-size:13px;font-weight:500;line-height:1.5;max-width:min(420px,90vw);padding:12px 32px 12px 16px;position:absolute;text-align:left;white-space:normal;width:auto;z-index:0}.ai-chat-welcome-bubble-close{align-items:center;background:transparent;border:none;border-radius:50%;color:inherit;cursor:pointer;display:flex;height:20px;justify-content:center;opacity:.8;padding:0;position:absolute;right:8px;top:8px;transition:opacity .15s ease,background .15s ease;width:20px}.ai-chat-welcome-bubble-close:hover{background:hsla(0,0%,100%,.2);opacity:1}.ai-chat-welcome-bubble-close svg{height:12px;width:12px}.ai-chat-welcome-bubble-arrow{border-bottom:8px solid transparent;border-top:8px solid transparent;height:0;position:absolute;width:0}.ai-chat-widget-container.bottom-right .ai-chat-welcome-bubble{bottom:50%;right:calc(100% + 12px);text-align:left;transform:translateY(50%)}.ai-chat-widget-container.bottom-left .ai-chat-welcome-bubble{bottom:50%;left:calc(100% + 12px);text-align:left;transform:translateY(50%)}.ai-chat-widget-container.top-right .ai-chat-welcome-bubble{right:calc(100% + 12px);text-align:left;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble{left:calc(100% + 12px);text-align:left;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.bottom-right .ai-chat-welcome-bubble-arrow{border-left:8px solid var(--button-color,var(--btn-primary-bg,#07f));right:-8px;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.bottom-left .ai-chat-welcome-bubble-arrow{border-right:8px solid var(--button-color,var(--btn-primary-bg,#07f));left:-8px;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.top-right .ai-chat-welcome-bubble-arrow{border-left:8px solid var(--button-color,var(--btn-primary-bg,#07f));right:-8px;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble-arrow{border-right:8px solid var(--button-color,var(--btn-primary-bg,#07f));left:-8px;top:50%;transform:translateY(-50%)}.ai-chat-welcome-bubble:hover{filter:brightness(1.1)}.ai-chat-widget-container.bottom-right .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-bottom-right}@keyframes ai-chat-bubble-fade-in-bottom-right{0%{opacity:0;transform:translateY(50%) translateX(8px)}to{opacity:1;transform:translateY(50%) translateX(0)}}.ai-chat-widget-container.bottom-left .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-bottom-left}@keyframes ai-chat-bubble-fade-in-bottom-left{0%{opacity:0;transform:translateY(50%) translateX(-8px)}to{opacity:1;transform:translateY(50%) translateX(0)}}.ai-chat-widget-container.top-right .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-top-right}@keyframes ai-chat-bubble-fade-in-top-right{0%{opacity:0;transform:translateY(-50%) translateX(8px)}to{opacity:1;transform:translateY(-50%) translateX(0)}}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-top-left}@keyframes ai-chat-bubble-fade-in-top-left{0%{opacity:0;transform:translateY(-50%) translateX(-8px)}to{opacity:1;transform:translateY(-50%) translateX(0)}}.ai-chat-trigger-pill{align-items:center;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);background:hsla(0,0%,100%,.08);border:1px solid hsla(0,0%,100%,.15);border-radius:9999px;color:var(--text-primary,#fff);cursor:pointer;display:flex;font-size:13px;font-weight:500;gap:8px;height:40px;justify-content:center;padding:0 20px;position:relative;transition:all .3s ease;white-space:nowrap;z-index:1}.ai-chat-trigger-pill.is-open{background:var(--button-color,var(--btn-primary-bg));border-color:var(--border-default,#d3d3d3);box-shadow:var(--shadow-button,0 0 15px 9px rgba(0,0,0,.03));height:56px;padding:0;width:56px}.ai-chat-trigger-pill.is-open .ai-chat-trigger-pill-icon{height:24px;width:24px}.ai-chat-trigger-pill:hover:not(.is-open){background:hsla(0,0%,100%,.12);border-color:hsla(0,0%,100%,.25)}.ai-chat-trigger-pill.is-open:hover{transform:scale(1.05)}.ai-chat-trigger-pill:active{transform:scale(.98)}.ai-chat-trigger-pill-icon{flex-shrink:0;height:16px;transition:all .3s ease;width:16px}.ai-chat-widget.light .ai-chat-trigger-pill{background:rgba(0,0,0,.04);border-color:rgba(0,0,0,.12);color:var(--text-primary,#1a1a1a)}.ai-chat-widget.light .ai-chat-trigger-pill:hover:not(.is-open){background:rgba(0,0,0,.08);border-color:rgba(0,0,0,.2)}.ai-chat-trigger-input-container{align-items:flex-end;display:flex;flex-direction:column;gap:8px}.ai-chat-widget-container.bottom-left .ai-chat-trigger-input-container,.ai-chat-widget-container.top-left .ai-chat-trigger-input-container{align-items:flex-start}.ai-chat-trigger-input-expand{align-items:center;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);background:hsla(0,0%,100%,.1);border:1px solid hsla(0,0%,100%,.15);border-radius:50%;color:hsla(0,0%,100%,.7);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:all .2s ease;width:32px}.ai-chat-trigger-input-expand:hover{background:hsla(0,0%,100%,.15);color:hsla(0,0%,100%,.9);transform:translateY(-2px)}.ai-chat-trigger-input-expand:active{transform:translateY(0)}.ai-chat-trigger-input-expand svg{height:16px;width:16px}.ai-chat-widget.light .ai-chat-trigger-input-expand{background:rgba(0,0,0,.05);border:1px solid rgba(0,0,0,.1);color:rgba(0,0,0,.5)}.ai-chat-widget.light .ai-chat-trigger-input-expand:hover{background:rgba(0,0,0,.1);color:rgba(0,0,0,.7)}.ai-chat-trigger-input-wrapper{max-width:calc(100vw - 40px);position:relative;z-index:1}.ai-chat-widget-container.trigger-input-bar .ai-chat-trigger-input-wrapper{width:348px}.ai-chat-widget-container.trigger-input-bar.size-medium .ai-chat-trigger-input-wrapper{width:388px}.ai-chat-widget-container.trigger-input-bar.size-large .ai-chat-trigger-input-wrapper{width:448px}.ai-chat-trigger-input{backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);background:hsla(0,0%,100%,.08);border:1px solid hsla(0,0%,100%,.12);border-radius:var(--radius-input,62px);box-shadow:0 4px 24px rgba(0,0,0,.15);box-sizing:border-box;color:var(--input-text,#fff);font-size:var(--text-md,15px);height:52px;outline:none;padding:6px 52px 6px 16px;transition:all .2s ease;width:100%}.ai-chat-trigger-input::placeholder{color:var(--text-placeholder,hsla(0,0%,100%,.5))}.ai-chat-trigger-input:focus{background:hsla(0,0%,100%,.12);border-color:hsla(0,0%,100%,.25)}.ai-chat-trigger-input-btn{align-items:center;background:var(--primary-color,var(--button-color,#07f));border:none;border-radius:50%;box-shadow:0 2px 8px rgba(0,119,255,.3);color:#fff;cursor:pointer;display:flex;height:40px;justify-content:center;position:absolute;right:6px;top:50%;transform:translateY(-50%);transition:all .2s ease;width:40px}.ai-chat-trigger-input-btn:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,119,255,.4);transform:translateY(-50%) scale(1.05)}.ai-chat-trigger-input-btn:active:not(:disabled){transform:translateY(-50%) scale(.95)}.ai-chat-trigger-input-btn:disabled{box-shadow:none;cursor:not-allowed;opacity:.4}.ai-chat-trigger-input-btn svg{height:18px;width:18px}.ai-chat-widget.light .ai-chat-trigger-input{backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);background:hsla(0,0%,100%,.7);border:1px solid rgba(0,0,0,.1);box-shadow:0 4px 24px rgba(0,0,0,.08);color:var(--input-text,#1a1a1a)}.ai-chat-widget.light .ai-chat-trigger-input::placeholder{color:var(--text-placeholder,rgba(0,0,0,.4))}.ai-chat-widget.light .ai-chat-trigger-input:focus{background:hsla(0,0%,100%,.85);border-color:rgba(0,0,0,.2)}.ai-chat-widget.light .ai-chat-trigger-input-btn{background:var(--primary-color,var(--button-color,#07f));box-shadow:0 2px 8px rgba(0,119,255,.25);color:#fff}.ai-chat-widget.light .ai-chat-trigger-input-btn:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,119,255,.35)}.ai-chat-widget-container.trigger-input-bar{align-items:flex-end;display:flex;flex-direction:column;gap:12px}.ai-chat-widget-container.trigger-input-bar.bottom-left,.ai-chat-widget-container.trigger-input-bar.top-left{align-items:flex-start}.ai-chat-widget-container.trigger-input-bar .ai-chat-window{bottom:auto;left:auto;order:-1;position:relative;right:auto;top:auto;width:100%}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-small{max-width:calc(100vw - 40px);width:380px}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-medium{max-width:calc(100vw - 40px);width:420px}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-large{max-width:calc(100vw - 40px);width:480px}.ai-chat-widget-container.trigger-input-bar .ai-chat-button,.ai-chat-widget-container.trigger-pill-text .ai-chat-button{display:none}.ai-chat-widget-container.trigger-pill-text.is-open{gap:8px}.ai-chat-input-container{background:var(--bg-primary,#fff);bottom:0;left:0;padding:8px 0 16px;position:absolute;right:0;z-index:10}.ai-chat-widget.dark .ai-chat-input-container{background:var(--bg-primary,#282625)}.ai-chat-input-container.separate{padding:0 var(--radius-window-gutter,16px) var(--radius-window-gutter,16px)}.ai-chat-input-wrapper{align-items:flex-end;background:var(--input-bg,#f4f4f4);border:1px solid var(--input-border,#d3d3d3);border-radius:var(--radius-input,62px);box-sizing:border-box;display:flex;gap:0;height:52px;overflow:hidden;padding:6px 6px 6px 16px;position:relative;transition:all var(--duration-fast,.15s) ease;z-index:5}.ai-chat-input-wrapper.multiline{border-radius:14px!important;min-height:64px;padding:10px 10px 10px 14px}.ai-chat-widget.dark .ai-chat-input-wrapper{background:var(--input-bg,#4a4846);border-color:var(--input-border,#5d5b5b);border-width:.7px;box-shadow:var(--shadow-input,0 0 10px rgba(0,0,0,.15))}.ai-chat-input-wrapper:focus-within{border-color:var(--text-muted,#a1a1aa)}.ai-chat-input{word-wrap:break-word!important;background:transparent!important;border:none!important;border-radius:0!important;box-shadow:none!important;box-sizing:border-box!important;color:var(--input-text,#000)!important;flex:1!important;font-family:inherit!important;font-size:var(--text-md,15px)!important;height:40px!important;line-height:20px!important;margin:0!important;max-height:40px!important;min-height:40px!important;min-width:0!important;outline:none!important;overflow-wrap:anywhere!important;overflow-x:hidden!important;overflow-y:auto!important;padding:10px var(--space-sm,8px)!important;resize:none!important;white-space:pre-wrap!important;width:0!important;word-break:break-word!important}.ai-chat-widget.dark .ai-chat-input{color:var(--input-text,#fff)}.ai-chat-input::placeholder{color:var(--text-placeholder,#a1a1aa)}.ai-chat-widget.dark .ai-chat-input::placeholder{color:var(--text-placeholder,#52525b)}.ai-chat-file-button{align-items:center;align-self:center;background:transparent;border:none;color:var(--text-placeholder);cursor:pointer;display:flex;flex-shrink:0;height:28px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:28px}.ai-chat-file-button:hover{color:var(--text-secondary)}.ai-chat-file-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-send-button{align-items:center;align-self:center;background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));border:none;border-radius:50%;color:var(--button-icon-color,var(--btn-primary-text,#f4f4f4));cursor:pointer;display:flex;flex-shrink:0;height:40px;justify-content:center;min-height:40px;min-width:40px;padding:0;transition:all var(--duration-fast,.15s) ease;width:40px}.ai-chat-widget.dark .ai-chat-send-button{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));color:var(--button-icon-color,var(--btn-primary-text,#f4f4f4))}.ai-chat-widget.dark .ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button:hover:not(:disabled){opacity:.8}.ai-chat-send-button:active:not(:disabled){transform:scale(.95)}.ai-chat-send-button:disabled{cursor:not-allowed;opacity:.3}.ai-chat-file-list{display:flex;flex-wrap:wrap;gap:var(--space-sm);padding:var(--space-sm) var(--space-sm)}.ai-chat-file-item{align-items:center;background:rgba(0,0,0,.05);border-radius:6px;display:flex;font-size:var(--text-xs);gap:var(--space-sm);padding:6px 10px}.ai-chat-file-extension{background:var(--btn-primary-bg);border-radius:3px;color:var(--btn-primary-text);display:inline-block;font-size:10px;font-weight:var(--font-weight-semibold);min-width:40px;padding:2px 6px;text-align:center;text-transform:uppercase}.ai-chat-file-info{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.ai-chat-file-name{font-weight:var(--font-weight-medium);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-file-size{color:var(--text-muted);font-size:10px;opacity:.7}.ai-chat-file-remove{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;justify-content:center;opacity:.5;padding:var(--space-xs);transition:opacity var(--duration-fast) ease}.ai-chat-file-remove:hover{opacity:1}.ai-chat-data-policy{bottom:2px;color:var(--text-muted,#71717a);font-size:9px;left:0;line-height:1.4;opacity:.5;pointer-events:auto;position:absolute;right:0;text-align:center}.ai-chat-widget.dark .ai-chat-data-policy{color:var(--text-muted,#a1a1aa)}.ai-chat-data-policy-link{background:none;border:none;color:var(--text-muted,#71717a);cursor:pointer;font-family:inherit;font-size:inherit;margin:0;padding:0;text-decoration:underline;text-underline-offset:2px;transition:color .15s ease}.ai-chat-data-policy-link:hover{color:var(--text-secondary,#52525b)}.ai-chat-widget.dark .ai-chat-data-policy-link{color:var(--text-muted,#a1a1aa)}.ai-chat-widget.dark .ai-chat-data-policy-link:hover{color:var(--text-secondary,#d4d4d8)}.ai-chat-page-disclaimer{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:10px;gap:4px;justify-content:center;line-height:1.4;opacity:.7;padding:8px 16px;text-align:center}.ai-chat-widget.dark .ai-chat-page-disclaimer{color:var(--text-muted,#a1a1aa)}.ai-chat-page-disclaimer-link{background:none;border:none;color:var(--text-muted,#71717a);cursor:pointer;font-family:inherit;font-size:inherit;margin:0;padding:0;text-decoration:underline;text-underline-offset:2px;transition:color .15s ease}.ai-chat-page-disclaimer-link:hover{color:var(--text-secondary,#52525b)}.ai-chat-widget.dark .ai-chat-page-disclaimer-link{color:var(--text-muted,#a1a1aa)}.ai-chat-widget.dark .ai-chat-page-disclaimer-link:hover{color:var(--text-secondary,#d4d4d8)}.ai-chat-messages{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;align-items:stretch;background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;gap:var(--space-md,16px);justify-content:flex-start;overflow-x:hidden;overflow-y:auto;padding:0 var(--space-md,16px) 100px;position:relative;scroll-behavior:smooth;scrollbar-width:none}.ai-chat-widget.dark .ai-chat-messages{background:var(--bg-primary,#18181b)}.ai-chat-messages::-webkit-scrollbar{display:none}.ai-chat-message{animation:ai-chat-message-slide-in .2s var(--spring-bounce);display:flex;flex-direction:column;max-width:90%}.ai-chat-message.user{align-items:flex-end;align-self:flex-end}.ai-chat-message.assistant{align-items:flex-start;align-self:flex-start;max-width:100%;width:100%}.ai-chat-message.tool{align-self:stretch;max-width:none;padding:0}.ai-chat-message-content{word-wrap:break-word;border-radius:18px;font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);overflow-wrap:break-word;padding:8px 14px}.ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#f4f3f0);border-radius:18px;color:var(--user-text,#000)}.ai-chat-widget.dark .ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#484848);color:var(--user-text,#fff)}.ai-chat-message.assistant .ai-chat-message-content{background:var(--agent-bg,transparent);box-sizing:border-box;color:var(--agent-text,#000);padding:0;width:100%}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content{color:var(--agent-text,#fff)}.ai-chat-message-timestamp{color:var(--text-muted,#71717a);font-size:var(--text-xs,12px);margin-top:var(--space-xs,4px);padding:0 var(--space-xs,4px)}.ai-chat-welcome{animation:ai-chat-welcome-fade-in .3s var(--spring-smooth);display:flex;flex-direction:column;gap:var(--space-md,16px);padding:var(--space-lg,24px) 0}.ai-chat-welcome-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-2xl,28px);font-weight:var(--font-weight-bold,700);line-height:var(--line-height-tight,1.3)}.ai-chat-widget.dark .ai-chat-welcome-title{color:var(--text-primary,#fff)}.ai-chat-welcome-text{color:var(--text-secondary,#000);font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);max-width:100%}.ai-chat-widget.dark .ai-chat-welcome-text{color:var(--text-secondary,#fff)}.ai-chat-typing{align-items:center;display:flex;gap:var(--space-xs,4px);padding:var(--space-sm,8px) var(--space-md,16px)}.ai-chat-typing-dot{animation:ai-chat-typing-bounce 1.4s ease-in-out infinite both;background:var(--text-muted,#71717a);border-radius:50%;height:8px;width:8px}.ai-chat-typing-dot:first-child{animation-delay:-.32s}.ai-chat-typing-dot:nth-child(2){animation-delay:-.16s}.ai-chat-typing-dot:nth-child(3){animation-delay:0s}@keyframes ai-chat-typing-bounce{0%,80%,to{opacity:.4;transform:scale(.6)}40%{opacity:1;transform:scale(1)}}.ai-chat-scroll-button{align-items:center;background:var(--bg-secondary,#f4f4f5);border:1px solid var(--border-subtle,rgba(0,0,0,.1));border-radius:50%;bottom:80px;box-shadow:0 2px 8px rgba(0,0,0,.1);color:var(--text-secondary,#71717a);cursor:pointer;display:flex;height:36px;justify-content:center;left:50%;opacity:0;pointer-events:none;position:absolute;transform:translateX(-50%);transition:background .15s ease,box-shadow .15s ease,opacity .15s ease,visibility .15s ease;visibility:hidden;width:36px;z-index:15}.ai-chat-scroll-button.visible{opacity:1;pointer-events:auto;visibility:visible}.ai-chat-scroll-button:hover{background:var(--bg-tertiary,#e4e4e7);box-shadow:0 4px 12px rgba(0,0,0,.15)}.ai-chat-scroll-button:active{background:var(--bg-tertiary,#d4d4d8)}.ai-chat-widget.dark .ai-chat-scroll-button{background:var(--bg-secondary,#3f3f46);border-color:var(--border-subtle,hsla(0,0%,100%,.1));box-shadow:0 2px 8px rgba(0,0,0,.3);color:var(--text-secondary,#a1a1aa)}.ai-chat-widget.dark .ai-chat-scroll-button:hover{background:var(--bg-tertiary,#52525b);box-shadow:0 4px 12px rgba(0,0,0,.4)}.ai-chat-error{background:var(--bg-secondary);border-radius:var(--radius-chat-bubble);color:var(--text-primary);font-size:var(--text-md);margin:0 auto;padding:10px var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content p{margin:0 0 var(--space-sm) 0}.ai-chat-message.assistant .ai-chat-message-content p:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content h1{font-size:1.5em}.ai-chat-message.assistant .ai-chat-message-content h1,.ai-chat-message.assistant .ai-chat-message-content h2{color:var(--text-primary,#3e3e3e);font-weight:var(--font-weight-bold,700);line-height:var(--line-height-tight,1.3);margin:var(--space-md,16px) 0 var(--space-sm,8px) 0}.ai-chat-message.assistant .ai-chat-message-content h2{font-size:1.3em}.ai-chat-message.assistant .ai-chat-message-content h3{color:var(--text-primary,#3e3e3e);font-size:1.15em;font-weight:var(--font-weight-semibold,600);line-height:var(--line-height-tight,1.3);margin:var(--space-sm,8px) 0 var(--space-xs,4px) 0}.ai-chat-message.assistant .ai-chat-message-content h4,.ai-chat-message.assistant .ai-chat-message-content h5,.ai-chat-message.assistant .ai-chat-message-content h6{color:var(--text-primary,#3e3e3e);font-size:1em;font-weight:var(--font-weight-semibold,600);line-height:var(--line-height-tight,1.3);margin:var(--space-sm,8px) 0 var(--space-xs,4px) 0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h1,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h2,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h3,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h4,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h5,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h6{color:var(--text-primary,#fff)}.ai-chat-message.assistant .ai-chat-message-content>h1:first-child,.ai-chat-message.assistant .ai-chat-message-content>h2:first-child,.ai-chat-message.assistant .ai-chat-message-content>h3:first-child,.ai-chat-message.assistant .ai-chat-message-content>h4:first-child,.ai-chat-message.assistant .ai-chat-message-content>h5:first-child,.ai-chat-message.assistant .ai-chat-message-content>h6:first-child{margin-top:0}.ai-chat-message.assistant .ai-chat-message-content ul{list-style-type:disc;margin:var(--space-sm,8px) 0;padding-left:var(--space-lg,24px)}.ai-chat-message.assistant .ai-chat-message-content ul ul{list-style-type:circle;margin:var(--space-xs,4px) 0}.ai-chat-message.assistant .ai-chat-message-content ul ul ul{list-style-type:square}.ai-chat-message.assistant .ai-chat-message-content ol{list-style-type:decimal;margin:var(--space-sm,8px) 0;padding-left:var(--space-lg,24px)}.ai-chat-message.assistant .ai-chat-message-content ol ol{list-style-type:lower-alpha;margin:var(--space-xs,4px) 0}.ai-chat-message.assistant .ai-chat-message-content ol ol ol{list-style-type:lower-roman}.ai-chat-message.assistant .ai-chat-message-content li{margin-bottom:var(--space-xs,4px);padding-left:var(--space-xs,4px)}.ai-chat-message.assistant .ai-chat-message-content li:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content li>ol,.ai-chat-message.assistant .ai-chat-message-content li>ul{margin-top:var(--space-xs,4px)}.ai-chat-message.assistant .ai-chat-message-content code{background:rgba(0,0,0,.05);border-radius:var(--radius-sm);font-family:SF Mono,Monaco,Cascadia Code,monospace;font-size:.9em;padding:2px 6px}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content code{background:hsla(0,0%,100%,.1)}.ai-chat-message.assistant .ai-chat-message-content pre{background:rgba(0,0,0,.05);border-radius:var(--radius-md);margin:var(--space-sm) 0;overflow-x:auto;padding:var(--space-sm)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content pre{background:hsla(0,0%,100%,.05)}.ai-chat-message.assistant .ai-chat-message-content pre code{background:transparent;padding:0}.ai-chat-message.assistant .ai-chat-message-content a{color:var(--btn-primary-bg);text-decoration:underline}.ai-chat-message.assistant .ai-chat-message-content strong{font-weight:var(--font-weight-semibold)}.ai-chat-message.assistant .ai-chat-message-content blockquote{border-left:3px solid var(--border-default);color:var(--text-muted);margin:var(--space-sm) 0;padding-left:var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content hr{border:none;border-top:1px solid var(--border-subtle,rgba(0,0,0,.1));margin:var(--space-lg,24px) 0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content hr{border-top-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content .table-wrapper{border:1px solid var(--border-subtle,rgba(0,0,0,.1));border-radius:var(--radius-md,8px);box-sizing:border-box;display:block;margin:var(--space-sm) var(--space-sm);max-width:100%;overflow:hidden;width:auto}.ai-chat-message.assistant .ai-chat-message-content .table-scroll{max-width:100%;overflow-x:auto;overflow-y:hidden;width:100%}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content .table-wrapper{border-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content table{border-collapse:collapse;font-size:var(--text-sm);min-width:100%;width:max-content}.ai-chat-message.assistant .ai-chat-message-content td,.ai-chat-message.assistant .ai-chat-message-content th{border-bottom:1px solid var(--border-subtle,rgba(0,0,0,.1));border-right:1px solid var(--border-subtle,rgba(0,0,0,.1));padding:var(--space-sm);text-align:left}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content td,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content th{border-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content td:last-child,.ai-chat-message.assistant .ai-chat-message-content th:last-child{border-right:none}.ai-chat-message.assistant .ai-chat-message-content tr:last-child td{border-bottom:none}.ai-chat-message.assistant .ai-chat-message-content th{background:rgba(0,0,0,.03);font-weight:var(--font-weight-semibold);white-space:nowrap}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content th{background:hsla(0,0%,100%,.05)}.ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:rgba(0,0,0,.02)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:hsla(0,0%,100%,.03)}.ai-chat-suggested-questions{align-self:flex-end;margin:0;padding:16px 0 0;width:100%}.ai-chat-suggested-questions-list{align-items:center;display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.ai-chat-suggested-question{align-items:center;background:transparent;border:1px solid var(--border-default,#d4d4d8);border-radius:var(--radius-preset-badge,18px);color:var(--text-primary,#18181b);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:background .15s ease,border-color .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-widget.dark .ai-chat-suggested-question{background:transparent;border-color:var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}.ai-chat-suggested-question-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-suggested-question:hover{background:var(--bg-hover,#f4f4f5);border-color:var(--border-default,#d4d4d8)}.ai-chat-widget.dark .ai-chat-suggested-question:hover{background:var(--bg-hover,#3f3f46);border-color:var(--border-subtle,#52525b)}.ai-chat-suggested-question:active{transform:scale(.98)}.ai-chat-suggested-question.action-type{border:none}.ai-chat-suggested-question.action-type,.ai-chat-widget.dark .ai-chat-suggested-question.action-type{background:var(--primary-color,var(--button-color,#ef4444));color:var(--button-icon-color,#fff)}.ai-chat-suggested-question.action-type:hover{background:var(--primary-color,var(--button-color,#ef4444));opacity:.9}.ai-chat-suggested-question-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-suggested-question:not(.action-type) .ai-chat-suggested-question-icon{display:none}.ai-chat-follow-up-suggestions{box-sizing:border-box;margin:0;padding:8px 16px 0;width:100%}.ai-chat-follow-up-list{align-items:flex-end;display:flex;flex-direction:column;gap:6px}.ai-chat-follow-up-item{align-items:center;border:none;border-radius:var(--radius-preset-badge,18px);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:opacity .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-follow-up-item,.ai-chat-widget.dark .ai-chat-follow-up-item{background:var(--primary-color,var(--button-color,#07f));color:var(--button-icon-color,#fff)}.ai-chat-follow-up-item:hover{opacity:.9}.ai-chat-follow-up-item:active{transform:scale(.98)}.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-default,#d4d4d8);color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type,.dark .ai-chat-follow-up-item.question-type,[data-color-mode=dark] .ai-chat-follow-up-item.question-type,[data-theme=dark] .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}}.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#f4f4f5);opacity:1}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type:hover,.dark .ai-chat-follow-up-item.question-type:hover,[data-color-mode=dark] .ai-chat-follow-up-item.question-type:hover,[data-theme=dark] .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}}.ai-chat-follow-up-item.action-type{background:var(--primary-color,var(--button-color,#07f));border:none;color:var(--button-icon-color,#fff)}.ai-chat-follow-up-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-follow-up-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-feedback-buttons{align-items:center;display:flex;gap:var(--space-xs)}.ai-chat-feedback{align-items:center;display:inline-flex;gap:0;height:20px}.ai-chat-feedback-button{align-items:center;background:transparent!important;border:none;border-radius:var(--radius-sm);color:var(--text-placeholder);cursor:pointer;display:flex;font-size:var(--text-sm);height:20px;justify-content:center;padding:var(--space-xs);transition:all var(--duration-fast) var(--spring-bounce)}.ai-chat-feedback-button:hover:not(:disabled){background:none!important;color:var(--text-secondary)}.ai-chat-feedback-button:active:not(:disabled){transform:scale(.9)}.ai-chat-feedback-button:disabled{cursor:not-allowed;opacity:.4}.ai-chat-feedback-button.active{background:none!important;color:var(--text-primary)}.ai-chat-feedback.submitted{align-items:center;animation:ai-chat-feedback-morph .3s var(--spring-bounce);gap:var(--space-xs)}.ai-chat-feedback-message{align-items:center;display:flex;gap:4px;margin-left:var(--space-xxs)}.ai-chat-feedback-checkmark{animation:ai-chat-checkmark-pop .3s var(--spring-bounce);color:#10b981;font-size:var(--text-md);font-weight:700}.ai-chat-feedback-text{color:#10b981;font-size:var(--text-xs);font-weight:var(--font-weight-medium)}.ai-chat-history-panel{background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;overflow:hidden}.ai-chat-widget.dark .ai-chat-history-panel{background:var(--bg-primary,#18181b)}.ai-chat-history-empty,.ai-chat-history-loading{align-items:center;color:var(--text-muted);display:flex;flex:1;font-size:var(--text-sm);justify-content:center;padding:var(--space-lg);text-align:center}.ai-chat-history-list{-ms-overflow-style:none;display:flex;flex:1;flex-direction:column;gap:var(--space-sm);overflow-y:auto;padding:var(--space-xs) var(--space-md) 120px;scrollbar-width:none}.ai-chat-history-list::-webkit-scrollbar{display:none}.ai-chat-history-list.exiting{animation:ai-chat-history-exit .22s var(--spring-smooth) forwards}.ai-chat-history-item{align-items:center;background:var(--user-bg,#f4f4f5);border-radius:var(--radius-history-item,15px);display:flex;flex:0 0 auto;flex-direction:row;height:var(--history-item-height,36px);margin:0;overflow:hidden;transition:background var(--duration-fast,.15s) ease;width:100%}.ai-chat-history-item-content{align-items:center;background:transparent;border:none;cursor:pointer;display:flex;flex:1;flex-direction:row;height:100%;min-width:0;padding:0 var(--space-xs,4px) 0 var(--space-md,16px);text-align:left}.ai-chat-widget.dark .ai-chat-history-item{background:var(--user-bg,#27272a)}.ai-chat-history-item:hover{background:var(--user-bg-hover,#e5e7eb)}.ai-chat-widget.dark .ai-chat-history-item:hover{background:var(--user-bg-hover,#3f3f46)}.ai-chat-history-item.active{background:var(--user-bg-hover,#e5e7eb)}.ai-chat-widget.dark .ai-chat-history-item.active{background:var(--user-bg-hover,#3f3f46)}.ai-chat-history-item-preview{color:var(--text-primary,#18181b);flex:1;font-size:var(--text-sm,14px);font-weight:var(--font-weight-medium,500);line-height:var(--line-height-normal,1.4);margin-bottom:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-widget.dark .ai-chat-history-item-preview{color:var(--text-primary,#fafafa)}.ai-chat-history-item.active .ai-chat-history-item-preview{font-weight:var(--font-weight-medium)}.ai-chat-history-item-meta{display:none}.ai-chat-history-item-delete{align-items:center;background:transparent;border:none;border-radius:var(--radius-sm,6px);color:var(--text-muted,#71717a);cursor:pointer;display:flex;flex-shrink:0;height:24px;justify-content:center;margin-left:auto;margin-right:var(--space-xs,4px);opacity:0;transition:opacity var(--duration-fast,.15s) ease,background var(--duration-fast,.15s) ease,color var(--duration-fast,.15s) ease;width:24px}.ai-chat-history-item-delete svg{height:14px;width:14px}.ai-chat-history-item:hover .ai-chat-history-item-delete{opacity:1}.ai-chat-history-item-delete:hover{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-widget.dark .ai-chat-history-item-delete:hover{background:rgba(239,68,68,.2);color:#f87171}.ai-chat-tool-row{align-items:center;display:flex;gap:10px;margin:2px 0;padding:0}.ai-chat-tool-gear{color:#1f2937;flex-shrink:0;height:20px;width:20px}.ai-chat-tool-gear.spinning{animation:ai-chat-gear-spin 1.5s linear infinite}.ai-chat-tool-badges{align-items:center;display:flex;flex-wrap:wrap;gap:8px}.ai-chat-tool-badge{align-items:center;background:#e5e7eb;border:1px solid #d1d5db;border-radius:var(--radius-action-badge,8px);color:#1f2937;display:inline-flex;font-size:12px;font-weight:500;gap:4px;line-height:1.2;padding:5px 12px;transition:all .2s ease;white-space:nowrap}.ai-chat-tool-badge.loading{animation:ai-chat-tool-gradient 2s linear infinite;background:linear-gradient(90deg,var(--tool-loading-bg-1,#e0e0e0) 0,var(--tool-loading-bg-2,#f0f0f0) 25%,var(--tool-loading-bg-3,#fff) 50%,var(--tool-loading-bg-2,#f0f0f0) 75%,var(--tool-loading-bg-1,#e0e0e0) 100%);background-size:200% 100%;color:var(--tool-loading-text,#1a1a1a);position:relative}.ai-chat-widget:not(.dark) .ai-chat-tool-badge.loading{--tool-loading-bg-1:#2a2a2a;--tool-loading-bg-2:#3a3a3a;--tool-loading-bg-3:#4a4a4a;--tool-loading-text:#fff}.ai-chat-tool-badge.completed{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.chakra-ui-dark .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.chakra-ui-dark .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.ai-chat-tool-badge.error{background:var(--tool-error-bg,rgba(239,68,68,.15));color:var(--tool-error-text,#ef4444)}.ai-chat-tool-badge .ai-chat-tool-check{color:#fff;flex-shrink:0}.ai-chat-tool-badge .ai-chat-tool-error{color:#ef4444;flex-shrink:0}.tool-name{font-weight:500;line-height:1.2;white-space:nowrap}.ai-chat-tool-action{box-sizing:border-box;padding:0;width:100%}@keyframes ai-chat-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.ai-chat-action-skeleton-item{animation:ai-chat-skeleton-pulse 1.5s ease-in-out infinite;background:var(--bg-secondary,#e5e7eb)}.ai-chat-widget.dark .ai-chat-action-skeleton-item,.chakra-ui-dark .ai-chat-action-skeleton-item,.dark .ai-chat-action-skeleton-item,[data-theme=dark] .ai-chat-action-skeleton-item{background:hsla(0,0%,100%,.1)}.ai-chat-action-skeleton-content{display:flex;flex-direction:column;gap:16px}.ai-chat-action-skeleton-header{align-items:center;display:flex;gap:10px}.ai-chat-action-skeleton-box{background:rgba(0,0,0,.08);border-radius:10px;display:flex;flex-direction:column;gap:8px;padding:14px}.ai-chat-widget.dark .ai-chat-action-skeleton-box,.chakra-ui-dark .ai-chat-action-skeleton-box,.dark .ai-chat-action-skeleton-box,[data-theme=dark] .ai-chat-action-skeleton-box{background:rgba(0,0,0,.25)}.ai-chat-action-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f9fafb);border:1px solid var(--border-subtle,rgba(0,0,0,.06));border-radius:12px;box-sizing:border-box;margin-top:4px;padding:16px;transition:all .2s ease;width:100%}.ai-chat-widget.dark .ai-chat-action-card,.chakra-ui-dark .ai-chat-action-card,.dark .ai-chat-action-card,[data-theme=dark] .ai-chat-action-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-action-booked{background:var(--bg-secondary,#f9fafb);border:1px solid var(--border-subtle,rgba(0,0,0,.06))}.ai-chat-widget.dark .ai-chat-action-booked,.chakra-ui-dark .ai-chat-action-booked,.dark .ai-chat-action-booked,[data-theme=dark] .ai-chat-action-booked{background:var(--bg-secondary,#3a3a3a)}.ai-chat-action-header{align-items:center;color:var(--text-primary,#3e3e3e);display:flex;font-size:var(--text-md,15px);font-weight:var(--font-weight-semibold,600);gap:var(--space-sm,8px);margin-bottom:var(--space-md,16px)}.ai-chat-widget.dark .ai-chat-action-header,.chakra-ui-dark .ai-chat-action-header,.dark .ai-chat-action-header,[data-theme=dark] .ai-chat-action-header{color:var(--text-primary,#fff)}.ai-chat-action-icon{color:var(--action-accent,var(--primary-color,#3b82f6));flex-shrink:0;height:20px;width:20px}.ai-chat-action-success-icon-wrapper{align-items:center;background:var(--action-accent,var(--primary-color,#22c55e));border-radius:50%;color:#fff;display:flex;flex-shrink:0;height:24px;justify-content:center;width:24px}.ai-chat-action-icon-success{color:currentColor;height:14px;width:14px}.ai-chat-action-detail-box{background:var(--bg-primary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-md,8px);display:flex;flex-direction:column;gap:4px;padding:12px 16px}.ai-chat-widget.dark .ai-chat-action-detail-box,.chakra-ui-dark .ai-chat-action-detail-box,.dark .ai-chat-action-detail-box,[data-theme=dark] .ai-chat-action-detail-box{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.05)}.ai-chat-action-label-small{color:var(--text-muted,#71717a);font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.ai-chat-action-value-large{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:500}.ai-chat-widget.dark .ai-chat-action-value-large,.chakra-ui-dark .ai-chat-action-value-large,.dark .ai-chat-action-value-large,[data-theme=dark] .ai-chat-action-value-large{color:#fff}.ai-chat-action-body{display:flex;flex-direction:column;gap:var(--space-md,16px)}.ai-chat-action-close-btn{align-items:center;background:transparent;border:none;border-radius:6px;color:var(--ai-chat-fg-muted,#6b7280);cursor:pointer;display:flex;height:28px;justify-content:center;padding:0;position:absolute;right:12px;top:12px;transition:all .15s ease;width:28px;z-index:10}.ai-chat-action-close-btn:hover{background:var(--ai-chat-bg-muted,#f3f4f6);color:var(--ai-chat-fg,#1f2937)}.ai-chat-action-close-btn:active{transform:scale(.95)}.ai-chat-action-close-btn:focus-visible{outline:2px solid var(--ai-chat-accent,#2563eb);outline-offset:2px}.ai-chat-action-card--closable,.ai-chat-form-card--closable{position:relative}.ai-chat-action-card--closable .ai-chat-action-header,.ai-chat-form-card--closable .ai-chat-form-card__header{padding-right:40px}.ai-chat-widget.dark .ai-chat-action-close-btn:hover,.chakra-ui-dark .ai-chat-action-close-btn:hover,.dark .ai-chat-action-close-btn:hover,[data-theme=dark] .ai-chat-action-close-btn:hover{background:hsla(0,0%,100%,.1);color:var(--ai-chat-fg,#f3f4f6)}.ai-chat-action-field{display:flex;flex-direction:column;gap:var(--space-xs,6px)}.ai-chat-action-label{color:var(--text-secondary,#6b7280);font-size:var(--text-sm,13px);font-weight:var(--font-weight-medium,500)}.ai-chat-widget.dark .ai-chat-action-label,.chakra-ui-dark .ai-chat-action-label,.dark .ai-chat-action-label,[data-theme=dark] .ai-chat-action-label{color:var(--text-secondary,#a1a1aa)}.ai-chat-action-input{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);font-size:var(--text-sm,13px);outline:none;padding:10px 12px;transition:border-color .2s ease,box-shadow .2s ease}.ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-action-input::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-action-input,.chakra-ui-dark .ai-chat-action-input,.dark .ai-chat-action-input,[data-theme=dark] .ai-chat-action-input{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-input:focus,.chakra-ui-dark .ai-chat-action-input:focus,.dark .ai-chat-action-input:focus,[data-theme=dark] .ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-action-button{background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;color:#fff;cursor:pointer;font-size:var(--text-sm,13px);font-weight:var(--font-weight-semibold,600);padding:12px 16px;transition:all .2s ease;width:100%}.ai-chat-action-button:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}.ai-chat-action-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-action-link-button{align-items:center;background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;box-sizing:border-box;color:#fff;display:flex;font-size:14px;font-weight:600;gap:6px;justify-content:center;margin-top:8px;padding:12px;text-decoration:none;transition:all .2s ease;width:100%}.ai-chat-action-link-button:hover{opacity:.9;transform:translateY(-1px)}.ai-chat-action-error{background:rgba(239,68,68,.1);border-radius:var(--radius-md,8px);color:#dc2626;font-size:var(--text-sm,13px);padding:10px 12px}.ai-chat-widget.dark .ai-chat-action-error,.chakra-ui-dark .ai-chat-action-error,.dark .ai-chat-action-error,[data-theme=dark] .ai-chat-action-error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-action-hint{color:var(--text-muted,#9ca3af);font-size:var(--text-sm,13px);padding:var(--space-sm,8px);text-align:center}.ai-chat-action-date-grid{display:grid;gap:var(--space-xs,6px);grid-template-columns:repeat(auto-fill,minmax(90px,1fr))}.ai-chat-action-date-btn{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;font-size:var(--text-xs,12px);font-weight:var(--font-weight-medium,500);padding:8px 10px;text-align:center;transition:all .15s ease}.ai-chat-action-date-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-date-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-action-date-btn,.chakra-ui-dark .ai-chat-action-date-btn,.dark .ai-chat-action-date-btn,[data-theme=dark] .ai-chat-action-date-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-date-btn:hover,.chakra-ui-dark .ai-chat-action-date-btn:hover,.dark .ai-chat-action-date-btn:hover,[data-theme=dark] .ai-chat-action-date-btn:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-action-date-btn.active,.chakra-ui-dark .ai-chat-action-date-btn.active,.dark .ai-chat-action-date-btn.active,[data-theme=dark] .ai-chat-action-date-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-action-time-grid{display:grid;gap:var(--space-xs,6px);grid-template-columns:repeat(auto-fill,minmax(100px,1fr))}.ai-chat-action-time-btn{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;font-size:var(--text-xs,12px);font-weight:var(--font-weight-medium,500);padding:8px 10px;text-align:center;transition:all .15s ease}.ai-chat-action-time-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-time-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-action-time-btn,.chakra-ui-dark .ai-chat-action-time-btn,.dark .ai-chat-action-time-btn,[data-theme=dark] .ai-chat-action-time-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-time-btn:hover,.chakra-ui-dark .ai-chat-action-time-btn:hover,.dark .ai-chat-action-time-btn:hover,[data-theme=dark] .ai-chat-action-time-btn:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-action-time-btn.active,.chakra-ui-dark .ai-chat-action-time-btn.active,.dark .ai-chat-action-time-btn.active,[data-theme=dark] .ai-chat-action-time-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-link-preview{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-lg,12px);cursor:pointer;display:flex;flex-direction:column;margin-top:4px;overflow:hidden;padding:0!important;position:relative;transition:border-color .2s,box-shadow .2s,transform .2s}.ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 8px rgba(0,0,0,.1);transform:translateY(-1px)}.ai-chat-link-preview:focus{border-color:var(--action-accent);box-shadow:0 0 0 2px rgba(59,130,246,.2);outline:none}.ai-chat-widget.dark .ai-chat-link-preview,.chakra-ui-dark .ai-chat-link-preview,.dark .ai-chat-link-preview,[data-theme=dark] .ai-chat-link-preview{background:var(--bg-secondary,#3a3a3a);border-color:hsla(0,0%,100%,.08)}.ai-chat-widget.dark .ai-chat-link-preview:hover,.chakra-ui-dark .ai-chat-link-preview:hover,.dark .ai-chat-link-preview:hover,[data-theme=dark] .ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 12px rgba(0,0,0,.3)}.ai-chat-link-preview__image{aspect-ratio:1.91/1;background:var(--bg-muted,#e5e7eb);overflow:hidden;width:100%}.ai-chat-widget.dark .ai-chat-link-preview__image,.chakra-ui-dark .ai-chat-link-preview__image,.dark .ai-chat-link-preview__image,[data-theme=dark] .ai-chat-link-preview__image{background:hsla(0,0%,100%,.05)}.ai-chat-link-preview__image img{height:100%;object-fit:cover;width:100%}.ai-chat-link-preview__content{flex:1;padding:8px 10px}.ai-chat-link-preview__site{align-items:center;display:flex;gap:6px;margin-bottom:6px}.ai-chat-link-preview__favicon{border-radius:2px;flex-shrink:0;height:16px;width:16px}.ai-chat-link-preview__domain{color:var(--text-muted,#71717a);font-size:12px;letter-spacing:.5px;overflow:hidden;text-overflow:ellipsis;text-transform:uppercase;white-space:nowrap}.ai-chat-link-preview__title{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-primary,#3e3e3e);display:-webkit-box;font-size:15px;font-weight:600;line-height:1.3;margin:0 0 4px;overflow:hidden}.ai-chat-widget.dark .ai-chat-link-preview__title,.chakra-ui-dark .ai-chat-link-preview__title,.dark .ai-chat-link-preview__title,[data-theme=dark] .ai-chat-link-preview__title{color:#fff}.ai-chat-link-preview__description{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-muted,#71717a);display:-webkit-box;font-size:13px;line-height:1.4;margin:0;overflow:hidden}.ai-chat-link-preview__context{border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin:8px 0 0;padding-top:8px}.ai-chat-widget.dark .ai-chat-link-preview__context,.chakra-ui-dark .ai-chat-link-preview__context,.dark .ai-chat-link-preview__context,[data-theme=dark] .ai-chat-link-preview__context{border-color:hsla(0,0%,100%,.08)}.ai-chat-link-preview__arrow{align-items:center;background:var(--bg-primary,#fff);border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.1);color:var(--text-muted,#71717a);display:flex;height:28px;justify-content:center;opacity:0;position:absolute;right:12px;top:12px;transition:opacity .2s,background .2s;width:28px}.ai-chat-link-preview:hover .ai-chat-link-preview__arrow{opacity:1}.ai-chat-widget.dark .ai-chat-link-preview__arrow,.chakra-ui-dark .ai-chat-link-preview__arrow,.dark .ai-chat-link-preview__arrow,[data-theme=dark] .ai-chat-link-preview__arrow{background:hsla(0,0%,100%,.1);color:#fff}.ai-chat-link-preview--error{border-color:rgba(239,68,68,.3)}.ai-chat-link-preview--error:hover{border-color:rgba(239,68,68,.5)}.ai-chat-link-preview__error-text{color:#dc2626;font-size:12px;margin:4px 0 0}.ai-chat-widget.dark .ai-chat-link-preview__error-text,.chakra-ui-dark .ai-chat-link-preview__error-text,.dark .ai-chat-link-preview__error-text,[data-theme=dark] .ai-chat-link-preview__error-text{color:#fca5a5}.ai-chat-video-player{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border-radius:var(--radius-lg,12px);display:flex;flex-direction:column;gap:0;margin-top:4px;overflow:hidden;padding:0!important}.ai-chat-widget.dark .ai-chat-video-player,.chakra-ui-dark .ai-chat-video-player,.dark .ai-chat-video-player,[data-theme=dark] .ai-chat-video-player{background:var(--bg-secondary,#3a3a3a)}.ai-chat-video-player__header{align-items:center;color:var(--action-accent,var(--primary-color,#3b82f6));display:flex;gap:8px}.ai-chat-video-player__title{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:600}.ai-chat-widget.dark .ai-chat-video-player__title,.chakra-ui-dark .ai-chat-video-player__title,.dark .ai-chat-video-player__title,[data-theme=dark] .ai-chat-video-player__title{color:#fff}.ai-chat-video-player__container{aspect-ratio:16/9;background:#000;border-radius:8px;overflow:hidden;position:relative;width:100%}.ai-chat-video-player__thumbnail{cursor:pointer;height:100%;position:relative;width:100%}.ai-chat-video-player__thumbnail img{height:100%;object-fit:cover;width:100%}.ai-chat-video-player__placeholder{align-items:center;background:linear-gradient(135deg,#1a1a2e,#16213e);cursor:pointer;display:flex;flex-direction:column;gap:8px;height:100%;justify-content:center;position:relative;width:100%}.ai-chat-video-player__click-text{color:hsla(0,0%,100%,.7);font-size:13px}.ai-chat-video-player__play-btn{align-items:center;background:rgba(0,0,0,.7);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:64px;justify-content:center;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s,transform .2s;width:64px}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn{left:auto;position:relative;top:auto;transform:none}.ai-chat-video-player__play-btn:hover{background:rgba(0,0,0,.9);transform:translate(-50%,-50%) scale(1.05)}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn:hover{transform:scale(1.05)}.ai-chat-video-player__provider-badge{background:rgba(0,0,0,.8);border-radius:4px;bottom:8px;color:#fff;font-size:11px;font-weight:600;letter-spacing:.5px;padding:4px 8px;position:absolute;right:8px;text-transform:uppercase}.ai-chat-video-player__iframe,.ai-chat-video-player__video{border:none;height:100%;left:0;position:absolute;top:0;width:100%}.ai-chat-video-player__error{align-items:center;background:rgba(239,68,68,.1);color:#dc2626;display:flex;font-size:13px;height:100%;justify-content:center;padding:16px;text-align:center;width:100%}.ai-chat-widget.dark .ai-chat-video-player__error,.chakra-ui-dark .ai-chat-video-player__error,.dark .ai-chat-video-player__error,[data-theme=dark] .ai-chat-video-player__error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-video-player__context{color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin-top:4px;padding:8px 12px 12px}.ai-chat-location-card{background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:12px;overflow:hidden;padding:0}.ai-chat-widget.dark .ai-chat-location-card,.chakra-ui-dark .ai-chat-location-card,.dark .ai-chat-location-card,[data-theme=dark] .ai-chat-location-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-location-card--compact{border-radius:10px}.ai-chat-location-card--error{color:var(--text-muted,#71717a);padding:16px;text-align:center}.ai-chat-location-card__map{background:var(--bg-muted,#f4f4f5);position:relative;width:100%}.ai-chat-widget.dark .ai-chat-location-card__map,.chakra-ui-dark .ai-chat-location-card__map,.dark .ai-chat-location-card__map,[data-theme=dark] .ai-chat-location-card__map{background:rgba(0,0,0,.2)}.ai-chat-location-card__map iframe{border:none;display:block;height:100%;width:100%}.ai-chat-location-card__content{padding:12px}.ai-chat-location-card--compact .ai-chat-location-card__content{padding:10px}.ai-chat-location-card__header{align-items:center;display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.ai-chat-location-card__name{color:var(--text-primary,#18181b);flex:1;font-size:16px;font-weight:600;margin:0;min-width:0}.ai-chat-widget.dark .ai-chat-location-card__name,.chakra-ui-dark .ai-chat-location-card__name,.dark .ai-chat-location-card__name,[data-theme=dark] .ai-chat-location-card__name{color:#fff}.ai-chat-location-card--compact .ai-chat-location-card__name{font-size:14px}.ai-chat-location-card__type{background:var(--bg-muted,#f4f4f5);border-radius:10px;color:var(--text-muted,#71717a);font-size:11px;font-weight:500;letter-spacing:.5px;padding:2px 8px;text-transform:uppercase}.ai-chat-widget.dark .ai-chat-location-card__type,.chakra-ui-dark .ai-chat-location-card__type,.dark .ai-chat-location-card__type,[data-theme=dark] .ai-chat-location-card__type{background:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.7)}.ai-chat-location-card__status{border-radius:12px;font-size:12px;font-weight:500;padding:2px 8px}.ai-chat-location-card__status--open{background:#dcfce7;color:#16a34a}.ai-chat-location-card__status--closed{background:#fef2f2;color:#dc2626}.ai-chat-widget.dark .ai-chat-location-card__status--open,.chakra-ui-dark .ai-chat-location-card__status--open,.dark .ai-chat-location-card__status--open,[data-theme=dark] .ai-chat-location-card__status--open{background:rgba(34,197,94,.2);color:#4ade80}.ai-chat-widget.dark .ai-chat-location-card__status--closed,.chakra-ui-dark .ai-chat-location-card__status--closed,.dark .ai-chat-location-card__status--closed,[data-theme=dark] .ai-chat-location-card__status--closed{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-location-card__address{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__address svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__hours{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;margin-bottom:8px}.ai-chat-location-card__hours svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__hours-list{flex:1}.ai-chat-location-card__hours-toggle{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;font:inherit;gap:4px;padding:0}.ai-chat-location-card__hours-toggle:hover{text-decoration:underline}.ai-chat-location-card__hours-full{list-style:none;margin:8px 0 0;padding:0}.ai-chat-location-card__hours-full li{display:flex;font-size:12px;justify-content:space-between;padding:4px 0}.ai-chat-location-card__hours-today{color:var(--text-primary,#18181b);font-weight:600}.ai-chat-widget.dark .ai-chat-location-card__hours-today,.chakra-ui-dark .ai-chat-location-card__hours-today,.dark .ai-chat-location-card__hours-today,[data-theme=dark] .ai-chat-location-card__hours-today{color:#fff}.ai-chat-location-card__phone{align-items:center;background:none;border:none;color:var(--action-accent,#3b82f6);cursor:pointer;display:flex;font-size:13px;gap:6px;margin-bottom:12px;padding:0}.ai-chat-location-card__phone:hover{text-decoration:underline}.ai-chat-location-card__actions{display:flex;gap:8px;justify-content:flex-start;width:100%}.ai-chat-location-card__button{align-items:center;background:var(--action-accent,#3b82f6);border:none;border-radius:20px;color:#fff;cursor:pointer;display:flex;flex:1;font-size:13px;font-weight:500;gap:6px;justify-content:center;padding:10px 16px;transition:opacity .2s}.ai-chat-location-card__button:hover{opacity:.9}.ai-chat-location-card--compact .ai-chat-location-card__button{font-size:12px;padding:8px 12px}.ai-chat-location-card__link{align-items:center;background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:20px;color:var(--text-primary,#18181b);display:flex;font-size:13px;gap:6px;padding:10px 16px;text-decoration:none;transition:border-color .2s}.ai-chat-widget.dark .ai-chat-location-card__link,.chakra-ui-dark .ai-chat-location-card__link,.dark .ai-chat-location-card__link,[data-theme=dark] .ai-chat-location-card__link{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-location-card__link:hover{border-color:var(--action-accent,#3b82f6)}.ai-chat-location-card-list{display:flex;flex-direction:column;gap:8px}.ai-chat-location-card-list__header{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:13px;font-weight:500;gap:6px;margin-bottom:4px;padding:0 4px}.ai-chat-location-card-list__stack{display:grid;gap:12px;grid-template-columns:1fr}.ai-chat-location-card-list__stack--cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ai-chat-location-card-list__stack--cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}@media (max-width:1000px){.ai-chat-location-card-list__stack--cols-3{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:640px){.ai-chat-location-card-list__stack--cols-2,.ai-chat-location-card-list__stack--cols-3{grid-template-columns:1fr}}.ai-chat-location-card-list__grid{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}@media (max-width:400px){.ai-chat-location-card-list__grid{grid-template-columns:1fr}}.ai-chat-location-card-list__carousel{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;scroll-snap-type:x mandatory;scrollbar-width:none}.ai-chat-location-card-list__carousel::-webkit-scrollbar{display:none}.ai-chat-location-card-list__carousel>.ai-chat-location-card{flex:0 0 280px;scroll-snap-align:start}.ai-chat-contact-card{background:#fff;border:1px solid rgba(0,0,0,.08);border-radius:16px;overflow:hidden;padding:0;position:relative}.ai-chat-widget.dark .ai-chat-contact-card,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card,.chakra-ui-dark .ai-chat-contact-card,.dark .ai-chat-contact-card,[data-theme=dark] .ai-chat-contact-card,html.dark .ai-chat-contact-card{background:#4a4a4a;border-color:hsla(0,0%,100%,.08)}.ai-chat-contact-card-list{gap:12px;width:100%}.ai-chat-contact-card--compact{border-radius:12px}.ai-chat-contact-card--empty{align-items:center;background:var(--bg-secondary,#f4f4f5);display:flex;flex-direction:column;gap:8px;justify-content:center;padding:24px 16px;text-align:center}.ai-chat-widget.dark .ai-chat-contact-card--empty,.chakra-ui-dark .ai-chat-contact-card--empty,.dark .ai-chat-contact-card--empty,[data-theme=dark] .ai-chat-contact-card--empty{background:#3a3a3a}.ai-chat-contact-card__empty-icon{color:var(--text-muted,#71717a);opacity:.6}.ai-chat-contact-card__empty-text{color:var(--text-muted,#71717a);font-size:14px;margin:0}.ai-chat-contact-card--vertical{display:flex;flex-direction:column}.ai-chat-contact-card--vertical .ai-chat-contact-card__image-section{aspect-ratio:3/2;overflow:hidden;width:100%}.ai-chat-contact-card--vertical .ai-chat-contact-card__image{height:100%;object-fit:cover;width:100%}.ai-chat-contact-card--vertical .ai-chat-contact-card__image-placeholder{align-items:center;background:linear-gradient(135deg,#5a5a5a,#3a3a3a);color:hsla(0,0%,100%,.5);display:flex;height:100%;justify-content:center;width:100%}.ai-chat-contact-card--vertical .ai-chat-contact-card__image-placeholder svg{height:48px;width:48px}.ai-chat-contact-card--vertical .ai-chat-contact-card__info{padding:16px;text-align:center}.ai-chat-contact-card--horizontal{display:flex;flex-direction:row}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-section{height:160px;min-width:140px;overflow:hidden;width:140px}.ai-chat-contact-card--horizontal.ai-chat-contact-card--compact .ai-chat-contact-card__image-section{height:120px;min-width:100px;width:100px}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image{height:100%;object-fit:cover;width:100%}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-placeholder{align-items:center;background:linear-gradient(135deg,#5a5a5a,#3a3a3a);color:hsla(0,0%,100%,.5);display:flex;height:100%;justify-content:center;width:100%}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-placeholder svg{height:36px;width:36px}.ai-chat-contact-card--horizontal .ai-chat-contact-card__info{display:flex;flex:1;flex-direction:column;justify-content:center;padding:16px}.ai-chat-contact-card__name{color:var(--action-accent,#ef4444);font-size:18px;font-weight:600;line-height:1.3;margin:0}.ai-chat-contact-card--compact .ai-chat-contact-card__name{font-size:15px}.ai-chat-contact-card__role{color:rgba(0,0,0,.7);font-size:14px;font-weight:400;margin:2px 0 0}.ai-chat-widget.dark .ai-chat-contact-card__role,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__role,.chakra-ui-dark .ai-chat-contact-card__role,.dark .ai-chat-contact-card__role,[data-theme=dark] .ai-chat-contact-card__role,html.dark .ai-chat-contact-card__role{color:hsla(0,0%,100%,.9)}.ai-chat-contact-card--compact .ai-chat-contact-card__role{font-size:13px}.ai-chat-contact-card__details{display:flex;flex-direction:column;gap:2px;margin-top:12px}.ai-chat-contact-card__detail{color:rgba(0,0,0,.6);display:block;font-size:14px;line-height:1.5;margin:0;text-decoration:none}.ai-chat-contact-card__detail:hover{color:#000;text-decoration:underline}.ai-chat-widget.dark .ai-chat-contact-card__detail,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__detail,.chakra-ui-dark .ai-chat-contact-card__detail,.dark .ai-chat-contact-card__detail,[data-theme=dark] .ai-chat-contact-card__detail,html.dark .ai-chat-contact-card__detail{color:hsla(0,0%,100%,.7)}.ai-chat-widget.dark .ai-chat-contact-card__detail:hover,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__detail:hover,.chakra-ui-dark .ai-chat-contact-card__detail:hover,.dark .ai-chat-contact-card__detail:hover,[data-theme=dark] .ai-chat-contact-card__detail:hover,html.dark .ai-chat-contact-card__detail:hover{color:#fff}.ai-chat-contact-card--compact .ai-chat-contact-card__detail{font-size:13px}.ai-chat-contact-card__responsibilities{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}.ai-chat-contact-card__responsibility-tag{background:rgba(0,0,0,.08);border-radius:10px;color:rgba(0,0,0,.8);font-size:11px;font-weight:500;padding:3px 10px}.ai-chat-widget.dark .ai-chat-contact-card__responsibility-tag,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__responsibility-tag,.chakra-ui-dark .ai-chat-contact-card__responsibility-tag,.dark .ai-chat-contact-card__responsibility-tag,[data-theme=dark] .ai-chat-contact-card__responsibility-tag,html.dark .ai-chat-contact-card__responsibility-tag{background:hsla(0,0%,100%,.15);color:hsla(0,0%,100%,.9)}.ai-chat-contact-card__responsibility-more{color:rgba(0,0,0,.5);font-size:11px;padding:3px 4px}.ai-chat-widget.dark .ai-chat-contact-card__responsibility-more,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__responsibility-more,.chakra-ui-dark .ai-chat-contact-card__responsibility-more,.dark .ai-chat-contact-card__responsibility-more,[data-theme=dark] .ai-chat-contact-card__responsibility-more,html.dark .ai-chat-contact-card__responsibility-more{color:hsla(0,0%,100%,.5)}.ai-chat-contact-card__actions{display:flex;gap:8px;padding:0 12px 12px}.ai-chat-contact-card--compact .ai-chat-contact-card__actions{gap:6px;padding:0 10px 10px}.ai-chat-contact-card__button{align-items:center;border:none;border-radius:9999px;cursor:pointer;display:flex;font-size:14px;font-weight:600;gap:8px;justify-content:center;padding:12px 20px;transition:all .15s ease;white-space:nowrap}.ai-chat-contact-card--compact .ai-chat-contact-card__button{font-size:13px;padding:10px 16px}.ai-chat-contact-card__button:hover{box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.ai-chat-contact-card__button:active{transform:translateY(0)}.ai-chat-contact-card__button--primary{background:var(--action-accent,#3b82f6);color:#fff;flex:1}.ai-chat-contact-card__button--primary:hover{background:color-mix(in srgb,var(--action-accent,#3b82f6) 90%,#000)}.ai-chat-contact-card__button--secondary{background:var(--bg-muted,#f4f4f5);border:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-primary,#18181b);flex:1}.ai-chat-contact-card__button--secondary:hover{background:var(--bg-hover,#e4e4e7)}.ai-chat-widget.dark .ai-chat-contact-card__button--secondary,.chakra-ui-dark .ai-chat-contact-card__button--secondary,.dark .ai-chat-contact-card__button--secondary,[data-theme=dark] .ai-chat-contact-card__button--secondary{background:hsla(0,0%,100%,.1);border-color:hsla(0,0%,100%,.15);color:#fff}.ai-chat-widget.dark .ai-chat-contact-card__button--secondary:hover,.chakra-ui-dark .ai-chat-contact-card__button--secondary:hover,.dark .ai-chat-contact-card__button--secondary:hover,[data-theme=dark] .ai-chat-contact-card__button--secondary:hover{background:hsla(0,0%,100%,.15)}.ai-chat-contact-card-list{display:flex;flex-direction:column;gap:8px}.ai-chat-contact-card-list__header{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:13px;font-weight:500;gap:6px;margin-bottom:2px;margin-top:8px;padding:0 4px}.ai-chat-contact-card-list__stack{display:grid;gap:12px;grid-template-columns:repeat(3,minmax(0,1fr))}@media (max-width:900px){.ai-chat-contact-card-list__stack{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:600px){.ai-chat-contact-card-list__stack{grid-template-columns:1fr}}.ai-chat-contact-card-list__stack--widget{grid-template-columns:1fr}@container (min-width: 380px){.ai-chat-contact-card-list__stack--widget{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:520px){.ai-chat-contact-card-list__stack{grid-template-columns:1fr!important}.ai-chat-contact-card--horizontal{flex-direction:column}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-section{aspect-ratio:3/2;height:auto;min-width:100%;width:100%}}.ai-chat-contact-card__initials{align-items:center;display:flex;font-size:48px;font-weight:600;height:100%;justify-content:center;letter-spacing:.05em;text-transform:uppercase;width:100%}.ai-chat-contact-card--compact .ai-chat-contact-card__initials{font-size:32px}.ai-chat-contact-card--horizontal .ai-chat-contact-card__initials{font-size:28px}.ai-chat-contact-card--horizontal.ai-chat-contact-card--compact .ai-chat-contact-card__initials{font-size:22px}.ai-chat-form-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f9fafb);border:1px solid var(--border-subtle,rgba(0,0,0,.06));border-radius:12px;box-sizing:border-box;margin:6px 0;overflow:hidden;padding:16px;width:100%}.ai-chat-widget.dark .ai-chat-form-card,.chakra-ui-dark .ai-chat-form-card,.dark .ai-chat-form-card,[data-theme=dark] .ai-chat-form-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-form-card--empty,.ai-chat-form-card--error,.ai-chat-form-card--skipped,.ai-chat-form-card--submitted{padding:12px 16px}.ai-chat-form-card__header{align-items:center;display:flex;gap:8px;margin-bottom:12px}.ai-chat-form-card__icon{font-size:18px}.ai-chat-form-card__title{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:600}.ai-chat-widget.dark .ai-chat-form-card__title,.chakra-ui-dark .ai-chat-form-card__title,.dark .ai-chat-form-card__title,[data-theme=dark] .ai-chat-form-card__title{color:#fff}.ai-chat-form-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0 0 12px}.ai-chat-form-card__context{color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin:0 0 12px}.ai-chat-form-card__error{color:#dc2626;font-size:13px;margin:0}.ai-chat-widget.dark .ai-chat-form-card__error,.chakra-ui-dark .ai-chat-form-card__error,.dark .ai-chat-form-card__error,[data-theme=dark] .ai-chat-form-card__error{color:#fca5a5}.ai-chat-form-card__success{color:#16a34a;font-size:13px;margin:0}.ai-chat-widget.dark .ai-chat-form-card__success,.chakra-ui-dark .ai-chat-form-card__success,.dark .ai-chat-form-card__success,[data-theme=dark] .ai-chat-form-card__success{color:#4ade80}.ai-chat-form-card__empty-text,.ai-chat-form-card__skipped-text{color:var(--text-muted,#71717a);font-size:13px;margin:0}.ai-chat-form-card__progress{align-items:center;display:flex;gap:12px;margin-bottom:16px}.ai-chat-form-card__progress-bar{background:var(--action-accent,var(--primary-color,#3b82f6));border-radius:2px;flex:1;height:4px;transition:width .3s ease}.ai-chat-form-card__progress-text{color:var(--text-muted,#71717a);font-size:12px;white-space:nowrap}.ai-chat-form-card__question{margin-bottom:16px}.ai-chat-form-card__question-text{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500;line-height:1.4;margin:0 0 12px}.ai-chat-widget.dark .ai-chat-form-card__question-text,.chakra-ui-dark .ai-chat-form-card__question-text,.dark .ai-chat-form-card__question-text,[data-theme=dark] .ai-chat-form-card__question-text{color:#fff}.ai-chat-form-card__required{color:#dc2626;margin-left:2px}.ai-chat-form-card__answer{margin-top:8px}.ai-chat-form-card__textarea{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);box-sizing:border-box;color:var(--text-primary,#3e3e3e);font-family:inherit;font-size:14px;min-height:80px;outline:none;padding:10px 12px;resize:vertical;transition:border-color .2s ease,box-shadow .2s ease;width:100%}.ai-chat-form-card__textarea:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-form-card__textarea::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-form-card__textarea,.chakra-ui-dark .ai-chat-form-card__textarea,.dark .ai-chat-form-card__textarea,[data-theme=dark] .ai-chat-form-card__textarea{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-form-card__textarea:focus,.chakra-ui-dark .ai-chat-form-card__textarea:focus,.dark .ai-chat-form-card__textarea:focus,[data-theme=dark] .ai-chat-form-card__textarea:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-form-card__options{display:flex;flex-direction:column;gap:8px}.ai-chat-form-card__option{align-items:center;background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);cursor:pointer;display:flex;gap:10px;padding:10px 12px;transition:border-color .15s,background .15s}.ai-chat-form-card__option:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-form-card__option,.chakra-ui-dark .ai-chat-form-card__option,.dark .ai-chat-form-card__option,[data-theme=dark] .ai-chat-form-card__option{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1)}.ai-chat-widget.dark .ai-chat-form-card__option:hover,.chakra-ui-dark .ai-chat-form-card__option:hover,.dark .ai-chat-form-card__option:hover,[data-theme=dark] .ai-chat-form-card__option:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-form-card__option input{accent-color:var(--action-accent,var(--primary-color,#3b82f6));margin:0}.ai-chat-form-card__option-text{color:var(--text-primary,#3e3e3e);font-size:14px}.ai-chat-widget.dark .ai-chat-form-card__option-text,.chakra-ui-dark .ai-chat-form-card__option-text,.dark .ai-chat-form-card__option-text,[data-theme=dark] .ai-chat-form-card__option-text{color:#fff}.ai-chat-form-card__rating{display:flex;flex-wrap:wrap;gap:8px}.ai-chat-form-card__rating-btn{align-items:center;background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;display:flex;font-size:14px;font-weight:500;height:40px;justify-content:center;transition:all .15s ease;width:40px}.ai-chat-form-card__rating-btn--selected,.ai-chat-form-card__rating-btn:hover{border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-form-card__rating-btn--selected{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-form-card__rating-btn,.chakra-ui-dark .ai-chat-form-card__rating-btn,.dark .ai-chat-form-card__rating-btn,[data-theme=dark] .ai-chat-form-card__rating-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-form-card__rating-btn:hover,.chakra-ui-dark .ai-chat-form-card__rating-btn:hover,.dark .ai-chat-form-card__rating-btn:hover,[data-theme=dark] .ai-chat-form-card__rating-btn:hover{border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-form-card__rating-btn--selected,.chakra-ui-dark .ai-chat-form-card__rating-btn--selected,.dark .ai-chat-form-card__rating-btn--selected,[data-theme=dark] .ai-chat-form-card__rating-btn--selected{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-form-card__actions{align-items:center;border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));display:flex;gap:8px;margin-top:16px;padding-top:16px}.ai-chat-widget.dark .ai-chat-form-card__actions,.chakra-ui-dark .ai-chat-form-card__actions,.dark .ai-chat-form-card__actions,[data-theme=dark] .ai-chat-form-card__actions{border-color:hsla(0,0%,100%,.08)}.ai-chat-form-card__actions-spacer{flex:1}.ai-chat-form-card__btn{border:none;border-radius:9999px;cursor:pointer;font-family:inherit;font-size:13px;font-weight:500;padding:8px 16px;transition:all .2s ease}.ai-chat-form-card__btn:disabled{cursor:not-allowed;opacity:.5}.ai-chat-form-card__btn--primary{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-form-card__btn--primary:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}.ai-chat-form-card__btn--secondary{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);color:var(--text-primary,#3e3e3e)}.ai-chat-form-card__btn--secondary:hover:not(:disabled){border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-form-card__btn--secondary,.chakra-ui-dark .ai-chat-form-card__btn--secondary,.dark .ai-chat-form-card__btn--secondary,[data-theme=dark] .ai-chat-form-card__btn--secondary{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-form-card__btn--ghost{background:transparent;color:var(--text-muted,#71717a)}.ai-chat-form-card__btn--ghost:hover:not(:disabled){background:rgba(0,0,0,.05);color:var(--text-primary,#3e3e3e)}.ai-chat-widget.dark .ai-chat-form-card__btn--ghost:hover:not(:disabled),.chakra-ui-dark .ai-chat-form-card__btn--ghost:hover:not(:disabled),.dark .ai-chat-form-card__btn--ghost:hover:not(:disabled),[data-theme=dark] .ai-chat-form-card__btn--ghost:hover:not(:disabled){background:hsla(0,0%,100%,.05);color:#fff}.ai-chat-booking-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f9fafb);border:1px solid var(--border-subtle,rgba(0,0,0,.06));border-radius:12px;box-sizing:border-box;margin:6px 0;padding:16px;width:100%}.ai-chat-widget.dark .ai-chat-booking-card,.chakra-ui-dark .ai-chat-booking-card,.dark .ai-chat-booking-card,[data-theme=dark] .ai-chat-booking-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-booking-card__header{align-items:center;display:flex;gap:8px;margin-bottom:12px}.ai-chat-booking-card__icon{flex-shrink:0;font-size:18px}.ai-chat-booking-card__title{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:600}.ai-chat-widget.dark .ai-chat-booking-card__title,.chakra-ui-dark .ai-chat-booking-card__title,.dark .ai-chat-booking-card__title,[data-theme=dark] .ai-chat-booking-card__title{color:#fff}.ai-chat-booking-card__content{display:flex;flex-direction:column;gap:12px}.ai-chat-booking-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0}.ai-chat-booking-card__empty{color:var(--text-muted,#71717a);font-size:13px;padding:16px;text-align:center}.ai-chat-booking-card__input{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;box-sizing:border-box;color:var(--text-primary,#3e3e3e);font-family:inherit;font-size:14px;outline:none;padding:10px 12px;transition:border-color .2s ease,box-shadow .2s ease;width:100%}.ai-chat-booking-card__input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-booking-card__input::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-booking-card__input,.chakra-ui-dark .ai-chat-booking-card__input,.dark .ai-chat-booking-card__input,[data-theme=dark] .ai-chat-booking-card__input{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-booking-card__input:focus,.chakra-ui-dark .ai-chat-booking-card__input:focus,.dark .ai-chat-booking-card__input:focus,[data-theme=dark] .ai-chat-booking-card__input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-booking-card__label{color:var(--text-secondary,#6b7280);display:block;font-size:13px;font-weight:500;margin-bottom:4px}.ai-chat-widget.dark .ai-chat-booking-card__label,.chakra-ui-dark .ai-chat-booking-card__label,.dark .ai-chat-booking-card__label,[data-theme=dark] .ai-chat-booking-card__label{color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__btn{border:none;border-radius:9999px;box-sizing:border-box;cursor:pointer;font-family:inherit;font-size:13px;font-weight:500;padding:10px 16px;transition:all .2s ease;width:100%}.ai-chat-booking-card__btn:disabled{cursor:not-allowed;opacity:.5}.ai-chat-booking-card__btn--primary{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-booking-card__btn--primary:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}.ai-chat-booking-card__btn--secondary{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);color:var(--text-primary,#3e3e3e)}.ai-chat-booking-card__btn--secondary:hover:not(:disabled){border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-booking-card__btn--secondary,.chakra-ui-dark .ai-chat-booking-card__btn--secondary,.dark .ai-chat-booking-card__btn--secondary,[data-theme=dark] .ai-chat-booking-card__btn--secondary{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-booking-card__btn--danger{background:rgba(220,38,38,.1);border:1px solid rgba(220,38,38,.2);color:#dc2626}.ai-chat-booking-card__btn--danger:hover:not(:disabled){background:rgba(220,38,38,.15)}.ai-chat-widget.dark .ai-chat-booking-card__btn--danger,.chakra-ui-dark .ai-chat-booking-card__btn--danger,.dark .ai-chat-booking-card__btn--danger,[data-theme=dark] .ai-chat-booking-card__btn--danger{background:rgba(239,68,68,.2);border-color:rgba(239,68,68,.3);color:#fca5a5}.ai-chat-booking-card__grid{display:grid;gap:10px;grid-template-columns:repeat(auto-fill,minmax(200px,1fr))}.ai-chat-booking-card__contact{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;cursor:pointer;display:flex;flex-direction:column;font-family:inherit;padding:12px;text-align:left;transition:all .2s ease}.ai-chat-booking-card__contact:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-booking-card__contact--selected{border-width:2px}.ai-chat-widget.dark .ai-chat-booking-card__contact,.chakra-ui-dark .ai-chat-booking-card__contact,.dark .ai-chat-booking-card__contact,[data-theme=dark] .ai-chat-booking-card__contact{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1)}.ai-chat-widget.dark .ai-chat-booking-card__contact--selected,.chakra-ui-dark .ai-chat-booking-card__contact--selected,.dark .ai-chat-booking-card__contact--selected,[data-theme=dark] .ai-chat-booking-card__contact--selected{background:rgba(59,130,246,.15)}.ai-chat-booking-card__contact-name{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500}.ai-chat-widget.dark .ai-chat-booking-card__contact-name,.chakra-ui-dark .ai-chat-booking-card__contact-name,.dark .ai-chat-booking-card__contact-name,[data-theme=dark] .ai-chat-booking-card__contact-name{color:#fff}.ai-chat-booking-card__contact-role{color:var(--text-muted,#71717a);font-size:12px;margin-top:2px}.ai-chat-booking-card__options{display:flex;flex-direction:column;gap:8px}.ai-chat-booking-card__option-btn{align-items:center;background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;box-sizing:border-box;cursor:pointer;display:flex;font-family:inherit;gap:12px;padding:12px;text-align:left;transition:all .2s ease;width:100%}.ai-chat-booking-card__option-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-booking-card__option-btn,.chakra-ui-dark .ai-chat-booking-card__option-btn,.dark .ai-chat-booking-card__option-btn,[data-theme=dark] .ai-chat-booking-card__option-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1)}.ai-chat-booking-card__option-icon{flex-shrink:0;font-size:18px}.ai-chat-booking-card__option-text{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500}.ai-chat-widget.dark .ai-chat-booking-card__option-text,.chakra-ui-dark .ai-chat-booking-card__option-text,.dark .ai-chat-booking-card__option-text,[data-theme=dark] .ai-chat-booking-card__option-text{color:#fff}.ai-chat-booking-card__date-group{margin-bottom:12px}.ai-chat-booking-card__date-header{color:var(--text-muted,#71717a);font-size:12px;font-weight:600;letter-spacing:.5px;margin-bottom:8px;text-transform:uppercase}.ai-chat-booking-card__slots{display:grid;gap:8px;grid-template-columns:repeat(auto-fill,minmax(120px,1fr))}.ai-chat-booking-card__slot{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;color:var(--text-primary,#3e3e3e);cursor:pointer;font-family:inherit;font-size:13px;font-weight:500;padding:10px 12px;transition:all .2s ease}.ai-chat-booking-card__slot:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-booking-card__slot--selected{border-width:2px}.ai-chat-widget.dark .ai-chat-booking-card__slot,.chakra-ui-dark .ai-chat-booking-card__slot,.dark .ai-chat-booking-card__slot,[data-theme=dark] .ai-chat-booking-card__slot{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-booking-card__slot--selected,.chakra-ui-dark .ai-chat-booking-card__slot--selected,.dark .ai-chat-booking-card__slot--selected,[data-theme=dark] .ai-chat-booking-card__slot--selected{background:rgba(59,130,246,.15)}.ai-chat-booking-card__appointments{display:flex;flex-direction:column;gap:10px}.ai-chat-booking-card__appointment{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;padding:12px}.ai-chat-widget.dark .ai-chat-booking-card__appointment,.chakra-ui-dark .ai-chat-booking-card__appointment,.dark .ai-chat-booking-card__appointment,[data-theme=dark] .ai-chat-booking-card__appointment{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1)}.ai-chat-booking-card__appointment-header{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:6px}.ai-chat-booking-card__appointment-subject{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500}.ai-chat-widget.dark .ai-chat-booking-card__appointment-subject,.chakra-ui-dark .ai-chat-booking-card__appointment-subject,.dark .ai-chat-booking-card__appointment-subject,[data-theme=dark] .ai-chat-booking-card__appointment-subject{color:#fff}.ai-chat-booking-card__appointment-status{border-radius:4px;font-size:11px;font-weight:600;padding:2px 6px;text-transform:uppercase}.ai-chat-booking-card__appointment-status--confirmed,.ai-chat-booking-card__appointment-status--pending{background:rgba(34,197,94,.1);color:#16a34a}.ai-chat-widget.dark .ai-chat-booking-card__appointment-status--confirmed,.ai-chat-widget.dark .ai-chat-booking-card__appointment-status--pending,.chakra-ui-dark .ai-chat-booking-card__appointment-status--confirmed,.chakra-ui-dark .ai-chat-booking-card__appointment-status--pending,.dark .ai-chat-booking-card__appointment-status--confirmed,.dark .ai-chat-booking-card__appointment-status--pending,[data-theme=dark] .ai-chat-booking-card__appointment-status--confirmed,[data-theme=dark] .ai-chat-booking-card__appointment-status--pending{background:rgba(34,197,94,.2);color:#4ade80}.ai-chat-booking-card__appointment-status--cancelled{background:hsla(220,9%,46%,.1);color:#6b7280}.ai-chat-booking-card__appointment-time{color:var(--text-secondary,#6b7280);font-size:13px;margin-bottom:4px}.ai-chat-widget.dark .ai-chat-booking-card__appointment-time,.chakra-ui-dark .ai-chat-booking-card__appointment-time,.dark .ai-chat-booking-card__appointment-time,[data-theme=dark] .ai-chat-booking-card__appointment-time{color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__appointment-contact{color:var(--text-muted,#71717a);font-size:12px}.ai-chat-booking-card__summary{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;margin-bottom:12px;padding:12px}.ai-chat-widget.dark .ai-chat-booking-card__summary,.chakra-ui-dark .ai-chat-booking-card__summary,.dark .ai-chat-booking-card__summary,[data-theme=dark] .ai-chat-booking-card__summary{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1)}.ai-chat-booking-card__summary-row{align-items:center;display:flex;justify-content:space-between;padding:6px 0}.ai-chat-booking-card__summary-row:not(:last-child){border-bottom:1px solid var(--border-subtle,rgba(0,0,0,.06))}.ai-chat-widget.dark .ai-chat-booking-card__summary-row:not(:last-child),.chakra-ui-dark .ai-chat-booking-card__summary-row:not(:last-child),.dark .ai-chat-booking-card__summary-row:not(:last-child),[data-theme=dark] .ai-chat-booking-card__summary-row:not(:last-child){border-bottom-color:hsla(0,0%,100%,.08)}.ai-chat-booking-card__summary-label{color:var(--text-muted,#71717a);font-size:12px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.ai-chat-booking-card__summary-value{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500;text-align:right}.ai-chat-widget.dark .ai-chat-booking-card__summary-value,.chakra-ui-dark .ai-chat-booking-card__summary-value,.dark .ai-chat-booking-card__summary-value,[data-theme=dark] .ai-chat-booking-card__summary-value{color:#fff}.ai-chat-booking-card__link{display:inline-block;font-size:13px;font-weight:500;margin-top:8px;text-decoration:none;transition:opacity .2s ease}.ai-chat-booking-card__link:hover{opacity:.8;text-decoration:underline}.ai-chat-booking-card--success{background:rgba(34,197,94,.05);border-color:rgba(34,197,94,.2)}.ai-chat-widget.dark .ai-chat-booking-card--success,.chakra-ui-dark .ai-chat-booking-card--success,.dark .ai-chat-booking-card--success,[data-theme=dark] .ai-chat-booking-card--success{background:rgba(34,197,94,.1);border-color:rgba(34,197,94,.3)}.ai-chat-booking-card--pending{background:rgba(234,179,8,.05);border-color:rgba(234,179,8,.2)}.ai-chat-widget.dark .ai-chat-booking-card--pending,.chakra-ui-dark .ai-chat-booking-card--pending,.dark .ai-chat-booking-card--pending,[data-theme=dark] .ai-chat-booking-card--pending{background:rgba(234,179,8,.1);border-color:rgba(234,179,8,.3)}.ai-chat-booking-card--cancelled{background:hsla(220,9%,46%,.05);border-color:hsla(220,9%,46%,.2)}.ai-chat-widget.dark .ai-chat-booking-card--cancelled,.chakra-ui-dark .ai-chat-booking-card--cancelled,.dark .ai-chat-booking-card--cancelled,[data-theme=dark] .ai-chat-booking-card--cancelled{background:hsla(220,9%,46%,.1);border-color:hsla(220,9%,46%,.3)}.ai-chat-booking-card--error{background:rgba(239,68,68,.05);border-color:rgba(239,68,68,.2)}.ai-chat-widget.dark .ai-chat-booking-card--error,.chakra-ui-dark .ai-chat-booking-card--error,.dark .ai-chat-booking-card--error,[data-theme=dark] .ai-chat-booking-card--error{background:rgba(239,68,68,.1);border-color:rgba(239,68,68,.3)}.ai-chat-booking-card__pending-text,.ai-chat-booking-card__success-text{color:var(--text-secondary,#6b7280);font-size:13px;margin:0}.ai-chat-widget.dark .ai-chat-booking-card__pending-text,.ai-chat-widget.dark .ai-chat-booking-card__success-text,.chakra-ui-dark .ai-chat-booking-card__pending-text,.chakra-ui-dark .ai-chat-booking-card__success-text,.dark .ai-chat-booking-card__pending-text,.dark .ai-chat-booking-card__success-text,[data-theme=dark] .ai-chat-booking-card__pending-text,[data-theme=dark] .ai-chat-booking-card__success-text{color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__error{color:#dc2626;font-size:13px;margin:0}.ai-chat-widget.dark .ai-chat-booking-card__error,.chakra-ui-dark .ai-chat-booking-card__error,.dark .ai-chat-booking-card__error,[data-theme=dark] .ai-chat-booking-card__error{color:#fca5a5}.chat-fullpage{--fp-max-width:800px;--fp-padding-x:16px;--fp-padding-top-mobile:64px;--fp-padding-top-desktop:16px;--fp-padding-bottom:200px;--fp-input-bottom:0}.chat-fullpage .ai-chat-messages{background:transparent;height:100%;margin:0 auto;max-width:var(--fp-max-width);padding:var(--fp-padding-top-desktop) var(--fp-padding-x) var(--fp-padding-bottom)}@media (max-width:768px){.chat-fullpage .ai-chat-messages{padding-top:var(--fp-padding-top-mobile)}}.chat-fullpage .ai-chat-message{animation:none}.chat-fullpage .ai-chat-message.user{max-width:85%}.chat-fullpage .ai-chat-message.user .ai-chat-message-content{background:var(--bg-muted,#f4f4f5);border-radius:24px;color:#000;padding:8px 16px}.chat-fullpage.dark .ai-chat-message.user .ai-chat-message-content{background:var(--bg-muted,#27272a);color:#fff}.chat-fullpage .ai-chat-message.assistant{width:100%}.chat-fullpage .ai-chat-message.assistant .ai-chat-message-content{color:#000;padding:8px 16px}.chat-fullpage.dark .ai-chat-message.assistant .ai-chat-message-content{color:#fff}.chat-fullpage .ai-chat-message.tool{margin:0;padding:0;width:100%}.chat-fullpage .ai-chat-welcome{align-items:center;display:flex;flex-direction:column;gap:24px;justify-content:center;min-height:60vh;padding:24px;text-align:center}.chat-fullpage .ai-chat-welcome-title{font-size:32px;font-weight:600}.chat-fullpage .ai-chat-welcome-text{color:var(--text-muted,#71717a);font-size:18px;max-width:400px}.chat-fullpage .ai-chat-input-container{background:transparent;bottom:0;left:0;padding:16px 16px calc(16px + env(safe-area-inset-bottom));position:fixed;right:0;z-index:20}.chat-fullpage .ai-chat-input-container:after{background:var(--bg-primary,#fff);bottom:0;content:\"\";height:calc(40% + 16px);left:0;pointer-events:none;position:absolute;right:0;z-index:-1}.chat-fullpage.dark .ai-chat-input-container:after{background:var(--bg-primary,#18181b)}@media (min-width:769px){.chat-fullpage .ai-chat-input-container{background:transparent;bottom:var(--fp-input-bottom);left:50%;max-width:var(--fp-max-width);padding:0;position:absolute;right:auto;transform:translateX(-50%);width:100%}}.chat-fullpage .ai-chat-input-wrapper{background:var(--bg-muted,#f4f4f5);border:1px solid var(--border-muted,#e4e4e7);border-radius:24px;box-shadow:0 1px 8px rgba(0,0,0,.06);margin:0 auto;max-width:var(--fp-max-width)}.chat-fullpage.dark .ai-chat-input-wrapper{background:var(--bg-muted,#27272a);border-color:var(--border-muted,#3f3f46);box-shadow:0 1px 12px rgba(0,0,0,.25)}.chat-fullpage .ai-chat-scroll-button{bottom:100px}@media (min-width:769px){.chat-fullpage .ai-chat-scroll-button{bottom:90px}}.chat-fullpage .ai-chat-suggested-questions{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;max-width:600px}.chat-fullpage .ai-chat-suggested-question{border-radius:9999px;font-size:14px;padding:8px 16px}.chat-fullpage .ai-chat-follow-up-suggestions{margin-top:12px}.chat-fullpage .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-default,#d4d4d8);color:#000}.chat-fullpage .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#f4f4f5)}.chat-fullpage.dark .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:#fff}.chat-fullpage.dark .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46)}.chat-fullpage .ai-chat-typing{padding:8px 16px}@media (max-width:480px){body.ai-chat-widget-open{height:100%!important;overflow:hidden!important;position:fixed!important;touch-action:none!important;width:100%!important}.ai-chat-widget-container.is-open{height:100vh!important;height:100dvh!important;width:100vw!important;z-index:var(--widget-z-index,2147483647)!important}.ai-chat-widget-container.is-open,.ai-chat-widget-container.is-open .ai-chat-window{bottom:0!important;left:0!important;position:fixed!important;right:0!important;top:0!important}.ai-chat-widget-container.is-open .ai-chat-window{animation:none!important;border:none!important;border-radius:0!important;box-shadow:none!important;height:100%!important;max-height:100%!important;max-width:100%!important;outline:none!important;transform:none!important;width:100%!important}.ai-chat-widget-container.is-open .ai-chat-button{display:none!important;pointer-events:none!important;visibility:hidden!important}.ai-chat-widget-container.is-open .ai-chat-header{border-radius:0!important;flex-shrink:0;padding-left:max(16px,env(safe-area-inset-left));padding-right:max(16px,env(safe-area-inset-right));padding-top:max(12px,env(safe-area-inset-top));position:relative;z-index:100}.ai-chat-widget-container.is-open .ai-chat-messages{-webkit-overflow-scrolling:touch;flex:1;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;padding-bottom:120px;padding-left:max(16px,env(safe-area-inset-left));padding-right:max(16px,env(safe-area-inset-right));touch-action:pan-y}.ai-chat-widget-container.is-open .ai-chat-input-container{background:var(--bg-primary,#fff);bottom:0!important;left:0!important;padding:8px max(12px,env(safe-area-inset-right)) max(16px,calc(env(safe-area-inset-bottom) + 8px)) max(12px,env(safe-area-inset-left));position:fixed!important;right:0!important;z-index:100}.ai-chat-widget.dark .ai-chat-widget-container.is-open .ai-chat-input-container{background:var(--bg-primary,#282625)}.ai-chat-widget-container.is-open .ai-chat-input-container:after{display:none}.ai-chat-widget-container.is-open .ai-chat-input-wrapper{margin:0;max-width:100%}.ai-chat-widget-container.is-open .ai-chat-scroll-button{bottom:calc(80px + env(safe-area-inset-bottom))}.ai-chat-widget-container.is-open .ai-chat-welcome{padding:16px 0}.ai-chat-widget-container.is-open .ai-chat-welcome-title{font-size:24px}.ai-chat-widget-container.is-open .ai-chat-suggested-questions{align-items:stretch;flex-direction:column}.ai-chat-widget-container.is-open .ai-chat-suggested-question{text-align:center;width:100%}}@media (min-width:481px) and (max-width:768px){.ai-chat-widget-container.is-open .ai-chat-window{border-radius:22px 22px 44px 44px;max-height:calc(100vh - 100px);max-width:calc(100vw - 32px)}}";
30847
+ styleInject(css_248z$1);
30848
+
30849
+ var css_248z = ".ai-chat-data-policy-view{display:flex;flex:1;flex-direction:column;min-height:0;overflow:hidden}.ai-chat-data-policy-content{-webkit-overflow-scrolling:touch;flex:1;overflow-y:auto;padding:20px 16px 40px}.ai-chat-data-policy-intro{margin-bottom:24px}.ai-chat-data-policy-intro p{color:var(--text-primary,#18181b);font-size:13px;line-height:1.6;margin:0;text-align:left}.ai-chat-widget.dark .ai-chat-data-policy-intro p{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-intro strong{color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-data-policy-intro strong{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section{margin-bottom:20px}.ai-chat-data-policy-section h3{color:var(--text-primary,#18181b);font-size:14px;font-weight:600;margin:0 0 12px}.ai-chat-widget.dark .ai-chat-data-policy-section h3{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section p{color:var(--text-secondary,#52525b);font-size:12px;line-height:1.6;margin:0 0 12px;text-align:justify;text-justify:inter-word}.ai-chat-widget.dark .ai-chat-data-policy-section p{color:var(--text-secondary,#a1a1aa)}.ai-chat-data-policy-section p strong{color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-data-policy-section p strong{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section p:last-child{margin-bottom:0}";
29688
30850
  styleInject(css_248z);
29689
30851
 
29690
30852
  // Icon components mapping
@@ -29692,11 +30854,23 @@ const iconComponents = {
29692
30854
  FiMessageCircle: () => (jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" }) })),
29693
30855
  FiChevronDown: () => (jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "6 9 12 15 18 9" }) })),
29694
30856
  };
29695
- const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = false, previewConfig, position = 'bottom-right', primaryColor, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, theme, suggestedQuestions, customStyles, currentRoute, defaultOpen = false, zIndex, onOpen, onClose, onMessage, onError, mode = 'bubble', }) => {
30857
+ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = false, previewConfig, demoMode = false, demoInput, demoOutput, onDemoComplete, position = 'bottom-right', primaryColor, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, welcomeBubbleText, triggerType, triggerText, theme, suggestedQuestions, customStyles, currentRoute, defaultOpen = false, zIndex, containerMode = false, onOpen, onClose, onMessage, onError, mode = 'bubble', }) => {
29696
30858
  const [isOpen, setIsOpen] = useState(defaultOpen);
30859
+ const [inputBarValue, setInputBarValue] = useState('');
29697
30860
  const [autoDetectedTheme, setAutoDetectedTheme] = useState('light');
30861
+ const [showWelcomeBubble, setShowWelcomeBubble] = useState(false);
29698
30862
  const widgetRef = useRef(null);
29699
30863
  const containerRef = useRef(null);
30864
+ // Demo mode state - track whether demo has been activated and completed
30865
+ const [demoMessages, setDemoMessages] = useState([]);
30866
+ const [isDemoComplete, setIsDemoComplete] = useState(false);
30867
+ const [isDemoTyping, setIsDemoTyping] = useState(false);
30868
+ const [demoInputBarText, setDemoInputBarText] = useState(''); // For animating text in input bar
30869
+ const [isDemoAnimatingInput, setIsDemoAnimatingInput] = useState(false); // True while typing into input bar
30870
+ const [isDemoActive, setIsDemoActive] = useState(false); // True when demo animation is running
30871
+ const demoStartedRef = useRef(false);
30872
+ // Track if user has sent a real message (transitions from demo to real chat)
30873
+ const [userSentRealMessage, setUserSentRealMessage] = useState(false);
29700
30874
  // Determine mode
29701
30875
  const isEmbedded = mode === 'embedded';
29702
30876
  // Default config for preview mode
@@ -29716,6 +30890,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29716
30890
  showChatHistory: true,
29717
30891
  showTimestamps: true,
29718
30892
  showTypingIndicator: true,
30893
+ showToolCalls: false,
29719
30894
  enableFileUpload: false,
29720
30895
  enableFeedback: true,
29721
30896
  },
@@ -29741,29 +30916,54 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29741
30916
  ...previewConfig?.behavior,
29742
30917
  },
29743
30918
  };
29744
- // Always call useChat hook (React rules), but skip initialization in preview mode
30919
+ // Always call useChat hook (React rules), but skip initialization in preview mode or during demo
30920
+ // Skip initialization during demo to prevent loading old conversations
30921
+ // Note: We still pass the real widgetId so createDemoConversation works correctly
30922
+ const shouldSkipInit = previewMode || (demoMode && !userSentRealMessage);
29745
30923
  const chatHook = useChat({
29746
30924
  widgetId: previewMode ? '__preview__' : (widgetId || '__preview__'),
29747
30925
  apiUrl,
29748
30926
  currentRoute,
29749
- onMessage: previewMode ? undefined : onMessage,
29750
- onError: previewMode ? undefined : onError,
29751
- skipInitialization: previewMode, // Don't make API calls in preview mode
30927
+ onMessage: shouldSkipInit ? undefined : onMessage,
30928
+ onError: shouldSkipInit ? undefined : onError,
30929
+ skipInitialization: shouldSkipInit, // Don't make API calls in preview mode or during demo
29752
30930
  });
29753
30931
  // Extract values from hook or use preview defaults
29754
- const messages = previewMode ? [] : chatHook.messages;
29755
- const isLoading = previewMode ? false : chatHook.isLoading;
29756
- const isTyping = previewMode ? false : chatHook.isTyping;
29757
- const error = previewMode ? null : chatHook.error;
30932
+ const hookMessages = previewMode ? [] : chatHook.messages;
30933
+ const hookIsLoading = previewMode ? false : chatHook.isLoading;
30934
+ const hookIsTyping = previewMode ? false : chatHook.isTyping;
29758
30935
  const config = previewMode ? mergedPreviewConfig : chatHook.config;
29759
- const sendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
30936
+ const hookSendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
29760
30937
  const submitFeedback = previewMode ? (() => Promise.resolve()) : chatHook.submitFeedback;
30938
+ const dismissAction = previewMode ? (() => Promise.resolve()) : chatHook.dismissAction;
29761
30939
  const conversations = previewMode ? [] : chatHook.conversations;
29762
30940
  const loadConversations = previewMode ? (() => { }) : chatHook.loadConversations;
29763
30941
  const switchConversation = previewMode ? (() => Promise.resolve()) : chatHook.switchConversation;
29764
30942
  const startNewConversation = previewMode ? (() => { }) : chatHook.startNewConversation;
29765
30943
  const deleteConversation = previewMode ? (() => { }) : chatHook.deleteConversation;
30944
+ const createDemoConversation = previewMode ? (() => Promise.resolve(null)) : chatHook.createDemoConversation;
29766
30945
  const conversationId = previewMode ? '' : chatHook.conversationId;
30946
+ // Message display logic:
30947
+ // - During demo (before user sends real message): show demoMessages
30948
+ // - After user sends real message: show hookMessages
30949
+ const showDemoMessages = demoMode && demoMessages.length > 0 && !userSentRealMessage;
30950
+ const messages = showDemoMessages ? demoMessages : hookMessages;
30951
+ const isLoading = showDemoMessages ? false : hookIsLoading;
30952
+ const isTyping = showDemoMessages ? isDemoTyping : hookIsTyping;
30953
+ // Send message handler - transitions from demo to real chat when user sends first message
30954
+ const sendMessage = useCallback((content) => {
30955
+ if (demoMode && isDemoActive && !isDemoComplete) {
30956
+ // Demo animation is still running - ignore user input
30957
+ return Promise.resolve();
30958
+ }
30959
+ // User is sending a real message - transition to real chat
30960
+ if (demoMode && !userSentRealMessage) {
30961
+ setUserSentRealMessage(true);
30962
+ // Clear demo messages so hook messages take over
30963
+ setDemoMessages([]);
30964
+ }
30965
+ return hookSendMessage(content);
30966
+ }, [demoMode, isDemoActive, isDemoComplete, userSentRealMessage, hookSendMessage]);
29767
30967
  // Auto-detect theme from background
29768
30968
  useEffect(() => {
29769
30969
  if (!containerRef.current)
@@ -29789,8 +30989,16 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29789
30989
  mediaQuery.removeEventListener('change', handleMediaChange);
29790
30990
  };
29791
30991
  }, [config]);
29792
- // Handle auto-open (only for bubble mode)
30992
+ // Check if device is mobile
30993
+ const isMobile = typeof window !== 'undefined' && window.innerWidth <= 480;
30994
+ // Handle auto-open (only for bubble mode, disabled on mobile)
29793
30995
  useEffect(() => {
30996
+ // Never auto-open on mobile devices
30997
+ if (isMobile)
30998
+ return undefined;
30999
+ // Don't auto-open if demo mode is active - let demo animation control opening
31000
+ if (demoMode && !isDemoComplete)
31001
+ return undefined;
29794
31002
  if (!isEmbedded && config?.settings.autoOpen) {
29795
31003
  const delay = config.settings.autoOpenDelay || 0;
29796
31004
  const timer = setTimeout(() => {
@@ -29800,7 +31008,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29800
31008
  return () => clearTimeout(timer);
29801
31009
  }
29802
31010
  return undefined;
29803
- }, [config, onOpen, isEmbedded]);
31011
+ }, [config, onOpen, isEmbedded, isMobile, demoMode, isDemoComplete]);
29804
31012
  // Handle close on Escape key (only for bubble mode)
29805
31013
  useEffect(() => {
29806
31014
  if (!isOpen || isEmbedded)
@@ -29814,6 +31022,203 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29814
31022
  document.addEventListener('keydown', handleEscapeKey);
29815
31023
  return () => document.removeEventListener('keydown', handleEscapeKey);
29816
31024
  }, [isOpen, onClose, isEmbedded]);
31025
+ // Handle body scroll lock on mobile when widget is open
31026
+ useEffect(() => {
31027
+ if (!isOpen || isEmbedded)
31028
+ return;
31029
+ // Only apply scroll lock on mobile
31030
+ const checkMobile = window.innerWidth <= 480;
31031
+ if (!checkMobile)
31032
+ return;
31033
+ // Add class to body to lock scrolling
31034
+ document.body.classList.add('ai-chat-widget-open');
31035
+ return () => {
31036
+ document.body.classList.remove('ai-chat-widget-open');
31037
+ };
31038
+ }, [isOpen, isEmbedded]);
31039
+ // Handle welcome bubble visibility based on frequency setting
31040
+ // Frequency options: 'always' (every page visit), 'session', 'weekly', 'monthly'
31041
+ useEffect(() => {
31042
+ if (isEmbedded || previewMode)
31043
+ return;
31044
+ const bubbleText = welcomeBubbleText ?? config?.appearance?.welcomeBubbleText;
31045
+ if (!bubbleText) {
31046
+ setShowWelcomeBubble(false);
31047
+ return;
31048
+ }
31049
+ const frequency = config?.appearance?.welcomeBubbleFrequency ?? 'session';
31050
+ const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
31051
+ // Check if bubble should be shown based on frequency
31052
+ const shouldShowBubble = () => {
31053
+ if (frequency === 'always') {
31054
+ // Always show on every page visit (no storage check)
31055
+ return true;
31056
+ }
31057
+ if (frequency === 'session') {
31058
+ // Show once per session
31059
+ return sessionStorage.getItem(storageKey) !== 'true';
31060
+ }
31061
+ // For weekly/monthly, use localStorage with timestamp
31062
+ try {
31063
+ const stored = localStorage.getItem(storageKey);
31064
+ if (!stored)
31065
+ return true;
31066
+ const dismissedAt = parseInt(stored, 10);
31067
+ if (isNaN(dismissedAt))
31068
+ return true;
31069
+ const now = Date.now();
31070
+ const weekMs = 7 * 24 * 60 * 60 * 1000;
31071
+ const monthMs = 30 * 24 * 60 * 60 * 1000;
31072
+ if (frequency === 'weekly') {
31073
+ return now - dismissedAt > weekMs;
31074
+ }
31075
+ if (frequency === 'monthly') {
31076
+ return now - dismissedAt > monthMs;
31077
+ }
31078
+ }
31079
+ catch {
31080
+ return true;
31081
+ }
31082
+ return true;
31083
+ };
31084
+ if (shouldShowBubble() && !isOpen) {
31085
+ setShowWelcomeBubble(true);
31086
+ }
31087
+ }, [widgetId, welcomeBubbleText, config, isOpen, isEmbedded, previewMode]);
31088
+ // Demo mode: animate typing into input bar, then open widget with conversation
31089
+ // This shows the widget in action without making expensive AI calls
31090
+ useEffect(() => {
31091
+ // Determine trigger type early (from prop or config)
31092
+ // IMPORTANT: For demo mode, we need config to be loaded to know the trigger type
31093
+ // If config is not loaded yet, wait for it (unless triggerType prop is provided)
31094
+ const effectiveTriggerTypeForDemo = triggerType ?? config?.appearance?.triggerType ?? 'button';
31095
+ const isInputBarTrigger = effectiveTriggerTypeForDemo === 'input-bar';
31096
+ // Debug logging
31097
+ console.log('[Widget] Demo effect check:', {
31098
+ demoMode,
31099
+ isDemoComplete,
31100
+ demoStartedRef: demoStartedRef.current,
31101
+ hasDemoInput: !!demoInput,
31102
+ hasDemoOutput: !!demoOutput,
31103
+ triggerType: effectiveTriggerTypeForDemo,
31104
+ isInputBar: isInputBarTrigger,
31105
+ isOpen,
31106
+ });
31107
+ // Start demo when demoMode is enabled and we have input/output
31108
+ const shouldStartDemo = demoMode && !isDemoComplete && !demoStartedRef.current && demoInput && demoOutput;
31109
+ if (!shouldStartDemo) {
31110
+ console.log('[Widget] Demo not starting:', { shouldStartDemo, reason: !demoMode ? 'demoMode false' : !demoInput ? 'no demoInput' : !demoOutput ? 'no demoOutput' : isDemoComplete ? 'already complete' : demoStartedRef.current ? 'already started' : 'unknown' });
31111
+ return;
31112
+ }
31113
+ // Wait for config to load before starting demo (unless triggerType prop is explicitly provided)
31114
+ // This prevents the demo from starting with wrong trigger type
31115
+ if (!triggerType && !config) {
31116
+ console.log('[Widget] Demo waiting for config or triggerType prop');
31117
+ return;
31118
+ }
31119
+ // For input-bar: start immediately (widget closed, type into bar)
31120
+ // For others: wait until widget is open
31121
+ if (!isInputBarTrigger && !isOpen) {
31122
+ console.log('[Widget] Demo waiting for widget to open (non-input-bar trigger)');
31123
+ return;
31124
+ }
31125
+ console.log('[Widget] Starting demo animation...', {
31126
+ triggerType: effectiveTriggerTypeForDemo,
31127
+ isInputBar: isInputBarTrigger,
31128
+ demoInput,
31129
+ demoOutput: demoOutput?.substring(0, 50) + '...',
31130
+ });
31131
+ demoStartedRef.current = true;
31132
+ setIsDemoActive(true);
31133
+ // Use stable IDs to prevent React from remounting components
31134
+ const userMessageId = 'demo-user-message';
31135
+ const assistantMessageId = 'demo-assistant-message';
31136
+ // Helper to create a message with stable ID
31137
+ const createMessage = (id, role, content, isStreaming = false) => ({
31138
+ id,
31139
+ message: { role, content },
31140
+ timestamp: new Date().toISOString(),
31141
+ sources: [],
31142
+ isStreaming,
31143
+ });
31144
+ // Animation sequence - runs to completion even if widget is closed
31145
+ // This ensures conversation is always created and saved consistently
31146
+ const runDemoAnimation = async () => {
31147
+ // STEP 1: Create conversation IMMEDIATELY at the start
31148
+ // This ensures we have a conversation ID before any animation
31149
+ console.log('[Widget] Creating demo conversation at start...');
31150
+ let conversationId = null;
31151
+ try {
31152
+ conversationId = await createDemoConversation(demoInput, demoOutput);
31153
+ if (conversationId) {
31154
+ console.log('[Widget] Demo conversation created:', conversationId);
31155
+ }
31156
+ }
31157
+ catch (err) {
31158
+ console.warn('[Widget] Failed to create demo conversation:', err);
31159
+ }
31160
+ // STEP 2: For input-bar trigger, animate typing into input bar first
31161
+ if (isInputBarTrigger && !isOpen) {
31162
+ setIsDemoAnimatingInput(true);
31163
+ // Wait before starting to type - ensure input bar is fully visible
31164
+ await new Promise(resolve => setTimeout(resolve, 1500));
31165
+ // Type into input bar character by character
31166
+ const inputChars = demoInput.split('');
31167
+ for (let i = 0; i < inputChars.length; i++) {
31168
+ setDemoInputBarText(demoInput.slice(0, i + 1));
31169
+ // Slower typing speed for better visibility
31170
+ const delay = inputChars[i] === ' ' ? 100 : 60 + Math.random() * 40;
31171
+ await new Promise(resolve => setTimeout(resolve, delay));
31172
+ }
31173
+ // Longer pause after typing so user can read the question
31174
+ await new Promise(resolve => setTimeout(resolve, 1000));
31175
+ setIsDemoAnimatingInput(false);
31176
+ setDemoInputBarText('');
31177
+ setIsOpen(true);
31178
+ onOpen?.();
31179
+ // Let widget open animation complete
31180
+ await new Promise(resolve => setTimeout(resolve, 500));
31181
+ }
31182
+ else {
31183
+ // For non-input-bar triggers, just wait for widget to settle
31184
+ await new Promise(resolve => setTimeout(resolve, 800));
31185
+ }
31186
+ // STEP 3: Add user message
31187
+ setDemoMessages([createMessage(userMessageId, 'user', demoInput)]);
31188
+ // Show typing indicator after a pause
31189
+ await new Promise(resolve => setTimeout(resolve, 500));
31190
+ setIsDemoTyping(true);
31191
+ // "Thinking" pause
31192
+ await new Promise(resolve => setTimeout(resolve, 1200));
31193
+ setIsDemoTyping(false);
31194
+ // STEP 4: Stream the response character by character
31195
+ const chars = demoOutput.split('');
31196
+ let currentText = '';
31197
+ // Initial message with empty content
31198
+ setDemoMessages([
31199
+ createMessage(userMessageId, 'user', demoInput),
31200
+ createMessage(assistantMessageId, 'assistant', '', true),
31201
+ ]);
31202
+ await new Promise(resolve => setTimeout(resolve, 100));
31203
+ // Stream characters - continues even if widget is closed
31204
+ for (let i = 0; i < chars.length; i++) {
31205
+ currentText += chars[i];
31206
+ setDemoMessages([
31207
+ createMessage(userMessageId, 'user', demoInput),
31208
+ createMessage(assistantMessageId, 'assistant', currentText, i < chars.length - 1),
31209
+ ]);
31210
+ const delay = chars[i] === ' ' ? 12 : 20;
31211
+ await new Promise(resolve => setTimeout(resolve, delay));
31212
+ }
31213
+ // STEP 5: Mark demo complete
31214
+ await new Promise(resolve => setTimeout(resolve, 500));
31215
+ setIsDemoComplete(true);
31216
+ setIsDemoActive(false);
31217
+ console.log('[Widget] Demo animation complete');
31218
+ onDemoComplete?.();
31219
+ };
31220
+ runDemoAnimation();
31221
+ }, [demoMode, isOpen, isDemoComplete, demoInput, demoOutput, onDemoComplete, triggerType, config?.appearance?.triggerType, onOpen, createDemoConversation]);
29817
31222
  // Determine theme - use prop override if provided, otherwise auto-detect
29818
31223
  const appearanceConfig = config?.appearance;
29819
31224
  const effectiveTheme = theme ?? autoDetectedTheme;
@@ -29822,11 +31227,14 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29822
31227
  // Get accent color from prop or config (empty string means no accent color / vanilla mode)
29823
31228
  const accentColor = primaryColor ?? appearanceConfig?.primaryColor ?? '';
29824
31229
  // Apply prop overrides for live preview (props take priority over config)
29825
- size || appearanceConfig?.size || 'small';
31230
+ const effectiveSize = size || appearanceConfig?.size || 'small';
29826
31231
  const effectiveHeaderTitle = headerTitle ?? appearanceConfig?.headerTitle ?? '';
29827
31232
  const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? '';
29828
31233
  const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? '';
29829
31234
  const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? '';
31235
+ const effectiveWelcomeBubbleText = welcomeBubbleText ?? appearanceConfig?.welcomeBubbleText ?? '';
31236
+ const effectiveTriggerType = triggerType ?? appearanceConfig?.triggerType ?? 'button';
31237
+ const effectiveTriggerText = triggerText ?? appearanceConfig?.triggerText ?? 'Chat';
29830
31238
  // Generate styles using simplified theme system
29831
31239
  const simpleAppearance = {
29832
31240
  accentColor};
@@ -29843,18 +31251,65 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29843
31251
  ...customStyles,
29844
31252
  ...(zIndex !== undefined ? { '--widget-z-index': String(zIndex) } : {}),
29845
31253
  };
31254
+ // Dismiss bubble and store based on frequency setting
31255
+ const dismissBubble = () => {
31256
+ setShowWelcomeBubble(false);
31257
+ const frequency = config?.appearance?.welcomeBubbleFrequency ?? 'session';
31258
+ const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
31259
+ try {
31260
+ if (frequency === 'always') {
31261
+ // For 'always', use sessionStorage so it only hides until page refresh
31262
+ sessionStorage.setItem(storageKey, 'true');
31263
+ }
31264
+ else if (frequency === 'session') {
31265
+ sessionStorage.setItem(storageKey, 'true');
31266
+ }
31267
+ else {
31268
+ // For weekly/monthly, store timestamp in localStorage
31269
+ localStorage.setItem(storageKey, String(Date.now()));
31270
+ }
31271
+ }
31272
+ catch {
31273
+ // Ignore storage errors
31274
+ }
31275
+ };
29846
31276
  const handleToggle = () => {
29847
31277
  if (isEmbedded)
29848
31278
  return;
29849
31279
  const newState = !isOpen;
29850
31280
  setIsOpen(newState);
31281
+ // Dismiss welcome bubble when chat is opened
31282
+ if (newState && showWelcomeBubble) {
31283
+ dismissBubble();
31284
+ }
29851
31285
  if (newState) {
29852
31286
  onOpen?.();
29853
31287
  }
29854
31288
  else {
31289
+ // Demo animation continues in background when widget is closed
31290
+ // The conversation was already created at the start, so closing is safe
31291
+ // When user reopens, they'll see the current state of the demo animation
29855
31292
  onClose?.();
29856
31293
  }
29857
31294
  };
31295
+ const handleDismissBubble = (e) => {
31296
+ e.stopPropagation();
31297
+ dismissBubble();
31298
+ };
31299
+ // Handle input bar submit - opens widget and sends message
31300
+ const handleInputBarSubmit = useCallback((e) => {
31301
+ e.preventDefault();
31302
+ if (!inputBarValue.trim() || previewMode)
31303
+ return;
31304
+ // Open the widget
31305
+ setIsOpen(true);
31306
+ onOpen?.();
31307
+ // Send the message after a brief delay to allow widget to open
31308
+ setTimeout(() => {
31309
+ sendMessage(inputBarValue.trim());
31310
+ setInputBarValue('');
31311
+ }, 100);
31312
+ }, [inputBarValue, previewMode, onOpen, sendMessage]);
29858
31313
  const handleFeedback = async (messageId, feedback) => {
29859
31314
  await submitFeedback(messageId, feedback);
29860
31315
  };
@@ -29870,22 +31325,33 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29870
31325
  sendMessage(actionInstruction);
29871
31326
  };
29872
31327
  // Don't render until config is loaded to avoid flash of unstyled content
31328
+ // Exception: If we have essential props (triggerType), allow rendering the trigger immediately
31329
+ // This improves perceived loading speed - users see the trigger while config loads
29873
31330
  // In preview mode, config is always available
29874
- if (!config && !previewMode) {
31331
+ const canRenderWithoutConfig = !!triggerType;
31332
+ if (!config && !previewMode && !canRenderWithoutConfig) {
29875
31333
  return null;
29876
31334
  }
29877
31335
  // Get button icon based on state
29878
31336
  const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
29879
31337
  // Embedded mode renders directly without wrapper positioning
29880
31338
  if (isEmbedded) {
29881
- return (jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage, onClose: () => { }, onFeedback: handleFeedback, onActionClick: handleActionClick, conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions }) }));
29882
- }
29883
- return (jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition} ${isOpen ? 'is-open' : ''}`, children: [isOpen && (jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback, onActionClick: handleActionClick,
31339
+ return (jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage: sendMessage, onClose: () => { }, onFeedback: handleFeedback, onActionClick: handleActionClick, onActionDismiss: dismissAction, conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions }) }));
31340
+ }
31341
+ // Determine trigger class for container
31342
+ const triggerClass = effectiveTriggerType === 'pill-text'
31343
+ ? 'trigger-pill-text'
31344
+ : effectiveTriggerType === 'input-bar'
31345
+ ? 'trigger-input-bar'
31346
+ : '';
31347
+ // Size class for CSS targeting (used by input-bar trigger for width matching)
31348
+ const sizeClass = `size-${effectiveSize}`;
31349
+ return (jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition} ${isOpen ? 'is-open' : ''} ${containerMode ? 'container-mode' : ''} ${triggerClass} ${sizeClass}`, children: [isOpen && (jsx(ChatWindow, { messages: demoMode && !isDemoComplete ? demoMessages : messages, isLoading: demoMode && !isDemoComplete ? false : isLoading, isTyping: demoMode && !isDemoComplete ? isDemoTyping : isTyping, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback, onActionClick: handleActionClick, onActionDismiss: dismissAction,
29884
31350
  // Chat history props (only active when persistConversation is true)
29885
31351
  conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId,
29886
31352
  // Override props for live preview
29887
- headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsx("div", { className: "ai-chat-button-svg", children: jsx(IconComponent, {}) }) })] }) }));
31353
+ headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), effectiveTriggerType === 'button' && !isOpen && effectiveWelcomeBubbleText && (previewMode || showWelcomeBubble) && (jsxs("div", { className: "ai-chat-welcome-bubble", onClick: handleToggle, children: [jsx("span", { children: effectiveWelcomeBubbleText }), jsx("button", { className: "ai-chat-welcome-bubble-close", onClick: handleDismissBubble, "aria-label": "Dismiss", children: jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) }), jsx("div", { className: "ai-chat-welcome-bubble-arrow" })] })), effectiveTriggerType === 'button' && (jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsx("div", { className: "ai-chat-button-svg", children: jsx(IconComponent, {}) }) })), effectiveTriggerType === 'pill-text' && (jsxs("button", { className: `ai-chat-trigger-pill ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Close chat" : "Open chat", children: [jsx("div", { className: "ai-chat-trigger-pill-icon", children: jsx(IconComponent, {}) }), !isOpen && jsx("span", { children: effectiveTriggerText })] })), effectiveTriggerType === 'input-bar' && !isOpen && (jsxs("div", { className: "ai-chat-trigger-input-container", children: [jsx("button", { type: "button", className: "ai-chat-trigger-input-expand", onClick: handleToggle, "aria-label": "Open chat", children: jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "18 15 12 9 6 15" }) }) }), jsxs("form", { className: "ai-chat-trigger-input-wrapper", onSubmit: handleInputBarSubmit, children: [jsx("input", { type: "text", className: "ai-chat-trigger-input", placeholder: effectivePlaceholder || "Ask me anything...", value: isDemoAnimatingInput ? demoInputBarText : inputBarValue, onChange: (e) => !isDemoAnimatingInput && setInputBarValue(e.target.value), readOnly: isDemoAnimatingInput, "aria-label": "Chat input" }), jsx("button", { type: "submit", className: "ai-chat-trigger-input-btn", disabled: isDemoAnimatingInput ? !demoInputBarText.trim() : !inputBarValue.trim(), "aria-label": "Send message", children: jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }), jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })] }) })] })] }))] }) }));
29888
31354
  };
29889
31355
 
29890
- export { ApiError, ChatWidget, useChat };
31356
+ export { ApiError, ChatWidget, DataPolicyView, useChat };
29891
31357
  //# sourceMappingURL=index.esm.js.map