@chatwidgetai/chat-widget 0.3.1 → 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 (48) hide show
  1. package/dist/ai-chat-widget.umd.js +1890 -1018
  2. package/dist/ai-chat-widget.umd.js.map +1 -1
  3. package/dist/api/client.d.ts +21 -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 +5 -1
  13. package/dist/components/ChatWindow.d.ts.map +1 -1
  14. package/dist/components/DataPolicyView.d.ts.map +1 -1
  15. package/dist/components/WelcomeBubble.d.ts +12 -0
  16. package/dist/components/WelcomeBubble.d.ts.map +1 -0
  17. package/dist/components/icons.d.ts +21 -0
  18. package/dist/components/icons.d.ts.map +1 -0
  19. package/dist/components/triggers/ButtonTrigger.d.ts +11 -0
  20. package/dist/components/triggers/ButtonTrigger.d.ts.map +1 -0
  21. package/dist/components/triggers/InputBarTrigger.d.ts +18 -0
  22. package/dist/components/triggers/InputBarTrigger.d.ts.map +1 -0
  23. package/dist/components/triggers/PillTrigger.d.ts +12 -0
  24. package/dist/components/triggers/PillTrigger.d.ts.map +1 -0
  25. package/dist/components/triggers/index.d.ts +8 -0
  26. package/dist/components/triggers/index.d.ts.map +1 -0
  27. package/dist/hooks/useChat/action-handler.d.ts +17 -1
  28. package/dist/hooks/useChat/action-handler.d.ts.map +1 -1
  29. package/dist/hooks/useChat/action-lifecycle.d.ts.map +1 -1
  30. package/dist/hooks/useChat/index.d.ts +7 -0
  31. package/dist/hooks/useChat/index.d.ts.map +1 -1
  32. package/dist/hooks/useChat/message-hydration.d.ts.map +1 -1
  33. package/dist/hooks/useChat/stream-buffer.d.ts +18 -0
  34. package/dist/hooks/useChat/stream-buffer.d.ts.map +1 -0
  35. package/dist/hooks/useChat/stream-handlers.d.ts +3 -3
  36. package/dist/hooks/useChat/stream-handlers.d.ts.map +1 -1
  37. package/dist/hooks/useChat/stream-state.d.ts.map +1 -1
  38. package/dist/hooks/useChat/types.d.ts +2 -0
  39. package/dist/hooks/useChat/types.d.ts.map +1 -1
  40. package/dist/index.d.ts +2 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.esm.js +1891 -1019
  43. package/dist/index.esm.js.map +1 -1
  44. package/dist/index.js +1891 -1018
  45. package/dist/index.js.map +1 -1
  46. package/dist/types/index.d.ts +12 -85
  47. package/dist/types/index.d.ts.map +1 -1
  48. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -212,31 +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,
228
+ reason: "user",
229
+ }),
230
+ signal,
231
+ });
232
+ if (response.status === 204) {
233
+ return;
234
+ }
235
+ if (!response.ok) {
236
+ throw await buildApiError(response, 'Failed to dismiss action');
237
+ }
238
+ yield* parseSSEStream(response, (data) => {
239
+ return typeof data === 'object' && data !== null && 'type' in data;
240
+ });
241
+ }
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) {
247
+ const headers = {
248
+ 'Content-Type': 'application/json',
249
+ };
250
+ if (this.config.currentRoute) {
251
+ headers['X-Current-Route'] = this.config.currentRoute;
252
+ }
253
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/continue`, {
254
+ method: 'POST',
255
+ headers,
256
+ body: JSON.stringify({
257
+ conversationId,
258
+ toolCallId,
259
+ body,
229
260
  timeZone: this.getTimeZone(),
230
261
  }),
231
262
  signal,
232
263
  });
233
264
  if (!response.ok) {
234
- throw await buildApiError(response, 'Failed to continue agent');
265
+ throw await buildApiError(response, 'Failed to continue agent action');
235
266
  }
236
267
  yield* parseSSEStream(response, (data) => {
237
268
  return typeof data === 'object' && data !== null && 'type' in data;
238
269
  });
239
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
+ }
240
292
  /**
241
293
  * Submit feedback for a message
242
294
  */
@@ -267,7 +319,8 @@ class WidgetApiClient {
267
319
  }
268
320
  /**
269
321
  * Generate follow-up suggestions based on conversation context and available actions.
270
- * 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.
271
324
  */
272
325
  async generateFollowUps(messages, actionIds) {
273
326
  try {
@@ -299,6 +352,27 @@ class WidgetApiClient {
299
352
  return [];
300
353
  }
301
354
  }
355
+ /**
356
+ * Create a demo conversation with preset messages
357
+ * Used when demo animation completes to persist the demo conversation to the database
358
+ */
359
+ async createDemoConversation(userMessage, assistantMessage) {
360
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/demo-conversation`, {
361
+ method: 'POST',
362
+ headers: {
363
+ 'Content-Type': 'application/json',
364
+ },
365
+ body: JSON.stringify({
366
+ userMessage,
367
+ assistantMessage,
368
+ timeZone: this.getTimeZone(),
369
+ }),
370
+ });
371
+ if (!response.ok) {
372
+ throw await buildApiError(response, 'Failed to create demo conversation');
373
+ }
374
+ return response.json();
375
+ }
302
376
  /**
303
377
  * Validate widget access
304
378
  */
@@ -27114,7 +27188,7 @@ function TypingIndicator({ className = '' }) {
27114
27188
  }
27115
27189
 
27116
27190
  // Styles are provided by global messages.css - no component-specific CSS needed
27117
- function ChevronDownIcon() {
27191
+ function ChevronDownIcon$1() {
27118
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" }) }));
27119
27193
  }
27120
27194
  function ScrollButton({ onClick, visible, className = '' }) {
@@ -27123,24 +27197,35 @@ function ScrollButton({ onClick, visible, className = '' }) {
27123
27197
  visible && 'visible',
27124
27198
  className,
27125
27199
  ].filter(Boolean).join(' ');
27126
- 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, {}) }));
27127
27201
  }
27128
27202
 
27129
27203
  const formatToolName = (name) => {
27130
27204
  return name
27131
27205
  .replace(/^(action_|tool_)/, '')
27206
+ .replace(/-/g, '_')
27132
27207
  .split('_')
27133
27208
  .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
27134
27209
  .join(' ');
27135
27210
  };
27136
27211
  function ToolIndicator({ badges, className = '' }) {
27137
- 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 }) }) }) }));
27138
27223
  }
27139
27224
 
27140
27225
  // SVG Icon components
27141
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" }) }));
27142
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" }) }));
27143
- 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" }) }));
27144
27229
  const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
27145
27230
  const [isSubmitting, setIsSubmitting] = React.useState(false);
27146
27231
  const [submitted, setSubmitted] = React.useState(false);
@@ -27161,7 +27246,7 @@ const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
27161
27246
  setIsSubmitting(false);
27162
27247
  }
27163
27248
  };
27164
- 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" })] }))] }));
27165
27250
  };
27166
27251
 
27167
27252
  const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, }) => {
@@ -27190,9 +27275,11 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedb
27190
27275
  const hasContent = aiContent.trim().length > 0;
27191
27276
  if (!hasContent)
27192
27277
  return null;
27193
- 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: {
27194
27281
  table: ({ children, ...props }) => (jsxRuntime.jsx("div", { className: "table-wrapper", children: jsxRuntime.jsx("div", { className: "table-scroll", children: jsxRuntime.jsx("table", { ...props, children: children }) }) })),
27195
- }, 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 }))] }))] }));
27196
27283
  }
27197
27284
  // System message rendering
27198
27285
  if (isSystem) {
@@ -27212,7 +27299,7 @@ function isActionComplete(state) {
27212
27299
  return false;
27213
27300
  const TERMINAL_STATUSES = [
27214
27301
  'completed', 'booked', 'scheduled', 'cancelled', 'failed', 'error',
27215
- 'displaying', 'clicked', 'contacted', 'submitted', 'sent'
27302
+ 'displaying', 'displayed', 'clicked', 'contacted', 'submitted', 'sent'
27216
27303
  ];
27217
27304
  const status = state.status;
27218
27305
  if (typeof status === 'string' && TERMINAL_STATUSES.includes(status)) {
@@ -27231,11 +27318,12 @@ function isActionLoading(message) {
27231
27318
  return false;
27232
27319
  if (message.isStreaming)
27233
27320
  return true;
27234
- const state = message.action.state;
27235
- return !isActionComplete(state);
27321
+ const input = message.action.input;
27322
+ return !isActionComplete(input);
27236
27323
  }
27237
- const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant }) => {
27238
- const actionMessages = messages.filter(message => message.action);
27324
+ const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant, onActionDismiss, onCallEndpoint, }) => {
27325
+ const visibleMessages = messages.filter(message => !message.action?.hidden);
27326
+ const actionMessages = visibleMessages.filter(message => message.action);
27239
27327
  // Debug logging
27240
27328
  console.log('[DEBUG ToolMessageGroup] ========================================');
27241
27329
  console.log('[DEBUG ToolMessageGroup] Total messages:', messages.length);
@@ -27257,14 +27345,14 @@ const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = tru
27257
27345
  implementation: impl,
27258
27346
  hasRenderer: !!renderer,
27259
27347
  rendererType: renderer ? typeof renderer : 'undefined',
27260
- state: msg.action?.state,
27348
+ input: msg.action?.input,
27261
27349
  });
27262
27350
  });
27263
27351
  // If tool indicator is hidden AND there are no action cards to render, don't render anything
27264
27352
  if (!showToolIndicator && actionMessages.length === 0) {
27265
27353
  return null;
27266
27354
  }
27267
- const badges = messages.map((message) => {
27355
+ const badges = visibleMessages.map((message) => {
27268
27356
  const toolName = message.toolExecuting || message.message.name || 'Tool';
27269
27357
  const hasError = message.isError || false;
27270
27358
  const loading = isActionLoading(message);
@@ -27284,7 +27372,7 @@ const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = tru
27284
27372
  console.log('[ToolMessageGroup] No renderer for:', message.action.implementation);
27285
27373
  return null;
27286
27374
  }
27287
- return (jsxRuntime.jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant) }, `action-${message.id}`));
27375
+ return (jsxRuntime.jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant, onActionDismiss, onCallEndpoint) }, `action-${message.id}`));
27288
27376
  })] }));
27289
27377
  };
27290
27378
 
@@ -27318,12 +27406,29 @@ const SuggestedQuestions = ({ questions, onQuestionClick, }) => {
27318
27406
  };
27319
27407
 
27320
27408
  const MAX_TEXT_LENGTH = 40;
27409
+ const STAGGER_DELAY_MS = 200; // Delay between each suggestion appearing
27321
27410
  const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, accentColor, }) => {
27322
- if (!suggestions || suggestions.length === 0) {
27323
- return null;
27324
- }
27411
+ const [visibleIndices, setVisibleIndices] = React.useState(new Set());
27325
27412
  // Filter out empty suggestions
27326
- 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
27327
27432
  if (validSuggestions.length === 0) {
27328
27433
  return null;
27329
27434
  }
@@ -27331,8 +27436,12 @@ const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, acce
27331
27436
  ? { "--primary-color": accentColor }
27332
27437
  : undefined;
27333
27438
  const trimText = (text) => text.length > MAX_TEXT_LENGTH ? `${text.slice(0, MAX_TEXT_LENGTH)}...` : text;
27334
- 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) => {
27335
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;
27336
27445
  const className = `ai-chat-follow-up-item ${isActionSuggestion ? 'action-type' : 'question-type'}`;
27337
27446
  const handleClick = () => {
27338
27447
  if (isActionSuggestion && onActionClick) {
@@ -27346,39 +27455,47 @@ const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, acce
27346
27455
  };
27347
27456
 
27348
27457
  const MessageList = (props) => {
27349
- const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, 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;
27350
27459
  const containerRef = React.useRef(null);
27351
27460
  const messagesEndRef = React.useRef(null);
27352
27461
  const [showScrollButton, setShowScrollButton] = React.useState(false);
27353
27462
  const prevMessageCountRef = React.useRef(0);
27463
+ const visibleMessages = React.useMemo(() => messages.filter((message) => !message.action?.hidden), [messages]);
27354
27464
  const hasActiveAction = React.useMemo(() => {
27355
27465
  // Find the last tool message and check if its action is still active (not done)
27356
- const lastToolMsg = [...messages].reverse().find(msg => msg.message.role === 'tool');
27466
+ const lastToolMsg = [...visibleMessages].reverse().find(msg => msg.message.role === 'tool');
27357
27467
  return lastToolMsg?.action && lastToolMsg.action.done !== true;
27358
- }, [messages]);
27359
- const checkScrollPosition = React.useCallback(() => {
27360
- const c = containerRef.current;
27361
- if (!c)
27362
- return;
27363
- const pb = parseInt(getComputedStyle(c).paddingBottom || '0', 10);
27364
- setShowScrollButton(c.scrollHeight - c.scrollTop - c.clientHeight - pb > 24);
27365
- }, []);
27468
+ }, [visibleMessages]);
27366
27469
  const scrollToBottom = React.useCallback(() => {
27367
27470
  messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
27368
27471
  }, []);
27369
- 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
27370
27474
  React.useEffect(() => {
27371
- const c = containerRef.current;
27372
- if (!c)
27475
+ const endMarker = messagesEndRef.current;
27476
+ const container = containerRef.current;
27477
+ if (!endMarker || !container)
27373
27478
  return;
27374
- c.addEventListener('scroll', checkScrollPosition);
27375
- return () => c.removeEventListener('scroll', checkScrollPosition);
27376
- }, [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]);
27377
27494
  React.useEffect(() => {
27378
27495
  const c = containerRef.current;
27379
27496
  if (!c)
27380
27497
  return;
27381
- const count = messages.length;
27498
+ const count = visibleMessages.length;
27382
27499
  const isNew = count > prevMessageCountRef.current;
27383
27500
  prevMessageCountRef.current = count;
27384
27501
  if (count === 0) {
@@ -27388,32 +27505,18 @@ const MessageList = (props) => {
27388
27505
  if ((isNew || isTyping) && c.scrollHeight - c.scrollTop - c.clientHeight < 150) {
27389
27506
  messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
27390
27507
  }
27391
- checkScrollPosition();
27392
- }, [messages, isTyping, checkScrollPosition]);
27508
+ }, [visibleMessages, isTyping]);
27393
27509
  const groupedMessages = React.useMemo(() => {
27394
- console.log('[DEBUG MessageList] ========================================');
27395
- console.log('[DEBUG MessageList] Processing messages:', messages.length);
27396
- messages.forEach((m, i) => {
27397
- console.log(`[DEBUG MessageList] Message ${i}:`, {
27398
- id: m.id,
27399
- role: m.message.role,
27400
- hasAction: !!m.action,
27401
- actionImpl: m.action?.implementation,
27402
- content: (m.message.content || '').substring(0, 50),
27403
- });
27404
- });
27405
27510
  const result = [];
27406
27511
  let toolGroup = [];
27407
27512
  const flush = () => {
27408
27513
  if (toolGroup.length) {
27409
- console.log('[DEBUG MessageList] Flushing tool group with', toolGroup.length, 'messages');
27410
27514
  result.push({ type: 'tool-group', messages: [...toolGroup] });
27411
27515
  toolGroup = [];
27412
27516
  }
27413
27517
  };
27414
- for (const m of messages) {
27518
+ for (const m of visibleMessages) {
27415
27519
  if (m.message.role === 'tool') {
27416
- console.log('[DEBUG MessageList] Adding to tool group:', m.id);
27417
27520
  toolGroup.push(m);
27418
27521
  }
27419
27522
  else if (m.message.role === 'user') {
@@ -27435,27 +27538,26 @@ const MessageList = (props) => {
27435
27538
  }
27436
27539
  }
27437
27540
  flush();
27438
- console.log('[DEBUG MessageList] Final grouped result:', result.length, 'items');
27439
- result.forEach((item, i) => {
27440
- if (item.type === 'tool-group') {
27441
- console.log(`[DEBUG MessageList] Group ${i}: tool-group with ${item.messages.length} messages`);
27442
- }
27443
- else {
27444
- console.log(`[DEBUG MessageList] Group ${i}: message (${item.message.message.role})`);
27445
- }
27446
- });
27447
27541
  return result;
27448
- }, [messages]);
27449
- const hasSuggestions = messages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
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]);
27553
+ const hasSuggestions = visibleMessages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
27450
27554
  const showWelcome = welcomeTitle || welcomeMessage || hasSuggestions;
27451
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) => {
27452
27556
  if (item.type === 'tool-group') {
27453
- return jsxRuntime.jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant }, `tg-${i}`);
27557
+ return (jsxRuntime.jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant, onActionDismiss: onActionDismiss, onCallEndpoint: onCallEndpoint }, `tg-${i}`));
27454
27558
  }
27455
- const isLast = i === groupedMessages.length - 1;
27456
- const hasFollowUp = item.message.message.role === 'assistant' && item.message.suggestions?.length && isLast && !isTyping;
27457
- 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));
27458
- }), isTyping && showTypingIndicator && !hasActiveAction && messages.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 })] }));
27459
27561
  };
27460
27562
 
27461
27563
  const ALLOWED_EXTENSIONS = ['.pdf', '.doc', '.docx', '.txt', '.md', '.csv'];
@@ -27469,7 +27571,7 @@ const formatFileSize = (bytes) => {
27469
27571
  return (bytes / 1024).toFixed(1) + ' KB';
27470
27572
  return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
27471
27573
  };
27472
- 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, }) => {
27473
27575
  const [value, setValue] = React.useState('');
27474
27576
  const [selectedFiles, setSelectedFiles] = React.useState([]);
27475
27577
  const textareaRef = React.useRef(null);
@@ -27504,481 +27606,15 @@ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled =
27504
27606
  }
27505
27607
  };
27506
27608
  const canSend = value.trim() || selectedFiles.length > 0;
27507
- 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: "KI-generierte Antworten k\u00F6nnen unzutreffend sein." }), onDataPolicyClick && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', jsxRuntime.jsx("button", { type: "button", className: "ai-chat-data-policy-link", onClick: onDataPolicyClick, children: "Datenschutzhinweis" })] }))] }))] }));
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" })] }))] }))] }));
27508
27610
  };
27509
27611
 
27510
- function groupSlotsByDate$1(slots) {
27511
- const grouped = new Map();
27512
- for (const slot of slots) {
27513
- if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
27514
- continue;
27515
- }
27516
- const date = slot.startTime.slice(0, 10);
27517
- if (!grouped.has(date)) {
27518
- grouped.set(date, []);
27519
- }
27520
- grouped.get(date).push(slot);
27521
- }
27522
- return grouped;
27523
- }
27524
- function formatDate$1(dateStr) {
27525
- try {
27526
- const date = new Date(dateStr);
27527
- return new Intl.DateTimeFormat("en-US", {
27528
- weekday: "short",
27529
- month: "short",
27530
- day: "numeric",
27531
- }).format(date);
27532
- }
27533
- catch {
27534
- return dateStr;
27535
- }
27536
- }
27537
- function CalendarIcon$1() {
27538
- 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" }) }));
27539
- }
27540
- function CheckIcon$1() {
27541
- 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" }) }));
27542
- }
27543
- function ExternalLinkIcon$2() {
27544
- 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" })] }));
27545
- }
27546
- function Skeleton$1({ width, height, borderRadius = '4px' }) {
27547
- return (jsxRuntime.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
27548
- }
27549
- function GoogleCalendarCard({ action, onComplete, accentColor, className = '' }) {
27550
- const state = action.state;
27551
- const rawSlots = state.availableSlots;
27552
- const availableSlots = Array.isArray(rawSlots)
27553
- ? rawSlots.filter((slot) => slot !== null &&
27554
- slot !== undefined &&
27555
- typeof slot === "object" &&
27556
- "startTime" in slot &&
27557
- "endTime" in slot &&
27558
- typeof slot.startTime === "string" &&
27559
- typeof slot.endTime === "string")
27560
- : [];
27561
- const allowTopic = state.allowTopic !== false;
27562
- const isBooked = state.status === "booked";
27563
- const slotsByDate = groupSlotsByDate$1(availableSlots);
27564
- const dates = Array.from(slotsByDate.keys()).sort();
27565
- const [selectedDate, setSelectedDate] = React.useState(dates[0] ?? "");
27566
- const [selectedSlot, setSelectedSlot] = React.useState(null);
27567
- const [topic, setTopic] = React.useState("");
27568
- const [error, setError] = React.useState(null);
27569
- const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
27570
- const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
27571
- const onConfirm = () => {
27572
- if (!selectedSlot) {
27573
- setError("Please select a time slot.");
27574
- return;
27575
- }
27576
- if (allowTopic && !topic.trim()) {
27577
- setError("Please enter a topic for the meeting.");
27578
- return;
27579
- }
27580
- setError(null);
27581
- onComplete?.(action.toolCallId, {
27582
- ...action.state,
27583
- selectedSlot: {
27584
- startTime: selectedSlot.startTime,
27585
- endTime: selectedSlot.endTime,
27586
- },
27587
- topic: allowTopic ? topic.trim() : null,
27588
- });
27589
- };
27590
- // Booked state
27591
- if (isBooked) {
27592
- const bookedSlot = state.selectedSlot;
27593
- const bookedTopic = state.topic;
27594
- const eventLink = state.bookedEventLink;
27595
- 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, {})] }))] })] }));
27596
- }
27597
- // Skeleton loading state - show when waiting for backend after user confirms
27598
- const isWaitingForBackend = !action.done && state.selectedSlot && !isBooked;
27599
- if (isWaitingForBackend) {
27600
- 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.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntime.jsx(Skeleton$1, { width: "50px", height: "12px", borderRadius: "4px" }), jsxRuntime.jsx(Skeleton$1, { width: "200px", height: "18px", borderRadius: "4px" })] }), jsxRuntime.jsx(Skeleton$1, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
27601
- }
27602
- // Booking form
27603
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ai-chat-google-calendar ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(CalendarIcon$1, {}), "Schedule an Appointment"] }), 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: () => {
27604
- setSelectedDate(date);
27605
- setSelectedSlot(null);
27606
- }, 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." }))] })] }));
27607
- }
27608
-
27609
- function groupSlotsByDate(slots) {
27610
- const grouped = new Map();
27611
- for (const slot of slots) {
27612
- if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
27613
- continue;
27614
- }
27615
- const date = slot.startTime.slice(0, 10);
27616
- if (!grouped.has(date)) {
27617
- grouped.set(date, []);
27618
- }
27619
- grouped.get(date).push(slot);
27620
- }
27621
- return grouped;
27622
- }
27623
- function formatDate(dateStr) {
27624
- try {
27625
- const date = new Date(dateStr);
27626
- return new Intl.DateTimeFormat("en-US", {
27627
- weekday: "short",
27628
- month: "short",
27629
- day: "numeric",
27630
- }).format(date);
27631
- }
27632
- catch {
27633
- return dateStr;
27634
- }
27635
- }
27636
- function CalendarIcon() {
27637
- 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" }) }));
27638
- }
27639
- function MailIcon() {
27640
- 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" })] }));
27641
- }
27642
- function CheckIcon() {
27643
- 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" }) }));
27644
- }
27645
- function ErrorIcon() {
27646
- 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" }) }));
27647
- }
27648
- function ExternalLinkIcon$1() {
27649
- 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" })] }));
27650
- }
27651
- function Skeleton({ width, height, borderRadius = '4px' }) {
27652
- return (jsxRuntime.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
27653
- }
27654
- function PinInputGroup({ values, onChange, disabled }) {
27655
- const inputRefs = React.useRef([]);
27656
- const handleChange = (index, value) => {
27657
- // Only allow digits
27658
- const digit = value.replace(/[^0-9]/g, '');
27659
- const newValues = [...values];
27660
- newValues[index] = digit.slice(-1);
27661
- onChange(newValues);
27662
- // Auto-focus next input
27663
- if (digit && index < 5) {
27664
- inputRefs.current[index + 1]?.focus();
27665
- }
27666
- };
27667
- const handleKeyDown = (index, e) => {
27668
- if (e.key === 'Backspace' && !values[index] && index > 0) {
27669
- inputRefs.current[index - 1]?.focus();
27670
- }
27671
- };
27672
- const handlePaste = (e) => {
27673
- e.preventDefault();
27674
- const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, 6);
27675
- const newValues = pastedData.split('').concat(Array(6 - pastedData.length).fill(''));
27676
- onChange(newValues);
27677
- // Focus the next empty input or the last one
27678
- const nextIndex = Math.min(pastedData.length, 5);
27679
- inputRefs.current[nextIndex]?.focus();
27680
- };
27681
- return (jsxRuntime.jsx("div", { className: "ai-chat-pin-input-group", children: values.map((value, index) => (jsxRuntime.jsx("input", { ref: (el) => {
27682
- inputRefs.current[index] = el;
27683
- }, 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))) }));
27684
- }
27685
- function MicrosoftCalendarCard({ action, onComplete, accentColor, className = '' }) {
27686
- const state = action.state;
27687
- const phase = state.phase || "awaiting_email";
27688
- const allowTopic = state.allowTopic !== false;
27689
- const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
27690
- // Debug: Log state changes
27691
- const prevStateRef = React.useRef(null);
27692
- React.useEffect(() => {
27693
- if (JSON.stringify(prevStateRef.current) !== JSON.stringify(state)) {
27694
- console.log('[MicrosoftCalendarCard] State updated:', {
27695
- phase: state.phase,
27696
- hasError: !!state.errorMessage,
27697
- error: state.errorMessage,
27698
- slotsCount: state.availableSlots?.length || 0
27699
- });
27700
- prevStateRef.current = state;
27701
- }
27702
- }, [state]);
27703
- // Email phase state
27704
- const [email, setEmail] = React.useState("");
27705
- const [emailError, setEmailError] = React.useState(null);
27706
- // OTP phase state
27707
- const [otpValues, setOtpValues] = React.useState(Array(6).fill(''));
27708
- const [otpError, setOtpError] = React.useState(null);
27709
- // Loading states
27710
- const [isSubmitting, setIsSubmitting] = React.useState(false);
27711
- // Reset loading state when phase changes (backend has responded)
27712
- // Use useEffect for reliable re-rendering
27713
- React.useEffect(() => {
27714
- console.log('[MicrosoftCalendarCard] Phase changed to:', phase);
27715
- setIsSubmitting(false);
27716
- // Clear errors when transitioning to new phase
27717
- if (phase === "awaiting_email") {
27718
- setEmailError(null);
27719
- setOtpError(null);
27720
- setSelectionError(null);
27721
- }
27722
- else if (phase === "awaiting_otp") {
27723
- setOtpError(state.errorMessage || null);
27724
- setEmailError(null);
27725
- setSelectionError(null);
27726
- // Clear OTP input for fresh attempt
27727
- setOtpValues(Array(6).fill(''));
27728
- }
27729
- else if (phase === "awaiting_options") {
27730
- setEmailError(null);
27731
- setOtpError(null);
27732
- setSelectionError(null);
27733
- }
27734
- else if (phase === "awaiting_booking") {
27735
- setSelectionError(state.errorMessage || null);
27736
- setEmailError(null);
27737
- setOtpError(null);
27738
- }
27739
- else if (phase === "booked" || phase === "cancelled" || phase === "error") {
27740
- setEmailError(null);
27741
- setOtpError(null);
27742
- setSelectionError(null);
27743
- setSelectedId(null); // Reset selection
27744
- }
27745
- }, [phase, state.errorMessage]);
27746
- // Selection phase state
27747
- const rawSlots = state.availableSlots;
27748
- const availableSlots = Array.isArray(rawSlots)
27749
- ? rawSlots.filter((slot) => slot !== null &&
27750
- slot !== undefined &&
27751
- typeof slot === "object" &&
27752
- "startTime" in slot &&
27753
- "endTime" in slot &&
27754
- typeof slot.startTime === "string" &&
27755
- typeof slot.endTime === "string")
27756
- : [];
27757
- const slotsByDate = groupSlotsByDate(availableSlots);
27758
- const dates = Array.from(slotsByDate.keys()).sort();
27759
- const [selectedDate, setSelectedDate] = React.useState(dates[0] ?? "");
27760
- const [selectedSlot, setSelectedSlot] = React.useState(null);
27761
- const [topic, setTopic] = React.useState("");
27762
- const [selectionError, setSelectionError] = React.useState(null);
27763
- // Cancellation phase state
27764
- const [selectedId, setSelectedId] = React.useState(null);
27765
- const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
27766
- // Phase 1: Email Input
27767
- const handleEmailSubmit = () => {
27768
- const trimmedEmail = email.trim();
27769
- if (!trimmedEmail) {
27770
- setEmailError("Please enter your email address");
27771
- return;
27772
- }
27773
- if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmedEmail)) {
27774
- setEmailError("Please enter a valid email address");
27775
- return;
27776
- }
27777
- setEmailError(null);
27778
- setIsSubmitting(true);
27779
- console.log('[MicrosoftCalendarCard] Submitting email:', trimmedEmail);
27780
- setTimeout(() => {
27781
- onComplete?.(action.toolCallId, {
27782
- ...action.state,
27783
- email: trimmedEmail,
27784
- });
27785
- }, 50);
27786
- };
27787
- // Phase 2: OTP Verification
27788
- const handleOtpSubmit = () => {
27789
- const otpCode = otpValues.join('');
27790
- if (otpCode.length !== 6) {
27791
- setOtpError("Please enter the 6-digit code");
27792
- return;
27793
- }
27794
- setOtpError(null);
27795
- setIsSubmitting(true);
27796
- console.log('[MicrosoftCalendarCard] Submitting OTP code');
27797
- setTimeout(() => {
27798
- onComplete?.(action.toolCallId, {
27799
- ...action.state,
27800
- otpCode,
27801
- });
27802
- }, 50);
27803
- };
27804
- // Phase 3: Appointment Selection
27805
- const handleAppointmentConfirm = () => {
27806
- if (!selectedSlot) {
27807
- setSelectionError("Please select a time slot");
27808
- return;
27809
- }
27810
- if (allowTopic && !topic.trim()) {
27811
- setSelectionError("Please enter a meeting topic");
27812
- return;
27813
- }
27814
- setSelectionError(null);
27815
- setIsSubmitting(true);
27816
- console.log('[MicrosoftCalendarCard] Confirming appointment:', {
27817
- slot: selectedSlot,
27818
- topic: topic.trim()
27819
- });
27820
- setTimeout(() => {
27821
- onComplete?.(action.toolCallId, {
27822
- ...action.state,
27823
- selectedSlot: {
27824
- startTime: selectedSlot.startTime,
27825
- endTime: selectedSlot.endTime,
27826
- },
27827
- topic: allowTopic ? topic.trim() : null,
27828
- });
27829
- }, 50);
27830
- };
27831
- // Handle "Use different email" button
27832
- const handleUseDifferentEmail = () => {
27833
- setEmail("");
27834
- setEmailError(null);
27835
- setOtpValues(Array(6).fill(''));
27836
- setOtpError(null);
27837
- onComplete?.(action.toolCallId, {
27838
- phase: "awaiting_email",
27839
- email: null,
27840
- otpVerified: false,
27841
- otpAttempts: 0,
27842
- availableSlots: [],
27843
- selectedSlot: null,
27844
- topic: null,
27845
- bookedEventId: null,
27846
- bookedEventLink: null,
27847
- allowTopic,
27848
- errorMessage: null,
27849
- });
27850
- };
27851
- // Phase 5: Booked Confirmation
27852
- if (phase === "booked") {
27853
- const bookedSlot = state.selectedSlot;
27854
- const bookedTopic = state.topic;
27855
- const eventLink = state.bookedEventLink;
27856
- const bookedEmail = state.email;
27857
- 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, {})] }))] })] }));
27858
- }
27859
- // Phase 6: Cancelled Confirmation
27860
- if (phase === "cancelled") {
27861
- const cancelledSubject = state.cancelledEventSubject;
27862
- const userEmail = state.email;
27863
- 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] }))] })] }));
27864
- }
27865
- // Error State
27866
- if (phase === "error") {
27867
- 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: () => {
27868
- setEmail("");
27869
- setEmailError(null);
27870
- setOtpValues(Array(6).fill(''));
27871
- setOtpError(null);
27872
- onComplete?.(action.toolCallId, {
27873
- phase: "awaiting_email",
27874
- email: null,
27875
- otpVerified: false,
27876
- otpAttempts: 0,
27877
- availableSlots: [],
27878
- selectedSlot: null,
27879
- topic: null,
27880
- bookedEventId: null,
27881
- bookedEventLink: null,
27882
- allowTopic,
27883
- errorMessage: null,
27884
- });
27885
- }, children: "Start Over" })] })] }));
27886
- }
27887
- // Loading State
27888
- if (isSubmitting) {
27889
- 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, { 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" })] }) }));
27890
- }
27891
- // Phase 1: Email Input
27892
- if (phase === "awaiting_email") {
27893
- const displayError = state.errorMessage || emailError;
27894
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(CalendarIcon, {}), "Schedule an Appointment"] }), 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) => {
27895
- setEmail(e.target.value);
27896
- setEmailError(null);
27897
- }, onKeyPress: (e) => {
27898
- if (e.key === 'Enter') {
27899
- handleEmailSubmit();
27900
- }
27901
- }, 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" })] })] }));
27902
- }
27903
- // Phase 2: OTP Input
27904
- if (phase === "awaiting_otp") {
27905
- const displayError = state.errorMessage || otpError;
27906
- const userEmail = state.email;
27907
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(MailIcon, {}), "Verify Your Email"] }), 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, { values: otpValues, onChange: (newValues) => {
27908
- setOtpValues(newValues);
27909
- setOtpError(null);
27910
- // Auto-submit when all 6 digits are entered
27911
- if (newValues.every(v => v.length === 1)) {
27912
- console.log('[MicrosoftCalendarCard] Auto-submitting OTP (all 6 digits entered)');
27913
- setIsSubmitting(true);
27914
- const code = newValues.join('');
27915
- setTimeout(() => {
27916
- onComplete?.(action.toolCallId, {
27917
- ...action.state,
27918
- otpCode: code,
27919
- });
27920
- }, 100);
27921
- }
27922
- }, 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" })] })] }));
27923
- }
27924
- // Phase 3: Options Menu (with inline cancel buttons and confirmation)
27925
- if (phase === "awaiting_options") {
27926
- const userAppointments = state.userAppointments || [];
27927
- const maxAppointments = state.maxAppointmentsPerUser || 3;
27928
- const appointmentCount = userAppointments.length;
27929
- const canBook = appointmentCount < maxAppointments;
27930
- const hasAppointments = appointmentCount > 0;
27931
- const displayError = state.errorMessage || selectionError;
27932
- // If confirming cancellation, show confirmation dialog
27933
- if (selectedId) {
27934
- const appointmentToCancel = userAppointments.find(appt => appt.id === selectedId);
27935
- if (!appointmentToCancel) {
27936
- setSelectedId(null); // Reset if appointment not found
27937
- }
27938
- else {
27939
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(CalendarIcon, {}), "Confirm Cancellation"] }), 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: () => {
27940
- setIsSubmitting(true);
27941
- onComplete?.(action.toolCallId, {
27942
- ...action.state,
27943
- selectedOption: "cancel",
27944
- selectedAppointmentId: selectedId,
27945
- });
27946
- }, disabled: isSubmitting, children: isSubmitting ? 'Cancelling...' : 'Confirm Cancellation' }), jsxRuntime.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
27947
- setSelectedId(null);
27948
- setSelectionError(null);
27949
- }, disabled: isSubmitting, children: "Go Back" })] })] })] }));
27950
- }
27951
- }
27952
- // Normal view with inline cancel buttons
27953
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(CalendarIcon, {}), "Manage Your Appointments"] }), 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: () => {
27954
- setSelectedId(appt.id);
27955
- setSelectionError(null);
27956
- }, 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: () => {
27957
- setIsSubmitting(true);
27958
- onComplete?.(action.toolCallId, {
27959
- ...action.state,
27960
- selectedOption: "book",
27961
- });
27962
- }, disabled: isSubmitting, children: isSubmitting ? 'Loading...' : 'Book New Appointment' })), !canBook && !hasAppointments && (jsxRuntime.jsx("div", { className: "ai-chat-action-hint", children: "No appointments found." }))] })] }));
27963
- }
27964
- // Phase 4: Appointment Selection (Booking)
27965
- if (phase === "awaiting_booking") {
27966
- const displayError = state.errorMessage || selectionError;
27967
- return (jsxRuntime.jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx(CalendarIcon, {}), "Select Appointment Time"] }), 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: () => {
27968
- setSelectedDate(date);
27969
- setSelectedSlot(null);
27970
- }, 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." }))] })] }));
27971
- }
27972
- // Fallback
27973
- return null;
27974
- }
27975
-
27976
- function truncate(text, maxLength) {
27612
+ function truncate$1(text, maxLength) {
27977
27613
  if (text.length <= maxLength)
27978
27614
  return text;
27979
27615
  return text.slice(0, maxLength).trim() + '...';
27980
27616
  }
27981
- function ExternalLinkIcon() {
27617
+ function ExternalLinkIcon$2() {
27982
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" })] }));
27983
27619
  }
27984
27620
  function SingleLinkPreview({ link, onLinkClick, accentColor }) {
@@ -27997,10 +27633,10 @@ function SingleLinkPreview({ link, onLinkClick, accentColor }) {
27997
27633
  e.currentTarget.parentElement.style.display = 'none';
27998
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) => {
27999
27635
  e.currentTarget.style.display = 'none';
28000
- } })), 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, {}) })] }));
28001
27637
  }
28002
27638
  function LinkPreviewCard({ action, onComplete, accentColor }) {
28003
- const rawState = action.state;
27639
+ const rawState = action.input;
28004
27640
  const hasCompletedRef = React.useRef(false);
28005
27641
  // Provide safe defaults if state is missing
28006
27642
  const state = {
@@ -28030,11 +27666,12 @@ function LinkPreviewCard({ action, onComplete, accentColor }) {
28030
27666
  if (state.links.length === 0) {
28031
27667
  return null;
28032
27668
  }
28033
- 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: {
28034
- display: 'grid',
28035
- gridTemplateColumns: state.links.length === 1 ? '1fr' : state.links.length === 2 ? 'repeat(2, 1fr)' : 'repeat(3, 1fr)',
28036
- gap: '12px',
28037
- }, 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))) })] }));
28038
27675
  }
28039
27676
 
28040
27677
  function PlayIcon() {
@@ -28055,7 +27692,7 @@ function getProviderLabel(provider) {
28055
27692
  }
28056
27693
  }
28057
27694
  function VideoPlayerCard({ action, onComplete, accentColor }) {
28058
- const rawState = action.state;
27695
+ const rawState = action.input;
28059
27696
  const hasCompletedRef = React.useRef(false);
28060
27697
  const [isPlaying, setIsPlaying] = React.useState(false);
28061
27698
  // Provide safe defaults if state is missing
@@ -28166,7 +27803,7 @@ function LocationItem({ location, settings, accentColor, onDirections, showMap =
28166
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"] }))] })] })] }));
28167
27804
  }
28168
27805
  function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28169
- const rawState = action.state;
27806
+ const rawState = action.input;
28170
27807
  const hasCompletedRef = React.useRef(false);
28171
27808
  const state = {
28172
27809
  locations: rawState?.locations || [],
@@ -28248,7 +27885,7 @@ function ContactItem({ contact, settings, accentColor, onEmail, onPhone, compact
28248
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"] }))] }))] })] }));
28249
27886
  }
28250
27887
  function ContactCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28251
- const rawState = action.state;
27888
+ const rawState = action.input;
28252
27889
  const hasCompletedRef = React.useRef(false);
28253
27890
  const state = {
28254
27891
  contacts: rawState?.contacts || [],
@@ -28283,11 +27920,37 @@ function ContactCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28283
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))) })] }));
28284
27921
  }
28285
27922
 
28286
- function FormCard({ action, onComplete, accentColor }) {
28287
- const state = action.state;
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
+
27943
+ function FormCard({ action, onComplete, onDismiss, accentColor }) {
27944
+ const state = action.input;
28288
27945
  const [currentStep, setCurrentStep] = React.useState(0);
28289
27946
  const [answers, setAnswers] = React.useState({});
28290
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
+ }
28291
27954
  const questions = state.questions || [];
28292
27955
  const currentQuestion = questions[currentStep];
28293
27956
  const totalQuestions = questions.length;
@@ -28308,6 +27971,7 @@ function FormCard({ action, onComplete, accentColor }) {
28308
27971
  if (!onComplete)
28309
27972
  return;
28310
27973
  setIsSubmitting(true);
27974
+ setLocalStatus('submitted');
28311
27975
  const formattedAnswers = Object.entries(answers).map(([questionId, value]) => ({
28312
27976
  questionId,
28313
27977
  value,
@@ -28321,6 +27985,7 @@ function FormCard({ action, onComplete, accentColor }) {
28321
27985
  const handleSkip = () => {
28322
27986
  if (!onComplete || !state.settings.allowSkip)
28323
27987
  return;
27988
+ setLocalStatus('skipped');
28324
27989
  onComplete(action.toolCallId, {
28325
27990
  ...state,
28326
27991
  status: 'skipped',
@@ -28348,23 +28013,29 @@ function FormCard({ action, onComplete, accentColor }) {
28348
28013
  return answer.trim() !== '';
28349
28014
  });
28350
28015
  };
28016
+ const handleDismiss = () => {
28017
+ onDismiss?.(action.toolCallId);
28018
+ };
28019
+ // Use local status if available (for immediate UI feedback), otherwise use state.status
28020
+ const effectiveStatus = localStatus || state.status;
28351
28021
  // Error state
28352
- if (state.status === 'error') {
28353
- 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' })] }));
28354
28024
  }
28355
28025
  // Submitted state
28356
- if (state.status === 'submitted' || action.done) {
28357
- 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!' })] }));
28358
28028
  }
28359
28029
  // Skipped state
28360
- if (state.status === 'skipped') {
28361
- 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" })] }));
28362
28032
  }
28363
28033
  // No questions
28364
28034
  if (totalQuestions === 0) {
28365
- 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." })] }));
28366
28036
  }
28367
- return (jsxRuntime.jsxs("div", { className: "ai-chat-form-card", 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 })] }), 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: {
28368
28039
  width: `${((currentStep + 1) / totalQuestions) * 100}%`,
28369
28040
  backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
28370
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) => {
@@ -28390,104 +28061,915 @@ function FormCard({ action, onComplete, accentColor }) {
28390
28061
  }, children: isSubmitting ? 'Submitting...' : (state.settings.submitButtonText || 'Submit') }))] })] }));
28391
28062
  }
28392
28063
 
28393
- const pendingResolvers = new Map();
28394
- const resumeCallbacks = new Map();
28395
- const frontendActionHandlers = {};
28396
- const actionRenderers = {};
28397
- function getFrontendActionHandler(implementation) {
28398
- return frontendActionHandlers[implementation];
28399
- }
28400
- function getActionRenderer(implementation) {
28401
- return actionRenderers[implementation];
28402
- }
28403
- function waitForActionState(toolCallId) {
28404
- return new Promise((resolve) => {
28405
- pendingResolvers.set(toolCallId, resolve);
28406
- });
28407
- }
28408
- function resolveActionState(toolCallId, state) {
28409
- const resolver = pendingResolvers.get(toolCallId);
28410
- if (resolver) {
28411
- pendingResolvers.delete(toolCallId);
28412
- resolver(state);
28413
- return;
28414
- }
28415
- const resumeCallback = resumeCallbacks.get(toolCallId);
28416
- if (resumeCallback) {
28417
- resumeCallback(state).catch((error) => {
28418
- console.error("[Action] Failed to resume action:", error);
28419
- });
28420
- }
28421
- }
28422
- function registerActionResumeCallback(toolCallId, callback) {
28423
- resumeCallbacks.set(toolCallId, callback);
28424
- }
28425
- function unregisterActionResumeCallback(toolCallId) {
28426
- resumeCallbacks.delete(toolCallId);
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' })] })] }));
28427
28089
  }
28428
28090
 
28429
- function registerGoogleCalendarHandler() {
28430
- frontendActionHandlers["google-calendar-appointment"] = async (_input, _state, context) => {
28431
- return waitForActionState(context.toolCallId);
28091
+ function Skeleton({ width, height, borderRadius = '4px' }) {
28092
+ return (jsxRuntime.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
28093
+ }
28094
+
28095
+ function PinInputGroup({ values, onChange, disabled }) {
28096
+ const inputRefs = React.useRef([]);
28097
+ const handleChange = (index, value) => {
28098
+ // Only allow digits
28099
+ const digit = value.replace(/[^0-9]/g, '');
28100
+ const newValues = [...values];
28101
+ newValues[index] = digit.slice(-1);
28102
+ onChange(newValues);
28103
+ // Auto-focus next input
28104
+ if (digit && index < 5) {
28105
+ inputRefs.current[index + 1]?.focus();
28106
+ }
28107
+ };
28108
+ const handleKeyDown = (index, e) => {
28109
+ if (e.key === 'Backspace' && !values[index] && index > 0) {
28110
+ inputRefs.current[index - 1]?.focus();
28111
+ }
28112
+ };
28113
+ const handlePaste = (e) => {
28114
+ e.preventDefault();
28115
+ const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, 6);
28116
+ const newValues = pastedData.split('').concat(Array(6 - pastedData.length).fill(''));
28117
+ onChange(newValues);
28118
+ // Focus the next empty input or the last one
28119
+ const nextIndex = Math.min(pastedData.length, 5);
28120
+ inputRefs.current[nextIndex]?.focus();
28121
+ };
28122
+ return (jsxRuntime.jsx("div", { className: "ai-chat-pin-input-group", children: values.map((value, index) => (jsxRuntime.jsx("input", { ref: (el) => {
28123
+ inputRefs.current[index] = el;
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))) }));
28125
+ }
28126
+
28127
+ function OtpPhase({ accentColor, onDismiss, showCloseButton, email, onSubmit, onResend, isLoading, error, }) {
28128
+ const [otpValues, setOtpValues] = React.useState(Array(6).fill(''));
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');
28135
+ return;
28136
+ }
28137
+ setLocalError(null);
28138
+ onSubmit(code);
28139
+ };
28140
+ const handleResend = async () => {
28141
+ setIsResending(true);
28142
+ setLocalError(null);
28143
+ try {
28144
+ await onResend();
28145
+ }
28146
+ finally {
28147
+ setIsResending(false);
28148
+ }
28432
28149
  };
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');
28212
+ return;
28213
+ }
28214
+ setLocalError(null);
28215
+ onConfirm(finalSubject);
28216
+ };
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' })] })] }));
28230
+ }
28231
+
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' }))] })] }));
28238
+ }
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 })] }))] })] })] }));
28433
28242
  }
28434
28243
 
28435
28244
  /**
28436
- * Register google-calendar-appointment action handler and renderer.
28437
- * Called by initializeActionHandlers to prevent tree-shaking.
28245
+ * Cancelled Phase Component (terminal state)
28438
28246
  */
28439
- function registerGoogleCalendarAction() {
28440
- // Register the handler
28441
- registerGoogleCalendarHandler();
28442
- // Register the renderer
28443
- actionRenderers["google-calendar-appointment"] = (message, accentColor) => {
28444
- const action = message.action;
28445
- if (!action)
28446
- return null;
28447
- const handleComplete = (toolCallId, newState) => {
28448
- resolveActionState(toolCallId, newState);
28449
- };
28450
- return (jsxRuntime.jsx(GoogleCalendarCard, { action: {
28451
- implementation: action.implementation,
28452
- toolCallId: action.toolCallId,
28453
- actionId: action.actionId,
28454
- input: action.input,
28455
- state: action.state,
28456
- done: action.done ?? false,
28457
- }, onComplete: handleComplete, accentColor: accentColor }));
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." }) })] }));
28249
+ }
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" }))] })] }));
28253
+ }
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" })] }) }));
28257
+ }
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" })] }) }));
28261
+ }
28262
+
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,
28458
28278
  };
28459
28279
  }
28460
28280
 
28461
- function registerMicrosoftCalendarHandler() {
28462
- frontendActionHandlers["microsoft-calendar-appointment"] = async (_input, _state, context) => {
28463
- return waitForActionState(context.toolCallId);
28281
+ /**
28282
+ * Helper functions for accessing booking data
28283
+ */
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,
28464
28300
  };
28465
28301
  }
28466
28302
 
28467
28303
  /**
28468
- * Register microsoft-calendar-appointment action handler and renderer.
28469
- * Called by initializeActionHandlers to prevent tree-shaking.
28304
+ * OTP-related operations for email verification
28470
28305
  */
28471
- function registerMicrosoftCalendarAction() {
28472
- // Register the handler
28473
- registerMicrosoftCalendarHandler();
28474
- // Register the renderer
28475
- actionRenderers["microsoft-calendar-appointment"] = (message, accentColor) => {
28476
- const action = message.action;
28477
- if (!action)
28478
- return null;
28479
- const handleComplete = (toolCallId, newState) => {
28480
- resolveActionState(toolCallId, newState);
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
+ });
28458
+ }
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,
28508
+ };
28509
+ }
28510
+
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
+ }
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, {})] }))] }))] }));
28712
+ }
28713
+
28714
+ /**
28715
+ * URL validation utilities for images, cards, and links
28716
+ * Prevents 404 errors by validating URLs before display
28717
+ */
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 });
28481
28743
  };
28482
- return (jsxRuntime.jsx(MicrosoftCalendarCard, { action: {
28483
- implementation: action.implementation,
28484
- toolCallId: action.toolCallId,
28485
- actionId: action.actionId,
28486
- input: action.input,
28487
- state: action.state,
28488
- done: action.done ?? false,
28489
- }, onComplete: handleComplete, accentColor: accentColor }));
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,
28490
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
+ }
28871
+ }
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);
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);
28491
28973
  }
28492
28974
 
28493
28975
  /**
@@ -28495,9 +28977,15 @@ function registerMicrosoftCalendarAction() {
28495
28977
  * Called by initializeActionHandlers to prevent tree-shaking.
28496
28978
  */
28497
28979
  function registerLinkPreviewAction() {
28498
- // Handler - auto-completes immediately since no user input is needed
28980
+ // Handler - auto-completes immediately, returns body for agent
28499
28981
  frontendActionHandlers["link-preview"] = async (_input, state, _context) => {
28500
- 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
+ };
28501
28989
  };
28502
28990
  // Renderer - displays the link preview card
28503
28991
  actionRenderers["link-preview"] = (message, accentColor) => {
@@ -28507,16 +28995,15 @@ function registerLinkPreviewAction() {
28507
28995
  const handleComplete = (toolCallId, newState) => {
28508
28996
  resolveActionState(toolCallId, newState);
28509
28997
  };
28510
- // Check if action state indicates it's already complete (displaying or clicked)
28511
- const state = action.state;
28512
- const status = state?.status;
28513
- 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";
28514
29002
  return (jsxRuntime.jsx(LinkPreviewCard, { action: {
28515
29003
  implementation: action.implementation,
28516
29004
  toolCallId: action.toolCallId,
28517
29005
  actionId: action.actionId,
28518
29006
  input: action.input,
28519
- state: action.state,
28520
29007
  done: isDone,
28521
29008
  }, onComplete: handleComplete, accentColor: accentColor }));
28522
29009
  };
@@ -28527,9 +29014,15 @@ function registerLinkPreviewAction() {
28527
29014
  * Called by initializeActionHandlers to prevent tree-shaking.
28528
29015
  */
28529
29016
  function registerVideoPlayerAction() {
28530
- // Handler - auto-completes immediately since no user input is needed
29017
+ // Handler - auto-completes immediately, returns body for agent
28531
29018
  frontendActionHandlers["video-player"] = async (_input, state, _context) => {
28532
- 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
+ };
28533
29026
  };
28534
29027
  // Renderer - displays the embedded video player card
28535
29028
  actionRenderers["video-player"] = (message, accentColor) => {
@@ -28539,16 +29032,15 @@ function registerVideoPlayerAction() {
28539
29032
  const handleComplete = (toolCallId, newState) => {
28540
29033
  resolveActionState(toolCallId, newState);
28541
29034
  };
28542
- // Check if action state indicates it's already complete (displaying or played)
28543
- const state = action.state;
28544
- const status = state?.status;
28545
- 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";
28546
29039
  return (jsxRuntime.jsx(VideoPlayerCard, { action: {
28547
29040
  implementation: action.implementation,
28548
29041
  toolCallId: action.toolCallId,
28549
29042
  actionId: action.actionId,
28550
29043
  input: action.input,
28551
- state: action.state,
28552
29044
  done: isDone,
28553
29045
  }, onComplete: handleComplete, accentColor: accentColor }));
28554
29046
  };
@@ -28559,9 +29051,15 @@ function registerVideoPlayerAction() {
28559
29051
  * Called by initializeActionHandlers to prevent tree-shaking.
28560
29052
  */
28561
29053
  function registerLocationCardAction() {
28562
- // Handler - auto-completes immediately since no user input is needed
29054
+ // Handler - auto-completes immediately, returns body for agent
28563
29055
  frontendActionHandlers["location-card"] = async (_input, state, _context) => {
28564
- 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
+ };
28565
29063
  };
28566
29064
  // Renderer - displays the location card
28567
29065
  actionRenderers["location-card"] = (message, accentColor, variant) => {
@@ -28571,25 +29069,30 @@ function registerLocationCardAction() {
28571
29069
  const handleComplete = (toolCallId, newState) => {
28572
29070
  resolveActionState(toolCallId, newState);
28573
29071
  };
28574
- // Check if action state indicates it's already complete
28575
- const state = action.state;
28576
- const status = state?.status;
28577
- 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";
28578
29076
  return (jsxRuntime.jsx(LocationCard, { action: {
28579
29077
  implementation: action.implementation,
28580
29078
  toolCallId: action.toolCallId,
28581
29079
  actionId: action.actionId,
28582
29080
  input: action.input,
28583
- state: action.state,
28584
29081
  done: isDone,
28585
29082
  }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28586
29083
  };
28587
29084
  }
28588
29085
 
28589
29086
  function registerContactCardAction() {
28590
- // Handler - auto-completes immediately since no user input is needed
29087
+ // Handler - auto-completes immediately, returns body for agent
28591
29088
  frontendActionHandlers['contact-card'] = async (_input, state, _context) => {
28592
- 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
+ };
28593
29096
  };
28594
29097
  // Renderer - displays the contact card
28595
29098
  actionRenderers['contact-card'] = (message, accentColor, variant) => {
@@ -28599,16 +29102,15 @@ function registerContactCardAction() {
28599
29102
  const handleComplete = (toolCallId, newState) => {
28600
29103
  resolveActionState(toolCallId, newState);
28601
29104
  };
28602
- // Check if action state indicates it's already complete
28603
- const state = action.state;
28604
- const status = state?.status;
28605
- 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';
28606
29109
  return (jsxRuntime.jsx(ContactCard, { action: {
28607
29110
  implementation: action.implementation,
28608
29111
  toolCallId: action.toolCallId,
28609
29112
  actionId: action.actionId,
28610
29113
  input: action.input,
28611
- state: action.state,
28612
29114
  done: isDone,
28613
29115
  }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28614
29116
  };
@@ -28619,55 +29121,133 @@ function registerQueryContactDirectoryAction() {
28619
29121
  frontendActionHandlers['query-contact-directory'] = async (_input, state, _context) => {
28620
29122
  return { ...state, status: 'displaying' };
28621
29123
  };
28622
- // Renderer - displays the contact card with search results
28623
- actionRenderers['query-contact-directory'] = (message, accentColor, variant) => {
29124
+ // Renderer - displays the contact card with search results
29125
+ actionRenderers['query-contact-directory'] = (message, accentColor, variant) => {
29126
+ const action = message.action;
29127
+ if (!action)
29128
+ return null;
29129
+ // Handle completion - triggers agent to continue with text response
29130
+ const handleComplete = (toolCallId, newState) => {
29131
+ resolveActionState(toolCallId, newState);
29132
+ };
29133
+ // Check if action input indicates it's already complete
29134
+ const input = action.input;
29135
+ const status = input?.status;
29136
+ const isDone = action.done || status === 'displaying' || status === 'contacted';
29137
+ return (jsxRuntime.jsx(ContactCard, { action: {
29138
+ implementation: action.implementation,
29139
+ toolCallId: action.toolCallId,
29140
+ actionId: action.actionId,
29141
+ input: action.input,
29142
+ done: isDone,
29143
+ }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
29144
+ };
29145
+ }
29146
+
29147
+ function registerDisplayFormAction() {
29148
+ // Handler - handles form submission and state updates
29149
+ frontendActionHandlers['display-form'] = async (_input, _state, context) => {
29150
+ return waitForActionState(context.toolCallId);
29151
+ };
29152
+ // Renderer - displays the form card
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) => {
29156
+ const action = message.action;
29157
+ if (!action)
29158
+ return null;
29159
+ const handleComplete = (toolCallId, newState) => {
29160
+ resolveActionState(toolCallId, newState);
29161
+ };
29162
+ const handleDismiss = onActionDismiss
29163
+ ? (toolCallId) => onActionDismiss(toolCallId)
29164
+ : undefined;
29165
+ return (jsxRuntime.jsx(FormCard, { action: {
29166
+ implementation: action.implementation,
29167
+ toolCallId: action.toolCallId,
29168
+ actionId: action.actionId,
29169
+ input: action.input,
29170
+ done: action.done ?? false,
29171
+ }, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
29172
+ };
29173
+ }
29174
+
29175
+ /**
29176
+ * Book Contact Appointment Handler
29177
+ * Frontend action handler that waits for action completion
29178
+ */
29179
+ function registerBookContactAppointmentHandler() {
29180
+ frontendActionHandlers["book-contact-appointment"] = async (_input, _state, context) => {
29181
+ return waitForActionState(context.toolCallId);
29182
+ };
29183
+ }
29184
+
29185
+ /**
29186
+ * Register book-contact-appointment action handler and renderer.
29187
+ * Called by initializeActionHandlers to prevent tree-shaking.
29188
+ */
29189
+ function registerBookContactAppointmentAction() {
29190
+ // Register the handler
29191
+ registerBookContactAppointmentHandler();
29192
+ // Register the renderer
29193
+ actionRenderers['book-contact-appointment'] = (message, accentColor, _variant, _onActionDismiss, onCallEndpoint) => {
28624
29194
  const action = message.action;
28625
29195
  if (!action)
28626
29196
  return null;
28627
- // Handle completion - triggers agent to continue with text response
28628
29197
  const handleComplete = (toolCallId, newState) => {
28629
29198
  resolveActionState(toolCallId, newState);
28630
29199
  };
28631
- // Check if action state indicates it's already complete
28632
- const state = action.state;
28633
- const status = state?.status;
28634
- const isDone = action.done || status === 'displaying' || status === 'contacted';
28635
- return (jsxRuntime.jsx(ContactCard, { action: {
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;
29211
+ return (jsxRuntime.jsx(BookContactAppointmentCard, { action: {
28636
29212
  implementation: action.implementation,
28637
29213
  toolCallId: action.toolCallId,
28638
29214
  actionId: action.actionId,
28639
29215
  input: action.input,
28640
- state: action.state,
28641
- done: isDone,
28642
- }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
29216
+ done: action.done ?? false,
29217
+ }, onComplete: handleComplete, onDismiss: handleDismiss, onCallEndpoint: handleCallEndpoint, accentColor: accentColor }));
28643
29218
  };
28644
29219
  }
28645
29220
 
28646
- function registerDisplayFormAction() {
28647
- // Handler - handles form submission and state updates
28648
- frontendActionHandlers['display-form'] = async (_input, _state, context) => {
28649
- return waitForActionState(context.toolCallId);
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
+ };
28650
29231
  };
28651
- // Renderer - displays the form card
28652
- actionRenderers['display-form'] = (message, accentColor, variant) => {
29232
+ // Renderer - displays the image content
29233
+ actionRenderers['structured-image'] = (message, accentColor, variant, onActionDismiss) => {
28653
29234
  const action = message.action;
28654
29235
  if (!action)
28655
29236
  return null;
28656
29237
  const handleComplete = (toolCallId, newState) => {
28657
29238
  resolveActionState(toolCallId, newState);
28658
29239
  };
28659
- // Check if action state indicates it's already complete
28660
- const state = action.state;
28661
- const status = state?.status;
28662
- const isDone = action.done || status === 'completed' || status === 'submitted';
28663
- return (jsxRuntime.jsx(FormCard, { action: {
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: {
28664
29245
  implementation: action.implementation,
28665
29246
  toolCallId: action.toolCallId,
28666
29247
  actionId: action.actionId,
28667
29248
  input: action.input,
28668
- state: action.state,
28669
29249
  done: isDone,
28670
- }, onComplete: handleComplete, accentColor: accentColor }));
29250
+ }, onComplete: handleComplete, onDismiss: onActionDismiss ? () => onActionDismiss(action.toolCallId) : undefined, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 2 }));
28671
29251
  };
28672
29252
  }
28673
29253
 
@@ -28683,14 +29263,14 @@ function initializeActionHandlers() {
28683
29263
  return;
28684
29264
  initialized = true;
28685
29265
  // Explicitly call each registration function to prevent tree-shaking
28686
- registerGoogleCalendarAction();
28687
- registerMicrosoftCalendarAction();
28688
29266
  registerLinkPreviewAction();
28689
29267
  registerVideoPlayerAction();
28690
29268
  registerLocationCardAction();
28691
29269
  registerQueryContactDirectoryAction();
28692
29270
  registerContactCardAction();
28693
29271
  registerDisplayFormAction();
29272
+ registerBookContactAppointmentAction();
29273
+ registerStructuredImageAction();
28694
29274
  }
28695
29275
 
28696
29276
  /**
@@ -28953,8 +29533,49 @@ function hydrateToolNames(messages) {
28953
29533
  };
28954
29534
  });
28955
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
+ }
28956
29575
  function hydrateMessages(messages) {
28957
- return hydrateToolNames(messages);
29576
+ const visibleMessages = messages.filter((message) => !message.action?.hidden);
29577
+ const cleanedMessages = cleanupInterruptedMessages(visibleMessages);
29578
+ return hydrateToolNames(cleanedMessages);
28958
29579
  }
28959
29580
 
28960
29581
  function deriveErrorInfo(error) {
@@ -29024,6 +29645,75 @@ function deriveErrorInfo(error) {
29024
29645
  return { message: 'Something went wrong. Please try again.' };
29025
29646
  }
29026
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
+
29027
29717
  function createStreamState() {
29028
29718
  return {
29029
29719
  currentContent: "",
@@ -29033,6 +29723,7 @@ function createStreamState() {
29033
29723
  sources: [],
29034
29724
  toolCallToActionId: {},
29035
29725
  requestId: generateMessageId(),
29726
+ buffer: createStreamBuffer(),
29036
29727
  };
29037
29728
  }
29038
29729
  function upsertMessage(setState, message, isTyping) {
@@ -29095,6 +29786,8 @@ function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
29095
29786
  },
29096
29787
  isStreaming: false,
29097
29788
  toolExecuting: existingName,
29789
+ // Mark action as done when tool message is finalized
29790
+ action: entry.action ? { ...entry.action, done: true } : undefined,
29098
29791
  };
29099
29792
  });
29100
29793
  return { ...prev, messages, isTyping: false, isLoading: false };
@@ -29103,26 +29796,34 @@ function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
29103
29796
  }
29104
29797
 
29105
29798
  function handleContentEvent(event, streamState, onMessageUpdate, setState) {
29799
+ // Track full content for finalization
29106
29800
  streamState.currentContent += event.content;
29107
- const assistantMessage = {
29108
- id: streamState.currentMessageId,
29109
- message: { role: "assistant", content: streamState.currentContent },
29110
- timestamp: new Date().toISOString(),
29111
- sources: streamState.sources,
29112
- isStreaming: true,
29113
- };
29114
- streamState.newMessageIds.add(assistantMessage.id);
29115
- onMessageUpdate(assistantMessage);
29116
- const hasContent = assistantMessage.message.content?.trim().length || 0 > 0;
29117
- const isToolExecuting = streamState.activeToolCallCount > 0;
29118
- const isTyping = (!hasContent && assistantMessage.isStreaming) || isToolExecuting;
29119
- 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
+ });
29120
29819
  }
29121
29820
  function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
29122
- if (streamState.currentContent.trim()) {
29821
+ // Flush buffer before tool starts
29822
+ const flushedContent = flushBuffer(streamState.buffer);
29823
+ if (flushedContent.trim()) {
29123
29824
  const finalAssistant = {
29124
29825
  id: streamState.currentMessageId,
29125
- message: { role: "assistant", content: streamState.currentContent },
29826
+ message: { role: "assistant", content: flushedContent },
29126
29827
  timestamp: new Date().toISOString(),
29127
29828
  sources: streamState.sources,
29128
29829
  isStreaming: false,
@@ -29133,6 +29834,8 @@ function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
29133
29834
  streamState.currentContent = "";
29134
29835
  streamState.currentMessageId = generateMessageId();
29135
29836
  }
29837
+ // Reset buffer for post-tool content
29838
+ resetBuffer(streamState.buffer);
29136
29839
  const toolMessageId = event.tool_call_id;
29137
29840
  streamState.activeToolCallCount += 1;
29138
29841
  streamState.newMessageIds.add(toolMessageId);
@@ -29150,43 +29853,22 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
29150
29853
  streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
29151
29854
  setState(prev => {
29152
29855
  const messages = prev.messages.map((msg) => {
29153
- const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
29154
- if (!matchesToolCall) {
29856
+ if (msg.message.role !== "tool" || msg.message.tool_call_id !== event.tool_call_id) {
29155
29857
  return msg;
29156
29858
  }
29157
- const existingName = msg.message.name || event.tool_name;
29158
- let action = msg.action;
29159
- if (event.action_id && event.implementation) {
29160
- action = {
29161
- implementation: event.implementation,
29162
- toolCallId: event.tool_call_id,
29163
- actionId: event.action_id,
29164
- input: (event.input || {}),
29165
- state: (event.state || {}),
29166
- done: event.done,
29167
- };
29168
- }
29169
- else if (action) {
29170
- action = {
29171
- ...action,
29172
- input: event.input ? event.input : action.input,
29173
- state: event.state ? event.state : action.state,
29174
- done: event.done,
29175
- };
29176
- }
29177
- 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 {
29178
29866
  ...msg,
29179
- message: {
29180
- role: "tool",
29181
- content: event.state ? JSON.stringify(event.state) : (typeof msg.message.content === "string" ? msg.message.content : ""),
29182
- tool_call_id: event.tool_call_id,
29183
- name: existingName,
29184
- },
29867
+ message: { ...msg.message, name: toolName },
29185
29868
  isStreaming: false,
29186
- toolExecuting: existingName,
29869
+ toolExecuting: toolName,
29187
29870
  action,
29188
29871
  };
29189
- return updatedMsg;
29190
29872
  });
29191
29873
  return { ...prev, messages, isTyping: true, isLoading: false };
29192
29874
  });
@@ -29219,11 +29901,6 @@ function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
29219
29901
  return { ...prev, messages, isTyping: true, isLoading: false };
29220
29902
  });
29221
29903
  }
29222
- function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
29223
- streamState.sources = event.sources;
29224
- streamState.toolCallToActionId = event.tool_call_to_action_id;
29225
- finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
29226
- }
29227
29904
  function handleHaltEvent(event, _streamState, onMessageUpdate, setState) {
29228
29905
  const toolNames = event.tool_calls.map(call => call.name).join(", ");
29229
29906
  const notice = toolNames
@@ -29238,7 +29915,8 @@ function handleHaltEvent(event, _streamState, onMessageUpdate, setState) {
29238
29915
  };
29239
29916
  onMessageUpdate(haltMessage);
29240
29917
  upsertMessage(setState, haltMessage, false);
29241
- 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." }));
29242
29920
  }
29243
29921
  function handleErrorEvent(_event, _streamState, onMessageUpdate, setState) {
29244
29922
  const errorMessage = {
@@ -29250,6 +29928,8 @@ function handleErrorEvent(_event, _streamState, onMessageUpdate, setState) {
29250
29928
  };
29251
29929
  onMessageUpdate(errorMessage);
29252
29930
  upsertMessage(setState, errorMessage, false);
29931
+ // Stop loading/typing state on error
29932
+ setState(prev => ({ ...prev, isLoading: false, isTyping: false }));
29253
29933
  }
29254
29934
  const eventHandlers = {
29255
29935
  content: handleContentEvent,
@@ -29277,7 +29957,37 @@ function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
29277
29957
  console.warn('[Chat] Unknown event type:', event.type);
29278
29958
  }
29279
29959
  }
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);
29979
+ }
29280
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
+ */
29281
29991
  async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
29282
29992
  let pendingEvent = initialEvent;
29283
29993
  while (pendingEvent) {
@@ -29303,7 +30013,6 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29303
30013
  toolCallId: pendingEvent.tool_call_id,
29304
30014
  actionId: pendingEvent.action_id,
29305
30015
  input: pendingEvent.input,
29306
- state: pendingEvent.state,
29307
30016
  done: pendingEvent.done ?? false,
29308
30017
  },
29309
30018
  };
@@ -29328,9 +30037,13 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29328
30037
  upsertMessage(setState, errorMessage, false);
29329
30038
  return;
29330
30039
  }
29331
- 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;
29332
30044
  try {
29333
- 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
+ {
29334
30047
  widgetId,
29335
30048
  conversationId,
29336
30049
  toolCallId: pendingEvent.tool_call_id,
@@ -29352,19 +30065,16 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29352
30065
  return;
29353
30066
  }
29354
30067
  pendingEvent = null;
29355
- const updatedToolMessage = {
29356
- ...toolMessage,
29357
- action: toolMessage.action ? { ...toolMessage.action, state: nextState } : toolMessage.action,
29358
- };
29359
- upsertMessage(setState, updatedToolMessage, true);
30068
+ // Send body to backend and continue agent
30069
+ // No need to update message - input is immutable and already contains display data
29360
30070
  let streamEnded = false;
29361
- for await (const event of client.continueAgentMessageStream(conversationId, resumeToolCallId, nextState)) {
30071
+ for await (const event of client.continueAgentAction(conversationId, resumeToolCallId, body)) {
29362
30072
  if (event.type === "action_request") {
30073
+ // Chained action - continue the loop
29363
30074
  pendingEvent = event;
29364
30075
  break;
29365
30076
  }
29366
30077
  if (event.type === "done") {
29367
- // Finalize tool message and stream messages
29368
30078
  finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
29369
30079
  streamState.sources = event.sources;
29370
30080
  streamState.toolCallToActionId = event.tool_call_to_action_id;
@@ -29394,57 +30104,118 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
29394
30104
  }
29395
30105
  }
29396
30106
  }
29397
- 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) {
29398
30114
  // Find all incomplete actions and register resume callbacks
29399
30115
  for (const message of messages) {
29400
- if (message.action && !message.action.done) {
29401
- const toolCallId = message.action.toolCallId;
29402
- const toolName = message.message.name || message.toolExecuting || "tool";
29403
- registerCallback(toolCallId, async (newState) => {
29404
- // When user interacts with the action after reload, continue the stream
30116
+ if (message.action && !message.action.done && !message.action.hidden) {
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
29405
30121
  try {
29406
- // Update the action message with the new state and check completion
29407
30122
  setState(prev => ({
29408
30123
  ...prev,
29409
- messages: prev.messages.map(m => {
29410
- if (m.action?.toolCallId !== toolCallId) {
29411
- return m;
29412
- }
29413
- if (!m.action) {
29414
- return m;
29415
- }
29416
- return { ...m, action: { ...m.action, state: newState } };
29417
- }),
29418
30124
  isTyping: true,
29419
30125
  }));
29420
30126
  const streamState = createStreamState();
29421
- // Continue the agent stream with the new state
29422
- for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
29423
- if (event.type === "done") {
29424
- finalizeToolMessage(streamState, setState, toolCallId, toolName);
29425
- streamState.sources = event.sources;
29426
- streamState.toolCallToActionId = event.tool_call_to_action_id;
29427
- finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
29428
- 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;
29429
30169
  }
29430
- if (event.type === "error") {
29431
- const errorMessage = {
29432
- id: generateMessageId(),
29433
- message: {
29434
- role: "assistant",
29435
- content: "Sorry, an error occurred. Please try again later.",
29436
- },
29437
- timestamp: new Date().toISOString(),
29438
- sources: [],
29439
- isError: true,
29440
- };
29441
- upsertMessage(setState, errorMessage, false);
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
+ });
30209
+ }
30210
+ catch (handlerError) {
30211
+ console.error("[Action Resume] Handler failed:", handlerError);
29442
30212
  setState(prev => ({ ...prev, isTyping: false }));
29443
30213
  return;
29444
30214
  }
29445
- handleStreamEvent(event, streamState, onMessageUpdate, setState);
30215
+ // Continue loop with new body
30216
+ currentToolCallId = nextActionRequest.tool_call_id;
30217
+ currentBody = handlerResult;
29446
30218
  }
29447
- setState(prev => ({ ...prev, isTyping: false }));
29448
30219
  }
29449
30220
  catch (error) {
29450
30221
  console.error("[Action Resume] Failed to continue stream:", error);
@@ -29523,7 +30294,7 @@ function useChat(options) {
29523
30294
  }));
29524
30295
  // Setup resume callbacks for incomplete actions
29525
30296
  if (conversationId) {
29526
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
30297
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, widgetId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
29527
30298
  }
29528
30299
  }
29529
30300
  catch (error) {
@@ -29546,7 +30317,7 @@ function useChat(options) {
29546
30317
  }
29547
30318
  });
29548
30319
  };
29549
- }, [widgetId, apiUrl, onError]);
30320
+ }, [widgetId, apiUrl, onError, skipInitialization]);
29550
30321
  // Save conversation when messages change
29551
30322
  React.useEffect(() => {
29552
30323
  const persistConversation = state.config?.settings.persistConversation ?? true;
@@ -29557,6 +30328,21 @@ function useChat(options) {
29557
30328
  saveConversation(widgetId, state.conversationId, state.messages);
29558
30329
  }
29559
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]);
29560
30346
  const sendMessage = React.useCallback(async (content, files) => {
29561
30347
  const trimmedContent = content.trim();
29562
30348
  const hasFiles = !!files && files.length > 0;
@@ -29640,12 +30426,14 @@ function useChat(options) {
29640
30426
  stateRef.current.conversationId !== streamConversationId ||
29641
30427
  currentRequestIdRef.current !== streamRequestId) {
29642
30428
  console.log('[Widget] Stream aborted, conversation changed, or superseded by new request');
30429
+ cancelBuffer(streamState.buffer);
29643
30430
  break;
29644
30431
  }
29645
30432
  if (event.type === "action_request") {
29646
30433
  if (currentAbortController?.signal.aborted ||
29647
30434
  stateRef.current.conversationId !== streamConversationId ||
29648
30435
  currentRequestIdRef.current !== streamRequestId) {
30436
+ cancelBuffer(streamState.buffer);
29649
30437
  break;
29650
30438
  }
29651
30439
  await handleActionLoop(apiClient.current, event, streamState, (message) => {
@@ -29671,26 +30459,8 @@ function useChat(options) {
29671
30459
  if (lastStreamedMessage) {
29672
30460
  onMessage?.(lastStreamedMessage);
29673
30461
  }
29674
- const enableFollowUps = state.config?.settings.enableFollowUpSuggestions !== false;
29675
- const actionIds = state.config?.actions || [];
29676
- if (enableFollowUps) {
29677
- apiClient.current.generateFollowUps(stateRef.current.messages, actionIds)
29678
- .then(suggestions => {
29679
- if (suggestions.length > 0) {
29680
- setState(prev => {
29681
- const messages = [...prev.messages];
29682
- for (let i = messages.length - 1; i >= 0; i--) {
29683
- if (messages[i].message.role === 'assistant' && !messages[i].isError) {
29684
- messages[i] = { ...messages[i], suggestions };
29685
- break;
29686
- }
29687
- }
29688
- return { ...prev, messages };
29689
- });
29690
- }
29691
- })
29692
- .catch(err => console.warn('[Widget] Follow-up generation failed:', err));
29693
- }
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()
29694
30464
  }
29695
30465
  catch (error) {
29696
30466
  console.error("[Widget] sendMessage error:", error);
@@ -29752,6 +30522,51 @@ function useChat(options) {
29752
30522
  onError?.(err);
29753
30523
  }
29754
30524
  }, [state.conversationId, onError]);
30525
+ const dismissAction = React.useCallback(async (toolCallId) => {
30526
+ if (!toolCallId)
30527
+ return;
30528
+ const dismissedAt = new Date().toISOString();
30529
+ setState(prev => ({
30530
+ ...prev,
30531
+ messages: prev.messages.map((message) => {
30532
+ if (message.action?.toolCallId !== toolCallId) {
30533
+ return message;
30534
+ }
30535
+ if (!message.action) {
30536
+ return message;
30537
+ }
30538
+ return {
30539
+ ...message,
30540
+ action: {
30541
+ ...message.action,
30542
+ hidden: true,
30543
+ dismissedAt,
30544
+ dismissedBy: "user",
30545
+ done: true,
30546
+ },
30547
+ };
30548
+ }),
30549
+ isTyping: true,
30550
+ isLoading: false,
30551
+ }));
30552
+ unregisterActionResumeCallback(toolCallId);
30553
+ const conversationId = stateRef.current.conversationId;
30554
+ if (!conversationId) {
30555
+ setState(prev => ({ ...prev, isTyping: false }));
30556
+ return;
30557
+ }
30558
+ try {
30559
+ const streamState = createStreamState();
30560
+ for await (const event of apiClient.current.dismissAgentMessageStream(conversationId, toolCallId)) {
30561
+ handleStreamEvent(event, streamState, onMessage ?? (() => { }), setState);
30562
+ }
30563
+ setState(prev => ({ ...prev, isTyping: false, isLoading: false }));
30564
+ }
30565
+ catch (error) {
30566
+ console.error("[Widget] dismissAction error:", error);
30567
+ setState(prev => ({ ...prev, isTyping: false, isLoading: false }));
30568
+ }
30569
+ }, [onMessage]);
29755
30570
  const loadConversations = React.useCallback(() => {
29756
30571
  const persistConversation = state.config?.settings.persistConversation ?? true;
29757
30572
  if (!persistConversation || !isStorageAvailable()) {
@@ -29802,7 +30617,7 @@ function useChat(options) {
29802
30617
  messages: hydratedMessages,
29803
30618
  isLoading: false,
29804
30619
  }));
29805
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
30620
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, widgetId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
29806
30621
  if (persistConversation && isStorageAvailable()) {
29807
30622
  saveConversation(widgetId, conversation.id, hydratedMessages);
29808
30623
  }
@@ -29852,6 +30667,53 @@ function useChat(options) {
29852
30667
  }));
29853
30668
  }
29854
30669
  }, [widgetId, state.config?.settings.persistConversation, state.conversationId]);
30670
+ const createDemoConversation = React.useCallback(async (userMessage, assistantMessage) => {
30671
+ try {
30672
+ const result = await apiClient.current.createDemoConversation(userMessage, assistantMessage);
30673
+ if (result.success && result.id) {
30674
+ // Update state with the new conversation ID
30675
+ setState(prev => ({
30676
+ ...prev,
30677
+ conversationId: result.id,
30678
+ }));
30679
+ // Save to local storage if persistence is enabled
30680
+ const persistConversation = state.config?.settings.persistConversation ?? true;
30681
+ if (persistConversation && isStorageAvailable()) {
30682
+ const demoMessages = [
30683
+ {
30684
+ id: generateMessageId(),
30685
+ message: { role: 'user', content: userMessage },
30686
+ timestamp: new Date().toISOString(),
30687
+ sources: [],
30688
+ },
30689
+ {
30690
+ id: generateMessageId(),
30691
+ message: { role: 'assistant', content: assistantMessage },
30692
+ timestamp: new Date(Date.now() + 1000).toISOString(),
30693
+ sources: [],
30694
+ },
30695
+ ];
30696
+ saveConversation(widgetId, result.id, demoMessages);
30697
+ }
30698
+ return result.id;
30699
+ }
30700
+ return null;
30701
+ }
30702
+ catch (error) {
30703
+ console.error('[useChat] Failed to create demo conversation:', error);
30704
+ return null;
30705
+ }
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]);
29855
30717
  return {
29856
30718
  messages: state.messages,
29857
30719
  isLoading: state.isLoading,
@@ -29862,20 +30724,22 @@ function useChat(options) {
29862
30724
  sendMessage,
29863
30725
  clearMessages,
29864
30726
  submitFeedback,
30727
+ dismissAction,
29865
30728
  conversations,
29866
30729
  loadConversations,
29867
30730
  switchConversation,
29868
30731
  startNewConversation,
29869
30732
  deleteConversation: deleteConversation$1,
30733
+ createDemoConversation,
30734
+ callActionEndpoint,
29870
30735
  };
29871
30736
  }
29872
30737
 
29873
- const ShieldIcon = () => (jsxRuntime.jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }), jsxRuntime.jsx("path", { d: "M9 12l2 2 4-4" })] }));
29874
30738
  const DataPolicyView = ({ config, widgetName, }) => {
29875
30739
  const headerTitle = widgetName || config?.appearance?.headerTitle || 'AI Assistant';
29876
30740
  const hasFileUpload = config?.settings?.enableFileUpload ?? false;
29877
30741
  const persistsConversation = config?.settings?.persistConversation ?? true;
29878
- return (jsxRuntime.jsx("div", { className: "ai-chat-data-policy-view", children: jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-content", children: [jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-intro", children: [jsxRuntime.jsx("div", { className: "ai-chat-data-policy-icon", children: jsxRuntime.jsx(ShieldIcon, {}) }), jsxRuntime.jsxs("p", { children: ["Dieser Datenschutzhinweis informiert dich gem\u00E4\u00DF Art. 13 DSGVO dar\u00FCber, wie ", jsxRuntime.jsx("strong", { children: headerTitle }), " Daten verarbeitet, wenn du diesen Chat nutzt. Bitte beachte, dass der konkrete Umfang der Verarbeitung vom Betreiber dieser Website/Anwendung (dem Verantwortlichen) sowie von den jeweils aktivierten Funktionen abh\u00E4ngt."] })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Verantwortlicher / Kontakt" }), jsxRuntime.jsx("p", { children: "Verantwortlicher im Sinne von Art. 4 Nr. 7 DSGVO ist der Betreiber dieser Website/Anwendung. Die Kontaktdaten (und ggf. die Kontaktdaten eines Datenschutzbeauftragten) findest du in der Datenschutzerkl\u00E4rung bzw. im Impressum der Website, in die dieses Chat-Widget eingebunden ist." })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Verarbeitete Daten (Kategorien)" }), jsxRuntime.jsxs("ul", { children: [jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Chat-Inhalte:" }), " Nachrichten (Text) sowie ggf. Kontextinformationen, die du im Chat angibst. Diese Inhalte werden verarbeitet, um Antworten zu generieren und die Unterhaltung bereitzustellen."] }), hasFileUpload && (jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Hochgeladene Dateien:" }), " Dateien, die du an den Chat \u00FCbermittelst, werden zur Bearbeitung des Anliegens verarbeitet. Die Verarbeitung kann das Extrahieren von Text/Informationen umfassen."] })), jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Technische Nutzungsdaten:" }), " z.B. Zeitstempel, Sitzungs-/Request-Informationen sowie technische Metadaten, die f\u00FCr den Betrieb, die Sicherheit (Missbrauchspr\u00E4vention) und Fehleranalyse erforderlich sind."] })] })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Zwecke und Rechtsgrundlagen" }), jsxRuntime.jsxs("ul", { children: [jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Bereitstellung des Chats und Beantwortung von Anfragen" }), " (Art. 6 Abs. 1 lit. b DSGVO, soweit Vertrags-/vorvertragliche Ma\u00DFnahmen; andernfalls Art. 6 Abs. 1 lit. f DSGVO \u2013 berechtigtes Interesse an effizienter Kommunikation und Support)."] }), jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Qualit\u00E4tssicherung, Betrieb und Sicherheit" }), " (Art. 6 Abs. 1 lit. f DSGVO), z.B. zur Stabilit\u00E4t, Missbrauchserkennung und Fehlerbehebung."] }), jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Einwilligungsbasierte Verarbeitung" }), " kann erfolgen, sofern der Betreiber dies vorsieht (Art. 6 Abs. 1 lit. a DSGVO)."] })] })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Empf\u00E4nger und Auftragsverarbeiter" }), jsxRuntime.jsxs("ul", { children: [jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Hosting/IT-Dienstleister:" }), " Der Betreiber kann Dienstleister f\u00FCr Hosting, Logging, Monitoring und Infrastruktur einsetzen."] }), jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "KI-Dienstleister:" }), " Zur Generierung von Antworten k\u00F6nnen Chat-Inhalte an KI-Modelle bzw. Anbieter von KI-Infrastruktur \u00FCbertragen werden. Soweit erforderlich, erfolgt dies auf Grundlage eines Auftragsverarbeitungsvertrags (Art. 28 DSGVO)."] }), jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Drittlandtransfer:" }), " Falls Empf\u00E4nger au\u00DFerhalb der EU/des EWR sitzen, kann ein Transfer in Drittl\u00E4nder stattfinden. In diesem Fall werden geeignete Garantien (z.B. EU-Standardvertragsklauseln) eingesetzt, soweit erforderlich."] })] })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Speicherdauer" }), jsxRuntime.jsxs("ul", { children: [persistsConversation ? (jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Chatverlauf:" }), " Der Chatverlauf kann gespeichert werden, um die Unterhaltung \u00FCber mehrere Sitzungen hinweg fortzusetzen."] })) : (jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Chatverlauf:" }), " Der Chatverlauf wird nicht dauerhaft gespeichert und wird beim Schlie\u00DFen des Chats beendet."] })), hasFileUpload && (jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Dateien:" }), " Hochgeladene Dateien werden nur so lange verarbeitet, wie dies f\u00FCr die Bearbeitung erforderlich ist, und anschlie\u00DFend gel\u00F6scht, sofern keine l\u00E4ngere Speicherung gesetzlich erforderlich ist."] })), jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Technische Protokolle:" }), " Technische Logdaten k\u00F6nnen f\u00FCr einen begrenzten Zeitraum gespeichert werden, um den sicheren Betrieb zu gew\u00E4hrleisten."] })] })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Deine Rechte (Betroffenenrechte)" }), jsxRuntime.jsxs("ul", { children: [jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Auskunft" }), " (Art. 15 DSGVO)"] }), jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Berichtigung" }), " (Art. 16 DSGVO)"] }), jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "L\u00F6schung" }), " (Art. 17 DSGVO) und ", jsxRuntime.jsx("strong", { children: "Einschr\u00E4nkung der Verarbeitung" }), " (Art. 18 DSGVO)"] }), jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Daten\u00FCbertragbarkeit" }), " (Art. 20 DSGVO), soweit anwendbar"] }), jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Widerspruch" }), " gegen Verarbeitungen auf Grundlage berechtigter Interessen (Art. 21 DSGVO)"] }), jsxRuntime.jsxs("li", { children: [jsxRuntime.jsx("strong", { children: "Beschwerderecht" }), " bei einer Datenschutzaufsichtsbeh\u00F6rde (Art. 77 DSGVO)"] })] }), jsxRuntime.jsx("p", { children: "Hinweis: Ohne eindeutige Identifikationsmerkmale kann der Betreiber einzelne Chatverl\u00E4ufe ggf. nicht einer Person zuordnen. F\u00FCr Anfragen wende dich bitte an den Betreiber dieser Website/Anwendung." })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Wichtiger Hinweis" }), jsxRuntime.jsx("p", { className: "ai-chat-data-policy-warning", children: "Bitte gib keine besonderen Kategorien personenbezogener Daten (z.B. Gesundheitsdaten), Passw\u00F6rter, Kreditkarten-/Bankdaten oder vertrauliche Gesch\u00E4ftsgeheimnisse in den Chat ein. KI-generierte Antworten k\u00F6nnen unzutreffend sein und sollten vor einer Nutzung eigenverantwortlich gepr\u00FCft werden." })] })] }) }));
30742
+ return (jsxRuntime.jsx("div", { className: "ai-chat-data-policy-view", children: jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-content", children: [jsxRuntime.jsx("div", { className: "ai-chat-data-policy-intro", children: jsxRuntime.jsxs("p", { children: ["This privacy notice informs you pursuant to Art. 13 GDPR about how ", jsxRuntime.jsx("strong", { children: headerTitle }), " processes data when you use this chat. Please note that the specific scope of processing depends on the operator of this website/application (the controller) and on the respective activated functions."] }) }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Controller / Contact" }), jsxRuntime.jsx("p", { children: "The controller within the meaning of Art. 4 No. 7 GDPR is the operator of this website/application. The contact details (and, if applicable, the contact details of a data protection officer) can be found in the privacy policy or in the legal notice of the website into which this chat widget is embedded." })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Processed Data" }), jsxRuntime.jsxs("p", { children: ["The chat processes the following categories of data. ", jsxRuntime.jsx("strong", { children: "Chat Content" }), " comprises messages (text) and, if applicable, context information that you provide in the chat. This content is processed to generate responses and provide the conversation."] }), hasFileUpload && (jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "Uploaded Files" }), " that you transmit to the chat are processed to handle your request. Processing may include extracting text or information."] })), jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "Technical Usage Data" }), " includes timestamps, session or request information, as well as technical metadata required for operation, security (abuse prevention), and error analysis."] }), jsxRuntime.jsx("p", { children: "Please do not enter special categories of personal data (e.g., health data), passwords, credit card or bank data, or confidential business secrets in the chat. AI-generated responses may be inaccurate and should be checked independently before use." })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Purposes and Legal Bases" }), jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "Provision of the chat and answering of inquiries" }), " is based on Art. 6 Para. 1 lit. b GDPR, insofar as contractual or pre-contractual measures apply; otherwise on Art. 6 Para. 1 lit. f GDPR (legitimate interest in efficient communication and support)."] }), jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "Quality assurance, operation and security" }), " are based on Art. 6 Para. 1 lit. f GDPR, for example for stability, abuse detection, and troubleshooting."] }), jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "Consent-based processing" }), " may occur if the operator provides for this (Art. 6 Para. 1 lit. a GDPR)."] })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Recipients and Processors" }), jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "Hosting/IT Service Providers" }), " may be used by the operator for hosting, logging, monitoring, and infrastructure."] }), jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "AI Service Providers" }), " may receive chat content to generate responses. Where required, this is done on the basis of a data processing agreement (Art. 28 GDPR)."] }), jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "Third-Country Transfer" }), " may occur if recipients are located outside the EU/EEA. In this case, appropriate safeguards (e.g., EU Standard Contractual Clauses) are used where required."] })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Retention Period" }), persistsConversation ? (jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "Chat History" }), " may be stored to continue the conversation across multiple sessions."] })) : (jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "Chat History" }), " is not permanently stored and ends when the chat is closed."] })), hasFileUpload && (jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "Files" }), " are processed only as long as necessary to handle the request and are then deleted, unless longer retention is legally required."] })), jsxRuntime.jsxs("p", { children: [jsxRuntime.jsx("strong", { children: "Technical Logs" }), " may be stored for a limited period to ensure secure operation."] })] }), jsxRuntime.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntime.jsx("h3", { children: "Your Rights (Data Subject Rights)" }), jsxRuntime.jsx("p", { children: "You have the following rights under the GDPR: Right to Information (Art. 15), Right to Rectification (Art. 16), Right to Erasure (Art. 17) and Restriction of Processing (Art. 18), Right to Data Portability (Art. 20), Right to Objection to processing based on legitimate interests (Art. 21), and Right to Complain to a supervisory authority (Art. 77)." }), jsxRuntime.jsx("p", { children: "Note: Without clear identification features, the operator may not be able to assign individual chat histories to a person. For inquiries, please contact the operator of this website/application." })] })] }) }));
29879
30743
  };
29880
30744
 
29881
30745
  const MenuIcon = () => (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: "4", y1: "10", x2: "20", y2: "10" }), jsxRuntime.jsx("line", { x1: "10", y1: "14", x2: "20", y2: "14" })] }));
@@ -29883,17 +30747,19 @@ const PlusIcon = () => (jsxRuntime.jsxs("svg", { width: "22", height: "22", view
29883
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" })] }));
29884
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" })] }));
29885
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" })] }));
29886
- const ChatWindow = ({ messages, isLoading, isTyping, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick,
30750
+ const ChatWindow = ({ messages, isLoading, isTyping, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick, onActionDismiss, onCallEndpoint,
29887
30751
  // Chat history props (only active when persistConversation is true)
29888
30752
  conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
29889
30753
  // Override props for live preview
29890
- headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride, }) => {
30754
+ sizeOverride, headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride,
30755
+ // Demo mode
30756
+ onInputFocus, }) => {
29891
30757
  const appearance = config?.appearance;
29892
30758
  const settings = config?.settings;
29893
30759
  // Check if chat history should be shown (requires both persistConversation AND showChatHistory)
29894
30760
  const canShowHistory = (settings?.persistConversation ?? true) && (settings?.showChatHistory ?? true);
29895
30761
  // Apply overrides for live preview (overrides take priority over saved config)
29896
- const size = appearance?.size || 'medium';
30762
+ const size = sizeOverride ?? appearance?.size ?? 'medium';
29897
30763
  const headerTitle = headerTitleOverride ?? appearance?.headerTitle ?? 'AI Assistant';
29898
30764
  const welcomeTitle = welcomeTitleOverride ?? appearance?.welcomeTitle ?? '';
29899
30765
  const welcomeMessage = welcomeMessageOverride ?? appearance?.welcomeMessage ?? '';
@@ -29965,12 +30831,12 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
29965
30831
  // The backend will detect and trigger the action based on the message
29966
30832
  onSendMessage(question);
29967
30833
  };
29968
- return (jsxRuntime.jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsxRuntime.jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''} ${showDataPolicy ? 'is-data-policy' : ''}`, children: showDataPolicy ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { className: "ai-chat-header-button", onClick: handleDataPolicyBack, "aria-label": "Back to chat", children: jsxRuntime.jsx(BackIcon, {}) }), jsxRuntime.jsx("div", { className: "ai-chat-title", children: "Datenschutzhinweis" })] })) : showHistory ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "ai-chat-title", children: headerTitle }), jsxRuntime.jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsxRuntime.jsx(PlusIcon, {}) })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsxRuntime.jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsxRuntime.jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxRuntime.jsxs("div", { className: "ai-chat-header-actions", children: [canShowHistory && (jsxRuntime.jsx("button", { className: "ai-chat-header-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsxRuntime.jsx(MenuIcon, {}) })), jsxRuntime.jsx("button", { className: "ai-chat-close-button header-close-button", onClick: _onClose, "aria-label": "Close chat", children: jsxRuntime.jsx(CloseIcon, {}) })] })] })) }), showDataPolicy ? (jsxRuntime.jsx(DataPolicyView, { config: config, onBack: handleDataPolicyBack, widgetName: headerTitle })) : showHistory ? (
30834
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsxRuntime.jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''} ${showDataPolicy ? 'is-data-policy' : ''}`, children: showDataPolicy ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { className: "ai-chat-header-button", onClick: handleDataPolicyBack, "aria-label": "Back to chat", children: jsxRuntime.jsx(BackIcon, {}) }), jsxRuntime.jsx("div", { className: "ai-chat-title", children: "Privacy Notice" })] })) : showHistory ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "ai-chat-title", children: headerTitle }), jsxRuntime.jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsxRuntime.jsx(PlusIcon, {}) })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsxRuntime.jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsxRuntime.jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxRuntime.jsxs("div", { className: "ai-chat-header-actions", children: [canShowHistory && (jsxRuntime.jsx("button", { className: "ai-chat-header-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsxRuntime.jsx(MenuIcon, {}) })), jsxRuntime.jsx("button", { className: "ai-chat-close-button header-close-button", onClick: _onClose, "aria-label": "Close chat", children: jsxRuntime.jsx(CloseIcon, {}) })] })] })) }), showDataPolicy ? (jsxRuntime.jsx(DataPolicyView, { config: config, onBack: handleDataPolicyBack, widgetName: headerTitle })) : showHistory ? (
29969
30835
  /* History Panel */
29970
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) => {
29971
30837
  e.stopPropagation();
29972
30838
  onDeleteConversation(conv.id);
29973
- }, "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." })), (() => {
29974
30840
  console.log('[DEBUG ChatWindow] Rendering MessageList with', messages.length, 'messages');
29975
30841
  messages.forEach((m, i) => {
29976
30842
  console.log(`[DEBUG ChatWindow] msg ${i}:`, { role: m.message.role, hasAction: !!m.action, impl: m.action?.implementation });
@@ -29980,7 +30846,15 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
29980
30846
  console.log('[DEBUG ChatWindow] Testing renderer for query-contact-directory:', !!getActionRenderer('query-contact-directory'));
29981
30847
  }
29982
30848
  return null;
29983
- })(), 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, onFeedback: onFeedback, onScrollStateChange: handleScrollStateChange, getActionRenderer: getActionRenderer }), 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,
29984
30858
  };
29985
30859
 
29986
30860
  /**
@@ -30278,108 +31152,60 @@ function generateThemeStyles(appearance, theme) {
30278
31152
  return styles;
30279
31153
  }
30280
31154
 
30281
- /**
30282
- * Auto Theme Detector
30283
- * Detects whether the widget should use light or dark mode
30284
- * based on the background behind it
30285
- */
30286
- /**
30287
- * Sample the background color behind an element
30288
- * Uses multiple sampling points for accuracy
30289
- */
30290
- function sampleBackgroundColor(element) {
30291
- const rect = element.getBoundingClientRect();
30292
- const centerX = rect.left + rect.width / 2;
30293
- const centerY = rect.top + rect.height / 2;
30294
- // Try to get the element behind our widget
30295
- // Temporarily hide the element to sample what's behind
30296
- const originalVisibility = element.style.visibility;
30297
- element.style.visibility = 'hidden';
30298
- // Sample the center point
30299
- const elementBehind = document.elementFromPoint(centerX, centerY);
30300
- // Restore visibility
30301
- element.style.visibility = originalVisibility;
30302
- if (!elementBehind) {
30303
- return '#ffffff'; // Default to white
30304
- }
30305
- // Get computed background color
30306
- const computedStyle = window.getComputedStyle(elementBehind);
30307
- let bgColor = computedStyle.backgroundColor;
30308
- // If transparent, walk up the DOM tree
30309
- if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
30310
- let parent = elementBehind.parentElement;
30311
- while (parent) {
30312
- const parentStyle = window.getComputedStyle(parent);
30313
- bgColor = parentStyle.backgroundColor;
30314
- if (bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent') {
30315
- break;
30316
- }
30317
- parent = parent.parentElement;
30318
- }
30319
- }
30320
- // If still transparent, check body/html
30321
- if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
30322
- const bodyStyle = window.getComputedStyle(document.body);
30323
- bgColor = bodyStyle.backgroundColor;
30324
- if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
30325
- 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);
30326
31162
  }
30327
- }
30328
- return rgbaToHex(bgColor);
30329
- }
30330
- /**
30331
- * Convert rgba/rgb string to hex
30332
- */
30333
- function rgbaToHex(rgba) {
30334
- // Handle rgb(r, g, b) or rgba(r, g, b, a)
30335
- const match = rgba.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
30336
- if (!match)
30337
- return '#ffffff';
30338
- const r = parseInt(match[1]);
30339
- const g = parseInt(match[2]);
30340
- const b = parseInt(match[3]);
30341
- return '#' + [r, g, b].map(x => {
30342
- const hex = x.toString(16);
30343
- return hex.length === 1 ? '0' + hex : hex;
30344
- }).join('');
30345
- }
30346
- /**
30347
- * Determine if the background is dark
30348
- */
30349
- function isBackgroundDark(backgroundColor) {
30350
- const luminance = getLuminance(backgroundColor);
30351
- return luminance < 0.5;
30352
- }
30353
- /**
30354
- * Auto-detect theme based on background
30355
- */
30356
- function detectTheme(element) {
30357
- const bgColor = sampleBackgroundColor(element);
30358
- 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
+ };
30359
31202
  }
30360
- /**
30361
- * Create a MutationObserver to watch for theme changes
30362
- */
30363
- function createThemeObserver(element, callback) {
30364
- let lastTheme = detectTheme(element);
30365
- const observer = new MutationObserver(() => {
30366
- const theme = detectTheme(element);
30367
- if (theme !== lastTheme) {
30368
- lastTheme = theme;
30369
- callback(theme);
30370
- }
30371
- });
30372
- // Observe body for class/style changes (common for theme switching)
30373
- observer.observe(document.body, {
30374
- attributes: true,
30375
- attributeFilter: ['class', 'style', 'data-theme', 'data-bs-theme'],
30376
- });
30377
- // Also observe html element
30378
- observer.observe(document.documentElement, {
30379
- attributes: true,
30380
- attributeFilter: ['class', 'style', 'data-theme', 'data-bs-theme'],
30381
- });
30382
- 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" }) }) })] })) }))] }));
30383
31209
  }
30384
31210
 
30385
31211
  function styleInject(css, ref) {
@@ -30409,21 +31235,17 @@ function styleInject(css, ref) {
30409
31235
  }
30410
31236
  }
30411
31237
 
30412
- 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:opacity var(--duration-fast) ease;width:var(--button-size,56px);z-index:1}.ai-chat-button:hover{opacity:.9}.ai-chat-button:active{opacity:.8}.ai-chat-button-svg{height:50%;min-height:24px;min-width:24px;transition:transform var(--duration-fast) ease;width:50%}.ai-chat-button.is-open .ai-chat-button-svg{transform:rotate(0deg)}.ai-chat-button-icon{font-size:1.5em;line-height:1}.ai-chat-welcome-bubble{animation:ai-chat-bubble-fade-in .3s ease-out;background:var(--button-color,var(--btn-primary-bg,#07f));border:none;border-radius:12px;box-shadow:0 4px 12px rgba(0,0,0,.15);color:var(--button-icon-color,var(--btn-primary-text,#fff));cursor:pointer;font-size:14px;font-weight:500;line-height:1.4;padding:12px 16px;position:absolute;width:200px;z-index:0}.ai-chat-widget-container.bottom-right .ai-chat-welcome-bubble{bottom:68px;right:0;text-align:right}.ai-chat-widget-container.bottom-left .ai-chat-welcome-bubble{bottom:68px;left:0;right:auto;text-align:left}.ai-chat-widget-container.top-right .ai-chat-welcome-bubble{right:0;text-align:right;top:68px}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble{left:0;right:auto;text-align:left;top:68px}.ai-chat-welcome-bubble:hover{filter:brightness(1.1)}@keyframes ai-chat-bubble-fade-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble,.ai-chat-widget-container.top-right .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-down}@keyframes ai-chat-bubble-fade-in-down{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.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-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 ol,.ai-chat-message.assistant .ai-chat-message-content ul{margin:var(--space-sm) 0;padding-left:var(--space-lg)}.ai-chat-message.assistant .ai-chat-message-content li{margin-bottom:var(--space-xs)}.ai-chat-message.assistant .ai-chat-message-content code{background:rgba(0,0,0,.05);border-radius:var(--radius-sm);font-family:SF Mono,Monaco,Cascadia Code,monospace;font-size:.9em;padding:2px 6px}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content code{background:hsla(0,0%,100%,.1)}.ai-chat-message.assistant .ai-chat-message-content pre{background:rgba(0,0,0,.05);border-radius:var(--radius-md);margin:var(--space-sm) 0;overflow-x:auto;padding:var(--space-sm)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content pre{background:hsla(0,0%,100%,.05)}.ai-chat-message.assistant .ai-chat-message-content pre code{background:transparent;padding:0}.ai-chat-message.assistant .ai-chat-message-content a{color:var(--btn-primary-bg);text-decoration:underline}.ai-chat-message.assistant .ai-chat-message-content strong{font-weight:var(--font-weight-semibold)}.ai-chat-message.assistant .ai-chat-message-content blockquote{border-left:3px solid var(--border-default);color:var(--text-muted);margin:var(--space-sm) 0;padding-left:var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content hr{border:none;border-top:1px solid var(--border-subtle,rgba(0,0,0,.1));margin:var(--space-lg,24px) 0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content hr{border-top-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content .table-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-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{border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin-top:4px;padding-top:8px}.ai-chat-widget.dark .ai-chat-video-player__context,.chakra-ui-dark .ai-chat-video-player__context,.dark .ai-chat-video-player__context,[data-theme=dark] .ai-chat-video-player__context{border-color:hsla(0,0%,100%,.08)}.ai-chat-location-card{background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:12px;overflow:hidden;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}.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}";
30413
31239
  styleInject(css_248z$1);
30414
31240
 
30415
- 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{align-items:center;background:var(--bg-subtle,rgba(0,0,0,.02));border-radius:12px;display:flex;flex-direction:column;margin-bottom:20px;padding:16px;text-align:center}.ai-chat-widget.dark .ai-chat-data-policy-intro{background:var(--bg-subtle,hsla(0,0%,100%,.04))}.ai-chat-data-policy-icon{align-items:center;background:var(--primary-color,#07f);border-radius:12px;color:#fff;display:flex;height:48px;justify-content:center;margin-bottom:12px;width:48px}.ai-chat-data-policy-intro p{color:var(--text-secondary,#52525b);font-size:13px;line-height:1.5;margin:0}.ai-chat-widget.dark .ai-chat-data-policy-intro p{color:var(--text-secondary,#a1a1aa)}.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:13px;font-weight:600;letter-spacing:.02em;margin:0 0 8px;text-transform:uppercase}.ai-chat-widget.dark .ai-chat-data-policy-section h3{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section ul{list-style:none;margin:0;padding:0}.ai-chat-data-policy-section li{color:var(--text-secondary,#52525b);font-size:12px;line-height:1.5;padding:8px 0 8px 16px;position:relative}.ai-chat-widget.dark .ai-chat-data-policy-section li{color:var(--text-secondary,#a1a1aa)}.ai-chat-data-policy-section li:before{background:var(--text-muted,#a1a1aa);border-radius:50%;content:\"\";height:4px;left:0;position:absolute;top:14px;width:4px}.ai-chat-data-policy-section li strong{color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-data-policy-section li strong{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section p{color:var(--text-secondary,#52525b);font-size:12px;line-height:1.5;margin:0}.ai-chat-widget.dark .ai-chat-data-policy-section p{color:var(--text-secondary,#a1a1aa)}.ai-chat-data-policy-warning{background:rgba(234,179,8,.1);border:1px solid rgba(234,179,8,.3);border-radius:8px;color:#92400e!important;padding:12px}.ai-chat-widget.dark .ai-chat-data-policy-warning{background:rgba(234,179,8,.15);border-color:rgba(234,179,8,.25);color:#fbbf24!important}";
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)}";
30416
31242
  styleInject(css_248z);
30417
31243
 
30418
- // Icon components mapping
30419
- const iconComponents = {
30420
- 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" }) })),
30421
- 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" }) })),
30422
- };
30423
- const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = false, previewConfig, position = 'bottom-right', primaryColor, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, welcomeBubbleText, 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', }) => {
30424
31245
  const [isOpen, setIsOpen] = React.useState(defaultOpen);
30425
- const [autoDetectedTheme, setAutoDetectedTheme] = React.useState('light');
31246
+ const [inputBarValue, setInputBarValue] = React.useState('');
30426
31247
  const [showWelcomeBubble, setShowWelcomeBubble] = React.useState(false);
31248
+ const [isInputBarCollapsed, setIsInputBarCollapsed] = React.useState(false);
30427
31249
  const widgetRef = React.useRef(null);
30428
31250
  const containerRef = React.useRef(null);
30429
31251
  // Determine mode
@@ -30472,13 +31294,14 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30472
31294
  },
30473
31295
  };
30474
31296
  // Always call useChat hook (React rules), but skip initialization in preview mode
31297
+ const shouldSkipInit = previewMode;
30475
31298
  const chatHook = useChat({
30476
31299
  widgetId: previewMode ? '__preview__' : (widgetId || '__preview__'),
30477
31300
  apiUrl,
30478
31301
  currentRoute,
30479
- onMessage: previewMode ? undefined : onMessage,
30480
- onError: previewMode ? undefined : onError,
30481
- skipInitialization: previewMode, // Don't make API calls in preview mode
31302
+ onMessage: shouldSkipInit ? undefined : onMessage,
31303
+ onError: shouldSkipInit ? undefined : onError,
31304
+ skipInitialization: shouldSkipInit,
30482
31305
  });
30483
31306
  // Extract values from hook or use preview defaults
30484
31307
  const messages = previewMode ? [] : chatHook.messages;
@@ -30487,37 +31310,32 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30487
31310
  const config = previewMode ? mergedPreviewConfig : chatHook.config;
30488
31311
  const sendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
30489
31312
  const submitFeedback = previewMode ? (() => Promise.resolve()) : chatHook.submitFeedback;
31313
+ const dismissAction = previewMode ? (() => Promise.resolve()) : chatHook.dismissAction;
30490
31314
  const conversations = previewMode ? [] : chatHook.conversations;
30491
31315
  const loadConversations = previewMode ? (() => { }) : chatHook.loadConversations;
30492
31316
  const switchConversation = previewMode ? (() => Promise.resolve()) : chatHook.switchConversation;
30493
31317
  const startNewConversation = previewMode ? (() => { }) : chatHook.startNewConversation;
30494
31318
  const deleteConversation = previewMode ? (() => { }) : chatHook.deleteConversation;
30495
31319
  const conversationId = previewMode ? '' : chatHook.conversationId;
30496
- // Auto-detect theme from background
30497
- React.useEffect(() => {
30498
- if (!containerRef.current)
30499
- return;
30500
- // Initial detection
30501
- const detected = detectTheme(containerRef.current);
30502
- setAutoDetectedTheme(detected);
30503
- // Watch for theme changes on the page
30504
- const observer = createThemeObserver(containerRef.current, (newTheme) => {
30505
- setAutoDetectedTheme(newTheme);
30506
- });
30507
- // Also listen for system preference changes
30508
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
30509
- const handleMediaChange = () => {
30510
- if (containerRef.current) {
30511
- const detected = detectTheme(containerRef.current);
30512
- setAutoDetectedTheme(detected);
30513
- }
30514
- };
30515
- mediaQuery.addEventListener('change', handleMediaChange);
30516
- return () => {
30517
- observer.disconnect();
30518
- mediaQuery.removeEventListener('change', handleMediaChange);
30519
- };
30520
- }, [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
+ });
30521
31339
  // Check if device is mobile
30522
31340
  const isMobile = typeof window !== 'undefined' && window.innerWidth <= 480;
30523
31341
  // Handle auto-open (only for bubble mode, disabled on mobile)
@@ -30562,8 +31380,8 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30562
31380
  document.body.classList.remove('ai-chat-widget-open');
30563
31381
  };
30564
31382
  }, [isOpen, isEmbedded]);
30565
- // Handle welcome bubble visibility per session
30566
- // Shows on each new session if welcomeBubbleText is configured
31383
+ // Handle welcome bubble visibility based on frequency setting
31384
+ // Frequency options: 'always' (every page visit), 'session', 'weekly', 'monthly'
30567
31385
  React.useEffect(() => {
30568
31386
  if (isEmbedded || previewMode)
30569
31387
  return;
@@ -30572,42 +31390,72 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30572
31390
  setShowWelcomeBubble(false);
30573
31391
  return;
30574
31392
  }
30575
- // Check if bubble was already dismissed this session
31393
+ const frequency = config?.appearance?.welcomeBubbleFrequency ?? 'session';
30576
31394
  const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
30577
- const wasDismissed = sessionStorage.getItem(storageKey) === 'true';
30578
- if (!wasDismissed && !isOpen) {
31395
+ // Check if bubble should be shown based on frequency
31396
+ const shouldShowBubble = () => {
31397
+ if (frequency === 'always') {
31398
+ // Always show on every page visit (no storage check)
31399
+ return true;
31400
+ }
31401
+ if (frequency === 'session') {
31402
+ // Show once per session
31403
+ return sessionStorage.getItem(storageKey) !== 'true';
31404
+ }
31405
+ // For weekly/monthly, use localStorage with timestamp
31406
+ try {
31407
+ const stored = localStorage.getItem(storageKey);
31408
+ if (!stored)
31409
+ return true;
31410
+ const dismissedAt = parseInt(stored, 10);
31411
+ if (isNaN(dismissedAt))
31412
+ return true;
31413
+ const now = Date.now();
31414
+ const weekMs = 7 * 24 * 60 * 60 * 1000;
31415
+ const monthMs = 30 * 24 * 60 * 60 * 1000;
31416
+ if (frequency === 'weekly') {
31417
+ return now - dismissedAt > weekMs;
31418
+ }
31419
+ if (frequency === 'monthly') {
31420
+ return now - dismissedAt > monthMs;
31421
+ }
31422
+ }
31423
+ catch {
31424
+ return true;
31425
+ }
31426
+ return true;
31427
+ };
31428
+ if (shouldShowBubble() && !isOpen) {
30579
31429
  setShowWelcomeBubble(true);
30580
31430
  }
30581
31431
  }, [widgetId, welcomeBubbleText, config, isOpen, isEmbedded, previewMode]);
30582
- // Determine theme - use prop override if provided, otherwise auto-detect
30583
- const appearanceConfig = config?.appearance;
30584
- const effectiveTheme = theme ?? autoDetectedTheme;
30585
- // Determine position (prop override takes priority for live preview)
30586
- const effectivePosition = position || config?.appearance.position || 'bottom-right';
30587
- // Get accent color from prop or config (empty string means no accent color / vanilla mode)
30588
- const accentColor = primaryColor ?? appearanceConfig?.primaryColor ?? '';
30589
- // Apply prop overrides for live preview (props take priority over config)
30590
- size || appearanceConfig?.size || 'small';
30591
- const effectiveHeaderTitle = headerTitle ?? appearanceConfig?.headerTitle ?? '';
30592
- const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? '';
30593
- const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? '';
30594
- const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? '';
30595
- const effectiveWelcomeBubbleText = welcomeBubbleText ?? appearanceConfig?.welcomeBubbleText ?? '';
30596
- // Generate styles using simplified theme system
30597
- const simpleAppearance = {
30598
- accentColor};
30599
- // Generate theme styles from accent color
30600
- const generatedStyles = generateThemeStyles(simpleAppearance, effectiveTheme);
30601
- // Also apply legacy styles for backward compatibility
30602
- const legacyStyles = appearanceConfig
30603
- ? applyAppearanceStyles(appearanceConfig)
30604
- : {};
30605
- // Merge styles (generated takes priority for new simplified system, then custom overrides)
30606
- const mergedStyles = {
30607
- ...legacyStyles,
30608
- ...generatedStyles,
30609
- ...customStyles,
30610
- ...(zIndex !== undefined ? { '--widget-z-index': String(zIndex) } : {}),
31432
+ const handleStartNewConversation = React.useCallback(() => {
31433
+ startNewConversation();
31434
+ }, [startNewConversation]);
31435
+ const handleSendMessage = React.useCallback((content) => {
31436
+ sendMessage(content);
31437
+ }, [sendMessage]);
31438
+ // Dismiss bubble and store based on frequency setting
31439
+ const dismissBubble = () => {
31440
+ setShowWelcomeBubble(false);
31441
+ const frequency = config?.appearance?.welcomeBubbleFrequency ?? 'session';
31442
+ const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
31443
+ try {
31444
+ if (frequency === 'always') {
31445
+ // For 'always', use sessionStorage so it only hides until page refresh
31446
+ sessionStorage.setItem(storageKey, 'true');
31447
+ }
31448
+ else if (frequency === 'session') {
31449
+ sessionStorage.setItem(storageKey, 'true');
31450
+ }
31451
+ else {
31452
+ // For weekly/monthly, store timestamp in localStorage
31453
+ localStorage.setItem(storageKey, String(Date.now()));
31454
+ }
31455
+ }
31456
+ catch {
31457
+ // Ignore storage errors
31458
+ }
30611
31459
  };
30612
31460
  const handleToggle = () => {
30613
31461
  if (isEmbedded)
@@ -30616,15 +31464,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30616
31464
  setIsOpen(newState);
30617
31465
  // Dismiss welcome bubble when chat is opened
30618
31466
  if (newState && showWelcomeBubble) {
30619
- setShowWelcomeBubble(false);
30620
- // Store in sessionStorage so it doesn't show again this session
30621
- const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
30622
- try {
30623
- sessionStorage.setItem(storageKey, 'true');
30624
- }
30625
- catch {
30626
- // Ignore storage errors
30627
- }
31467
+ dismissBubble();
30628
31468
  }
30629
31469
  if (newState) {
30630
31470
  onOpen?.();
@@ -30633,6 +31473,24 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30633
31473
  onClose?.();
30634
31474
  }
30635
31475
  };
31476
+ const handleDismissBubble = (e) => {
31477
+ e.stopPropagation();
31478
+ dismissBubble();
31479
+ };
31480
+ // Handle input bar submit - opens widget and sends message
31481
+ const handleInputBarSubmit = React.useCallback((e) => {
31482
+ e.preventDefault();
31483
+ if (!inputBarValue.trim() || previewMode)
31484
+ return;
31485
+ // Open the widget
31486
+ setIsOpen(true);
31487
+ onOpen?.();
31488
+ // Send the message after a brief delay to allow widget to open
31489
+ setTimeout(() => {
31490
+ sendMessage(inputBarValue.trim());
31491
+ setInputBarValue('');
31492
+ }, 100);
31493
+ }, [inputBarValue, previewMode, onOpen, sendMessage]);
30636
31494
  const handleFeedback = async (messageId, feedback) => {
30637
31495
  await submitFeedback(messageId, feedback);
30638
31496
  };
@@ -30648,24 +31506,39 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
30648
31506
  sendMessage(actionInstruction);
30649
31507
  };
30650
31508
  // Don't render until config is loaded to avoid flash of unstyled content
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
30651
31513
  // In preview mode, config is always available
30652
- if (!config && !previewMode) {
31514
+ const hasInitialStyling = !!primaryColor;
31515
+ const canRenderWithoutConfig = !!triggerType || hasInitialStyling;
31516
+ if (!config && !previewMode && !canRenderWithoutConfig) {
30653
31517
  return null;
30654
31518
  }
30655
31519
  // Get button icon based on state
30656
31520
  const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
30657
31521
  // Embedded mode renders directly without wrapper positioning
30658
31522
  if (isEmbedded) {
30659
- 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, conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions }) }));
30660
- }
30661
- 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' : ''}`, children: [isOpen && (jsxRuntime.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback, onActionClick: handleActionClick,
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 }) }));
31524
+ }
31525
+ // Determine trigger class for container
31526
+ const triggerClass = effectiveTriggerType === 'pill-text'
31527
+ ? 'trigger-pill-text'
31528
+ : effectiveTriggerType === 'input-bar'
31529
+ ? 'trigger-input-bar'
31530
+ : 'trigger-button';
31531
+ // Size class for CSS targeting (used by input-bar trigger for width matching)
31532
+ const sizeClass = `size-${effectiveSize}`;
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,
30662
31536
  // Chat history props (only active when persistConversation is true)
30663
- conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId,
30664
- // Override props for live preview
30665
- headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), !isOpen && effectiveWelcomeBubbleText && (previewMode || showWelcomeBubble) && (jsxRuntime.jsx("div", { className: "ai-chat-welcome-bubble", onClick: handleToggle, children: jsxRuntime.jsx("span", { children: effectiveWelcomeBubbleText }) })), 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, {}) }) })] }) }));
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 })] }) }));
30666
31538
  };
30667
31539
 
30668
31540
  exports.ApiError = ApiError;
30669
31541
  exports.ChatWidget = ChatWidget;
31542
+ exports.DataPolicyView = DataPolicyView;
30670
31543
  exports.useChat = useChat;
30671
31544
  //# sourceMappingURL=index.js.map