@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.js CHANGED
@@ -212,58 +212,83 @@ class WidgetApiClient {
212
212
  return typeof data === 'object' && data !== null && 'type' in data;
213
213
  });
214
214
  }
215
- async *continueAgentMessageStream(conversationId, toolCallId, state, signal) {
215
+ async *dismissAgentMessageStream(conversationId, toolCallId, signal) {
216
216
  const headers = {
217
217
  'Content-Type': 'application/json',
218
218
  };
219
219
  if (this.config.currentRoute) {
220
220
  headers['X-Current-Route'] = this.config.currentRoute;
221
221
  }
222
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/continue`, {
222
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/dismiss`, {
223
223
  method: 'POST',
224
224
  headers,
225
225
  body: JSON.stringify({
226
226
  conversationId: conversationId,
227
227
  toolCallId,
228
- state,
229
- timeZone: this.getTimeZone(),
228
+ reason: "user",
230
229
  }),
231
230
  signal,
232
231
  });
232
+ if (response.status === 204) {
233
+ return;
234
+ }
233
235
  if (!response.ok) {
234
- throw await buildApiError(response, 'Failed to continue agent');
236
+ throw await buildApiError(response, 'Failed to dismiss action');
235
237
  }
236
238
  yield* parseSSEStream(response, (data) => {
237
239
  return typeof data === 'object' && data !== null && 'type' in data;
238
240
  });
239
241
  }
240
- async *dismissAgentMessageStream(conversationId, toolCallId, signal) {
242
+ /**
243
+ * Continue agent after halting action completes
244
+ * Call this when frontend completes an action and wants to pass result back to agent
245
+ */
246
+ async *continueAgentAction(conversationId, toolCallId, body, signal) {
241
247
  const headers = {
242
248
  'Content-Type': 'application/json',
243
249
  };
244
250
  if (this.config.currentRoute) {
245
251
  headers['X-Current-Route'] = this.config.currentRoute;
246
252
  }
247
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/dismiss`, {
253
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/continue`, {
248
254
  method: 'POST',
249
255
  headers,
250
256
  body: JSON.stringify({
251
- conversationId: conversationId,
257
+ conversationId,
252
258
  toolCallId,
253
- reason: "user",
259
+ body,
260
+ timeZone: this.getTimeZone(),
254
261
  }),
255
262
  signal,
256
263
  });
257
- if (response.status === 204) {
258
- return;
259
- }
260
264
  if (!response.ok) {
261
- throw await buildApiError(response, 'Failed to dismiss action');
265
+ throw await buildApiError(response, 'Failed to continue agent action');
262
266
  }
263
267
  yield* parseSSEStream(response, (data) => {
264
268
  return typeof data === 'object' && data !== null && 'type' in data;
265
269
  });
266
270
  }
271
+ /**
272
+ * NEW: Call action endpoint (frontend-owned flow)
273
+ * Used for multi-step actions like booking appointments
274
+ */
275
+ async callActionEndpoint(actionId, endpoint, input, token) {
276
+ const headers = {
277
+ 'Content-Type': 'application/json',
278
+ };
279
+ if (token) {
280
+ headers['Authorization'] = `Bearer ${token}`;
281
+ }
282
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/actions/${actionId}/${endpoint}`, {
283
+ method: 'POST',
284
+ headers,
285
+ body: JSON.stringify(input),
286
+ });
287
+ if (!response.ok) {
288
+ throw await buildApiError(response, `Action endpoint '${endpoint}' failed`);
289
+ }
290
+ return response.json();
291
+ }
267
292
  /**
268
293
  * Submit feedback for a message
269
294
  */
@@ -294,7 +319,8 @@ class WidgetApiClient {
294
319
  }
295
320
  /**
296
321
  * Generate follow-up suggestions based on conversation context and available actions.
297
- * Called by the frontend after receiving a "done" event from the agent.
322
+ * @deprecated Follow-ups are now generated server-side in parallel and included in the done event.
323
+ * This method is kept for backwards compatibility but is no longer called by the widget.
298
324
  */
299
325
  async generateFollowUps(messages, actionIds) {
300
326
  try {
@@ -27162,7 +27188,7 @@ function TypingIndicator({ className = '' }) {
27162
27188
  }
27163
27189
 
27164
27190
  // Styles are provided by global messages.css - no component-specific CSS needed
27165
- function ChevronDownIcon() {
27191
+ function ChevronDownIcon$1() {
27166
27192
  return (jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" }) }));
27167
27193
  }
27168
27194
  function ScrollButton({ onClick, visible, className = '' }) {
@@ -27171,7 +27197,7 @@ function ScrollButton({ onClick, visible, className = '' }) {
27171
27197
  visible && 'visible',
27172
27198
  className,
27173
27199
  ].filter(Boolean).join(' ');
27174
- return (jsxRuntime.jsx("button", { type: "button", className: classes, onClick: onClick, "aria-label": "Scroll to bottom", children: jsxRuntime.jsx(ChevronDownIcon, {}) }));
27200
+ return (jsxRuntime.jsx("button", { type: "button", className: classes, onClick: onClick, "aria-label": "Scroll to bottom", children: jsxRuntime.jsx(ChevronDownIcon$1, {}) }));
27175
27201
  }
27176
27202
 
27177
27203
  const formatToolName = (name) => {
@@ -27183,13 +27209,23 @@ const formatToolName = (name) => {
27183
27209
  .join(' ');
27184
27210
  };
27185
27211
  function ToolIndicator({ badges, className = '' }) {
27186
- return (jsxRuntime.jsx("div", { className: `ai-chat-tool-row ${className}`, children: jsxRuntime.jsx("div", { className: "ai-chat-tool-badges", children: badges.map((badge) => (jsxRuntime.jsx("div", { className: `ai-chat-tool-badge ${badge.status}`, children: jsxRuntime.jsx("span", { className: "tool-name", children: formatToolName(badge.name) }) }, badge.id))) }) }));
27212
+ // Consolidate multiple badges into a single status indicator
27213
+ const hasLoading = badges.some(b => b.status === 'loading');
27214
+ const hasError = badges.some(b => b.status === 'error');
27215
+ const status = hasLoading ? 'loading' : hasError ? 'error' : 'completed';
27216
+ // Show only the most relevant badge name, or count if multiple
27217
+ const displayName = badges.length === 1
27218
+ ? formatToolName(badges[0].name)
27219
+ : badges.length > 1
27220
+ ? `${badges.length} actions`
27221
+ : 'Processing';
27222
+ return (jsxRuntime.jsx("div", { className: `ai-chat-tool-row ${className}`, children: jsxRuntime.jsx("div", { className: "ai-chat-tool-badges", children: jsxRuntime.jsx("div", { className: `ai-chat-tool-badge ${status}`, children: jsxRuntime.jsx("span", { className: "tool-name", children: displayName }) }) }) }));
27187
27223
  }
27188
27224
 
27189
27225
  // SVG Icon components
27190
27226
  const ThumbsUpIcon = () => (jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.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" }) }));
27191
27227
  const ThumbsDownIcon = () => (jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.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" }) }));
27192
- const CheckIcon$2 = () => (jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) }));
27228
+ const CheckIcon$1 = () => (jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) }));
27193
27229
  const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
27194
27230
  const [isSubmitting, setIsSubmitting] = React.useState(false);
27195
27231
  const [submitted, setSubmitted] = React.useState(false);
@@ -27210,7 +27246,7 @@ const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
27210
27246
  setIsSubmitting(false);
27211
27247
  }
27212
27248
  };
27213
- return (jsxRuntime.jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsxRuntime.jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsxRuntime.jsx(ThumbsUpIcon, {}) }), jsxRuntime.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: jsxRuntime.jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxRuntime.jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsxRuntime.jsx("span", { className: "ai-chat-feedback-checkmark", children: jsxRuntime.jsx(CheckIcon$2, {}) }), jsxRuntime.jsx("span", { className: "ai-chat-feedback-text", children: "Thanks for feedback" })] }))] }));
27249
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsxRuntime.jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsxRuntime.jsx(ThumbsUpIcon, {}) }), jsxRuntime.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: jsxRuntime.jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxRuntime.jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsxRuntime.jsx("span", { className: "ai-chat-feedback-checkmark", children: jsxRuntime.jsx(CheckIcon$1, {}) }), jsxRuntime.jsx("span", { className: "ai-chat-feedback-text", children: "Thanks for feedback" })] }))] }));
27214
27250
  };
27215
27251
 
27216
27252
  const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, }) => {
@@ -27239,9 +27275,11 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedb
27239
27275
  const hasContent = aiContent.trim().length > 0;
27240
27276
  if (!hasContent)
27241
27277
  return null;
27242
- return (jsxRuntime.jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsxRuntime.jsx("div", { className: "ai-chat-message-content", children: jsxRuntime.jsx(Markdown, { remarkPlugins: [remarkGfm], components: {
27278
+ // Only show timestamp and feedback when message is complete (not streaming)
27279
+ const isComplete = !message.isStreaming;
27280
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''} ${message.isStreaming ? 'streaming' : ''}`, children: [jsxRuntime.jsx("div", { className: "ai-chat-message-content", children: jsxRuntime.jsx(Markdown, { remarkPlugins: [remarkGfm], components: {
27243
27281
  table: ({ children, ...props }) => (jsxRuntime.jsx("div", { className: "table-wrapper", children: jsxRuntime.jsx("div", { className: "table-scroll", children: jsxRuntime.jsx("table", { ...props, children: children }) }) })),
27244
- }, children: aiContent }) }), showTimestamp && (jsxRuntime.jsxs("div", { className: "ai-chat-message-meta", children: [jsxRuntime.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsxRuntime.jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
27282
+ }, children: aiContent }) }), showTimestamp && isComplete && (jsxRuntime.jsxs("div", { className: "ai-chat-message-meta", children: [jsxRuntime.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsxRuntime.jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
27245
27283
  }
27246
27284
  // System message rendering
27247
27285
  if (isSystem) {
@@ -27261,7 +27299,7 @@ function isActionComplete(state) {
27261
27299
  return false;
27262
27300
  const TERMINAL_STATUSES = [
27263
27301
  'completed', 'booked', 'scheduled', 'cancelled', 'failed', 'error',
27264
- 'displaying', 'clicked', 'contacted', 'submitted', 'sent'
27302
+ 'displaying', 'displayed', 'clicked', 'contacted', 'submitted', 'sent'
27265
27303
  ];
27266
27304
  const status = state.status;
27267
27305
  if (typeof status === 'string' && TERMINAL_STATUSES.includes(status)) {
@@ -27280,10 +27318,10 @@ function isActionLoading(message) {
27280
27318
  return false;
27281
27319
  if (message.isStreaming)
27282
27320
  return true;
27283
- const state = message.action.state;
27284
- return !isActionComplete(state);
27321
+ const input = message.action.input;
27322
+ return !isActionComplete(input);
27285
27323
  }
27286
- const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant, onActionDismiss, }) => {
27324
+ const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant, onActionDismiss, onCallEndpoint, }) => {
27287
27325
  const visibleMessages = messages.filter(message => !message.action?.hidden);
27288
27326
  const actionMessages = visibleMessages.filter(message => message.action);
27289
27327
  // Debug logging
@@ -27307,7 +27345,7 @@ const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = tru
27307
27345
  implementation: impl,
27308
27346
  hasRenderer: !!renderer,
27309
27347
  rendererType: renderer ? typeof renderer : 'undefined',
27310
- state: msg.action?.state,
27348
+ input: msg.action?.input,
27311
27349
  });
27312
27350
  });
27313
27351
  // If tool indicator is hidden AND there are no action cards to render, don't render anything
@@ -27334,7 +27372,7 @@ const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = tru
27334
27372
  console.log('[ToolMessageGroup] No renderer for:', message.action.implementation);
27335
27373
  return null;
27336
27374
  }
27337
- return (jsxRuntime.jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant, onActionDismiss) }, `action-${message.id}`));
27375
+ return (jsxRuntime.jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant, onActionDismiss, onCallEndpoint) }, `action-${message.id}`));
27338
27376
  })] }));
27339
27377
  };
27340
27378
 
@@ -27368,12 +27406,29 @@ const SuggestedQuestions = ({ questions, onQuestionClick, }) => {
27368
27406
  };
27369
27407
 
27370
27408
  const MAX_TEXT_LENGTH = 40;
27409
+ const STAGGER_DELAY_MS = 200; // Delay between each suggestion appearing
27371
27410
  const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, accentColor, }) => {
27372
- if (!suggestions || suggestions.length === 0) {
27373
- return null;
27374
- }
27411
+ const [visibleIndices, setVisibleIndices] = React.useState(new Set());
27375
27412
  // Filter out empty suggestions
27376
- const validSuggestions = suggestions.filter(s => s && s.text && s.text.trim());
27413
+ const validSuggestions = suggestions?.filter(s => s && s.text && s.text.trim()) || [];
27414
+ // Create a stable key for the current suggestions set
27415
+ const suggestionsKey = validSuggestions.map(s => s.id).join(',');
27416
+ // Stagger reveal each suggestion one at a time
27417
+ React.useEffect(() => {
27418
+ // Reset when suggestions change
27419
+ setVisibleIndices(new Set());
27420
+ if (validSuggestions.length === 0)
27421
+ return;
27422
+ const timers = [];
27423
+ // Reveal each suggestion one by one
27424
+ validSuggestions.slice(0, 5).forEach((_, index) => {
27425
+ const timer = setTimeout(() => {
27426
+ setVisibleIndices(prev => new Set([...prev, index]));
27427
+ }, (index + 1) * STAGGER_DELAY_MS);
27428
+ timers.push(timer);
27429
+ });
27430
+ return () => timers.forEach(t => clearTimeout(t));
27431
+ }, [suggestionsKey]); // eslint-disable-line react-hooks/exhaustive-deps
27377
27432
  if (validSuggestions.length === 0) {
27378
27433
  return null;
27379
27434
  }
@@ -27381,8 +27436,12 @@ const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, acce
27381
27436
  ? { "--primary-color": accentColor }
27382
27437
  : undefined;
27383
27438
  const trimText = (text) => text.length > MAX_TEXT_LENGTH ? `${text.slice(0, MAX_TEXT_LENGTH)}...` : text;
27384
- return (jsxRuntime.jsx("div", { className: "ai-chat-follow-up-suggestions", style: containerStyle, children: jsxRuntime.jsx("div", { className: "ai-chat-follow-up-list", children: validSuggestions.slice(0, 5).map((suggestion) => {
27439
+ return (jsxRuntime.jsx("div", { className: "ai-chat-follow-up-suggestions", style: containerStyle, children: jsxRuntime.jsx("div", { className: "ai-chat-follow-up-list", children: validSuggestions.slice(0, 5).map((suggestion, index) => {
27385
27440
  const isActionSuggestion = suggestion.type === 'action';
27441
+ const isVisible = visibleIndices.has(index);
27442
+ // Only render if visible - this adds items one by one instead of showing all at once
27443
+ if (!isVisible)
27444
+ return null;
27386
27445
  const className = `ai-chat-follow-up-item ${isActionSuggestion ? 'action-type' : 'question-type'}`;
27387
27446
  const handleClick = () => {
27388
27447
  if (isActionSuggestion && onActionClick) {
@@ -27396,7 +27455,7 @@ const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, acce
27396
27455
  };
27397
27456
 
27398
27457
  const MessageList = (props) => {
27399
- const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onActionDismiss, onFeedback, onScrollStateChange, getActionRenderer, variant, } = props;
27458
+ 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;
27400
27459
  const containerRef = React.useRef(null);
27401
27460
  const messagesEndRef = React.useRef(null);
27402
27461
  const [showScrollButton, setShowScrollButton] = React.useState(false);
@@ -27407,24 +27466,31 @@ const MessageList = (props) => {
27407
27466
  const lastToolMsg = [...visibleMessages].reverse().find(msg => msg.message.role === 'tool');
27408
27467
  return lastToolMsg?.action && lastToolMsg.action.done !== true;
27409
27468
  }, [visibleMessages]);
27410
- const checkScrollPosition = React.useCallback(() => {
27411
- const c = containerRef.current;
27412
- if (!c)
27413
- return;
27414
- const pb = parseInt(getComputedStyle(c).paddingBottom || '0', 10);
27415
- setShowScrollButton(c.scrollHeight - c.scrollTop - c.clientHeight - pb > 24);
27416
- }, []);
27417
27469
  const scrollToBottom = React.useCallback(() => {
27418
27470
  messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
27419
27471
  }, []);
27420
- React.useEffect(() => { onScrollStateChange?.(showScrollButton, scrollToBottom); }, [showScrollButton, scrollToBottom, onScrollStateChange]);
27472
+ // Use IntersectionObserver to detect when the end marker is visible
27473
+ // This is more reliable than scroll position calculations
27421
27474
  React.useEffect(() => {
27422
- const c = containerRef.current;
27423
- if (!c)
27475
+ const endMarker = messagesEndRef.current;
27476
+ const container = containerRef.current;
27477
+ if (!endMarker || !container)
27424
27478
  return;
27425
- c.addEventListener('scroll', checkScrollPosition);
27426
- return () => c.removeEventListener('scroll', checkScrollPosition);
27427
- }, [checkScrollPosition]);
27479
+ const observer = new IntersectionObserver((entries) => {
27480
+ // If the end marker is intersecting (visible), hide the button
27481
+ // If it's not visible, show the button
27482
+ const isAtBottom = entries[0]?.isIntersecting ?? false;
27483
+ setShowScrollButton(!isAtBottom);
27484
+ }, {
27485
+ root: container,
27486
+ // rootMargin adds extra space - if end marker is within 100px of viewport, consider it "visible"
27487
+ rootMargin: '0px 0px 100px 0px',
27488
+ threshold: 0,
27489
+ });
27490
+ observer.observe(endMarker);
27491
+ return () => observer.disconnect();
27492
+ }, []);
27493
+ React.useEffect(() => { onScrollStateChange?.(showScrollButton, scrollToBottom); }, [showScrollButton, scrollToBottom, onScrollStateChange]);
27428
27494
  React.useEffect(() => {
27429
27495
  const c = containerRef.current;
27430
27496
  if (!c)
@@ -27439,32 +27505,18 @@ const MessageList = (props) => {
27439
27505
  if ((isNew || isTyping) && c.scrollHeight - c.scrollTop - c.clientHeight < 150) {
27440
27506
  messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
27441
27507
  }
27442
- checkScrollPosition();
27443
- }, [visibleMessages, isTyping, checkScrollPosition]);
27508
+ }, [visibleMessages, isTyping]);
27444
27509
  const groupedMessages = React.useMemo(() => {
27445
- console.log('[DEBUG MessageList] ========================================');
27446
- console.log('[DEBUG MessageList] Processing messages:', visibleMessages.length);
27447
- visibleMessages.forEach((m, i) => {
27448
- console.log(`[DEBUG MessageList] Message ${i}:`, {
27449
- id: m.id,
27450
- role: m.message.role,
27451
- hasAction: !!m.action,
27452
- actionImpl: m.action?.implementation,
27453
- content: (m.message.content || '').substring(0, 50),
27454
- });
27455
- });
27456
27510
  const result = [];
27457
27511
  let toolGroup = [];
27458
27512
  const flush = () => {
27459
27513
  if (toolGroup.length) {
27460
- console.log('[DEBUG MessageList] Flushing tool group with', toolGroup.length, 'messages');
27461
27514
  result.push({ type: 'tool-group', messages: [...toolGroup] });
27462
27515
  toolGroup = [];
27463
27516
  }
27464
27517
  };
27465
27518
  for (const m of visibleMessages) {
27466
27519
  if (m.message.role === 'tool') {
27467
- console.log('[DEBUG MessageList] Adding to tool group:', m.id);
27468
27520
  toolGroup.push(m);
27469
27521
  }
27470
27522
  else if (m.message.role === 'user') {
@@ -27486,27 +27538,26 @@ const MessageList = (props) => {
27486
27538
  }
27487
27539
  }
27488
27540
  flush();
27489
- console.log('[DEBUG MessageList] Final grouped result:', result.length, 'items');
27490
- result.forEach((item, i) => {
27491
- if (item.type === 'tool-group') {
27492
- console.log(`[DEBUG MessageList] Group ${i}: tool-group with ${item.messages.length} messages`);
27493
- }
27494
- else {
27495
- console.log(`[DEBUG MessageList] Group ${i}: message (${item.message.message.role})`);
27496
- }
27497
- });
27498
27541
  return result;
27499
27542
  }, [visibleMessages]);
27543
+ // Get the last assistant message's suggestions for rendering at the end
27544
+ const lastAssistantSuggestions = React.useMemo(() => {
27545
+ for (let i = groupedMessages.length - 1; i >= 0; i--) {
27546
+ const item = groupedMessages[i];
27547
+ if (item.type === 'message' && item.message.message.role === 'assistant') {
27548
+ return item.message.suggestions;
27549
+ }
27550
+ }
27551
+ return undefined;
27552
+ }, [groupedMessages]);
27500
27553
  const hasSuggestions = visibleMessages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
27501
27554
  const showWelcome = welcomeTitle || welcomeMessage || hasSuggestions;
27502
27555
  return (jsxRuntime.jsxs("div", { ref: containerRef, className: "ai-chat-messages", role: "log", "aria-live": "polite", children: [showWelcome && (jsxRuntime.jsxs("div", { className: "ai-chat-welcome", children: [welcomeTitle && jsxRuntime.jsx("div", { className: "ai-chat-welcome-title", children: welcomeTitle }), welcomeMessage && jsxRuntime.jsx("div", { className: "ai-chat-welcome-text", children: welcomeMessage }), hasSuggestions && jsxRuntime.jsx(SuggestedQuestions, { questions: suggestedQuestions, onQuestionClick: onSuggestedQuestionClick })] })), groupedMessages.map((item, i) => {
27503
27556
  if (item.type === 'tool-group') {
27504
- return (jsxRuntime.jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant, onActionDismiss: onActionDismiss }, `tg-${i}`));
27557
+ return (jsxRuntime.jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant, onActionDismiss: onActionDismiss, onCallEndpoint: onCallEndpoint }, `tg-${i}`));
27505
27558
  }
27506
- const isLast = i === groupedMessages.length - 1;
27507
- const hasFollowUp = item.message.message.role === 'assistant' && item.message.suggestions?.length && isLast && !isTyping;
27508
- return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx(Message, { message: item.message, showTimestamp: showTimestamps, onFeedback: onFeedback, getActionRenderer: getActionRenderer, accentColor: accentColor }), hasFollowUp && onSuggestedQuestionClick && jsxRuntime.jsx(FollowUpSuggestions, { suggestions: item.message.suggestions, onQuestionClick: onSuggestedQuestionClick, onActionClick: onActionClick, accentColor: accentColor })] }, item.message.id));
27509
- }), isTyping && showTypingIndicator && !hasActiveAction && visibleMessages.length > 0 && jsxRuntime.jsx(TypingIndicator, {}), jsxRuntime.jsx("div", { ref: messagesEndRef })] }));
27559
+ return (jsxRuntime.jsx(Message, { message: item.message, showTimestamp: showTimestamps, enableFeedback: enableFeedback, onFeedback: onFeedback, getActionRenderer: getActionRenderer, accentColor: accentColor }, item.message.id));
27560
+ }), !isTyping && lastAssistantSuggestions?.length && onSuggestedQuestionClick && (jsxRuntime.jsx(FollowUpSuggestions, { suggestions: lastAssistantSuggestions, onQuestionClick: onSuggestedQuestionClick, onActionClick: onActionClick, accentColor: accentColor })), isTyping && showTypingIndicator && !hasActiveAction && visibleMessages.length > 0 && jsxRuntime.jsx(TypingIndicator, {}), jsxRuntime.jsx("div", { ref: messagesEndRef })] }));
27510
27561
  };
27511
27562
 
27512
27563
  const ALLOWED_EXTENSIONS = ['.pdf', '.doc', '.docx', '.txt', '.md', '.csv'];
@@ -27520,7 +27571,7 @@ const formatFileSize = (bytes) => {
27520
27571
  return (bytes / 1024).toFixed(1) + ' KB';
27521
27572
  return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
27522
27573
  };
27523
- const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, showDataPolicy = true, onDataPolicyClick, }) => {
27574
+ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, showDataPolicy = true, onDataPolicyClick, onInputFocus, }) => {
27524
27575
  const [value, setValue] = React.useState('');
27525
27576
  const [selectedFiles, setSelectedFiles] = React.useState([]);
27526
27577
  const textareaRef = React.useRef(null);
@@ -27555,492 +27606,15 @@ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled =
27555
27606
  }
27556
27607
  };
27557
27608
  const canSend = value.trim() || selectedFiles.length > 0;
27558
- return (jsxRuntime.jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsxRuntime.jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: "ai-chat-file-item", children: [jsxRuntime.jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxRuntime.jsxs("div", { className: "ai-chat-file-info", children: [jsxRuntime.jsx("span", { className: "ai-chat-file-name", children: file.name }), jsxRuntime.jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsxRuntime.jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxRuntime.jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsxRuntime.jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.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" }) }) })] })), jsxRuntime.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" }), jsxRuntime.jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsxRuntime.jsx("path", { d: "M12 19V5" }), jsxRuntime.jsx("path", { d: "M5 12l7-7 7 7" })] }) })] }), showDataPolicy && (jsxRuntime.jsxs("div", { className: "ai-chat-data-policy", children: [jsxRuntime.jsx("span", { children: "AI-generated responses may be inaccurate." }), onDataPolicyClick && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', jsxRuntime.jsx("button", { type: "button", className: "ai-chat-data-policy-link", onClick: onDataPolicyClick, children: "Privacy Notice" })] }))] }))] }));
27559
- };
27560
-
27561
- const CloseButton = ({ onClick, className = "", ariaLabel = "Close", }) => {
27562
- return (jsxRuntime.jsx("button", { type: "button", className: `ai-chat-action-close-btn ${className}`, onClick: onClick, "aria-label": ariaLabel, children: jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.jsx("path", { d: "M1 1L13 13M1 13L13 1" }) }) }));
27609
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsxRuntime.jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: "ai-chat-file-item", children: [jsxRuntime.jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxRuntime.jsxs("div", { className: "ai-chat-file-info", children: [jsxRuntime.jsx("span", { className: "ai-chat-file-name", children: file.name }), jsxRuntime.jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsxRuntime.jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxRuntime.jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsxRuntime.jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.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" }) }) })] })), jsxRuntime.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" }), jsxRuntime.jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsxRuntime.jsx("path", { d: "M12 19V5" }), jsxRuntime.jsx("path", { d: "M5 12l7-7 7 7" })] }) })] }), showDataPolicy && (jsxRuntime.jsxs("div", { className: "ai-chat-data-policy", children: [jsxRuntime.jsx("span", { children: "AI-generated responses may be inaccurate." }), onDataPolicyClick && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', jsxRuntime.jsx("button", { type: "button", className: "ai-chat-data-policy-link", onClick: onDataPolicyClick, children: "Privacy Notice" })] }))] }))] }));
27563
27610
  };
27564
27611
 
27565
- function groupSlotsByDate$1(slots) {
27566
- const grouped = new Map();
27567
- for (const slot of slots) {
27568
- if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
27569
- continue;
27570
- }
27571
- const date = slot.startTime.slice(0, 10);
27572
- if (!grouped.has(date)) {
27573
- grouped.set(date, []);
27574
- }
27575
- grouped.get(date).push(slot);
27576
- }
27577
- return grouped;
27578
- }
27579
- function formatDate$1(dateStr) {
27580
- try {
27581
- const date = new Date(dateStr);
27582
- return new Intl.DateTimeFormat("en-US", {
27583
- weekday: "short",
27584
- month: "short",
27585
- day: "numeric",
27586
- }).format(date);
27587
- }
27588
- catch {
27589
- return dateStr;
27590
- }
27591
- }
27592
- function CalendarIcon$1() {
27593
- return (jsxRuntime.jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntime.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" }) }));
27594
- }
27595
- function CheckIcon$1() {
27596
- return (jsxRuntime.jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntime.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" }) }));
27597
- }
27598
- function ExternalLinkIcon$2() {
27599
- return (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntime.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntime.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
27600
- }
27601
- function Skeleton$2({ width, height, borderRadius = '4px' }) {
27602
- return (jsxRuntime.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
27603
- }
27604
- function GoogleCalendarCard({ action, onComplete, onDismiss, accentColor, className = '' }) {
27605
- const state = action.state;
27606
- const rawSlots = state.availableSlots;
27607
- const availableSlots = Array.isArray(rawSlots)
27608
- ? rawSlots.filter((slot) => slot !== null &&
27609
- slot !== undefined &&
27610
- typeof slot === "object" &&
27611
- "startTime" in slot &&
27612
- "endTime" in slot &&
27613
- typeof slot.startTime === "string" &&
27614
- typeof slot.endTime === "string")
27615
- : [];
27616
- const allowTopic = state.allowTopic !== false;
27617
- const isBooked = state.status === "booked";
27618
- const slotsByDate = groupSlotsByDate$1(availableSlots);
27619
- const dates = Array.from(slotsByDate.keys()).sort();
27620
- const [selectedDate, setSelectedDate] = React.useState(dates[0] ?? "");
27621
- const [selectedSlot, setSelectedSlot] = React.useState(null);
27622
- const [topic, setTopic] = React.useState("");
27623
- const [error, setError] = React.useState(null);
27624
- const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
27625
- const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
27626
- const onConfirm = () => {
27627
- if (!selectedSlot) {
27628
- setError("Please select a time slot.");
27629
- return;
27630
- }
27631
- if (allowTopic && !topic.trim()) {
27632
- setError("Please enter a topic for the meeting.");
27633
- return;
27634
- }
27635
- setError(null);
27636
- onComplete?.(action.toolCallId, {
27637
- ...action.state,
27638
- selectedSlot: {
27639
- startTime: selectedSlot.startTime,
27640
- endTime: selectedSlot.endTime,
27641
- },
27642
- topic: allowTopic ? topic.trim() : null,
27643
- });
27644
- };
27645
- const handleDismiss = () => {
27646
- onDismiss?.(action.toolCallId);
27647
- };
27648
- // Booked state
27649
- if (isBooked) {
27650
- const bookedSlot = state.selectedSlot;
27651
- const bookedTopic = state.topic;
27652
- const eventLink = state.bookedEventLink;
27653
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsxRuntime.jsx(CheckIcon$1, {}) }), "Appointment Confirmed"] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxRuntime.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntime.jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsxRuntime.jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxRuntime.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntime.jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsxRuntime.jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), eventLink && (jsxRuntime.jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Google Calendar", jsxRuntime.jsx(ExternalLinkIcon$2, {})] }))] })] }));
27654
- }
27655
- // Skeleton loading state - show when waiting for backend after user confirms
27656
- const isWaitingForBackend = !action.done && state.selectedSlot && !isBooked;
27657
- if (isWaitingForBackend) {
27658
- return (jsxRuntime.jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsxRuntime.jsx(Skeleton$2, { width: "28px", height: "28px", borderRadius: "50%" }), jsxRuntime.jsx(Skeleton$2, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntime.jsx(Skeleton$2, { width: "60px", height: "12px", borderRadius: "4px" }), jsxRuntime.jsx(Skeleton$2, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntime.jsx(Skeleton$2, { width: "50px", height: "12px", borderRadius: "4px" }), jsxRuntime.jsx(Skeleton$2, { width: "200px", height: "18px", borderRadius: "4px" })] }), jsxRuntime.jsx(Skeleton$2, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
27659
- }
27660
- // Booking form
27661
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ai-chat-google-calendar ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(CalendarIcon$1, {}), "Schedule an Appointment", onDismiss && (jsxRuntime.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxRuntime.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntime.jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsxRuntime.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) })] })), jsxRuntime.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntime.jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsxRuntime.jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsxRuntime.jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
27662
- setSelectedDate(date);
27663
- setSelectedSlot(null);
27664
- }, children: formatDate$1(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxRuntime.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntime.jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsxRuntime.jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsxRuntime.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 && jsxRuntime.jsx("div", { className: "ai-chat-action-error", children: error }), jsxRuntime.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: onConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsxRuntime.jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
27665
- }
27666
-
27667
- function groupSlotsByDate(slots) {
27668
- const grouped = new Map();
27669
- for (const slot of slots) {
27670
- if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
27671
- continue;
27672
- }
27673
- const date = slot.startTime.slice(0, 10);
27674
- if (!grouped.has(date)) {
27675
- grouped.set(date, []);
27676
- }
27677
- grouped.get(date).push(slot);
27678
- }
27679
- return grouped;
27680
- }
27681
- function formatDate(dateStr) {
27682
- try {
27683
- const date = new Date(dateStr);
27684
- return new Intl.DateTimeFormat("en-US", {
27685
- weekday: "short",
27686
- month: "short",
27687
- day: "numeric",
27688
- }).format(date);
27689
- }
27690
- catch {
27691
- return dateStr;
27692
- }
27693
- }
27694
- function CalendarIcon() {
27695
- return (jsxRuntime.jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntime.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" }) }));
27696
- }
27697
- function MailIcon() {
27698
- return (jsxRuntime.jsxs("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z" }), jsxRuntime.jsx("path", { d: "M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z" })] }));
27699
- }
27700
- function CheckIcon() {
27701
- return (jsxRuntime.jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntime.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" }) }));
27702
- }
27703
- function ErrorIcon() {
27704
- return (jsxRuntime.jsx("svg", { className: "ai-chat-action-icon-error", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntime.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" }) }));
27705
- }
27706
- function ExternalLinkIcon$1() {
27707
- return (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntime.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntime.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
27708
- }
27709
- function Skeleton$1({ width, height, borderRadius = '4px' }) {
27710
- return (jsxRuntime.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
27711
- }
27712
- function PinInputGroup$1({ values, onChange, disabled }) {
27713
- const inputRefs = React.useRef([]);
27714
- const handleChange = (index, value) => {
27715
- // Only allow digits
27716
- const digit = value.replace(/[^0-9]/g, '');
27717
- const newValues = [...values];
27718
- newValues[index] = digit.slice(-1);
27719
- onChange(newValues);
27720
- // Auto-focus next input
27721
- if (digit && index < 5) {
27722
- inputRefs.current[index + 1]?.focus();
27723
- }
27724
- };
27725
- const handleKeyDown = (index, e) => {
27726
- if (e.key === 'Backspace' && !values[index] && index > 0) {
27727
- inputRefs.current[index - 1]?.focus();
27728
- }
27729
- };
27730
- const handlePaste = (e) => {
27731
- e.preventDefault();
27732
- const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, 6);
27733
- const newValues = pastedData.split('').concat(Array(6 - pastedData.length).fill(''));
27734
- onChange(newValues);
27735
- // Focus the next empty input or the last one
27736
- const nextIndex = Math.min(pastedData.length, 5);
27737
- inputRefs.current[nextIndex]?.focus();
27738
- };
27739
- return (jsxRuntime.jsx("div", { className: "ai-chat-pin-input-group", children: values.map((value, index) => (jsxRuntime.jsx("input", { ref: (el) => {
27740
- inputRefs.current[index] = el;
27741
- }, 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))) }));
27742
- }
27743
- function MicrosoftCalendarCard({ action, onComplete, onDismiss, accentColor, className = '' }) {
27744
- const state = action.state;
27745
- const phase = state.phase || "awaiting_email";
27746
- const allowTopic = state.allowTopic !== false;
27747
- const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
27748
- const handleDismiss = () => {
27749
- onDismiss?.(action.toolCallId);
27750
- };
27751
- const showCloseButton = Boolean(onDismiss);
27752
- // Debug: Log state changes
27753
- const prevStateRef = React.useRef(null);
27754
- React.useEffect(() => {
27755
- if (JSON.stringify(prevStateRef.current) !== JSON.stringify(state)) {
27756
- console.log('[MicrosoftCalendarCard] State updated:', {
27757
- phase: state.phase,
27758
- hasError: !!state.errorMessage,
27759
- error: state.errorMessage,
27760
- slotsCount: state.availableSlots?.length || 0
27761
- });
27762
- prevStateRef.current = state;
27763
- }
27764
- }, [state]);
27765
- // Email phase state
27766
- const [email, setEmail] = React.useState("");
27767
- const [emailError, setEmailError] = React.useState(null);
27768
- // OTP phase state
27769
- const [otpValues, setOtpValues] = React.useState(Array(6).fill(''));
27770
- const [otpError, setOtpError] = React.useState(null);
27771
- // Loading states
27772
- const [isSubmitting, setIsSubmitting] = React.useState(false);
27773
- // Reset loading state when phase changes (backend has responded)
27774
- // Use useEffect for reliable re-rendering
27775
- React.useEffect(() => {
27776
- console.log('[MicrosoftCalendarCard] Phase changed to:', phase);
27777
- setIsSubmitting(false);
27778
- // Clear errors when transitioning to new phase
27779
- if (phase === "awaiting_email") {
27780
- setEmailError(null);
27781
- setOtpError(null);
27782
- setSelectionError(null);
27783
- }
27784
- else if (phase === "awaiting_otp") {
27785
- setOtpError(state.errorMessage || null);
27786
- setEmailError(null);
27787
- setSelectionError(null);
27788
- // Clear OTP input for fresh attempt
27789
- setOtpValues(Array(6).fill(''));
27790
- }
27791
- else if (phase === "awaiting_options") {
27792
- setEmailError(null);
27793
- setOtpError(null);
27794
- setSelectionError(null);
27795
- }
27796
- else if (phase === "awaiting_booking") {
27797
- setSelectionError(state.errorMessage || null);
27798
- setEmailError(null);
27799
- setOtpError(null);
27800
- }
27801
- else if (phase === "booked" || phase === "cancelled" || phase === "error") {
27802
- setEmailError(null);
27803
- setOtpError(null);
27804
- setSelectionError(null);
27805
- setSelectedId(null); // Reset selection
27806
- }
27807
- }, [phase, state.errorMessage]);
27808
- // Selection phase state
27809
- const rawSlots = state.availableSlots;
27810
- const availableSlots = Array.isArray(rawSlots)
27811
- ? rawSlots.filter((slot) => slot !== null &&
27812
- slot !== undefined &&
27813
- typeof slot === "object" &&
27814
- "startTime" in slot &&
27815
- "endTime" in slot &&
27816
- typeof slot.startTime === "string" &&
27817
- typeof slot.endTime === "string")
27818
- : [];
27819
- const slotsByDate = groupSlotsByDate(availableSlots);
27820
- const dates = Array.from(slotsByDate.keys()).sort();
27821
- const [selectedDate, setSelectedDate] = React.useState(dates[0] ?? "");
27822
- const [selectedSlot, setSelectedSlot] = React.useState(null);
27823
- const [topic, setTopic] = React.useState("");
27824
- const [selectionError, setSelectionError] = React.useState(null);
27825
- // Cancellation phase state
27826
- const [selectedId, setSelectedId] = React.useState(null);
27827
- const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
27828
- // Phase 1: Email Input
27829
- const handleEmailSubmit = () => {
27830
- const trimmedEmail = email.trim();
27831
- if (!trimmedEmail) {
27832
- setEmailError("Please enter your email address");
27833
- return;
27834
- }
27835
- if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmedEmail)) {
27836
- setEmailError("Please enter a valid email address");
27837
- return;
27838
- }
27839
- setEmailError(null);
27840
- setIsSubmitting(true);
27841
- console.log('[MicrosoftCalendarCard] Submitting email:', trimmedEmail);
27842
- setTimeout(() => {
27843
- onComplete?.(action.toolCallId, {
27844
- ...action.state,
27845
- email: trimmedEmail,
27846
- });
27847
- }, 50);
27848
- };
27849
- // Phase 2: OTP Verification
27850
- const handleOtpSubmit = () => {
27851
- const otpCode = otpValues.join('');
27852
- if (otpCode.length !== 6) {
27853
- setOtpError("Please enter the 6-digit code");
27854
- return;
27855
- }
27856
- setOtpError(null);
27857
- setIsSubmitting(true);
27858
- console.log('[MicrosoftCalendarCard] Submitting OTP code');
27859
- setTimeout(() => {
27860
- onComplete?.(action.toolCallId, {
27861
- ...action.state,
27862
- otpCode,
27863
- });
27864
- }, 50);
27865
- };
27866
- // Phase 3: Appointment Selection
27867
- const handleAppointmentConfirm = () => {
27868
- if (!selectedSlot) {
27869
- setSelectionError("Please select a time slot");
27870
- return;
27871
- }
27872
- if (allowTopic && !topic.trim()) {
27873
- setSelectionError("Please enter a meeting topic");
27874
- return;
27875
- }
27876
- setSelectionError(null);
27877
- setIsSubmitting(true);
27878
- console.log('[MicrosoftCalendarCard] Confirming appointment:', {
27879
- slot: selectedSlot,
27880
- topic: topic.trim()
27881
- });
27882
- setTimeout(() => {
27883
- onComplete?.(action.toolCallId, {
27884
- ...action.state,
27885
- selectedSlot: {
27886
- startTime: selectedSlot.startTime,
27887
- endTime: selectedSlot.endTime,
27888
- },
27889
- topic: allowTopic ? topic.trim() : null,
27890
- });
27891
- }, 50);
27892
- };
27893
- // Handle "Use different email" button
27894
- const handleUseDifferentEmail = () => {
27895
- setEmail("");
27896
- setEmailError(null);
27897
- setOtpValues(Array(6).fill(''));
27898
- setOtpError(null);
27899
- onComplete?.(action.toolCallId, {
27900
- phase: "awaiting_email",
27901
- email: null,
27902
- otpVerified: false,
27903
- otpAttempts: 0,
27904
- availableSlots: [],
27905
- selectedSlot: null,
27906
- topic: null,
27907
- bookedEventId: null,
27908
- bookedEventLink: null,
27909
- allowTopic,
27910
- errorMessage: null,
27911
- });
27912
- };
27913
- // Phase 5: Booked Confirmation
27914
- if (phase === "booked") {
27915
- const bookedSlot = state.selectedSlot;
27916
- const bookedTopic = state.topic;
27917
- const eventLink = state.bookedEventLink;
27918
- const bookedEmail = state.email;
27919
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsxRuntime.jsx(CheckIcon, {}) }), "Appointment Confirmed"] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxRuntime.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntime.jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsxRuntime.jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxRuntime.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntime.jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsxRuntime.jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), bookedEmail && (jsxRuntime.jsxs("div", { className: "ai-chat-action-hint", children: ["A calendar invitation has been sent to ", bookedEmail] })), eventLink && (jsxRuntime.jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Outlook Calendar", jsxRuntime.jsx(ExternalLinkIcon$1, {})] }))] })] }));
27920
- }
27921
- // Phase 6: Cancelled Confirmation
27922
- if (phase === "cancelled") {
27923
- const cancelledSubject = state.cancelledEventSubject;
27924
- const userEmail = state.email;
27925
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsxRuntime.jsx(CheckIcon, {}) }), "Appointment Cancelled"] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-body", children: [cancelledSubject && (jsxRuntime.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntime.jsx("span", { className: "ai-chat-action-label-small", children: "CANCELLED" }), jsxRuntime.jsx("span", { className: "ai-chat-action-value-large", children: cancelledSubject })] })), userEmail && (jsxRuntime.jsxs("div", { className: "ai-chat-action-hint", children: ["A cancellation notice has been sent to ", userEmail] }))] })] }));
27926
- }
27927
- // Error State
27928
- if (phase === "error") {
27929
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-action-error ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(ErrorIcon, {}), "Error"] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntime.jsx("div", { className: "ai-chat-action-error-message", children: state.errorMessage || "An error occurred. Please try again." }), jsxRuntime.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
27930
- setEmail("");
27931
- setEmailError(null);
27932
- setOtpValues(Array(6).fill(''));
27933
- setOtpError(null);
27934
- onComplete?.(action.toolCallId, {
27935
- phase: "awaiting_email",
27936
- email: null,
27937
- otpVerified: false,
27938
- otpAttempts: 0,
27939
- availableSlots: [],
27940
- selectedSlot: null,
27941
- topic: null,
27942
- bookedEventId: null,
27943
- bookedEventLink: null,
27944
- allowTopic,
27945
- errorMessage: null,
27946
- });
27947
- }, children: "Start Over" })] })] }));
27948
- }
27949
- // Loading State
27950
- if (isSubmitting) {
27951
- return (jsxRuntime.jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsxRuntime.jsx(Skeleton$1, { width: "28px", height: "28px", borderRadius: "50%" }), jsxRuntime.jsx(Skeleton$1, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntime.jsx(Skeleton$1, { width: "60px", height: "12px", borderRadius: "4px" }), jsxRuntime.jsx(Skeleton$1, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxRuntime.jsx(Skeleton$1, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
27952
- }
27953
- // Phase 1: Email Input
27954
- if (phase === "awaiting_email") {
27955
- const displayError = state.errorMessage || emailError;
27956
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(CalendarIcon, {}), "Schedule an Appointment", showCloseButton && (jsxRuntime.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntime.jsx("div", { className: "ai-chat-action-hint", children: "We'll send a verification code to your email" }), jsxRuntime.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntime.jsx("label", { htmlFor: `email-${action.toolCallId}`, className: "ai-chat-action-label", children: "Email Address" }), jsxRuntime.jsx("input", { id: `email-${action.toolCallId}`, type: "email", className: "ai-chat-action-input", placeholder: "your@email.com", value: email, onChange: (e) => {
27957
- setEmail(e.target.value);
27958
- setEmailError(null);
27959
- }, onKeyPress: (e) => {
27960
- if (e.key === 'Enter') {
27961
- handleEmailSubmit();
27962
- }
27963
- }, autoFocus: true })] }), displayError && (jsxRuntime.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntime.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleEmailSubmit, children: "Continue" })] })] }));
27964
- }
27965
- // Phase 2: OTP Input
27966
- if (phase === "awaiting_otp") {
27967
- const displayError = state.errorMessage || otpError;
27968
- const userEmail = state.email;
27969
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(MailIcon, {}), "Verify Your Email", showCloseButton && (jsxRuntime.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-hint", children: ["We sent a 6-digit code to ", jsxRuntime.jsx("strong", { children: userEmail })] }), jsxRuntime.jsx(PinInputGroup$1, { values: otpValues, onChange: (newValues) => {
27970
- setOtpValues(newValues);
27971
- setOtpError(null);
27972
- // Auto-submit when all 6 digits are entered
27973
- if (newValues.every(v => v.length === 1)) {
27974
- console.log('[MicrosoftCalendarCard] Auto-submitting OTP (all 6 digits entered)');
27975
- setIsSubmitting(true);
27976
- const code = newValues.join('');
27977
- setTimeout(() => {
27978
- onComplete?.(action.toolCallId, {
27979
- ...action.state,
27980
- otpCode: code,
27981
- });
27982
- }, 100);
27983
- }
27984
- }, disabled: isSubmitting }), displayError && (jsxRuntime.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntime.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleOtpSubmit, disabled: otpValues.join('').length !== 6, children: "Verify Code" }), jsxRuntime.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: handleUseDifferentEmail, children: "Use different email" })] })] }));
27985
- }
27986
- // Phase 3: Options Menu (with inline cancel buttons and confirmation)
27987
- if (phase === "awaiting_options") {
27988
- const userAppointments = state.userAppointments || [];
27989
- const maxAppointments = state.maxAppointmentsPerUser || 3;
27990
- const appointmentCount = userAppointments.length;
27991
- const canBook = appointmentCount < maxAppointments;
27992
- const hasAppointments = appointmentCount > 0;
27993
- const displayError = state.errorMessage || selectionError;
27994
- // If confirming cancellation, show confirmation dialog
27995
- if (selectedId) {
27996
- const appointmentToCancel = userAppointments.find(appt => appt.id === selectedId);
27997
- if (!appointmentToCancel) {
27998
- setSelectedId(null); // Reset if appointment not found
27999
- }
28000
- else {
28001
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(CalendarIcon, {}), "Confirm Cancellation", showCloseButton && (jsxRuntime.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntime.jsx("div", { className: "ai-chat-action-hint", children: "Are you sure you want to cancel this appointment?" }), jsxRuntime.jsx("div", { className: "ai-chat-action-appointment-item", style: { marginBottom: '16px' }, children: jsxRuntime.jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsxRuntime.jsx("div", { className: "ai-chat-action-appointment-subject", children: appointmentToCancel.subject }), jsxRuntime.jsx("div", { className: "ai-chat-action-appointment-time", children: appointmentToCancel.displayTime })] }) }), displayError && (jsxRuntime.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntime.jsxs("div", { className: "ai-chat-action-button-group", children: [jsxRuntime.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
28002
- setIsSubmitting(true);
28003
- onComplete?.(action.toolCallId, {
28004
- ...action.state,
28005
- selectedOption: "cancel",
28006
- selectedAppointmentId: selectedId,
28007
- });
28008
- }, disabled: isSubmitting, children: isSubmitting ? 'Cancelling...' : 'Confirm Cancellation' }), jsxRuntime.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
28009
- setSelectedId(null);
28010
- setSelectionError(null);
28011
- }, disabled: isSubmitting, children: "Go Back" })] })] })] }));
28012
- }
28013
- }
28014
- // Normal view with inline cancel buttons
28015
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(CalendarIcon, {}), "Manage Your Appointments", showCloseButton && (jsxRuntime.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntime.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 && (jsxRuntime.jsxs("div", { className: "ai-chat-action-appointment-list", children: [jsxRuntime.jsx("div", { className: "ai-chat-action-label", children: "Your Upcoming Appointments" }), userAppointments.map((appt) => (jsxRuntime.jsxs("div", { className: "ai-chat-action-appointment-item", children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsxRuntime.jsx("div", { className: "ai-chat-action-appointment-subject", children: appt.subject }), jsxRuntime.jsx("div", { className: "ai-chat-action-appointment-time", children: appt.displayTime })] }), jsxRuntime.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
28016
- setSelectedId(appt.id);
28017
- setSelectionError(null);
28018
- }, children: "Cancel" })] }, appt.id)))] })), displayError && (jsxRuntime.jsx("div", { className: "ai-chat-action-error", children: displayError })), canBook && (jsxRuntime.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
28019
- setIsSubmitting(true);
28020
- onComplete?.(action.toolCallId, {
28021
- ...action.state,
28022
- selectedOption: "book",
28023
- });
28024
- }, disabled: isSubmitting, children: isSubmitting ? 'Loading...' : 'Book New Appointment' })), !canBook && !hasAppointments && (jsxRuntime.jsx("div", { className: "ai-chat-action-hint", children: "No appointments found." }))] })] }));
28025
- }
28026
- // Phase 4: Appointment Selection (Booking)
28027
- if (phase === "awaiting_booking") {
28028
- const displayError = state.errorMessage || selectionError;
28029
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(CalendarIcon, {}), "Select Appointment Time", showCloseButton && (jsxRuntime.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxRuntime.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntime.jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsxRuntime.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) })] })), jsxRuntime.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntime.jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsxRuntime.jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsxRuntime.jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
28030
- setSelectedDate(date);
28031
- setSelectedSlot(null);
28032
- }, children: formatDate(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxRuntime.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntime.jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsxRuntime.jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsxRuntime.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 && (jsxRuntime.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntime.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleAppointmentConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsxRuntime.jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
28033
- }
28034
- // Fallback
28035
- return null;
28036
- }
28037
-
28038
- function truncate(text, maxLength) {
27612
+ function truncate$1(text, maxLength) {
28039
27613
  if (text.length <= maxLength)
28040
27614
  return text;
28041
27615
  return text.slice(0, maxLength).trim() + '...';
28042
27616
  }
28043
- function ExternalLinkIcon() {
27617
+ function ExternalLinkIcon$2() {
28044
27618
  return (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntime.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntime.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
28045
27619
  }
28046
27620
  function SingleLinkPreview({ link, onLinkClick, accentColor }) {
@@ -28059,10 +27633,10 @@ function SingleLinkPreview({ link, onLinkClick, accentColor }) {
28059
27633
  e.currentTarget.parentElement.style.display = 'none';
28060
27634
  } }) })), jsxRuntime.jsxs("div", { className: "ai-chat-link-preview__content", children: [jsxRuntime.jsxs("div", { className: "ai-chat-link-preview__site", children: [link.favicon && (jsxRuntime.jsx("img", { src: link.favicon, alt: "", className: "ai-chat-link-preview__favicon", onError: (e) => {
28061
27635
  e.currentTarget.style.display = 'none';
28062
- } })), jsxRuntime.jsx("span", { className: "ai-chat-link-preview__domain", children: link.siteName || domain })] }), jsxRuntime.jsx("h4", { className: "ai-chat-link-preview__title", children: link.title }), link.description && (jsxRuntime.jsx("p", { className: "ai-chat-link-preview__description", children: truncate(link.description, 120) }))] }), jsxRuntime.jsx("div", { className: "ai-chat-link-preview__arrow", children: jsxRuntime.jsx(ExternalLinkIcon, {}) })] }));
27636
+ } })), jsxRuntime.jsx("span", { className: "ai-chat-link-preview__domain", children: link.siteName || domain })] }), jsxRuntime.jsx("h4", { className: "ai-chat-link-preview__title", children: link.title }), link.description && (jsxRuntime.jsx("p", { className: "ai-chat-link-preview__description", children: truncate$1(link.description, 120) }))] }), jsxRuntime.jsx("div", { className: "ai-chat-link-preview__arrow", children: jsxRuntime.jsx(ExternalLinkIcon$2, {}) })] }));
28063
27637
  }
28064
27638
  function LinkPreviewCard({ action, onComplete, accentColor }) {
28065
- const rawState = action.state;
27639
+ const rawState = action.input;
28066
27640
  const hasCompletedRef = React.useRef(false);
28067
27641
  // Provide safe defaults if state is missing
28068
27642
  const state = {
@@ -28092,11 +27666,12 @@ function LinkPreviewCard({ action, onComplete, accentColor }) {
28092
27666
  if (state.links.length === 0) {
28093
27667
  return null;
28094
27668
  }
28095
- return (jsxRuntime.jsxs("div", { className: "ai-chat-link-preview-container", children: [state.context && (jsxRuntime.jsx("p", { className: "ai-chat-link-preview__context", style: { marginBottom: '8px', fontSize: '0.9em', color: 'var(--ai-chat-fg-muted)' }, children: state.context })), jsxRuntime.jsx("div", { className: "ai-chat-link-preview-grid", style: {
28096
- display: 'grid',
28097
- gridTemplateColumns: state.links.length === 1 ? '1fr' : state.links.length === 2 ? 'repeat(2, 1fr)' : 'repeat(3, 1fr)',
28098
- gap: '12px',
28099
- }, children: state.links.map((link, index) => (jsxRuntime.jsx(SingleLinkPreview, { link: link, onLinkClick: () => handleLinkClick(link.url), accentColor: accentColor }, index))) })] }));
27669
+ const gridClass = state.links.length === 1
27670
+ ? 'ai-chat-link-preview-grid ai-chat-link-preview-grid--single'
27671
+ : state.links.length === 2
27672
+ ? 'ai-chat-link-preview-grid ai-chat-link-preview-grid--double'
27673
+ : 'ai-chat-link-preview-grid ai-chat-link-preview-grid--triple';
27674
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-link-preview-container", children: [state.context && (jsxRuntime.jsx("p", { className: "ai-chat-link-preview__context", style: { marginBottom: '8px', fontSize: '0.9em', color: 'var(--ai-chat-fg-muted)' }, children: state.context })), jsxRuntime.jsx("div", { className: gridClass, children: state.links.map((link, index) => (jsxRuntime.jsx(SingleLinkPreview, { link: link, onLinkClick: () => handleLinkClick(link.url), accentColor: accentColor }, index))) })] }));
28100
27675
  }
28101
27676
 
28102
27677
  function PlayIcon() {
@@ -28117,7 +27692,7 @@ function getProviderLabel(provider) {
28117
27692
  }
28118
27693
  }
28119
27694
  function VideoPlayerCard({ action, onComplete, accentColor }) {
28120
- const rawState = action.state;
27695
+ const rawState = action.input;
28121
27696
  const hasCompletedRef = React.useRef(false);
28122
27697
  const [isPlaying, setIsPlaying] = React.useState(false);
28123
27698
  // Provide safe defaults if state is missing
@@ -28228,7 +27803,7 @@ function LocationItem({ location, settings, accentColor, onDirections, showMap =
28228
27803
  return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-location-card ${compact ? 'ai-chat-location-card--compact' : ''}`, style: style, children: [showMap && settings.showMap !== false && (jsxRuntime.jsx("div", { className: "ai-chat-location-card__map", style: { height: effectiveMapHeight }, children: jsxRuntime.jsx("iframe", { src: getMapEmbedUrl(), allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade", title: `Map of ${location.name}` }) })), jsxRuntime.jsxs("div", { className: "ai-chat-location-card__content", children: [jsxRuntime.jsxs("div", { className: "ai-chat-location-card__header", children: [jsxRuntime.jsx("h4", { className: "ai-chat-location-card__name", children: location.name }), location.type && (jsxRuntime.jsx("span", { className: "ai-chat-location-card__type", children: location.type })), openStatus !== null && (jsxRuntime.jsx("span", { className: `ai-chat-location-card__status ai-chat-location-card__status--${openStatus ? 'open' : 'closed'}`, children: openStatus ? 'Open' : 'Closed' }))] }), jsxRuntime.jsxs("p", { className: "ai-chat-location-card__address", children: [jsxRuntime.jsx(MapPinIcon, {}), location.address] }), location.description && (jsxRuntime.jsx("p", { className: "ai-chat-location-card__description", children: location.description })), settings.showHours !== false && location.hours && location.hours.length > 0 && (jsxRuntime.jsx(HoursDisplay, { hours: location.hours, compact: compact })), settings.showPhone !== false && location.phone && (jsxRuntime.jsxs("button", { type: "button", className: "ai-chat-location-card__phone", onClick: handleCall, children: [jsxRuntime.jsx(PhoneIcon, {}), location.phone] })), jsxRuntime.jsxs("div", { className: "ai-chat-location-card__actions", children: [settings.showDirectionsButton !== false && (jsxRuntime.jsxs("button", { type: "button", className: "ai-chat-location-card__button", style: accentColor ? { backgroundColor: accentColor } : undefined, onClick: onDirections, children: [jsxRuntime.jsx(NavigationIcon, {}), compact ? 'Directions' : 'Get Directions'] })), !compact && location.website && (jsxRuntime.jsxs("a", { href: location.website, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-location-card__link", children: [jsxRuntime.jsx(GlobeIcon, {}), "Website"] }))] })] })] }));
28229
27804
  }
28230
27805
  function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28231
- const rawState = action.state;
27806
+ const rawState = action.input;
28232
27807
  const hasCompletedRef = React.useRef(false);
28233
27808
  const state = {
28234
27809
  locations: rawState?.locations || [],
@@ -28310,7 +27885,7 @@ function ContactItem({ contact, settings, accentColor, onEmail, onPhone, compact
28310
27885
  })()] }), jsxRuntime.jsxs("div", { className: "ai-chat-contact-card__info", children: [jsxRuntime.jsx("h4", { className: "ai-chat-contact-card__name", children: contact.name }), settings.showRole !== false && contact.role && (jsxRuntime.jsx("p", { className: "ai-chat-contact-card__role", children: contact.role })), jsxRuntime.jsxs("div", { className: "ai-chat-contact-card__details", children: [settings.showEmail !== false && contact.email && (jsxRuntime.jsx("a", { href: `mailto:${contact.email}`, className: "ai-chat-contact-card__detail", onClick: onEmail, children: contact.email })), settings.showPhone !== false && contact.phone && (jsxRuntime.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 && (jsxRuntime.jsxs("div", { className: "ai-chat-contact-card__responsibilities", children: [contact.responsibilities.slice(0, 3).map((resp, idx) => (jsxRuntime.jsx("span", { className: "ai-chat-contact-card__responsibility-tag", children: resp }, idx))), contact.responsibilities.length > 3 && (jsxRuntime.jsxs("span", { className: "ai-chat-contact-card__responsibility-more", children: ["+", contact.responsibilities.length - 3, " more"] }))] }))] })] }));
28311
27886
  }
28312
27887
  function ContactCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28313
- const rawState = action.state;
27888
+ const rawState = action.input;
28314
27889
  const hasCompletedRef = React.useRef(false);
28315
27890
  const state = {
28316
27891
  contacts: rawState?.contacts || [],
@@ -28345,11 +27920,37 @@ function ContactCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28345
27920
  }, children: contacts.map((contact) => (jsxRuntime.jsx(ContactItem, { contact: contact, settings: settings, accentColor: accentColor, onEmail: handleContact, onPhone: handleContact, compact: true, layout: settings.layout || 'vertical' }, contact.id))) })] }));
28346
27921
  }
28347
27922
 
27923
+ const CloseButton = ({ onClick, className = "", ariaLabel = "Close", }) => {
27924
+ return (jsxRuntime.jsx("button", { type: "button", className: `ai-chat-action-close-btn ${className}`, onClick: onClick, "aria-label": ariaLabel, children: jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.jsx("path", { d: "M1 1L13 13M1 13L13 1" }) }) }));
27925
+ };
27926
+
27927
+ function FormIcon(props) {
27928
+ return (jsxRuntime.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: [jsxRuntime.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" }), jsxRuntime.jsx("polyline", { points: "14,2 14,8 20,8" }), jsxRuntime.jsx("line", { x1: "16", y1: "13", x2: "8", y2: "13" }), jsxRuntime.jsx("line", { x1: "16", y1: "17", x2: "8", y2: "17" }), jsxRuntime.jsx("line", { x1: "10", y1: "9", x2: "8", y2: "9" })] }));
27929
+ }
27930
+ function CheckIcon(props) {
27931
+ return (jsxRuntime.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: jsxRuntime.jsx("polyline", { points: "20,6 9,17 4,12" }) }));
27932
+ }
27933
+ function WarningIcon(props) {
27934
+ return (jsxRuntime.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: [jsxRuntime.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" }), jsxRuntime.jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }), jsxRuntime.jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })] }));
27935
+ }
27936
+ function SkipIcon(props) {
27937
+ return (jsxRuntime.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: [jsxRuntime.jsx("polygon", { points: "5,4 15,12 5,20 5,4" }), jsxRuntime.jsx("line", { x1: "19", y1: "5", x2: "19", y2: "19" })] }));
27938
+ }
27939
+ function BackArrowIcon(props) {
27940
+ return (jsxRuntime.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: jsxRuntime.jsx("polyline", { points: "15,18 9,12 15,6" }) }));
27941
+ }
27942
+
28348
27943
  function FormCard({ action, onComplete, onDismiss, accentColor }) {
28349
- const state = action.state;
27944
+ const state = action.input;
28350
27945
  const [currentStep, setCurrentStep] = React.useState(0);
28351
27946
  const [answers, setAnswers] = React.useState({});
28352
27947
  const [isSubmitting, setIsSubmitting] = React.useState(false);
27948
+ const [localStatus, setLocalStatus] = React.useState(null);
27949
+ // If action is already done, show simple completion indicator
27950
+ // The agent's response will convey what happened
27951
+ if (action.done) {
27952
+ return (jsxRuntime.jsx("div", { className: "ai-chat-form-card ai-chat-form-card--completed", children: jsxRuntime.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntime.jsx(CheckIcon, {}) }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__title", children: "Form completed" })] }) }));
27953
+ }
28353
27954
  const questions = state.questions || [];
28354
27955
  const currentQuestion = questions[currentStep];
28355
27956
  const totalQuestions = questions.length;
@@ -28370,6 +27971,7 @@ function FormCard({ action, onComplete, onDismiss, accentColor }) {
28370
27971
  if (!onComplete)
28371
27972
  return;
28372
27973
  setIsSubmitting(true);
27974
+ setLocalStatus('submitted');
28373
27975
  const formattedAnswers = Object.entries(answers).map(([questionId, value]) => ({
28374
27976
  questionId,
28375
27977
  value,
@@ -28383,6 +27985,7 @@ function FormCard({ action, onComplete, onDismiss, accentColor }) {
28383
27985
  const handleSkip = () => {
28384
27986
  if (!onComplete || !state.settings.allowSkip)
28385
27987
  return;
27988
+ setLocalStatus('skipped');
28386
27989
  onComplete(action.toolCallId, {
28387
27990
  ...state,
28388
27991
  status: 'skipped',
@@ -28413,24 +28016,26 @@ function FormCard({ action, onComplete, onDismiss, accentColor }) {
28413
28016
  const handleDismiss = () => {
28414
28017
  onDismiss?.(action.toolCallId);
28415
28018
  };
28019
+ // Use local status if available (for immediate UI feedback), otherwise use state.status
28020
+ const effectiveStatus = localStatus || state.status;
28416
28021
  // Error state
28417
- if (state.status === 'error') {
28418
- return (jsxRuntime.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--error", children: [jsxRuntime.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-form-card__icon", children: "\u26A0\uFE0F" }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__title", children: "Form Error" })] }), jsxRuntime.jsx("p", { className: "ai-chat-form-card__error", children: state.error || 'Could not load form' })] }));
28022
+ if (effectiveStatus === 'error') {
28023
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--error", children: [jsxRuntime.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntime.jsx(WarningIcon, {}) }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__title", children: "Form Error" })] }), jsxRuntime.jsx("p", { className: "ai-chat-form-card__error", children: state.error || 'Could not load form' })] }));
28419
28024
  }
28420
28025
  // Submitted state
28421
- if (state.status === 'submitted' || action.done) {
28422
- return (jsxRuntime.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--submitted", children: [jsxRuntime.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-form-card__icon", children: "\u2713" }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntime.jsx("p", { className: "ai-chat-form-card__success", children: state.settings.successMessage || 'Thank you for your response!' })] }));
28026
+ if (effectiveStatus === 'submitted') {
28027
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--submitted", children: [jsxRuntime.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntime.jsx(CheckIcon, {}) }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntime.jsx("p", { className: "ai-chat-form-card__success", children: state.settings.successMessage || 'Thank you for your response!' })] }));
28423
28028
  }
28424
28029
  // Skipped state
28425
- if (state.status === 'skipped') {
28426
- return (jsxRuntime.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--skipped", children: [jsxRuntime.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-form-card__icon", children: "\u21B7" }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntime.jsx("p", { className: "ai-chat-form-card__skipped-text", children: "Form skipped" })] }));
28030
+ if (effectiveStatus === 'skipped') {
28031
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--skipped", children: [jsxRuntime.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntime.jsx(SkipIcon, {}) }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntime.jsx("p", { className: "ai-chat-form-card__skipped-text", children: "Form skipped" })] }));
28427
28032
  }
28428
28033
  // No questions
28429
28034
  if (totalQuestions === 0) {
28430
- return (jsxRuntime.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--empty", children: [jsxRuntime.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-form-card__icon", children: "\uD83D\uDCCB" }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntime.jsx("p", { className: "ai-chat-form-card__empty-text", children: "This form has no questions." })] }));
28035
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--empty", children: [jsxRuntime.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntime.jsx(FormIcon, {}) }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntime.jsx("p", { className: "ai-chat-form-card__empty-text", children: "This form has no questions." })] }));
28431
28036
  }
28432
- const showCloseButton = state.status === "displaying" && !action.done && Boolean(onDismiss);
28433
- return (jsxRuntime.jsxs("div", { className: `ai-chat-form-card${showCloseButton ? " ai-chat-form-card--closable" : ""}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-form-card__icon", children: "\uD83D\uDCCB" }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__title", children: state.title }), showCloseButton && (jsxRuntime.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Close form" }))] }), state.description && (jsxRuntime.jsx("p", { className: "ai-chat-form-card__description", children: state.description })), state.context && (jsxRuntime.jsx("p", { className: "ai-chat-form-card__context", children: state.context })), state.settings.showProgress && (jsxRuntime.jsxs("div", { className: "ai-chat-form-card__progress", children: [jsxRuntime.jsx("div", { className: "ai-chat-form-card__progress-bar", style: {
28037
+ const showCloseButton = effectiveStatus === "displaying" && !action.done && Boolean(onDismiss);
28038
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-form-card${showCloseButton ? " ai-chat-form-card--closable" : ""}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntime.jsx(FormIcon, {}) }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__title", children: state.title }), showCloseButton && (jsxRuntime.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Close form" }))] }), state.description && (jsxRuntime.jsx("p", { className: "ai-chat-form-card__description", children: state.description })), state.context && (jsxRuntime.jsx("p", { className: "ai-chat-form-card__context", children: state.context })), state.settings.showProgress && (jsxRuntime.jsxs("div", { className: "ai-chat-form-card__progress", children: [jsxRuntime.jsx("div", { className: "ai-chat-form-card__progress-bar", style: {
28434
28039
  width: `${((currentStep + 1) / totalQuestions) * 100}%`,
28435
28040
  backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
28436
28041
  } }), jsxRuntime.jsxs("span", { className: "ai-chat-form-card__progress-text", children: [currentStep + 1, " of ", totalQuestions] })] })), jsxRuntime.jsxs("div", { className: "ai-chat-form-card__question", children: [jsxRuntime.jsxs("p", { className: "ai-chat-form-card__question-text", children: [currentQuestion.text, currentQuestion.required && jsxRuntime.jsx("span", { className: "ai-chat-form-card__required", children: "*" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-form-card__answer", children: [currentQuestion.type === 'text' && (jsxRuntime.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 && (jsxRuntime.jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => (jsxRuntime.jsxs("label", { className: "ai-chat-form-card__option", children: [jsxRuntime.jsx("input", { type: "radio", name: currentQuestion.id, value: option.value, checked: answers[currentQuestion.id] === option.value, onChange: () => handleAnswerChange(currentQuestion.id, option.value) }), jsxRuntime.jsx("span", { className: "ai-chat-form-card__option-text", children: option.text })] }, option.id))) })), currentQuestion.type === 'multiple_choice' && currentQuestion.options && (jsxRuntime.jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => {
@@ -28456,9 +28061,37 @@ function FormCard({ action, onComplete, onDismiss, accentColor }) {
28456
28061
  }, children: isSubmitting ? 'Submitting...' : (state.settings.submitButtonText || 'Submit') }))] })] }));
28457
28062
  }
28458
28063
 
28064
+ function EmailPhase({ accentColor, onDismiss, showCloseButton, onSubmit, isLoading, error, }) {
28065
+ const [emailInput, setEmailInput] = React.useState('');
28066
+ const [localError, setLocalError] = React.useState(null);
28067
+ const handleSubmit = () => {
28068
+ const trimmedEmail = emailInput.trim();
28069
+ if (!trimmedEmail) {
28070
+ setLocalError('Please enter your email address');
28071
+ return;
28072
+ }
28073
+ if (!trimmedEmail.includes('@')) {
28074
+ setLocalError('Please enter a valid email address');
28075
+ return;
28076
+ }
28077
+ setLocalError(null);
28078
+ onSubmit(trimmedEmail);
28079
+ };
28080
+ const displayError = localError || error;
28081
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Enter Your Email" }), showCloseButton && onDismiss && jsxRuntime.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntime.jsx("p", { className: "ai-chat-booking-card__description", children: "Please enter your email address to start the booking process." }), displayError && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), jsxRuntime.jsx("input", { type: "email", className: "ai-chat-booking-card__input", placeholder: "your@email.com", value: emailInput, onChange: (e) => {
28082
+ setEmailInput(e.target.value);
28083
+ setLocalError(null);
28084
+ }, onKeyDown: (e) => {
28085
+ if (e.key === 'Enter' && !isLoading) {
28086
+ handleSubmit();
28087
+ }
28088
+ }, disabled: isLoading }), jsxRuntime.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleSubmit, disabled: !emailInput.trim() || isLoading, children: isLoading ? 'Sending...' : 'Continue' })] })] }));
28089
+ }
28090
+
28459
28091
  function Skeleton({ width, height, borderRadius = '4px' }) {
28460
28092
  return (jsxRuntime.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
28461
28093
  }
28094
+
28462
28095
  function PinInputGroup({ values, onChange, disabled }) {
28463
28096
  const inputRefs = React.useRef([]);
28464
28097
  const handleChange = (index, value) => {
@@ -28490,299 +28123,853 @@ function PinInputGroup({ values, onChange, disabled }) {
28490
28123
  inputRefs.current[index] = el;
28491
28124
  }, 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))) }));
28492
28125
  }
28493
- function BookContactAppointmentCard({ action, onComplete, accentColor }) {
28494
- const state = action.state;
28495
- const [emailInput, setEmailInput] = React.useState('');
28126
+
28127
+ function OtpPhase({ accentColor, onDismiss, showCloseButton, email, onSubmit, onResend, isLoading, error, }) {
28496
28128
  const [otpValues, setOtpValues] = React.useState(Array(6).fill(''));
28497
- const [subjectInput, setSubjectInput] = React.useState(state.subject || '');
28498
- const [isSubmitting, setIsSubmitting] = React.useState(false);
28499
- const [emailError, setEmailError] = React.useState(null);
28500
- const [otpError, setOtpError] = React.useState(null);
28501
- const phase = state.phase || 'awaiting_email';
28502
- const handleSubmit = (newState, delay = 50) => {
28503
- if (!onComplete)
28129
+ const [localError, setLocalError] = React.useState(null);
28130
+ const [isResending, setIsResending] = React.useState(false);
28131
+ const handleSubmit = () => {
28132
+ const code = otpValues.join('');
28133
+ if (code.length !== 6) {
28134
+ setLocalError('Please enter the 6-digit code');
28504
28135
  return;
28505
- setIsSubmitting(true);
28506
- setTimeout(() => {
28507
- onComplete(action.toolCallId, { ...state, ...newState, errorMessage: null });
28508
- }, delay);
28509
- };
28510
- React.useEffect(() => {
28511
- setIsSubmitting(false);
28512
- if (phase === 'awaiting_email') {
28513
- setEmailError(null);
28514
- setOtpError(null);
28515
- }
28516
- else if (phase === 'awaiting_otp') {
28517
- setOtpError(state.errorMessage || null);
28518
- setEmailError(null);
28519
- setOtpValues(Array(6).fill(''));
28520
- if (state.email) {
28521
- setEmailInput(state.email);
28522
- }
28523
28136
  }
28524
- else {
28525
- setEmailError(null);
28526
- setOtpError(null);
28137
+ setLocalError(null);
28138
+ onSubmit(code);
28139
+ };
28140
+ const handleResend = async () => {
28141
+ setIsResending(true);
28142
+ setLocalError(null);
28143
+ try {
28144
+ await onResend();
28527
28145
  }
28528
- }, [phase, state.errorMessage]);
28529
- const isWaitingForBackend = !action.done && Boolean(state.confirmed) && phase === 'awaiting_confirmation';
28530
- const renderSkeleton = () => (jsxRuntime.jsx("div", { className: "ai-chat-booking-card", children: jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsxRuntime.jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsxRuntime.jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntime.jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsxRuntime.jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxRuntime.jsx(Skeleton, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
28531
- const handleEmailSubmit = () => {
28532
- const trimmedEmail = emailInput.trim();
28533
- if (!trimmedEmail) {
28534
- setEmailError('Please enter your email address');
28535
- return;
28146
+ finally {
28147
+ setIsResending(false);
28536
28148
  }
28537
- setEmailError(null);
28538
- setEmailInput(trimmedEmail);
28539
- handleSubmit({ email: trimmedEmail });
28540
28149
  };
28541
- const handleOtpSubmit = () => {
28542
- const code = otpValues.join('');
28543
- if (code.length !== 6) {
28544
- setOtpError('Please enter the 6-digit code');
28150
+ const displayError = localError || error;
28151
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Verify Your Email" }), showCloseButton && onDismiss && jsxRuntime.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntime.jsxs("p", { className: "ai-chat-booking-card__description", children: ["Enter the verification code sent to ", jsxRuntime.jsx("strong", { children: email })] }), jsxRuntime.jsx(PinInputGroup, { values: otpValues, onChange: (newValues) => {
28152
+ setOtpValues(newValues);
28153
+ setLocalError(null);
28154
+ // Auto-submit when all 6 digits are entered
28155
+ if (newValues.every((value) => value.length === 1) && !isLoading) {
28156
+ onSubmit(newValues.join(''));
28157
+ }
28158
+ }, disabled: isLoading }), displayError && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), jsxRuntime.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' }), jsxRuntime.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: handleResend, disabled: isLoading || isResending, children: isResending ? 'Sending...' : 'Resend Code' })] })] }));
28159
+ }
28160
+
28161
+ function ContactSelectionPhase({ accentColor, onDismiss, showCloseButton, contacts, onSelect, }) {
28162
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Select Contact" }), showCloseButton && onDismiss && jsxRuntime.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntime.jsx("p", { className: "ai-chat-booking-card__description", children: "Choose who you would like to book an appointment with:" }), jsxRuntime.jsx("div", { className: "ai-chat-booking-card__list", children: contacts.map((contact) => (jsxRuntime.jsxs("button", { className: "ai-chat-booking-card__list-item", onClick: () => onSelect(contact.id), children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__list-item-content", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__list-item-name", children: contact.name }), contact.role && (jsxRuntime.jsx("span", { className: "ai-chat-booking-card__list-item-role", children: contact.role }))] }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__list-item-arrow", "aria-hidden": "true" })] }, contact.id))) })] })] }));
28163
+ }
28164
+
28165
+ // Calendar icon SVG
28166
+ const CalendarIcon = () => (jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), jsxRuntime.jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }), jsxRuntime.jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }), jsxRuntime.jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })] }));
28167
+ // List icon SVG
28168
+ const ListIcon = () => (jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("line", { x1: "8", y1: "6", x2: "21", y2: "6" }), jsxRuntime.jsx("line", { x1: "8", y1: "12", x2: "21", y2: "12" }), jsxRuntime.jsx("line", { x1: "8", y1: "18", x2: "21", y2: "18" }), jsxRuntime.jsx("line", { x1: "3", y1: "6", x2: "3.01", y2: "6" }), jsxRuntime.jsx("line", { x1: "3", y1: "12", x2: "3.01", y2: "12" }), jsxRuntime.jsx("line", { x1: "3", y1: "18", x2: "3.01", y2: "18" })] }));
28169
+ function OptionsPhase({ onDismiss, showCloseButton, appointments, maxAppointments, onBookNew, onViewAppointments, isCancelling, }) {
28170
+ const activeAppointments = appointments.filter(a => a.status !== 'cancelled' && a.status !== 'declined');
28171
+ const canBookNew = activeAppointments.length < maxAppointments;
28172
+ const hasAppointments = appointments.length > 0;
28173
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Booking Options" }), showCloseButton && onDismiss && jsxRuntime.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [!canBookNew && (jsxRuntime.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."] })), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__options", children: [jsxRuntime.jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: onBookNew, disabled: !canBookNew || isCancelling, children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__option-icon", children: jsxRuntime.jsx(CalendarIcon, {}) }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__option-text", children: "Book New Appointment" })] }), hasAppointments && (jsxRuntime.jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: onViewAppointments, disabled: isCancelling, children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__option-icon", children: jsxRuntime.jsx(ListIcon, {}) }), jsxRuntime.jsxs("span", { className: "ai-chat-booking-card__option-text", children: ["View My Appointments (", activeAppointments.length, ")"] })] }))] })] })] }));
28174
+ }
28175
+
28176
+ function ViewAppointmentsPhase({ accentColor, onDismiss, showCloseButton, appointments, onBack, onCancelAppointment, isCancelling, }) {
28177
+ const [cancellingId, setCancellingId] = React.useState(null);
28178
+ const handleCancel = async (appointmentId) => {
28179
+ setCancellingId(appointmentId);
28180
+ await onCancelAppointment(appointmentId);
28181
+ setCancellingId(null);
28182
+ };
28183
+ const activeAppointments = appointments.filter(a => a.status !== 'cancelled');
28184
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("button", { className: "ai-chat-booking-card__back-btn", onClick: onBack, children: "Back" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "My Appointments" }), showCloseButton && onDismiss && jsxRuntime.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntime.jsx("div", { className: "ai-chat-booking-card__content", children: activeAppointments.length === 0 ? (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__empty", children: "No appointments found." })) : (jsxRuntime.jsx("div", { className: "ai-chat-booking-card__appointments", children: activeAppointments.map((apt) => (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__appointment", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__appointment-info", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__appointment-subject", children: apt.subject }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__appointment-contact", children: apt.contactName }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__appointment-time", children: apt.displayTime }), jsxRuntime.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 })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__appointment-actions", children: [apt.teamsLink && (jsxRuntime.jsx("a", { href: apt.teamsLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__appointment-link", children: "Join Meeting" })), apt.googleMeetLink && (jsxRuntime.jsx("a", { href: apt.googleMeetLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__appointment-link", children: "Join Meeting" })), jsxRuntime.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))) })) })] }));
28185
+ }
28186
+
28187
+ function SlotSelectionPhase({ onDismiss, showCloseButton, slots, contactName, onSelect, onBack, isLoading, error, }) {
28188
+ // Group slots by date
28189
+ const slotsByDate = React.useMemo(() => {
28190
+ const grouped = {};
28191
+ for (const slot of slots) {
28192
+ const date = slot.displayDate;
28193
+ if (!grouped[date]) {
28194
+ grouped[date] = [];
28195
+ }
28196
+ grouped[date].push(slot);
28197
+ }
28198
+ return grouped;
28199
+ }, [slots]);
28200
+ const dates = Object.keys(slotsByDate);
28201
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("button", { className: "ai-chat-booking-card__back-btn", onClick: onBack, children: "Back" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Select Time Slot" }), showCloseButton && onDismiss && jsxRuntime.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [contactName && (jsxRuntime.jsxs("p", { className: "ai-chat-booking-card__description", children: ["Available times for ", jsxRuntime.jsx("strong", { children: contactName }), ":"] })), error && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: error })), slots.length === 0 ? (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__empty", children: "No available time slots found. Please try again later." })) : (jsxRuntime.jsx("div", { className: "ai-chat-booking-card__slots-container", children: dates.map((date) => (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__date-group", children: [jsxRuntime.jsx("h4", { className: "ai-chat-booking-card__date-header", children: date }), jsxRuntime.jsx("div", { className: "ai-chat-booking-card__slots", children: slotsByDate[date].map((slot) => (jsxRuntime.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))) }))] })] }));
28202
+ }
28203
+
28204
+ function ConfirmationPhase({ onDismiss, showCloseButton, contactName, slotDisplay, subjectMode, predefinedSubjects, onConfirm, onBack, isLoading, error, }) {
28205
+ const [subject, setSubject] = React.useState('');
28206
+ const [selectedPredefined, setSelectedPredefined] = React.useState('');
28207
+ const [localError, setLocalError] = React.useState(null);
28208
+ const handleConfirm = () => {
28209
+ const finalSubject = subjectMode === 'predefined' ? selectedPredefined : subject.trim();
28210
+ if (!finalSubject) {
28211
+ setLocalError('Please enter a subject for your appointment');
28545
28212
  return;
28546
28213
  }
28547
- setOtpError(null);
28548
- const resolvedEmail = state.email || emailInput.trim() || null;
28549
- handleSubmit({ otpCode: code, email: resolvedEmail });
28214
+ setLocalError(null);
28215
+ onConfirm(finalSubject);
28550
28216
  };
28551
- // ========================================
28552
- // Terminal States
28553
- // ========================================
28554
- if (phase === 'booked') {
28555
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--success", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2713" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Booked" })] }), state.bookedTeamsLink && (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntime.jsx("p", { className: "ai-chat-booking-card__success-text", children: "Your appointment has been confirmed. You can join via Microsoft Teams." }), jsxRuntime.jsx("a", { href: state.bookedTeamsLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__link", style: { color: accentColor }, children: "Join Teams Meeting \u2192" })] }))] }));
28556
- }
28557
- if (phase === 'pending_approval') {
28558
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--pending", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u23F3" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Awaiting Approval" })] }), jsxRuntime.jsx("div", { className: "ai-chat-booking-card__content", children: jsxRuntime.jsx("p", { className: "ai-chat-booking-card__pending-text", children: "Your appointment request has been sent and is awaiting approval from the contact." }) })] }));
28559
- }
28560
- if (phase === 'cancelled') {
28561
- return (jsxRuntime.jsx("div", { className: "ai-chat-booking-card ai-chat-booking-card--cancelled", children: jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2715" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Cancelled" })] }) }));
28562
- }
28563
- if (phase === 'error') {
28564
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--error", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u26A0\uFE0F" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Booking Error" })] }), state.errorMessage && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage }))] }));
28565
- }
28566
- if (isSubmitting || isWaitingForBackend) {
28567
- return renderSkeleton();
28568
- }
28569
- // ========================================
28570
- // Phase: Email Collection
28571
- // ========================================
28572
- if (phase === 'awaiting_email') {
28573
- const displayError = emailError || state.errorMessage;
28574
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCE7" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Enter Your Email" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntime.jsx("p", { className: "ai-chat-booking-card__description", children: "Please enter your email address to start the booking process." }), displayError && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), jsxRuntime.jsx("input", { type: "email", className: "ai-chat-booking-card__input", placeholder: "your@email.com", value: emailInput, onChange: (e) => {
28575
- setEmailInput(e.target.value);
28576
- setEmailError(null);
28577
- }, onKeyDown: (e) => {
28578
- if (e.key === 'Enter') {
28579
- handleEmailSubmit();
28580
- }
28581
- } }), jsxRuntime.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleEmailSubmit, disabled: !emailInput.trim(), style: {
28582
- backgroundColor: accentColor || undefined,
28583
- borderColor: accentColor || undefined,
28584
- }, children: "Continue" })] })] }));
28585
- }
28586
- // ========================================
28587
- // Phase: OTP Verification
28588
- // ========================================
28589
- if (phase === 'awaiting_otp') {
28590
- const displayError = otpError || state.errorMessage;
28591
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDD10" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Verify Your Email" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntime.jsxs("p", { className: "ai-chat-booking-card__description", children: ["Enter the verification code sent to ", jsxRuntime.jsx("strong", { children: state.email })] }), jsxRuntime.jsx(PinInputGroup, { values: otpValues, onChange: (newValues) => {
28592
- setOtpValues(newValues);
28593
- setOtpError(null);
28594
- if (newValues.every((value) => value.length === 1) && !isSubmitting) {
28595
- const resolvedEmail = state.email || emailInput.trim() || null;
28596
- handleSubmit({ otpCode: newValues.join(''), email: resolvedEmail }, 100);
28597
- }
28598
- }, disabled: isSubmitting }), displayError && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), jsxRuntime.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleOtpSubmit, disabled: otpValues.join('').length !== 6, style: {
28599
- backgroundColor: accentColor || undefined,
28600
- borderColor: accentColor || undefined,
28601
- }, children: "Verify" })] })] }));
28602
- }
28603
- // ========================================
28604
- // Phase: Contact Selection
28605
- // ========================================
28606
- if (phase === 'awaiting_contact_selection') {
28607
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDC65" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Select a Contact" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), state.bookableContacts.length === 0 ? (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__empty", children: "No contacts available for booking." })) : (jsxRuntime.jsx("div", { className: "ai-chat-booking-card__grid", children: state.bookableContacts.map((contact) => (jsxRuntime.jsxs("button", { className: `ai-chat-booking-card__contact ${state.selectedContactId === contact.id ? 'ai-chat-booking-card__contact--selected' : ''}`, onClick: () => handleSubmit({ selectedContactId: contact.id }), style: {
28608
- borderColor: state.selectedContactId === contact.id
28609
- ? accentColor || undefined
28610
- : undefined,
28611
- backgroundColor: state.selectedContactId === contact.id
28612
- ? `${accentColor || '#3b82f6'}15`
28613
- : undefined,
28614
- }, children: [jsxRuntime.jsx("div", { className: "ai-chat-booking-card__contact-name", children: contact.name }), contact.role && (jsxRuntime.jsx("div", { className: "ai-chat-booking-card__contact-role", children: contact.role }))] }, contact.id))) }))] })] }));
28615
- }
28616
- // ========================================
28617
- // Phase: Options Selection
28618
- // ========================================
28619
- if (phase === 'awaiting_options') {
28620
- const selectedContact = state.bookableContacts.find((c) => c.id === state.selectedContactId);
28621
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCC5" }), jsxRuntime.jsxs("span", { className: "ai-chat-booking-card__title", children: ["Book with ", selectedContact?.name] })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__options", children: [jsxRuntime.jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: () => handleSubmit({ selectedOption: 'book_new' }), children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__option-icon", children: "\u2795" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__option-text", children: "Book New Appointment" })] }), state.userAppointments.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: () => handleSubmit({ selectedOption: 'view_existing' }), children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__option-icon", children: "\uD83D\uDCCB" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__option-text", children: "View Appointments" })] }), jsxRuntime.jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: () => handleSubmit({ selectedOption: 'cancel_existing' }), children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__option-icon", children: "\u2715" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__option-text", children: "Cancel Appointment" })] })] }))] })] })] }));
28622
- }
28623
- // ========================================
28624
- // Phase: View Existing Appointments
28625
- // ========================================
28626
- if (state.phase === 'awaiting_options' && state.selectedOption === 'view_existing') {
28627
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCCB" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Your Appointments" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [state.userAppointments.length === 0 ? (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__empty", children: "You have no appointments yet." })) : (jsxRuntime.jsx("div", { className: "ai-chat-booking-card__appointments", children: state.userAppointments.map((apt) => (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__appointment", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__appointment-header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__appointment-subject", children: apt.subject }), jsxRuntime.jsx("span", { className: `ai-chat-booking-card__appointment-status ai-chat-booking-card__appointment-status--${apt.status}`, children: apt.status })] }), jsxRuntime.jsx("div", { className: "ai-chat-booking-card__appointment-time", children: apt.displayTime }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__appointment-contact", children: ["with ", apt.contactName] }), apt.teamsLink && (jsxRuntime.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))) })), jsxRuntime.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: () => handleSubmit({ selectedOption: undefined }), children: "Back" })] })] }));
28628
- }
28629
- // ========================================
28630
- // Phase: Cancel Appointment
28631
- // ========================================
28632
- if (state.phase === 'awaiting_options' && state.selectedOption === 'cancel_existing') {
28633
- const activeAppointments = state.userAppointments.filter((a) => a.status !== 'cancelled' && a.status !== 'declined');
28634
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2715" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Cancel Appointment" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), activeAppointments.length === 0 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("p", { className: "ai-chat-booking-card__empty", children: "No active appointments to cancel." }), jsxRuntime.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: () => handleSubmit({ selectedOption: undefined }), children: "Back" })] })) : (jsxRuntime.jsx("div", { className: "ai-chat-booking-card__appointments", children: activeAppointments.map((apt) => (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__appointment", children: [jsxRuntime.jsx("div", { className: "ai-chat-booking-card__appointment-header", children: jsxRuntime.jsx("span", { className: "ai-chat-booking-card__appointment-subject", children: apt.subject }) }), jsxRuntime.jsx("div", { className: "ai-chat-booking-card__appointment-time", children: apt.displayTime }), jsxRuntime.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))) }))] })] }));
28635
- }
28636
- // ========================================
28637
- // Phase: Slot Selection
28638
- // ========================================
28639
- if (phase === 'awaiting_slot_selection') {
28640
- const groupedSlots = state.availableSlots.reduce((acc, slot) => {
28641
- if (!acc[slot.displayDate]) {
28642
- acc[slot.displayDate] = [];
28643
- }
28644
- acc[slot.displayDate].push(slot);
28645
- return acc;
28646
- }, {});
28647
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDD50" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Select a Time Slot" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntime.jsxs("p", { className: "ai-chat-booking-card__description", children: ["Available times in ", state.timeZone] }), state.errorMessage && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), Object.entries(groupedSlots).map(([date, slots]) => (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__date-group", children: [jsxRuntime.jsx("div", { className: "ai-chat-booking-card__date-header", children: date }), jsxRuntime.jsx("div", { className: "ai-chat-booking-card__slots", children: slots.map((slot, idx) => {
28648
- const isSelected = state.selectedSlot?.startTime === slot.startTime &&
28649
- state.selectedSlot?.endTime === slot.endTime;
28650
- return (jsxRuntime.jsx("button", { className: `ai-chat-booking-card__slot ${isSelected ? 'ai-chat-booking-card__slot--selected' : ''}`, onClick: () => handleSubmit({
28651
- selectedSlot: { startTime: slot.startTime, endTime: slot.endTime },
28652
- }), style: {
28653
- borderColor: isSelected ? accentColor || undefined : undefined,
28654
- backgroundColor: isSelected ? `${accentColor || '#3b82f6'}15` : undefined,
28655
- }, children: slot.displayTime }, `${slot.startTime}-${idx}`));
28656
- }) })] }, date))), state.availableSlots.length === 0 && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__empty", children: "No available time slots." }))] })] }));
28657
- }
28658
- // ========================================
28659
- // Phase: Confirmation
28660
- // ========================================
28661
- if (phase === 'awaiting_confirmation') {
28662
- const selectedContact = state.bookableContacts.find((c) => c.id === state.selectedContactId);
28663
- const selectedSlot = state.availableSlots.find((s) => s.startTime === state.selectedSlot?.startTime && s.endTime === state.selectedSlot?.endTime);
28664
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2713" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Confirm Booking" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Contact:" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-value", children: selectedContact?.name })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Date:" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-value", children: selectedSlot?.displayDate })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Time:" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-value", children: selectedSlot?.displayTime })] })] }), state.allowCustomSubject && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("label", { className: "ai-chat-booking-card__label", children: "Subject (optional):" }), jsxRuntime.jsx("input", { type: "text", className: "ai-chat-booking-card__input", placeholder: "Meeting subject", value: subjectInput, onChange: (e) => setSubjectInput(e.target.value) })] })), jsxRuntime.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: () => handleSubmit({
28665
- subject: state.allowCustomSubject ? subjectInput || undefined : undefined,
28666
- confirmed: true,
28667
- }), style: {
28668
- backgroundColor: accentColor || undefined,
28669
- borderColor: accentColor || undefined,
28670
- }, children: "Confirm Booking" })] })] }));
28671
- }
28672
- // Fallback for unknown states
28673
- return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCC5" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Booking" })] }), jsxRuntime.jsx("div", { className: "ai-chat-booking-card__content", children: jsxRuntime.jsx("p", { className: "ai-chat-booking-card__description", children: "Loading booking options..." }) })] }));
28217
+ const displayError = localError || error;
28218
+ const isValid = subjectMode === 'predefined' ? !!selectedPredefined : !!subject.trim();
28219
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("button", { className: "ai-chat-booking-card__back-btn", onClick: onBack, "aria-label": "Go back", children: jsxRuntime.jsx(BackArrowIcon, {}) }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Confirm Booking" }), showCloseButton && onDismiss && jsxRuntime.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary", children: [contactName && (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "With:" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-value", children: contactName })] })), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "When:" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-value", children: slotDisplay })] })] }), displayError && (jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), subjectMode === 'predefined' ? (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__field", children: [jsxRuntime.jsx("label", { className: "ai-chat-booking-card__label", children: "Select a topic:" }), jsxRuntime.jsx("div", { className: "ai-chat-booking-card__subject-options", children: predefinedSubjects.map((subj) => (jsxRuntime.jsx("button", { className: `ai-chat-booking-card__subject-option ${selectedPredefined === subj ? 'ai-chat-booking-card__subject-option--selected' : ''}`, onClick: () => {
28220
+ setSelectedPredefined(subj);
28221
+ setLocalError(null);
28222
+ }, disabled: isLoading, children: subj }, subj))) })] })) : (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__field", children: [jsxRuntime.jsx("label", { className: "ai-chat-booking-card__label", children: "What would you like to discuss?" }), jsxRuntime.jsx("input", { type: "text", className: "ai-chat-booking-card__input", placeholder: "Enter appointment subject...", value: subject, onChange: (e) => {
28223
+ setSubject(e.target.value);
28224
+ setLocalError(null);
28225
+ }, onKeyDown: (e) => {
28226
+ if (e.key === 'Enter' && isValid && !isLoading) {
28227
+ handleConfirm();
28228
+ }
28229
+ }, disabled: isLoading })] })), jsxRuntime.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleConfirm, disabled: !isValid || isLoading, children: isLoading ? 'Booking...' : 'Confirm Booking' })] })] }));
28674
28230
  }
28675
28231
 
28676
- const pendingResolvers = new Map();
28677
- const resumeCallbacks = new Map();
28678
- const frontendActionHandlers = {};
28679
- const actionRenderers = {};
28680
- function getFrontendActionHandler(implementation) {
28681
- return frontendActionHandlers[implementation];
28232
+ function BookedPhase({ subject, contactName, meetingLink, meetingProvider, }) {
28233
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--success", children: [jsxRuntime.jsx("div", { className: "ai-chat-booking-card__header", children: jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Booked" }) }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntime.jsx("div", { className: "ai-chat-booking-card__success-icon", "aria-hidden": "true" }), jsxRuntime.jsx("p", { className: "ai-chat-booking-card__success-message", children: "Your appointment has been successfully scheduled." }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Subject:" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-value", children: subject })] }), contactName && (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "With:" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-value", children: contactName })] }))] }), meetingLink && (jsxRuntime.jsx("a", { href: meetingLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", style: {
28234
+ textDecoration: 'none',
28235
+ display: 'inline-block',
28236
+ textAlign: 'center',
28237
+ }, children: meetingProvider === 'google' ? 'Join Google Meet' : 'Join Teams Meeting' }))] })] }));
28682
28238
  }
28683
- function getActionRenderer(implementation) {
28684
- return actionRenderers[implementation];
28239
+
28240
+ function PendingApprovalPhase({ subject, contactName }) {
28241
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--pending", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__status-icon ai-chat-booking-card__status-icon--pending" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Awaiting Approval" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntime.jsx("p", { className: "ai-chat-booking-card__pending-text", children: "Your appointment request has been sent and is awaiting approval." }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Subject:" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-value", children: subject })] }), contactName && (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "With:" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__summary-value", children: contactName })] }))] })] })] }));
28685
28242
  }
28686
- function waitForActionState(toolCallId) {
28687
- return new Promise((resolve) => {
28688
- pendingResolvers.set(toolCallId, resolve);
28689
- });
28243
+
28244
+ /**
28245
+ * Cancelled Phase Component (terminal state)
28246
+ */
28247
+ function CancelledPhase() {
28248
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--cancelled", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__status-icon ai-chat-booking-card__status-icon--cancelled" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Cancelled" })] }), jsxRuntime.jsx("div", { className: "ai-chat-booking-card__content", children: jsxRuntime.jsx("p", { className: "ai-chat-booking-card__description", children: "This appointment has been cancelled." }) })] }));
28690
28249
  }
28691
- function resolveActionState(toolCallId, state) {
28692
- const resolver = pendingResolvers.get(toolCallId);
28693
- if (resolver) {
28694
- pendingResolvers.delete(toolCallId);
28695
- resolver(state);
28696
- return;
28697
- }
28698
- const resumeCallback = resumeCallbacks.get(toolCallId);
28699
- if (resumeCallback) {
28700
- resumeCallback(state).catch((error) => {
28701
- console.error("[Action] Failed to resume action:", error);
28702
- });
28703
- }
28250
+
28251
+ function ErrorPhase({ error, onRetry }) {
28252
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--error", children: [jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntime.jsx("span", { className: "ai-chat-booking-card__status-icon ai-chat-booking-card__status-icon--error" }), jsxRuntime.jsx("span", { className: "ai-chat-booking-card__title", children: "Booking Error" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntime.jsx("p", { className: "ai-chat-booking-card__error", children: error }), onRetry && (jsxRuntime.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: onRetry, children: "Try Again" }))] })] }));
28704
28253
  }
28705
- function registerActionResumeCallback(toolCallId, callback) {
28706
- resumeCallbacks.set(toolCallId, callback);
28254
+
28255
+ function CompletedPhase() {
28256
+ return (jsxRuntime.jsx("div", { className: "ai-chat-booking-card ai-chat-booking-card--completed", children: jsxRuntime.jsxs("div", { className: "ai-chat-booking-card__completed-indicator", children: [jsxRuntime.jsx(CheckIcon, {}), jsxRuntime.jsx("span", { children: "Booking action completed" })] }) }));
28707
28257
  }
28708
- function unregisterActionResumeCallback(toolCallId) {
28709
- resumeCallbacks.delete(toolCallId);
28258
+
28259
+ function LoadingPhase() {
28260
+ return (jsxRuntime.jsx("div", { className: "ai-chat-booking-card", children: jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsxRuntime.jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsxRuntime.jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntime.jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsxRuntime.jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxRuntime.jsx(Skeleton, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
28710
28261
  }
28711
28262
 
28712
- function registerGoogleCalendarHandler() {
28713
- frontendActionHandlers["google-calendar-appointment"] = async (_input, _state, context) => {
28714
- return waitForActionState(context.toolCallId);
28263
+ /**
28264
+ * Core action lifecycle handlers for booking flow
28265
+ */
28266
+ function useBookingAction({ onComplete, onDismiss, toolCallId, }) {
28267
+ const handleDismiss = React.useCallback(() => {
28268
+ onDismiss?.(toolCallId);
28269
+ }, [onDismiss, toolCallId]);
28270
+ const finishAction = React.useCallback((body) => {
28271
+ if (!onComplete)
28272
+ return;
28273
+ onComplete(toolCallId, body);
28274
+ }, [onComplete, toolCallId]);
28275
+ return {
28276
+ handleDismiss,
28277
+ finishAction,
28715
28278
  };
28716
28279
  }
28717
28280
 
28718
28281
  /**
28719
- * Register google-calendar-appointment action handler and renderer.
28720
- * Called by initializeActionHandlers to prevent tree-shaking.
28282
+ * Helper functions for accessing booking data
28721
28283
  */
28722
- function registerGoogleCalendarAction() {
28723
- // Register the handler
28724
- registerGoogleCalendarHandler();
28725
- // Register the renderer
28726
- actionRenderers["google-calendar-appointment"] = (message, accentColor, _variant, onActionDismiss) => {
28727
- const action = message.action;
28728
- if (!action)
28729
- return null;
28730
- const handleComplete = (toolCallId, newState) => {
28731
- resolveActionState(toolCallId, newState);
28732
- };
28733
- const handleDismiss = onActionDismiss
28734
- ? (toolCallId) => {
28735
- resolveActionState(toolCallId, { __dismissed: true });
28736
- onActionDismiss(toolCallId);
28284
+ function useBookingHelpers({ contacts, slots, bookingMode, }) {
28285
+ const getContactName = React.useCallback((contactId) => {
28286
+ if (!contactId)
28287
+ return bookingMode === 'general' ? 'Shared Calendar' : null;
28288
+ const contact = contacts.find(c => c.id === contactId);
28289
+ return contact?.name || null;
28290
+ }, [contacts, bookingMode]);
28291
+ const getSlotDisplay = React.useCallback((slot) => {
28292
+ if (!slot)
28293
+ return '';
28294
+ const slotData = slots.find(s => s.startTime === slot.startTime && s.endTime === slot.endTime);
28295
+ return slotData ? `${slotData.displayDate} ${slotData.displayTime}` : '';
28296
+ }, [slots]);
28297
+ return {
28298
+ getContactName,
28299
+ getSlotDisplay,
28300
+ };
28301
+ }
28302
+
28303
+ /**
28304
+ * OTP-related operations for email verification
28305
+ */
28306
+ function useBookingOtp({ onCallEndpoint, state, setState, config, }) {
28307
+ const handleSendOtp = React.useCallback(async (email) => {
28308
+ if (!onCallEndpoint) {
28309
+ setState(prev => ({ ...prev, error: 'Endpoint not available' }));
28310
+ return;
28311
+ }
28312
+ setState(prev => ({ ...prev, isLoading: true, error: null, email }));
28313
+ try {
28314
+ await onCallEndpoint('send-otp', { email });
28315
+ setState(prev => ({ ...prev, isLoading: false, step: 'otp' }));
28316
+ }
28317
+ catch (err) {
28318
+ const message = err instanceof Error ? err.message : 'Failed to send verification code';
28319
+ setState(prev => ({ ...prev, isLoading: false, error: message }));
28320
+ }
28321
+ }, [onCallEndpoint, setState]);
28322
+ const handleVerifyOtp = React.useCallback(async (code) => {
28323
+ if (!onCallEndpoint) {
28324
+ setState(prev => ({ ...prev, error: 'Endpoint not available' }));
28325
+ return;
28326
+ }
28327
+ setState(prev => ({ ...prev, isLoading: true, error: null }));
28328
+ try {
28329
+ const result = await onCallEndpoint('verify-otp', {
28330
+ email: state.email,
28331
+ code,
28332
+ bookingMode: config.bookingMode,
28333
+ timeZone: config.timeZone,
28334
+ });
28335
+ const nextStep = config.bookingMode === 'general'
28336
+ ? 'options'
28337
+ : result.contacts.length === 1
28338
+ ? 'options'
28339
+ : 'contact_selection';
28340
+ setState(prev => ({
28341
+ ...prev,
28342
+ isLoading: false,
28343
+ token: result.token,
28344
+ contacts: result.contacts,
28345
+ appointments: result.appointments,
28346
+ selectedContactId: result.contacts.length === 1 ? result.contacts[0].id : null,
28347
+ step: nextStep,
28348
+ }));
28349
+ }
28350
+ catch (err) {
28351
+ const message = err instanceof Error ? err.message : 'Invalid verification code';
28352
+ setState(prev => ({ ...prev, isLoading: false, error: message }));
28353
+ }
28354
+ }, [onCallEndpoint, state.email, config.bookingMode, config.timeZone, setState]);
28355
+ const handleResendOtp = React.useCallback(async () => {
28356
+ await handleSendOtp(state.email);
28357
+ }, [handleSendOtp, state.email]);
28358
+ return {
28359
+ handleSendOtp,
28360
+ handleVerifyOtp,
28361
+ handleResendOtp,
28362
+ };
28363
+ }
28364
+
28365
+ /**
28366
+ * Navigation and flow control handlers for booking steps
28367
+ */
28368
+ function useBookingNavigation({ onCallEndpoint, state, setState, config, }) {
28369
+ const handleSelectContact = React.useCallback((contactId) => {
28370
+ setState(prev => ({
28371
+ ...prev,
28372
+ selectedContactId: contactId,
28373
+ step: 'options',
28374
+ }));
28375
+ }, [setState]);
28376
+ const handleBookNew = React.useCallback(async () => {
28377
+ if (!onCallEndpoint || !state.token) {
28378
+ setState(prev => ({ ...prev, error: 'Not authenticated' }));
28379
+ return;
28380
+ }
28381
+ setState(prev => ({ ...prev, isLoading: true, error: null }));
28382
+ try {
28383
+ const result = await onCallEndpoint('get-slots', {
28384
+ contactId: state.selectedContactId,
28385
+ daysAhead: config.daysAhead,
28386
+ timeZone: config.timeZone,
28387
+ }, { token: state.token });
28388
+ setState(prev => ({
28389
+ ...prev,
28390
+ isLoading: false,
28391
+ slots: result.slots,
28392
+ step: 'slot_selection',
28393
+ }));
28394
+ }
28395
+ catch (err) {
28396
+ const message = err instanceof Error ? err.message : 'Failed to load available slots';
28397
+ setState(prev => ({ ...prev, isLoading: false, error: message }));
28398
+ }
28399
+ }, [onCallEndpoint, state.token, state.selectedContactId, config.daysAhead, config.timeZone, setState]);
28400
+ const handleViewAppointments = React.useCallback(() => {
28401
+ setState(prev => ({ ...prev, step: 'view_appointments' }));
28402
+ }, [setState]);
28403
+ const handleBackToOptions = React.useCallback(() => {
28404
+ setState(prev => ({ ...prev, step: 'options', error: null }));
28405
+ }, [setState]);
28406
+ const handleSelectSlot = React.useCallback((slot) => {
28407
+ setState(prev => ({
28408
+ ...prev,
28409
+ selectedSlot: slot,
28410
+ step: 'confirmation',
28411
+ }));
28412
+ }, [setState]);
28413
+ const handleBackToSlots = React.useCallback(() => {
28414
+ setState(prev => ({ ...prev, step: 'slot_selection', error: null }));
28415
+ }, [setState]);
28416
+ return {
28417
+ handleSelectContact,
28418
+ handleBookNew,
28419
+ handleViewAppointments,
28420
+ handleBackToOptions,
28421
+ handleSelectSlot,
28422
+ handleBackToSlots,
28423
+ };
28424
+ }
28425
+
28426
+ /**
28427
+ * Core booking operations (confirm and cancel)
28428
+ */
28429
+ function useBookingOperations({ onCallEndpoint, state, setState, config, getContactName, finishAction, }) {
28430
+ const [isCancelling, setIsCancelling] = React.useState(false);
28431
+ const handleConfirmBooking = React.useCallback(async (subject) => {
28432
+ if (!onCallEndpoint || !state.token || !state.selectedSlot) {
28433
+ setState(prev => ({ ...prev, error: 'Missing required data' }));
28434
+ return;
28435
+ }
28436
+ setState(prev => ({ ...prev, isLoading: true, error: null, subject }));
28437
+ try {
28438
+ const result = await onCallEndpoint('book', {
28439
+ contactId: state.selectedContactId,
28440
+ slot: state.selectedSlot,
28441
+ subject,
28442
+ timeZone: config.timeZone,
28443
+ }, { token: state.token });
28444
+ const contactName = getContactName(state.selectedContactId);
28445
+ if (result.status === 'pending_approval') {
28446
+ setState(prev => ({
28447
+ ...prev,
28448
+ isLoading: false,
28449
+ step: 'pending_approval',
28450
+ }));
28451
+ // Finish with pending status
28452
+ finishAction({
28453
+ status: 'pending_approval',
28454
+ subject,
28455
+ contactName,
28456
+ message: `Appointment request "${subject}" submitted and awaiting approval.`,
28457
+ });
28737
28458
  }
28738
- : undefined;
28739
- return (jsxRuntime.jsx(GoogleCalendarCard, { action: {
28740
- implementation: action.implementation,
28741
- toolCallId: action.toolCallId,
28742
- actionId: action.actionId,
28743
- input: action.input,
28744
- state: action.state,
28745
- done: action.done ?? false,
28746
- }, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
28459
+ else {
28460
+ setState(prev => ({
28461
+ ...prev,
28462
+ isLoading: false,
28463
+ bookedMeetingLink: result.meetingLink || null,
28464
+ bookedMeetingProvider: result.meetingProvider || null,
28465
+ step: 'booked',
28466
+ }));
28467
+ // Finish with booked status
28468
+ finishAction({
28469
+ status: 'booked',
28470
+ subject,
28471
+ contactName,
28472
+ meetingLink: result.meetingLink,
28473
+ message: `Successfully booked appointment "${subject}"${contactName ? ` with ${contactName}` : ''}.`,
28474
+ });
28475
+ }
28476
+ }
28477
+ catch (err) {
28478
+ const message = err instanceof Error ? err.message : 'Failed to book appointment';
28479
+ setState(prev => ({ ...prev, isLoading: false, error: message }));
28480
+ }
28481
+ }, [onCallEndpoint, state.token, state.selectedSlot, state.selectedContactId, config.timeZone, getContactName, finishAction, setState]);
28482
+ const handleCancelAppointment = React.useCallback(async (appointmentId) => {
28483
+ if (!onCallEndpoint || !state.token) {
28484
+ setState(prev => ({ ...prev, error: 'Not authenticated' }));
28485
+ return;
28486
+ }
28487
+ setIsCancelling(true);
28488
+ try {
28489
+ await onCallEndpoint('cancel', { appointmentId }, { token: state.token });
28490
+ // Update local appointments list
28491
+ setState(prev => ({
28492
+ ...prev,
28493
+ appointments: prev.appointments.map(apt => apt.id === appointmentId ? { ...apt, status: 'cancelled' } : apt),
28494
+ }));
28495
+ }
28496
+ catch (err) {
28497
+ const message = err instanceof Error ? err.message : 'Failed to cancel appointment';
28498
+ setState(prev => ({ ...prev, error: message }));
28499
+ }
28500
+ finally {
28501
+ setIsCancelling(false);
28502
+ }
28503
+ }, [onCallEndpoint, state.token, setState]);
28504
+ return {
28505
+ handleConfirmBooking,
28506
+ handleCancelAppointment,
28507
+ isCancelling,
28747
28508
  };
28748
28509
  }
28749
28510
 
28750
- function registerMicrosoftCalendarHandler() {
28751
- frontendActionHandlers["microsoft-calendar-appointment"] = async (_input, _state, context) => {
28752
- return waitForActionState(context.toolCallId);
28511
+ // Default config values
28512
+ const DEFAULT_CONFIG = {
28513
+ bookingMode: 'per-contact',
28514
+ timeZone: 'UTC',
28515
+ maxAppointmentsPerUser: 3,
28516
+ daysAhead: 14,
28517
+ subjectMode: 'user_defined',
28518
+ predefinedSubjects: [],
28519
+ };
28520
+ // Initial UI state
28521
+ const createInitialState = () => ({
28522
+ step: 'email',
28523
+ email: '',
28524
+ selectedContactId: null,
28525
+ selectedSlot: null,
28526
+ subject: '',
28527
+ token: null,
28528
+ contacts: [],
28529
+ appointments: [],
28530
+ slots: [],
28531
+ bookedMeetingLink: null,
28532
+ bookedMeetingProvider: null,
28533
+ isLoading: false,
28534
+ error: null,
28535
+ });
28536
+ function BookContactAppointmentCard({ action, onComplete, onDismiss, onCallEndpoint, accentColor, }) {
28537
+ // Parse config from input (from getInitialClientState)
28538
+ const initialState = action.input;
28539
+ const config = {
28540
+ bookingMode: initialState.bookingMode || DEFAULT_CONFIG.bookingMode,
28541
+ timeZone: initialState.timeZone || DEFAULT_CONFIG.timeZone,
28542
+ maxAppointmentsPerUser: initialState.maxAppointmentsPerUser || DEFAULT_CONFIG.maxAppointmentsPerUser,
28543
+ daysAhead: initialState.daysAhead || DEFAULT_CONFIG.daysAhead,
28544
+ subjectMode: initialState.subjectMode || DEFAULT_CONFIG.subjectMode,
28545
+ predefinedSubjects: initialState.predefinedSubjects || DEFAULT_CONFIG.predefinedSubjects,
28546
+ };
28547
+ // Local UI state
28548
+ const [state, setState] = React.useState(createInitialState);
28549
+ // Check if action is already done (from server state)
28550
+ const isDone = action.done;
28551
+ // Determine if dismiss should be available
28552
+ const isInteractiveStep = ['email', 'otp', 'contact_selection', 'options', 'view_appointments', 'slot_selection', 'confirmation'].includes(state.step);
28553
+ const showCloseButton = !isDone && isInteractiveStep && Boolean(onDismiss);
28554
+ // =========================================================================
28555
+ // Custom Hooks
28556
+ // =========================================================================
28557
+ // Core action lifecycle
28558
+ const { handleDismiss, finishAction } = useBookingAction({
28559
+ onComplete,
28560
+ onDismiss,
28561
+ toolCallId: action.toolCallId,
28562
+ });
28563
+ // Helper functions
28564
+ const { getContactName, getSlotDisplay } = useBookingHelpers({
28565
+ contacts: state.contacts,
28566
+ slots: state.slots,
28567
+ bookingMode: config.bookingMode,
28568
+ });
28569
+ // OTP operations
28570
+ const { handleSendOtp, handleVerifyOtp, handleResendOtp, } = useBookingOtp({
28571
+ onCallEndpoint,
28572
+ state: { email: state.email },
28573
+ setState,
28574
+ config: {
28575
+ bookingMode: config.bookingMode,
28576
+ timeZone: config.timeZone,
28577
+ },
28578
+ });
28579
+ // Navigation handlers
28580
+ const { handleSelectContact, handleBookNew, handleViewAppointments, handleBackToOptions, handleSelectSlot, handleBackToSlots, } = useBookingNavigation({
28581
+ onCallEndpoint,
28582
+ state,
28583
+ setState,
28584
+ config: {
28585
+ daysAhead: config.daysAhead,
28586
+ timeZone: config.timeZone,
28587
+ },
28588
+ });
28589
+ // Booking operations
28590
+ const { handleConfirmBooking, handleCancelAppointment, isCancelling, } = useBookingOperations({
28591
+ onCallEndpoint,
28592
+ state,
28593
+ setState,
28594
+ config: {
28595
+ timeZone: config.timeZone,
28596
+ },
28597
+ getContactName,
28598
+ finishAction,
28599
+ });
28600
+ // =========================================================================
28601
+ // Render
28602
+ // =========================================================================
28603
+ // If action is already done, show a simple completion indicator
28604
+ // The agent's response will convey what happened - no need to reconstruct terminal state
28605
+ if (isDone) {
28606
+ return jsxRuntime.jsx(CompletedPhase, {});
28607
+ }
28608
+ // Show loading when making API calls
28609
+ if (state.isLoading) {
28610
+ return jsxRuntime.jsx(LoadingPhase, {});
28611
+ }
28612
+ // Render based on current step
28613
+ switch (state.step) {
28614
+ case 'email':
28615
+ return (jsxRuntime.jsx(EmailPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, onSubmit: handleSendOtp, isLoading: state.isLoading, error: state.error }));
28616
+ case 'otp':
28617
+ return (jsxRuntime.jsx(OtpPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, email: state.email, onSubmit: handleVerifyOtp, onResend: handleResendOtp, isLoading: state.isLoading, error: state.error }));
28618
+ case 'contact_selection':
28619
+ return (jsxRuntime.jsx(ContactSelectionPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, contacts: state.contacts, onSelect: handleSelectContact }));
28620
+ case 'options':
28621
+ return (jsxRuntime.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 }));
28622
+ case 'view_appointments':
28623
+ return (jsxRuntime.jsx(ViewAppointmentsPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, appointments: state.appointments, onBack: handleBackToOptions, onCancelAppointment: handleCancelAppointment, isCancelling: isCancelling }));
28624
+ case 'slot_selection':
28625
+ return (jsxRuntime.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 }));
28626
+ case 'confirmation':
28627
+ return (jsxRuntime.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 }));
28628
+ case 'booked':
28629
+ return (jsxRuntime.jsx(BookedPhase, { subject: state.subject, contactName: getContactName(state.selectedContactId), meetingLink: state.bookedMeetingLink, meetingProvider: state.bookedMeetingProvider }));
28630
+ case 'pending_approval':
28631
+ return (jsxRuntime.jsx(PendingApprovalPhase, { subject: state.subject, contactName: getContactName(state.selectedContactId) }));
28632
+ case 'cancelled':
28633
+ return jsxRuntime.jsx(CancelledPhase, {});
28634
+ case 'error':
28635
+ return jsxRuntime.jsx(ErrorPhase, { error: state.error || 'An error occurred' });
28636
+ default:
28637
+ return jsxRuntime.jsx(ErrorPhase, { error: "Unknown state" });
28638
+ }
28639
+ }
28640
+
28641
+ function ExternalLinkIcon$1() {
28642
+ return (jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntime.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntime.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
28643
+ }
28644
+ function ImageCard({ item, accentColor, showOverlay = true, onClick, onLinkClick }) {
28645
+ const [imageError, setImageError] = React.useState(false);
28646
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28647
+ const hasMetadata = item.title || item.description || item.link;
28648
+ const handleLinkClick = (e) => {
28649
+ e.stopPropagation();
28650
+ if (item.link) {
28651
+ onLinkClick?.(item.link);
28652
+ window.open(item.link, '_blank', 'noopener,noreferrer');
28653
+ }
28654
+ };
28655
+ const handleImageClick = () => {
28656
+ if (onClick) {
28657
+ onClick();
28658
+ }
28753
28659
  };
28660
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-image-card", style: style, onClick: handleImageClick, children: [jsxRuntime.jsx("div", { className: "ai-chat-image-card__media", children: !imageError ? (jsxRuntime.jsx("img", { src: item.url, alt: item.alt || item.title || 'Image', className: "ai-chat-image-card__image", onError: () => setImageError(true) })) : (jsxRuntime.jsx("div", { className: "ai-chat-image-card__image-error", children: jsxRuntime.jsx("span", { children: "Failed to load image" }) })) }), hasMetadata && showOverlay && (jsxRuntime.jsxs("div", { className: "ai-chat-image-card__content", children: [item.title && (jsxRuntime.jsx("h4", { className: "ai-chat-image-card__title", children: item.title })), item.description && (jsxRuntime.jsx("p", { className: "ai-chat-image-card__description", children: item.description })), item.link && (jsxRuntime.jsxs("button", { className: "ai-chat-image-card__link-btn", onClick: handleLinkClick, children: [item.linkText || 'View More', jsxRuntime.jsx(ExternalLinkIcon$1, {})] }))] }))] }));
28661
+ }
28662
+
28663
+ function ImageGallery({ items, columns = 2, accentColor }) {
28664
+ const [imageErrors, setImageErrors] = React.useState(new Set());
28665
+ const imageItems = items;
28666
+ if (imageItems.length === 0)
28667
+ return null;
28668
+ // Determine if first item should span full width (for odd counts > 1)
28669
+ const itemCount = imageItems.length;
28670
+ const isOddCount = itemCount > 1 && itemCount % 2 === 1;
28671
+ const style = {
28672
+ ...(accentColor ? { '--action-accent': accentColor } : {}),
28673
+ '--gallery-item-count': itemCount,
28674
+ };
28675
+ const handleImageError = (index) => {
28676
+ setImageErrors(prev => new Set(prev).add(index));
28677
+ };
28678
+ return (jsxRuntime.jsx("div", { className: "ai-chat-image-gallery", style: style, "data-item-count": itemCount, children: jsxRuntime.jsx("div", { className: `ai-chat-image-gallery__grid ${isOddCount ? 'odd-count' : ''}`, "data-count": itemCount, children: imageItems.map((item, index) => (jsxRuntime.jsx("div", { className: `ai-chat-image-gallery__item ${isOddCount && index === 0 ? 'span-full' : ''}`, children: jsxRuntime.jsxs("div", { className: "ai-chat-image-gallery__item-media", children: [!imageErrors.has(index) ? (jsxRuntime.jsx("img", { src: item.url, alt: item.alt || item.title || `Image ${index + 1}`, onError: () => handleImageError(index) })) : (jsxRuntime.jsx("div", { className: "ai-chat-image-gallery__error", children: jsxRuntime.jsx("span", { children: "Failed to load" }) })), item.title && (jsxRuntime.jsx("div", { className: "ai-chat-image-gallery__item-overlay", children: jsxRuntime.jsx("span", { className: "ai-chat-image-gallery__item-title", children: item.title }) }))] }) }, index))) }) }));
28679
+ }
28680
+
28681
+ function ExternalLinkIcon() {
28682
+ return (jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntime.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntime.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
28683
+ }
28684
+ function truncate(text, maxLength) {
28685
+ if (text.length <= maxLength)
28686
+ return text;
28687
+ return text.slice(0, maxLength).trim() + '...';
28688
+ }
28689
+ function ProjectCard({ item, accentColor, onLinkClick, variant }) {
28690
+ const [imageError, setImageError] = React.useState(false);
28691
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28692
+ const imageUrl = item.url;
28693
+ // Determine variant based on content if not specified
28694
+ const hasTextContent = item.title || item.description;
28695
+ const effectiveVariant = variant || (hasTextContent ? 'full' : 'image-only');
28696
+ const handleCardClick = () => {
28697
+ if (item.link) {
28698
+ onLinkClick?.(item.link);
28699
+ window.open(item.link, '_blank', 'noopener,noreferrer');
28700
+ }
28701
+ };
28702
+ // Image-only variant - just the image with optional hover effect
28703
+ if (effectiveVariant === 'image-only') {
28704
+ return (jsxRuntime.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: jsxRuntime.jsx("div", { className: "ai-chat-project-card__media", children: imageUrl && !imageError ? (jsxRuntime.jsx("img", { src: imageUrl, alt: item.alt || 'Image', onError: () => setImageError(true) })) : (jsxRuntime.jsx("div", { className: "ai-chat-project-card__placeholder", children: imageError ? 'Failed to load' : 'No image' })) }) }));
28705
+ }
28706
+ // Overlay variant - title overlaid on image
28707
+ if (effectiveVariant === 'overlay') {
28708
+ return (jsxRuntime.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: jsxRuntime.jsxs("div", { className: "ai-chat-project-card__media", children: [imageUrl && !imageError ? (jsxRuntime.jsx("img", { src: imageUrl, alt: item.alt || item.title || 'Image', onError: () => setImageError(true) })) : (jsxRuntime.jsx("div", { className: "ai-chat-project-card__placeholder", children: imageError ? 'Failed to load' : 'No image' })), item.title && (jsxRuntime.jsx("div", { className: "ai-chat-project-card__overlay", children: jsxRuntime.jsx("h4", { className: "ai-chat-project-card__overlay-title", children: truncate(item.title, 50) }) }))] }) }));
28709
+ }
28710
+ // Full variant - image with separate content section below
28711
+ return (jsxRuntime.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: [jsxRuntime.jsx("div", { className: "ai-chat-project-card__media", children: imageUrl && !imageError ? (jsxRuntime.jsx("img", { src: imageUrl, alt: item.alt || item.title || 'Project image', onError: () => setImageError(true) })) : (jsxRuntime.jsx("div", { className: "ai-chat-project-card__placeholder", children: imageError ? 'Failed to load' : 'No image' })) }), hasTextContent && (jsxRuntime.jsxs("div", { className: "ai-chat-project-card__content", children: [item.title && (jsxRuntime.jsx("h4", { className: "ai-chat-project-card__title", children: truncate(item.title, 60) })), item.description && (jsxRuntime.jsx("p", { className: "ai-chat-project-card__description", children: truncate(item.description, 120) })), item.link && (jsxRuntime.jsxs("div", { className: "ai-chat-project-card__link", children: [jsxRuntime.jsx("span", { children: item.linkText || 'View' }), jsxRuntime.jsx(ExternalLinkIcon, {})] }))] }))] }));
28754
28712
  }
28755
28713
 
28756
28714
  /**
28757
- * Register microsoft-calendar-appointment action handler and renderer.
28758
- * Called by initializeActionHandlers to prevent tree-shaking.
28715
+ * URL validation utilities for images, cards, and links
28716
+ * Prevents 404 errors by validating URLs before display
28759
28717
  */
28760
- function registerMicrosoftCalendarAction() {
28761
- // Register the handler
28762
- registerMicrosoftCalendarHandler();
28763
- // Register the renderer
28764
- actionRenderers["microsoft-calendar-appointment"] = (message, accentColor, _variant, onActionDismiss) => {
28765
- const action = message.action;
28766
- if (!action)
28767
- return null;
28768
- const handleComplete = (toolCallId, newState) => {
28769
- resolveActionState(toolCallId, newState);
28718
+ /**
28719
+ * Validate a single URL by attempting to load it
28720
+ */
28721
+ /**
28722
+ * Validate an image URL by attempting to load it as an Image
28723
+ */
28724
+ async function validateImageUrl(url, timeout = 5000) {
28725
+ if (!url || typeof url !== 'string') {
28726
+ return { isValid: false, error: 'Invalid URL format' };
28727
+ }
28728
+ try {
28729
+ new URL(url);
28730
+ }
28731
+ catch (e) {
28732
+ return { isValid: false, error: 'Invalid URL structure' };
28733
+ }
28734
+ return new Promise((resolve) => {
28735
+ const img = new Image();
28736
+ const timeoutId = setTimeout(() => {
28737
+ img.src = '';
28738
+ resolve({ isValid: false, error: 'Image load timeout' });
28739
+ }, timeout);
28740
+ img.onload = () => {
28741
+ clearTimeout(timeoutId);
28742
+ resolve({ isValid: true });
28770
28743
  };
28771
- const handleDismiss = onActionDismiss
28772
- ? (toolCallId) => {
28773
- resolveActionState(toolCallId, { __dismissed: true });
28774
- onActionDismiss(toolCallId);
28744
+ img.onerror = () => {
28745
+ clearTimeout(timeoutId);
28746
+ resolve({ isValid: false, error: 'Failed to load image' });
28747
+ };
28748
+ img.src = url;
28749
+ });
28750
+ }
28751
+ /**
28752
+ * Validate multiple image URLs concurrently
28753
+ */
28754
+ async function validateImageUrls(urls, timeout = 5000, maxConcurrent = 10) {
28755
+ const results = new Map();
28756
+ // Process in batches to limit concurrent requests
28757
+ for (let i = 0; i < urls.length; i += maxConcurrent) {
28758
+ const batch = urls.slice(i, i + maxConcurrent);
28759
+ const batchResults = await Promise.all(batch.map(async (url) => {
28760
+ const result = await validateImageUrl(url, timeout);
28761
+ return { url, result };
28762
+ }));
28763
+ batchResults.forEach(({ url, result }) => {
28764
+ results.set(url, result);
28765
+ });
28766
+ }
28767
+ return results;
28768
+ }
28769
+ /**
28770
+ * Validate image items and separate valid from invalid
28771
+ */
28772
+ async function validateImageItems(items, timeout = 5000) {
28773
+ const urls = items.map(item => item.url).filter(Boolean);
28774
+ if (urls.length === 0) {
28775
+ return { validItems: [], invalidItems: items };
28776
+ }
28777
+ const validationResults = await validateImageUrls(urls, timeout);
28778
+ const validItems = [];
28779
+ const invalidItems = [];
28780
+ items.forEach(item => {
28781
+ if (!item.url) {
28782
+ invalidItems.push({
28783
+ ...item,
28784
+ isValid: false,
28785
+ validationError: 'Missing URL',
28786
+ });
28787
+ return;
28788
+ }
28789
+ const result = validationResults.get(item.url);
28790
+ if (result?.isValid) {
28791
+ validItems.push({
28792
+ ...item,
28793
+ isValid: true,
28794
+ });
28795
+ }
28796
+ else {
28797
+ invalidItems.push({
28798
+ ...item,
28799
+ isValid: false,
28800
+ validationError: result?.error || 'Unknown error',
28801
+ });
28802
+ }
28803
+ });
28804
+ return { validItems, invalidItems };
28805
+ }
28806
+ /**
28807
+ * Preload and validate images before rendering
28808
+ * Returns items with validation status
28809
+ */
28810
+ async function preloadAndValidateImages(items, timeout = 5000) {
28811
+ const { validItems, invalidItems } = await validateImageItems(items, timeout);
28812
+ if (invalidItems.length > 0) {
28813
+ console.warn('[URLValidator] Invalid image URLs detected:', invalidItems.map(i => ({
28814
+ url: i.url,
28815
+ error: i.validationError,
28816
+ })));
28817
+ }
28818
+ return [...validItems, ...invalidItems];
28819
+ }
28820
+
28821
+ function determineLayout(items, requestedLayout) {
28822
+ // Single item always uses single layout
28823
+ if (items.length === 1) {
28824
+ return 'single';
28825
+ }
28826
+ // For multiple items, use gallery (which now supports overlay titles)
28827
+ // Cards and gallery are now visually the same - 2-column grid with overlay titles
28828
+ return 'gallery';
28829
+ }
28830
+ function determineColumns(itemCount, maxColumns = 2) {
28831
+ if (itemCount === 1)
28832
+ return 1;
28833
+ return Math.min(2, maxColumns);
28834
+ }
28835
+ function StructuredImageDisplay({ action, onComplete, accentColor, maxColumns = 3 }) {
28836
+ const rawState = action.input;
28837
+ const hasCompletedRef = React.useRef(false);
28838
+ const [validatedItems, setValidatedItems] = React.useState([]);
28839
+ const [isValidating, setIsValidating] = React.useState(true);
28840
+ const [validationErrors, setValidationErrors] = React.useState([]);
28841
+ // Provide safe defaults if state is missing
28842
+ const state = {
28843
+ items: rawState?.items || [],
28844
+ layout: rawState?.layout || 'single',
28845
+ context: rawState?.context,
28846
+ columns: rawState?.columns,
28847
+ status: rawState?.status || 'displaying',
28848
+ error: rawState?.error,
28849
+ };
28850
+ const isError = state.status === 'error';
28851
+ // Validate URLs before displaying
28852
+ React.useEffect(() => {
28853
+ if (state.items.length === 0) {
28854
+ setIsValidating(false);
28855
+ return;
28856
+ }
28857
+ let isMounted = true;
28858
+ const validateItems = async () => {
28859
+ try {
28860
+ const validated = await preloadAndValidateImages(state.items, 3000);
28861
+ if (!isMounted)
28862
+ return;
28863
+ const valid = validated.filter(item => item.isValid !== false);
28864
+ const invalid = validated.filter(item => item.isValid === false);
28865
+ setValidatedItems(valid);
28866
+ if (invalid.length > 0) {
28867
+ const errors = invalid.map(item => `${item.url}: ${item.validationError || 'Failed to load'}`);
28868
+ setValidationErrors(errors);
28869
+ console.warn('[StructuredImageDisplay] Filtered invalid URLs:', errors);
28870
+ }
28775
28871
  }
28776
- : undefined;
28777
- return (jsxRuntime.jsx(MicrosoftCalendarCard, { action: {
28778
- implementation: action.implementation,
28779
- toolCallId: action.toolCallId,
28780
- actionId: action.actionId,
28781
- input: action.input,
28782
- state: action.state,
28783
- done: action.done ?? false,
28784
- }, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
28872
+ catch (error) {
28873
+ console.error('[StructuredImageDisplay] Validation error:', error);
28874
+ // Fallback to unvalidated items on error
28875
+ if (isMounted) {
28876
+ setValidatedItems(state.items);
28877
+ }
28878
+ }
28879
+ finally {
28880
+ if (isMounted) {
28881
+ setIsValidating(false);
28882
+ }
28883
+ }
28884
+ };
28885
+ validateItems();
28886
+ return () => {
28887
+ isMounted = false;
28888
+ };
28889
+ }, [state.items]);
28890
+ // Auto-complete on mount so AI can continue generating text response
28891
+ React.useEffect(() => {
28892
+ if (!action.done && !hasCompletedRef.current && onComplete && state.items.length > 0) {
28893
+ hasCompletedRef.current = true;
28894
+ onComplete(action.toolCallId, { ...state, status: 'displaying' });
28895
+ }
28896
+ }, [action.done, action.toolCallId, onComplete, state]);
28897
+ const handleInteraction = () => {
28898
+ onComplete?.(action.toolCallId, { ...state, status: 'interacted' });
28899
+ };
28900
+ const handleLinkClick = (url) => {
28901
+ handleInteraction();
28902
+ };
28903
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28904
+ // Error state
28905
+ if (isError) {
28906
+ return (jsxRuntime.jsx("div", { className: "ai-chat-structured-image ai-chat-structured-image--error", style: style, children: jsxRuntime.jsx("div", { className: "ai-chat-structured-image__error", children: state.error || 'Failed to load media' }) }));
28907
+ }
28908
+ // Loading state
28909
+ if (isValidating) {
28910
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-structured-image", style: style, children: [state.context && (jsxRuntime.jsx("p", { className: "ai-chat-structured-image__context", children: state.context })), jsxRuntime.jsx("div", { className: "ai-chat-structured-image__loading", children: "Validating images..." })] }));
28911
+ }
28912
+ // No valid items after validation
28913
+ if (validatedItems.length === 0) {
28914
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-structured-image", style: style, children: [state.context && (jsxRuntime.jsx("p", { className: "ai-chat-structured-image__context", children: state.context })), validationErrors.length > 0 && (jsxRuntime.jsx("div", { className: "ai-chat-structured-image__error", children: "All images failed to load. Please check the URLs." }))] }));
28915
+ }
28916
+ const layout = determineLayout(validatedItems, state.layout);
28917
+ const columns = state.columns || determineColumns(validatedItems.length, maxColumns);
28918
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-structured-image", style: style, children: [state.context && (jsxRuntime.jsx("p", { className: "ai-chat-structured-image__context", children: state.context })), validationErrors.length > 0 && (jsxRuntime.jsxs("div", { className: "ai-chat-structured-image__warning", children: [validationErrors.length, " image(s) could not be loaded and were filtered."] })), layout === 'single' && validatedItems[0] && (jsxRuntime.jsx(ImageCard, { item: validatedItems[0], accentColor: accentColor, onLinkClick: handleLinkClick })), layout === 'gallery' && (jsxRuntime.jsx(ImageGallery, { items: validatedItems, columns: columns, accentColor: accentColor, maxColumns: maxColumns })), layout === 'cards' && (jsxRuntime.jsx("div", { className: "ai-chat-structured-image__cards", style: { '--card-columns': validatedItems.length === 1 ? 1 : 2 }, children: validatedItems.map((item, index) => (jsxRuntime.jsx(ProjectCard, { item: item, accentColor: accentColor, onLinkClick: handleLinkClick, variant: "overlay" }, index))) })), layout === 'carousel' && (jsxRuntime.jsx(ImageCarousel, { items: validatedItems, accentColor: accentColor, onLinkClick: handleLinkClick }))] }));
28919
+ }
28920
+ function ChevronLeftIcon() {
28921
+ return (jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "15 18 9 12 15 6" }) }));
28922
+ }
28923
+ function ChevronRightIcon() {
28924
+ return (jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "9 18 15 12 9 6" }) }));
28925
+ }
28926
+ function ImageCarousel({ items, accentColor, onLinkClick }) {
28927
+ const [currentIndex, setCurrentIndex] = React.useState(0);
28928
+ const containerRef = React.useRef(null);
28929
+ const goToPrevious = () => {
28930
+ setCurrentIndex(prev => prev === 0 ? items.length - 1 : prev - 1);
28785
28931
  };
28932
+ const goToNext = () => {
28933
+ setCurrentIndex(prev => prev === items.length - 1 ? 0 : prev + 1);
28934
+ };
28935
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28936
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-image-carousel", style: style, ref: containerRef, children: [jsxRuntime.jsx("div", { className: "ai-chat-image-carousel__track", style: { transform: `translateX(-${currentIndex * 100}%)` }, children: items.map((item, index) => (jsxRuntime.jsx("div", { className: "ai-chat-image-carousel__slide", children: jsxRuntime.jsx(ProjectCard, { item: item, accentColor: accentColor, onLinkClick: onLinkClick }) }, index))) }), items.length > 1 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { className: "ai-chat-image-carousel__nav prev", onClick: goToPrevious, "aria-label": "Previous", children: jsxRuntime.jsx(ChevronLeftIcon, {}) }), jsxRuntime.jsx("button", { className: "ai-chat-image-carousel__nav next", onClick: goToNext, "aria-label": "Next", children: jsxRuntime.jsx(ChevronRightIcon, {}) }), jsxRuntime.jsx("div", { className: "ai-chat-image-carousel__dots", children: items.map((_, index) => (jsxRuntime.jsx("button", { className: `ai-chat-image-carousel__dot ${index === currentIndex ? 'active' : ''}`, onClick: () => setCurrentIndex(index), "aria-label": `Go to slide ${index + 1}` }, index))) })] }))] }));
28937
+ }
28938
+
28939
+ const pendingResolvers = new Map();
28940
+ const resumeCallbacks = new Map();
28941
+ const frontendActionHandlers = {};
28942
+ const actionRenderers = {};
28943
+ function getFrontendActionHandler(implementation) {
28944
+ return frontendActionHandlers[implementation];
28945
+ }
28946
+ function getActionRenderer(implementation) {
28947
+ return actionRenderers[implementation];
28948
+ }
28949
+ function waitForActionState(toolCallId) {
28950
+ return new Promise((resolve) => {
28951
+ pendingResolvers.set(toolCallId, resolve);
28952
+ });
28953
+ }
28954
+ function resolveActionState(toolCallId, state) {
28955
+ const resolver = pendingResolvers.get(toolCallId);
28956
+ if (resolver) {
28957
+ pendingResolvers.delete(toolCallId);
28958
+ resolver(state);
28959
+ return;
28960
+ }
28961
+ const resumeCallback = resumeCallbacks.get(toolCallId);
28962
+ if (resumeCallback) {
28963
+ resumeCallback(state).catch((error) => {
28964
+ console.error("[Action] Failed to resume action:", error);
28965
+ });
28966
+ }
28967
+ }
28968
+ function registerActionResumeCallback(toolCallId, callback) {
28969
+ resumeCallbacks.set(toolCallId, callback);
28970
+ }
28971
+ function unregisterActionResumeCallback(toolCallId) {
28972
+ resumeCallbacks.delete(toolCallId);
28786
28973
  }
28787
28974
 
28788
28975
  /**
@@ -28790,9 +28977,15 @@ function registerMicrosoftCalendarAction() {
28790
28977
  * Called by initializeActionHandlers to prevent tree-shaking.
28791
28978
  */
28792
28979
  function registerLinkPreviewAction() {
28793
- // Handler - auto-completes immediately since no user input is needed
28980
+ // Handler - auto-completes immediately, returns body for agent
28794
28981
  frontendActionHandlers["link-preview"] = async (_input, state, _context) => {
28795
- return { ...state, status: "displaying" };
28982
+ const links = state?.links || [];
28983
+ // Return body directly - sent to backend via continueAgentAction
28984
+ return {
28985
+ status: "displayed",
28986
+ linkCount: links.length,
28987
+ message: `Displayed ${links.length} link preview${links.length > 1 ? 's' : ''}.`,
28988
+ };
28796
28989
  };
28797
28990
  // Renderer - displays the link preview card
28798
28991
  actionRenderers["link-preview"] = (message, accentColor) => {
@@ -28802,16 +28995,15 @@ function registerLinkPreviewAction() {
28802
28995
  const handleComplete = (toolCallId, newState) => {
28803
28996
  resolveActionState(toolCallId, newState);
28804
28997
  };
28805
- // Check if action state indicates it's already complete (displaying or clicked)
28806
- const state = action.state;
28807
- const status = state?.status;
28808
- const isDone = action.done || status === "displaying" || status === "clicked";
28998
+ // Check if action input indicates it's already complete (displaying or clicked)
28999
+ const input = action.input;
29000
+ const status = input?.status;
29001
+ const isDone = action.done || status === "displaying" || status === "displayed" || status === "clicked";
28809
29002
  return (jsxRuntime.jsx(LinkPreviewCard, { action: {
28810
29003
  implementation: action.implementation,
28811
29004
  toolCallId: action.toolCallId,
28812
29005
  actionId: action.actionId,
28813
29006
  input: action.input,
28814
- state: action.state,
28815
29007
  done: isDone,
28816
29008
  }, onComplete: handleComplete, accentColor: accentColor }));
28817
29009
  };
@@ -28822,9 +29014,15 @@ function registerLinkPreviewAction() {
28822
29014
  * Called by initializeActionHandlers to prevent tree-shaking.
28823
29015
  */
28824
29016
  function registerVideoPlayerAction() {
28825
- // Handler - auto-completes immediately since no user input is needed
29017
+ // Handler - auto-completes immediately, returns body for agent
28826
29018
  frontendActionHandlers["video-player"] = async (_input, state, _context) => {
28827
- return { ...state, status: "displaying" };
29019
+ const videos = state?.videos || [];
29020
+ // Return body directly - sent to backend via continueAgentAction
29021
+ return {
29022
+ status: "displayed",
29023
+ videoCount: videos.length,
29024
+ message: `Displayed ${videos.length} video${videos.length !== 1 ? 's' : ''}.`,
29025
+ };
28828
29026
  };
28829
29027
  // Renderer - displays the embedded video player card
28830
29028
  actionRenderers["video-player"] = (message, accentColor) => {
@@ -28834,16 +29032,15 @@ function registerVideoPlayerAction() {
28834
29032
  const handleComplete = (toolCallId, newState) => {
28835
29033
  resolveActionState(toolCallId, newState);
28836
29034
  };
28837
- // Check if action state indicates it's already complete (displaying or played)
28838
- const state = action.state;
28839
- const status = state?.status;
28840
- const isDone = action.done || status === "displaying" || status === "played";
29035
+ // Check if action input indicates it's already complete (displaying or played)
29036
+ const input = action.input;
29037
+ const status = input?.status;
29038
+ const isDone = action.done || status === "displaying" || status === "displayed" || status === "played";
28841
29039
  return (jsxRuntime.jsx(VideoPlayerCard, { action: {
28842
29040
  implementation: action.implementation,
28843
29041
  toolCallId: action.toolCallId,
28844
29042
  actionId: action.actionId,
28845
29043
  input: action.input,
28846
- state: action.state,
28847
29044
  done: isDone,
28848
29045
  }, onComplete: handleComplete, accentColor: accentColor }));
28849
29046
  };
@@ -28854,9 +29051,15 @@ function registerVideoPlayerAction() {
28854
29051
  * Called by initializeActionHandlers to prevent tree-shaking.
28855
29052
  */
28856
29053
  function registerLocationCardAction() {
28857
- // Handler - auto-completes immediately since no user input is needed
29054
+ // Handler - auto-completes immediately, returns body for agent
28858
29055
  frontendActionHandlers["location-card"] = async (_input, state, _context) => {
28859
- return { ...state, status: "displaying" };
29056
+ const locations = state?.locations || [];
29057
+ // Return body directly - sent to backend via continueAgentAction
29058
+ return {
29059
+ status: "displayed",
29060
+ locationCount: locations.length,
29061
+ message: `Displayed ${locations.length} location${locations.length !== 1 ? 's' : ''}.`,
29062
+ };
28860
29063
  };
28861
29064
  // Renderer - displays the location card
28862
29065
  actionRenderers["location-card"] = (message, accentColor, variant) => {
@@ -28866,25 +29069,30 @@ function registerLocationCardAction() {
28866
29069
  const handleComplete = (toolCallId, newState) => {
28867
29070
  resolveActionState(toolCallId, newState);
28868
29071
  };
28869
- // Check if action state indicates it's already complete
28870
- const state = action.state;
28871
- const status = state?.status;
28872
- const isDone = action.done || status === "displaying" || status === "directions_opened";
29072
+ // Check if action input indicates it's already complete
29073
+ const input = action.input;
29074
+ const status = input?.status;
29075
+ const isDone = action.done || status === "displaying" || status === "displayed" || status === "directions_opened";
28873
29076
  return (jsxRuntime.jsx(LocationCard, { action: {
28874
29077
  implementation: action.implementation,
28875
29078
  toolCallId: action.toolCallId,
28876
29079
  actionId: action.actionId,
28877
29080
  input: action.input,
28878
- state: action.state,
28879
29081
  done: isDone,
28880
29082
  }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28881
29083
  };
28882
29084
  }
28883
29085
 
28884
29086
  function registerContactCardAction() {
28885
- // Handler - auto-completes immediately since no user input is needed
29087
+ // Handler - auto-completes immediately, returns body for agent
28886
29088
  frontendActionHandlers['contact-card'] = async (_input, state, _context) => {
28887
- return { ...state, status: 'displaying' };
29089
+ const contacts = state?.contacts || [];
29090
+ // Return body directly - sent to backend via continueAgentAction
29091
+ return {
29092
+ status: 'displayed',
29093
+ contactCount: contacts.length,
29094
+ message: `Displayed ${contacts.length} contact${contacts.length !== 1 ? 's' : ''}.`,
29095
+ };
28888
29096
  };
28889
29097
  // Renderer - displays the contact card
28890
29098
  actionRenderers['contact-card'] = (message, accentColor, variant) => {
@@ -28894,16 +29102,15 @@ function registerContactCardAction() {
28894
29102
  const handleComplete = (toolCallId, newState) => {
28895
29103
  resolveActionState(toolCallId, newState);
28896
29104
  };
28897
- // Check if action state indicates it's already complete
28898
- const state = action.state;
28899
- const status = state?.status;
28900
- const isDone = action.done || status === 'displaying' || status === 'contacted';
29105
+ // Check if action input indicates it's already complete
29106
+ const input = action.input;
29107
+ const status = input?.status;
29108
+ const isDone = action.done || status === 'displaying' || status === 'displayed' || status === 'contacted';
28901
29109
  return (jsxRuntime.jsx(ContactCard, { action: {
28902
29110
  implementation: action.implementation,
28903
29111
  toolCallId: action.toolCallId,
28904
29112
  actionId: action.actionId,
28905
29113
  input: action.input,
28906
- state: action.state,
28907
29114
  done: isDone,
28908
29115
  }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28909
29116
  };
@@ -28923,16 +29130,15 @@ function registerQueryContactDirectoryAction() {
28923
29130
  const handleComplete = (toolCallId, newState) => {
28924
29131
  resolveActionState(toolCallId, newState);
28925
29132
  };
28926
- // Check if action state indicates it's already complete
28927
- const state = action.state;
28928
- const status = state?.status;
29133
+ // Check if action input indicates it's already complete
29134
+ const input = action.input;
29135
+ const status = input?.status;
28929
29136
  const isDone = action.done || status === 'displaying' || status === 'contacted';
28930
29137
  return (jsxRuntime.jsx(ContactCard, { action: {
28931
29138
  implementation: action.implementation,
28932
29139
  toolCallId: action.toolCallId,
28933
29140
  actionId: action.actionId,
28934
29141
  input: action.input,
28935
- state: action.state,
28936
29142
  done: isDone,
28937
29143
  }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28938
29144
  };
@@ -28944,7 +29150,9 @@ function registerDisplayFormAction() {
28944
29150
  return waitForActionState(context.toolCallId);
28945
29151
  };
28946
29152
  // Renderer - displays the form card
28947
- actionRenderers['display-form'] = (message, accentColor, variant, onActionDismiss) => {
29153
+ // Rendering is based only on action.input and action.done
29154
+ // When done=true, FormCard shows a simple completion indicator
29155
+ actionRenderers['display-form'] = (message, accentColor, _variant, onActionDismiss) => {
28948
29156
  const action = message.action;
28949
29157
  if (!action)
28950
29158
  return null;
@@ -28952,22 +29160,14 @@ function registerDisplayFormAction() {
28952
29160
  resolveActionState(toolCallId, newState);
28953
29161
  };
28954
29162
  const handleDismiss = onActionDismiss
28955
- ? (toolCallId) => {
28956
- resolveActionState(toolCallId, { __dismissed: true });
28957
- onActionDismiss(toolCallId);
28958
- }
29163
+ ? (toolCallId) => onActionDismiss(toolCallId)
28959
29164
  : undefined;
28960
- // Check if action state indicates it's already complete
28961
- const state = action.state;
28962
- const status = state?.status;
28963
- const isDone = action.done || status === 'completed' || status === 'submitted';
28964
29165
  return (jsxRuntime.jsx(FormCard, { action: {
28965
29166
  implementation: action.implementation,
28966
29167
  toolCallId: action.toolCallId,
28967
29168
  actionId: action.actionId,
28968
29169
  input: action.input,
28969
- state: action.state,
28970
- done: isDone,
29170
+ done: action.done ?? false,
28971
29171
  }, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
28972
29172
  };
28973
29173
  }
@@ -28990,21 +29190,64 @@ function registerBookContactAppointmentAction() {
28990
29190
  // Register the handler
28991
29191
  registerBookContactAppointmentHandler();
28992
29192
  // Register the renderer
28993
- actionRenderers['book-contact-appointment'] = (message, accentColor) => {
29193
+ actionRenderers['book-contact-appointment'] = (message, accentColor, _variant, _onActionDismiss, onCallEndpoint) => {
28994
29194
  const action = message.action;
28995
29195
  if (!action)
28996
29196
  return null;
28997
29197
  const handleComplete = (toolCallId, newState) => {
28998
29198
  resolveActionState(toolCallId, newState);
28999
29199
  };
29200
+ // Create action-specific endpoint callback
29201
+ // Include toolCallId for done flag enforcement (server rejects calls for completed actions)
29202
+ const handleCallEndpoint = onCallEndpoint
29203
+ ? async (endpoint, input, options) => {
29204
+ return onCallEndpoint(action.actionId, endpoint, input, { ...options, toolCallId: action.toolCallId });
29205
+ }
29206
+ : undefined;
29207
+ // Create dismiss handler
29208
+ const handleDismiss = _onActionDismiss
29209
+ ? (toolCallId) => _onActionDismiss(toolCallId)
29210
+ : undefined;
29000
29211
  return (jsxRuntime.jsx(BookContactAppointmentCard, { action: {
29001
29212
  implementation: action.implementation,
29002
29213
  toolCallId: action.toolCallId,
29003
29214
  actionId: action.actionId,
29004
29215
  input: action.input,
29005
- state: action.state,
29006
29216
  done: action.done ?? false,
29007
- }, onComplete: handleComplete, accentColor: accentColor }));
29217
+ }, onComplete: handleComplete, onDismiss: handleDismiss, onCallEndpoint: handleCallEndpoint, accentColor: accentColor }));
29218
+ };
29219
+ }
29220
+
29221
+ function registerStructuredImageAction() {
29222
+ // Handler - auto-completes immediately, returns body for agent
29223
+ frontendActionHandlers['structured-image'] = async (_input, state, _context) => {
29224
+ const images = state?.images || [];
29225
+ // Return body directly - sent to backend via continueAgentAction
29226
+ return {
29227
+ status: 'displayed',
29228
+ imageCount: images.length,
29229
+ message: `Displayed ${images.length} image${images.length !== 1 ? 's' : ''}.`,
29230
+ };
29231
+ };
29232
+ // Renderer - displays the image content
29233
+ actionRenderers['structured-image'] = (message, accentColor, variant, onActionDismiss) => {
29234
+ const action = message.action;
29235
+ if (!action)
29236
+ return null;
29237
+ const handleComplete = (toolCallId, newState) => {
29238
+ resolveActionState(toolCallId, newState);
29239
+ };
29240
+ // Check if action input indicates it's already complete
29241
+ const input = action.input;
29242
+ const status = input?.status;
29243
+ const isDone = action.done || status === 'displaying' || status === 'displayed' || status === 'interacted';
29244
+ return (jsxRuntime.jsx(StructuredImageDisplay, { action: {
29245
+ implementation: action.implementation,
29246
+ toolCallId: action.toolCallId,
29247
+ actionId: action.actionId,
29248
+ input: action.input,
29249
+ done: isDone,
29250
+ }, onComplete: handleComplete, onDismiss: onActionDismiss ? () => onActionDismiss(action.toolCallId) : undefined, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 2 }));
29008
29251
  };
29009
29252
  }
29010
29253
 
@@ -29020,8 +29263,6 @@ function initializeActionHandlers() {
29020
29263
  return;
29021
29264
  initialized = true;
29022
29265
  // Explicitly call each registration function to prevent tree-shaking
29023
- registerGoogleCalendarAction();
29024
- registerMicrosoftCalendarAction();
29025
29266
  registerLinkPreviewAction();
29026
29267
  registerVideoPlayerAction();
29027
29268
  registerLocationCardAction();
@@ -29029,6 +29270,7 @@ function initializeActionHandlers() {
29029
29270
  registerContactCardAction();
29030
29271
  registerDisplayFormAction();
29031
29272
  registerBookContactAppointmentAction();
29273
+ registerStructuredImageAction();
29032
29274
  }
29033
29275
 
29034
29276
  /**
@@ -29291,9 +29533,49 @@ function hydrateToolNames(messages) {
29291
29533
  };
29292
29534
  });
29293
29535
  }
29536
+ /**
29537
+ * Clean up messages that were interrupted during streaming.
29538
+ * - Marks streaming messages as complete
29539
+ * - Removes empty assistant messages
29540
+ * - Marks incomplete tool calls as done
29541
+ */
29542
+ function cleanupInterruptedMessages(messages) {
29543
+ return messages
29544
+ .map((msg) => {
29545
+ // Mark streaming messages as complete
29546
+ if (msg.isStreaming) {
29547
+ msg = { ...msg, isStreaming: false };
29548
+ }
29549
+ // Mark incomplete tool calls as done (they were interrupted)
29550
+ if (msg.message.role === 'tool' && msg.action && !msg.action.done) {
29551
+ msg = {
29552
+ ...msg,
29553
+ action: {
29554
+ ...msg.action,
29555
+ done: true,
29556
+ // Mark as interrupted so UI can show appropriate state
29557
+ input: {
29558
+ ...msg.action.input,
29559
+ _interrupted: true,
29560
+ },
29561
+ },
29562
+ };
29563
+ }
29564
+ return msg;
29565
+ })
29566
+ // Remove empty assistant messages (streaming was interrupted before content)
29567
+ .filter((msg) => {
29568
+ if (msg.message.role === 'assistant') {
29569
+ const content = msg.message.content;
29570
+ return content && typeof content === 'string' && content.trim().length > 0;
29571
+ }
29572
+ return true;
29573
+ });
29574
+ }
29294
29575
  function hydrateMessages(messages) {
29295
29576
  const visibleMessages = messages.filter((message) => !message.action?.hidden);
29296
- return hydrateToolNames(visibleMessages);
29577
+ const cleanedMessages = cleanupInterruptedMessages(visibleMessages);
29578
+ return hydrateToolNames(cleanedMessages);
29297
29579
  }
29298
29580
 
29299
29581
  function deriveErrorInfo(error) {
@@ -29363,6 +29645,75 @@ function deriveErrorInfo(error) {
29363
29645
  return { message: 'Something went wrong. Please try again.' };
29364
29646
  }
29365
29647
 
29648
+ /**
29649
+ * Stream Buffer
29650
+ * Smooths out streaming text rendering by buffering words and draining them
29651
+ * with requestAnimationFrame for a fluid typing effect.
29652
+ */
29653
+ function createStreamBuffer() {
29654
+ return {
29655
+ pendingWords: [],
29656
+ displayedContent: '',
29657
+ streamEnded: false,
29658
+ rafHandle: null,
29659
+ };
29660
+ }
29661
+ function appendToBuffer(buffer, content) {
29662
+ // Split by whitespace while preserving the whitespace characters
29663
+ const words = content.split(/(\s+)/);
29664
+ buffer.pendingWords.push(...words.filter(w => w.length > 0));
29665
+ }
29666
+ function startBufferDrain(buffer, onContentUpdate) {
29667
+ if (buffer.rafHandle !== null) {
29668
+ return; // Already draining
29669
+ }
29670
+ const drainLoop = () => {
29671
+ if (buffer.pendingWords.length === 0) {
29672
+ if (buffer.streamEnded) {
29673
+ buffer.rafHandle = null;
29674
+ return;
29675
+ }
29676
+ // No words to render, wait for more
29677
+ buffer.rafHandle = requestAnimationFrame(drainLoop);
29678
+ return;
29679
+ }
29680
+ // Adaptive: render more words if buffer is filling up
29681
+ const wordsToRender = buffer.pendingWords.length > 20 ? 3 : 1;
29682
+ const chunk = buffer.pendingWords.splice(0, wordsToRender).join('');
29683
+ buffer.displayedContent += chunk;
29684
+ onContentUpdate(buffer.displayedContent);
29685
+ buffer.rafHandle = requestAnimationFrame(drainLoop);
29686
+ };
29687
+ buffer.rafHandle = requestAnimationFrame(drainLoop);
29688
+ }
29689
+ function flushBuffer(buffer) {
29690
+ buffer.streamEnded = true;
29691
+ if (buffer.rafHandle !== null) {
29692
+ cancelAnimationFrame(buffer.rafHandle);
29693
+ buffer.rafHandle = null;
29694
+ }
29695
+ const remaining = buffer.pendingWords.join('');
29696
+ buffer.displayedContent += remaining;
29697
+ buffer.pendingWords = [];
29698
+ return buffer.displayedContent;
29699
+ }
29700
+ function cancelBuffer(buffer) {
29701
+ if (buffer.rafHandle !== null) {
29702
+ cancelAnimationFrame(buffer.rafHandle);
29703
+ buffer.rafHandle = null;
29704
+ }
29705
+ buffer.streamEnded = true;
29706
+ }
29707
+ function resetBuffer(buffer) {
29708
+ if (buffer.rafHandle !== null) {
29709
+ cancelAnimationFrame(buffer.rafHandle);
29710
+ buffer.rafHandle = null;
29711
+ }
29712
+ buffer.pendingWords = [];
29713
+ buffer.displayedContent = '';
29714
+ buffer.streamEnded = false;
29715
+ }
29716
+
29366
29717
  function createStreamState() {
29367
29718
  return {
29368
29719
  currentContent: "",
@@ -29372,6 +29723,7 @@ function createStreamState() {
29372
29723
  sources: [],
29373
29724
  toolCallToActionId: {},
29374
29725
  requestId: generateMessageId(),
29726
+ buffer: createStreamBuffer(),
29375
29727
  };
29376
29728
  }
29377
29729
  function upsertMessage(setState, message, isTyping) {
@@ -29434,6 +29786,8 @@ function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
29434
29786
  },
29435
29787
  isStreaming: false,
29436
29788
  toolExecuting: existingName,
29789
+ // Mark action as done when tool message is finalized
29790
+ action: entry.action ? { ...entry.action, done: true } : undefined,
29437
29791
  };
29438
29792
  });
29439
29793
  return { ...prev, messages, isTyping: false, isLoading: false };
@@ -29442,26 +29796,34 @@ function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
29442
29796
  }
29443
29797
 
29444
29798
  function handleContentEvent(event, streamState, onMessageUpdate, setState) {
29799
+ // Track full content for finalization
29445
29800
  streamState.currentContent += event.content;
29446
- const assistantMessage = {
29447
- id: streamState.currentMessageId,
29448
- message: { role: "assistant", content: streamState.currentContent },
29449
- timestamp: new Date().toISOString(),
29450
- sources: streamState.sources,
29451
- isStreaming: true,
29452
- };
29453
- streamState.newMessageIds.add(assistantMessage.id);
29454
- onMessageUpdate(assistantMessage);
29455
- const hasContent = assistantMessage.message.content?.trim().length || 0 > 0;
29456
- const isToolExecuting = streamState.activeToolCallCount > 0;
29457
- const isTyping = (!hasContent && assistantMessage.isStreaming) || isToolExecuting;
29458
- upsertMessage(setState, assistantMessage, isTyping);
29801
+ // Add to buffer for smooth rendering
29802
+ appendToBuffer(streamState.buffer, event.content);
29803
+ // Start drain loop if not already running
29804
+ startBufferDrain(streamState.buffer, (displayedContent) => {
29805
+ const assistantMessage = {
29806
+ id: streamState.currentMessageId,
29807
+ message: { role: "assistant", content: displayedContent },
29808
+ timestamp: new Date().toISOString(),
29809
+ sources: streamState.sources,
29810
+ isStreaming: true,
29811
+ };
29812
+ streamState.newMessageIds.add(assistantMessage.id);
29813
+ onMessageUpdate(assistantMessage);
29814
+ const hasContent = displayedContent.trim().length > 0;
29815
+ const isToolExecuting = streamState.activeToolCallCount > 0;
29816
+ const isTyping = (!hasContent && assistantMessage.isStreaming) || isToolExecuting;
29817
+ upsertMessage(setState, assistantMessage, isTyping);
29818
+ });
29459
29819
  }
29460
29820
  function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
29461
- if (streamState.currentContent.trim()) {
29821
+ // Flush buffer before tool starts
29822
+ const flushedContent = flushBuffer(streamState.buffer);
29823
+ if (flushedContent.trim()) {
29462
29824
  const finalAssistant = {
29463
29825
  id: streamState.currentMessageId,
29464
- message: { role: "assistant", content: streamState.currentContent },
29826
+ message: { role: "assistant", content: flushedContent },
29465
29827
  timestamp: new Date().toISOString(),
29466
29828
  sources: streamState.sources,
29467
29829
  isStreaming: false,
@@ -29472,6 +29834,8 @@ function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
29472
29834
  streamState.currentContent = "";
29473
29835
  streamState.currentMessageId = generateMessageId();
29474
29836
  }
29837
+ // Reset buffer for post-tool content
29838
+ resetBuffer(streamState.buffer);
29475
29839
  const toolMessageId = event.tool_call_id;
29476
29840
  streamState.activeToolCallCount += 1;
29477
29841
  streamState.newMessageIds.add(toolMessageId);
@@ -29489,44 +29853,22 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
29489
29853
  streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
29490
29854
  setState(prev => {
29491
29855
  const messages = prev.messages.map((msg) => {
29492
- const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
29493
- if (!matchesToolCall) {
29856
+ if (msg.message.role !== "tool" || msg.message.tool_call_id !== event.tool_call_id) {
29494
29857
  return msg;
29495
29858
  }
29496
- const existingName = msg.message.name || event.tool_name;
29497
- let action = msg.action;
29498
- if (event.action_id && event.implementation) {
29499
- action = {
29500
- ...action,
29501
- implementation: event.implementation,
29502
- toolCallId: event.tool_call_id,
29503
- actionId: event.action_id,
29504
- input: (event.input || {}),
29505
- state: (event.state || {}),
29506
- done: event.done,
29507
- };
29508
- }
29509
- else if (action) {
29510
- action = {
29511
- ...action,
29512
- input: event.input ? event.input : action.input,
29513
- state: event.state ? event.state : action.state,
29514
- done: event.done,
29515
- };
29516
- }
29517
- const updatedMsg = {
29859
+ const toolName = msg.message.name || event.tool_name;
29860
+ // For actions: just mark as done, preserve existing input (display data is immutable)
29861
+ // For non-action tools: update normally
29862
+ const action = msg.action
29863
+ ? { ...msg.action, done: event.done }
29864
+ : undefined;
29865
+ return {
29518
29866
  ...msg,
29519
- message: {
29520
- role: "tool",
29521
- content: event.state ? JSON.stringify(event.state) : (typeof msg.message.content === "string" ? msg.message.content : ""),
29522
- tool_call_id: event.tool_call_id,
29523
- name: existingName,
29524
- },
29867
+ message: { ...msg.message, name: toolName },
29525
29868
  isStreaming: false,
29526
- toolExecuting: existingName,
29869
+ toolExecuting: toolName,
29527
29870
  action,
29528
29871
  };
29529
- return updatedMsg;
29530
29872
  });
29531
29873
  return { ...prev, messages, isTyping: true, isLoading: false };
29532
29874
  });
@@ -29559,11 +29901,6 @@ function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
29559
29901
  return { ...prev, messages, isTyping: true, isLoading: false };
29560
29902
  });
29561
29903
  }
29562
- function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
29563
- streamState.sources = event.sources;
29564
- streamState.toolCallToActionId = event.tool_call_to_action_id;
29565
- finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
29566
- }
29567
29904
  function handleHaltEvent(event, _streamState, onMessageUpdate, setState) {
29568
29905
  const toolNames = event.tool_calls.map(call => call.name).join(", ");
29569
29906
  const notice = toolNames
@@ -29578,7 +29915,8 @@ function handleHaltEvent(event, _streamState, onMessageUpdate, setState) {
29578
29915
  };
29579
29916
  onMessageUpdate(haltMessage);
29580
29917
  upsertMessage(setState, haltMessage, false);
29581
- setState(prev => ({ ...prev, error: "Awaiting external tool handling." }));
29918
+ // Stop loading/typing state when halted
29919
+ setState(prev => ({ ...prev, isLoading: false, isTyping: false, error: "Awaiting external tool handling." }));
29582
29920
  }
29583
29921
  function handleErrorEvent(_event, _streamState, onMessageUpdate, setState) {
29584
29922
  const errorMessage = {
@@ -29590,6 +29928,8 @@ function handleErrorEvent(_event, _streamState, onMessageUpdate, setState) {
29590
29928
  };
29591
29929
  onMessageUpdate(errorMessage);
29592
29930
  upsertMessage(setState, errorMessage, false);
29931
+ // Stop loading/typing state on error
29932
+ setState(prev => ({ ...prev, isLoading: false, isTyping: false }));
29593
29933
  }
29594
29934
  const eventHandlers = {
29595
29935
  content: handleContentEvent,
@@ -29617,10 +29957,37 @@ function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
29617
29957
  console.warn('[Chat] Unknown event type:', event.type);
29618
29958
  }
29619
29959
  }
29620
-
29621
- function isDismissedState(state) {
29622
- return Boolean(state.__dismissed);
29960
+ function handleDoneEvent(event, streamState, onMessageUpdate, setState) {
29961
+ // Flush any remaining buffered content
29962
+ const flushedContent = flushBuffer(streamState.buffer);
29963
+ // Update the final message with complete content if there was content
29964
+ if (flushedContent.trim()) {
29965
+ const finalMessage = {
29966
+ id: streamState.currentMessageId,
29967
+ message: { role: "assistant", content: flushedContent },
29968
+ timestamp: new Date().toISOString(),
29969
+ sources: event.sources,
29970
+ isStreaming: false,
29971
+ };
29972
+ streamState.newMessageIds.add(finalMessage.id);
29973
+ onMessageUpdate(finalMessage);
29974
+ upsertMessage(setState, finalMessage, false);
29975
+ }
29976
+ streamState.sources = event.sources;
29977
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
29978
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
29623
29979
  }
29980
+
29981
+ /**
29982
+ * Handle the action loop for halting actions.
29983
+ *
29984
+ * Flow:
29985
+ * 1. Display the action in UI
29986
+ * 2. Call the frontend handler (which waits for user interaction or returns immediately for display actions)
29987
+ * 3. Handler returns body when complete
29988
+ * 4. Send body to backend via continueAgentAction
29989
+ * 5. Process any subsequent events (may include new action_request for chained actions)
29990
+ */
29624
29991
  async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
29625
29992
  let pendingEvent = initialEvent;
29626
29993
  while (pendingEvent) {
@@ -29646,7 +30013,6 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29646
30013
  toolCallId: pendingEvent.tool_call_id,
29647
30014
  actionId: pendingEvent.action_id,
29648
30015
  input: pendingEvent.input,
29649
- state: pendingEvent.state,
29650
30016
  done: pendingEvent.done ?? false,
29651
30017
  },
29652
30018
  };
@@ -29671,9 +30037,13 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29671
30037
  upsertMessage(setState, errorMessage, false);
29672
30038
  return;
29673
30039
  }
29674
- let nextState;
30040
+ // Handler returns body when complete (for display actions this is immediate,
30041
+ // for interactive actions this waits for user completion)
30042
+ // Note: For halting actions, input contains the transformed data from getInitialClientState
30043
+ let body;
29675
30044
  try {
29676
- nextState = await handler(pendingEvent.input, pendingEvent.state, {
30045
+ body = await handler(pendingEvent.input, pendingEvent.input, // Input now contains the display data for halting actions
30046
+ {
29677
30047
  widgetId,
29678
30048
  conversationId,
29679
30049
  toolCallId: pendingEvent.tool_call_id,
@@ -29695,25 +30065,16 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29695
30065
  return;
29696
30066
  }
29697
30067
  pendingEvent = null;
29698
- const dismissed = isDismissedState(nextState);
29699
- if (!dismissed) {
29700
- const updatedToolMessage = {
29701
- ...toolMessage,
29702
- action: toolMessage.action ? { ...toolMessage.action, state: nextState } : toolMessage.action,
29703
- };
29704
- upsertMessage(setState, updatedToolMessage, true);
29705
- }
29706
- if (dismissed) {
29707
- return;
29708
- }
30068
+ // Send body to backend and continue agent
30069
+ // No need to update message - input is immutable and already contains display data
29709
30070
  let streamEnded = false;
29710
- for await (const event of client.continueAgentMessageStream(conversationId, resumeToolCallId, nextState)) {
30071
+ for await (const event of client.continueAgentAction(conversationId, resumeToolCallId, body)) {
29711
30072
  if (event.type === "action_request") {
30073
+ // Chained action - continue the loop
29712
30074
  pendingEvent = event;
29713
30075
  break;
29714
30076
  }
29715
30077
  if (event.type === "done") {
29716
- // Finalize tool message and stream messages
29717
30078
  finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
29718
30079
  streamState.sources = event.sources;
29719
30080
  streamState.toolCallToActionId = event.tool_call_to_action_id;
@@ -29743,61 +30104,118 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29743
30104
  }
29744
30105
  }
29745
30106
  }
29746
- function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate, createStreamState, registerCallback) {
30107
+ /**
30108
+ * Setup resume callbacks for incomplete actions after page reload.
30109
+ *
30110
+ * When a page reloads with an incomplete action, this sets up callbacks
30111
+ * so when the user completes the action, we can continue the agent flow.
30112
+ */
30113
+ function setupActionResumeCallbacks(messages, client, conversationId, widgetId, setState, onMessageUpdate, createStreamState, registerCallback) {
29747
30114
  // Find all incomplete actions and register resume callbacks
29748
30115
  for (const message of messages) {
29749
30116
  if (message.action && !message.action.done && !message.action.hidden) {
29750
- const toolCallId = message.action.toolCallId;
29751
- const toolName = message.message.name || message.toolExecuting || "tool";
29752
- registerCallback(toolCallId, async (newState) => {
29753
- // When user interacts with the action after reload, continue the stream
30117
+ const initialToolCallId = message.action.toolCallId;
30118
+ const initialToolName = message.message.name || message.toolExecuting || "tool";
30119
+ registerCallback(initialToolCallId, async (body) => {
30120
+ // When user completes the action after reload, continue the stream
29754
30121
  try {
29755
- // Update the action message with the new state and check completion
29756
- if (isDismissedState(newState)) {
29757
- setState(prev => ({ ...prev, isTyping: false }));
29758
- return;
29759
- }
29760
30122
  setState(prev => ({
29761
30123
  ...prev,
29762
- messages: prev.messages.map(m => {
29763
- if (m.action?.toolCallId !== toolCallId) {
29764
- return m;
29765
- }
29766
- if (!m.action) {
29767
- return m;
29768
- }
29769
- return { ...m, action: { ...m.action, state: newState } };
29770
- }),
29771
30124
  isTyping: true,
29772
30125
  }));
29773
30126
  const streamState = createStreamState();
29774
- // Continue the agent stream with the new state
29775
- for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
29776
- if (event.type === "done") {
29777
- finalizeToolMessage(streamState, setState, toolCallId, toolName);
29778
- streamState.sources = event.sources;
29779
- streamState.toolCallToActionId = event.tool_call_to_action_id;
29780
- finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
29781
- continue;
30127
+ let currentToolCallId = initialToolCallId;
30128
+ let currentToolName = initialToolName;
30129
+ let currentBody = body;
30130
+ // Loop to handle chained action_requests
30131
+ while (true) {
30132
+ let nextActionRequest = null;
30133
+ // Continue the agent with the body
30134
+ for await (const event of client.continueAgentAction(conversationId, currentToolCallId, currentBody)) {
30135
+ if (event.type === "action_request") {
30136
+ // Chained action - need to handle the new action request
30137
+ nextActionRequest = event;
30138
+ break;
30139
+ }
30140
+ if (event.type === "done") {
30141
+ finalizeToolMessage(streamState, setState, currentToolCallId, currentToolName);
30142
+ streamState.sources = event.sources;
30143
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
30144
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
30145
+ setState(prev => ({ ...prev, isTyping: false }));
30146
+ return;
30147
+ }
30148
+ if (event.type === "error") {
30149
+ const errorMessage = {
30150
+ id: generateMessageId(),
30151
+ message: {
30152
+ role: "assistant",
30153
+ content: "Sorry, an error occurred. Please try again later.",
30154
+ },
30155
+ timestamp: new Date().toISOString(),
30156
+ sources: [],
30157
+ isError: true,
30158
+ };
30159
+ upsertMessage(setState, errorMessage, false);
30160
+ setState(prev => ({ ...prev, isTyping: false }));
30161
+ return;
30162
+ }
30163
+ handleStreamEvent(event, streamState, onMessageUpdate, setState);
30164
+ }
30165
+ // If no action_request, stream ended normally
30166
+ if (!nextActionRequest) {
30167
+ setState(prev => ({ ...prev, isTyping: false }));
30168
+ return;
30169
+ }
30170
+ // Update UI with new action for the chained action
30171
+ const toolMessage = {
30172
+ id: nextActionRequest.tool_call_id,
30173
+ sources: [],
30174
+ message: {
30175
+ role: "tool",
30176
+ content: "",
30177
+ tool_call_id: nextActionRequest.tool_call_id,
30178
+ name: currentToolName,
30179
+ },
30180
+ timestamp: new Date().toISOString(),
30181
+ isStreaming: true,
30182
+ toolExecuting: currentToolName,
30183
+ action: {
30184
+ implementation: nextActionRequest.implementation,
30185
+ toolCallId: nextActionRequest.tool_call_id,
30186
+ actionId: nextActionRequest.action_id,
30187
+ input: nextActionRequest.input,
30188
+ done: nextActionRequest.done ?? false,
30189
+ },
30190
+ };
30191
+ upsertMessage(setState, toolMessage, true);
30192
+ // Wait for user to complete the chained action
30193
+ const handler = getFrontendActionHandler(nextActionRequest.implementation);
30194
+ if (!handler) {
30195
+ console.error("[Action Resume] No handler for implementation:", nextActionRequest.implementation);
30196
+ setState(prev => ({ ...prev, isTyping: false }));
30197
+ return;
30198
+ }
30199
+ let handlerResult;
30200
+ try {
30201
+ handlerResult = await handler(nextActionRequest.input, nextActionRequest.input, // Input contains display data for halting actions
30202
+ {
30203
+ widgetId,
30204
+ conversationId,
30205
+ toolCallId: nextActionRequest.tool_call_id,
30206
+ actionId: nextActionRequest.action_id,
30207
+ implementation: nextActionRequest.implementation,
30208
+ });
29782
30209
  }
29783
- if (event.type === "error") {
29784
- const errorMessage = {
29785
- id: generateMessageId(),
29786
- message: {
29787
- role: "assistant",
29788
- content: "Sorry, an error occurred. Please try again later.",
29789
- },
29790
- timestamp: new Date().toISOString(),
29791
- sources: [],
29792
- isError: true,
29793
- };
29794
- upsertMessage(setState, errorMessage, false);
30210
+ catch (handlerError) {
30211
+ console.error("[Action Resume] Handler failed:", handlerError);
29795
30212
  setState(prev => ({ ...prev, isTyping: false }));
29796
30213
  return;
29797
30214
  }
29798
- handleStreamEvent(event, streamState, onMessageUpdate, setState);
30215
+ // Continue loop with new body
30216
+ currentToolCallId = nextActionRequest.tool_call_id;
30217
+ currentBody = handlerResult;
29799
30218
  }
29800
- setState(prev => ({ ...prev, isTyping: false }));
29801
30219
  }
29802
30220
  catch (error) {
29803
30221
  console.error("[Action Resume] Failed to continue stream:", error);
@@ -29876,7 +30294,7 @@ function useChat(options) {
29876
30294
  }));
29877
30295
  // Setup resume callbacks for incomplete actions
29878
30296
  if (conversationId) {
29879
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
30297
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, widgetId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
29880
30298
  }
29881
30299
  }
29882
30300
  catch (error) {
@@ -29910,6 +30328,21 @@ function useChat(options) {
29910
30328
  saveConversation(widgetId, state.conversationId, state.messages);
29911
30329
  }
29912
30330
  }, [widgetId, state.messages, state.conversationId, state.config?.settings.persistConversation]);
30331
+ // Save conversation on page unload to preserve streaming state
30332
+ React.useEffect(() => {
30333
+ const persistConversation = state.config?.settings.persistConversation ?? true;
30334
+ if (!persistConversation || !isStorageAvailable())
30335
+ return;
30336
+ const handleBeforeUnload = () => {
30337
+ const currentState = stateRef.current;
30338
+ if (currentState.messages.length > 0 && currentState.conversationId) {
30339
+ // Force save current state before page closes
30340
+ saveConversation(widgetId, currentState.conversationId, currentState.messages);
30341
+ }
30342
+ };
30343
+ window.addEventListener('beforeunload', handleBeforeUnload);
30344
+ return () => window.removeEventListener('beforeunload', handleBeforeUnload);
30345
+ }, [widgetId, state.config?.settings.persistConversation]);
29913
30346
  const sendMessage = React.useCallback(async (content, files) => {
29914
30347
  const trimmedContent = content.trim();
29915
30348
  const hasFiles = !!files && files.length > 0;
@@ -29993,12 +30426,14 @@ function useChat(options) {
29993
30426
  stateRef.current.conversationId !== streamConversationId ||
29994
30427
  currentRequestIdRef.current !== streamRequestId) {
29995
30428
  console.log('[Widget] Stream aborted, conversation changed, or superseded by new request');
30429
+ cancelBuffer(streamState.buffer);
29996
30430
  break;
29997
30431
  }
29998
30432
  if (event.type === "action_request") {
29999
30433
  if (currentAbortController?.signal.aborted ||
30000
30434
  stateRef.current.conversationId !== streamConversationId ||
30001
30435
  currentRequestIdRef.current !== streamRequestId) {
30436
+ cancelBuffer(streamState.buffer);
30002
30437
  break;
30003
30438
  }
30004
30439
  await handleActionLoop(apiClient.current, event, streamState, (message) => {
@@ -30024,26 +30459,8 @@ function useChat(options) {
30024
30459
  if (lastStreamedMessage) {
30025
30460
  onMessage?.(lastStreamedMessage);
30026
30461
  }
30027
- const enableFollowUps = state.config?.settings.enableFollowUpSuggestions !== false;
30028
- const actionIds = state.config?.actions || [];
30029
- if (enableFollowUps) {
30030
- apiClient.current.generateFollowUps(stateRef.current.messages, actionIds)
30031
- .then(suggestions => {
30032
- if (suggestions.length > 0) {
30033
- setState(prev => {
30034
- const messages = [...prev.messages];
30035
- for (let i = messages.length - 1; i >= 0; i--) {
30036
- if (messages[i].message.role === 'assistant' && !messages[i].isError) {
30037
- messages[i] = { ...messages[i], suggestions };
30038
- break;
30039
- }
30040
- }
30041
- return { ...prev, messages };
30042
- });
30043
- }
30044
- })
30045
- .catch(err => console.warn('[Widget] Follow-up generation failed:', err));
30046
- }
30462
+ // Follow-up suggestions are now generated server-side in parallel and included in the done event
30463
+ // They are automatically attached to the last assistant message by finalizeStreamMessages()
30047
30464
  }
30048
30465
  catch (error) {
30049
30466
  console.error("[Widget] sendMessage error:", error);
@@ -30200,7 +30617,7 @@ function useChat(options) {
30200
30617
  messages: hydratedMessages,
30201
30618
  isLoading: false,
30202
30619
  }));
30203
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
30620
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, widgetId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
30204
30621
  if (persistConversation && isStorageAvailable()) {
30205
30622
  saveConversation(widgetId, conversation.id, hydratedMessages);
30206
30623
  }
@@ -30287,6 +30704,16 @@ function useChat(options) {
30287
30704
  return null;
30288
30705
  }
30289
30706
  }, [widgetId, state.config?.settings.persistConversation]);
30707
+ // Call an action endpoint directly (frontend-owned flow)
30708
+ // Auto-injects conversationId and toolCallId for done flag enforcement
30709
+ const callActionEndpoint = React.useCallback(async (actionId, endpoint, input, options) => {
30710
+ const enrichedInput = {
30711
+ ...input,
30712
+ conversationId: state.conversationId,
30713
+ toolCallId: options?.toolCallId,
30714
+ };
30715
+ return apiClient.current.callActionEndpoint(actionId, endpoint, enrichedInput, options?.token);
30716
+ }, [state.conversationId]);
30290
30717
  return {
30291
30718
  messages: state.messages,
30292
30719
  isLoading: state.isLoading,
@@ -30304,6 +30731,7 @@ function useChat(options) {
30304
30731
  startNewConversation,
30305
30732
  deleteConversation: deleteConversation$1,
30306
30733
  createDemoConversation,
30734
+ callActionEndpoint,
30307
30735
  };
30308
30736
  }
30309
30737
 
@@ -30319,17 +30747,19 @@ const PlusIcon = () => (jsxRuntime.jsxs("svg", { width: "22", height: "22", view
30319
30747
  const TrashIcon = () => (jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M3 6h18" }), jsxRuntime.jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }), jsxRuntime.jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })] }));
30320
30748
  const CloseIcon = () => (jsxRuntime.jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }));
30321
30749
  const BackIcon = () => (jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M19 12H5" }), jsxRuntime.jsx("path", { d: "M12 19l-7-7 7-7" })] }));
30322
- const ChatWindow = ({ messages, isLoading, isTyping, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick, onActionDismiss,
30750
+ const ChatWindow = ({ messages, isLoading, isTyping, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick, onActionDismiss, onCallEndpoint,
30323
30751
  // Chat history props (only active when persistConversation is true)
30324
30752
  conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
30325
30753
  // Override props for live preview
30326
- headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride, }) => {
30754
+ sizeOverride, headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride,
30755
+ // Demo mode
30756
+ onInputFocus, }) => {
30327
30757
  const appearance = config?.appearance;
30328
30758
  const settings = config?.settings;
30329
30759
  // Check if chat history should be shown (requires both persistConversation AND showChatHistory)
30330
30760
  const canShowHistory = (settings?.persistConversation ?? true) && (settings?.showChatHistory ?? true);
30331
30761
  // Apply overrides for live preview (overrides take priority over saved config)
30332
- const size = appearance?.size || 'medium';
30762
+ const size = sizeOverride ?? appearance?.size ?? 'medium';
30333
30763
  const headerTitle = headerTitleOverride ?? appearance?.headerTitle ?? 'AI Assistant';
30334
30764
  const welcomeTitle = welcomeTitleOverride ?? appearance?.welcomeTitle ?? '';
30335
30765
  const welcomeMessage = welcomeMessageOverride ?? appearance?.welcomeMessage ?? '';
@@ -30406,7 +30836,7 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
30406
30836
  jsxRuntime.jsxs("div", { className: "ai-chat-history-panel", children: [conversations.length === 0 ? (jsxRuntime.jsx("div", { className: "ai-chat-history-empty", children: "No previous conversations" })) : (jsxRuntime.jsx("div", { className: `ai-chat-history-list ${isHistoryExiting ? 'exiting' : ''}`, children: conversations.map((conv) => (jsxRuntime.jsx("div", { className: `ai-chat-history-item ${conv.id === currentConversationId ? 'active' : ''}`, onClick: () => handleSelectConversation(conv.id), children: jsxRuntime.jsxs("div", { className: "ai-chat-history-item-content", children: [jsxRuntime.jsx("div", { className: "ai-chat-history-item-preview", children: conv.preview }), onDeleteConversation && (jsxRuntime.jsx("button", { className: "ai-chat-history-item-delete", onClick: (e) => {
30407
30837
  e.stopPropagation();
30408
30838
  onDeleteConversation(conv.id);
30409
- }, "aria-label": "Delete conversation", children: jsxRuntime.jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsxRuntime.jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxRuntime.jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsxRuntime.jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), (() => {
30839
+ }, "aria-label": "Delete conversation", children: jsxRuntime.jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsxRuntime.jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick, onInputFocus: onInputFocus })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxRuntime.jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsxRuntime.jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), (() => {
30410
30840
  console.log('[DEBUG ChatWindow] Rendering MessageList with', messages.length, 'messages');
30411
30841
  messages.forEach((m, i) => {
30412
30842
  console.log(`[DEBUG ChatWindow] msg ${i}:`, { role: m.message.role, hasAction: !!m.action, impl: m.action?.implementation });
@@ -30416,7 +30846,15 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
30416
30846
  console.log('[DEBUG ChatWindow] Testing renderer for query-contact-directory:', !!getActionRenderer('query-contact-directory'));
30417
30847
  }
30418
30848
  return null;
30419
- })(), jsxRuntime.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 && (jsxRuntime.jsxs("div", { className: "ai-chat-page-disclaimer", children: [jsxRuntime.jsx("span", { children: "AI-generated responses may be inaccurate." }), jsxRuntime.jsx("button", { type: "button", className: "ai-chat-page-disclaimer-link", onClick: handleDataPolicyClick, children: "Privacy Notice" })] })), jsxRuntime.jsx(ScrollButton, { onClick: () => scrollToBottom?.(), visible: showScrollButton }), jsxRuntime.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 })] }))] }));
30849
+ })(), jsxRuntime.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 && (jsxRuntime.jsxs("div", { className: "ai-chat-page-disclaimer", children: [jsxRuntime.jsx("span", { children: "AI-generated responses may be inaccurate." }), jsxRuntime.jsx("button", { type: "button", className: "ai-chat-page-disclaimer-link", onClick: handleDataPolicyClick, children: "Privacy Notice" })] })), jsxRuntime.jsx(ScrollButton, { onClick: () => scrollToBottom?.(), visible: showScrollButton }), jsxRuntime.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 })] }))] }));
30850
+ };
30851
+
30852
+ const MessageCircleIcon = () => (jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.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" }) }));
30853
+ const ChevronDownIcon = () => (jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" }) }));
30854
+ // Icon components mapping for dynamic lookup
30855
+ const iconComponents = {
30856
+ FiMessageCircle: MessageCircleIcon,
30857
+ FiChevronDown: ChevronDownIcon,
30420
30858
  };
30421
30859
 
30422
30860
  /**
@@ -30714,108 +31152,60 @@ function generateThemeStyles(appearance, theme) {
30714
31152
  return styles;
30715
31153
  }
30716
31154
 
30717
- /**
30718
- * Auto Theme Detector
30719
- * Detects whether the widget should use light or dark mode
30720
- * based on the background behind it
30721
- */
30722
- /**
30723
- * Sample the background color behind an element
30724
- * Uses multiple sampling points for accuracy
30725
- */
30726
- function sampleBackgroundColor(element) {
30727
- const rect = element.getBoundingClientRect();
30728
- const centerX = rect.left + rect.width / 2;
30729
- const centerY = rect.top + rect.height / 2;
30730
- // Try to get the element behind our widget
30731
- // Temporarily hide the element to sample what's behind
30732
- const originalVisibility = element.style.visibility;
30733
- element.style.visibility = 'hidden';
30734
- // Sample the center point
30735
- const elementBehind = document.elementFromPoint(centerX, centerY);
30736
- // Restore visibility
30737
- element.style.visibility = originalVisibility;
30738
- if (!elementBehind) {
30739
- return '#ffffff'; // Default to white
30740
- }
30741
- // Get computed background color
30742
- const computedStyle = window.getComputedStyle(elementBehind);
30743
- let bgColor = computedStyle.backgroundColor;
30744
- // If transparent, walk up the DOM tree
30745
- if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
30746
- let parent = elementBehind.parentElement;
30747
- while (parent) {
30748
- const parentStyle = window.getComputedStyle(parent);
30749
- bgColor = parentStyle.backgroundColor;
30750
- if (bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent') {
30751
- break;
30752
- }
30753
- parent = parent.parentElement;
30754
- }
30755
- }
30756
- // If still transparent, check body/html
30757
- if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
30758
- const bodyStyle = window.getComputedStyle(document.body);
30759
- bgColor = bodyStyle.backgroundColor;
30760
- if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
30761
- return '#ffffff'; // Default to white
31155
+ function useWidgetAppearance({ containerRef, config, theme, primaryColor, position, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, welcomeBubbleText, triggerType, triggerText, customStyles, zIndex, previewMode: _previewMode, }) {
31156
+ // Use theme prop directly - no dynamic detection
31157
+ const effectiveTheme = theme ?? "light";
31158
+ // Set data attribute for CSS styling
31159
+ React.useEffect(() => {
31160
+ if (containerRef.current) {
31161
+ containerRef.current.setAttribute('data-theme', effectiveTheme);
30762
31162
  }
30763
- }
30764
- return rgbaToHex(bgColor);
30765
- }
30766
- /**
30767
- * Convert rgba/rgb string to hex
30768
- */
30769
- function rgbaToHex(rgba) {
30770
- // Handle rgb(r, g, b) or rgba(r, g, b, a)
30771
- const match = rgba.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
30772
- if (!match)
30773
- return '#ffffff';
30774
- const r = parseInt(match[1]);
30775
- const g = parseInt(match[2]);
30776
- const b = parseInt(match[3]);
30777
- return '#' + [r, g, b].map(x => {
30778
- const hex = x.toString(16);
30779
- return hex.length === 1 ? '0' + hex : hex;
30780
- }).join('');
30781
- }
30782
- /**
30783
- * Determine if the background is dark
30784
- */
30785
- function isBackgroundDark(backgroundColor) {
30786
- const luminance = getLuminance(backgroundColor);
30787
- return luminance < 0.5;
30788
- }
30789
- /**
30790
- * Auto-detect theme based on background
30791
- */
30792
- function detectTheme(element) {
30793
- const bgColor = sampleBackgroundColor(element);
30794
- return isBackgroundDark(bgColor) ? 'dark' : 'light';
31163
+ }, [effectiveTheme, containerRef]);
31164
+ const appearanceConfig = config?.appearance;
31165
+ const effectivePosition = position || appearanceConfig?.position || "bottom-right";
31166
+ const accentColor = primaryColor !== undefined ? primaryColor : appearanceConfig?.primaryColor ?? "";
31167
+ const effectiveSize = size || appearanceConfig?.size || "small";
31168
+ const effectiveHeaderTitle = headerTitle ?? appearanceConfig?.headerTitle ?? "";
31169
+ const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? "";
31170
+ const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? "";
31171
+ const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? "";
31172
+ const effectiveWelcomeBubbleText = welcomeBubbleText ?? appearanceConfig?.welcomeBubbleText ?? "";
31173
+ const effectiveTriggerType = triggerType ?? appearanceConfig?.triggerType ?? "button";
31174
+ const effectiveTriggerText = triggerText ?? appearanceConfig?.triggerText ?? "Chat";
31175
+ const simpleAppearance = {
31176
+ accentColor};
31177
+ const generatedStyles = generateThemeStyles(simpleAppearance, effectiveTheme);
31178
+ const legacyStyles = appearanceConfig ? applyAppearanceStyles(appearanceConfig) : {};
31179
+ const mergedStyles = {
31180
+ ...legacyStyles,
31181
+ ...generatedStyles,
31182
+ ...customStyles,
31183
+ ...(zIndex !== undefined ? { "--widget-z-index": String(zIndex) } : {}),
31184
+ };
31185
+ // Compute icon contrast color for inline button styling (prevents FOUC)
31186
+ const iconContrastColor = accentColor ? getContrastText(accentColor) : undefined;
31187
+ return {
31188
+ effectiveTheme,
31189
+ effectivePosition,
31190
+ accentColor,
31191
+ iconContrastColor,
31192
+ effectiveSize,
31193
+ effectiveHeaderTitle,
31194
+ effectiveWelcomeTitle,
31195
+ effectiveWelcomeMessage,
31196
+ effectivePlaceholder,
31197
+ effectiveWelcomeBubbleText,
31198
+ effectiveTriggerType,
31199
+ effectiveTriggerText,
31200
+ mergedStyles,
31201
+ };
30795
31202
  }
30796
- /**
30797
- * Create a MutationObserver to watch for theme changes
30798
- */
30799
- function createThemeObserver(element, callback) {
30800
- let lastTheme = detectTheme(element);
30801
- const observer = new MutationObserver(() => {
30802
- const theme = detectTheme(element);
30803
- if (theme !== lastTheme) {
30804
- lastTheme = theme;
30805
- callback(theme);
30806
- }
30807
- });
30808
- // Observe body for class/style changes (common for theme switching)
30809
- observer.observe(document.body, {
30810
- attributes: true,
30811
- attributeFilter: ['class', 'style', 'data-theme', 'data-bs-theme'],
30812
- });
30813
- // Also observe html element
30814
- observer.observe(document.documentElement, {
30815
- attributes: true,
30816
- attributeFilter: ['class', 'style', 'data-theme', 'data-bs-theme'],
30817
- });
30818
- return observer;
31203
+
31204
+ function WidgetTriggers({ triggerType, isOpen, onToggle, triggerText, placeholder, IconComponent, showWelcomeBubble, welcomeBubbleText, previewMode, onDismissBubble, isInputBarCollapsed, setIsInputBarCollapsed, inputBarValue, setInputBarValue, onSubmitInputBar, accentColor, iconColor, }) {
31205
+ // Inline button styles to prevent flash of unstyled content (FOUC)
31206
+ // Applied directly to button elements, bypassing CSS variable cascade timing
31207
+ const buttonStyle = accentColor ? { background: accentColor, color: iconColor } : undefined;
31208
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [triggerType === "button" && !isOpen && welcomeBubbleText && (previewMode || showWelcomeBubble) && (jsxRuntime.jsxs("div", { className: "ai-chat-welcome-bubble", onClick: onToggle, children: [jsxRuntime.jsx("span", { children: welcomeBubbleText }), jsxRuntime.jsx("button", { className: "ai-chat-welcome-bubble-close", onClick: onDismissBubble, "aria-label": "Dismiss", children: jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) }), jsxRuntime.jsx("div", { className: "ai-chat-welcome-bubble-arrow" })] })), triggerType === "button" && (jsxRuntime.jsx("button", { className: `ai-chat-button ${isOpen ? "is-open" : ""}`, onClick: onToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", style: buttonStyle, children: jsxRuntime.jsx("div", { className: "ai-chat-button-svg", children: jsxRuntime.jsx(IconComponent, {}) }) })), triggerType === "pill-text" && (jsxRuntime.jsxs("button", { className: `ai-chat-trigger-pill ${isOpen ? "is-open" : ""}`, onClick: onToggle, "aria-label": isOpen ? "Close chat" : "Open chat", style: isOpen ? buttonStyle : undefined, children: [jsxRuntime.jsx("div", { className: "ai-chat-trigger-pill-icon", children: jsxRuntime.jsx(IconComponent, {}) }), !isOpen && jsxRuntime.jsx("span", { children: triggerText })] })), triggerType === "input-bar" && !isOpen && (jsxRuntime.jsx("div", { className: "ai-chat-trigger-input-container", children: isInputBarCollapsed ? (jsxRuntime.jsxs("div", { className: "ai-chat-trigger-input-row", children: [jsxRuntime.jsx("button", { type: "button", className: "ai-chat-trigger-collapse-toggle", onClick: () => setIsInputBarCollapsed(false), "aria-label": "Expand input bar", children: jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "15 18 9 12 15 6" }) }) }), jsxRuntime.jsx("button", { type: "button", className: "ai-chat-button", onClick: onToggle, "aria-label": "Open chat", style: buttonStyle, children: jsxRuntime.jsx("div", { className: "ai-chat-button-svg", children: jsxRuntime.jsx(IconComponent, {}) }) })] })) : (jsxRuntime.jsxs("div", { className: "ai-chat-trigger-input-row", children: [jsxRuntime.jsx("button", { type: "button", className: "ai-chat-trigger-collapse-toggle", onClick: () => setIsInputBarCollapsed(true), "aria-label": "Collapse input bar", children: jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "9 18 15 12 9 6" }) }) }), jsxRuntime.jsxs("form", { className: "ai-chat-trigger-input-wrapper", onSubmit: onSubmitInputBar, children: [jsxRuntime.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" }), jsxRuntime.jsx("button", { type: "submit", className: "ai-chat-trigger-input-btn", disabled: !inputBarValue.trim(), "aria-label": "Send message", style: buttonStyle, children: jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("line", { x1: "12", y1: "19", x2: "12", y2: "5" }), jsxRuntime.jsx("polyline", { points: "5 12 12 5 19 12" })] }) })] }), jsxRuntime.jsx("button", { type: "button", className: "ai-chat-trigger-input-expand", onClick: onToggle, "aria-label": "Open chat", children: jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "18 15 12 9 6 15" }) }) })] })) }))] }));
30819
31209
  }
30820
31210
 
30821
31211
  function styleInject(css, ref) {
@@ -30845,34 +31235,19 @@ function styleInject(css, ref) {
30845
31235
  }
30846
31236
  }
30847
31237
 
30848
- 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)}}";
31238
+ 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}";
30849
31239
  styleInject(css_248z$1);
30850
31240
 
30851
- 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}";
31241
+ 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)}";
30852
31242
  styleInject(css_248z);
30853
31243
 
30854
- // Icon components mapping
30855
- const iconComponents = {
30856
- FiMessageCircle: () => (jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.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" }) })),
30857
- FiChevronDown: () => (jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" }) })),
30858
- };
30859
- 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', }) => {
31244
+ 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', }) => {
30860
31245
  const [isOpen, setIsOpen] = React.useState(defaultOpen);
30861
31246
  const [inputBarValue, setInputBarValue] = React.useState('');
30862
- const [autoDetectedTheme, setAutoDetectedTheme] = React.useState('light');
30863
31247
  const [showWelcomeBubble, setShowWelcomeBubble] = React.useState(false);
31248
+ const [isInputBarCollapsed, setIsInputBarCollapsed] = React.useState(false);
30864
31249
  const widgetRef = React.useRef(null);
30865
31250
  const containerRef = React.useRef(null);
30866
- // Demo mode state - track whether demo has been activated and completed
30867
- const [demoMessages, setDemoMessages] = React.useState([]);
30868
- const [isDemoComplete, setIsDemoComplete] = React.useState(false);
30869
- const [isDemoTyping, setIsDemoTyping] = React.useState(false);
30870
- const [demoInputBarText, setDemoInputBarText] = React.useState(''); // For animating text in input bar
30871
- const [isDemoAnimatingInput, setIsDemoAnimatingInput] = React.useState(false); // True while typing into input bar
30872
- const [isDemoActive, setIsDemoActive] = React.useState(false); // True when demo animation is running
30873
- const demoStartedRef = React.useRef(false);
30874
- // Track if user has sent a real message (transitions from demo to real chat)
30875
- const [userSentRealMessage, setUserSentRealMessage] = React.useState(false);
30876
31251
  // Determine mode
30877
31252
  const isEmbedded = mode === 'embedded';
30878
31253
  // Default config for preview mode
@@ -30918,24 +31293,22 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30918
31293
  ...previewConfig?.behavior,
30919
31294
  },
30920
31295
  };
30921
- // Always call useChat hook (React rules), but skip initialization in preview mode or during demo
30922
- // Skip initialization during demo to prevent loading old conversations
30923
- // Note: We still pass the real widgetId so createDemoConversation works correctly
30924
- const shouldSkipInit = previewMode || (demoMode && !userSentRealMessage);
31296
+ // Always call useChat hook (React rules), but skip initialization in preview mode
31297
+ const shouldSkipInit = previewMode;
30925
31298
  const chatHook = useChat({
30926
31299
  widgetId: previewMode ? '__preview__' : (widgetId || '__preview__'),
30927
31300
  apiUrl,
30928
31301
  currentRoute,
30929
31302
  onMessage: shouldSkipInit ? undefined : onMessage,
30930
31303
  onError: shouldSkipInit ? undefined : onError,
30931
- skipInitialization: shouldSkipInit, // Don't make API calls in preview mode or during demo
31304
+ skipInitialization: shouldSkipInit,
30932
31305
  });
30933
31306
  // Extract values from hook or use preview defaults
30934
- const hookMessages = previewMode ? [] : chatHook.messages;
30935
- const hookIsLoading = previewMode ? false : chatHook.isLoading;
30936
- const hookIsTyping = previewMode ? false : chatHook.isTyping;
31307
+ const messages = previewMode ? [] : chatHook.messages;
31308
+ const isLoading = previewMode ? false : chatHook.isLoading;
31309
+ const isTyping = previewMode ? false : chatHook.isTyping;
30937
31310
  const config = previewMode ? mergedPreviewConfig : chatHook.config;
30938
- const hookSendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
31311
+ const sendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
30939
31312
  const submitFeedback = previewMode ? (() => Promise.resolve()) : chatHook.submitFeedback;
30940
31313
  const dismissAction = previewMode ? (() => Promise.resolve()) : chatHook.dismissAction;
30941
31314
  const conversations = previewMode ? [] : chatHook.conversations;
@@ -30943,54 +31316,26 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30943
31316
  const switchConversation = previewMode ? (() => Promise.resolve()) : chatHook.switchConversation;
30944
31317
  const startNewConversation = previewMode ? (() => { }) : chatHook.startNewConversation;
30945
31318
  const deleteConversation = previewMode ? (() => { }) : chatHook.deleteConversation;
30946
- const createDemoConversation = previewMode ? (() => Promise.resolve(null)) : chatHook.createDemoConversation;
30947
31319
  const conversationId = previewMode ? '' : chatHook.conversationId;
30948
- // Message display logic:
30949
- // - During demo (before user sends real message): show demoMessages
30950
- // - After user sends real message: show hookMessages
30951
- const showDemoMessages = demoMode && demoMessages.length > 0 && !userSentRealMessage;
30952
- const messages = showDemoMessages ? demoMessages : hookMessages;
30953
- const isLoading = showDemoMessages ? false : hookIsLoading;
30954
- const isTyping = showDemoMessages ? isDemoTyping : hookIsTyping;
30955
- // Send message handler - transitions from demo to real chat when user sends first message
30956
- const sendMessage = React.useCallback((content) => {
30957
- if (demoMode && isDemoActive && !isDemoComplete) {
30958
- // Demo animation is still running - ignore user input
30959
- return Promise.resolve();
30960
- }
30961
- // User is sending a real message - transition to real chat
30962
- if (demoMode && !userSentRealMessage) {
30963
- setUserSentRealMessage(true);
30964
- // Clear demo messages so hook messages take over
30965
- setDemoMessages([]);
30966
- }
30967
- return hookSendMessage(content);
30968
- }, [demoMode, isDemoActive, isDemoComplete, userSentRealMessage, hookSendMessage]);
30969
- // Auto-detect theme from background
30970
- React.useEffect(() => {
30971
- if (!containerRef.current)
30972
- return;
30973
- // Initial detection
30974
- const detected = detectTheme(containerRef.current);
30975
- setAutoDetectedTheme(detected);
30976
- // Watch for theme changes on the page
30977
- const observer = createThemeObserver(containerRef.current, (newTheme) => {
30978
- setAutoDetectedTheme(newTheme);
30979
- });
30980
- // Also listen for system preference changes
30981
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
30982
- const handleMediaChange = () => {
30983
- if (containerRef.current) {
30984
- const detected = detectTheme(containerRef.current);
30985
- setAutoDetectedTheme(detected);
30986
- }
30987
- };
30988
- mediaQuery.addEventListener('change', handleMediaChange);
30989
- return () => {
30990
- observer.disconnect();
30991
- mediaQuery.removeEventListener('change', handleMediaChange);
30992
- };
30993
- }, [config]);
31320
+ const callActionEndpoint = previewMode ? (async () => { throw new Error('Not available in preview mode'); }) : chatHook.callActionEndpoint;
31321
+ const { effectiveTheme, effectivePosition, accentColor, iconContrastColor, effectiveSize, effectiveHeaderTitle, effectiveWelcomeTitle, effectiveWelcomeMessage, effectivePlaceholder, effectiveWelcomeBubbleText, effectiveTriggerType, effectiveTriggerText, mergedStyles, } = useWidgetAppearance({
31322
+ containerRef,
31323
+ config,
31324
+ theme,
31325
+ primaryColor,
31326
+ position,
31327
+ size,
31328
+ headerTitle,
31329
+ welcomeTitle,
31330
+ welcomeMessage,
31331
+ placeholder,
31332
+ welcomeBubbleText,
31333
+ triggerType,
31334
+ triggerText,
31335
+ customStyles,
31336
+ zIndex,
31337
+ previewMode,
31338
+ });
30994
31339
  // Check if device is mobile
30995
31340
  const isMobile = typeof window !== 'undefined' && window.innerWidth <= 480;
30996
31341
  // Handle auto-open (only for bubble mode, disabled on mobile)
@@ -30998,9 +31343,6 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30998
31343
  // Never auto-open on mobile devices
30999
31344
  if (isMobile)
31000
31345
  return undefined;
31001
- // Don't auto-open if demo mode is active - let demo animation control opening
31002
- if (demoMode && !isDemoComplete)
31003
- return undefined;
31004
31346
  if (!isEmbedded && config?.settings.autoOpen) {
31005
31347
  const delay = config.settings.autoOpenDelay || 0;
31006
31348
  const timer = setTimeout(() => {
@@ -31010,7 +31352,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
31010
31352
  return () => clearTimeout(timer);
31011
31353
  }
31012
31354
  return undefined;
31013
- }, [config, onOpen, isEmbedded, isMobile, demoMode, isDemoComplete]);
31355
+ }, [config, onOpen, isEmbedded, isMobile]);
31014
31356
  // Handle close on Escape key (only for bubble mode)
31015
31357
  React.useEffect(() => {
31016
31358
  if (!isOpen || isEmbedded)
@@ -31087,172 +31429,12 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
31087
31429
  setShowWelcomeBubble(true);
31088
31430
  }
31089
31431
  }, [widgetId, welcomeBubbleText, config, isOpen, isEmbedded, previewMode]);
31090
- // Demo mode: animate typing into input bar, then open widget with conversation
31091
- // This shows the widget in action without making expensive AI calls
31092
- React.useEffect(() => {
31093
- // Determine trigger type early (from prop or config)
31094
- // IMPORTANT: For demo mode, we need config to be loaded to know the trigger type
31095
- // If config is not loaded yet, wait for it (unless triggerType prop is provided)
31096
- const effectiveTriggerTypeForDemo = triggerType ?? config?.appearance?.triggerType ?? 'button';
31097
- const isInputBarTrigger = effectiveTriggerTypeForDemo === 'input-bar';
31098
- // Debug logging
31099
- console.log('[Widget] Demo effect check:', {
31100
- demoMode,
31101
- isDemoComplete,
31102
- demoStartedRef: demoStartedRef.current,
31103
- hasDemoInput: !!demoInput,
31104
- hasDemoOutput: !!demoOutput,
31105
- triggerType: effectiveTriggerTypeForDemo,
31106
- isInputBar: isInputBarTrigger,
31107
- isOpen,
31108
- });
31109
- // Start demo when demoMode is enabled and we have input/output
31110
- const shouldStartDemo = demoMode && !isDemoComplete && !demoStartedRef.current && demoInput && demoOutput;
31111
- if (!shouldStartDemo) {
31112
- 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' });
31113
- return;
31114
- }
31115
- // Wait for config to load before starting demo (unless triggerType prop is explicitly provided)
31116
- // This prevents the demo from starting with wrong trigger type
31117
- if (!triggerType && !config) {
31118
- console.log('[Widget] Demo waiting for config or triggerType prop');
31119
- return;
31120
- }
31121
- // For input-bar: start immediately (widget closed, type into bar)
31122
- // For others: wait until widget is open
31123
- if (!isInputBarTrigger && !isOpen) {
31124
- console.log('[Widget] Demo waiting for widget to open (non-input-bar trigger)');
31125
- return;
31126
- }
31127
- console.log('[Widget] Starting demo animation...', {
31128
- triggerType: effectiveTriggerTypeForDemo,
31129
- isInputBar: isInputBarTrigger,
31130
- demoInput,
31131
- demoOutput: demoOutput?.substring(0, 50) + '...',
31132
- });
31133
- demoStartedRef.current = true;
31134
- setIsDemoActive(true);
31135
- // Use stable IDs to prevent React from remounting components
31136
- const userMessageId = 'demo-user-message';
31137
- const assistantMessageId = 'demo-assistant-message';
31138
- // Helper to create a message with stable ID
31139
- const createMessage = (id, role, content, isStreaming = false) => ({
31140
- id,
31141
- message: { role, content },
31142
- timestamp: new Date().toISOString(),
31143
- sources: [],
31144
- isStreaming,
31145
- });
31146
- // Animation sequence - runs to completion even if widget is closed
31147
- // This ensures conversation is always created and saved consistently
31148
- const runDemoAnimation = async () => {
31149
- // STEP 1: Create conversation IMMEDIATELY at the start
31150
- // This ensures we have a conversation ID before any animation
31151
- console.log('[Widget] Creating demo conversation at start...');
31152
- let conversationId = null;
31153
- try {
31154
- conversationId = await createDemoConversation(demoInput, demoOutput);
31155
- if (conversationId) {
31156
- console.log('[Widget] Demo conversation created:', conversationId);
31157
- }
31158
- }
31159
- catch (err) {
31160
- console.warn('[Widget] Failed to create demo conversation:', err);
31161
- }
31162
- // STEP 2: For input-bar trigger, animate typing into input bar first
31163
- if (isInputBarTrigger && !isOpen) {
31164
- setIsDemoAnimatingInput(true);
31165
- // Wait before starting to type - ensure input bar is fully visible
31166
- await new Promise(resolve => setTimeout(resolve, 1500));
31167
- // Type into input bar character by character
31168
- const inputChars = demoInput.split('');
31169
- for (let i = 0; i < inputChars.length; i++) {
31170
- setDemoInputBarText(demoInput.slice(0, i + 1));
31171
- // Slower typing speed for better visibility
31172
- const delay = inputChars[i] === ' ' ? 100 : 60 + Math.random() * 40;
31173
- await new Promise(resolve => setTimeout(resolve, delay));
31174
- }
31175
- // Longer pause after typing so user can read the question
31176
- await new Promise(resolve => setTimeout(resolve, 1000));
31177
- setIsDemoAnimatingInput(false);
31178
- setDemoInputBarText('');
31179
- setIsOpen(true);
31180
- onOpen?.();
31181
- // Let widget open animation complete
31182
- await new Promise(resolve => setTimeout(resolve, 500));
31183
- }
31184
- else {
31185
- // For non-input-bar triggers, just wait for widget to settle
31186
- await new Promise(resolve => setTimeout(resolve, 800));
31187
- }
31188
- // STEP 3: Add user message
31189
- setDemoMessages([createMessage(userMessageId, 'user', demoInput)]);
31190
- // Show typing indicator after a pause
31191
- await new Promise(resolve => setTimeout(resolve, 500));
31192
- setIsDemoTyping(true);
31193
- // "Thinking" pause
31194
- await new Promise(resolve => setTimeout(resolve, 1200));
31195
- setIsDemoTyping(false);
31196
- // STEP 4: Stream the response character by character
31197
- const chars = demoOutput.split('');
31198
- let currentText = '';
31199
- // Initial message with empty content
31200
- setDemoMessages([
31201
- createMessage(userMessageId, 'user', demoInput),
31202
- createMessage(assistantMessageId, 'assistant', '', true),
31203
- ]);
31204
- await new Promise(resolve => setTimeout(resolve, 100));
31205
- // Stream characters - continues even if widget is closed
31206
- for (let i = 0; i < chars.length; i++) {
31207
- currentText += chars[i];
31208
- setDemoMessages([
31209
- createMessage(userMessageId, 'user', demoInput),
31210
- createMessage(assistantMessageId, 'assistant', currentText, i < chars.length - 1),
31211
- ]);
31212
- const delay = chars[i] === ' ' ? 12 : 20;
31213
- await new Promise(resolve => setTimeout(resolve, delay));
31214
- }
31215
- // STEP 5: Mark demo complete
31216
- await new Promise(resolve => setTimeout(resolve, 500));
31217
- setIsDemoComplete(true);
31218
- setIsDemoActive(false);
31219
- console.log('[Widget] Demo animation complete');
31220
- onDemoComplete?.();
31221
- };
31222
- runDemoAnimation();
31223
- }, [demoMode, isOpen, isDemoComplete, demoInput, demoOutput, onDemoComplete, triggerType, config?.appearance?.triggerType, onOpen, createDemoConversation]);
31224
- // Determine theme - use prop override if provided, otherwise auto-detect
31225
- const appearanceConfig = config?.appearance;
31226
- const effectiveTheme = theme ?? autoDetectedTheme;
31227
- // Determine position (prop override takes priority for live preview)
31228
- const effectivePosition = position || config?.appearance.position || 'bottom-right';
31229
- // Get accent color from prop or config (empty string means no accent color / vanilla mode)
31230
- const accentColor = primaryColor ?? appearanceConfig?.primaryColor ?? '';
31231
- // Apply prop overrides for live preview (props take priority over config)
31232
- const effectiveSize = size || appearanceConfig?.size || 'small';
31233
- const effectiveHeaderTitle = headerTitle ?? appearanceConfig?.headerTitle ?? '';
31234
- const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? '';
31235
- const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? '';
31236
- const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? '';
31237
- const effectiveWelcomeBubbleText = welcomeBubbleText ?? appearanceConfig?.welcomeBubbleText ?? '';
31238
- const effectiveTriggerType = triggerType ?? appearanceConfig?.triggerType ?? 'button';
31239
- const effectiveTriggerText = triggerText ?? appearanceConfig?.triggerText ?? 'Chat';
31240
- // Generate styles using simplified theme system
31241
- const simpleAppearance = {
31242
- accentColor};
31243
- // Generate theme styles from accent color
31244
- const generatedStyles = generateThemeStyles(simpleAppearance, effectiveTheme);
31245
- // Also apply legacy styles for backward compatibility
31246
- const legacyStyles = appearanceConfig
31247
- ? applyAppearanceStyles(appearanceConfig)
31248
- : {};
31249
- // Merge styles (generated takes priority for new simplified system, then custom overrides)
31250
- const mergedStyles = {
31251
- ...legacyStyles,
31252
- ...generatedStyles,
31253
- ...customStyles,
31254
- ...(zIndex !== undefined ? { '--widget-z-index': String(zIndex) } : {}),
31255
- };
31432
+ const handleStartNewConversation = React.useCallback(() => {
31433
+ startNewConversation();
31434
+ }, [startNewConversation]);
31435
+ const handleSendMessage = React.useCallback((content) => {
31436
+ sendMessage(content);
31437
+ }, [sendMessage]);
31256
31438
  // Dismiss bubble and store based on frequency setting
31257
31439
  const dismissBubble = () => {
31258
31440
  setShowWelcomeBubble(false);
@@ -31288,9 +31470,6 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
31288
31470
  onOpen?.();
31289
31471
  }
31290
31472
  else {
31291
- // Demo animation continues in background when widget is closed
31292
- // The conversation was already created at the start, so closing is safe
31293
- // When user reopens, they'll see the current state of the demo animation
31294
31473
  onClose?.();
31295
31474
  }
31296
31475
  };
@@ -31327,10 +31506,13 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
31327
31506
  sendMessage(actionInstruction);
31328
31507
  };
31329
31508
  // Don't render until config is loaded to avoid flash of unstyled content
31330
- // Exception: If we have essential props (triggerType), allow rendering the trigger immediately
31331
- // This improves perceived loading speed - users see the trigger while config loads
31509
+ // Exceptions that allow immediate rendering:
31510
+ // 1. triggerType prop provided - user wants specific trigger shown immediately
31511
+ // 2. primaryColor prop provided - we have initial styling, no flash will occur
31512
+ // This improves perceived loading speed - users see the correctly styled trigger while config loads
31332
31513
  // In preview mode, config is always available
31333
- const canRenderWithoutConfig = !!triggerType;
31514
+ const hasInitialStyling = !!primaryColor;
31515
+ const canRenderWithoutConfig = !!triggerType || hasInitialStyling;
31334
31516
  if (!config && !previewMode && !canRenderWithoutConfig) {
31335
31517
  return null;
31336
31518
  }
@@ -31338,21 +31520,21 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
31338
31520
  const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
31339
31521
  // Embedded mode renders directly without wrapper positioning
31340
31522
  if (isEmbedded) {
31341
- return (jsxRuntime.jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsxRuntime.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 }) }));
31523
+ return (jsxRuntime.jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsxRuntime.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 }) }));
31342
31524
  }
31343
31525
  // Determine trigger class for container
31344
31526
  const triggerClass = effectiveTriggerType === 'pill-text'
31345
31527
  ? 'trigger-pill-text'
31346
31528
  : effectiveTriggerType === 'input-bar'
31347
31529
  ? 'trigger-input-bar'
31348
- : '';
31530
+ : 'trigger-button';
31349
31531
  // Size class for CSS targeting (used by input-bar trigger for width matching)
31350
31532
  const sizeClass = `size-${effectiveSize}`;
31351
- return (jsxRuntime.jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxRuntime.jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition} ${isOpen ? 'is-open' : ''} ${containerMode ? 'container-mode' : ''} ${triggerClass} ${sizeClass}`, children: [isOpen && (jsxRuntime.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,
31533
+ // Collapsed class for input bar
31534
+ const collapsedClass = isInputBarCollapsed ? 'is-collapsed' : '';
31535
+ return (jsxRuntime.jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxRuntime.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 && (jsxRuntime.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage: handleSendMessage, onClose: handleToggle, onFeedback: handleFeedback, onActionClick: handleActionClick, onActionDismiss: dismissAction, onCallEndpoint: callActionEndpoint,
31352
31536
  // Chat history props (only active when persistConversation is true)
31353
- conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId,
31354
- // Override props for live preview
31355
- headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), effectiveTriggerType === 'button' && !isOpen && effectiveWelcomeBubbleText && (previewMode || showWelcomeBubble) && (jsxRuntime.jsxs("div", { className: "ai-chat-welcome-bubble", onClick: handleToggle, children: [jsxRuntime.jsx("span", { children: effectiveWelcomeBubbleText }), jsxRuntime.jsx("button", { className: "ai-chat-welcome-bubble-close", onClick: handleDismissBubble, "aria-label": "Dismiss", children: jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) }), jsxRuntime.jsx("div", { className: "ai-chat-welcome-bubble-arrow" })] })), effectiveTriggerType === 'button' && (jsxRuntime.jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsxRuntime.jsx("div", { className: "ai-chat-button-svg", children: jsxRuntime.jsx(IconComponent, {}) }) })), effectiveTriggerType === 'pill-text' && (jsxRuntime.jsxs("button", { className: `ai-chat-trigger-pill ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Close chat" : "Open chat", children: [jsxRuntime.jsx("div", { className: "ai-chat-trigger-pill-icon", children: jsxRuntime.jsx(IconComponent, {}) }), !isOpen && jsxRuntime.jsx("span", { children: effectiveTriggerText })] })), effectiveTriggerType === 'input-bar' && !isOpen && (jsxRuntime.jsxs("div", { className: "ai-chat-trigger-input-container", children: [jsxRuntime.jsx("button", { type: "button", className: "ai-chat-trigger-input-expand", onClick: handleToggle, "aria-label": "Open chat", children: jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "18 15 12 9 6 15" }) }) }), jsxRuntime.jsxs("form", { className: "ai-chat-trigger-input-wrapper", onSubmit: handleInputBarSubmit, children: [jsxRuntime.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" }), jsxRuntime.jsx("button", { type: "submit", className: "ai-chat-trigger-input-btn", disabled: isDemoAnimatingInput ? !demoInputBarText.trim() : !inputBarValue.trim(), "aria-label": "Send message", children: jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }), jsxRuntime.jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })] }) })] })] }))] }) }));
31537
+ conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: handleStartNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, sizeOverride: effectiveSize, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), jsxRuntime.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 })] }) }));
31356
31538
  };
31357
31539
 
31358
31540
  exports.ApiError = ApiError;