@chatwidgetai/chat-widget 0.3.6 → 0.3.8

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 (44) hide show
  1. package/dist/ai-chat-widget.umd.js +1562 -1380
  2. package/dist/ai-chat-widget.umd.js.map +1 -1
  3. package/dist/api/client.d.ts +12 -2
  4. package/dist/api/client.d.ts.map +1 -1
  5. package/dist/components/ChatWidget/hooks/useWidgetAppearance.d.ts +37 -0
  6. package/dist/components/ChatWidget/hooks/useWidgetAppearance.d.ts.map +1 -0
  7. package/dist/components/ChatWidget/icons.d.ts +2 -0
  8. package/dist/components/ChatWidget/icons.d.ts.map +1 -0
  9. package/dist/components/ChatWidget/parts/WidgetTriggers.d.ts +25 -0
  10. package/dist/components/ChatWidget/parts/WidgetTriggers.d.ts.map +1 -0
  11. package/dist/components/ChatWidget.d.ts.map +1 -1
  12. package/dist/components/ChatWindow.d.ts +4 -1
  13. package/dist/components/ChatWindow.d.ts.map +1 -1
  14. package/dist/components/WelcomeBubble.d.ts +12 -0
  15. package/dist/components/WelcomeBubble.d.ts.map +1 -0
  16. package/dist/components/icons.d.ts +21 -0
  17. package/dist/components/icons.d.ts.map +1 -0
  18. package/dist/components/triggers/ButtonTrigger.d.ts +11 -0
  19. package/dist/components/triggers/ButtonTrigger.d.ts.map +1 -0
  20. package/dist/components/triggers/InputBarTrigger.d.ts +18 -0
  21. package/dist/components/triggers/InputBarTrigger.d.ts.map +1 -0
  22. package/dist/components/triggers/PillTrigger.d.ts +12 -0
  23. package/dist/components/triggers/PillTrigger.d.ts.map +1 -0
  24. package/dist/components/triggers/index.d.ts +8 -0
  25. package/dist/components/triggers/index.d.ts.map +1 -0
  26. package/dist/hooks/useChat/action-handler.d.ts +17 -1
  27. package/dist/hooks/useChat/action-handler.d.ts.map +1 -1
  28. package/dist/hooks/useChat/index.d.ts +5 -0
  29. package/dist/hooks/useChat/index.d.ts.map +1 -1
  30. package/dist/hooks/useChat/message-hydration.d.ts.map +1 -1
  31. package/dist/hooks/useChat/stream-buffer.d.ts +18 -0
  32. package/dist/hooks/useChat/stream-buffer.d.ts.map +1 -0
  33. package/dist/hooks/useChat/stream-handlers.d.ts +3 -3
  34. package/dist/hooks/useChat/stream-handlers.d.ts.map +1 -1
  35. package/dist/hooks/useChat/stream-state.d.ts.map +1 -1
  36. package/dist/hooks/useChat/types.d.ts +2 -0
  37. package/dist/hooks/useChat/types.d.ts.map +1 -1
  38. package/dist/index.esm.js +1562 -1380
  39. package/dist/index.esm.js.map +1 -1
  40. package/dist/index.js +1562 -1380
  41. package/dist/index.js.map +1 -1
  42. package/dist/types/index.d.ts +5 -92
  43. package/dist/types/index.d.ts.map +1 -1
  44. package/package.json +1 -1
package/dist/index.esm.js CHANGED
@@ -210,58 +210,83 @@ class WidgetApiClient {
210
210
  return typeof data === 'object' && data !== null && 'type' in data;
211
211
  });
212
212
  }
213
- async *continueAgentMessageStream(conversationId, toolCallId, state, signal) {
213
+ async *dismissAgentMessageStream(conversationId, toolCallId, signal) {
214
214
  const headers = {
215
215
  'Content-Type': 'application/json',
216
216
  };
217
217
  if (this.config.currentRoute) {
218
218
  headers['X-Current-Route'] = this.config.currentRoute;
219
219
  }
220
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/continue`, {
220
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/dismiss`, {
221
221
  method: 'POST',
222
222
  headers,
223
223
  body: JSON.stringify({
224
224
  conversationId: conversationId,
225
225
  toolCallId,
226
- state,
227
- timeZone: this.getTimeZone(),
226
+ reason: "user",
228
227
  }),
229
228
  signal,
230
229
  });
230
+ if (response.status === 204) {
231
+ return;
232
+ }
231
233
  if (!response.ok) {
232
- throw await buildApiError(response, 'Failed to continue agent');
234
+ throw await buildApiError(response, 'Failed to dismiss action');
233
235
  }
234
236
  yield* parseSSEStream(response, (data) => {
235
237
  return typeof data === 'object' && data !== null && 'type' in data;
236
238
  });
237
239
  }
238
- async *dismissAgentMessageStream(conversationId, toolCallId, signal) {
240
+ /**
241
+ * Continue agent after halting action completes
242
+ * Call this when frontend completes an action and wants to pass result back to agent
243
+ */
244
+ async *continueAgentAction(conversationId, toolCallId, body, signal) {
239
245
  const headers = {
240
246
  'Content-Type': 'application/json',
241
247
  };
242
248
  if (this.config.currentRoute) {
243
249
  headers['X-Current-Route'] = this.config.currentRoute;
244
250
  }
245
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/dismiss`, {
251
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/continue`, {
246
252
  method: 'POST',
247
253
  headers,
248
254
  body: JSON.stringify({
249
- conversationId: conversationId,
255
+ conversationId,
250
256
  toolCallId,
251
- reason: "user",
257
+ body,
258
+ timeZone: this.getTimeZone(),
252
259
  }),
253
260
  signal,
254
261
  });
255
- if (response.status === 204) {
256
- return;
257
- }
258
262
  if (!response.ok) {
259
- throw await buildApiError(response, 'Failed to dismiss action');
263
+ throw await buildApiError(response, 'Failed to continue agent action');
260
264
  }
261
265
  yield* parseSSEStream(response, (data) => {
262
266
  return typeof data === 'object' && data !== null && 'type' in data;
263
267
  });
264
268
  }
269
+ /**
270
+ * NEW: Call action endpoint (frontend-owned flow)
271
+ * Used for multi-step actions like booking appointments
272
+ */
273
+ async callActionEndpoint(actionId, endpoint, input, token) {
274
+ const headers = {
275
+ 'Content-Type': 'application/json',
276
+ };
277
+ if (token) {
278
+ headers['Authorization'] = `Bearer ${token}`;
279
+ }
280
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/actions/${actionId}/${endpoint}`, {
281
+ method: 'POST',
282
+ headers,
283
+ body: JSON.stringify(input),
284
+ });
285
+ if (!response.ok) {
286
+ throw await buildApiError(response, `Action endpoint '${endpoint}' failed`);
287
+ }
288
+ return response.json();
289
+ }
265
290
  /**
266
291
  * Submit feedback for a message
267
292
  */
@@ -292,7 +317,8 @@ class WidgetApiClient {
292
317
  }
293
318
  /**
294
319
  * Generate follow-up suggestions based on conversation context and available actions.
295
- * Called by the frontend after receiving a "done" event from the agent.
320
+ * @deprecated Follow-ups are now generated server-side in parallel and included in the done event.
321
+ * This method is kept for backwards compatibility but is no longer called by the widget.
296
322
  */
297
323
  async generateFollowUps(messages, actionIds) {
298
324
  try {
@@ -27160,7 +27186,7 @@ function TypingIndicator({ className = '' }) {
27160
27186
  }
27161
27187
 
27162
27188
  // Styles are provided by global messages.css - no component-specific CSS needed
27163
- function ChevronDownIcon() {
27189
+ function ChevronDownIcon$1() {
27164
27190
  return (jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "6 9 12 15 18 9" }) }));
27165
27191
  }
27166
27192
  function ScrollButton({ onClick, visible, className = '' }) {
@@ -27169,7 +27195,7 @@ function ScrollButton({ onClick, visible, className = '' }) {
27169
27195
  visible && 'visible',
27170
27196
  className,
27171
27197
  ].filter(Boolean).join(' ');
27172
- return (jsx("button", { type: "button", className: classes, onClick: onClick, "aria-label": "Scroll to bottom", children: jsx(ChevronDownIcon, {}) }));
27198
+ return (jsx("button", { type: "button", className: classes, onClick: onClick, "aria-label": "Scroll to bottom", children: jsx(ChevronDownIcon$1, {}) }));
27173
27199
  }
27174
27200
 
27175
27201
  const formatToolName = (name) => {
@@ -27181,13 +27207,23 @@ const formatToolName = (name) => {
27181
27207
  .join(' ');
27182
27208
  };
27183
27209
  function ToolIndicator({ badges, className = '' }) {
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))) }) }));
27210
+ // Consolidate multiple badges into a single status indicator
27211
+ const hasLoading = badges.some(b => b.status === 'loading');
27212
+ const hasError = badges.some(b => b.status === 'error');
27213
+ const status = hasLoading ? 'loading' : hasError ? 'error' : 'completed';
27214
+ // Show only the most relevant badge name, or count if multiple
27215
+ const displayName = badges.length === 1
27216
+ ? formatToolName(badges[0].name)
27217
+ : badges.length > 1
27218
+ ? `${badges.length} actions`
27219
+ : 'Processing';
27220
+ return (jsx("div", { className: `ai-chat-tool-row ${className}`, children: jsx("div", { className: "ai-chat-tool-badges", children: jsx("div", { className: `ai-chat-tool-badge ${status}`, children: jsx("span", { className: "tool-name", children: displayName }) }) }) }));
27185
27221
  }
27186
27222
 
27187
27223
  // SVG Icon components
27188
27224
  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" }) }));
27189
27225
  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" }) }));
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" }) }));
27226
+ 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" }) }));
27191
27227
  const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
27192
27228
  const [isSubmitting, setIsSubmitting] = useState(false);
27193
27229
  const [submitted, setSubmitted] = useState(false);
@@ -27208,7 +27244,7 @@ const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
27208
27244
  setIsSubmitting(false);
27209
27245
  }
27210
27246
  };
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" })] }))] }));
27247
+ 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" })] }))] }));
27212
27248
  };
27213
27249
 
27214
27250
  const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, }) => {
@@ -27237,9 +27273,11 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedb
27237
27273
  const hasContent = aiContent.trim().length > 0;
27238
27274
  if (!hasContent)
27239
27275
  return null;
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: {
27276
+ // Only show timestamp and feedback when message is complete (not streaming)
27277
+ const isComplete = !message.isStreaming;
27278
+ return (jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''} ${message.isStreaming ? 'streaming' : ''}`, children: [jsx("div", { className: "ai-chat-message-content", children: jsx(Markdown, { remarkPlugins: [remarkGfm], components: {
27241
27279
  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 }))] }))] }));
27280
+ }, children: aiContent }) }), showTimestamp && isComplete && (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 }))] }))] }));
27243
27281
  }
27244
27282
  // System message rendering
27245
27283
  if (isSystem) {
@@ -27259,7 +27297,7 @@ function isActionComplete(state) {
27259
27297
  return false;
27260
27298
  const TERMINAL_STATUSES = [
27261
27299
  'completed', 'booked', 'scheduled', 'cancelled', 'failed', 'error',
27262
- 'displaying', 'clicked', 'contacted', 'submitted', 'sent'
27300
+ 'displaying', 'displayed', 'clicked', 'contacted', 'submitted', 'sent'
27263
27301
  ];
27264
27302
  const status = state.status;
27265
27303
  if (typeof status === 'string' && TERMINAL_STATUSES.includes(status)) {
@@ -27278,10 +27316,10 @@ function isActionLoading(message) {
27278
27316
  return false;
27279
27317
  if (message.isStreaming)
27280
27318
  return true;
27281
- const state = message.action.state;
27282
- return !isActionComplete(state);
27319
+ const input = message.action.input;
27320
+ return !isActionComplete(input);
27283
27321
  }
27284
- const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant, onActionDismiss, }) => {
27322
+ const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant, onActionDismiss, onCallEndpoint, }) => {
27285
27323
  const visibleMessages = messages.filter(message => !message.action?.hidden);
27286
27324
  const actionMessages = visibleMessages.filter(message => message.action);
27287
27325
  // Debug logging
@@ -27305,7 +27343,7 @@ const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = tru
27305
27343
  implementation: impl,
27306
27344
  hasRenderer: !!renderer,
27307
27345
  rendererType: renderer ? typeof renderer : 'undefined',
27308
- state: msg.action?.state,
27346
+ input: msg.action?.input,
27309
27347
  });
27310
27348
  });
27311
27349
  // If tool indicator is hidden AND there are no action cards to render, don't render anything
@@ -27332,7 +27370,7 @@ const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = tru
27332
27370
  console.log('[ToolMessageGroup] No renderer for:', message.action.implementation);
27333
27371
  return null;
27334
27372
  }
27335
- return (jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant, onActionDismiss) }, `action-${message.id}`));
27373
+ return (jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant, onActionDismiss, onCallEndpoint) }, `action-${message.id}`));
27336
27374
  })] }));
27337
27375
  };
27338
27376
 
@@ -27366,12 +27404,29 @@ const SuggestedQuestions = ({ questions, onQuestionClick, }) => {
27366
27404
  };
27367
27405
 
27368
27406
  const MAX_TEXT_LENGTH = 40;
27407
+ const STAGGER_DELAY_MS = 200; // Delay between each suggestion appearing
27369
27408
  const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, accentColor, }) => {
27370
- if (!suggestions || suggestions.length === 0) {
27371
- return null;
27372
- }
27409
+ const [visibleIndices, setVisibleIndices] = useState(new Set());
27373
27410
  // Filter out empty suggestions
27374
- const validSuggestions = suggestions.filter(s => s && s.text && s.text.trim());
27411
+ const validSuggestions = suggestions?.filter(s => s && s.text && s.text.trim()) || [];
27412
+ // Create a stable key for the current suggestions set
27413
+ const suggestionsKey = validSuggestions.map(s => s.id).join(',');
27414
+ // Stagger reveal each suggestion one at a time
27415
+ useEffect(() => {
27416
+ // Reset when suggestions change
27417
+ setVisibleIndices(new Set());
27418
+ if (validSuggestions.length === 0)
27419
+ return;
27420
+ const timers = [];
27421
+ // Reveal each suggestion one by one
27422
+ validSuggestions.slice(0, 5).forEach((_, index) => {
27423
+ const timer = setTimeout(() => {
27424
+ setVisibleIndices(prev => new Set([...prev, index]));
27425
+ }, (index + 1) * STAGGER_DELAY_MS);
27426
+ timers.push(timer);
27427
+ });
27428
+ return () => timers.forEach(t => clearTimeout(t));
27429
+ }, [suggestionsKey]); // eslint-disable-line react-hooks/exhaustive-deps
27375
27430
  if (validSuggestions.length === 0) {
27376
27431
  return null;
27377
27432
  }
@@ -27379,8 +27434,12 @@ const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, acce
27379
27434
  ? { "--primary-color": accentColor }
27380
27435
  : undefined;
27381
27436
  const trimText = (text) => text.length > MAX_TEXT_LENGTH ? `${text.slice(0, MAX_TEXT_LENGTH)}...` : text;
27382
- return (jsx("div", { className: "ai-chat-follow-up-suggestions", style: containerStyle, children: jsx("div", { className: "ai-chat-follow-up-list", children: validSuggestions.slice(0, 5).map((suggestion) => {
27437
+ return (jsx("div", { className: "ai-chat-follow-up-suggestions", style: containerStyle, children: jsx("div", { className: "ai-chat-follow-up-list", children: validSuggestions.slice(0, 5).map((suggestion, index) => {
27383
27438
  const isActionSuggestion = suggestion.type === 'action';
27439
+ const isVisible = visibleIndices.has(index);
27440
+ // Only render if visible - this adds items one by one instead of showing all at once
27441
+ if (!isVisible)
27442
+ return null;
27384
27443
  const className = `ai-chat-follow-up-item ${isActionSuggestion ? 'action-type' : 'question-type'}`;
27385
27444
  const handleClick = () => {
27386
27445
  if (isActionSuggestion && onActionClick) {
@@ -27394,7 +27453,7 @@ const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, acce
27394
27453
  };
27395
27454
 
27396
27455
  const MessageList = (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;
27456
+ const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onActionDismiss, onFeedback, onScrollStateChange, getActionRenderer, onCallEndpoint, variant, } = props;
27398
27457
  const containerRef = useRef(null);
27399
27458
  const messagesEndRef = useRef(null);
27400
27459
  const [showScrollButton, setShowScrollButton] = useState(false);
@@ -27405,24 +27464,31 @@ const MessageList = (props) => {
27405
27464
  const lastToolMsg = [...visibleMessages].reverse().find(msg => msg.message.role === 'tool');
27406
27465
  return lastToolMsg?.action && lastToolMsg.action.done !== true;
27407
27466
  }, [visibleMessages]);
27408
- const checkScrollPosition = useCallback(() => {
27409
- const c = containerRef.current;
27410
- if (!c)
27411
- return;
27412
- const pb = parseInt(getComputedStyle(c).paddingBottom || '0', 10);
27413
- setShowScrollButton(c.scrollHeight - c.scrollTop - c.clientHeight - pb > 24);
27414
- }, []);
27415
27467
  const scrollToBottom = useCallback(() => {
27416
27468
  messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
27417
27469
  }, []);
27418
- useEffect(() => { onScrollStateChange?.(showScrollButton, scrollToBottom); }, [showScrollButton, scrollToBottom, onScrollStateChange]);
27470
+ // Use IntersectionObserver to detect when the end marker is visible
27471
+ // This is more reliable than scroll position calculations
27419
27472
  useEffect(() => {
27420
- const c = containerRef.current;
27421
- if (!c)
27473
+ const endMarker = messagesEndRef.current;
27474
+ const container = containerRef.current;
27475
+ if (!endMarker || !container)
27422
27476
  return;
27423
- c.addEventListener('scroll', checkScrollPosition);
27424
- return () => c.removeEventListener('scroll', checkScrollPosition);
27425
- }, [checkScrollPosition]);
27477
+ const observer = new IntersectionObserver((entries) => {
27478
+ // If the end marker is intersecting (visible), hide the button
27479
+ // If it's not visible, show the button
27480
+ const isAtBottom = entries[0]?.isIntersecting ?? false;
27481
+ setShowScrollButton(!isAtBottom);
27482
+ }, {
27483
+ root: container,
27484
+ // rootMargin adds extra space - if end marker is within 100px of viewport, consider it "visible"
27485
+ rootMargin: '0px 0px 100px 0px',
27486
+ threshold: 0,
27487
+ });
27488
+ observer.observe(endMarker);
27489
+ return () => observer.disconnect();
27490
+ }, []);
27491
+ useEffect(() => { onScrollStateChange?.(showScrollButton, scrollToBottom); }, [showScrollButton, scrollToBottom, onScrollStateChange]);
27426
27492
  useEffect(() => {
27427
27493
  const c = containerRef.current;
27428
27494
  if (!c)
@@ -27437,32 +27503,18 @@ const MessageList = (props) => {
27437
27503
  if ((isNew || isTyping) && c.scrollHeight - c.scrollTop - c.clientHeight < 150) {
27438
27504
  messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
27439
27505
  }
27440
- checkScrollPosition();
27441
- }, [visibleMessages, isTyping, checkScrollPosition]);
27506
+ }, [visibleMessages, isTyping]);
27442
27507
  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
- });
27454
27508
  const result = [];
27455
27509
  let toolGroup = [];
27456
27510
  const flush = () => {
27457
27511
  if (toolGroup.length) {
27458
- console.log('[DEBUG MessageList] Flushing tool group with', toolGroup.length, 'messages');
27459
27512
  result.push({ type: 'tool-group', messages: [...toolGroup] });
27460
27513
  toolGroup = [];
27461
27514
  }
27462
27515
  };
27463
27516
  for (const m of visibleMessages) {
27464
27517
  if (m.message.role === 'tool') {
27465
- console.log('[DEBUG MessageList] Adding to tool group:', m.id);
27466
27518
  toolGroup.push(m);
27467
27519
  }
27468
27520
  else if (m.message.role === 'user') {
@@ -27484,27 +27536,26 @@ const MessageList = (props) => {
27484
27536
  }
27485
27537
  }
27486
27538
  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
- });
27496
27539
  return result;
27497
27540
  }, [visibleMessages]);
27541
+ // Get the last assistant message's suggestions for rendering at the end
27542
+ const lastAssistantSuggestions = useMemo(() => {
27543
+ for (let i = groupedMessages.length - 1; i >= 0; i--) {
27544
+ const item = groupedMessages[i];
27545
+ if (item.type === 'message' && item.message.message.role === 'assistant') {
27546
+ return item.message.suggestions;
27547
+ }
27548
+ }
27549
+ return undefined;
27550
+ }, [groupedMessages]);
27498
27551
  const hasSuggestions = visibleMessages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
27499
27552
  const showWelcome = welcomeTitle || welcomeMessage || hasSuggestions;
27500
27553
  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) => {
27501
27554
  if (item.type === 'tool-group') {
27502
- return (jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant, onActionDismiss: onActionDismiss }, `tg-${i}`));
27555
+ return (jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant, onActionDismiss: onActionDismiss, onCallEndpoint: onCallEndpoint }, `tg-${i}`));
27503
27556
  }
27504
- const isLast = i === groupedMessages.length - 1;
27505
- const hasFollowUp = item.message.message.role === 'assistant' && item.message.suggestions?.length && isLast && !isTyping;
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));
27507
- }), isTyping && showTypingIndicator && !hasActiveAction && visibleMessages.length > 0 && jsx(TypingIndicator, {}), jsx("div", { ref: messagesEndRef })] }));
27557
+ return (jsx(Message, { message: item.message, showTimestamp: showTimestamps, enableFeedback: enableFeedback, onFeedback: onFeedback, getActionRenderer: getActionRenderer, accentColor: accentColor }, item.message.id));
27558
+ }), !isTyping && lastAssistantSuggestions?.length && onSuggestedQuestionClick && (jsx(FollowUpSuggestions, { suggestions: lastAssistantSuggestions, onQuestionClick: onSuggestedQuestionClick, onActionClick: onActionClick, accentColor: accentColor })), isTyping && showTypingIndicator && !hasActiveAction && visibleMessages.length > 0 && jsx(TypingIndicator, {}), jsx("div", { ref: messagesEndRef })] }));
27508
27559
  };
27509
27560
 
27510
27561
  const ALLOWED_EXTENSIONS = ['.pdf', '.doc', '.docx', '.txt', '.md', '.csv'];
@@ -27518,7 +27569,7 @@ const formatFileSize = (bytes) => {
27518
27569
  return (bytes / 1024).toFixed(1) + ' KB';
27519
27570
  return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
27520
27571
  };
27521
- const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, showDataPolicy = true, onDataPolicyClick, }) => {
27572
+ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, showDataPolicy = true, onDataPolicyClick, onInputFocus, }) => {
27522
27573
  const [value, setValue] = useState('');
27523
27574
  const [selectedFiles, setSelectedFiles] = useState([]);
27524
27575
  const textareaRef = useRef(null);
@@ -27553,492 +27604,15 @@ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled =
27553
27604
  }
27554
27605
  };
27555
27606
  const canSend = value.trim() || selectedFiles.length > 0;
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" })] }))] }))] }));
27557
- };
27558
-
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" }) }) }));
27607
+ 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, onFocus: onInputFocus, 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" })] }))] }))] }));
27561
27608
  };
27562
27609
 
27563
- function groupSlotsByDate$1(slots) {
27564
- const grouped = new Map();
27565
- for (const slot of slots) {
27566
- if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
27567
- continue;
27568
- }
27569
- const date = slot.startTime.slice(0, 10);
27570
- if (!grouped.has(date)) {
27571
- grouped.set(date, []);
27572
- }
27573
- grouped.get(date).push(slot);
27574
- }
27575
- return grouped;
27576
- }
27577
- function formatDate$1(dateStr) {
27578
- try {
27579
- const date = new Date(dateStr);
27580
- return new Intl.DateTimeFormat("en-US", {
27581
- weekday: "short",
27582
- month: "short",
27583
- day: "numeric",
27584
- }).format(date);
27585
- }
27586
- catch {
27587
- return dateStr;
27588
- }
27589
- }
27590
- function CalendarIcon$1() {
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" }) }));
27592
- }
27593
- function CheckIcon$1() {
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" }) }));
27595
- }
27596
- function ExternalLinkIcon$2() {
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" })] }));
27598
- }
27599
- function Skeleton$2({ width, height, borderRadius = '4px' }) {
27600
- return (jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
27601
- }
27602
- function GoogleCalendarCard({ action, onComplete, onDismiss, accentColor, className = '' }) {
27603
- const state = action.state;
27604
- const rawSlots = state.availableSlots;
27605
- const availableSlots = Array.isArray(rawSlots)
27606
- ? rawSlots.filter((slot) => slot !== null &&
27607
- slot !== undefined &&
27608
- typeof slot === "object" &&
27609
- "startTime" in slot &&
27610
- "endTime" in slot &&
27611
- typeof slot.startTime === "string" &&
27612
- typeof slot.endTime === "string")
27613
- : [];
27614
- const allowTopic = state.allowTopic !== false;
27615
- const isBooked = state.status === "booked";
27616
- const slotsByDate = groupSlotsByDate$1(availableSlots);
27617
- const dates = Array.from(slotsByDate.keys()).sort();
27618
- const [selectedDate, setSelectedDate] = useState(dates[0] ?? "");
27619
- const [selectedSlot, setSelectedSlot] = useState(null);
27620
- const [topic, setTopic] = useState("");
27621
- const [error, setError] = useState(null);
27622
- const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
27623
- const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
27624
- const onConfirm = () => {
27625
- if (!selectedSlot) {
27626
- setError("Please select a time slot.");
27627
- return;
27628
- }
27629
- if (allowTopic && !topic.trim()) {
27630
- setError("Please enter a topic for the meeting.");
27631
- return;
27632
- }
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);
27875
- setIsSubmitting(true);
27876
- console.log('[MicrosoftCalendarCard] Confirming appointment:', {
27877
- slot: selectedSlot,
27878
- topic: topic.trim()
27879
- });
27880
- setTimeout(() => {
27881
- onComplete?.(action.toolCallId, {
27882
- ...action.state,
27883
- selectedSlot: {
27884
- startTime: selectedSlot.startTime,
27885
- endTime: selectedSlot.endTime,
27886
- },
27887
- topic: allowTopic ? topic.trim() : null,
27888
- });
27889
- }, 50);
27890
- };
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") {
27913
- const bookedSlot = state.selectedSlot;
27914
- const bookedTopic = state.topic;
27915
- const eventLink = state.bookedEventLink;
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
27948
- if (isSubmitting) {
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;
28034
- }
28035
-
28036
- function truncate(text, maxLength) {
27610
+ function truncate$1(text, maxLength) {
28037
27611
  if (text.length <= maxLength)
28038
27612
  return text;
28039
27613
  return text.slice(0, maxLength).trim() + '...';
28040
27614
  }
28041
- function ExternalLinkIcon() {
27615
+ function ExternalLinkIcon$2() {
28042
27616
  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" })] }));
28043
27617
  }
28044
27618
  function SingleLinkPreview({ link, onLinkClick, accentColor }) {
@@ -28057,10 +27631,10 @@ function SingleLinkPreview({ link, onLinkClick, accentColor }) {
28057
27631
  e.currentTarget.parentElement.style.display = 'none';
28058
27632
  } }) })), 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
27633
  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, {}) })] }));
27634
+ } })), 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$1(link.description, 120) }))] }), jsx("div", { className: "ai-chat-link-preview__arrow", children: jsx(ExternalLinkIcon$2, {}) })] }));
28061
27635
  }
28062
27636
  function LinkPreviewCard({ action, onComplete, accentColor }) {
28063
- const rawState = action.state;
27637
+ const rawState = action.input;
28064
27638
  const hasCompletedRef = useRef(false);
28065
27639
  // Provide safe defaults if state is missing
28066
27640
  const state = {
@@ -28090,11 +27664,12 @@ function LinkPreviewCard({ action, onComplete, accentColor }) {
28090
27664
  if (state.links.length === 0) {
28091
27665
  return null;
28092
27666
  }
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))) })] }));
27667
+ const gridClass = state.links.length === 1
27668
+ ? 'ai-chat-link-preview-grid ai-chat-link-preview-grid--single'
27669
+ : state.links.length === 2
27670
+ ? 'ai-chat-link-preview-grid ai-chat-link-preview-grid--double'
27671
+ : 'ai-chat-link-preview-grid ai-chat-link-preview-grid--triple';
27672
+ 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: gridClass, children: state.links.map((link, index) => (jsx(SingleLinkPreview, { link: link, onLinkClick: () => handleLinkClick(link.url), accentColor: accentColor }, index))) })] }));
28098
27673
  }
28099
27674
 
28100
27675
  function PlayIcon() {
@@ -28115,7 +27690,7 @@ function getProviderLabel(provider) {
28115
27690
  }
28116
27691
  }
28117
27692
  function VideoPlayerCard({ action, onComplete, accentColor }) {
28118
- const rawState = action.state;
27693
+ const rawState = action.input;
28119
27694
  const hasCompletedRef = useRef(false);
28120
27695
  const [isPlaying, setIsPlaying] = useState(false);
28121
27696
  // Provide safe defaults if state is missing
@@ -28226,7 +27801,7 @@ function LocationItem({ location, settings, accentColor, onDirections, showMap =
28226
27801
  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"] }))] })] })] }));
28227
27802
  }
28228
27803
  function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28229
- const rawState = action.state;
27804
+ const rawState = action.input;
28230
27805
  const hasCompletedRef = useRef(false);
28231
27806
  const state = {
28232
27807
  locations: rawState?.locations || [],
@@ -28308,7 +27883,7 @@ function ContactItem({ contact, settings, accentColor, onEmail, onPhone, compact
28308
27883
  })()] }), 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
27884
  }
28310
27885
  function ContactCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28311
- const rawState = action.state;
27886
+ const rawState = action.input;
28312
27887
  const hasCompletedRef = useRef(false);
28313
27888
  const state = {
28314
27889
  contacts: rawState?.contacts || [],
@@ -28343,11 +27918,37 @@ function ContactCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28343
27918
  }, 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
27919
  }
28345
27920
 
27921
+ const CloseButton = ({ onClick, className = "", ariaLabel = "Close", }) => {
27922
+ 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" }) }) }));
27923
+ };
27924
+
27925
+ function FormIcon(props) {
27926
+ return (jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsx("path", { d: "M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" }), jsx("polyline", { points: "14,2 14,8 20,8" }), jsx("line", { x1: "16", y1: "13", x2: "8", y2: "13" }), jsx("line", { x1: "16", y1: "17", x2: "8", y2: "17" }), jsx("line", { x1: "10", y1: "9", x2: "8", y2: "9" })] }));
27927
+ }
27928
+ function CheckIcon(props) {
27929
+ return (jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: jsx("polyline", { points: "20,6 9,17 4,12" }) }));
27930
+ }
27931
+ function WarningIcon(props) {
27932
+ return (jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsx("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }), jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }), jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })] }));
27933
+ }
27934
+ function SkipIcon(props) {
27935
+ return (jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsx("polygon", { points: "5,4 15,12 5,20 5,4" }), jsx("line", { x1: "19", y1: "5", x2: "19", y2: "19" })] }));
27936
+ }
27937
+ function BackArrowIcon(props) {
27938
+ return (jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: jsx("polyline", { points: "15,18 9,12 15,6" }) }));
27939
+ }
27940
+
28346
27941
  function FormCard({ action, onComplete, onDismiss, accentColor }) {
28347
- const state = action.state;
27942
+ const state = action.input;
28348
27943
  const [currentStep, setCurrentStep] = useState(0);
28349
27944
  const [answers, setAnswers] = useState({});
28350
27945
  const [isSubmitting, setIsSubmitting] = useState(false);
27946
+ const [localStatus, setLocalStatus] = useState(null);
27947
+ // If action is already done, show simple completion indicator
27948
+ // The agent's response will convey what happened
27949
+ if (action.done) {
27950
+ return (jsx("div", { className: "ai-chat-form-card ai-chat-form-card--completed", children: jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: jsx(CheckIcon, {}) }), jsx("span", { className: "ai-chat-form-card__title", children: "Form completed" })] }) }));
27951
+ }
28351
27952
  const questions = state.questions || [];
28352
27953
  const currentQuestion = questions[currentStep];
28353
27954
  const totalQuestions = questions.length;
@@ -28368,6 +27969,7 @@ function FormCard({ action, onComplete, onDismiss, accentColor }) {
28368
27969
  if (!onComplete)
28369
27970
  return;
28370
27971
  setIsSubmitting(true);
27972
+ setLocalStatus('submitted');
28371
27973
  const formattedAnswers = Object.entries(answers).map(([questionId, value]) => ({
28372
27974
  questionId,
28373
27975
  value,
@@ -28381,6 +27983,7 @@ function FormCard({ action, onComplete, onDismiss, accentColor }) {
28381
27983
  const handleSkip = () => {
28382
27984
  if (!onComplete || !state.settings.allowSkip)
28383
27985
  return;
27986
+ setLocalStatus('skipped');
28384
27987
  onComplete(action.toolCallId, {
28385
27988
  ...state,
28386
27989
  status: 'skipped',
@@ -28411,24 +28014,26 @@ function FormCard({ action, onComplete, onDismiss, accentColor }) {
28411
28014
  const handleDismiss = () => {
28412
28015
  onDismiss?.(action.toolCallId);
28413
28016
  };
28017
+ // Use local status if available (for immediate UI feedback), otherwise use state.status
28018
+ const effectiveStatus = localStatus || state.status;
28414
28019
  // 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' })] }));
28020
+ if (effectiveStatus === 'error') {
28021
+ 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: jsx(WarningIcon, {}) }), 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
28022
  }
28418
28023
  // 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!' })] }));
28024
+ if (effectiveStatus === 'submitted') {
28025
+ 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: jsx(CheckIcon, {}) }), 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
28026
  }
28422
28027
  // 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" })] }));
28028
+ if (effectiveStatus === 'skipped') {
28029
+ 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: jsx(SkipIcon, {}) }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsx("p", { className: "ai-chat-form-card__skipped-text", children: "Form skipped" })] }));
28425
28030
  }
28426
28031
  // No questions
28427
28032
  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." })] }));
28033
+ 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: jsx(FormIcon, {}) }), 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
28034
  }
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: {
28035
+ const showCloseButton = effectiveStatus === "displaying" && !action.done && Boolean(onDismiss);
28036
+ 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: jsx(FormIcon, {}) }), 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
28037
  width: `${((currentStep + 1) / totalQuestions) * 100}%`,
28433
28038
  backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
28434
28039
  } }), 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) => {
@@ -28454,9 +28059,37 @@ function FormCard({ action, onComplete, onDismiss, accentColor }) {
28454
28059
  }, children: isSubmitting ? 'Submitting...' : (state.settings.submitButtonText || 'Submit') }))] })] }));
28455
28060
  }
28456
28061
 
28062
+ function EmailPhase({ accentColor, onDismiss, showCloseButton, onSubmit, isLoading, error, }) {
28063
+ const [emailInput, setEmailInput] = useState('');
28064
+ const [localError, setLocalError] = useState(null);
28065
+ const handleSubmit = () => {
28066
+ const trimmedEmail = emailInput.trim();
28067
+ if (!trimmedEmail) {
28068
+ setLocalError('Please enter your email address');
28069
+ return;
28070
+ }
28071
+ if (!trimmedEmail.includes('@')) {
28072
+ setLocalError('Please enter a valid email address');
28073
+ return;
28074
+ }
28075
+ setLocalError(null);
28076
+ onSubmit(trimmedEmail);
28077
+ };
28078
+ const displayError = localError || error;
28079
+ return (jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__title", children: "Enter Your Email" }), showCloseButton && onDismiss && jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), 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) => {
28080
+ setEmailInput(e.target.value);
28081
+ setLocalError(null);
28082
+ }, onKeyDown: (e) => {
28083
+ if (e.key === 'Enter' && !isLoading) {
28084
+ handleSubmit();
28085
+ }
28086
+ }, disabled: isLoading }), jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleSubmit, disabled: !emailInput.trim() || isLoading, children: isLoading ? 'Sending...' : 'Continue' })] })] }));
28087
+ }
28088
+
28457
28089
  function Skeleton({ width, height, borderRadius = '4px' }) {
28458
28090
  return (jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
28459
28091
  }
28092
+
28460
28093
  function PinInputGroup({ values, onChange, disabled }) {
28461
28094
  const inputRefs = useRef([]);
28462
28095
  const handleChange = (index, value) => {
@@ -28488,299 +28121,853 @@ function PinInputGroup({ values, onChange, disabled }) {
28488
28121
  inputRefs.current[index] = el;
28489
28122
  }, 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
28123
  }
28491
- function BookContactAppointmentCard({ action, onComplete, accentColor }) {
28492
- const state = action.state;
28493
- const [emailInput, setEmailInput] = useState('');
28124
+
28125
+ function OtpPhase({ accentColor, onDismiss, showCloseButton, email, onSubmit, onResend, isLoading, error, }) {
28494
28126
  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)
28127
+ const [localError, setLocalError] = useState(null);
28128
+ const [isResending, setIsResending] = useState(false);
28129
+ const handleSubmit = () => {
28130
+ const code = otpValues.join('');
28131
+ if (code.length !== 6) {
28132
+ setLocalError('Please enter the 6-digit code');
28502
28133
  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
28134
  }
28522
- else {
28523
- setEmailError(null);
28524
- setOtpError(null);
28135
+ setLocalError(null);
28136
+ onSubmit(code);
28137
+ };
28138
+ const handleResend = async () => {
28139
+ setIsResending(true);
28140
+ setLocalError(null);
28141
+ try {
28142
+ await onResend();
28525
28143
  }
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;
28144
+ finally {
28145
+ setIsResending(false);
28534
28146
  }
28535
- setEmailError(null);
28536
- setEmailInput(trimmedEmail);
28537
- handleSubmit({ email: trimmedEmail });
28538
28147
  };
28539
- const handleOtpSubmit = () => {
28540
- const code = otpValues.join('');
28541
- if (code.length !== 6) {
28542
- setOtpError('Please enter the 6-digit code');
28148
+ const displayError = localError || error;
28149
+ return (jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__title", children: "Verify Your Email" }), showCloseButton && onDismiss && jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), 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: email })] }), jsx(PinInputGroup, { values: otpValues, onChange: (newValues) => {
28150
+ setOtpValues(newValues);
28151
+ setLocalError(null);
28152
+ // Auto-submit when all 6 digits are entered
28153
+ if (newValues.every((value) => value.length === 1) && !isLoading) {
28154
+ onSubmit(newValues.join(''));
28155
+ }
28156
+ }, disabled: isLoading }), 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: handleSubmit, disabled: otpValues.join('').length !== 6 || isLoading, children: isLoading ? 'Verifying...' : 'Verify' }), jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: handleResend, disabled: isLoading || isResending, children: isResending ? 'Sending...' : 'Resend Code' })] })] }));
28157
+ }
28158
+
28159
+ function ContactSelectionPhase({ accentColor, onDismiss, showCloseButton, contacts, onSelect, }) {
28160
+ return (jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__title", children: "Select Contact" }), showCloseButton && onDismiss && jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [jsx("p", { className: "ai-chat-booking-card__description", children: "Choose who you would like to book an appointment with:" }), jsx("div", { className: "ai-chat-booking-card__list", children: contacts.map((contact) => (jsxs("button", { className: "ai-chat-booking-card__list-item", onClick: () => onSelect(contact.id), children: [jsxs("div", { className: "ai-chat-booking-card__list-item-content", children: [jsx("span", { className: "ai-chat-booking-card__list-item-name", children: contact.name }), contact.role && (jsx("span", { className: "ai-chat-booking-card__list-item-role", children: contact.role }))] }), jsx("span", { className: "ai-chat-booking-card__list-item-arrow", "aria-hidden": "true" })] }, contact.id))) })] })] }));
28161
+ }
28162
+
28163
+ // Calendar icon SVG
28164
+ const CalendarIcon = () => (jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }), jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }), jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })] }));
28165
+ // List icon SVG
28166
+ const ListIcon = () => (jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "8", y1: "6", x2: "21", y2: "6" }), jsx("line", { x1: "8", y1: "12", x2: "21", y2: "12" }), jsx("line", { x1: "8", y1: "18", x2: "21", y2: "18" }), jsx("line", { x1: "3", y1: "6", x2: "3.01", y2: "6" }), jsx("line", { x1: "3", y1: "12", x2: "3.01", y2: "12" }), jsx("line", { x1: "3", y1: "18", x2: "3.01", y2: "18" })] }));
28167
+ function OptionsPhase({ onDismiss, showCloseButton, appointments, maxAppointments, onBookNew, onViewAppointments, isCancelling, }) {
28168
+ const activeAppointments = appointments.filter(a => a.status !== 'cancelled' && a.status !== 'declined');
28169
+ const canBookNew = activeAppointments.length < maxAppointments;
28170
+ const hasAppointments = appointments.length > 0;
28171
+ return (jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("span", { className: "ai-chat-booking-card__title", children: "Booking Options" }), showCloseButton && onDismiss && jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [!canBookNew && (jsxs("p", { className: "ai-chat-booking-card__warning", children: ["You have reached the maximum number of appointments (", maxAppointments, "). Please cancel an existing appointment to book a new one."] })), jsxs("div", { className: "ai-chat-booking-card__options", children: [jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: onBookNew, disabled: !canBookNew || isCancelling, children: [jsx("span", { className: "ai-chat-booking-card__option-icon", children: jsx(CalendarIcon, {}) }), jsx("span", { className: "ai-chat-booking-card__option-text", children: "Book New Appointment" })] }), hasAppointments && (jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: onViewAppointments, disabled: isCancelling, children: [jsx("span", { className: "ai-chat-booking-card__option-icon", children: jsx(ListIcon, {}) }), jsxs("span", { className: "ai-chat-booking-card__option-text", children: ["View My Appointments (", activeAppointments.length, ")"] })] }))] })] })] }));
28172
+ }
28173
+
28174
+ function ViewAppointmentsPhase({ accentColor, onDismiss, showCloseButton, appointments, onBack, onCancelAppointment, isCancelling, }) {
28175
+ const [cancellingId, setCancellingId] = useState(null);
28176
+ const handleCancel = async (appointmentId) => {
28177
+ setCancellingId(appointmentId);
28178
+ await onCancelAppointment(appointmentId);
28179
+ setCancellingId(null);
28180
+ };
28181
+ const activeAppointments = appointments.filter(a => a.status !== 'cancelled');
28182
+ return (jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("button", { className: "ai-chat-booking-card__back-btn", onClick: onBack, children: "Back" }), jsx("span", { className: "ai-chat-booking-card__title", children: "My Appointments" }), showCloseButton && onDismiss && jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsx("div", { className: "ai-chat-booking-card__content", children: activeAppointments.length === 0 ? (jsx("p", { className: "ai-chat-booking-card__empty", children: "No appointments found." })) : (jsx("div", { className: "ai-chat-booking-card__appointments", children: activeAppointments.map((apt) => (jsxs("div", { className: "ai-chat-booking-card__appointment", children: [jsxs("div", { className: "ai-chat-booking-card__appointment-info", children: [jsx("span", { className: "ai-chat-booking-card__appointment-subject", children: apt.subject }), jsx("span", { className: "ai-chat-booking-card__appointment-contact", children: apt.contactName }), jsx("span", { className: "ai-chat-booking-card__appointment-time", children: apt.displayTime }), jsx("span", { className: `ai-chat-booking-card__appointment-status ai-chat-booking-card__appointment-status--${apt.status}`, children: apt.status === 'pending' ? 'Pending Approval' : apt.status })] }), jsxs("div", { className: "ai-chat-booking-card__appointment-actions", children: [apt.teamsLink && (jsx("a", { href: apt.teamsLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__appointment-link", children: "Join Meeting" })), apt.googleMeetLink && (jsx("a", { href: apt.googleMeetLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__appointment-link", children: "Join Meeting" })), jsx("button", { className: "ai-chat-booking-card__appointment-cancel", onClick: () => handleCancel(apt.id), disabled: isCancelling || cancellingId === apt.id, children: cancellingId === apt.id ? 'Cancelling...' : 'Cancel' })] })] }, apt.id))) })) })] }));
28183
+ }
28184
+
28185
+ function SlotSelectionPhase({ onDismiss, showCloseButton, slots, contactName, onSelect, onBack, isLoading, error, }) {
28186
+ // Group slots by date
28187
+ const slotsByDate = useMemo(() => {
28188
+ const grouped = {};
28189
+ for (const slot of slots) {
28190
+ const date = slot.displayDate;
28191
+ if (!grouped[date]) {
28192
+ grouped[date] = [];
28193
+ }
28194
+ grouped[date].push(slot);
28195
+ }
28196
+ return grouped;
28197
+ }, [slots]);
28198
+ const dates = Object.keys(slotsByDate);
28199
+ return (jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("button", { className: "ai-chat-booking-card__back-btn", onClick: onBack, children: "Back" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Select Time Slot" }), showCloseButton && onDismiss && jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [contactName && (jsxs("p", { className: "ai-chat-booking-card__description", children: ["Available times for ", jsx("strong", { children: contactName }), ":"] })), error && (jsx("p", { className: "ai-chat-booking-card__error", children: error })), slots.length === 0 ? (jsx("p", { className: "ai-chat-booking-card__empty", children: "No available time slots found. Please try again later." })) : (jsx("div", { className: "ai-chat-booking-card__slots-container", children: dates.map((date) => (jsxs("div", { className: "ai-chat-booking-card__date-group", children: [jsx("h4", { className: "ai-chat-booking-card__date-header", children: date }), jsx("div", { className: "ai-chat-booking-card__slots", children: slotsByDate[date].map((slot) => (jsx("button", { className: "ai-chat-booking-card__slot", onClick: () => onSelect({ startTime: slot.startTime, endTime: slot.endTime }), disabled: isLoading, children: slot.displayTime }, `${slot.startTime}-${slot.endTime}`))) })] }, date))) }))] })] }));
28200
+ }
28201
+
28202
+ function ConfirmationPhase({ onDismiss, showCloseButton, contactName, slotDisplay, subjectMode, predefinedSubjects, onConfirm, onBack, isLoading, error, }) {
28203
+ const [subject, setSubject] = useState('');
28204
+ const [selectedPredefined, setSelectedPredefined] = useState('');
28205
+ const [localError, setLocalError] = useState(null);
28206
+ const handleConfirm = () => {
28207
+ const finalSubject = subjectMode === 'predefined' ? selectedPredefined : subject.trim();
28208
+ if (!finalSubject) {
28209
+ setLocalError('Please enter a subject for your appointment');
28543
28210
  return;
28544
28211
  }
28545
- setOtpError(null);
28546
- const resolvedEmail = state.email || emailInput.trim() || null;
28547
- handleSubmit({ otpCode: code, email: resolvedEmail });
28212
+ setLocalError(null);
28213
+ onConfirm(finalSubject);
28548
28214
  };
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..." }) })] }));
28215
+ const displayError = localError || error;
28216
+ const isValid = subjectMode === 'predefined' ? !!selectedPredefined : !!subject.trim();
28217
+ return (jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxs("div", { className: "ai-chat-booking-card__header", children: [jsx("button", { className: "ai-chat-booking-card__back-btn", onClick: onBack, "aria-label": "Go back", children: jsx(BackArrowIcon, {}) }), jsx("span", { className: "ai-chat-booking-card__title", children: "Confirm Booking" }), showCloseButton && onDismiss && jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxs("div", { className: "ai-chat-booking-card__summary", children: [contactName && (jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsx("span", { className: "ai-chat-booking-card__summary-label", children: "With:" }), jsx("span", { className: "ai-chat-booking-card__summary-value", children: contactName })] })), jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsx("span", { className: "ai-chat-booking-card__summary-label", children: "When:" }), jsx("span", { className: "ai-chat-booking-card__summary-value", children: slotDisplay })] })] }), displayError && (jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), subjectMode === 'predefined' ? (jsxs("div", { className: "ai-chat-booking-card__field", children: [jsx("label", { className: "ai-chat-booking-card__label", children: "Select a topic:" }), jsx("div", { className: "ai-chat-booking-card__subject-options", children: predefinedSubjects.map((subj) => (jsx("button", { className: `ai-chat-booking-card__subject-option ${selectedPredefined === subj ? 'ai-chat-booking-card__subject-option--selected' : ''}`, onClick: () => {
28218
+ setSelectedPredefined(subj);
28219
+ setLocalError(null);
28220
+ }, disabled: isLoading, children: subj }, subj))) })] })) : (jsxs("div", { className: "ai-chat-booking-card__field", children: [jsx("label", { className: "ai-chat-booking-card__label", children: "What would you like to discuss?" }), jsx("input", { type: "text", className: "ai-chat-booking-card__input", placeholder: "Enter appointment subject...", value: subject, onChange: (e) => {
28221
+ setSubject(e.target.value);
28222
+ setLocalError(null);
28223
+ }, onKeyDown: (e) => {
28224
+ if (e.key === 'Enter' && isValid && !isLoading) {
28225
+ handleConfirm();
28226
+ }
28227
+ }, disabled: isLoading })] })), jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleConfirm, disabled: !isValid || isLoading, children: isLoading ? 'Booking...' : 'Confirm Booking' })] })] }));
28672
28228
  }
28673
28229
 
28674
- const pendingResolvers = new Map();
28675
- const resumeCallbacks = new Map();
28676
- const frontendActionHandlers = {};
28677
- const actionRenderers = {};
28678
- function getFrontendActionHandler(implementation) {
28679
- return frontendActionHandlers[implementation];
28230
+ function BookedPhase({ subject, contactName, meetingLink, meetingProvider, }) {
28231
+ return (jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--success", children: [jsx("div", { className: "ai-chat-booking-card__header", children: jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Booked" }) }), jsxs("div", { className: "ai-chat-booking-card__content", children: [jsx("div", { className: "ai-chat-booking-card__success-icon", "aria-hidden": "true" }), jsx("p", { className: "ai-chat-booking-card__success-message", children: "Your appointment has been successfully scheduled." }), 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: "Subject:" }), jsx("span", { className: "ai-chat-booking-card__summary-value", children: subject })] }), contactName && (jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsx("span", { className: "ai-chat-booking-card__summary-label", children: "With:" }), jsx("span", { className: "ai-chat-booking-card__summary-value", children: contactName })] }))] }), meetingLink && (jsx("a", { href: meetingLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", style: {
28232
+ textDecoration: 'none',
28233
+ display: 'inline-block',
28234
+ textAlign: 'center',
28235
+ }, children: meetingProvider === 'google' ? 'Join Google Meet' : 'Join Teams Meeting' }))] })] }));
28680
28236
  }
28681
- function getActionRenderer(implementation) {
28682
- return actionRenderers[implementation];
28237
+
28238
+ function PendingApprovalPhase({ subject, contactName }) {
28239
+ 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__status-icon ai-chat-booking-card__status-icon--pending" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Awaiting Approval" })] }), jsxs("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." }), 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: "Subject:" }), jsx("span", { className: "ai-chat-booking-card__summary-value", children: subject })] }), contactName && (jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsx("span", { className: "ai-chat-booking-card__summary-label", children: "With:" }), jsx("span", { className: "ai-chat-booking-card__summary-value", children: contactName })] }))] })] })] }));
28683
28240
  }
28684
- function waitForActionState(toolCallId) {
28685
- return new Promise((resolve) => {
28686
- pendingResolvers.set(toolCallId, resolve);
28687
- });
28241
+
28242
+ /**
28243
+ * Cancelled Phase Component (terminal state)
28244
+ */
28245
+ function CancelledPhase() {
28246
+ return (jsxs("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__status-icon ai-chat-booking-card__status-icon--cancelled" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Cancelled" })] }), jsx("div", { className: "ai-chat-booking-card__content", children: jsx("p", { className: "ai-chat-booking-card__description", children: "This appointment has been cancelled." }) })] }));
28688
28247
  }
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);
28697
- if (resumeCallback) {
28698
- resumeCallback(state).catch((error) => {
28699
- console.error("[Action] Failed to resume action:", error);
28700
- });
28701
- }
28248
+
28249
+ function ErrorPhase({ error, onRetry }) {
28250
+ 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__status-icon ai-chat-booking-card__status-icon--error" }), jsx("span", { className: "ai-chat-booking-card__title", children: "Booking Error" })] }), jsxs("div", { className: "ai-chat-booking-card__content", children: [jsx("p", { className: "ai-chat-booking-card__error", children: error }), onRetry && (jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: onRetry, children: "Try Again" }))] })] }));
28702
28251
  }
28703
- function registerActionResumeCallback(toolCallId, callback) {
28704
- resumeCallbacks.set(toolCallId, callback);
28252
+
28253
+ function CompletedPhase() {
28254
+ return (jsx("div", { className: "ai-chat-booking-card ai-chat-booking-card--completed", children: jsxs("div", { className: "ai-chat-booking-card__completed-indicator", children: [jsx(CheckIcon, {}), jsx("span", { children: "Booking action completed" })] }) }));
28705
28255
  }
28706
- function unregisterActionResumeCallback(toolCallId) {
28707
- resumeCallbacks.delete(toolCallId);
28256
+
28257
+ function LoadingPhase() {
28258
+ return (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" })] }) }));
28708
28259
  }
28709
28260
 
28710
- function registerGoogleCalendarHandler() {
28711
- frontendActionHandlers["google-calendar-appointment"] = async (_input, _state, context) => {
28712
- return waitForActionState(context.toolCallId);
28261
+ /**
28262
+ * Core action lifecycle handlers for booking flow
28263
+ */
28264
+ function useBookingAction({ onComplete, onDismiss, toolCallId, }) {
28265
+ const handleDismiss = useCallback(() => {
28266
+ onDismiss?.(toolCallId);
28267
+ }, [onDismiss, toolCallId]);
28268
+ const finishAction = useCallback((body) => {
28269
+ if (!onComplete)
28270
+ return;
28271
+ onComplete(toolCallId, body);
28272
+ }, [onComplete, toolCallId]);
28273
+ return {
28274
+ handleDismiss,
28275
+ finishAction,
28713
28276
  };
28714
28277
  }
28715
28278
 
28716
28279
  /**
28717
- * Register google-calendar-appointment action handler and renderer.
28718
- * Called by initializeActionHandlers to prevent tree-shaking.
28280
+ * Helper functions for accessing booking data
28719
28281
  */
28720
- function registerGoogleCalendarAction() {
28721
- // Register the handler
28722
- registerGoogleCalendarHandler();
28723
- // Register the renderer
28724
- actionRenderers["google-calendar-appointment"] = (message, accentColor, _variant, onActionDismiss) => {
28725
- const action = message.action;
28726
- if (!action)
28727
- return null;
28728
- const handleComplete = (toolCallId, newState) => {
28729
- resolveActionState(toolCallId, newState);
28730
- };
28731
- const handleDismiss = onActionDismiss
28732
- ? (toolCallId) => {
28733
- resolveActionState(toolCallId, { __dismissed: true });
28734
- onActionDismiss(toolCallId);
28282
+ function useBookingHelpers({ contacts, slots, bookingMode, }) {
28283
+ const getContactName = useCallback((contactId) => {
28284
+ if (!contactId)
28285
+ return bookingMode === 'general' ? 'Shared Calendar' : null;
28286
+ const contact = contacts.find(c => c.id === contactId);
28287
+ return contact?.name || null;
28288
+ }, [contacts, bookingMode]);
28289
+ const getSlotDisplay = useCallback((slot) => {
28290
+ if (!slot)
28291
+ return '';
28292
+ const slotData = slots.find(s => s.startTime === slot.startTime && s.endTime === slot.endTime);
28293
+ return slotData ? `${slotData.displayDate} ${slotData.displayTime}` : '';
28294
+ }, [slots]);
28295
+ return {
28296
+ getContactName,
28297
+ getSlotDisplay,
28298
+ };
28299
+ }
28300
+
28301
+ /**
28302
+ * OTP-related operations for email verification
28303
+ */
28304
+ function useBookingOtp({ onCallEndpoint, state, setState, config, }) {
28305
+ const handleSendOtp = useCallback(async (email) => {
28306
+ if (!onCallEndpoint) {
28307
+ setState(prev => ({ ...prev, error: 'Endpoint not available' }));
28308
+ return;
28309
+ }
28310
+ setState(prev => ({ ...prev, isLoading: true, error: null, email }));
28311
+ try {
28312
+ await onCallEndpoint('send-otp', { email });
28313
+ setState(prev => ({ ...prev, isLoading: false, step: 'otp' }));
28314
+ }
28315
+ catch (err) {
28316
+ const message = err instanceof Error ? err.message : 'Failed to send verification code';
28317
+ setState(prev => ({ ...prev, isLoading: false, error: message }));
28318
+ }
28319
+ }, [onCallEndpoint, setState]);
28320
+ const handleVerifyOtp = useCallback(async (code) => {
28321
+ if (!onCallEndpoint) {
28322
+ setState(prev => ({ ...prev, error: 'Endpoint not available' }));
28323
+ return;
28324
+ }
28325
+ setState(prev => ({ ...prev, isLoading: true, error: null }));
28326
+ try {
28327
+ const result = await onCallEndpoint('verify-otp', {
28328
+ email: state.email,
28329
+ code,
28330
+ bookingMode: config.bookingMode,
28331
+ timeZone: config.timeZone,
28332
+ });
28333
+ const nextStep = config.bookingMode === 'general'
28334
+ ? 'options'
28335
+ : result.contacts.length === 1
28336
+ ? 'options'
28337
+ : 'contact_selection';
28338
+ setState(prev => ({
28339
+ ...prev,
28340
+ isLoading: false,
28341
+ token: result.token,
28342
+ contacts: result.contacts,
28343
+ appointments: result.appointments,
28344
+ selectedContactId: result.contacts.length === 1 ? result.contacts[0].id : null,
28345
+ step: nextStep,
28346
+ }));
28347
+ }
28348
+ catch (err) {
28349
+ const message = err instanceof Error ? err.message : 'Invalid verification code';
28350
+ setState(prev => ({ ...prev, isLoading: false, error: message }));
28351
+ }
28352
+ }, [onCallEndpoint, state.email, config.bookingMode, config.timeZone, setState]);
28353
+ const handleResendOtp = useCallback(async () => {
28354
+ await handleSendOtp(state.email);
28355
+ }, [handleSendOtp, state.email]);
28356
+ return {
28357
+ handleSendOtp,
28358
+ handleVerifyOtp,
28359
+ handleResendOtp,
28360
+ };
28361
+ }
28362
+
28363
+ /**
28364
+ * Navigation and flow control handlers for booking steps
28365
+ */
28366
+ function useBookingNavigation({ onCallEndpoint, state, setState, config, }) {
28367
+ const handleSelectContact = useCallback((contactId) => {
28368
+ setState(prev => ({
28369
+ ...prev,
28370
+ selectedContactId: contactId,
28371
+ step: 'options',
28372
+ }));
28373
+ }, [setState]);
28374
+ const handleBookNew = useCallback(async () => {
28375
+ if (!onCallEndpoint || !state.token) {
28376
+ setState(prev => ({ ...prev, error: 'Not authenticated' }));
28377
+ return;
28378
+ }
28379
+ setState(prev => ({ ...prev, isLoading: true, error: null }));
28380
+ try {
28381
+ const result = await onCallEndpoint('get-slots', {
28382
+ contactId: state.selectedContactId,
28383
+ daysAhead: config.daysAhead,
28384
+ timeZone: config.timeZone,
28385
+ }, { token: state.token });
28386
+ setState(prev => ({
28387
+ ...prev,
28388
+ isLoading: false,
28389
+ slots: result.slots,
28390
+ step: 'slot_selection',
28391
+ }));
28392
+ }
28393
+ catch (err) {
28394
+ const message = err instanceof Error ? err.message : 'Failed to load available slots';
28395
+ setState(prev => ({ ...prev, isLoading: false, error: message }));
28396
+ }
28397
+ }, [onCallEndpoint, state.token, state.selectedContactId, config.daysAhead, config.timeZone, setState]);
28398
+ const handleViewAppointments = useCallback(() => {
28399
+ setState(prev => ({ ...prev, step: 'view_appointments' }));
28400
+ }, [setState]);
28401
+ const handleBackToOptions = useCallback(() => {
28402
+ setState(prev => ({ ...prev, step: 'options', error: null }));
28403
+ }, [setState]);
28404
+ const handleSelectSlot = useCallback((slot) => {
28405
+ setState(prev => ({
28406
+ ...prev,
28407
+ selectedSlot: slot,
28408
+ step: 'confirmation',
28409
+ }));
28410
+ }, [setState]);
28411
+ const handleBackToSlots = useCallback(() => {
28412
+ setState(prev => ({ ...prev, step: 'slot_selection', error: null }));
28413
+ }, [setState]);
28414
+ return {
28415
+ handleSelectContact,
28416
+ handleBookNew,
28417
+ handleViewAppointments,
28418
+ handleBackToOptions,
28419
+ handleSelectSlot,
28420
+ handleBackToSlots,
28421
+ };
28422
+ }
28423
+
28424
+ /**
28425
+ * Core booking operations (confirm and cancel)
28426
+ */
28427
+ function useBookingOperations({ onCallEndpoint, state, setState, config, getContactName, finishAction, }) {
28428
+ const [isCancelling, setIsCancelling] = useState(false);
28429
+ const handleConfirmBooking = useCallback(async (subject) => {
28430
+ if (!onCallEndpoint || !state.token || !state.selectedSlot) {
28431
+ setState(prev => ({ ...prev, error: 'Missing required data' }));
28432
+ return;
28433
+ }
28434
+ setState(prev => ({ ...prev, isLoading: true, error: null, subject }));
28435
+ try {
28436
+ const result = await onCallEndpoint('book', {
28437
+ contactId: state.selectedContactId,
28438
+ slot: state.selectedSlot,
28439
+ subject,
28440
+ timeZone: config.timeZone,
28441
+ }, { token: state.token });
28442
+ const contactName = getContactName(state.selectedContactId);
28443
+ if (result.status === 'pending_approval') {
28444
+ setState(prev => ({
28445
+ ...prev,
28446
+ isLoading: false,
28447
+ step: 'pending_approval',
28448
+ }));
28449
+ // Finish with pending status
28450
+ finishAction({
28451
+ status: 'pending_approval',
28452
+ subject,
28453
+ contactName,
28454
+ message: `Appointment request "${subject}" submitted and awaiting approval.`,
28455
+ });
28735
28456
  }
28736
- : undefined;
28737
- return (jsx(GoogleCalendarCard, { action: {
28738
- implementation: action.implementation,
28739
- toolCallId: action.toolCallId,
28740
- actionId: action.actionId,
28741
- input: action.input,
28742
- state: action.state,
28743
- done: action.done ?? false,
28744
- }, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
28457
+ else {
28458
+ setState(prev => ({
28459
+ ...prev,
28460
+ isLoading: false,
28461
+ bookedMeetingLink: result.meetingLink || null,
28462
+ bookedMeetingProvider: result.meetingProvider || null,
28463
+ step: 'booked',
28464
+ }));
28465
+ // Finish with booked status
28466
+ finishAction({
28467
+ status: 'booked',
28468
+ subject,
28469
+ contactName,
28470
+ meetingLink: result.meetingLink,
28471
+ message: `Successfully booked appointment "${subject}"${contactName ? ` with ${contactName}` : ''}.`,
28472
+ });
28473
+ }
28474
+ }
28475
+ catch (err) {
28476
+ const message = err instanceof Error ? err.message : 'Failed to book appointment';
28477
+ setState(prev => ({ ...prev, isLoading: false, error: message }));
28478
+ }
28479
+ }, [onCallEndpoint, state.token, state.selectedSlot, state.selectedContactId, config.timeZone, getContactName, finishAction, setState]);
28480
+ const handleCancelAppointment = useCallback(async (appointmentId) => {
28481
+ if (!onCallEndpoint || !state.token) {
28482
+ setState(prev => ({ ...prev, error: 'Not authenticated' }));
28483
+ return;
28484
+ }
28485
+ setIsCancelling(true);
28486
+ try {
28487
+ await onCallEndpoint('cancel', { appointmentId }, { token: state.token });
28488
+ // Update local appointments list
28489
+ setState(prev => ({
28490
+ ...prev,
28491
+ appointments: prev.appointments.map(apt => apt.id === appointmentId ? { ...apt, status: 'cancelled' } : apt),
28492
+ }));
28493
+ }
28494
+ catch (err) {
28495
+ const message = err instanceof Error ? err.message : 'Failed to cancel appointment';
28496
+ setState(prev => ({ ...prev, error: message }));
28497
+ }
28498
+ finally {
28499
+ setIsCancelling(false);
28500
+ }
28501
+ }, [onCallEndpoint, state.token, setState]);
28502
+ return {
28503
+ handleConfirmBooking,
28504
+ handleCancelAppointment,
28505
+ isCancelling,
28745
28506
  };
28746
28507
  }
28747
28508
 
28748
- function registerMicrosoftCalendarHandler() {
28749
- frontendActionHandlers["microsoft-calendar-appointment"] = async (_input, _state, context) => {
28750
- return waitForActionState(context.toolCallId);
28509
+ // Default config values
28510
+ const DEFAULT_CONFIG = {
28511
+ bookingMode: 'per-contact',
28512
+ timeZone: 'UTC',
28513
+ maxAppointmentsPerUser: 3,
28514
+ daysAhead: 14,
28515
+ subjectMode: 'user_defined',
28516
+ predefinedSubjects: [],
28517
+ };
28518
+ // Initial UI state
28519
+ const createInitialState = () => ({
28520
+ step: 'email',
28521
+ email: '',
28522
+ selectedContactId: null,
28523
+ selectedSlot: null,
28524
+ subject: '',
28525
+ token: null,
28526
+ contacts: [],
28527
+ appointments: [],
28528
+ slots: [],
28529
+ bookedMeetingLink: null,
28530
+ bookedMeetingProvider: null,
28531
+ isLoading: false,
28532
+ error: null,
28533
+ });
28534
+ function BookContactAppointmentCard({ action, onComplete, onDismiss, onCallEndpoint, accentColor, }) {
28535
+ // Parse config from input (from getInitialClientState)
28536
+ const initialState = action.input;
28537
+ const config = {
28538
+ bookingMode: initialState.bookingMode || DEFAULT_CONFIG.bookingMode,
28539
+ timeZone: initialState.timeZone || DEFAULT_CONFIG.timeZone,
28540
+ maxAppointmentsPerUser: initialState.maxAppointmentsPerUser || DEFAULT_CONFIG.maxAppointmentsPerUser,
28541
+ daysAhead: initialState.daysAhead || DEFAULT_CONFIG.daysAhead,
28542
+ subjectMode: initialState.subjectMode || DEFAULT_CONFIG.subjectMode,
28543
+ predefinedSubjects: initialState.predefinedSubjects || DEFAULT_CONFIG.predefinedSubjects,
28544
+ };
28545
+ // Local UI state
28546
+ const [state, setState] = useState(createInitialState);
28547
+ // Check if action is already done (from server state)
28548
+ const isDone = action.done;
28549
+ // Determine if dismiss should be available
28550
+ const isInteractiveStep = ['email', 'otp', 'contact_selection', 'options', 'view_appointments', 'slot_selection', 'confirmation'].includes(state.step);
28551
+ const showCloseButton = !isDone && isInteractiveStep && Boolean(onDismiss);
28552
+ // =========================================================================
28553
+ // Custom Hooks
28554
+ // =========================================================================
28555
+ // Core action lifecycle
28556
+ const { handleDismiss, finishAction } = useBookingAction({
28557
+ onComplete,
28558
+ onDismiss,
28559
+ toolCallId: action.toolCallId,
28560
+ });
28561
+ // Helper functions
28562
+ const { getContactName, getSlotDisplay } = useBookingHelpers({
28563
+ contacts: state.contacts,
28564
+ slots: state.slots,
28565
+ bookingMode: config.bookingMode,
28566
+ });
28567
+ // OTP operations
28568
+ const { handleSendOtp, handleVerifyOtp, handleResendOtp, } = useBookingOtp({
28569
+ onCallEndpoint,
28570
+ state: { email: state.email },
28571
+ setState,
28572
+ config: {
28573
+ bookingMode: config.bookingMode,
28574
+ timeZone: config.timeZone,
28575
+ },
28576
+ });
28577
+ // Navigation handlers
28578
+ const { handleSelectContact, handleBookNew, handleViewAppointments, handleBackToOptions, handleSelectSlot, handleBackToSlots, } = useBookingNavigation({
28579
+ onCallEndpoint,
28580
+ state,
28581
+ setState,
28582
+ config: {
28583
+ daysAhead: config.daysAhead,
28584
+ timeZone: config.timeZone,
28585
+ },
28586
+ });
28587
+ // Booking operations
28588
+ const { handleConfirmBooking, handleCancelAppointment, isCancelling, } = useBookingOperations({
28589
+ onCallEndpoint,
28590
+ state,
28591
+ setState,
28592
+ config: {
28593
+ timeZone: config.timeZone,
28594
+ },
28595
+ getContactName,
28596
+ finishAction,
28597
+ });
28598
+ // =========================================================================
28599
+ // Render
28600
+ // =========================================================================
28601
+ // If action is already done, show a simple completion indicator
28602
+ // The agent's response will convey what happened - no need to reconstruct terminal state
28603
+ if (isDone) {
28604
+ return jsx(CompletedPhase, {});
28605
+ }
28606
+ // Show loading when making API calls
28607
+ if (state.isLoading) {
28608
+ return jsx(LoadingPhase, {});
28609
+ }
28610
+ // Render based on current step
28611
+ switch (state.step) {
28612
+ case 'email':
28613
+ return (jsx(EmailPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, onSubmit: handleSendOtp, isLoading: state.isLoading, error: state.error }));
28614
+ case 'otp':
28615
+ return (jsx(OtpPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, email: state.email, onSubmit: handleVerifyOtp, onResend: handleResendOtp, isLoading: state.isLoading, error: state.error }));
28616
+ case 'contact_selection':
28617
+ return (jsx(ContactSelectionPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, contacts: state.contacts, onSelect: handleSelectContact }));
28618
+ case 'options':
28619
+ return (jsx(OptionsPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, appointments: state.appointments.filter(a => a.status !== 'cancelled'), maxAppointments: config.maxAppointmentsPerUser, onBookNew: handleBookNew, onViewAppointments: handleViewAppointments, onCancelAppointment: handleCancelAppointment, isCancelling: isCancelling }));
28620
+ case 'view_appointments':
28621
+ return (jsx(ViewAppointmentsPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, appointments: state.appointments, onBack: handleBackToOptions, onCancelAppointment: handleCancelAppointment, isCancelling: isCancelling }));
28622
+ case 'slot_selection':
28623
+ return (jsx(SlotSelectionPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, slots: state.slots, contactName: getContactName(state.selectedContactId), onSelect: handleSelectSlot, onBack: handleBackToOptions, isLoading: state.isLoading, error: state.error }));
28624
+ case 'confirmation':
28625
+ return (jsx(ConfirmationPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, contactName: getContactName(state.selectedContactId), slot: state.selectedSlot, slotDisplay: getSlotDisplay(state.selectedSlot), subjectMode: config.subjectMode, predefinedSubjects: config.predefinedSubjects, onConfirm: handleConfirmBooking, onBack: handleBackToSlots, isLoading: state.isLoading, error: state.error }));
28626
+ case 'booked':
28627
+ return (jsx(BookedPhase, { subject: state.subject, contactName: getContactName(state.selectedContactId), meetingLink: state.bookedMeetingLink, meetingProvider: state.bookedMeetingProvider }));
28628
+ case 'pending_approval':
28629
+ return (jsx(PendingApprovalPhase, { subject: state.subject, contactName: getContactName(state.selectedContactId) }));
28630
+ case 'cancelled':
28631
+ return jsx(CancelledPhase, {});
28632
+ case 'error':
28633
+ return jsx(ErrorPhase, { error: state.error || 'An error occurred' });
28634
+ default:
28635
+ return jsx(ErrorPhase, { error: "Unknown state" });
28636
+ }
28637
+ }
28638
+
28639
+ function ExternalLinkIcon$1() {
28640
+ return (jsxs("svg", { width: "14", height: "14", 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" })] }));
28641
+ }
28642
+ function ImageCard({ item, accentColor, showOverlay = true, onClick, onLinkClick }) {
28643
+ const [imageError, setImageError] = useState(false);
28644
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28645
+ const hasMetadata = item.title || item.description || item.link;
28646
+ const handleLinkClick = (e) => {
28647
+ e.stopPropagation();
28648
+ if (item.link) {
28649
+ onLinkClick?.(item.link);
28650
+ window.open(item.link, '_blank', 'noopener,noreferrer');
28651
+ }
28652
+ };
28653
+ const handleImageClick = () => {
28654
+ if (onClick) {
28655
+ onClick();
28656
+ }
28751
28657
  };
28658
+ return (jsxs("div", { className: "ai-chat-image-card", style: style, onClick: handleImageClick, children: [jsx("div", { className: "ai-chat-image-card__media", children: !imageError ? (jsx("img", { src: item.url, alt: item.alt || item.title || 'Image', className: "ai-chat-image-card__image", onError: () => setImageError(true) })) : (jsx("div", { className: "ai-chat-image-card__image-error", children: jsx("span", { children: "Failed to load image" }) })) }), hasMetadata && showOverlay && (jsxs("div", { className: "ai-chat-image-card__content", children: [item.title && (jsx("h4", { className: "ai-chat-image-card__title", children: item.title })), item.description && (jsx("p", { className: "ai-chat-image-card__description", children: item.description })), item.link && (jsxs("button", { className: "ai-chat-image-card__link-btn", onClick: handleLinkClick, children: [item.linkText || 'View More', jsx(ExternalLinkIcon$1, {})] }))] }))] }));
28659
+ }
28660
+
28661
+ function ImageGallery({ items, columns = 2, accentColor }) {
28662
+ const [imageErrors, setImageErrors] = useState(new Set());
28663
+ const imageItems = items;
28664
+ if (imageItems.length === 0)
28665
+ return null;
28666
+ // Determine if first item should span full width (for odd counts > 1)
28667
+ const itemCount = imageItems.length;
28668
+ const isOddCount = itemCount > 1 && itemCount % 2 === 1;
28669
+ const style = {
28670
+ ...(accentColor ? { '--action-accent': accentColor } : {}),
28671
+ '--gallery-item-count': itemCount,
28672
+ };
28673
+ const handleImageError = (index) => {
28674
+ setImageErrors(prev => new Set(prev).add(index));
28675
+ };
28676
+ return (jsx("div", { className: "ai-chat-image-gallery", style: style, "data-item-count": itemCount, children: jsx("div", { className: `ai-chat-image-gallery__grid ${isOddCount ? 'odd-count' : ''}`, "data-count": itemCount, children: imageItems.map((item, index) => (jsx("div", { className: `ai-chat-image-gallery__item ${isOddCount && index === 0 ? 'span-full' : ''}`, children: jsxs("div", { className: "ai-chat-image-gallery__item-media", children: [!imageErrors.has(index) ? (jsx("img", { src: item.url, alt: item.alt || item.title || `Image ${index + 1}`, onError: () => handleImageError(index) })) : (jsx("div", { className: "ai-chat-image-gallery__error", children: jsx("span", { children: "Failed to load" }) })), item.title && (jsx("div", { className: "ai-chat-image-gallery__item-overlay", children: jsx("span", { className: "ai-chat-image-gallery__item-title", children: item.title }) }))] }) }, index))) }) }));
28677
+ }
28678
+
28679
+ function ExternalLinkIcon() {
28680
+ return (jsxs("svg", { width: "14", height: "14", 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" })] }));
28681
+ }
28682
+ function truncate(text, maxLength) {
28683
+ if (text.length <= maxLength)
28684
+ return text;
28685
+ return text.slice(0, maxLength).trim() + '...';
28686
+ }
28687
+ function ProjectCard({ item, accentColor, onLinkClick, variant }) {
28688
+ const [imageError, setImageError] = useState(false);
28689
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28690
+ const imageUrl = item.url;
28691
+ // Determine variant based on content if not specified
28692
+ const hasTextContent = item.title || item.description;
28693
+ const effectiveVariant = variant || (hasTextContent ? 'full' : 'image-only');
28694
+ const handleCardClick = () => {
28695
+ if (item.link) {
28696
+ onLinkClick?.(item.link);
28697
+ window.open(item.link, '_blank', 'noopener,noreferrer');
28698
+ }
28699
+ };
28700
+ // Image-only variant - just the image with optional hover effect
28701
+ if (effectiveVariant === 'image-only') {
28702
+ return (jsx("div", { className: `ai-chat-project-card ai-chat-project-card--image-only ${item.link ? 'clickable' : ''}`, style: style, onClick: item.link ? handleCardClick : undefined, role: item.link ? 'link' : undefined, tabIndex: item.link ? 0 : undefined, onKeyDown: (e) => e.key === 'Enter' && item.link && handleCardClick(), children: jsx("div", { className: "ai-chat-project-card__media", children: imageUrl && !imageError ? (jsx("img", { src: imageUrl, alt: item.alt || 'Image', onError: () => setImageError(true) })) : (jsx("div", { className: "ai-chat-project-card__placeholder", children: imageError ? 'Failed to load' : 'No image' })) }) }));
28703
+ }
28704
+ // Overlay variant - title overlaid on image
28705
+ if (effectiveVariant === 'overlay') {
28706
+ return (jsx("div", { className: `ai-chat-project-card ai-chat-project-card--overlay ${item.link ? 'clickable' : ''}`, style: style, onClick: item.link ? handleCardClick : undefined, role: item.link ? 'link' : undefined, tabIndex: item.link ? 0 : undefined, onKeyDown: (e) => e.key === 'Enter' && item.link && handleCardClick(), children: jsxs("div", { className: "ai-chat-project-card__media", children: [imageUrl && !imageError ? (jsx("img", { src: imageUrl, alt: item.alt || item.title || 'Image', onError: () => setImageError(true) })) : (jsx("div", { className: "ai-chat-project-card__placeholder", children: imageError ? 'Failed to load' : 'No image' })), item.title && (jsx("div", { className: "ai-chat-project-card__overlay", children: jsx("h4", { className: "ai-chat-project-card__overlay-title", children: truncate(item.title, 50) }) }))] }) }));
28707
+ }
28708
+ // Full variant - image with separate content section below
28709
+ return (jsxs("div", { className: `ai-chat-project-card ai-chat-project-card--full ${item.link ? 'clickable' : ''}`, style: style, onClick: item.link ? handleCardClick : undefined, role: item.link ? 'link' : undefined, tabIndex: item.link ? 0 : undefined, onKeyDown: (e) => e.key === 'Enter' && item.link && handleCardClick(), children: [jsx("div", { className: "ai-chat-project-card__media", children: imageUrl && !imageError ? (jsx("img", { src: imageUrl, alt: item.alt || item.title || 'Project image', onError: () => setImageError(true) })) : (jsx("div", { className: "ai-chat-project-card__placeholder", children: imageError ? 'Failed to load' : 'No image' })) }), hasTextContent && (jsxs("div", { className: "ai-chat-project-card__content", children: [item.title && (jsx("h4", { className: "ai-chat-project-card__title", children: truncate(item.title, 60) })), item.description && (jsx("p", { className: "ai-chat-project-card__description", children: truncate(item.description, 120) })), item.link && (jsxs("div", { className: "ai-chat-project-card__link", children: [jsx("span", { children: item.linkText || 'View' }), jsx(ExternalLinkIcon, {})] }))] }))] }));
28752
28710
  }
28753
28711
 
28754
28712
  /**
28755
- * Register microsoft-calendar-appointment action handler and renderer.
28756
- * Called by initializeActionHandlers to prevent tree-shaking.
28713
+ * URL validation utilities for images, cards, and links
28714
+ * Prevents 404 errors by validating URLs before display
28757
28715
  */
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);
28716
+ /**
28717
+ * Validate a single URL by attempting to load it
28718
+ */
28719
+ /**
28720
+ * Validate an image URL by attempting to load it as an Image
28721
+ */
28722
+ async function validateImageUrl(url, timeout = 5000) {
28723
+ if (!url || typeof url !== 'string') {
28724
+ return { isValid: false, error: 'Invalid URL format' };
28725
+ }
28726
+ try {
28727
+ new URL(url);
28728
+ }
28729
+ catch (e) {
28730
+ return { isValid: false, error: 'Invalid URL structure' };
28731
+ }
28732
+ return new Promise((resolve) => {
28733
+ const img = new Image();
28734
+ const timeoutId = setTimeout(() => {
28735
+ img.src = '';
28736
+ resolve({ isValid: false, error: 'Image load timeout' });
28737
+ }, timeout);
28738
+ img.onload = () => {
28739
+ clearTimeout(timeoutId);
28740
+ resolve({ isValid: true });
28768
28741
  };
28769
- const handleDismiss = onActionDismiss
28770
- ? (toolCallId) => {
28771
- resolveActionState(toolCallId, { __dismissed: true });
28772
- onActionDismiss(toolCallId);
28742
+ img.onerror = () => {
28743
+ clearTimeout(timeoutId);
28744
+ resolve({ isValid: false, error: 'Failed to load image' });
28745
+ };
28746
+ img.src = url;
28747
+ });
28748
+ }
28749
+ /**
28750
+ * Validate multiple image URLs concurrently
28751
+ */
28752
+ async function validateImageUrls(urls, timeout = 5000, maxConcurrent = 10) {
28753
+ const results = new Map();
28754
+ // Process in batches to limit concurrent requests
28755
+ for (let i = 0; i < urls.length; i += maxConcurrent) {
28756
+ const batch = urls.slice(i, i + maxConcurrent);
28757
+ const batchResults = await Promise.all(batch.map(async (url) => {
28758
+ const result = await validateImageUrl(url, timeout);
28759
+ return { url, result };
28760
+ }));
28761
+ batchResults.forEach(({ url, result }) => {
28762
+ results.set(url, result);
28763
+ });
28764
+ }
28765
+ return results;
28766
+ }
28767
+ /**
28768
+ * Validate image items and separate valid from invalid
28769
+ */
28770
+ async function validateImageItems(items, timeout = 5000) {
28771
+ const urls = items.map(item => item.url).filter(Boolean);
28772
+ if (urls.length === 0) {
28773
+ return { validItems: [], invalidItems: items };
28774
+ }
28775
+ const validationResults = await validateImageUrls(urls, timeout);
28776
+ const validItems = [];
28777
+ const invalidItems = [];
28778
+ items.forEach(item => {
28779
+ if (!item.url) {
28780
+ invalidItems.push({
28781
+ ...item,
28782
+ isValid: false,
28783
+ validationError: 'Missing URL',
28784
+ });
28785
+ return;
28786
+ }
28787
+ const result = validationResults.get(item.url);
28788
+ if (result?.isValid) {
28789
+ validItems.push({
28790
+ ...item,
28791
+ isValid: true,
28792
+ });
28793
+ }
28794
+ else {
28795
+ invalidItems.push({
28796
+ ...item,
28797
+ isValid: false,
28798
+ validationError: result?.error || 'Unknown error',
28799
+ });
28800
+ }
28801
+ });
28802
+ return { validItems, invalidItems };
28803
+ }
28804
+ /**
28805
+ * Preload and validate images before rendering
28806
+ * Returns items with validation status
28807
+ */
28808
+ async function preloadAndValidateImages(items, timeout = 5000) {
28809
+ const { validItems, invalidItems } = await validateImageItems(items, timeout);
28810
+ if (invalidItems.length > 0) {
28811
+ console.warn('[URLValidator] Invalid image URLs detected:', invalidItems.map(i => ({
28812
+ url: i.url,
28813
+ error: i.validationError,
28814
+ })));
28815
+ }
28816
+ return [...validItems, ...invalidItems];
28817
+ }
28818
+
28819
+ function determineLayout(items, requestedLayout) {
28820
+ // Single item always uses single layout
28821
+ if (items.length === 1) {
28822
+ return 'single';
28823
+ }
28824
+ // For multiple items, use gallery (which now supports overlay titles)
28825
+ // Cards and gallery are now visually the same - 2-column grid with overlay titles
28826
+ return 'gallery';
28827
+ }
28828
+ function determineColumns(itemCount, maxColumns = 2) {
28829
+ if (itemCount === 1)
28830
+ return 1;
28831
+ return Math.min(2, maxColumns);
28832
+ }
28833
+ function StructuredImageDisplay({ action, onComplete, accentColor, maxColumns = 3 }) {
28834
+ const rawState = action.input;
28835
+ const hasCompletedRef = useRef(false);
28836
+ const [validatedItems, setValidatedItems] = useState([]);
28837
+ const [isValidating, setIsValidating] = useState(true);
28838
+ const [validationErrors, setValidationErrors] = useState([]);
28839
+ // Provide safe defaults if state is missing
28840
+ const state = {
28841
+ items: rawState?.items || [],
28842
+ layout: rawState?.layout || 'single',
28843
+ context: rawState?.context,
28844
+ columns: rawState?.columns,
28845
+ status: rawState?.status || 'displaying',
28846
+ error: rawState?.error,
28847
+ };
28848
+ const isError = state.status === 'error';
28849
+ // Validate URLs before displaying
28850
+ useEffect(() => {
28851
+ if (state.items.length === 0) {
28852
+ setIsValidating(false);
28853
+ return;
28854
+ }
28855
+ let isMounted = true;
28856
+ const validateItems = async () => {
28857
+ try {
28858
+ const validated = await preloadAndValidateImages(state.items, 3000);
28859
+ if (!isMounted)
28860
+ return;
28861
+ const valid = validated.filter(item => item.isValid !== false);
28862
+ const invalid = validated.filter(item => item.isValid === false);
28863
+ setValidatedItems(valid);
28864
+ if (invalid.length > 0) {
28865
+ const errors = invalid.map(item => `${item.url}: ${item.validationError || 'Failed to load'}`);
28866
+ setValidationErrors(errors);
28867
+ console.warn('[StructuredImageDisplay] Filtered invalid URLs:', errors);
28868
+ }
28773
28869
  }
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 }));
28870
+ catch (error) {
28871
+ console.error('[StructuredImageDisplay] Validation error:', error);
28872
+ // Fallback to unvalidated items on error
28873
+ if (isMounted) {
28874
+ setValidatedItems(state.items);
28875
+ }
28876
+ }
28877
+ finally {
28878
+ if (isMounted) {
28879
+ setIsValidating(false);
28880
+ }
28881
+ }
28882
+ };
28883
+ validateItems();
28884
+ return () => {
28885
+ isMounted = false;
28886
+ };
28887
+ }, [state.items]);
28888
+ // Auto-complete on mount so AI can continue generating text response
28889
+ useEffect(() => {
28890
+ if (!action.done && !hasCompletedRef.current && onComplete && state.items.length > 0) {
28891
+ hasCompletedRef.current = true;
28892
+ onComplete(action.toolCallId, { ...state, status: 'displaying' });
28893
+ }
28894
+ }, [action.done, action.toolCallId, onComplete, state]);
28895
+ const handleInteraction = () => {
28896
+ onComplete?.(action.toolCallId, { ...state, status: 'interacted' });
28897
+ };
28898
+ const handleLinkClick = (url) => {
28899
+ handleInteraction();
28900
+ };
28901
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28902
+ // Error state
28903
+ if (isError) {
28904
+ return (jsx("div", { className: "ai-chat-structured-image ai-chat-structured-image--error", style: style, children: jsx("div", { className: "ai-chat-structured-image__error", children: state.error || 'Failed to load media' }) }));
28905
+ }
28906
+ // Loading state
28907
+ if (isValidating) {
28908
+ return (jsxs("div", { className: "ai-chat-structured-image", style: style, children: [state.context && (jsx("p", { className: "ai-chat-structured-image__context", children: state.context })), jsx("div", { className: "ai-chat-structured-image__loading", children: "Validating images..." })] }));
28909
+ }
28910
+ // No valid items after validation
28911
+ if (validatedItems.length === 0) {
28912
+ return (jsxs("div", { className: "ai-chat-structured-image", style: style, children: [state.context && (jsx("p", { className: "ai-chat-structured-image__context", children: state.context })), validationErrors.length > 0 && (jsx("div", { className: "ai-chat-structured-image__error", children: "All images failed to load. Please check the URLs." }))] }));
28913
+ }
28914
+ const layout = determineLayout(validatedItems, state.layout);
28915
+ const columns = state.columns || determineColumns(validatedItems.length, maxColumns);
28916
+ return (jsxs("div", { className: "ai-chat-structured-image", style: style, children: [state.context && (jsx("p", { className: "ai-chat-structured-image__context", children: state.context })), validationErrors.length > 0 && (jsxs("div", { className: "ai-chat-structured-image__warning", children: [validationErrors.length, " image(s) could not be loaded and were filtered."] })), layout === 'single' && validatedItems[0] && (jsx(ImageCard, { item: validatedItems[0], accentColor: accentColor, onLinkClick: handleLinkClick })), layout === 'gallery' && (jsx(ImageGallery, { items: validatedItems, columns: columns, accentColor: accentColor, maxColumns: maxColumns })), layout === 'cards' && (jsx("div", { className: "ai-chat-structured-image__cards", style: { '--card-columns': validatedItems.length === 1 ? 1 : 2 }, children: validatedItems.map((item, index) => (jsx(ProjectCard, { item: item, accentColor: accentColor, onLinkClick: handleLinkClick, variant: "overlay" }, index))) })), layout === 'carousel' && (jsx(ImageCarousel, { items: validatedItems, accentColor: accentColor, onLinkClick: handleLinkClick }))] }));
28917
+ }
28918
+ function ChevronLeftIcon() {
28919
+ return (jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "15 18 9 12 15 6" }) }));
28920
+ }
28921
+ function ChevronRightIcon() {
28922
+ return (jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "9 18 15 12 9 6" }) }));
28923
+ }
28924
+ function ImageCarousel({ items, accentColor, onLinkClick }) {
28925
+ const [currentIndex, setCurrentIndex] = React.useState(0);
28926
+ const containerRef = useRef(null);
28927
+ const goToPrevious = () => {
28928
+ setCurrentIndex(prev => prev === 0 ? items.length - 1 : prev - 1);
28783
28929
  };
28930
+ const goToNext = () => {
28931
+ setCurrentIndex(prev => prev === items.length - 1 ? 0 : prev + 1);
28932
+ };
28933
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28934
+ return (jsxs("div", { className: "ai-chat-image-carousel", style: style, ref: containerRef, children: [jsx("div", { className: "ai-chat-image-carousel__track", style: { transform: `translateX(-${currentIndex * 100}%)` }, children: items.map((item, index) => (jsx("div", { className: "ai-chat-image-carousel__slide", children: jsx(ProjectCard, { item: item, accentColor: accentColor, onLinkClick: onLinkClick }) }, index))) }), items.length > 1 && (jsxs(Fragment, { children: [jsx("button", { className: "ai-chat-image-carousel__nav prev", onClick: goToPrevious, "aria-label": "Previous", children: jsx(ChevronLeftIcon, {}) }), jsx("button", { className: "ai-chat-image-carousel__nav next", onClick: goToNext, "aria-label": "Next", children: jsx(ChevronRightIcon, {}) }), jsx("div", { className: "ai-chat-image-carousel__dots", children: items.map((_, index) => (jsx("button", { className: `ai-chat-image-carousel__dot ${index === currentIndex ? 'active' : ''}`, onClick: () => setCurrentIndex(index), "aria-label": `Go to slide ${index + 1}` }, index))) })] }))] }));
28935
+ }
28936
+
28937
+ const pendingResolvers = new Map();
28938
+ const resumeCallbacks = new Map();
28939
+ const frontendActionHandlers = {};
28940
+ const actionRenderers = {};
28941
+ function getFrontendActionHandler(implementation) {
28942
+ return frontendActionHandlers[implementation];
28943
+ }
28944
+ function getActionRenderer(implementation) {
28945
+ return actionRenderers[implementation];
28946
+ }
28947
+ function waitForActionState(toolCallId) {
28948
+ return new Promise((resolve) => {
28949
+ pendingResolvers.set(toolCallId, resolve);
28950
+ });
28951
+ }
28952
+ function resolveActionState(toolCallId, state) {
28953
+ const resolver = pendingResolvers.get(toolCallId);
28954
+ if (resolver) {
28955
+ pendingResolvers.delete(toolCallId);
28956
+ resolver(state);
28957
+ return;
28958
+ }
28959
+ const resumeCallback = resumeCallbacks.get(toolCallId);
28960
+ if (resumeCallback) {
28961
+ resumeCallback(state).catch((error) => {
28962
+ console.error("[Action] Failed to resume action:", error);
28963
+ });
28964
+ }
28965
+ }
28966
+ function registerActionResumeCallback(toolCallId, callback) {
28967
+ resumeCallbacks.set(toolCallId, callback);
28968
+ }
28969
+ function unregisterActionResumeCallback(toolCallId) {
28970
+ resumeCallbacks.delete(toolCallId);
28784
28971
  }
28785
28972
 
28786
28973
  /**
@@ -28788,9 +28975,15 @@ function registerMicrosoftCalendarAction() {
28788
28975
  * Called by initializeActionHandlers to prevent tree-shaking.
28789
28976
  */
28790
28977
  function registerLinkPreviewAction() {
28791
- // Handler - auto-completes immediately since no user input is needed
28978
+ // Handler - auto-completes immediately, returns body for agent
28792
28979
  frontendActionHandlers["link-preview"] = async (_input, state, _context) => {
28793
- return { ...state, status: "displaying" };
28980
+ const links = state?.links || [];
28981
+ // Return body directly - sent to backend via continueAgentAction
28982
+ return {
28983
+ status: "displayed",
28984
+ linkCount: links.length,
28985
+ message: `Displayed ${links.length} link preview${links.length > 1 ? 's' : ''}.`,
28986
+ };
28794
28987
  };
28795
28988
  // Renderer - displays the link preview card
28796
28989
  actionRenderers["link-preview"] = (message, accentColor) => {
@@ -28800,16 +28993,15 @@ function registerLinkPreviewAction() {
28800
28993
  const handleComplete = (toolCallId, newState) => {
28801
28994
  resolveActionState(toolCallId, newState);
28802
28995
  };
28803
- // Check if action state indicates it's already complete (displaying or clicked)
28804
- const state = action.state;
28805
- const status = state?.status;
28806
- const isDone = action.done || status === "displaying" || status === "clicked";
28996
+ // Check if action input indicates it's already complete (displaying or clicked)
28997
+ const input = action.input;
28998
+ const status = input?.status;
28999
+ const isDone = action.done || status === "displaying" || status === "displayed" || status === "clicked";
28807
29000
  return (jsx(LinkPreviewCard, { action: {
28808
29001
  implementation: action.implementation,
28809
29002
  toolCallId: action.toolCallId,
28810
29003
  actionId: action.actionId,
28811
29004
  input: action.input,
28812
- state: action.state,
28813
29005
  done: isDone,
28814
29006
  }, onComplete: handleComplete, accentColor: accentColor }));
28815
29007
  };
@@ -28820,9 +29012,15 @@ function registerLinkPreviewAction() {
28820
29012
  * Called by initializeActionHandlers to prevent tree-shaking.
28821
29013
  */
28822
29014
  function registerVideoPlayerAction() {
28823
- // Handler - auto-completes immediately since no user input is needed
29015
+ // Handler - auto-completes immediately, returns body for agent
28824
29016
  frontendActionHandlers["video-player"] = async (_input, state, _context) => {
28825
- return { ...state, status: "displaying" };
29017
+ const videos = state?.videos || [];
29018
+ // Return body directly - sent to backend via continueAgentAction
29019
+ return {
29020
+ status: "displayed",
29021
+ videoCount: videos.length,
29022
+ message: `Displayed ${videos.length} video${videos.length !== 1 ? 's' : ''}.`,
29023
+ };
28826
29024
  };
28827
29025
  // Renderer - displays the embedded video player card
28828
29026
  actionRenderers["video-player"] = (message, accentColor) => {
@@ -28832,16 +29030,15 @@ function registerVideoPlayerAction() {
28832
29030
  const handleComplete = (toolCallId, newState) => {
28833
29031
  resolveActionState(toolCallId, newState);
28834
29032
  };
28835
- // Check if action state indicates it's already complete (displaying or played)
28836
- const state = action.state;
28837
- const status = state?.status;
28838
- const isDone = action.done || status === "displaying" || status === "played";
29033
+ // Check if action input indicates it's already complete (displaying or played)
29034
+ const input = action.input;
29035
+ const status = input?.status;
29036
+ const isDone = action.done || status === "displaying" || status === "displayed" || status === "played";
28839
29037
  return (jsx(VideoPlayerCard, { action: {
28840
29038
  implementation: action.implementation,
28841
29039
  toolCallId: action.toolCallId,
28842
29040
  actionId: action.actionId,
28843
29041
  input: action.input,
28844
- state: action.state,
28845
29042
  done: isDone,
28846
29043
  }, onComplete: handleComplete, accentColor: accentColor }));
28847
29044
  };
@@ -28852,9 +29049,15 @@ function registerVideoPlayerAction() {
28852
29049
  * Called by initializeActionHandlers to prevent tree-shaking.
28853
29050
  */
28854
29051
  function registerLocationCardAction() {
28855
- // Handler - auto-completes immediately since no user input is needed
29052
+ // Handler - auto-completes immediately, returns body for agent
28856
29053
  frontendActionHandlers["location-card"] = async (_input, state, _context) => {
28857
- return { ...state, status: "displaying" };
29054
+ const locations = state?.locations || [];
29055
+ // Return body directly - sent to backend via continueAgentAction
29056
+ return {
29057
+ status: "displayed",
29058
+ locationCount: locations.length,
29059
+ message: `Displayed ${locations.length} location${locations.length !== 1 ? 's' : ''}.`,
29060
+ };
28858
29061
  };
28859
29062
  // Renderer - displays the location card
28860
29063
  actionRenderers["location-card"] = (message, accentColor, variant) => {
@@ -28864,25 +29067,30 @@ function registerLocationCardAction() {
28864
29067
  const handleComplete = (toolCallId, newState) => {
28865
29068
  resolveActionState(toolCallId, newState);
28866
29069
  };
28867
- // Check if action state indicates it's already complete
28868
- const state = action.state;
28869
- const status = state?.status;
28870
- const isDone = action.done || status === "displaying" || status === "directions_opened";
29070
+ // Check if action input indicates it's already complete
29071
+ const input = action.input;
29072
+ const status = input?.status;
29073
+ const isDone = action.done || status === "displaying" || status === "displayed" || status === "directions_opened";
28871
29074
  return (jsx(LocationCard, { action: {
28872
29075
  implementation: action.implementation,
28873
29076
  toolCallId: action.toolCallId,
28874
29077
  actionId: action.actionId,
28875
29078
  input: action.input,
28876
- state: action.state,
28877
29079
  done: isDone,
28878
29080
  }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28879
29081
  };
28880
29082
  }
28881
29083
 
28882
29084
  function registerContactCardAction() {
28883
- // Handler - auto-completes immediately since no user input is needed
29085
+ // Handler - auto-completes immediately, returns body for agent
28884
29086
  frontendActionHandlers['contact-card'] = async (_input, state, _context) => {
28885
- return { ...state, status: 'displaying' };
29087
+ const contacts = state?.contacts || [];
29088
+ // Return body directly - sent to backend via continueAgentAction
29089
+ return {
29090
+ status: 'displayed',
29091
+ contactCount: contacts.length,
29092
+ message: `Displayed ${contacts.length} contact${contacts.length !== 1 ? 's' : ''}.`,
29093
+ };
28886
29094
  };
28887
29095
  // Renderer - displays the contact card
28888
29096
  actionRenderers['contact-card'] = (message, accentColor, variant) => {
@@ -28892,16 +29100,15 @@ function registerContactCardAction() {
28892
29100
  const handleComplete = (toolCallId, newState) => {
28893
29101
  resolveActionState(toolCallId, newState);
28894
29102
  };
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';
29103
+ // Check if action input indicates it's already complete
29104
+ const input = action.input;
29105
+ const status = input?.status;
29106
+ const isDone = action.done || status === 'displaying' || status === 'displayed' || status === 'contacted';
28899
29107
  return (jsx(ContactCard, { action: {
28900
29108
  implementation: action.implementation,
28901
29109
  toolCallId: action.toolCallId,
28902
29110
  actionId: action.actionId,
28903
29111
  input: action.input,
28904
- state: action.state,
28905
29112
  done: isDone,
28906
29113
  }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28907
29114
  };
@@ -28921,16 +29128,15 @@ function registerQueryContactDirectoryAction() {
28921
29128
  const handleComplete = (toolCallId, newState) => {
28922
29129
  resolveActionState(toolCallId, newState);
28923
29130
  };
28924
- // Check if action state indicates it's already complete
28925
- const state = action.state;
28926
- const status = state?.status;
29131
+ // Check if action input indicates it's already complete
29132
+ const input = action.input;
29133
+ const status = input?.status;
28927
29134
  const isDone = action.done || status === 'displaying' || status === 'contacted';
28928
29135
  return (jsx(ContactCard, { action: {
28929
29136
  implementation: action.implementation,
28930
29137
  toolCallId: action.toolCallId,
28931
29138
  actionId: action.actionId,
28932
29139
  input: action.input,
28933
- state: action.state,
28934
29140
  done: isDone,
28935
29141
  }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28936
29142
  };
@@ -28942,7 +29148,9 @@ function registerDisplayFormAction() {
28942
29148
  return waitForActionState(context.toolCallId);
28943
29149
  };
28944
29150
  // Renderer - displays the form card
28945
- actionRenderers['display-form'] = (message, accentColor, variant, onActionDismiss) => {
29151
+ // Rendering is based only on action.input and action.done
29152
+ // When done=true, FormCard shows a simple completion indicator
29153
+ actionRenderers['display-form'] = (message, accentColor, _variant, onActionDismiss) => {
28946
29154
  const action = message.action;
28947
29155
  if (!action)
28948
29156
  return null;
@@ -28950,22 +29158,14 @@ function registerDisplayFormAction() {
28950
29158
  resolveActionState(toolCallId, newState);
28951
29159
  };
28952
29160
  const handleDismiss = onActionDismiss
28953
- ? (toolCallId) => {
28954
- resolveActionState(toolCallId, { __dismissed: true });
28955
- onActionDismiss(toolCallId);
28956
- }
29161
+ ? (toolCallId) => onActionDismiss(toolCallId)
28957
29162
  : 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
29163
  return (jsx(FormCard, { action: {
28963
29164
  implementation: action.implementation,
28964
29165
  toolCallId: action.toolCallId,
28965
29166
  actionId: action.actionId,
28966
29167
  input: action.input,
28967
- state: action.state,
28968
- done: isDone,
29168
+ done: action.done ?? false,
28969
29169
  }, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
28970
29170
  };
28971
29171
  }
@@ -28988,21 +29188,64 @@ function registerBookContactAppointmentAction() {
28988
29188
  // Register the handler
28989
29189
  registerBookContactAppointmentHandler();
28990
29190
  // Register the renderer
28991
- actionRenderers['book-contact-appointment'] = (message, accentColor) => {
29191
+ actionRenderers['book-contact-appointment'] = (message, accentColor, _variant, _onActionDismiss, onCallEndpoint) => {
28992
29192
  const action = message.action;
28993
29193
  if (!action)
28994
29194
  return null;
28995
29195
  const handleComplete = (toolCallId, newState) => {
28996
29196
  resolveActionState(toolCallId, newState);
28997
29197
  };
29198
+ // Create action-specific endpoint callback
29199
+ // Include toolCallId for done flag enforcement (server rejects calls for completed actions)
29200
+ const handleCallEndpoint = onCallEndpoint
29201
+ ? async (endpoint, input, options) => {
29202
+ return onCallEndpoint(action.actionId, endpoint, input, { ...options, toolCallId: action.toolCallId });
29203
+ }
29204
+ : undefined;
29205
+ // Create dismiss handler
29206
+ const handleDismiss = _onActionDismiss
29207
+ ? (toolCallId) => _onActionDismiss(toolCallId)
29208
+ : undefined;
28998
29209
  return (jsx(BookContactAppointmentCard, { action: {
28999
29210
  implementation: action.implementation,
29000
29211
  toolCallId: action.toolCallId,
29001
29212
  actionId: action.actionId,
29002
29213
  input: action.input,
29003
- state: action.state,
29004
29214
  done: action.done ?? false,
29005
- }, onComplete: handleComplete, accentColor: accentColor }));
29215
+ }, onComplete: handleComplete, onDismiss: handleDismiss, onCallEndpoint: handleCallEndpoint, accentColor: accentColor }));
29216
+ };
29217
+ }
29218
+
29219
+ function registerStructuredImageAction() {
29220
+ // Handler - auto-completes immediately, returns body for agent
29221
+ frontendActionHandlers['structured-image'] = async (_input, state, _context) => {
29222
+ const images = state?.images || [];
29223
+ // Return body directly - sent to backend via continueAgentAction
29224
+ return {
29225
+ status: 'displayed',
29226
+ imageCount: images.length,
29227
+ message: `Displayed ${images.length} image${images.length !== 1 ? 's' : ''}.`,
29228
+ };
29229
+ };
29230
+ // Renderer - displays the image content
29231
+ actionRenderers['structured-image'] = (message, accentColor, variant, onActionDismiss) => {
29232
+ const action = message.action;
29233
+ if (!action)
29234
+ return null;
29235
+ const handleComplete = (toolCallId, newState) => {
29236
+ resolveActionState(toolCallId, newState);
29237
+ };
29238
+ // Check if action input indicates it's already complete
29239
+ const input = action.input;
29240
+ const status = input?.status;
29241
+ const isDone = action.done || status === 'displaying' || status === 'displayed' || status === 'interacted';
29242
+ return (jsx(StructuredImageDisplay, { action: {
29243
+ implementation: action.implementation,
29244
+ toolCallId: action.toolCallId,
29245
+ actionId: action.actionId,
29246
+ input: action.input,
29247
+ done: isDone,
29248
+ }, onComplete: handleComplete, onDismiss: onActionDismiss ? () => onActionDismiss(action.toolCallId) : undefined, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 2 }));
29006
29249
  };
29007
29250
  }
29008
29251
 
@@ -29018,8 +29261,6 @@ function initializeActionHandlers() {
29018
29261
  return;
29019
29262
  initialized = true;
29020
29263
  // Explicitly call each registration function to prevent tree-shaking
29021
- registerGoogleCalendarAction();
29022
- registerMicrosoftCalendarAction();
29023
29264
  registerLinkPreviewAction();
29024
29265
  registerVideoPlayerAction();
29025
29266
  registerLocationCardAction();
@@ -29027,6 +29268,7 @@ function initializeActionHandlers() {
29027
29268
  registerContactCardAction();
29028
29269
  registerDisplayFormAction();
29029
29270
  registerBookContactAppointmentAction();
29271
+ registerStructuredImageAction();
29030
29272
  }
29031
29273
 
29032
29274
  /**
@@ -29289,9 +29531,49 @@ function hydrateToolNames(messages) {
29289
29531
  };
29290
29532
  });
29291
29533
  }
29534
+ /**
29535
+ * Clean up messages that were interrupted during streaming.
29536
+ * - Marks streaming messages as complete
29537
+ * - Removes empty assistant messages
29538
+ * - Marks incomplete tool calls as done
29539
+ */
29540
+ function cleanupInterruptedMessages(messages) {
29541
+ return messages
29542
+ .map((msg) => {
29543
+ // Mark streaming messages as complete
29544
+ if (msg.isStreaming) {
29545
+ msg = { ...msg, isStreaming: false };
29546
+ }
29547
+ // Mark incomplete tool calls as done (they were interrupted)
29548
+ if (msg.message.role === 'tool' && msg.action && !msg.action.done) {
29549
+ msg = {
29550
+ ...msg,
29551
+ action: {
29552
+ ...msg.action,
29553
+ done: true,
29554
+ // Mark as interrupted so UI can show appropriate state
29555
+ input: {
29556
+ ...msg.action.input,
29557
+ _interrupted: true,
29558
+ },
29559
+ },
29560
+ };
29561
+ }
29562
+ return msg;
29563
+ })
29564
+ // Remove empty assistant messages (streaming was interrupted before content)
29565
+ .filter((msg) => {
29566
+ if (msg.message.role === 'assistant') {
29567
+ const content = msg.message.content;
29568
+ return content && typeof content === 'string' && content.trim().length > 0;
29569
+ }
29570
+ return true;
29571
+ });
29572
+ }
29292
29573
  function hydrateMessages(messages) {
29293
29574
  const visibleMessages = messages.filter((message) => !message.action?.hidden);
29294
- return hydrateToolNames(visibleMessages);
29575
+ const cleanedMessages = cleanupInterruptedMessages(visibleMessages);
29576
+ return hydrateToolNames(cleanedMessages);
29295
29577
  }
29296
29578
 
29297
29579
  function deriveErrorInfo(error) {
@@ -29361,6 +29643,75 @@ function deriveErrorInfo(error) {
29361
29643
  return { message: 'Something went wrong. Please try again.' };
29362
29644
  }
29363
29645
 
29646
+ /**
29647
+ * Stream Buffer
29648
+ * Smooths out streaming text rendering by buffering words and draining them
29649
+ * with requestAnimationFrame for a fluid typing effect.
29650
+ */
29651
+ function createStreamBuffer() {
29652
+ return {
29653
+ pendingWords: [],
29654
+ displayedContent: '',
29655
+ streamEnded: false,
29656
+ rafHandle: null,
29657
+ };
29658
+ }
29659
+ function appendToBuffer(buffer, content) {
29660
+ // Split by whitespace while preserving the whitespace characters
29661
+ const words = content.split(/(\s+)/);
29662
+ buffer.pendingWords.push(...words.filter(w => w.length > 0));
29663
+ }
29664
+ function startBufferDrain(buffer, onContentUpdate) {
29665
+ if (buffer.rafHandle !== null) {
29666
+ return; // Already draining
29667
+ }
29668
+ const drainLoop = () => {
29669
+ if (buffer.pendingWords.length === 0) {
29670
+ if (buffer.streamEnded) {
29671
+ buffer.rafHandle = null;
29672
+ return;
29673
+ }
29674
+ // No words to render, wait for more
29675
+ buffer.rafHandle = requestAnimationFrame(drainLoop);
29676
+ return;
29677
+ }
29678
+ // Adaptive: render more words if buffer is filling up
29679
+ const wordsToRender = buffer.pendingWords.length > 20 ? 3 : 1;
29680
+ const chunk = buffer.pendingWords.splice(0, wordsToRender).join('');
29681
+ buffer.displayedContent += chunk;
29682
+ onContentUpdate(buffer.displayedContent);
29683
+ buffer.rafHandle = requestAnimationFrame(drainLoop);
29684
+ };
29685
+ buffer.rafHandle = requestAnimationFrame(drainLoop);
29686
+ }
29687
+ function flushBuffer(buffer) {
29688
+ buffer.streamEnded = true;
29689
+ if (buffer.rafHandle !== null) {
29690
+ cancelAnimationFrame(buffer.rafHandle);
29691
+ buffer.rafHandle = null;
29692
+ }
29693
+ const remaining = buffer.pendingWords.join('');
29694
+ buffer.displayedContent += remaining;
29695
+ buffer.pendingWords = [];
29696
+ return buffer.displayedContent;
29697
+ }
29698
+ function cancelBuffer(buffer) {
29699
+ if (buffer.rafHandle !== null) {
29700
+ cancelAnimationFrame(buffer.rafHandle);
29701
+ buffer.rafHandle = null;
29702
+ }
29703
+ buffer.streamEnded = true;
29704
+ }
29705
+ function resetBuffer(buffer) {
29706
+ if (buffer.rafHandle !== null) {
29707
+ cancelAnimationFrame(buffer.rafHandle);
29708
+ buffer.rafHandle = null;
29709
+ }
29710
+ buffer.pendingWords = [];
29711
+ buffer.displayedContent = '';
29712
+ buffer.streamEnded = false;
29713
+ }
29714
+
29364
29715
  function createStreamState() {
29365
29716
  return {
29366
29717
  currentContent: "",
@@ -29370,6 +29721,7 @@ function createStreamState() {
29370
29721
  sources: [],
29371
29722
  toolCallToActionId: {},
29372
29723
  requestId: generateMessageId(),
29724
+ buffer: createStreamBuffer(),
29373
29725
  };
29374
29726
  }
29375
29727
  function upsertMessage(setState, message, isTyping) {
@@ -29432,6 +29784,8 @@ function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
29432
29784
  },
29433
29785
  isStreaming: false,
29434
29786
  toolExecuting: existingName,
29787
+ // Mark action as done when tool message is finalized
29788
+ action: entry.action ? { ...entry.action, done: true } : undefined,
29435
29789
  };
29436
29790
  });
29437
29791
  return { ...prev, messages, isTyping: false, isLoading: false };
@@ -29440,26 +29794,34 @@ function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
29440
29794
  }
29441
29795
 
29442
29796
  function handleContentEvent(event, streamState, onMessageUpdate, setState) {
29797
+ // Track full content for finalization
29443
29798
  streamState.currentContent += event.content;
29444
- const assistantMessage = {
29445
- id: streamState.currentMessageId,
29446
- message: { role: "assistant", content: streamState.currentContent },
29447
- timestamp: new Date().toISOString(),
29448
- sources: streamState.sources,
29449
- isStreaming: true,
29450
- };
29451
- streamState.newMessageIds.add(assistantMessage.id);
29452
- onMessageUpdate(assistantMessage);
29453
- const hasContent = assistantMessage.message.content?.trim().length || 0 > 0;
29454
- const isToolExecuting = streamState.activeToolCallCount > 0;
29455
- const isTyping = (!hasContent && assistantMessage.isStreaming) || isToolExecuting;
29456
- upsertMessage(setState, assistantMessage, isTyping);
29799
+ // Add to buffer for smooth rendering
29800
+ appendToBuffer(streamState.buffer, event.content);
29801
+ // Start drain loop if not already running
29802
+ startBufferDrain(streamState.buffer, (displayedContent) => {
29803
+ const assistantMessage = {
29804
+ id: streamState.currentMessageId,
29805
+ message: { role: "assistant", content: displayedContent },
29806
+ timestamp: new Date().toISOString(),
29807
+ sources: streamState.sources,
29808
+ isStreaming: true,
29809
+ };
29810
+ streamState.newMessageIds.add(assistantMessage.id);
29811
+ onMessageUpdate(assistantMessage);
29812
+ const hasContent = displayedContent.trim().length > 0;
29813
+ const isToolExecuting = streamState.activeToolCallCount > 0;
29814
+ const isTyping = (!hasContent && assistantMessage.isStreaming) || isToolExecuting;
29815
+ upsertMessage(setState, assistantMessage, isTyping);
29816
+ });
29457
29817
  }
29458
29818
  function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
29459
- if (streamState.currentContent.trim()) {
29819
+ // Flush buffer before tool starts
29820
+ const flushedContent = flushBuffer(streamState.buffer);
29821
+ if (flushedContent.trim()) {
29460
29822
  const finalAssistant = {
29461
29823
  id: streamState.currentMessageId,
29462
- message: { role: "assistant", content: streamState.currentContent },
29824
+ message: { role: "assistant", content: flushedContent },
29463
29825
  timestamp: new Date().toISOString(),
29464
29826
  sources: streamState.sources,
29465
29827
  isStreaming: false,
@@ -29470,6 +29832,8 @@ function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
29470
29832
  streamState.currentContent = "";
29471
29833
  streamState.currentMessageId = generateMessageId();
29472
29834
  }
29835
+ // Reset buffer for post-tool content
29836
+ resetBuffer(streamState.buffer);
29473
29837
  const toolMessageId = event.tool_call_id;
29474
29838
  streamState.activeToolCallCount += 1;
29475
29839
  streamState.newMessageIds.add(toolMessageId);
@@ -29487,44 +29851,22 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
29487
29851
  streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
29488
29852
  setState(prev => {
29489
29853
  const messages = prev.messages.map((msg) => {
29490
- const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
29491
- if (!matchesToolCall) {
29854
+ if (msg.message.role !== "tool" || msg.message.tool_call_id !== event.tool_call_id) {
29492
29855
  return msg;
29493
29856
  }
29494
- const existingName = msg.message.name || event.tool_name;
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 = {
29857
+ const toolName = msg.message.name || event.tool_name;
29858
+ // For actions: just mark as done, preserve existing input (display data is immutable)
29859
+ // For non-action tools: update normally
29860
+ const action = msg.action
29861
+ ? { ...msg.action, done: event.done }
29862
+ : undefined;
29863
+ return {
29516
29864
  ...msg,
29517
- message: {
29518
- role: "tool",
29519
- content: event.state ? JSON.stringify(event.state) : (typeof msg.message.content === "string" ? msg.message.content : ""),
29520
- tool_call_id: event.tool_call_id,
29521
- name: existingName,
29522
- },
29865
+ message: { ...msg.message, name: toolName },
29523
29866
  isStreaming: false,
29524
- toolExecuting: existingName,
29867
+ toolExecuting: toolName,
29525
29868
  action,
29526
29869
  };
29527
- return updatedMsg;
29528
29870
  });
29529
29871
  return { ...prev, messages, isTyping: true, isLoading: false };
29530
29872
  });
@@ -29557,11 +29899,6 @@ function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
29557
29899
  return { ...prev, messages, isTyping: true, isLoading: false };
29558
29900
  });
29559
29901
  }
29560
- function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
29561
- streamState.sources = event.sources;
29562
- streamState.toolCallToActionId = event.tool_call_to_action_id;
29563
- finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
29564
- }
29565
29902
  function handleHaltEvent(event, _streamState, onMessageUpdate, setState) {
29566
29903
  const toolNames = event.tool_calls.map(call => call.name).join(", ");
29567
29904
  const notice = toolNames
@@ -29576,7 +29913,8 @@ function handleHaltEvent(event, _streamState, onMessageUpdate, setState) {
29576
29913
  };
29577
29914
  onMessageUpdate(haltMessage);
29578
29915
  upsertMessage(setState, haltMessage, false);
29579
- setState(prev => ({ ...prev, error: "Awaiting external tool handling." }));
29916
+ // Stop loading/typing state when halted
29917
+ setState(prev => ({ ...prev, isLoading: false, isTyping: false, error: "Awaiting external tool handling." }));
29580
29918
  }
29581
29919
  function handleErrorEvent(_event, _streamState, onMessageUpdate, setState) {
29582
29920
  const errorMessage = {
@@ -29588,6 +29926,8 @@ function handleErrorEvent(_event, _streamState, onMessageUpdate, setState) {
29588
29926
  };
29589
29927
  onMessageUpdate(errorMessage);
29590
29928
  upsertMessage(setState, errorMessage, false);
29929
+ // Stop loading/typing state on error
29930
+ setState(prev => ({ ...prev, isLoading: false, isTyping: false }));
29591
29931
  }
29592
29932
  const eventHandlers = {
29593
29933
  content: handleContentEvent,
@@ -29615,10 +29955,37 @@ function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
29615
29955
  console.warn('[Chat] Unknown event type:', event.type);
29616
29956
  }
29617
29957
  }
29618
-
29619
- function isDismissedState(state) {
29620
- return Boolean(state.__dismissed);
29958
+ function handleDoneEvent(event, streamState, onMessageUpdate, setState) {
29959
+ // Flush any remaining buffered content
29960
+ const flushedContent = flushBuffer(streamState.buffer);
29961
+ // Update the final message with complete content if there was content
29962
+ if (flushedContent.trim()) {
29963
+ const finalMessage = {
29964
+ id: streamState.currentMessageId,
29965
+ message: { role: "assistant", content: flushedContent },
29966
+ timestamp: new Date().toISOString(),
29967
+ sources: event.sources,
29968
+ isStreaming: false,
29969
+ };
29970
+ streamState.newMessageIds.add(finalMessage.id);
29971
+ onMessageUpdate(finalMessage);
29972
+ upsertMessage(setState, finalMessage, false);
29973
+ }
29974
+ streamState.sources = event.sources;
29975
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
29976
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
29621
29977
  }
29978
+
29979
+ /**
29980
+ * Handle the action loop for halting actions.
29981
+ *
29982
+ * Flow:
29983
+ * 1. Display the action in UI
29984
+ * 2. Call the frontend handler (which waits for user interaction or returns immediately for display actions)
29985
+ * 3. Handler returns body when complete
29986
+ * 4. Send body to backend via continueAgentAction
29987
+ * 5. Process any subsequent events (may include new action_request for chained actions)
29988
+ */
29622
29989
  async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
29623
29990
  let pendingEvent = initialEvent;
29624
29991
  while (pendingEvent) {
@@ -29644,7 +30011,6 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29644
30011
  toolCallId: pendingEvent.tool_call_id,
29645
30012
  actionId: pendingEvent.action_id,
29646
30013
  input: pendingEvent.input,
29647
- state: pendingEvent.state,
29648
30014
  done: pendingEvent.done ?? false,
29649
30015
  },
29650
30016
  };
@@ -29669,9 +30035,13 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29669
30035
  upsertMessage(setState, errorMessage, false);
29670
30036
  return;
29671
30037
  }
29672
- let nextState;
30038
+ // Handler returns body when complete (for display actions this is immediate,
30039
+ // for interactive actions this waits for user completion)
30040
+ // Note: For halting actions, input contains the transformed data from getInitialClientState
30041
+ let body;
29673
30042
  try {
29674
- nextState = await handler(pendingEvent.input, pendingEvent.state, {
30043
+ body = await handler(pendingEvent.input, pendingEvent.input, // Input now contains the display data for halting actions
30044
+ {
29675
30045
  widgetId,
29676
30046
  conversationId,
29677
30047
  toolCallId: pendingEvent.tool_call_id,
@@ -29693,25 +30063,16 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29693
30063
  return;
29694
30064
  }
29695
30065
  pendingEvent = null;
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
- }
30066
+ // Send body to backend and continue agent
30067
+ // No need to update message - input is immutable and already contains display data
29707
30068
  let streamEnded = false;
29708
- for await (const event of client.continueAgentMessageStream(conversationId, resumeToolCallId, nextState)) {
30069
+ for await (const event of client.continueAgentAction(conversationId, resumeToolCallId, body)) {
29709
30070
  if (event.type === "action_request") {
30071
+ // Chained action - continue the loop
29710
30072
  pendingEvent = event;
29711
30073
  break;
29712
30074
  }
29713
30075
  if (event.type === "done") {
29714
- // Finalize tool message and stream messages
29715
30076
  finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
29716
30077
  streamState.sources = event.sources;
29717
30078
  streamState.toolCallToActionId = event.tool_call_to_action_id;
@@ -29741,61 +30102,118 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29741
30102
  }
29742
30103
  }
29743
30104
  }
29744
- function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate, createStreamState, registerCallback) {
30105
+ /**
30106
+ * Setup resume callbacks for incomplete actions after page reload.
30107
+ *
30108
+ * When a page reloads with an incomplete action, this sets up callbacks
30109
+ * so when the user completes the action, we can continue the agent flow.
30110
+ */
30111
+ function setupActionResumeCallbacks(messages, client, conversationId, widgetId, setState, onMessageUpdate, createStreamState, registerCallback) {
29745
30112
  // Find all incomplete actions and register resume callbacks
29746
30113
  for (const message of messages) {
29747
30114
  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
30115
+ const initialToolCallId = message.action.toolCallId;
30116
+ const initialToolName = message.message.name || message.toolExecuting || "tool";
30117
+ registerCallback(initialToolCallId, async (body) => {
30118
+ // When user completes the action after reload, continue the stream
29752
30119
  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
30120
  setState(prev => ({
29759
30121
  ...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
30122
  isTyping: true,
29770
30123
  }));
29771
30124
  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;
30125
+ let currentToolCallId = initialToolCallId;
30126
+ let currentToolName = initialToolName;
30127
+ let currentBody = body;
30128
+ // Loop to handle chained action_requests
30129
+ while (true) {
30130
+ let nextActionRequest = null;
30131
+ // Continue the agent with the body
30132
+ for await (const event of client.continueAgentAction(conversationId, currentToolCallId, currentBody)) {
30133
+ if (event.type === "action_request") {
30134
+ // Chained action - need to handle the new action request
30135
+ nextActionRequest = event;
30136
+ break;
30137
+ }
30138
+ if (event.type === "done") {
30139
+ finalizeToolMessage(streamState, setState, currentToolCallId, currentToolName);
30140
+ streamState.sources = event.sources;
30141
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
30142
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
30143
+ setState(prev => ({ ...prev, isTyping: false }));
30144
+ return;
30145
+ }
30146
+ if (event.type === "error") {
30147
+ const errorMessage = {
30148
+ id: generateMessageId(),
30149
+ message: {
30150
+ role: "assistant",
30151
+ content: "Sorry, an error occurred. Please try again later.",
30152
+ },
30153
+ timestamp: new Date().toISOString(),
30154
+ sources: [],
30155
+ isError: true,
30156
+ };
30157
+ upsertMessage(setState, errorMessage, false);
30158
+ setState(prev => ({ ...prev, isTyping: false }));
30159
+ return;
30160
+ }
30161
+ handleStreamEvent(event, streamState, onMessageUpdate, setState);
30162
+ }
30163
+ // If no action_request, stream ended normally
30164
+ if (!nextActionRequest) {
30165
+ setState(prev => ({ ...prev, isTyping: false }));
30166
+ return;
30167
+ }
30168
+ // Update UI with new action for the chained action
30169
+ const toolMessage = {
30170
+ id: nextActionRequest.tool_call_id,
30171
+ sources: [],
30172
+ message: {
30173
+ role: "tool",
30174
+ content: "",
30175
+ tool_call_id: nextActionRequest.tool_call_id,
30176
+ name: currentToolName,
30177
+ },
30178
+ timestamp: new Date().toISOString(),
30179
+ isStreaming: true,
30180
+ toolExecuting: currentToolName,
30181
+ action: {
30182
+ implementation: nextActionRequest.implementation,
30183
+ toolCallId: nextActionRequest.tool_call_id,
30184
+ actionId: nextActionRequest.action_id,
30185
+ input: nextActionRequest.input,
30186
+ done: nextActionRequest.done ?? false,
30187
+ },
30188
+ };
30189
+ upsertMessage(setState, toolMessage, true);
30190
+ // Wait for user to complete the chained action
30191
+ const handler = getFrontendActionHandler(nextActionRequest.implementation);
30192
+ if (!handler) {
30193
+ console.error("[Action Resume] No handler for implementation:", nextActionRequest.implementation);
30194
+ setState(prev => ({ ...prev, isTyping: false }));
30195
+ return;
30196
+ }
30197
+ let handlerResult;
30198
+ try {
30199
+ handlerResult = await handler(nextActionRequest.input, nextActionRequest.input, // Input contains display data for halting actions
30200
+ {
30201
+ widgetId,
30202
+ conversationId,
30203
+ toolCallId: nextActionRequest.tool_call_id,
30204
+ actionId: nextActionRequest.action_id,
30205
+ implementation: nextActionRequest.implementation,
30206
+ });
29780
30207
  }
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);
30208
+ catch (handlerError) {
30209
+ console.error("[Action Resume] Handler failed:", handlerError);
29793
30210
  setState(prev => ({ ...prev, isTyping: false }));
29794
30211
  return;
29795
30212
  }
29796
- handleStreamEvent(event, streamState, onMessageUpdate, setState);
30213
+ // Continue loop with new body
30214
+ currentToolCallId = nextActionRequest.tool_call_id;
30215
+ currentBody = handlerResult;
29797
30216
  }
29798
- setState(prev => ({ ...prev, isTyping: false }));
29799
30217
  }
29800
30218
  catch (error) {
29801
30219
  console.error("[Action Resume] Failed to continue stream:", error);
@@ -29874,7 +30292,7 @@ function useChat(options) {
29874
30292
  }));
29875
30293
  // Setup resume callbacks for incomplete actions
29876
30294
  if (conversationId) {
29877
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
30295
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, widgetId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
29878
30296
  }
29879
30297
  }
29880
30298
  catch (error) {
@@ -29908,6 +30326,21 @@ function useChat(options) {
29908
30326
  saveConversation(widgetId, state.conversationId, state.messages);
29909
30327
  }
29910
30328
  }, [widgetId, state.messages, state.conversationId, state.config?.settings.persistConversation]);
30329
+ // Save conversation on page unload to preserve streaming state
30330
+ useEffect(() => {
30331
+ const persistConversation = state.config?.settings.persistConversation ?? true;
30332
+ if (!persistConversation || !isStorageAvailable())
30333
+ return;
30334
+ const handleBeforeUnload = () => {
30335
+ const currentState = stateRef.current;
30336
+ if (currentState.messages.length > 0 && currentState.conversationId) {
30337
+ // Force save current state before page closes
30338
+ saveConversation(widgetId, currentState.conversationId, currentState.messages);
30339
+ }
30340
+ };
30341
+ window.addEventListener('beforeunload', handleBeforeUnload);
30342
+ return () => window.removeEventListener('beforeunload', handleBeforeUnload);
30343
+ }, [widgetId, state.config?.settings.persistConversation]);
29911
30344
  const sendMessage = useCallback(async (content, files) => {
29912
30345
  const trimmedContent = content.trim();
29913
30346
  const hasFiles = !!files && files.length > 0;
@@ -29991,12 +30424,14 @@ function useChat(options) {
29991
30424
  stateRef.current.conversationId !== streamConversationId ||
29992
30425
  currentRequestIdRef.current !== streamRequestId) {
29993
30426
  console.log('[Widget] Stream aborted, conversation changed, or superseded by new request');
30427
+ cancelBuffer(streamState.buffer);
29994
30428
  break;
29995
30429
  }
29996
30430
  if (event.type === "action_request") {
29997
30431
  if (currentAbortController?.signal.aborted ||
29998
30432
  stateRef.current.conversationId !== streamConversationId ||
29999
30433
  currentRequestIdRef.current !== streamRequestId) {
30434
+ cancelBuffer(streamState.buffer);
30000
30435
  break;
30001
30436
  }
30002
30437
  await handleActionLoop(apiClient.current, event, streamState, (message) => {
@@ -30022,26 +30457,8 @@ function useChat(options) {
30022
30457
  if (lastStreamedMessage) {
30023
30458
  onMessage?.(lastStreamedMessage);
30024
30459
  }
30025
- const enableFollowUps = state.config?.settings.enableFollowUpSuggestions !== false;
30026
- const actionIds = state.config?.actions || [];
30027
- if (enableFollowUps) {
30028
- apiClient.current.generateFollowUps(stateRef.current.messages, actionIds)
30029
- .then(suggestions => {
30030
- if (suggestions.length > 0) {
30031
- setState(prev => {
30032
- const messages = [...prev.messages];
30033
- for (let i = messages.length - 1; i >= 0; i--) {
30034
- if (messages[i].message.role === 'assistant' && !messages[i].isError) {
30035
- messages[i] = { ...messages[i], suggestions };
30036
- break;
30037
- }
30038
- }
30039
- return { ...prev, messages };
30040
- });
30041
- }
30042
- })
30043
- .catch(err => console.warn('[Widget] Follow-up generation failed:', err));
30044
- }
30460
+ // Follow-up suggestions are now generated server-side in parallel and included in the done event
30461
+ // They are automatically attached to the last assistant message by finalizeStreamMessages()
30045
30462
  }
30046
30463
  catch (error) {
30047
30464
  console.error("[Widget] sendMessage error:", error);
@@ -30198,7 +30615,7 @@ function useChat(options) {
30198
30615
  messages: hydratedMessages,
30199
30616
  isLoading: false,
30200
30617
  }));
30201
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
30618
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, widgetId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
30202
30619
  if (persistConversation && isStorageAvailable()) {
30203
30620
  saveConversation(widgetId, conversation.id, hydratedMessages);
30204
30621
  }
@@ -30285,6 +30702,16 @@ function useChat(options) {
30285
30702
  return null;
30286
30703
  }
30287
30704
  }, [widgetId, state.config?.settings.persistConversation]);
30705
+ // Call an action endpoint directly (frontend-owned flow)
30706
+ // Auto-injects conversationId and toolCallId for done flag enforcement
30707
+ const callActionEndpoint = useCallback(async (actionId, endpoint, input, options) => {
30708
+ const enrichedInput = {
30709
+ ...input,
30710
+ conversationId: state.conversationId,
30711
+ toolCallId: options?.toolCallId,
30712
+ };
30713
+ return apiClient.current.callActionEndpoint(actionId, endpoint, enrichedInput, options?.token);
30714
+ }, [state.conversationId]);
30288
30715
  return {
30289
30716
  messages: state.messages,
30290
30717
  isLoading: state.isLoading,
@@ -30302,6 +30729,7 @@ function useChat(options) {
30302
30729
  startNewConversation,
30303
30730
  deleteConversation: deleteConversation$1,
30304
30731
  createDemoConversation,
30732
+ callActionEndpoint,
30305
30733
  };
30306
30734
  }
30307
30735
 
@@ -30317,17 +30745,19 @@ const PlusIcon = () => (jsxs("svg", { width: "22", height: "22", viewBox: "0 0 2
30317
30745
  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" })] }));
30318
30746
  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" })] }));
30319
30747
  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,
30748
+ const ChatWindow = ({ messages, isLoading, isTyping, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick, onActionDismiss, onCallEndpoint,
30321
30749
  // Chat history props (only active when persistConversation is true)
30322
30750
  conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
30323
30751
  // Override props for live preview
30324
- headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride, }) => {
30752
+ sizeOverride, headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride,
30753
+ // Demo mode
30754
+ onInputFocus, }) => {
30325
30755
  const appearance = config?.appearance;
30326
30756
  const settings = config?.settings;
30327
30757
  // Check if chat history should be shown (requires both persistConversation AND showChatHistory)
30328
30758
  const canShowHistory = (settings?.persistConversation ?? true) && (settings?.showChatHistory ?? true);
30329
30759
  // Apply overrides for live preview (overrides take priority over saved config)
30330
- const size = appearance?.size || 'medium';
30760
+ const size = sizeOverride ?? appearance?.size ?? 'medium';
30331
30761
  const headerTitle = headerTitleOverride ?? appearance?.headerTitle ?? 'AI Assistant';
30332
30762
  const welcomeTitle = welcomeTitleOverride ?? appearance?.welcomeTitle ?? '';
30333
30763
  const welcomeMessage = welcomeMessageOverride ?? appearance?.welcomeMessage ?? '';
@@ -30404,7 +30834,7 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
30404
30834
  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) => {
30405
30835
  e.stopPropagation();
30406
30836
  onDeleteConversation(conv.id);
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." })), (() => {
30837
+ }, "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, onInputFocus: onInputFocus })] })) : (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
30838
  console.log('[DEBUG ChatWindow] Rendering MessageList with', messages.length, 'messages');
30409
30839
  messages.forEach((m, i) => {
30410
30840
  console.log(`[DEBUG ChatWindow] msg ${i}:`, { role: m.message.role, hasAction: !!m.action, impl: m.action?.implementation });
@@ -30414,7 +30844,15 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
30414
30844
  console.log('[DEBUG ChatWindow] Testing renderer for query-contact-directory:', !!getActionRenderer('query-contact-directory'));
30415
30845
  }
30416
30846
  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 })] }))] }));
30847
+ })(), 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, onCallEndpoint: onCallEndpoint }), 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, onInputFocus: onInputFocus })] }))] }));
30848
+ };
30849
+
30850
+ const MessageCircleIcon = () => (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" }) }));
30851
+ const ChevronDownIcon = () => (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" }) }));
30852
+ // Icon components mapping for dynamic lookup
30853
+ const iconComponents = {
30854
+ FiMessageCircle: MessageCircleIcon,
30855
+ FiChevronDown: ChevronDownIcon,
30418
30856
  };
30419
30857
 
30420
30858
  /**
@@ -30712,108 +31150,60 @@ function generateThemeStyles(appearance, theme) {
30712
31150
  return styles;
30713
31151
  }
30714
31152
 
30715
- /**
30716
- * Auto Theme Detector
30717
- * Detects whether the widget should use light or dark mode
30718
- * based on the background behind it
30719
- */
30720
- /**
30721
- * Sample the background color behind an element
30722
- * Uses multiple sampling points for accuracy
30723
- */
30724
- function sampleBackgroundColor(element) {
30725
- const rect = element.getBoundingClientRect();
30726
- const centerX = rect.left + rect.width / 2;
30727
- const centerY = rect.top + rect.height / 2;
30728
- // Try to get the element behind our widget
30729
- // Temporarily hide the element to sample what's behind
30730
- const originalVisibility = element.style.visibility;
30731
- element.style.visibility = 'hidden';
30732
- // Sample the center point
30733
- const elementBehind = document.elementFromPoint(centerX, centerY);
30734
- // Restore visibility
30735
- element.style.visibility = originalVisibility;
30736
- if (!elementBehind) {
30737
- return '#ffffff'; // Default to white
30738
- }
30739
- // Get computed background color
30740
- const computedStyle = window.getComputedStyle(elementBehind);
30741
- let bgColor = computedStyle.backgroundColor;
30742
- // If transparent, walk up the DOM tree
30743
- if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
30744
- let parent = elementBehind.parentElement;
30745
- while (parent) {
30746
- const parentStyle = window.getComputedStyle(parent);
30747
- bgColor = parentStyle.backgroundColor;
30748
- if (bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent') {
30749
- break;
30750
- }
30751
- parent = parent.parentElement;
30752
- }
30753
- }
30754
- // If still transparent, check body/html
30755
- if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
30756
- const bodyStyle = window.getComputedStyle(document.body);
30757
- bgColor = bodyStyle.backgroundColor;
30758
- if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
30759
- return '#ffffff'; // Default to white
31153
+ function useWidgetAppearance({ containerRef, config, theme, primaryColor, position, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, welcomeBubbleText, triggerType, triggerText, customStyles, zIndex, previewMode: _previewMode, }) {
31154
+ // Use theme prop directly - no dynamic detection
31155
+ const effectiveTheme = theme ?? "light";
31156
+ // Set data attribute for CSS styling
31157
+ useEffect(() => {
31158
+ if (containerRef.current) {
31159
+ containerRef.current.setAttribute('data-theme', effectiveTheme);
30760
31160
  }
30761
- }
30762
- return rgbaToHex(bgColor);
30763
- }
30764
- /**
30765
- * Convert rgba/rgb string to hex
30766
- */
30767
- function rgbaToHex(rgba) {
30768
- // Handle rgb(r, g, b) or rgba(r, g, b, a)
30769
- const match = rgba.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
30770
- if (!match)
30771
- return '#ffffff';
30772
- const r = parseInt(match[1]);
30773
- const g = parseInt(match[2]);
30774
- const b = parseInt(match[3]);
30775
- return '#' + [r, g, b].map(x => {
30776
- const hex = x.toString(16);
30777
- return hex.length === 1 ? '0' + hex : hex;
30778
- }).join('');
30779
- }
30780
- /**
30781
- * Determine if the background is dark
30782
- */
30783
- function isBackgroundDark(backgroundColor) {
30784
- const luminance = getLuminance(backgroundColor);
30785
- return luminance < 0.5;
30786
- }
30787
- /**
30788
- * Auto-detect theme based on background
30789
- */
30790
- function detectTheme(element) {
30791
- const bgColor = sampleBackgroundColor(element);
30792
- return isBackgroundDark(bgColor) ? 'dark' : 'light';
31161
+ }, [effectiveTheme, containerRef]);
31162
+ const appearanceConfig = config?.appearance;
31163
+ const effectivePosition = position || appearanceConfig?.position || "bottom-right";
31164
+ const accentColor = primaryColor !== undefined ? primaryColor : appearanceConfig?.primaryColor ?? "";
31165
+ const effectiveSize = size || appearanceConfig?.size || "small";
31166
+ const effectiveHeaderTitle = headerTitle ?? appearanceConfig?.headerTitle ?? "";
31167
+ const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? "";
31168
+ const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? "";
31169
+ const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? "";
31170
+ const effectiveWelcomeBubbleText = welcomeBubbleText ?? appearanceConfig?.welcomeBubbleText ?? "";
31171
+ const effectiveTriggerType = triggerType ?? appearanceConfig?.triggerType ?? "button";
31172
+ const effectiveTriggerText = triggerText ?? appearanceConfig?.triggerText ?? "Chat";
31173
+ const simpleAppearance = {
31174
+ accentColor};
31175
+ const generatedStyles = generateThemeStyles(simpleAppearance, effectiveTheme);
31176
+ const legacyStyles = appearanceConfig ? applyAppearanceStyles(appearanceConfig) : {};
31177
+ const mergedStyles = {
31178
+ ...legacyStyles,
31179
+ ...generatedStyles,
31180
+ ...customStyles,
31181
+ ...(zIndex !== undefined ? { "--widget-z-index": String(zIndex) } : {}),
31182
+ };
31183
+ // Compute icon contrast color for inline button styling (prevents FOUC)
31184
+ const iconContrastColor = accentColor ? getContrastText(accentColor) : undefined;
31185
+ return {
31186
+ effectiveTheme,
31187
+ effectivePosition,
31188
+ accentColor,
31189
+ iconContrastColor,
31190
+ effectiveSize,
31191
+ effectiveHeaderTitle,
31192
+ effectiveWelcomeTitle,
31193
+ effectiveWelcomeMessage,
31194
+ effectivePlaceholder,
31195
+ effectiveWelcomeBubbleText,
31196
+ effectiveTriggerType,
31197
+ effectiveTriggerText,
31198
+ mergedStyles,
31199
+ };
30793
31200
  }
30794
- /**
30795
- * Create a MutationObserver to watch for theme changes
30796
- */
30797
- function createThemeObserver(element, callback) {
30798
- let lastTheme = detectTheme(element);
30799
- const observer = new MutationObserver(() => {
30800
- const theme = detectTheme(element);
30801
- if (theme !== lastTheme) {
30802
- lastTheme = theme;
30803
- callback(theme);
30804
- }
30805
- });
30806
- // Observe body for class/style changes (common for theme switching)
30807
- observer.observe(document.body, {
30808
- attributes: true,
30809
- attributeFilter: ['class', 'style', 'data-theme', 'data-bs-theme'],
30810
- });
30811
- // Also observe html element
30812
- observer.observe(document.documentElement, {
30813
- attributes: true,
30814
- attributeFilter: ['class', 'style', 'data-theme', 'data-bs-theme'],
30815
- });
30816
- return observer;
31201
+
31202
+ function WidgetTriggers({ triggerType, isOpen, onToggle, triggerText, placeholder, IconComponent, showWelcomeBubble, welcomeBubbleText, previewMode, onDismissBubble, isInputBarCollapsed, setIsInputBarCollapsed, inputBarValue, setInputBarValue, onSubmitInputBar, accentColor, iconColor, }) {
31203
+ // Inline button styles to prevent flash of unstyled content (FOUC)
31204
+ // Applied directly to button elements, bypassing CSS variable cascade timing
31205
+ const buttonStyle = accentColor ? { background: accentColor, color: iconColor } : undefined;
31206
+ return (jsxs(Fragment, { children: [triggerType === "button" && !isOpen && welcomeBubbleText && (previewMode || showWelcomeBubble) && (jsxs("div", { className: "ai-chat-welcome-bubble", onClick: onToggle, children: [jsx("span", { children: welcomeBubbleText }), jsx("button", { className: "ai-chat-welcome-bubble-close", onClick: onDismissBubble, "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" })] })), triggerType === "button" && (jsx("button", { className: `ai-chat-button ${isOpen ? "is-open" : ""}`, onClick: onToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", style: buttonStyle, children: jsx("div", { className: "ai-chat-button-svg", children: jsx(IconComponent, {}) }) })), triggerType === "pill-text" && (jsxs("button", { className: `ai-chat-trigger-pill ${isOpen ? "is-open" : ""}`, onClick: onToggle, "aria-label": isOpen ? "Close chat" : "Open chat", style: isOpen ? buttonStyle : undefined, children: [jsx("div", { className: "ai-chat-trigger-pill-icon", children: jsx(IconComponent, {}) }), !isOpen && jsx("span", { children: triggerText })] })), triggerType === "input-bar" && !isOpen && (jsx("div", { className: "ai-chat-trigger-input-container", children: isInputBarCollapsed ? (jsxs("div", { className: "ai-chat-trigger-input-row", children: [jsx("button", { type: "button", className: "ai-chat-trigger-collapse-toggle", onClick: () => setIsInputBarCollapsed(false), "aria-label": "Expand input bar", children: jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "15 18 9 12 15 6" }) }) }), jsx("button", { type: "button", className: "ai-chat-button", onClick: onToggle, "aria-label": "Open chat", style: buttonStyle, children: jsx("div", { className: "ai-chat-button-svg", children: jsx(IconComponent, {}) }) })] })) : (jsxs("div", { className: "ai-chat-trigger-input-row", children: [jsx("button", { type: "button", className: "ai-chat-trigger-collapse-toggle", onClick: () => setIsInputBarCollapsed(true), "aria-label": "Collapse input bar", children: jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "9 18 15 12 9 6" }) }) }), jsxs("form", { className: "ai-chat-trigger-input-wrapper", onSubmit: onSubmitInputBar, children: [jsx("input", { type: "text", className: "ai-chat-trigger-input", placeholder: placeholder || "Ask me anything...", value: inputBarValue, onChange: (event) => setInputBarValue(event.target.value), "aria-label": "Chat input" }), jsx("button", { type: "submit", className: "ai-chat-trigger-input-btn", disabled: !inputBarValue.trim(), "aria-label": "Send message", style: buttonStyle, children: jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "12", y1: "19", x2: "12", y2: "5" }), jsx("polyline", { points: "5 12 12 5 19 12" })] }) })] }), jsx("button", { type: "button", className: "ai-chat-trigger-input-expand", onClick: onToggle, "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" }) }) })] })) }))] }));
30817
31207
  }
30818
31208
 
30819
31209
  function styleInject(css, ref) {
@@ -30843,34 +31233,19 @@ function styleInject(css, ref) {
30843
31233
  }
30844
31234
  }
30845
31235
 
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)}}";
31236
+ 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)}@keyframes ai-chat-message-appear{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(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-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;--breakpoint-mobile:480px;--breakpoint-tablet:768px;--breakpoint-desktop:769px;--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)!important}.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{height:100%;inset:0;pointer-events:none;position:absolute;width:100%}.ai-chat-widget-container.container-mode .ai-chat-button,.ai-chat-widget-container.container-mode .ai-chat-trigger-button,.ai-chat-widget-container.container-mode .ai-chat-trigger-input-container,.ai-chat-widget-container.container-mode .ai-chat-window{pointer-events:auto}.ai-chat-widget-container.container-mode:not(.trigger-input-bar) .ai-chat-button{position:absolute}.ai-chat-widget-container.container-mode:not(.trigger-input-bar).bottom-right .ai-chat-button{bottom:20px;left:auto;right:20px;top:auto}.ai-chat-widget-container.container-mode:not(.trigger-input-bar).bottom-left .ai-chat-button{bottom:20px;left:20px;right:auto;top:auto}.ai-chat-widget-container.container-mode:not(.trigger-input-bar).top-right .ai-chat-button{bottom:auto;left:auto;right:20px;top:20px}.ai-chat-widget-container.container-mode:not(.trigger-input-bar).top-left .ai-chat-button{bottom:auto;left:20px;right:auto;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-user-message-sent{0%{opacity:0;transform:translateX(20px) scale(.95)}60%{opacity:1;transform:translateX(-4px) scale(1.02)}to{opacity:1;transform:translateX(0) scale(1)}}@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{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;animation:ai-chat-window-open var(--duration-slow,.35s) var(--spring-bounce);-webkit-backface-visibility:hidden;backface-visibility:hidden;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;-webkit-transform:translateZ(0);transform:translateZ(0);transform-origin:bottom right;will-change:transform,opacity;z-index:2147483647!important}.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;max-height:calc(100vh - 100px);max-width:calc(100vw - 40px);min-width:320px;width:380px}.ai-chat-window.size-medium{height:calc(100vh - 140px);max-height:680px;max-width:calc(100vw - 40px);min-width:380px;width:440px}.ai-chat-window.size-large{height:calc(100vh - 48px);max-height:calc(100vh - 48px);max-width:560px;min-width:440px;width:33vw}.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-widget-container.trigger-button.size-large.bottom-left .ai-chat-window,.ai-chat-widget-container.trigger-button.size-large.bottom-right .ai-chat-window{bottom:0}.ai-chat-widget-container.trigger-button.size-large.top-left .ai-chat-window,.ai-chat-widget-container.trigger-button.size-large.top-right .ai-chat-window{top:0}.ai-chat-widget-container.trigger-pill-text.size-large.bottom-left .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.size-large.bottom-right .ai-chat-window{bottom:72px;height:calc(100vh - 120px);max-height:calc(100vh - 120px)}.ai-chat-widget-container.trigger-pill-text.size-large.top-left .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.size-large.top-right .ai-chat-window{height:calc(100vh - 120px);max-height:calc(100vh - 120px);top:72px}.ai-chat-widget-container.trigger-input-bar.size-large.bottom-left .ai-chat-window,.ai-chat-widget-container.trigger-input-bar.size-large.bottom-right .ai-chat-window{bottom:72px;height:calc(100vh - 120px);max-height:calc(100vh - 120px)}.ai-chat-widget-container.trigger-input-bar.size-large.top-left .ai-chat-window,.ai-chat-widget-container.trigger-input-bar.size-large.top-right .ai-chat-window{height:calc(100vh - 120px);max-height:calc(100vh - 120px);top:72px}.ai-chat-widget-container.container-mode.bottom-right .ai-chat-window{bottom:20px;left:auto;right:20px;top:auto}.ai-chat-widget-container.container-mode.bottom-left .ai-chat-window{bottom:20px;left:20px;right:auto;top:auto}.ai-chat-widget-container.container-mode.top-right .ai-chat-window{bottom:auto;left:auto;right:20px;top:20px}.ai-chat-widget-container.container-mode.top-left .ai-chat-window{bottom:auto;left:20px;right:auto;top:20px}.ai-chat-widget-container.container-mode.size-small .ai-chat-window{height:min(500px,50%);max-height:calc(100% - 100px);max-width:calc(100% - 40px);min-height:300px;min-width:280px;width:min(380px,calc(100% - 40px))}.ai-chat-widget-container.container-mode.size-medium .ai-chat-window{height:min(680px,70%);max-height:calc(100% - 80px);max-width:calc(100% - 40px);min-height:400px;min-width:320px;width:min(440px,calc(100% - 40px))}.ai-chat-widget-container.container-mode.size-large .ai-chat-window{height:90%;max-height:calc(100% - 60px);max-width:calc(100% - 40px);min-height:500px;min-width:380px;width:min(560px,calc(100% - 40px))}.ai-chat-widget-container.trigger-button.container-mode.bottom-left .ai-chat-window,.ai-chat-widget-container.trigger-button.container-mode.bottom-right .ai-chat-window{bottom:88px}.ai-chat-widget-container.trigger-pill-text.container-mode.bottom-left .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.container-mode.bottom-right .ai-chat-window{bottom:80px}.ai-chat-widget-container.trigger-button.container-mode.size-medium .ai-chat-window,.ai-chat-widget-container.trigger-button.container-mode.size-small .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.container-mode.size-medium .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.container-mode.size-small .ai-chat-window{max-height:calc(100% - 108px)}.ai-chat-widget-container.trigger-button.container-mode.size-large .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.container-mode.size-large .ai-chat-window{height:calc(100% - 108px);max-height:calc(100% - 108px)}.ai-chat-widget-container.trigger-button.container-mode.top-left .ai-chat-window,.ai-chat-widget-container.trigger-button.container-mode.top-right .ai-chat-window{bottom:auto;top:88px}.ai-chat-widget-container.trigger-pill-text.container-mode.top-left .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.container-mode.top-right .ai-chat-window{bottom:auto;top:80px}.ai-chat-widget-container.container-mode.mobile-mode.is-open{margin:0!important;padding:0!important}.ai-chat-widget-container.container-mode.mobile-mode.is-open,.ai-chat-widget-container.container-mode.mobile-mode.is-open .ai-chat-window{bottom:0!important;height:100%!important;left:0!important;position:absolute!important;right:0!important;top:0!important;width:100%!important}.ai-chat-widget-container.container-mode.mobile-mode.is-open .ai-chat-window{animation:none!important;border:none!important;border-radius:0!important;box-shadow:none!important;max-height:100%!important;max-width:100%!important;min-height:100%!important;min-width:100%!important}.ai-chat-widget-container.container-mode.mobile-mode.is-open .ai-chat-button,.ai-chat-widget-container.container-mode.mobile-mode.is-open .ai-chat-trigger-input-container,.ai-chat-widget-container.container-mode.mobile-mode.is-open .ai-chat-trigger-pill{display:none!important}.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{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:center;-webkit-backface-visibility:hidden;backface-visibility:hidden;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;-webkit-transform:translateZ(0);transform:translateZ(0);transition:transform var(--duration-fast) ease;width:var(--button-size,56px);will-change:transform;z-index:2147483647!important}.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:2147483647!important}.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{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:center;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--trigger-bg,rgba(0,0,0,.04));border:1px solid var(--trigger-border,rgba(0,0,0,.12));border-radius:9999px;box-shadow:0 4px 16px rgba(0,0,0,.12);color:var(--trigger-text,#1a1a1a);cursor:pointer;display:flex;font-size:14px;font-weight:500;gap:10px;height:48px;justify-content:center;padding:0 24px;position:relative;-webkit-transform:translateZ(0);transform:translateZ(0);transition:all .3s ease,color .4s ease,background .4s ease,border-color .4s ease;white-space:nowrap;will-change:transform;z-index:2147483647!important}.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));color:var(--button-icon-color,var(--btn-primary-text));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:var(--trigger-bg-hover,rgba(0,0,0,.08));border-color:var(--trigger-border-hover,rgba(0,0,0,.2))}.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:20px;transition:all .3s ease;width:20px}.ai-chat-widget-container.trigger-pill-text.container-mode .ai-chat-trigger-pill{position:absolute}.ai-chat-widget-container.trigger-pill-text.container-mode.bottom-right .ai-chat-trigger-pill{bottom:20px;left:auto;right:20px;top:auto}.ai-chat-widget-container.trigger-pill-text.container-mode.bottom-left .ai-chat-trigger-pill{bottom:20px;left:20px;right:auto;top:auto}.ai-chat-widget-container.trigger-pill-text.container-mode.top-right .ai-chat-trigger-pill{bottom:auto;left:auto;right:20px;top:20px}.ai-chat-widget-container.trigger-pill-text.container-mode.top-left .ai-chat-trigger-pill{bottom:auto;left:20px;right:auto;top:20px}.ai-chat-widget-container.trigger-pill-text.container-mode .ai-chat-trigger-pill{pointer-events:auto}.ai-chat-trigger-input-container{align-items:flex-end;display:flex;flex-direction:column;gap:8px;z-index:2147483647!important}.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-row{align-items:center;display:flex;gap:8px;transition:gap .4s cubic-bezier(.4,0,.2,1),width .4s cubic-bezier(.4,0,.2,1)}.ai-chat-widget-container.trigger-input-bar.is-collapsed .ai-chat-trigger-input-row{gap:4px}.ai-chat-trigger-input-expand{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:center;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--trigger-bg,rgba(0,0,0,.04));border:1px solid var(--trigger-border,rgba(0,0,0,.12));border-radius:50%;box-shadow:0 2px 12px rgba(0,0,0,.12);color:var(--trigger-text-muted,rgba(0,0,0,.5));cursor:pointer;display:flex;flex-shrink:0;height:48px;justify-content:center;padding:0;-webkit-transform:translateZ(0);transform:translateZ(0);transition:all .2s ease,color .4s ease,background .4s ease,border-color .4s ease;width:48px;will-change:transform}.ai-chat-trigger-input-expand:hover{background:var(--trigger-bg-hover,rgba(0,0,0,.08));color:var(--trigger-text,#1a1a1a);transform:translateY(-2px)}.ai-chat-trigger-input-expand:active{transform:translateY(0)}.ai-chat-trigger-input-expand svg{stroke-width:2.5;height:20px;width:20px}.ai-chat-trigger-input-wrapper{flex:1;min-width:120px;position:relative;transform-origin:right center;transition:flex .4s cubic-bezier(.4,0,.2,1),width .4s cubic-bezier(.4,0,.2,1),opacity .3s cubic-bezier(.4,0,.2,1),transform .4s cubic-bezier(.4,0,.2,1);z-index:1}.ai-chat-widget-container.bottom-left .ai-chat-trigger-input-wrapper,.ai-chat-widget-container.top-left .ai-chat-trigger-input-wrapper{transform-origin:left center}.ai-chat-trigger-input{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--trigger-bg,rgba(0,0,0,.04));border:1px solid var(--trigger-border,rgba(0,0,0,.12));border-radius:var(--radius-input,62px);box-shadow:0 4px 24px rgba(0,0,0,.15);box-sizing:border-box;color:var(--trigger-text,#1a1a1a);font-size:var(--text-md,15px);height:48px;outline:none;padding:6px 52px 6px 16px;-webkit-transform:translateZ(0);transform:translateZ(0);transition:all .2s ease,color .4s ease,background .4s ease,border-color .4s ease;width:100%}.ai-chat-trigger-input::placeholder{color:var(--trigger-text-muted,rgba(0,0,0,.5))}.ai-chat-trigger-input:focus{background:var(--trigger-bg-hover,rgba(0,0,0,.08));border-color:var(--trigger-border-hover,rgba(0,0,0,.2))}.ai-chat-trigger-input-btn{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:center;-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--primary-color,var(--button-color,#07f));border:none;border-radius:50%;box-shadow:0 2px 8px rgba(0,119,255,.3);color:var(--send-button-icon-color,var(--button-icon-color,#fff));cursor:pointer;display:flex;height:38px;justify-content:center;position:absolute;right:4px;top:50%;transform:translateY(-50%);transition:all .2s ease;width:38px;will-change:transform}.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-container.trigger-input-bar .ai-chat-trigger-input-row{width:min(380px,calc(100vw - 40px))}.ai-chat-widget-container.trigger-input-bar.size-medium .ai-chat-trigger-input-row{width:min(440px,calc(100vw - 40px))}.ai-chat-widget-container.trigger-input-bar.size-large .ai-chat-trigger-input-row{width:min(560px,calc(100vw - 40px))}.ai-chat-widget-container.trigger-input-bar .ai-chat-trigger-input-wrapper{flex:1;min-width:160px}.ai-chat-widget-container.trigger-input-bar.container-mode .ai-chat-trigger-input-container{position:absolute;width:min(380px,calc(100% - 40px))}.ai-chat-widget-container.trigger-input-bar.container-mode.size-small .ai-chat-trigger-input-container{width:min(380px,calc(100% - 40px))}.ai-chat-widget-container.trigger-input-bar.container-mode.size-medium .ai-chat-trigger-input-container{width:min(440px,calc(100% - 40px))}.ai-chat-widget-container.trigger-input-bar.container-mode.size-large .ai-chat-trigger-input-container{width:min(560px,calc(100% - 40px))}.ai-chat-widget-container.trigger-input-bar.container-mode.bottom-right .ai-chat-trigger-input-container{bottom:20px;left:auto;right:20px;top:auto}.ai-chat-widget-container.trigger-input-bar.container-mode.bottom-left .ai-chat-trigger-input-container{bottom:20px;left:20px;right:auto;top:auto}.ai-chat-widget-container.trigger-input-bar.container-mode.top-right .ai-chat-trigger-input-container{bottom:auto;left:auto;right:20px;top:20px}.ai-chat-widget-container.trigger-input-bar.container-mode.top-left .ai-chat-trigger-input-container{bottom:auto;left:20px;right:auto;top:20px}.ai-chat-widget-container.trigger-input-bar.container-mode .ai-chat-trigger-input-row{width:100%}.ai-chat-widget-container.trigger-input-bar.container-mode .ai-chat-trigger-input-wrapper{flex:1;min-width:120px}.ai-chat-widget-container.trigger-input-bar.is-collapsed .ai-chat-trigger-input-wrapper{opacity:0;overflow:hidden;pointer-events:none;transform:scaleX(0);width:0}.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}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-small{max-width:calc(100vw - 40px);min-width:320px;width:380px}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-medium{max-width:calc(100vw - 40px);min-width:380px;width:440px}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-large{max-width:calc(100vw - 40px);min-width:440px;width:560px}.ai-chat-widget-container.trigger-input-bar.container-mode .ai-chat-window{max-width:calc(100% - 40px);position:absolute}.ai-chat-widget-container.trigger-input-bar.container-mode.bottom-right .ai-chat-window{bottom:20px;left:auto;right:20px;top:auto}.ai-chat-widget-container.trigger-input-bar.container-mode.bottom-left .ai-chat-window{bottom:20px;left:20px;right:auto;top:auto}.ai-chat-widget-container.trigger-input-bar.container-mode.top-right .ai-chat-window{bottom:auto;left:auto;right:20px;top:20px}.ai-chat-widget-container.trigger-input-bar.container-mode.top-left .ai-chat-window{bottom:auto;left:20px;right:auto;top:20px}.ai-chat-widget-container.trigger-input-bar.container-mode.size-small .ai-chat-window{max-width:calc(100% - 40px);width:380px}.ai-chat-widget-container.trigger-input-bar.container-mode.size-medium .ai-chat-window{max-width:calc(100% - 40px);width:440px}.ai-chat-widget-container.trigger-input-bar.container-mode.size-large .ai-chat-window{max-width:calc(100% - 40px);width:560px}.ai-chat-widget-container.trigger-input-bar.mobile-mode .ai-chat-trigger-input-container{width:calc(100% - 40px)}.ai-chat-widget-container.trigger-input-bar.mobile-mode .ai-chat-trigger-input-row{width:100%}.ai-chat-widget-container.trigger-input-bar.mobile-mode .ai-chat-trigger-input-wrapper{flex:1;min-width:120px}.ai-chat-widget-container.trigger-input-bar.mobile-mode.is-collapsed .ai-chat-trigger-input-container{width:auto}.ai-chat-widget-container.trigger-input-bar.mobile-mode.is-collapsed .ai-chat-trigger-input-row{gap:8px;justify-content:flex-end}.ai-chat-trigger-collapse-toggle{align-items:center;background:transparent;border:none;border-radius:50%;color:var(--trigger-text-muted,rgba(0,0,0,.5));cursor:pointer;display:flex;flex-shrink:0;height:24px;justify-content:center;margin-right:-4px;order:-1;padding:0;transition:all .2s ease;width:24px}.ai-chat-trigger-collapse-toggle:hover{color:var(--trigger-text,#1a1a1a)}.ai-chat-trigger-collapse-toggle svg{stroke-width:2.5;height:20px;transition:transform .4s cubic-bezier(.4,0,.2,1);width:20px}.ai-chat-widget-container.trigger-input-bar.bottom-left .ai-chat-trigger-collapse-toggle svg,.ai-chat-widget-container.trigger-input-bar.top-left .ai-chat-trigger-collapse-toggle svg{transform:rotate(180deg)}.ai-chat-trigger-input-expand{margin-left:-4px;order:1;transition:transform .2s ease,opacity .3s ease}.ai-chat-widget-container.container-mode .ai-chat-trigger-input-expand{margin-left:0}.ai-chat-trigger-input-expand svg{transition:transform .4s cubic-bezier(.4,0,.2,1)}.ai-chat-widget-container.trigger-input-bar .ai-chat-trigger-input-expand svg{transform:rotate(0deg)}.ai-chat-widget-container.bottom-left .ai-chat-trigger-collapse-toggle,.ai-chat-widget-container.top-left .ai-chat-trigger-collapse-toggle{margin-left:-4px;margin-right:0;order:1}.ai-chat-widget-container.bottom-left .ai-chat-trigger-input-expand,.ai-chat-widget-container.top-left .ai-chat-trigger-input-expand{margin-left:0;margin-right:-4px;order:-1}.ai-chat-widget-container.trigger-input-bar .ai-chat-trigger-input-row .ai-chat-button{order:1}.ai-chat-widget-container.trigger-input-bar.bottom-left .ai-chat-trigger-input-row .ai-chat-button,.ai-chat-widget-container.trigger-input-bar.top-left .ai-chat-trigger-input-row .ai-chat-button{order:-1}.ai-chat-widget-container.trigger-input-bar.is-collapsed.bottom-right .ai-chat-button,.ai-chat-widget-container.trigger-input-bar.is-collapsed.top-right .ai-chat-button{margin-right:16px}.ai-chat-widget-container.trigger-input-bar.is-collapsed.bottom-left .ai-chat-button,.ai-chat-widget-container.trigger-input-bar.is-collapsed.top-left .ai-chat-button{margin-left:16px}.ai-chat-widget-container.trigger-input-bar.is-collapsed .ai-chat-trigger-input-row{flex-direction:row;justify-content:flex-end}.ai-chat-widget-container.trigger-input-bar.is-collapsed.bottom-left .ai-chat-trigger-input-row,.ai-chat-widget-container.trigger-input-bar.is-collapsed.top-left .ai-chat-trigger-input-row{justify-content:flex-start}.ai-chat-widget-container.trigger-input-bar .ai-chat-button{display:flex;opacity:1;transform:scale(1);transition:transform .4s cubic-bezier(.4,0,.2,1),opacity .3s cubic-bezier(.4,0,.2,1),width .4s cubic-bezier(.4,0,.2,1),height .4s cubic-bezier(.4,0,.2,1)}.ai-chat-widget-container.trigger-input-bar:not(.is-collapsed) .ai-chat-button{border:none;height:0;margin:0;min-width:0;opacity:0;overflow:hidden;padding:0;pointer-events:none;transform:scale(0);width:0}.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-widget.light .ai-chat-trigger-pill:not(.is-open){backdrop-filter:none;-webkit-backdrop-filter:none;background:#fff;border:1px solid rgba(0,0,0,.15);box-shadow:0 2px 8px rgba(0,0,0,.08);color:#18181b}.ai-chat-widget.light .ai-chat-trigger-pill:not(.is-open):hover{background:#fafafa;border-color:rgba(0,0,0,.2)}.ai-chat-widget.light .ai-chat-trigger-input-expand{backdrop-filter:none;-webkit-backdrop-filter:none;background:#fff;border:1px solid rgba(0,0,0,.15);box-shadow:0 2px 8px rgba(0,0,0,.08);color:#52525b}.ai-chat-widget.light .ai-chat-trigger-input-expand:hover{background:#fafafa;color:#18181b}.ai-chat-widget.light .ai-chat-trigger-input{backdrop-filter:none;-webkit-backdrop-filter:none;background:#fff;border:1px solid rgba(0,0,0,.15);box-shadow:0 2px 8px rgba(0,0,0,.08);color:#18181b}.ai-chat-widget.light .ai-chat-trigger-input::placeholder{color:#71717a}.ai-chat-widget.light .ai-chat-trigger-input:focus{background:#fff;border-color:rgba(0,0,0,.25)}.ai-chat-widget.light .ai-chat-trigger-collapse-toggle{color:#71717a}.ai-chat-widget.light .ai-chat-trigger-collapse-toggle:hover{color:#18181b}.ai-chat-widget.dark .ai-chat-trigger-pill:not(.is-open){backdrop-filter:none;-webkit-backdrop-filter:none;background:#27272a;border:1px solid hsla(0,0%,100%,.15);box-shadow:0 2px 8px rgba(0,0,0,.3);color:#fafafa}.ai-chat-widget.dark .ai-chat-trigger-pill:not(.is-open):hover{background:#3f3f46;border-color:hsla(0,0%,100%,.25)}.ai-chat-widget.dark .ai-chat-trigger-input-expand{backdrop-filter:none;-webkit-backdrop-filter:none;background:#27272a;border:1px solid hsla(0,0%,100%,.15);box-shadow:0 2px 8px rgba(0,0,0,.3);color:#a1a1aa}.ai-chat-widget.dark .ai-chat-trigger-input-expand:hover{background:#3f3f46;color:#fafafa}.ai-chat-widget.dark .ai-chat-trigger-input{backdrop-filter:none;-webkit-backdrop-filter:none;background:#27272a;border:1px solid hsla(0,0%,100%,.15);box-shadow:0 2px 8px rgba(0,0,0,.3);color:#fafafa}.ai-chat-widget.dark .ai-chat-trigger-input::placeholder{color:#71717a}.ai-chat-widget.dark .ai-chat-trigger-input:focus{background:#27272a;border-color:hsla(0,0%,100%,.25)}.ai-chat-widget.dark .ai-chat-trigger-collapse-toggle{color:#71717a}.ai-chat-widget.dark .ai-chat-trigger-collapse-toggle:hover{color:#fafafa}.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{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:flex-end;-webkit-backface-visibility:hidden;backface-visibility:hidden;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;-webkit-transform:translateZ(0);transform:translateZ(0);transition:all var(--duration-fast,.15s) ease;will-change:transform;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:16px!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{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:center;align-self:center;-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));border:none;border-radius:50%;color:var(--send-button-icon-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;-webkit-transform:translateZ(0);transform:translateZ(0);transition:all var(--duration-fast,.15s) ease;width:40px;will-change:transform,opacity}.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(--send-button-icon-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(--send-button-icon-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(--send-button-icon-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;min-height:0;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;animation:ai-chat-user-message-sent .35s var(--spring-bounce)}.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);max-width:100%;overflow-wrap:break-word;padding:8px 14px;word-break:break-word}.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-meta{align-items:center;display:flex;gap:var(--space-sm,8px);margin-top:var(--space-xs,4px);padding:0 var(--space-xs,4px)}.ai-chat-message.user .ai-chat-message-meta{justify-content:flex-end}.ai-chat-message.assistant .ai-chat-message-meta{justify-content:flex-start}.ai-chat-message-timestamp{color:var(--text-muted,#71717a);font-size:var(--text-xs,12px)}.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-message.assistant.streaming .ai-chat-message-content>ol:last-child>li:last-child,.ai-chat-message.assistant.streaming .ai-chat-message-content>p:last-child,.ai-chat-message.assistant.streaming .ai-chat-message-content>ul:last-child>li:last-child{animation:ai-chat-text-fade-in .3s ease-out}@keyframes ai-chat-text-fade-in{0%{opacity:0}to{opacity:1}}.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-widget-container.container-mode.trigger-input-bar .ai-chat-suggested-questions{box-sizing:border-box;margin:0;padding:16px 0 0;width:100%}.ai-chat-widget-container.container-mode.trigger-input-bar .ai-chat-suggested-questions-list{box-sizing:border-box;display:flex;flex-wrap:wrap;gap:6px}.ai-chat-widget-container.container-mode.trigger-input-bar.bottom-right .ai-chat-suggested-questions-list,.ai-chat-widget-container.container-mode.trigger-input-bar.top-right .ai-chat-suggested-questions-list{justify-content:flex-end;margin-left:auto;margin-right:0;padding-right:0}.ai-chat-widget-container.container-mode.trigger-input-bar.bottom-left .ai-chat-suggested-questions-list,.ai-chat-widget-container.container-mode.trigger-input-bar.top-left .ai-chat-suggested-questions-list{justify-content:flex-start;margin-left:0;margin-right:auto;padding-left:0}.ai-chat-widget-container.container-mode.trigger-input-bar.size-small .ai-chat-suggested-questions-list{max-width:calc(100% - 132px);width:348px}.ai-chat-widget-container.container-mode.trigger-input-bar.size-medium .ai-chat-suggested-questions-list{max-width:calc(100% - 132px);width:408px}.ai-chat-widget-container.container-mode.trigger-input-bar.size-large .ai-chat-suggested-questions-list{max-width:calc(100% - 132px);width:528px}.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;animation:followUpFadeIn .25s ease-out forwards;background:var(--primary-color,var(--button-color,#07f));border:none;border-radius:var(--radius-preset-badge,18px);color:var(--button-icon-color,#fff);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;white-space:nowrap}@keyframes followUpFadeIn{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.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}@media (max-width:480px){.ai-chat-action-card{padding:12px}.ai-chat-action-header{font-size:var(--text-sm,14px);margin-bottom:var(--space-sm,12px)}.ai-chat-action-button{font-size:13px;padding:10px 14px}.ai-chat-action-link-button{font-size:13px;padding:10px}}.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-link-preview-grid{display:grid;gap:12px}.ai-chat-link-preview-grid--single{grid-template-columns:1fr}.ai-chat-link-preview-grid--double{grid-template-columns:repeat(2,1fr)}.ai-chat-link-preview-grid--triple{grid-template-columns:repeat(3,1fr)}@media (max-width:768px){.ai-chat-link-preview-grid--triple{grid-template-columns:repeat(2,1fr)}}@media (max-width:480px){.ai-chat-link-preview-grid--double,.ai-chat-link-preview-grid--triple{grid-template-columns:1fr}}.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}@media (max-width:480px){.ai-chat-video-player__play-btn{height:56px;width:56px}.ai-chat-video-player__provider-badge{font-size:10px;padding:3px 6px}}.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;flex-wrap:wrap;gap:8px;justify-content:flex-start;width:100%}@media (max-width:380px){.ai-chat-location-card__actions{flex-direction:column}.ai-chat-location-card__button,.ai-chat-location-card__link{flex:none;justify-content:center;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}@media (max-width:480px){.ai-chat-location-card__content{padding:10px}.ai-chat-location-card__name{font-size:14px}.ai-chat-location-card__address,.ai-chat-location-card__description,.ai-chat-location-card__hours{font-size:12px}.ai-chat-location-card__button,.ai-chat-location-card__link{font-size:12px;padding:8px 12px}.ai-chat-location-card-list__carousel>.ai-chat-location-card{flex:0 0 240px}}.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;flex-wrap:wrap;gap:8px;padding:0 12px 12px}@media (max-width:380px){.ai-chat-contact-card__actions{flex-direction:column}.ai-chat-contact-card__button{flex:none;width:100%}}.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}@media (max-width:480px){.ai-chat-contact-card__name{font-size:16px}.ai-chat-contact-card__detail,.ai-chat-contact-card__role{font-size:13px}.ai-chat-contact-card__button{font-size:13px;padding:10px 16px}.ai-chat-contact-card--horizontal .ai-chat-contact-card__info,.ai-chat-contact-card--vertical .ai-chat-contact-card__info{padding:12px}}.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--completed,.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--completed .ai-chat-form-card__header{margin-bottom:0}.ai-chat-form-card--completed .ai-chat-form-card__icon svg{color:#10b981}.ai-chat-form-card__header{align-items:center;display:flex;gap:8px;margin-bottom:12px}.ai-chat-form-card__icon{align-items:center;display:inline-flex;justify-content:center}.ai-chat-form-card__icon svg{color:var(--text-primary,#3e3e3e);height:18px;width:18px}.ai-chat-widget.dark .ai-chat-form-card__icon svg,.chakra-ui-dark .ai-chat-form-card__icon svg,.dark .ai-chat-form-card__icon svg,[data-theme=dark] .ai-chat-form-card__icon svg{color:#fff}.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 .ai-chat-form-card__icon svg{color:#dc2626}.ai-chat-form-card--submitted .ai-chat-form-card__icon svg{color:#16a34a}.ai-chat-widget.dark .ai-chat-form-card--error .ai-chat-form-card__icon svg,.chakra-ui-dark .ai-chat-form-card--error .ai-chat-form-card__icon svg,.dark .ai-chat-form-card--error .ai-chat-form-card__icon svg,[data-theme=dark] .ai-chat-form-card--error .ai-chat-form-card__icon svg{color:#fca5a5}.ai-chat-widget.dark .ai-chat-form-card--submitted .ai-chat-form-card__icon svg,.chakra-ui-dark .ai-chat-form-card--submitted .ai-chat-form-card__icon svg,.dark .ai-chat-form-card--submitted .ai-chat-form-card__icon svg,[data-theme=dark] .ai-chat-form-card--submitted .ai-chat-form-card__icon svg{color:#4ade80}.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;justify-content:flex-start}@media (max-width:380px){.ai-chat-form-card__rating{gap:6px}.ai-chat-form-card__rating-btn{font-size:13px;height:36px;width:36px}}.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;flex-wrap:wrap;gap:8px;margin-top:16px;padding-top:16px}@media (max-width:380px){.ai-chat-form-card__actions{align-items:stretch;flex-direction:column}.ai-chat-form-card__actions-spacer{display:none}.ai-chat-form-card__btn{width:100%}}.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}@media (max-width:480px){.ai-chat-form-card{padding:12px}.ai-chat-form-card__title{font-size:14px}.ai-chat-form-card__context,.ai-chat-form-card__description{font-size:12px}.ai-chat-form-card__question-text{font-size:13px}.ai-chat-form-card__textarea{font-size:13px;min-height:70px}.ai-chat-form-card__option{padding:8px 10px}.ai-chat-form-card__option-text{font-size:13px}}.ai-chat-booking-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f5f5f5);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%,.06)}.ai-chat-booking-card__header{align-items:center;display:flex;gap:8px;margin-bottom:12px}.ai-chat-booking-card__back-btn{align-items:center;background:rgba(0,0,0,.05);border:none;border-radius:6px;color:var(--text-secondary,#6b7280);cursor:pointer;display:flex;font-family:inherit;font-size:13px;font-weight:500;justify-content:center;padding:6px;transition:background .15s ease,color .15s ease}.ai-chat-booking-card__back-btn svg{height:16px;width:16px}.ai-chat-booking-card__back-btn:hover{background:rgba(0,0,0,.1);color:var(--text-primary,#3e3e3e)}.ai-chat-widget.dark .ai-chat-booking-card__back-btn,.chakra-ui-dark .ai-chat-booking-card__back-btn,.dark .ai-chat-booking-card__back-btn,[data-theme=dark] .ai-chat-booking-card__back-btn{background:hsla(0,0%,100%,.08);color:var(--text-secondary,#a1a1aa)}.ai-chat-widget.dark .ai-chat-booking-card__back-btn:hover,.chakra-ui-dark .ai-chat-booking-card__back-btn:hover,.dark .ai-chat-booking-card__back-btn:hover,[data-theme=dark] .ai-chat-booking-card__back-btn:hover{background:hsla(0,0%,100%,.15);color:#fff}.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__status-icon{align-items:center;border-radius:50%;display:flex;flex-shrink:0;height:20px;justify-content:center;position:relative;width:20px}.ai-chat-booking-card__status-icon--pending{background:#6b7280}.ai-chat-booking-card__status-icon--pending:before{background:#fff;border-radius:1px;content:\"\";height:6px;position:absolute;top:5px;width:2px}.ai-chat-booking-card__status-icon--pending:after{background:#fff;border-radius:1px;content:\"\";height:2px;left:9px;position:absolute;top:9px;width:4px}.ai-chat-booking-card__status-icon--cancelled{background:#6b7280}.ai-chat-booking-card__status-icon--cancelled:after,.ai-chat-booking-card__status-icon--cancelled:before{background:#fff;border-radius:1px;content:\"\";height:2px;position:absolute;width:10px}.ai-chat-booking-card__status-icon--cancelled:before{transform:rotate(45deg)}.ai-chat-booking-card__status-icon--cancelled:after{transform:rotate(-45deg)}.ai-chat-booking-card__status-icon--error{background:#6b7280}.ai-chat-booking-card__status-icon--error:after{color:#fff;content:\"!\";font-size:12px;font-weight:700}.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__warning{background:rgba(0,0,0,.04);border-radius:8px;color:var(--text-secondary,#6b7280);font-size:13px;margin:0;padding:10px 12px}.ai-chat-widget.dark .ai-chat-booking-card__warning,.chakra-ui-dark .ai-chat-booking-card__warning,.dark .ai-chat-booking-card__warning,[data-theme=dark] .ai-chat-booking-card__warning{background:hsla(0,0%,100%,.06);color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__input{background:rgba(0,0,0,.05);border:none;border-radius:8px;box-sizing:border-box;color:var(--text-primary,#3e3e3e);font-family:inherit;font-size:14px;outline:none;padding:10px 12px;transition:background .15s ease,box-shadow .15s ease;width:100%}.ai-chat-booking-card__input:focus{background:rgba(0,0,0,.08);box-shadow:0 0 0 2px var(--action-accent,var(--primary-color,#3b82f6))}.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:hsla(0,0%,100%,.08);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{background:hsla(0,0%,100%,.12)}.ai-chat-booking-card__field{display:flex;flex-direction:column;gap:8px}.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 .15s 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){filter:brightness(1.1);transform:translateY(-1px)}.ai-chat-booking-card__btn--secondary{background:rgba(0,0,0,.06);color:var(--text-primary,#3e3e3e)}.ai-chat-booking-card__btn--secondary:hover:not(:disabled){background:rgba(0,0,0,.1)}.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%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-booking-card__btn--secondary:hover:not(:disabled),.chakra-ui-dark .ai-chat-booking-card__btn--secondary:hover:not(:disabled),.dark .ai-chat-booking-card__btn--secondary:hover:not(:disabled),[data-theme=dark] .ai-chat-booking-card__btn--secondary:hover:not(:disabled){background:hsla(0,0%,100%,.15)}.ai-chat-booking-card__btn--danger{background:rgba(220,38,38,.1);color:#dc2626}.ai-chat-booking-card__btn--danger:hover:not(:disabled){background:rgba(220,38,38,.18)}.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);color:#fca5a5}.ai-chat-booking-card__btn--inline{font-size:12px;margin-top:8px;padding:6px 12px;width:auto}.ai-chat-booking-card__options{display:flex;flex-direction:column;gap:8px}.ai-chat-booking-card__option-btn{align-items:center;background:rgba(0,0,0,.04);border:none;border-radius:10px;box-sizing:border-box;cursor:pointer;display:flex;font-family:inherit;gap:12px;padding:14px 16px;text-align:left;transition:background .15s ease;width:100%}.ai-chat-booking-card__option-btn:hover:not(:disabled){background:rgba(0,0,0,.08)}.ai-chat-booking-card__option-btn:disabled{cursor:not-allowed;opacity:.5}.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:hsla(0,0%,100%,.06)}.ai-chat-widget.dark .ai-chat-booking-card__option-btn:hover:not(:disabled),.chakra-ui-dark .ai-chat-booking-card__option-btn:hover:not(:disabled),.dark .ai-chat-booking-card__option-btn:hover:not(:disabled),[data-theme=dark] .ai-chat-booking-card__option-btn:hover:not(:disabled){background:hsla(0,0%,100%,.1)}.ai-chat-booking-card__option-icon{align-items:center;background:var(--action-accent,var(--primary-color,#3b82f6));border-radius:8px;color:#fff;display:flex;flex-shrink:0;height:32px;justify-content:center;width:32px}.ai-chat-booking-card__option-icon svg{height:16px;width:16px}.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__list{display:flex;flex-direction:column;gap:6px}.ai-chat-booking-card__list-item{align-items:center;background:rgba(0,0,0,.04);border:none;border-radius:10px;box-sizing:border-box;cursor:pointer;display:flex;font-family:inherit;justify-content:space-between;padding:12px 14px;text-align:left;transition:background .15s ease;width:100%}.ai-chat-booking-card__list-item:hover{background:rgba(0,0,0,.08)}.ai-chat-widget.dark .ai-chat-booking-card__list-item,.chakra-ui-dark .ai-chat-booking-card__list-item,.dark .ai-chat-booking-card__list-item,[data-theme=dark] .ai-chat-booking-card__list-item{background:hsla(0,0%,100%,.06)}.ai-chat-widget.dark .ai-chat-booking-card__list-item:hover,.chakra-ui-dark .ai-chat-booking-card__list-item:hover,.dark .ai-chat-booking-card__list-item:hover,[data-theme=dark] .ai-chat-booking-card__list-item:hover{background:hsla(0,0%,100%,.1)}.ai-chat-booking-card__list-item-content{display:flex;flex-direction:column;gap:2px}.ai-chat-booking-card__list-item-name{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500}.ai-chat-widget.dark .ai-chat-booking-card__list-item-name,.chakra-ui-dark .ai-chat-booking-card__list-item-name,.dark .ai-chat-booking-card__list-item-name,[data-theme=dark] .ai-chat-booking-card__list-item-name{color:#fff}.ai-chat-booking-card__list-item-role{color:var(--text-muted,#71717a);font-size:12px}.ai-chat-booking-card__list-item-arrow{flex-shrink:0;height:16px;position:relative;width:16px}.ai-chat-booking-card__list-item-arrow:before{border-width:medium;border-bottom:2px solid var(--text-muted,#9ca3af);border-left:0 solid var(--text-muted,#9ca3af);border-right:2px solid var(--text-muted,#9ca3af);border-top:0 solid var(--text-muted,#9ca3af);content:\"\";height:6px;left:50%;position:absolute;top:50%;transform:translate(-70%,-50%) rotate(-45deg);width:6px}.ai-chat-booking-card__slots-container{display:flex;flex-direction:column;gap:12px;max-height:280px;overflow-y:auto}.ai-chat-booking-card__date-group{display:flex;flex-direction:column;gap:8px}.ai-chat-booking-card__date-header{color:var(--text-muted,#71717a);font-size:12px;font-weight:600;letter-spacing:.5px;margin:0;padding-left:2px;text-transform:uppercase}.ai-chat-booking-card__slots{display:flex;flex-wrap:wrap;gap:6px}.ai-chat-booking-card__slot{background:rgba(0,0,0,.05);border:none;border-radius:20px;color:var(--text-primary,#3e3e3e);cursor:pointer;flex:0 0 auto;font-family:inherit;font-size:13px;font-weight:500;padding:8px 14px;transition:background .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-booking-card__slot:hover:not(:disabled){background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-booking-card__slot:active:not(:disabled){transform:scale(.97)}.ai-chat-booking-card__slot:disabled{cursor:not-allowed;opacity:.5}.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:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-booking-card__slot:hover:not(:disabled),.chakra-ui-dark .ai-chat-booking-card__slot:hover:not(:disabled),.dark .ai-chat-booking-card__slot:hover:not(:disabled),[data-theme=dark] .ai-chat-booking-card__slot:hover:not(:disabled){background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-booking-card__subject-options{display:flex;flex-direction:column;gap:6px}.ai-chat-booking-card__subject-option{background:rgba(0,0,0,.04);border:none;border-radius:10px;color:var(--text-primary,#3e3e3e);cursor:pointer;font-family:inherit;font-size:14px;font-weight:500;padding:12px 14px;text-align:left;transition:background .15s ease,filter .15s ease}.ai-chat-booking-card__subject-option:hover:not(.ai-chat-booking-card__subject-option--selected){background:rgba(0,0,0,.08)}.ai-chat-booking-card__subject-option--selected,.ai-chat-booking-card__subject-option--selected:hover{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-booking-card__subject-option--selected:hover{filter:brightness(1.1)}.ai-chat-widget.dark .ai-chat-booking-card__subject-option,.chakra-ui-dark .ai-chat-booking-card__subject-option,.dark .ai-chat-booking-card__subject-option,[data-theme=dark] .ai-chat-booking-card__subject-option{background:hsla(0,0%,100%,.06);color:#fff}.ai-chat-widget.dark .ai-chat-booking-card__subject-option:hover:not(.ai-chat-booking-card__subject-option--selected),.chakra-ui-dark .ai-chat-booking-card__subject-option:hover:not(.ai-chat-booking-card__subject-option--selected),.dark .ai-chat-booking-card__subject-option:hover:not(.ai-chat-booking-card__subject-option--selected),[data-theme=dark] .ai-chat-booking-card__subject-option:hover:not(.ai-chat-booking-card__subject-option--selected){background:hsla(0,0%,100%,.1)}.ai-chat-widget.dark .ai-chat-booking-card__subject-option--selected,.ai-chat-widget.dark .ai-chat-booking-card__subject-option--selected:hover,.chakra-ui-dark .ai-chat-booking-card__subject-option--selected,.chakra-ui-dark .ai-chat-booking-card__subject-option--selected:hover,.dark .ai-chat-booking-card__subject-option--selected,.dark .ai-chat-booking-card__subject-option--selected:hover,[data-theme=dark] .ai-chat-booking-card__subject-option--selected,[data-theme=dark] .ai-chat-booking-card__subject-option--selected:hover{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-booking-card__appointments{display:flex;flex-direction:column;gap:8px}.ai-chat-booking-card__appointment{background:rgba(0,0,0,.04);border-radius:10px;padding:12px 14px}.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:hsla(0,0%,100%,.06)}.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:10px;font-size:11px;font-weight:600;padding:3px 8px;text-transform:uppercase}.ai-chat-booking-card__appointment-status--confirmed{background:rgba(59,130,246,.15);color:#3b82f6}.ai-chat-booking-card__appointment-status--pending{background:hsla(220,9%,46%,.15);color:#6b7280}.ai-chat-widget.dark .ai-chat-booking-card__appointment-status--confirmed,.chakra-ui-dark .ai-chat-booking-card__appointment-status--confirmed,.dark .ai-chat-booking-card__appointment-status--confirmed,[data-theme=dark] .ai-chat-booking-card__appointment-status--confirmed{background:rgba(59,130,246,.25);color:#60a5fa}.ai-chat-widget.dark .ai-chat-booking-card__appointment-status--pending,.chakra-ui-dark .ai-chat-booking-card__appointment-status--pending,.dark .ai-chat-booking-card__appointment-status--pending,[data-theme=dark] .ai-chat-booking-card__appointment-status--pending{background:hsla(220,9%,46%,.25);color:#9ca3af}.ai-chat-booking-card__appointment-status--cancelled{background:hsla(220,9%,46%,.15);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__appointment-info{display:flex;flex-direction:column;gap:4px;margin-bottom:10px}.ai-chat-booking-card__appointment-actions{display:flex;flex-wrap:wrap;gap:8px}@media (max-width:380px){.ai-chat-booking-card__appointment-actions{flex-direction:column}.ai-chat-booking-card__appointment-cancel,.ai-chat-booking-card__appointment-link{justify-content:center;text-align:center;width:100%}}.ai-chat-booking-card__appointment-link{background:var(--action-accent,var(--primary-color,#3b82f6));border-radius:6px;color:#fff;display:inline-block;font-size:12px;font-weight:500;padding:6px 12px;text-decoration:none;transition:filter .15s ease}.ai-chat-booking-card__appointment-link:hover{filter:brightness(1.1);text-decoration:none}.ai-chat-booking-card__appointment-cancel{background:rgba(220,38,38,.1);border:none;border-radius:6px;color:#dc2626;cursor:pointer;font-family:inherit;font-size:12px;font-weight:500;padding:6px 12px;transition:background .15s ease}.ai-chat-booking-card__appointment-cancel:hover:not(:disabled){background:rgba(220,38,38,.18)}.ai-chat-booking-card__appointment-cancel:disabled{cursor:not-allowed;opacity:.5}.ai-chat-widget.dark .ai-chat-booking-card__appointment-cancel,.chakra-ui-dark .ai-chat-booking-card__appointment-cancel,.dark .ai-chat-booking-card__appointment-cancel,[data-theme=dark] .ai-chat-booking-card__appointment-cancel{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-booking-card__summary{background:rgba(0,0,0,.04);border-radius:10px;padding:12px 14px}.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:hsla(0,0%,100%,.06)}.ai-chat-booking-card__summary-row{align-items:center;display:flex;gap:8px;justify-content:space-between;padding:6px 0}@media (max-width:380px){.ai-chat-booking-card__summary-row{align-items:flex-start;flex-direction:column;gap:2px}.ai-chat-booking-card__summary-value{text-align:left}}.ai-chat-booking-card__summary-row:not(:last-child){border-bottom:1px solid 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__success-icon{align-items:center;background:var(--action-accent,var(--primary-color,#3b82f6));border-radius:50%;display:flex;height:40px;justify-content:center;margin:0 auto 12px;position:relative;width:40px}.ai-chat-booking-card__success-icon:after{border:solid #fff;border-width:0 3px 3px 0;content:\"\";height:16px;margin-bottom:4px;transform:rotate(45deg);width:10px}.ai-chat-booking-card__success-message{color:var(--text-secondary,#6b7280);font-size:14px;margin:0 0 12px;text-align:center}.ai-chat-widget.dark .ai-chat-booking-card__success-message,.chakra-ui-dark .ai-chat-booking-card__success-message,.dark .ai-chat-booking-card__success-message,[data-theme=dark] .ai-chat-booking-card__success-message{color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__link{display:inline-block;font-size:13px;font-weight:500;margin-top:8px;text-decoration:none;transition:opacity .15s ease}.ai-chat-booking-card__link:hover{opacity:.8;text-decoration:underline}.ai-chat-booking-card--success{background:rgba(59,130,246,.08)}.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(59,130,246,.12)}.ai-chat-booking-card--pending{background:hsla(220,9%,46%,.08)}.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:hsla(220,9%,46%,.12)}.ai-chat-booking-card--cancelled{background:hsla(220,9%,46%,.08)}.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%,.12)}.ai-chat-booking-card--error{background:hsla(220,9%,46%,.08)}.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:hsla(220,9%,46%,.12)}.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{background:rgba(220,38,38,.08);border-radius:8px;color:#dc2626;font-size:13px;margin:0;padding:10px 12px}.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,.15);color:#fca5a5}.ai-chat-booking-card--closable{position:relative}.ai-chat-booking-card--closable .ai-chat-booking-card__header{padding-right:40px}.ai-chat-pin-input-group{display:flex;flex-wrap:wrap;gap:8px;justify-content:center}@media (max-width:320px){.ai-chat-pin-input-group{gap:6px}}.ai-chat-pin-input{background:rgba(0,0,0,.05);border:none;border-radius:8px;box-sizing:border-box;color:var(--text-primary,#3e3e3e);font-family:inherit;font-size:20px;font-weight:600;height:48px;outline:none;padding:0;text-align:center;transition:background .15s ease,box-shadow .15s ease;width:42px}@media (max-width:320px){.ai-chat-pin-input{font-size:18px;height:42px;width:36px}}.ai-chat-pin-input:focus{background:rgba(0,0,0,.08);box-shadow:0 0 0 2px var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-pin-input::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-pin-input:disabled{cursor:not-allowed;opacity:.5}.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:hsla(0,0%,100%,.08);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{background:hsla(0,0%,100%,.12)}@media (max-width:480px){.ai-chat-booking-card{padding:12px}.ai-chat-booking-card__title{font-size:14px}.ai-chat-booking-card__option-btn{padding:12px 14px}.ai-chat-booking-card__option-icon{height:28px;width:28px}.ai-chat-booking-card__option-icon svg{height:14px;width:14px}.ai-chat-booking-card__option-text{font-size:13px}.ai-chat-booking-card__slots-container{max-height:240px}.ai-chat-booking-card__slot{font-size:12px;padding:6px 12px}}.ai-chat-structured-image{--action-accent:var(--primary-color,#3b82f6);display:flex;flex-direction:column;gap:8px;width:100%}.ai-chat-structured-image__context{color:var(--text-primary,#3e3e3e);font-size:13px;line-height:1.4;margin:0 0 4px}.ai-chat-widget.dark .ai-chat-structured-image__context,.chakra-ui-dark .ai-chat-structured-image__context,.dark .ai-chat-structured-image__context,[data-theme=dark] .ai-chat-structured-image__context{color:var(--text-primary,#fff)}.ai-chat-structured-image__error{background:rgba(239,68,68,.1);border-radius:var(--radius-md,8px);color:#dc2626;font-size:13px;padding:12px 16px;text-align:center}.ai-chat-widget.dark .ai-chat-structured-image__error,.chakra-ui-dark .ai-chat-structured-image__error,.dark .ai-chat-structured-image__error,[data-theme=dark] .ai-chat-structured-image__error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-structured-image__cards{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}.ai-chat-structured-image__cards:has(.ai-chat-project-card:only-child){grid-template-columns:1fr}@supports not selector(:has(*)){.ai-chat-structured-image__cards{grid-template-columns:repeat(var(--card-columns,2),1fr)}}@media (max-width:480px){.ai-chat-structured-image__cards{grid-template-columns:1fr}}.ai-chat-media-display{--action-accent:var(--primary-color,#3b82f6);display:flex;flex-direction:column;gap:8px;margin-top:4px;padding:0!important}.ai-chat-media-display__context{color:var(--text-muted,#71717a);font-size:13px;margin:0 0 4px;padding:0 4px}.ai-chat-media-display__error{background:rgba(239,68,68,.1);border-radius:var(--radius-lg,12px);color:#dc2626;font-size:13px;padding:16px;text-align:center}.ai-chat-widget.dark .ai-chat-media-display__error,.chakra-ui-dark .ai-chat-media-display__error,.dark .ai-chat-media-display__error,[data-theme=dark] .ai-chat-media-display__error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-media-display__cards{display:grid;gap:12px;grid-template-columns:repeat(var(--card-columns,1),1fr)}.ai-chat-image-card{--action-accent:var(--primary-color,#3b82f6);background:transparent;display:flex;flex-direction:column}.ai-chat-image-card,.ai-chat-image-card__media{border-radius:var(--radius-lg,12px);overflow:hidden}.ai-chat-image-card__media{position:relative;width:100%}.ai-chat-image-card__image{border-radius:var(--radius-lg,12px);display:block;height:auto;max-height:300px;object-fit:cover;width:100%}.ai-chat-image-card__image-error{align-items:center;background:var(--bg-muted,#e5e7eb);border-radius:var(--radius-lg,12px);color:var(--text-muted,#71717a);display:flex;font-size:13px;height:150px;justify-content:center;width:100%}.ai-chat-image-card__content{padding:10px 0 0}.ai-chat-image-card__title{color:var(--text-primary,#1a1a1a);font-size:14px;font-weight:600;line-height:1.3;margin:0 0 4px}.ai-chat-widget.dark .ai-chat-image-card__title,.dark .ai-chat-image-card__title,[data-theme=dark] .ai-chat-image-card__title{color:#fff}.ai-chat-image-card__description{color:var(--text-muted,#6b7280);font-size:13px;line-height:1.4;margin:0 0 8px}.ai-chat-image-card__link-btn{align-items:center;background:transparent;border:none;color:var(--action-accent);cursor:pointer;display:inline-flex;font-size:13px;font-weight:500;gap:4px;padding:0;transition:opacity .2s}.ai-chat-image-card__link-btn:hover{opacity:.8}.ai-chat-media-card{--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);display:flex;flex-direction:column;overflow:hidden}.ai-chat-widget.dark .ai-chat-media-card,.chakra-ui-dark .ai-chat-media-card,.dark .ai-chat-media-card,[data-theme=dark] .ai-chat-media-card{background:var(--bg-secondary,#3a3a3a);border-color:hsla(0,0%,100%,.08)}.ai-chat-media-card__media{background:#000;position:relative;width:100%}.ai-chat-media-card__media.video{aspect-ratio:16/9}.ai-chat-media-card__media.image{aspect-ratio:auto;max-height:400px}.ai-chat-media-card__image{display:block;height:100%;object-fit:cover;width:100%}.ai-chat-media-card__image-error{align-items:center;background:var(--bg-muted,#e5e7eb);color:var(--text-muted,#71717a);display:flex;font-size:13px;height:200px;justify-content:center;width:100%}.ai-chat-media-card__video-placeholder{cursor:pointer;height:100%;position:relative;width:100%}.ai-chat-media-card__video-placeholder img{height:100%;object-fit:cover;width:100%}.ai-chat-media-card__video-bg{background:linear-gradient(135deg,#1a1a2e,#16213e);height:100%;width:100%}.ai-chat-media-card__play-btn{align-items:center;background:rgba(0,0,0,.7);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:56px;justify-content:center;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s,transform .2s;width:56px}.ai-chat-media-card__play-btn:hover{background:rgba(0,0,0,.9);transform:translate(-50%,-50%) scale(1.05)}.ai-chat-media-card__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-media-card__iframe,.ai-chat-media-card__video{border:none;height:100%;left:0;position:absolute;top:0;width:100%}.ai-chat-media-card__content{padding:12px}.ai-chat-media-card__title{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:600;line-height:1.3;margin:0 0 4px}.ai-chat-widget.dark .ai-chat-media-card__title,.chakra-ui-dark .ai-chat-media-card__title,.dark .ai-chat-media-card__title,[data-theme=dark] .ai-chat-media-card__title{color:#fff}.ai-chat-media-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0 0 8px}.ai-chat-media-card__link-btn{align-items:center;background:var(--action-accent);border:none;border-radius:6px;color:#fff;cursor:pointer;display:inline-flex;font-size:13px;font-weight:500;gap:6px;padding:6px 12px;transition:opacity .2s}.ai-chat-media-card__link-btn:hover{opacity:.9}.ai-chat-image-gallery{--action-accent:var(--primary-color,#3b82f6)}.ai-chat-image-gallery__grid{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}@media (max-width:480px){.ai-chat-image-gallery__grid{grid-template-columns:1fr}.ai-chat-image-gallery__grid .ai-chat-image-gallery__item:first-child{grid-column:span 1}}.ai-chat-image-gallery__grid:has(.ai-chat-image-gallery__item:only-child){grid-template-columns:1fr}.ai-chat-image-gallery__grid:has(.ai-chat-image-gallery__item:nth-child(3):last-child) .ai-chat-image-gallery__item:first-child{grid-column:span 2}.ai-chat-image-gallery__grid:has(.ai-chat-image-gallery__item:nth-child(5):last-child) .ai-chat-image-gallery__item:first-child{grid-column:span 2}.ai-chat-image-gallery__grid:has(.ai-chat-image-gallery__item:nth-child(7):last-child) .ai-chat-image-gallery__item:first-child{grid-column:span 2}.ai-chat-image-gallery__item.span-full{grid-column:span 2}.ai-chat-image-gallery[data-item-count=\"1\"] .ai-chat-image-gallery__grid{grid-template-columns:1fr}.ai-chat-image-gallery__item{position:relative}.ai-chat-image-gallery__item-media{aspect-ratio:4/3;background:var(--bg-muted,#e5e7eb);border-radius:var(--radius-lg,12px);overflow:hidden;position:relative}.ai-chat-image-gallery__item-media img{height:100%;object-fit:cover;width:100%}.ai-chat-image-gallery__item-overlay{background:linear-gradient(0deg,rgba(0,0,0,.85) 0,rgba(0,0,0,.4) 60%,transparent);border-radius:0 0 var(--radius-lg,12px) var(--radius-lg,12px);bottom:0;left:0;padding:24px 12px 10px;position:absolute;right:0}.ai-chat-image-gallery__item-title{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:#fff;display:-webkit-box;font-size:12px;font-weight:600;line-height:1.3;margin:0;overflow:hidden;text-shadow:0 1px 3px rgba(0,0,0,.5)}.ai-chat-image-gallery__error{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:12px;height:100%;justify-content:center;width:100%}.ai-chat-media-gallery{--action-accent:var(--primary-color,#3b82f6)}.ai-chat-media-gallery__grid{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}.ai-chat-image-gallery__lightbox,.ai-chat-media-gallery__lightbox{align-items:center;background:rgba(0,0,0,.95);bottom:0;display:flex;justify-content:center;left:0;padding:40px;position:fixed;right:0;top:0;z-index:10000}.ai-chat-image-gallery__lightbox-close,.ai-chat-media-gallery__lightbox-close{align-items:center;background:hsla(0,0%,100%,.1);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:40px;justify-content:center;position:absolute;right:16px;top:16px;transition:background .2s;width:40px}.ai-chat-image-gallery__lightbox-close:hover,.ai-chat-media-gallery__lightbox-close:hover{background:hsla(0,0%,100%,.2)}.ai-chat-image-gallery__lightbox-nav,.ai-chat-media-gallery__lightbox-nav{align-items:center;background:hsla(0,0%,100%,.1);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:48px;justify-content:center;position:absolute;top:50%;transform:translateY(-50%);transition:background .2s;width:48px}.ai-chat-image-gallery__lightbox-nav:hover,.ai-chat-media-gallery__lightbox-nav:hover{background:hsla(0,0%,100%,.2)}.ai-chat-image-gallery__lightbox-nav.prev,.ai-chat-media-gallery__lightbox-nav.prev{left:16px}.ai-chat-image-gallery__lightbox-nav.next,.ai-chat-media-gallery__lightbox-nav.next{right:16px}.ai-chat-image-gallery__lightbox-content,.ai-chat-media-gallery__lightbox-content{align-items:center;display:flex;flex-direction:column;max-height:80vh;max-width:90vw}.ai-chat-image-gallery__lightbox-content img,.ai-chat-media-gallery__lightbox-content img{border-radius:4px;max-height:70vh;max-width:100%;object-fit:contain}.ai-chat-image-gallery__lightbox-caption,.ai-chat-media-gallery__lightbox-caption{color:#fff;margin-top:16px;text-align:center}.ai-chat-image-gallery__lightbox-caption h4,.ai-chat-media-gallery__lightbox-caption h4{font-size:16px;font-weight:600;margin:0 0 4px}.ai-chat-image-gallery__lightbox-caption p,.ai-chat-media-gallery__lightbox-caption p{color:hsla(0,0%,100%,.7);font-size:14px;margin:0}.ai-chat-image-gallery__lightbox-counter,.ai-chat-media-gallery__lightbox-counter{background:rgba(0,0,0,.6);border-radius:20px;bottom:16px;color:#fff;font-size:13px;left:50%;padding:6px 12px;position:absolute;transform:translateX(-50%)}.ai-chat-project-card{--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);display:flex;flex-direction:column;overflow:hidden;transition:border-color .2s,box-shadow .2s,transform .2s}.ai-chat-project-card.clickable{cursor:pointer}.ai-chat-project-card.clickable:hover{border-color:var(--action-accent);box-shadow:0 4px 12px rgba(0,0,0,.1);transform:translateY(-2px)}.ai-chat-widget.dark .ai-chat-project-card,.chakra-ui-dark .ai-chat-project-card,.dark .ai-chat-project-card,[data-theme=dark] .ai-chat-project-card{background:var(--bg-secondary,#2a2a2a);border-color:hsla(0,0%,100%,.1)}.ai-chat-widget.dark .ai-chat-project-card.clickable:hover,.chakra-ui-dark .ai-chat-project-card.clickable:hover,.dark .ai-chat-project-card.clickable:hover,[data-theme=dark] .ai-chat-project-card.clickable:hover{border-color:var(--action-accent);box-shadow:0 4px 16px rgba(0,0,0,.3)}.ai-chat-project-card--image-only{background:transparent;border:none}.ai-chat-project-card--image-only .ai-chat-project-card__media{aspect-ratio:16/9;border-radius:var(--radius-lg,12px)}.ai-chat-project-card--image-only.clickable:hover{border:none;box-shadow:0 4px 16px rgba(0,0,0,.2)}.ai-chat-project-card--overlay{background:transparent;border:none;border-radius:var(--radius-lg,12px);overflow:hidden}.ai-chat-project-card--overlay .ai-chat-project-card__media{aspect-ratio:4/3;border-radius:var(--radius-lg,12px)}.ai-chat-project-card__overlay{background:linear-gradient(0deg,rgba(0,0,0,.85) 0,rgba(0,0,0,.5) 50%,transparent);border-radius:0 0 var(--radius-lg,12px) var(--radius-lg,12px);bottom:0;left:0;padding:10px 12px;position:absolute;right:0}.ai-chat-project-card__overlay-title{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:#fff;display:-webkit-box;font-size:12px;font-weight:600;line-height:1.3;margin:0;overflow:hidden;text-shadow:0 1px 3px rgba(0,0,0,.5)}.ai-chat-project-card--full .ai-chat-project-card__media{aspect-ratio:16/10;border-bottom:1px solid var(--border-subtle,rgba(0,0,0,.06))}.ai-chat-widget.dark .ai-chat-project-card--full .ai-chat-project-card__media,.chakra-ui-dark .ai-chat-project-card--full .ai-chat-project-card__media,.dark .ai-chat-project-card--full .ai-chat-project-card__media,[data-theme=dark] .ai-chat-project-card--full .ai-chat-project-card__media{border-bottom-color:hsla(0,0%,100%,.08)}.ai-chat-project-card__media{aspect-ratio:16/10;background:var(--bg-muted,#e5e7eb);overflow:hidden;position:relative;width:100%}.ai-chat-widget.dark .ai-chat-project-card__media,.chakra-ui-dark .ai-chat-project-card__media,.dark .ai-chat-project-card__media,[data-theme=dark] .ai-chat-project-card__media{background:hsla(0,0%,100%,.05)}.ai-chat-project-card__media img{height:100%;object-fit:cover;transition:transform .3s ease;width:100%}.ai-chat-project-card.clickable:hover .ai-chat-project-card__media img{transform:scale(1.03)}.ai-chat-project-card__iframe,.ai-chat-project-card__video{border:none;height:100%;left:0;position:absolute;top:0;width:100%}.ai-chat-project-card__placeholder{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:13px;height:100%;justify-content:center;width:100%}.ai-chat-project-card__play-btn{align-items:center;background:rgba(0,0,0,.7);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:48px;justify-content:center;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s,transform .2s;width:48px}.ai-chat-project-card__play-btn:hover{background:rgba(0,0,0,.9);transform:translate(-50%,-50%) scale(1.1)}.ai-chat-project-card__content{background:var(--bg-secondary,#f4f4f4);padding:12px 14px 14px}.ai-chat-widget.dark .ai-chat-project-card__content,.chakra-ui-dark .ai-chat-project-card__content,.dark .ai-chat-project-card__content,[data-theme=dark] .ai-chat-project-card__content{background:var(--bg-secondary,#2a2a2a)}.ai-chat-project-card__title{color:var(--text-primary,#1a1a1a);font-size:14px;font-weight:600;line-height:1.35;margin:0 0 6px}.ai-chat-widget.dark .ai-chat-project-card__title,.chakra-ui-dark .ai-chat-project-card__title,.dark .ai-chat-project-card__title,[data-theme=dark] .ai-chat-project-card__title{color:#fff}.ai-chat-project-card__description{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-muted,#6b7280);display:-webkit-box;font-size:13px;line-height:1.45;margin:0 0 10px;overflow:hidden}.ai-chat-project-card__link{align-items:center;color:var(--action-accent);display:inline-flex;font-size:13px;font-weight:500;gap:4px;transition:opacity .2s}.ai-chat-project-card__link:hover{opacity:.8}.ai-chat-media-carousel{--action-accent:var(--primary-color,#3b82f6);border-radius:var(--radius-lg,12px);overflow:hidden;position:relative}.ai-chat-media-carousel__track{display:flex;transition:transform .3s ease-out}.ai-chat-media-carousel__slide{flex:0 0 100%;min-width:0}.ai-chat-media-carousel__slide .ai-chat-project-card{border-radius:var(--radius-md,8px);margin:0 4px}.ai-chat-media-carousel__nav{align-items:center;background:hsla(0,0%,100%,.9);border:none;border-radius:50%;box-shadow:0 2px 8px rgba(0,0,0,.15);color:#333;cursor:pointer;display:flex;height:32px;justify-content:center;position:absolute;top:50%;transform:translateY(-50%);transition:background .2s;width:32px;z-index:2}.ai-chat-media-carousel__nav:hover{background:#fff}.ai-chat-media-carousel__nav.prev{left:8px}.ai-chat-media-carousel__nav.next{right:8px}.ai-chat-widget.dark .ai-chat-media-carousel__nav,.chakra-ui-dark .ai-chat-media-carousel__nav,.dark .ai-chat-media-carousel__nav,[data-theme=dark] .ai-chat-media-carousel__nav{background:rgba(0,0,0,.7);color:#fff}.ai-chat-widget.dark .ai-chat-media-carousel__nav:hover,.chakra-ui-dark .ai-chat-media-carousel__nav:hover,.dark .ai-chat-media-carousel__nav:hover,[data-theme=dark] .ai-chat-media-carousel__nav:hover{background:rgba(0,0,0,.9)}.ai-chat-media-carousel__dots{display:flex;gap:6px;justify-content:center;padding:12px 0 4px}.ai-chat-media-carousel__dot{background:var(--border-subtle,rgba(0,0,0,.2));border:none;border-radius:50%;cursor:pointer;height:8px;padding:0;transition:background .2s,transform .2s;width:8px}.ai-chat-media-carousel__dot:hover{transform:scale(1.2)}.ai-chat-media-carousel__dot.active{background:var(--action-accent)}.ai-chat-widget.dark .ai-chat-media-carousel__dot,.chakra-ui-dark .ai-chat-media-carousel__dot,.dark .ai-chat-media-carousel__dot,[data-theme=dark] .ai-chat-media-carousel__dot{background:hsla(0,0%,100%,.3)}.ai-chat-widget.dark .ai-chat-media-carousel__dot.active,.chakra-ui-dark .ai-chat-media-carousel__dot.active,.dark .ai-chat-media-carousel__dot.active,[data-theme=dark] .ai-chat-media-carousel__dot.active{background:var(--action-accent)}@media (max-width:480px){.ai-chat-media-carousel__nav{height:28px;width:28px}.ai-chat-media-carousel__nav.prev{left:4px}.ai-chat-media-carousel__nav.next{right:4px}.ai-chat-image-gallery__lightbox-nav,.ai-chat-media-gallery__lightbox-nav{height:40px;width:40px}.ai-chat-image-gallery__lightbox,.ai-chat-media-gallery__lightbox{padding:16px}.ai-chat-project-card__content{padding:10px 12px 12px}.ai-chat-project-card__title{font-size:13px}.ai-chat-project-card__description{font-size:12px}}.chat-fullpage{--fp-max-width:800px;--fp-padding-x:16px;--fp-padding-top-mobile:64px;--fp-padding-top-desktop:24px;--fp-padding-bottom:200px;--fp-input-bottom:0}.chat-fullpage .ai-chat-messages{background:transparent;flex:1 1 auto;height:auto;justify-content:flex-start;margin:0 auto;max-height:none;max-width:var(--fp-max-width);min-height:0!important;overflow-x:hidden!important;overflow-y:scroll!important;padding:var(--fp-padding-top-desktop) var(--fp-padding-x) var(--fp-padding-bottom);position:relative}@media (max-width:767px){.chat-fullpage .ai-chat-messages{padding-top:var(--fp-padding-top-mobile)!important}}@media (max-width:480px){.chat-fullpage .ai-chat-messages{padding-top:calc(var(--fp-padding-top-mobile) + env(safe-area-inset-top, 0px))}}.chat-fullpage .ai-chat-messages>.ai-chat-message:first-child,.chat-fullpage .ai-chat-messages>.ai-chat-welcome:first-child{margin-top:0}.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:12px 0 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:110px}}.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}.chat-fullpage .ai-chat-message-meta{align-items:center;display:flex;gap:8px;margin-top:4px;padding:0 16px}.chat-fullpage .ai-chat-message-timestamp{color:var(--text-muted,#71717a);font-size:12px}.chat-fullpage .ai-chat-feedback{display:inline-flex}.chat-fullpage .ai-chat-feedback-button{display:flex}@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:not(.is-open).bottom-right .ai-chat-button{bottom:12px!important;right:12px!important}.ai-chat-widget-container:not(.is-open).bottom-left .ai-chat-button{bottom:12px!important;left:12px!important}.ai-chat-widget-container:not(.is-open).top-right .ai-chat-button{right:12px!important;top:12px!important}.ai-chat-widget-container:not(.is-open).top-left .ai-chat-button{left:12px!important;top:12px!important}.ai-chat-widget-container.trigger-pill-text.container-mode:not(.is-open).bottom-right .ai-chat-trigger-pill{bottom:12px!important;right:12px!important}.ai-chat-widget-container.trigger-pill-text.container-mode:not(.is-open).bottom-left .ai-chat-trigger-pill{bottom:12px!important;left:12px!important}.ai-chat-widget-container.trigger-pill-text.container-mode:not(.is-open).top-right .ai-chat-trigger-pill{right:12px!important;top:12px!important}.ai-chat-widget-container.trigger-pill-text.container-mode:not(.is-open).top-left .ai-chat-trigger-pill{left:12px!important;top:12px!important}.ai-chat-widget-container.trigger-input-bar.container-mode:not(.is-open) .ai-chat-trigger-input-container{bottom:12px!important;left:12px!important;right:12px!important;width:calc(100% - 24px)!important}.ai-chat-widget-container.trigger-input-bar:not(.is-open) .ai-chat-trigger-input-wrapper{max-width:100%!important;width:100%!important}.ai-chat-widget-container.trigger-input-bar:not(.is-open) .ai-chat-trigger-input-row{display:flex;gap:8px;max-width:calc(100vw - 24px)!important;width:calc(100vw - 24px)!important}.ai-chat-widget-container.trigger-input-bar.is-collapsed:not(.is-open) .ai-chat-trigger-input-container{bottom:12px!important;right:12px!important;width:auto!important}.ai-chat-widget-container.trigger-input-bar.is-collapsed:not(.is-open) .ai-chat-button{margin-left:0!important;margin-right:0!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%}.ai-chat-widget-container.is-open .ai-chat-message-meta{align-items:center;display:flex;gap:8px;margin-top:4px}.ai-chat-widget-container.is-open .ai-chat-message-timestamp{font-size:11px}.ai-chat-widget-container.is-open .ai-chat-feedback{display:inline-flex}.ai-chat-widget-container.is-open .ai-chat-feedback-button{display:flex;padding:4px}.ai-chat-widget-container.is-open .ai-chat-input{font-size:16px!important}}@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)}}.ai-chat-widget-container.desktop-mode.container-mode.is-open{height:100%!important;inset:0!important;position:absolute!important;width:100%!important}.ai-chat-widget-container.desktop-mode.container-mode.is-open .ai-chat-window{border:1px solid var(--border-color,rgba(0,0,0,.08))!important;border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) var(--radius-window-bottom,44px) var(--radius-window-bottom,44px)!important;box-shadow:var(--window-shadow,0 20px 60px -10px rgba(0,0,0,.25))!important;position:absolute!important}.ai-chat-widget-container.desktop-mode.container-mode.size-small.is-open .ai-chat-window{height:min(500px,calc(100% - 120px))!important;max-height:500px!important;max-width:380px!important;min-height:300px!important;min-width:280px!important;width:min(380px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.size-medium.is-open .ai-chat-window{height:min(65%,calc(100% - 120px))!important;max-height:680px!important;max-width:440px!important;min-height:400px!important;min-width:320px!important;width:min(440px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.size-large.is-open .ai-chat-window{height:calc(100% - 100px)!important;max-height:calc(100% - 100px)!important;max-width:560px!important;min-height:500px!important;min-width:380px!important;width:min(560px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.is-open.bottom-right .ai-chat-window{bottom:88px!important;left:auto!important;right:20px!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode.is-open.bottom-left .ai-chat-window{bottom:88px!important;left:20px!important;right:auto!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode.is-open.top-right .ai-chat-window{bottom:auto!important;left:auto!important;right:20px!important;top:88px!important}.ai-chat-widget-container.desktop-mode.container-mode.is-open.top-left .ai-chat-window{bottom:auto!important;left:20px!important;right:auto!important;top:88px!important}.ai-chat-widget-container.desktop-mode.is-open .ai-chat-button{display:flex!important;opacity:1!important;pointer-events:auto!important;visibility:visible!important}.ai-chat-widget-container.desktop-mode.container-mode:not(.trigger-input-bar).bottom-right .ai-chat-button{bottom:20px!important;left:auto!important;right:20px!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode:not(.trigger-input-bar).bottom-left .ai-chat-button{bottom:20px!important;left:20px!important;right:auto!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode:not(.trigger-input-bar).top-right .ai-chat-button{bottom:auto!important;left:auto!important;right:20px!important;top:20px!important}.ai-chat-widget-container.desktop-mode.container-mode:not(.trigger-input-bar).top-left .ai-chat-button{bottom:auto!important;left:20px!important;right:auto!important;top:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.bottom-right .ai-chat-trigger-input-container{bottom:20px!important;left:auto!important;right:20px!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.bottom-left .ai-chat-trigger-input-container{bottom:20px!important;left:20px!important;right:auto!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.top-right .ai-chat-trigger-input-container{bottom:auto!important;left:auto!important;right:20px!important;top:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.top-left .ai-chat-trigger-input-container{bottom:auto!important;left:20px!important;right:auto!important;top:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.size-small .ai-chat-trigger-input-container{width:min(380px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.size-medium .ai-chat-trigger-input-container{width:min(440px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.size-large .ai-chat-trigger-input-container{width:min(560px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.bottom-left .ai-chat-window,.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.bottom-right .ai-chat-window{bottom:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.top-left .ai-chat-window,.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.top-right .ai-chat-window{top:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.bottom-right .ai-chat-window,.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.top-right .ai-chat-window{left:auto!important;right:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.bottom-left .ai-chat-window,.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.top-left .ai-chat-window{left:20px!important;right:auto!important}";
30847
31237
  styleInject(css_248z$1);
30848
31238
 
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}";
31239
+ 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}.ai-chat-widget-embedded .ai-chat-data-policy-view{-webkit-overflow-scrolling:touch;overflow-y:auto}.ai-chat-widget-embedded .ai-chat-data-policy-content{margin:0 auto;max-width:640px;overflow-y:visible;padding:32px 24px 60px}.ai-chat-widget-embedded .ai-chat-data-policy-intro p{font-size:14px;line-height:1.7}.ai-chat-widget-embedded .ai-chat-data-policy-section h3{font-size:15px;margin-bottom:14px}.ai-chat-widget-embedded .ai-chat-data-policy-section p{font-size:13px;line-height:1.7}.ai-chat-widget-embedded.dark .ai-chat-data-policy-intro p,.ai-chat-widget-embedded.dark .ai-chat-data-policy-intro strong,.ai-chat-widget-embedded.dark .ai-chat-data-policy-section h3{color:var(--text-primary,#fafafa)}.ai-chat-widget-embedded.dark .ai-chat-data-policy-section p{color:var(--text-secondary,#a1a1aa)}.ai-chat-widget-embedded.dark .ai-chat-data-policy-section p strong{color:var(--text-primary,#fafafa)}";
30850
31240
  styleInject(css_248z);
30851
31241
 
30852
- // Icon components mapping
30853
- const iconComponents = {
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" }) })),
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" }) })),
30856
- };
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', }) => {
31242
+ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = false, previewConfig, position = 'bottom-right', primaryColor, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, welcomeBubbleText, triggerType, triggerText, theme, suggestedQuestions, customStyles, currentRoute, defaultOpen = false, zIndex, containerMode = false, mobileMode = false, desktopMode = false, onOpen, onClose, onMessage, onError, mode = 'bubble', }) => {
30858
31243
  const [isOpen, setIsOpen] = useState(defaultOpen);
30859
31244
  const [inputBarValue, setInputBarValue] = useState('');
30860
- const [autoDetectedTheme, setAutoDetectedTheme] = useState('light');
30861
31245
  const [showWelcomeBubble, setShowWelcomeBubble] = useState(false);
31246
+ const [isInputBarCollapsed, setIsInputBarCollapsed] = useState(false);
30862
31247
  const widgetRef = useRef(null);
30863
31248
  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);
30874
31249
  // Determine mode
30875
31250
  const isEmbedded = mode === 'embedded';
30876
31251
  // Default config for preview mode
@@ -30916,24 +31291,22 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30916
31291
  ...previewConfig?.behavior,
30917
31292
  },
30918
31293
  };
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);
31294
+ // Always call useChat hook (React rules), but skip initialization in preview mode
31295
+ const shouldSkipInit = previewMode;
30923
31296
  const chatHook = useChat({
30924
31297
  widgetId: previewMode ? '__preview__' : (widgetId || '__preview__'),
30925
31298
  apiUrl,
30926
31299
  currentRoute,
30927
31300
  onMessage: shouldSkipInit ? undefined : onMessage,
30928
31301
  onError: shouldSkipInit ? undefined : onError,
30929
- skipInitialization: shouldSkipInit, // Don't make API calls in preview mode or during demo
31302
+ skipInitialization: shouldSkipInit,
30930
31303
  });
30931
31304
  // Extract values from hook or use preview defaults
30932
- const hookMessages = previewMode ? [] : chatHook.messages;
30933
- const hookIsLoading = previewMode ? false : chatHook.isLoading;
30934
- const hookIsTyping = previewMode ? false : chatHook.isTyping;
31305
+ const messages = previewMode ? [] : chatHook.messages;
31306
+ const isLoading = previewMode ? false : chatHook.isLoading;
31307
+ const isTyping = previewMode ? false : chatHook.isTyping;
30935
31308
  const config = previewMode ? mergedPreviewConfig : chatHook.config;
30936
- const hookSendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
31309
+ const sendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
30937
31310
  const submitFeedback = previewMode ? (() => Promise.resolve()) : chatHook.submitFeedback;
30938
31311
  const dismissAction = previewMode ? (() => Promise.resolve()) : chatHook.dismissAction;
30939
31312
  const conversations = previewMode ? [] : chatHook.conversations;
@@ -30941,54 +31314,26 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30941
31314
  const switchConversation = previewMode ? (() => Promise.resolve()) : chatHook.switchConversation;
30942
31315
  const startNewConversation = previewMode ? (() => { }) : chatHook.startNewConversation;
30943
31316
  const deleteConversation = previewMode ? (() => { }) : chatHook.deleteConversation;
30944
- const createDemoConversation = previewMode ? (() => Promise.resolve(null)) : chatHook.createDemoConversation;
30945
31317
  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]);
30967
- // Auto-detect theme from background
30968
- useEffect(() => {
30969
- if (!containerRef.current)
30970
- return;
30971
- // Initial detection
30972
- const detected = detectTheme(containerRef.current);
30973
- setAutoDetectedTheme(detected);
30974
- // Watch for theme changes on the page
30975
- const observer = createThemeObserver(containerRef.current, (newTheme) => {
30976
- setAutoDetectedTheme(newTheme);
30977
- });
30978
- // Also listen for system preference changes
30979
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
30980
- const handleMediaChange = () => {
30981
- if (containerRef.current) {
30982
- const detected = detectTheme(containerRef.current);
30983
- setAutoDetectedTheme(detected);
30984
- }
30985
- };
30986
- mediaQuery.addEventListener('change', handleMediaChange);
30987
- return () => {
30988
- observer.disconnect();
30989
- mediaQuery.removeEventListener('change', handleMediaChange);
30990
- };
30991
- }, [config]);
31318
+ const callActionEndpoint = previewMode ? (async () => { throw new Error('Not available in preview mode'); }) : chatHook.callActionEndpoint;
31319
+ const { effectiveTheme, effectivePosition, accentColor, iconContrastColor, effectiveSize, effectiveHeaderTitle, effectiveWelcomeTitle, effectiveWelcomeMessage, effectivePlaceholder, effectiveWelcomeBubbleText, effectiveTriggerType, effectiveTriggerText, mergedStyles, } = useWidgetAppearance({
31320
+ containerRef,
31321
+ config,
31322
+ theme,
31323
+ primaryColor,
31324
+ position,
31325
+ size,
31326
+ headerTitle,
31327
+ welcomeTitle,
31328
+ welcomeMessage,
31329
+ placeholder,
31330
+ welcomeBubbleText,
31331
+ triggerType,
31332
+ triggerText,
31333
+ customStyles,
31334
+ zIndex,
31335
+ previewMode,
31336
+ });
30992
31337
  // Check if device is mobile
30993
31338
  const isMobile = typeof window !== 'undefined' && window.innerWidth <= 480;
30994
31339
  // Handle auto-open (only for bubble mode, disabled on mobile)
@@ -30996,9 +31341,6 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30996
31341
  // Never auto-open on mobile devices
30997
31342
  if (isMobile)
30998
31343
  return undefined;
30999
- // Don't auto-open if demo mode is active - let demo animation control opening
31000
- if (demoMode && !isDemoComplete)
31001
- return undefined;
31002
31344
  if (!isEmbedded && config?.settings.autoOpen) {
31003
31345
  const delay = config.settings.autoOpenDelay || 0;
31004
31346
  const timer = setTimeout(() => {
@@ -31008,7 +31350,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
31008
31350
  return () => clearTimeout(timer);
31009
31351
  }
31010
31352
  return undefined;
31011
- }, [config, onOpen, isEmbedded, isMobile, demoMode, isDemoComplete]);
31353
+ }, [config, onOpen, isEmbedded, isMobile]);
31012
31354
  // Handle close on Escape key (only for bubble mode)
31013
31355
  useEffect(() => {
31014
31356
  if (!isOpen || isEmbedded)
@@ -31085,172 +31427,12 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
31085
31427
  setShowWelcomeBubble(true);
31086
31428
  }
31087
31429
  }, [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]);
31222
- // Determine theme - use prop override if provided, otherwise auto-detect
31223
- const appearanceConfig = config?.appearance;
31224
- const effectiveTheme = theme ?? autoDetectedTheme;
31225
- // Determine position (prop override takes priority for live preview)
31226
- const effectivePosition = position || config?.appearance.position || 'bottom-right';
31227
- // Get accent color from prop or config (empty string means no accent color / vanilla mode)
31228
- const accentColor = primaryColor ?? appearanceConfig?.primaryColor ?? '';
31229
- // Apply prop overrides for live preview (props take priority over config)
31230
- const effectiveSize = size || appearanceConfig?.size || 'small';
31231
- const effectiveHeaderTitle = headerTitle ?? appearanceConfig?.headerTitle ?? '';
31232
- const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? '';
31233
- const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? '';
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';
31238
- // Generate styles using simplified theme system
31239
- const simpleAppearance = {
31240
- accentColor};
31241
- // Generate theme styles from accent color
31242
- const generatedStyles = generateThemeStyles(simpleAppearance, effectiveTheme);
31243
- // Also apply legacy styles for backward compatibility
31244
- const legacyStyles = appearanceConfig
31245
- ? applyAppearanceStyles(appearanceConfig)
31246
- : {};
31247
- // Merge styles (generated takes priority for new simplified system, then custom overrides)
31248
- const mergedStyles = {
31249
- ...legacyStyles,
31250
- ...generatedStyles,
31251
- ...customStyles,
31252
- ...(zIndex !== undefined ? { '--widget-z-index': String(zIndex) } : {}),
31253
- };
31430
+ const handleStartNewConversation = useCallback(() => {
31431
+ startNewConversation();
31432
+ }, [startNewConversation]);
31433
+ const handleSendMessage = useCallback((content) => {
31434
+ sendMessage(content);
31435
+ }, [sendMessage]);
31254
31436
  // Dismiss bubble and store based on frequency setting
31255
31437
  const dismissBubble = () => {
31256
31438
  setShowWelcomeBubble(false);
@@ -31286,9 +31468,6 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
31286
31468
  onOpen?.();
31287
31469
  }
31288
31470
  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
31292
31471
  onClose?.();
31293
31472
  }
31294
31473
  };
@@ -31325,10 +31504,13 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
31325
31504
  sendMessage(actionInstruction);
31326
31505
  };
31327
31506
  // 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
31507
+ // Exceptions that allow immediate rendering:
31508
+ // 1. triggerType prop provided - user wants specific trigger shown immediately
31509
+ // 2. primaryColor prop provided - we have initial styling, no flash will occur
31510
+ // This improves perceived loading speed - users see the correctly styled trigger while config loads
31330
31511
  // In preview mode, config is always available
31331
- const canRenderWithoutConfig = !!triggerType;
31512
+ const hasInitialStyling = !!primaryColor;
31513
+ const canRenderWithoutConfig = !!triggerType || hasInitialStyling;
31332
31514
  if (!config && !previewMode && !canRenderWithoutConfig) {
31333
31515
  return null;
31334
31516
  }
@@ -31336,21 +31518,21 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
31336
31518
  const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
31337
31519
  // Embedded mode renders directly without wrapper positioning
31338
31520
  if (isEmbedded) {
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 }) }));
31521
+ 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: handleSendMessage, onClose: () => { }, onFeedback: handleFeedback, onActionClick: handleActionClick, onActionDismiss: dismissAction, onCallEndpoint: callActionEndpoint, conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: handleStartNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, sizeOverride: effectiveSize, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions }) }));
31340
31522
  }
31341
31523
  // Determine trigger class for container
31342
31524
  const triggerClass = effectiveTriggerType === 'pill-text'
31343
31525
  ? 'trigger-pill-text'
31344
31526
  : effectiveTriggerType === 'input-bar'
31345
31527
  ? 'trigger-input-bar'
31346
- : '';
31528
+ : 'trigger-button';
31347
31529
  // Size class for CSS targeting (used by input-bar trigger for width matching)
31348
31530
  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,
31531
+ // Collapsed class for input bar
31532
+ const collapsedClass = isInputBarCollapsed ? 'is-collapsed' : '';
31533
+ 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' : ''} ${mobileMode ? 'mobile-mode' : ''} ${desktopMode ? 'desktop-mode' : ''} ${triggerClass} ${sizeClass} ${collapsedClass}`, children: [isOpen && (jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage: handleSendMessage, onClose: handleToggle, onFeedback: handleFeedback, onActionClick: handleActionClick, onActionDismiss: dismissAction, onCallEndpoint: callActionEndpoint,
31350
31534
  // Chat history props (only active when persistConversation is true)
31351
- conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId,
31352
- // Override props for live preview
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" })] }) })] })] }))] }) }));
31535
+ conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: handleStartNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, sizeOverride: effectiveSize, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), jsx(WidgetTriggers, { triggerType: effectiveTriggerType, isOpen: isOpen, onToggle: handleToggle, triggerText: effectiveTriggerText, placeholder: effectivePlaceholder, IconComponent: IconComponent, showWelcomeBubble: showWelcomeBubble, welcomeBubbleText: effectiveWelcomeBubbleText, previewMode: previewMode, onDismissBubble: handleDismissBubble, isInputBarCollapsed: isInputBarCollapsed, setIsInputBarCollapsed: setIsInputBarCollapsed, inputBarValue: inputBarValue, setInputBarValue: setInputBarValue, onSubmitInputBar: handleInputBarSubmit, accentColor: accentColor, iconColor: iconContrastColor })] }) }));
31354
31536
  };
31355
31537
 
31356
31538
  export { ApiError, ChatWidget, DataPolicyView, useChat };