@chatwidgetai/chat-widget 0.3.0 → 0.3.1

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 (35) hide show
  1. package/dist/ai-chat-widget.umd.js +1176 -400
  2. package/dist/ai-chat-widget.umd.js.map +1 -1
  3. package/dist/api/client.d.ts +2 -2
  4. package/dist/api/client.d.ts.map +1 -1
  5. package/dist/components/ChatWidget.d.ts +2 -1
  6. package/dist/components/ChatWidget.d.ts.map +1 -1
  7. package/dist/components/ChatWindow.d.ts +0 -1
  8. package/dist/components/ChatWindow.d.ts.map +1 -1
  9. package/dist/components/DataPolicyView.d.ts +14 -0
  10. package/dist/components/DataPolicyView.d.ts.map +1 -0
  11. package/dist/hooks/useChat/action-handler.d.ts +6 -0
  12. package/dist/hooks/useChat/action-handler.d.ts.map +1 -0
  13. package/dist/hooks/useChat/action-lifecycle.d.ts +19 -0
  14. package/dist/hooks/useChat/action-lifecycle.d.ts.map +1 -0
  15. package/dist/hooks/useChat/error-utils.d.ts +7 -0
  16. package/dist/hooks/useChat/error-utils.d.ts.map +1 -0
  17. package/dist/hooks/{useChat.d.ts → useChat/index.d.ts} +2 -2
  18. package/dist/hooks/useChat/index.d.ts.map +1 -0
  19. package/dist/hooks/useChat/message-hydration.d.ts +4 -0
  20. package/dist/hooks/useChat/message-hydration.d.ts.map +1 -0
  21. package/dist/hooks/useChat/stream-handlers.d.ts +27 -0
  22. package/dist/hooks/useChat/stream-handlers.d.ts.map +1 -0
  23. package/dist/hooks/useChat/stream-state.d.ts +8 -0
  24. package/dist/hooks/useChat/stream-state.d.ts.map +1 -0
  25. package/dist/hooks/useChat/types.d.ts +26 -0
  26. package/dist/hooks/useChat/types.d.ts.map +1 -0
  27. package/dist/index.esm.js +1176 -400
  28. package/dist/index.esm.js.map +1 -1
  29. package/dist/index.js +1176 -400
  30. package/dist/index.js.map +1 -1
  31. package/dist/types/index.d.ts +8 -0
  32. package/dist/types/index.d.ts.map +1 -1
  33. package/dist/utils/sse-parser.d.ts.map +1 -1
  34. package/package.json +7 -3
  35. package/dist/hooks/useChat.d.ts.map +0 -1
package/dist/index.esm.js CHANGED
@@ -8,11 +8,14 @@ async function* parseSSEStream(response, validator) {
8
8
  const reader = response.body.getReader();
9
9
  const decoder = new TextDecoder();
10
10
  let buffer = "";
11
+ let eventCount = 0;
11
12
  try {
12
13
  while (true) {
13
14
  const { done, value } = await reader.read();
14
- if (done)
15
+ if (done) {
16
+ console.log(`[SSE Parser] Stream ended normally after ${eventCount} events`);
15
17
  break;
18
+ }
16
19
  buffer += decoder.decode(value, { stream: true });
17
20
  const chunks = buffer.split("\n\n");
18
21
  buffer = chunks.pop() || "";
@@ -24,6 +27,7 @@ async function* parseSSEStream(response, validator) {
24
27
  const data = JSON.parse(line.slice(6));
25
28
  if (validator) {
26
29
  if (validator(data)) {
30
+ eventCount++;
27
31
  yield data;
28
32
  }
29
33
  else {
@@ -31,6 +35,7 @@ async function* parseSSEStream(response, validator) {
31
35
  }
32
36
  }
33
37
  else {
38
+ eventCount++;
34
39
  yield data;
35
40
  }
36
41
  }
@@ -43,6 +48,10 @@ async function* parseSSEStream(response, validator) {
43
48
  }
44
49
  }
45
50
  }
51
+ catch (error) {
52
+ console.error(`[SSE Parser] Stream error after ${eventCount} events:`, error);
53
+ throw error;
54
+ }
46
55
  finally {
47
56
  reader.releaseLock();
48
57
  }
@@ -176,7 +185,7 @@ class WidgetApiClient {
176
185
  const result = await response.json();
177
186
  return result.file;
178
187
  }
179
- async *sendAgentMessageStream(conversationId, message, fileIds) {
188
+ async *sendAgentMessageStream(conversationId, message, fileIds, signal) {
180
189
  const headers = {
181
190
  'Content-Type': 'application/json',
182
191
  };
@@ -192,6 +201,7 @@ class WidgetApiClient {
192
201
  fileIds,
193
202
  timeZone: this.getTimeZone(),
194
203
  }),
204
+ signal,
195
205
  });
196
206
  if (!response.ok) {
197
207
  throw await buildApiError(response, 'Failed to send agent message');
@@ -200,7 +210,7 @@ class WidgetApiClient {
200
210
  return typeof data === 'object' && data !== null && 'type' in data;
201
211
  });
202
212
  }
203
- async *continueAgentMessageStream(conversationId, toolCallId, state) {
213
+ async *continueAgentMessageStream(conversationId, toolCallId, state, signal) {
204
214
  const headers = {
205
215
  'Content-Type': 'application/json',
206
216
  };
@@ -216,6 +226,7 @@ class WidgetApiClient {
216
226
  state,
217
227
  timeZone: this.getTimeZone(),
218
228
  }),
229
+ signal,
219
230
  });
220
231
  if (!response.ok) {
221
232
  throw await buildApiError(response, 'Failed to continue agent');
@@ -27120,18 +27131,14 @@ const formatToolName = (name) => {
27120
27131
  .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
27121
27132
  .join(' ');
27122
27133
  };
27123
- const GearIcon = ({ spinning = false }) => (jsxs("svg", { className: `ai-chat-tool-gear ${spinning ? 'spinning' : ''}`, width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M12 20a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z" }), jsx("path", { d: "M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z" }), jsx("path", { d: "M12 2v2" }), jsx("path", { d: "M12 22v-2" }), jsx("path", { d: "m17 20.66-1-1.73" }), jsx("path", { d: "M11 10.27 7 3.34" }), jsx("path", { d: "m20.66 17-1.73-1" }), jsx("path", { d: "m3.34 7 1.73 1" }), jsx("path", { d: "M14 12h8" }), jsx("path", { d: "M2 12h2" }), jsx("path", { d: "m20.66 7-1.73 1" }), jsx("path", { d: "m3.34 17 1.73-1" }), jsx("path", { d: "m17 3.34-1 1.73" }), jsx("path", { d: "m11 13.73-4 6.93" })] }));
27124
- const CheckIcon$2 = () => (jsx("svg", { className: "ai-chat-tool-check", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "20 6 9 17 4 12" }) }));
27125
- const ErrorIcon = () => (jsx("svg", { className: "ai-chat-tool-error", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }));
27126
27134
  function ToolIndicator({ badges, className = '' }) {
27127
- const isAnyLoading = badges.some(b => b.status === 'loading');
27128
- return (jsxs("div", { className: `ai-chat-tool-row ${className}`, children: [jsx(GearIcon, { spinning: isAnyLoading }), jsx("div", { className: "ai-chat-tool-badges", children: badges.map((badge) => (jsxs("div", { className: `ai-chat-tool-badge ${badge.status}`, children: [badge.status !== 'loading' && (badge.status === 'error' ? jsx(ErrorIcon, {}) : jsx(CheckIcon$2, {})), jsx("span", { className: "tool-name", children: formatToolName(badge.name) })] }, badge.id))) })] }));
27135
+ return (jsx("div", { className: `ai-chat-tool-row ${className}`, children: jsx("div", { className: "ai-chat-tool-badges", children: badges.map((badge) => (jsx("div", { className: `ai-chat-tool-badge ${badge.status}`, children: jsx("span", { className: "tool-name", children: formatToolName(badge.name) }) }, badge.id))) }) }));
27129
27136
  }
27130
27137
 
27131
27138
  // SVG Icon components
27132
27139
  const ThumbsUpIcon = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3" }) }));
27133
27140
  const ThumbsDownIcon = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" }) }));
27134
- const CheckIcon$1 = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "20 6 9 17 4 12" }) }));
27141
+ const CheckIcon$2 = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "20 6 9 17 4 12" }) }));
27135
27142
  const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
27136
27143
  const [isSubmitting, setIsSubmitting] = useState(false);
27137
27144
  const [submitted, setSubmitted] = useState(false);
@@ -27152,10 +27159,10 @@ const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
27152
27159
  setIsSubmitting(false);
27153
27160
  }
27154
27161
  };
27155
- return (jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsx(ThumbsUpIcon, {}) }), jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'negative' ? 'active' : ''}`, onClick: () => handleFeedback('negative'), disabled: isDisabled, "aria-label": "Not helpful", title: "This was not helpful", children: jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsx("span", { className: "ai-chat-feedback-checkmark", children: jsx(CheckIcon$1, {}) }), jsx("span", { className: "ai-chat-feedback-text", children: "Thanks for feedback" })] }))] }));
27162
+ return (jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsx(ThumbsUpIcon, {}) }), jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'negative' ? 'active' : ''}`, onClick: () => handleFeedback('negative'), disabled: isDisabled, "aria-label": "Not helpful", title: "This was not helpful", children: jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsx("span", { className: "ai-chat-feedback-checkmark", children: jsx(CheckIcon$2, {}) }), jsx("span", { className: "ai-chat-feedback-text", children: "Thanks for feedback" })] }))] }));
27156
27163
  };
27157
27164
 
27158
- const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, getActionRenderer, accentColor, }) => {
27165
+ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, }) => {
27159
27166
  const formatTime = (timestamp) => {
27160
27167
  const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;
27161
27168
  return date.toLocaleTimeString('en-US', {
@@ -27175,15 +27182,15 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedb
27175
27182
  return null;
27176
27183
  }
27177
27184
  // AI message rendering
27185
+ // Note: Actions are rendered by ToolMessageGroup for tool messages, not here
27178
27186
  if (isAssistant) {
27179
27187
  const aiContent = message.message.content || '';
27180
27188
  const hasContent = aiContent.trim().length > 0;
27181
27189
  if (!hasContent)
27182
27190
  return null;
27183
- const actionRenderer = message.action && getActionRenderer
27184
- ? getActionRenderer(message.action.implementation)
27185
- : undefined;
27186
- return (jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsxs("div", { className: "ai-chat-message-content", children: [isError && (jsxs("div", { className: "ai-chat-error-indicator", children: [jsx("span", { className: "error-icon", children: "\u26A0\uFE0F" }), jsx("span", { className: "error-text", children: "Error" })] })), jsx(Markdown, { remarkPlugins: [remarkGfm], children: aiContent })] }), actionRenderer && message.action && actionRenderer(message, accentColor), showTimestamp && (jsxs("div", { className: "ai-chat-message-meta", children: [jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
27191
+ return (jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsx("div", { className: "ai-chat-message-content", children: jsx(Markdown, { remarkPlugins: [remarkGfm], components: {
27192
+ table: ({ children, ...props }) => (jsx("div", { className: "table-wrapper", children: jsx("div", { className: "table-scroll", children: jsx("table", { ...props, children: children }) }) })),
27193
+ }, children: aiContent }) }), showTimestamp && (jsxs("div", { className: "ai-chat-message-meta", children: [jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
27187
27194
  }
27188
27195
  // System message rendering
27189
27196
  if (isSystem) {
@@ -27197,35 +27204,85 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedb
27197
27204
  return null;
27198
27205
  };
27199
27206
 
27200
- const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor }) => {
27207
+ // Centralized action state logic
27208
+ function isActionComplete(state) {
27209
+ if (!state)
27210
+ return false;
27211
+ const TERMINAL_STATUSES = [
27212
+ 'completed', 'booked', 'scheduled', 'cancelled', 'failed', 'error',
27213
+ 'displaying', 'clicked', 'contacted', 'submitted', 'sent'
27214
+ ];
27215
+ const status = state.status;
27216
+ if (typeof status === 'string' && TERMINAL_STATUSES.includes(status)) {
27217
+ return true;
27218
+ }
27219
+ // For non-halting actions (query_contact_directory, etc.) with results/success
27220
+ if (!status && (state.success !== undefined || state.results !== undefined)) {
27221
+ return true;
27222
+ }
27223
+ return false;
27224
+ }
27225
+ function isActionLoading(message) {
27226
+ if (!message.action)
27227
+ return false;
27228
+ if (message.action.done)
27229
+ return false;
27230
+ if (message.isStreaming)
27231
+ return true;
27232
+ const state = message.action.state;
27233
+ return !isActionComplete(state);
27234
+ }
27235
+ const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant }) => {
27201
27236
  const actionMessages = messages.filter(message => message.action);
27237
+ // Debug logging
27238
+ console.log('[DEBUG ToolMessageGroup] ========================================');
27239
+ console.log('[DEBUG ToolMessageGroup] Total messages:', messages.length);
27240
+ console.log('[DEBUG ToolMessageGroup] Messages with action:', actionMessages.length);
27241
+ console.log('[DEBUG ToolMessageGroup] hasGetActionRenderer:', !!getActionRenderer);
27242
+ messages.forEach((msg, i) => {
27243
+ console.log(`[DEBUG ToolMessageGroup] Message ${i}:`, {
27244
+ id: msg.id,
27245
+ role: msg.message.role,
27246
+ hasAction: !!msg.action,
27247
+ actionImpl: msg.action?.implementation,
27248
+ toolExecuting: msg.toolExecuting,
27249
+ });
27250
+ });
27251
+ actionMessages.forEach((msg, i) => {
27252
+ const impl = msg.action?.implementation || '';
27253
+ const renderer = getActionRenderer?.(impl);
27254
+ console.log(`[DEBUG ToolMessageGroup] Action ${i}:`, {
27255
+ implementation: impl,
27256
+ hasRenderer: !!renderer,
27257
+ rendererType: renderer ? typeof renderer : 'undefined',
27258
+ state: msg.action?.state,
27259
+ });
27260
+ });
27202
27261
  // If tool indicator is hidden AND there are no action cards to render, don't render anything
27203
- // This prevents empty wrapper divs that cause layout jumping
27204
27262
  if (!showToolIndicator && actionMessages.length === 0) {
27205
27263
  return null;
27206
27264
  }
27207
27265
  const badges = messages.map((message) => {
27208
27266
  const toolName = message.toolExecuting || message.message.name || 'Tool';
27209
27267
  const hasError = message.isError || false;
27210
- const actionState = message.action?.state;
27211
- const actionStatus = actionState?.status;
27212
- const terminalStatuses = ['completed', 'booked', 'scheduled', 'failed', 'cancelled', 'displaying', 'clicked'];
27213
- const isTerminalStatus = actionStatus && terminalStatuses.includes(actionStatus);
27214
- const isDone = message.action ? (message.action.done ?? isTerminalStatus ?? false) : !message.isStreaming;
27215
- const isLoading = !isDone;
27268
+ const loading = isActionLoading(message);
27216
27269
  return {
27217
27270
  id: message.id,
27218
27271
  name: toolName,
27219
- status: isLoading ? 'loading' : hasError ? 'error' : 'completed',
27272
+ status: loading ? 'loading' : hasError ? 'error' : 'completed',
27220
27273
  };
27221
27274
  });
27222
27275
  return (jsxs("div", { className: "ai-chat-message tool", children: [showToolIndicator && jsx(ToolIndicator, { badges: badges }), actionMessages.map((message) => {
27223
- if (!message.action || !getActionRenderer)
27276
+ if (!message.action || !getActionRenderer) {
27277
+ console.log('[ToolMessageGroup] Skipping - no action or renderer:', { hasAction: !!message.action, hasGetRenderer: !!getActionRenderer });
27224
27278
  return null;
27279
+ }
27225
27280
  const renderer = getActionRenderer(message.action.implementation);
27226
- if (!renderer)
27281
+ if (!renderer) {
27282
+ console.log('[ToolMessageGroup] No renderer for:', message.action.implementation);
27227
27283
  return null;
27228
- return (jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor) }, `action-${message.id}`));
27284
+ }
27285
+ return (jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant) }, `action-${message.id}`));
27229
27286
  })] }));
27230
27287
  };
27231
27288
 
@@ -27287,12 +27344,16 @@ const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, acce
27287
27344
  };
27288
27345
 
27289
27346
  const MessageList = (props) => {
27290
- const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onFeedback, onScrollStateChange, getActionRenderer, } = props;
27347
+ const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onFeedback, onScrollStateChange, getActionRenderer, variant, } = props;
27291
27348
  const containerRef = useRef(null);
27292
27349
  const messagesEndRef = useRef(null);
27293
27350
  const [showScrollButton, setShowScrollButton] = useState(false);
27294
27351
  const prevMessageCountRef = useRef(0);
27295
- const hasActiveAction = useMemo(() => messages.some(msg => msg.action?.state?.status && !['completed', 'booked', 'failed'].includes(msg.action.state.status)), [messages]);
27352
+ const hasActiveAction = useMemo(() => {
27353
+ // Find the last tool message and check if its action is still active (not done)
27354
+ const lastToolMsg = [...messages].reverse().find(msg => msg.message.role === 'tool');
27355
+ return lastToolMsg?.action && lastToolMsg.action.done !== true;
27356
+ }, [messages]);
27296
27357
  const checkScrollPosition = useCallback(() => {
27297
27358
  const c = containerRef.current;
27298
27359
  if (!c)
@@ -27328,15 +27389,31 @@ const MessageList = (props) => {
27328
27389
  checkScrollPosition();
27329
27390
  }, [messages, isTyping, checkScrollPosition]);
27330
27391
  const groupedMessages = useMemo(() => {
27392
+ console.log('[DEBUG MessageList] ========================================');
27393
+ console.log('[DEBUG MessageList] Processing messages:', messages.length);
27394
+ messages.forEach((m, i) => {
27395
+ console.log(`[DEBUG MessageList] Message ${i}:`, {
27396
+ id: m.id,
27397
+ role: m.message.role,
27398
+ hasAction: !!m.action,
27399
+ actionImpl: m.action?.implementation,
27400
+ content: (m.message.content || '').substring(0, 50),
27401
+ });
27402
+ });
27331
27403
  const result = [];
27332
27404
  let toolGroup = [];
27333
- const flush = () => { if (toolGroup.length) {
27334
- result.push({ type: 'tool-group', messages: [...toolGroup] });
27335
- toolGroup = [];
27336
- } };
27405
+ const flush = () => {
27406
+ if (toolGroup.length) {
27407
+ console.log('[DEBUG MessageList] Flushing tool group with', toolGroup.length, 'messages');
27408
+ result.push({ type: 'tool-group', messages: [...toolGroup] });
27409
+ toolGroup = [];
27410
+ }
27411
+ };
27337
27412
  for (const m of messages) {
27338
- if (m.message.role === 'tool')
27413
+ if (m.message.role === 'tool') {
27414
+ console.log('[DEBUG MessageList] Adding to tool group:', m.id);
27339
27415
  toolGroup.push(m);
27416
+ }
27340
27417
  else if (m.message.role === 'user') {
27341
27418
  flush();
27342
27419
  result.push({ type: 'message', message: m });
@@ -27348,6 +27425,7 @@ const MessageList = (props) => {
27348
27425
  flush();
27349
27426
  result.push({ type: 'message', message: m });
27350
27427
  }
27428
+ // Don't flush on empty assistant messages - let tools continue grouping
27351
27429
  }
27352
27430
  else {
27353
27431
  flush();
@@ -27355,13 +27433,22 @@ const MessageList = (props) => {
27355
27433
  }
27356
27434
  }
27357
27435
  flush();
27436
+ console.log('[DEBUG MessageList] Final grouped result:', result.length, 'items');
27437
+ result.forEach((item, i) => {
27438
+ if (item.type === 'tool-group') {
27439
+ console.log(`[DEBUG MessageList] Group ${i}: tool-group with ${item.messages.length} messages`);
27440
+ }
27441
+ else {
27442
+ console.log(`[DEBUG MessageList] Group ${i}: message (${item.message.message.role})`);
27443
+ }
27444
+ });
27358
27445
  return result;
27359
27446
  }, [messages]);
27360
27447
  const hasSuggestions = messages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
27361
27448
  const showWelcome = welcomeTitle || welcomeMessage || hasSuggestions;
27362
27449
  return (jsxs("div", { ref: containerRef, className: "ai-chat-messages", role: "log", "aria-live": "polite", children: [showWelcome && (jsxs("div", { className: "ai-chat-welcome", children: [welcomeTitle && jsx("div", { className: "ai-chat-welcome-title", children: welcomeTitle }), welcomeMessage && jsx("div", { className: "ai-chat-welcome-text", children: welcomeMessage }), hasSuggestions && jsx(SuggestedQuestions, { questions: suggestedQuestions, onQuestionClick: onSuggestedQuestionClick })] })), groupedMessages.map((item, i) => {
27363
27450
  if (item.type === 'tool-group') {
27364
- return jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor }, `tg-${i}`);
27451
+ return jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant }, `tg-${i}`);
27365
27452
  }
27366
27453
  const isLast = i === groupedMessages.length - 1;
27367
27454
  const hasFollowUp = item.message.message.role === 'assistant' && item.message.suggestions?.length && isLast && !isTyping;
@@ -27380,7 +27467,7 @@ const formatFileSize = (bytes) => {
27380
27467
  return (bytes / 1024).toFixed(1) + ' KB';
27381
27468
  return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
27382
27469
  };
27383
- const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, }) => {
27470
+ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, showDataPolicy = true, onDataPolicyClick, }) => {
27384
27471
  const [value, setValue] = useState('');
27385
27472
  const [selectedFiles, setSelectedFiles] = useState([]);
27386
27473
  const textareaRef = useRef(null);
@@ -27415,10 +27502,10 @@ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled =
27415
27502
  }
27416
27503
  };
27417
27504
  const canSend = value.trim() || selectedFiles.length > 0;
27418
- return (jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxs("div", { className: "ai-chat-file-item", children: [jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxs("div", { className: "ai-chat-file-info", children: [jsx("span", { className: "ai-chat-file-name", children: file.name }), jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxs(Fragment, { children: [jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) }) })] })), jsx("textarea", { ref: textareaRef, className: "ai-chat-input", value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 2, wrap: "soft", "aria-label": "Message input" }), jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsx("path", { d: "M12 19V5" }), jsx("path", { d: "M5 12l7-7 7 7" })] }) })] })] }));
27505
+ return (jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxs("div", { className: "ai-chat-file-item", children: [jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxs("div", { className: "ai-chat-file-info", children: [jsx("span", { className: "ai-chat-file-name", children: file.name }), jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxs(Fragment, { children: [jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) }) })] })), jsx("textarea", { ref: textareaRef, className: "ai-chat-input", value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 2, wrap: "soft", "aria-label": "Message input" }), jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsx("path", { d: "M12 19V5" }), jsx("path", { d: "M5 12l7-7 7 7" })] }) })] }), showDataPolicy && (jsxs("div", { className: "ai-chat-data-policy", children: [jsx("span", { children: "KI-generierte Antworten k\u00F6nnen unzutreffend sein." }), onDataPolicyClick && (jsxs(Fragment, { children: [' ', jsx("button", { type: "button", className: "ai-chat-data-policy-link", onClick: onDataPolicyClick, children: "Datenschutzhinweis" })] }))] }))] }));
27419
27506
  };
27420
27507
 
27421
- function groupSlotsByDate(slots) {
27508
+ function groupSlotsByDate$1(slots) {
27422
27509
  const grouped = new Map();
27423
27510
  for (const slot of slots) {
27424
27511
  if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
@@ -27432,7 +27519,7 @@ function groupSlotsByDate(slots) {
27432
27519
  }
27433
27520
  return grouped;
27434
27521
  }
27435
- function formatDate(dateStr) {
27522
+ function formatDate$1(dateStr) {
27436
27523
  try {
27437
27524
  const date = new Date(dateStr);
27438
27525
  return new Intl.DateTimeFormat("en-US", {
@@ -27445,16 +27532,16 @@ function formatDate(dateStr) {
27445
27532
  return dateStr;
27446
27533
  }
27447
27534
  }
27448
- function CalendarIcon() {
27535
+ function CalendarIcon$1() {
27449
27536
  return (jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsx("path", { fillRule: "evenodd", d: "M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z", clipRule: "evenodd" }) }));
27450
27537
  }
27451
- function CheckIcon() {
27538
+ function CheckIcon$1() {
27452
27539
  return (jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }));
27453
27540
  }
27454
- function ExternalLinkIcon$1() {
27541
+ function ExternalLinkIcon$2() {
27455
27542
  return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsx("polyline", { points: "15 3 21 3 21 9" }), jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
27456
27543
  }
27457
- function Skeleton({ width, height, borderRadius = '4px' }) {
27544
+ function Skeleton$1({ width, height, borderRadius = '4px' }) {
27458
27545
  return (jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
27459
27546
  }
27460
27547
  function GoogleCalendarCard({ action, onComplete, accentColor, className = '' }) {
@@ -27471,13 +27558,12 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
27471
27558
  : [];
27472
27559
  const allowTopic = state.allowTopic !== false;
27473
27560
  const isBooked = state.status === "booked";
27474
- const slotsByDate = groupSlotsByDate(availableSlots);
27561
+ const slotsByDate = groupSlotsByDate$1(availableSlots);
27475
27562
  const dates = Array.from(slotsByDate.keys()).sort();
27476
27563
  const [selectedDate, setSelectedDate] = useState(dates[0] ?? "");
27477
27564
  const [selectedSlot, setSelectedSlot] = useState(null);
27478
27565
  const [topic, setTopic] = useState("");
27479
27566
  const [error, setError] = useState(null);
27480
- const [isSubmitting, setIsSubmitting] = useState(false);
27481
27567
  const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
27482
27568
  const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
27483
27569
  const onConfirm = () => {
@@ -27490,8 +27576,245 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
27490
27576
  return;
27491
27577
  }
27492
27578
  setError(null);
27579
+ onComplete?.(action.toolCallId, {
27580
+ ...action.state,
27581
+ selectedSlot: {
27582
+ startTime: selectedSlot.startTime,
27583
+ endTime: selectedSlot.endTime,
27584
+ },
27585
+ topic: allowTopic ? topic.trim() : null,
27586
+ });
27587
+ };
27588
+ // Booked state
27589
+ if (isBooked) {
27590
+ const bookedSlot = state.selectedSlot;
27591
+ const bookedTopic = state.topic;
27592
+ const eventLink = state.bookedEventLink;
27593
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsx(CheckIcon$1, {}) }), "Appointment Confirmed"] }), jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), eventLink && (jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Google Calendar", jsx(ExternalLinkIcon$2, {})] }))] })] }));
27594
+ }
27595
+ // Skeleton loading state - show when waiting for backend after user confirms
27596
+ const isWaitingForBackend = !action.done && state.selectedSlot && !isBooked;
27597
+ if (isWaitingForBackend) {
27598
+ return (jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsx(Skeleton$1, { width: "28px", height: "28px", borderRadius: "50%" }), jsx(Skeleton$1, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton$1, { width: "60px", height: "12px", borderRadius: "4px" }), jsx(Skeleton$1, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton$1, { width: "50px", height: "12px", borderRadius: "4px" }), jsx(Skeleton$1, { width: "200px", height: "18px", borderRadius: "4px" })] }), jsx(Skeleton$1, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
27599
+ }
27600
+ // Booking form
27601
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-google-calendar ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon$1, {}), "Schedule an Appointment"] }), jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsx("input", { id: `topic-${action.toolCallId}`, type: "text", className: "ai-chat-action-input", placeholder: "e.g., Product Demo", value: topic, onChange: (e) => setTopic(e.target.value) })] })), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
27602
+ setSelectedDate(date);
27603
+ setSelectedSlot(null);
27604
+ }, children: formatDate$1(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsx("button", { type: "button", className: `ai-chat-action-time-btn ${selectedSlot?.startTime === slot.startTime ? "active" : ""}`, onClick: () => setSelectedSlot(slot), children: slot.displayTime || new Date(slot.startTime).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }, slot.startTime))) })] })), error && jsx("div", { className: "ai-chat-action-error", children: error }), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: onConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
27605
+ }
27606
+
27607
+ function groupSlotsByDate(slots) {
27608
+ const grouped = new Map();
27609
+ for (const slot of slots) {
27610
+ if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
27611
+ continue;
27612
+ }
27613
+ const date = slot.startTime.slice(0, 10);
27614
+ if (!grouped.has(date)) {
27615
+ grouped.set(date, []);
27616
+ }
27617
+ grouped.get(date).push(slot);
27618
+ }
27619
+ return grouped;
27620
+ }
27621
+ function formatDate(dateStr) {
27622
+ try {
27623
+ const date = new Date(dateStr);
27624
+ return new Intl.DateTimeFormat("en-US", {
27625
+ weekday: "short",
27626
+ month: "short",
27627
+ day: "numeric",
27628
+ }).format(date);
27629
+ }
27630
+ catch {
27631
+ return dateStr;
27632
+ }
27633
+ }
27634
+ function CalendarIcon() {
27635
+ return (jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsx("path", { fillRule: "evenodd", d: "M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z", clipRule: "evenodd" }) }));
27636
+ }
27637
+ function MailIcon() {
27638
+ return (jsxs("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: [jsx("path", { d: "M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z" }), jsx("path", { d: "M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z" })] }));
27639
+ }
27640
+ function CheckIcon() {
27641
+ return (jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }));
27642
+ }
27643
+ function ErrorIcon() {
27644
+ return (jsx("svg", { className: "ai-chat-action-icon-error", viewBox: "0 0 20 20", fill: "currentColor", children: jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }) }));
27645
+ }
27646
+ function ExternalLinkIcon$1() {
27647
+ return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsx("polyline", { points: "15 3 21 3 21 9" }), jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
27648
+ }
27649
+ function Skeleton({ width, height, borderRadius = '4px' }) {
27650
+ return (jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
27651
+ }
27652
+ function PinInputGroup({ values, onChange, disabled }) {
27653
+ const inputRefs = useRef([]);
27654
+ const handleChange = (index, value) => {
27655
+ // Only allow digits
27656
+ const digit = value.replace(/[^0-9]/g, '');
27657
+ const newValues = [...values];
27658
+ newValues[index] = digit.slice(-1);
27659
+ onChange(newValues);
27660
+ // Auto-focus next input
27661
+ if (digit && index < 5) {
27662
+ inputRefs.current[index + 1]?.focus();
27663
+ }
27664
+ };
27665
+ const handleKeyDown = (index, e) => {
27666
+ if (e.key === 'Backspace' && !values[index] && index > 0) {
27667
+ inputRefs.current[index - 1]?.focus();
27668
+ }
27669
+ };
27670
+ const handlePaste = (e) => {
27671
+ e.preventDefault();
27672
+ const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, 6);
27673
+ const newValues = pastedData.split('').concat(Array(6 - pastedData.length).fill(''));
27674
+ onChange(newValues);
27675
+ // Focus the next empty input or the last one
27676
+ const nextIndex = Math.min(pastedData.length, 5);
27677
+ inputRefs.current[nextIndex]?.focus();
27678
+ };
27679
+ return (jsx("div", { className: "ai-chat-pin-input-group", children: values.map((value, index) => (jsx("input", { ref: (el) => {
27680
+ inputRefs.current[index] = el;
27681
+ }, 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))) }));
27682
+ }
27683
+ function MicrosoftCalendarCard({ action, onComplete, accentColor, className = '' }) {
27684
+ const state = action.state;
27685
+ const phase = state.phase || "awaiting_email";
27686
+ const allowTopic = state.allowTopic !== false;
27687
+ const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
27688
+ // Debug: Log state changes
27689
+ const prevStateRef = useRef(null);
27690
+ useEffect(() => {
27691
+ if (JSON.stringify(prevStateRef.current) !== JSON.stringify(state)) {
27692
+ console.log('[MicrosoftCalendarCard] State updated:', {
27693
+ phase: state.phase,
27694
+ hasError: !!state.errorMessage,
27695
+ error: state.errorMessage,
27696
+ slotsCount: state.availableSlots?.length || 0
27697
+ });
27698
+ prevStateRef.current = state;
27699
+ }
27700
+ }, [state]);
27701
+ // Email phase state
27702
+ const [email, setEmail] = useState("");
27703
+ const [emailError, setEmailError] = useState(null);
27704
+ // OTP phase state
27705
+ const [otpValues, setOtpValues] = useState(Array(6).fill(''));
27706
+ const [otpError, setOtpError] = useState(null);
27707
+ // Loading states
27708
+ const [isSubmitting, setIsSubmitting] = useState(false);
27709
+ // Reset loading state when phase changes (backend has responded)
27710
+ // Use useEffect for reliable re-rendering
27711
+ useEffect(() => {
27712
+ console.log('[MicrosoftCalendarCard] Phase changed to:', phase);
27713
+ setIsSubmitting(false);
27714
+ // Clear errors when transitioning to new phase
27715
+ if (phase === "awaiting_email") {
27716
+ setEmailError(null);
27717
+ setOtpError(null);
27718
+ setSelectionError(null);
27719
+ }
27720
+ else if (phase === "awaiting_otp") {
27721
+ setOtpError(state.errorMessage || null);
27722
+ setEmailError(null);
27723
+ setSelectionError(null);
27724
+ // Clear OTP input for fresh attempt
27725
+ setOtpValues(Array(6).fill(''));
27726
+ }
27727
+ else if (phase === "awaiting_options") {
27728
+ setEmailError(null);
27729
+ setOtpError(null);
27730
+ setSelectionError(null);
27731
+ }
27732
+ else if (phase === "awaiting_booking") {
27733
+ setSelectionError(state.errorMessage || null);
27734
+ setEmailError(null);
27735
+ setOtpError(null);
27736
+ }
27737
+ else if (phase === "booked" || phase === "cancelled" || phase === "error") {
27738
+ setEmailError(null);
27739
+ setOtpError(null);
27740
+ setSelectionError(null);
27741
+ setSelectedId(null); // Reset selection
27742
+ }
27743
+ }, [phase, state.errorMessage]);
27744
+ // Selection phase state
27745
+ const rawSlots = state.availableSlots;
27746
+ const availableSlots = Array.isArray(rawSlots)
27747
+ ? rawSlots.filter((slot) => slot !== null &&
27748
+ slot !== undefined &&
27749
+ typeof slot === "object" &&
27750
+ "startTime" in slot &&
27751
+ "endTime" in slot &&
27752
+ typeof slot.startTime === "string" &&
27753
+ typeof slot.endTime === "string")
27754
+ : [];
27755
+ const slotsByDate = groupSlotsByDate(availableSlots);
27756
+ const dates = Array.from(slotsByDate.keys()).sort();
27757
+ const [selectedDate, setSelectedDate] = useState(dates[0] ?? "");
27758
+ const [selectedSlot, setSelectedSlot] = useState(null);
27759
+ const [topic, setTopic] = useState("");
27760
+ const [selectionError, setSelectionError] = useState(null);
27761
+ // Cancellation phase state
27762
+ const [selectedId, setSelectedId] = useState(null);
27763
+ const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
27764
+ // Phase 1: Email Input
27765
+ const handleEmailSubmit = () => {
27766
+ const trimmedEmail = email.trim();
27767
+ if (!trimmedEmail) {
27768
+ setEmailError("Please enter your email address");
27769
+ return;
27770
+ }
27771
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmedEmail)) {
27772
+ setEmailError("Please enter a valid email address");
27773
+ return;
27774
+ }
27775
+ setEmailError(null);
27776
+ setIsSubmitting(true);
27777
+ console.log('[MicrosoftCalendarCard] Submitting email:', trimmedEmail);
27778
+ setTimeout(() => {
27779
+ onComplete?.(action.toolCallId, {
27780
+ ...action.state,
27781
+ email: trimmedEmail,
27782
+ });
27783
+ }, 50);
27784
+ };
27785
+ // Phase 2: OTP Verification
27786
+ const handleOtpSubmit = () => {
27787
+ const otpCode = otpValues.join('');
27788
+ if (otpCode.length !== 6) {
27789
+ setOtpError("Please enter the 6-digit code");
27790
+ return;
27791
+ }
27792
+ setOtpError(null);
27793
+ setIsSubmitting(true);
27794
+ console.log('[MicrosoftCalendarCard] Submitting OTP code');
27795
+ setTimeout(() => {
27796
+ onComplete?.(action.toolCallId, {
27797
+ ...action.state,
27798
+ otpCode,
27799
+ });
27800
+ }, 50);
27801
+ };
27802
+ // Phase 3: Appointment Selection
27803
+ const handleAppointmentConfirm = () => {
27804
+ if (!selectedSlot) {
27805
+ setSelectionError("Please select a time slot");
27806
+ return;
27807
+ }
27808
+ if (allowTopic && !topic.trim()) {
27809
+ setSelectionError("Please enter a meeting topic");
27810
+ return;
27811
+ }
27812
+ setSelectionError(null);
27493
27813
  setIsSubmitting(true);
27494
- // Small delay to ensure UI updates
27814
+ console.log('[MicrosoftCalendarCard] Confirming appointment:', {
27815
+ slot: selectedSlot,
27816
+ topic: topic.trim()
27817
+ });
27495
27818
  setTimeout(() => {
27496
27819
  onComplete?.(action.toolCallId, {
27497
27820
  ...action.state,
@@ -27503,22 +27826,149 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
27503
27826
  });
27504
27827
  }, 50);
27505
27828
  };
27506
- // Booked state
27507
- if (isBooked) {
27829
+ // Handle "Use different email" button
27830
+ const handleUseDifferentEmail = () => {
27831
+ setEmail("");
27832
+ setEmailError(null);
27833
+ setOtpValues(Array(6).fill(''));
27834
+ setOtpError(null);
27835
+ onComplete?.(action.toolCallId, {
27836
+ phase: "awaiting_email",
27837
+ email: null,
27838
+ otpVerified: false,
27839
+ otpAttempts: 0,
27840
+ availableSlots: [],
27841
+ selectedSlot: null,
27842
+ topic: null,
27843
+ bookedEventId: null,
27844
+ bookedEventLink: null,
27845
+ allowTopic,
27846
+ errorMessage: null,
27847
+ });
27848
+ };
27849
+ // Phase 5: Booked Confirmation
27850
+ if (phase === "booked") {
27508
27851
  const bookedSlot = state.selectedSlot;
27509
27852
  const bookedTopic = state.topic;
27510
27853
  const eventLink = state.bookedEventLink;
27511
- return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsx(CheckIcon, {}) }), "Appointment Confirmed"] }), jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), eventLink && (jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Google Calendar", jsx(ExternalLinkIcon$1, {})] }))] })] }));
27512
- }
27513
- // Skeleton loading state
27854
+ const bookedEmail = state.email;
27855
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsx(CheckIcon, {}) }), "Appointment Confirmed"] }), jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), bookedEmail && (jsxs("div", { className: "ai-chat-action-hint", children: ["A calendar invitation has been sent to ", bookedEmail] })), eventLink && (jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Outlook Calendar", jsx(ExternalLinkIcon$1, {})] }))] })] }));
27856
+ }
27857
+ // Phase 6: Cancelled Confirmation
27858
+ if (phase === "cancelled") {
27859
+ const cancelledSubject = state.cancelledEventSubject;
27860
+ const userEmail = state.email;
27861
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsx(CheckIcon, {}) }), "Appointment Cancelled"] }), jsxs("div", { className: "ai-chat-action-body", children: [cancelledSubject && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "CANCELLED" }), jsx("span", { className: "ai-chat-action-value-large", children: cancelledSubject })] })), userEmail && (jsxs("div", { className: "ai-chat-action-hint", children: ["A cancellation notice has been sent to ", userEmail] }))] })] }));
27862
+ }
27863
+ // Error State
27864
+ if (phase === "error") {
27865
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-error ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(ErrorIcon, {}), "Error"] }), jsxs("div", { className: "ai-chat-action-body", children: [jsx("div", { className: "ai-chat-action-error-message", children: state.errorMessage || "An error occurred. Please try again." }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
27866
+ setEmail("");
27867
+ setEmailError(null);
27868
+ setOtpValues(Array(6).fill(''));
27869
+ setOtpError(null);
27870
+ onComplete?.(action.toolCallId, {
27871
+ phase: "awaiting_email",
27872
+ email: null,
27873
+ otpVerified: false,
27874
+ otpAttempts: 0,
27875
+ availableSlots: [],
27876
+ selectedSlot: null,
27877
+ topic: null,
27878
+ bookedEventId: null,
27879
+ bookedEventLink: null,
27880
+ allowTopic,
27881
+ errorMessage: null,
27882
+ });
27883
+ }, children: "Start Over" })] })] }));
27884
+ }
27885
+ // Loading State
27514
27886
  if (isSubmitting) {
27515
- return (jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton, { width: "50px", height: "12px", borderRadius: "4px" }), jsx(Skeleton, { width: "200px", height: "18px", borderRadius: "4px" })] }), jsx(Skeleton, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
27516
- }
27517
- // Booking form
27518
- return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Schedule an Appointment"] }), jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsx("input", { id: `topic-${action.toolCallId}`, type: "text", className: "ai-chat-action-input", placeholder: "e.g., Product Demo", value: topic, onChange: (e) => setTopic(e.target.value) })] })), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
27519
- setSelectedDate(date);
27520
- setSelectedSlot(null);
27521
- }, children: formatDate(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsx("button", { type: "button", className: `ai-chat-action-time-btn ${selectedSlot?.startTime === slot.startTime ? "active" : ""}`, onClick: () => setSelectedSlot(slot), children: slot.displayTime || new Date(slot.startTime).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }, slot.startTime))) })] })), error && jsx("div", { className: "ai-chat-action-error", children: error }), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: onConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
27887
+ return (jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsx(Skeleton, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
27888
+ }
27889
+ // Phase 1: Email Input
27890
+ if (phase === "awaiting_email") {
27891
+ const displayError = state.errorMessage || emailError;
27892
+ return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Schedule an Appointment"] }), jsxs("div", { className: "ai-chat-action-body", children: [jsx("div", { className: "ai-chat-action-hint", children: "We'll send a verification code to your email" }), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `email-${action.toolCallId}`, className: "ai-chat-action-label", children: "Email Address" }), jsx("input", { id: `email-${action.toolCallId}`, type: "email", className: "ai-chat-action-input", placeholder: "your@email.com", value: email, onChange: (e) => {
27893
+ setEmail(e.target.value);
27894
+ setEmailError(null);
27895
+ }, onKeyPress: (e) => {
27896
+ if (e.key === 'Enter') {
27897
+ handleEmailSubmit();
27898
+ }
27899
+ }, autoFocus: true })] }), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleEmailSubmit, children: "Continue" })] })] }));
27900
+ }
27901
+ // Phase 2: OTP Input
27902
+ if (phase === "awaiting_otp") {
27903
+ const displayError = state.errorMessage || otpError;
27904
+ const userEmail = state.email;
27905
+ return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(MailIcon, {}), "Verify Your Email"] }), jsxs("div", { className: "ai-chat-action-body", children: [jsxs("div", { className: "ai-chat-action-hint", children: ["We sent a 6-digit code to ", jsx("strong", { children: userEmail })] }), jsx(PinInputGroup, { values: otpValues, onChange: (newValues) => {
27906
+ setOtpValues(newValues);
27907
+ setOtpError(null);
27908
+ // Auto-submit when all 6 digits are entered
27909
+ if (newValues.every(v => v.length === 1)) {
27910
+ console.log('[MicrosoftCalendarCard] Auto-submitting OTP (all 6 digits entered)');
27911
+ setIsSubmitting(true);
27912
+ const code = newValues.join('');
27913
+ setTimeout(() => {
27914
+ onComplete?.(action.toolCallId, {
27915
+ ...action.state,
27916
+ otpCode: code,
27917
+ });
27918
+ }, 100);
27919
+ }
27920
+ }, disabled: isSubmitting }), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleOtpSubmit, disabled: otpValues.join('').length !== 6, children: "Verify Code" }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: handleUseDifferentEmail, children: "Use different email" })] })] }));
27921
+ }
27922
+ // Phase 3: Options Menu (with inline cancel buttons and confirmation)
27923
+ if (phase === "awaiting_options") {
27924
+ const userAppointments = state.userAppointments || [];
27925
+ const maxAppointments = state.maxAppointmentsPerUser || 3;
27926
+ const appointmentCount = userAppointments.length;
27927
+ const canBook = appointmentCount < maxAppointments;
27928
+ const hasAppointments = appointmentCount > 0;
27929
+ const displayError = state.errorMessage || selectionError;
27930
+ // If confirming cancellation, show confirmation dialog
27931
+ if (selectedId) {
27932
+ const appointmentToCancel = userAppointments.find(appt => appt.id === selectedId);
27933
+ if (!appointmentToCancel) {
27934
+ setSelectedId(null); // Reset if appointment not found
27935
+ }
27936
+ else {
27937
+ return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Confirm Cancellation"] }), jsxs("div", { className: "ai-chat-action-body", children: [jsx("div", { className: "ai-chat-action-hint", children: "Are you sure you want to cancel this appointment?" }), jsx("div", { className: "ai-chat-action-appointment-item", style: { marginBottom: '16px' }, children: jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsx("div", { className: "ai-chat-action-appointment-subject", children: appointmentToCancel.subject }), jsx("div", { className: "ai-chat-action-appointment-time", children: appointmentToCancel.displayTime })] }) }), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxs("div", { className: "ai-chat-action-button-group", children: [jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
27938
+ setIsSubmitting(true);
27939
+ onComplete?.(action.toolCallId, {
27940
+ ...action.state,
27941
+ selectedOption: "cancel",
27942
+ selectedAppointmentId: selectedId,
27943
+ });
27944
+ }, disabled: isSubmitting, children: isSubmitting ? 'Cancelling...' : 'Confirm Cancellation' }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
27945
+ setSelectedId(null);
27946
+ setSelectionError(null);
27947
+ }, disabled: isSubmitting, children: "Go Back" })] })] })] }));
27948
+ }
27949
+ }
27950
+ // Normal view with inline cancel buttons
27951
+ return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Manage Your Appointments"] }), jsxs("div", { className: "ai-chat-action-body", children: [jsxs("div", { className: "ai-chat-action-hint", children: ["You have ", appointmentCount, " active appointment", appointmentCount !== 1 ? 's' : '', canBook && ` (${maxAppointments - appointmentCount} slot${maxAppointments - appointmentCount !== 1 ? 's' : ''} remaining)`] }), hasAppointments && (jsxs("div", { className: "ai-chat-action-appointment-list", children: [jsx("div", { className: "ai-chat-action-label", children: "Your Upcoming Appointments" }), userAppointments.map((appt) => (jsxs("div", { className: "ai-chat-action-appointment-item", children: [jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsx("div", { className: "ai-chat-action-appointment-subject", children: appt.subject }), jsx("div", { className: "ai-chat-action-appointment-time", children: appt.displayTime })] }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
27952
+ setSelectedId(appt.id);
27953
+ setSelectionError(null);
27954
+ }, children: "Cancel" })] }, appt.id)))] })), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), canBook && (jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
27955
+ setIsSubmitting(true);
27956
+ onComplete?.(action.toolCallId, {
27957
+ ...action.state,
27958
+ selectedOption: "book",
27959
+ });
27960
+ }, disabled: isSubmitting, children: isSubmitting ? 'Loading...' : 'Book New Appointment' })), !canBook && !hasAppointments && (jsx("div", { className: "ai-chat-action-hint", children: "No appointments found." }))] })] }));
27961
+ }
27962
+ // Phase 4: Appointment Selection (Booking)
27963
+ if (phase === "awaiting_booking") {
27964
+ const displayError = state.errorMessage || selectionError;
27965
+ return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Select Appointment Time"] }), jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsx("input", { id: `topic-${action.toolCallId}`, type: "text", className: "ai-chat-action-input", placeholder: "e.g., Product Demo", value: topic, onChange: (e) => setTopic(e.target.value) })] })), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
27966
+ setSelectedDate(date);
27967
+ setSelectedSlot(null);
27968
+ }, children: formatDate(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsx("button", { type: "button", className: `ai-chat-action-time-btn ${selectedSlot?.startTime === slot.startTime ? "active" : ""}`, onClick: () => setSelectedSlot(slot), children: slot.displayTime || new Date(slot.startTime).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }, slot.startTime))) })] })), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleAppointmentConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
27969
+ }
27970
+ // Fallback
27971
+ return null;
27522
27972
  }
27523
27973
 
27524
27974
  function truncate(text, maxLength) {
@@ -27529,17 +27979,30 @@ function truncate(text, maxLength) {
27529
27979
  function ExternalLinkIcon() {
27530
27980
  return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsx("polyline", { points: "15 3 21 3 21 9" }), jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
27531
27981
  }
27982
+ function SingleLinkPreview({ link, onLinkClick, accentColor }) {
27983
+ const domain = (() => {
27984
+ if (!link.url)
27985
+ return '';
27986
+ try {
27987
+ return new URL(link.url).hostname.replace('www.', '');
27988
+ }
27989
+ catch {
27990
+ return link.url;
27991
+ }
27992
+ })();
27993
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
27994
+ return (jsxs("div", { className: "ai-chat-action-card ai-chat-link-preview", onClick: onLinkClick, style: style, role: "link", tabIndex: 0, onKeyDown: (e) => e.key === 'Enter' && onLinkClick(), children: [link.image && (jsx("div", { className: "ai-chat-link-preview__image", children: jsx("img", { src: link.image, alt: link.title, onError: (e) => {
27995
+ e.currentTarget.parentElement.style.display = 'none';
27996
+ } }) })), jsxs("div", { className: "ai-chat-link-preview__content", children: [jsxs("div", { className: "ai-chat-link-preview__site", children: [link.favicon && (jsx("img", { src: link.favicon, alt: "", className: "ai-chat-link-preview__favicon", onError: (e) => {
27997
+ e.currentTarget.style.display = 'none';
27998
+ } })), jsx("span", { className: "ai-chat-link-preview__domain", children: link.siteName || domain })] }), jsx("h4", { className: "ai-chat-link-preview__title", children: link.title }), link.description && (jsx("p", { className: "ai-chat-link-preview__description", children: truncate(link.description, 120) }))] }), jsx("div", { className: "ai-chat-link-preview__arrow", children: jsx(ExternalLinkIcon, {}) })] }));
27999
+ }
27532
28000
  function LinkPreviewCard({ action, onComplete, accentColor }) {
27533
28001
  const rawState = action.state;
27534
28002
  const hasCompletedRef = useRef(false);
27535
28003
  // Provide safe defaults if state is missing
27536
28004
  const state = {
27537
- url: rawState?.url || '',
27538
- title: rawState?.title || 'Link',
27539
- description: rawState?.description,
27540
- image: rawState?.image,
27541
- siteName: rawState?.siteName,
27542
- favicon: rawState?.favicon,
28005
+ links: rawState?.links || [],
27543
28006
  context: rawState?.context,
27544
28007
  status: rawState?.status || 'displaying',
27545
28008
  error: rawState?.error,
@@ -27547,34 +28010,29 @@ function LinkPreviewCard({ action, onComplete, accentColor }) {
27547
28010
  const isError = state.status === 'error';
27548
28011
  // Auto-complete on mount so AI can continue generating text response
27549
28012
  useEffect(() => {
27550
- if (!action.done && !hasCompletedRef.current && onComplete && state.url) {
28013
+ if (!action.done && !hasCompletedRef.current && onComplete && state.links.length > 0) {
27551
28014
  hasCompletedRef.current = true;
27552
28015
  // Signal completion immediately - the card is displayed, AI can continue
27553
28016
  onComplete(action.toolCallId, { ...state, status: 'displaying' });
27554
28017
  }
27555
28018
  }, [action.done, action.toolCallId, onComplete, state]);
27556
- const handleClick = () => {
27557
- if (state.url) {
27558
- window.open(state.url, '_blank', 'noopener,noreferrer');
28019
+ const handleLinkClick = (url) => {
28020
+ if (url) {
28021
+ window.open(url, '_blank', 'noopener,noreferrer');
27559
28022
  }
27560
28023
  onComplete?.(action.toolCallId, { ...state, status: 'clicked' });
27561
28024
  };
27562
- const domain = (() => {
27563
- if (!state.url)
27564
- return '';
27565
- try {
27566
- return new URL(state.url).hostname.replace('www.', '');
27567
- }
27568
- catch {
27569
- return state.url;
27570
- }
27571
- })();
27572
- const style = accentColor ? { '--action-accent': accentColor } : undefined;
27573
- return (jsxs("div", { className: `ai-chat-link-preview ${isError ? 'ai-chat-link-preview--error' : ''}`, onClick: handleClick, style: style, role: "link", tabIndex: 0, onKeyDown: (e) => e.key === 'Enter' && handleClick(), children: [state.image && !isError && (jsx("div", { className: "ai-chat-link-preview__image", children: jsx("img", { src: state.image, alt: state.title, onError: (e) => {
27574
- e.currentTarget.parentElement.style.display = 'none';
27575
- } }) })), jsxs("div", { className: "ai-chat-link-preview__content", children: [jsxs("div", { className: "ai-chat-link-preview__site", children: [state.favicon && (jsx("img", { src: state.favicon, alt: "", className: "ai-chat-link-preview__favicon", onError: (e) => {
27576
- e.currentTarget.style.display = 'none';
27577
- } })), jsx("span", { className: "ai-chat-link-preview__domain", children: state.siteName || domain })] }), jsx("h4", { className: "ai-chat-link-preview__title", children: state.title }), state.description && (jsx("p", { className: "ai-chat-link-preview__description", children: truncate(state.description, 120) })), state.context && (jsx("p", { className: "ai-chat-link-preview__context", children: state.context })), isError && state.error && (jsx("p", { className: "ai-chat-link-preview__error-text", children: state.error }))] }), jsx("div", { className: "ai-chat-link-preview__arrow", children: jsx(ExternalLinkIcon, {}) })] }));
28025
+ if (isError) {
28026
+ return (jsx("div", { className: "ai-chat-action-card ai-chat-link-preview ai-chat-link-preview--error", children: jsx("div", { className: "ai-chat-link-preview__content", children: jsx("p", { className: "ai-chat-link-preview__error-text", children: state.error || 'Failed to load preview' }) }) }));
28027
+ }
28028
+ if (state.links.length === 0) {
28029
+ return null;
28030
+ }
28031
+ return (jsxs("div", { className: "ai-chat-link-preview-container", children: [state.context && (jsx("p", { className: "ai-chat-link-preview__context", style: { marginBottom: '8px', fontSize: '0.9em', color: 'var(--ai-chat-fg-muted)' }, children: state.context })), jsx("div", { className: "ai-chat-link-preview-grid", style: {
28032
+ display: 'grid',
28033
+ gridTemplateColumns: state.links.length === 1 ? '1fr' : state.links.length === 2 ? 'repeat(2, 1fr)' : 'repeat(3, 1fr)',
28034
+ gap: '12px',
28035
+ }, children: state.links.map((link, index) => (jsx(SingleLinkPreview, { link: link, onLinkClick: () => handleLinkClick(link.url), accentColor: accentColor }, index))) })] }));
27578
28036
  }
27579
28037
 
27580
28038
  function PlayIcon() {
@@ -27640,7 +28098,7 @@ function VideoPlayerCard({ action, onComplete, accentColor }) {
27640
28098
  return src;
27641
28099
  }
27642
28100
  };
27643
- return (jsxs("div", { className: "ai-chat-video-player", style: style, children: [state.title && (jsx("div", { className: "ai-chat-video-player__header", children: jsx("span", { className: "ai-chat-video-player__title", children: state.title }) })), jsx("div", { className: "ai-chat-video-player__container", children: isError ? (jsx("div", { className: "ai-chat-video-player__error", children: jsx("span", { children: state.error || 'Could not load video' }) })) : !isPlaying && state.thumbnailUrl ? (jsxs("div", { className: "ai-chat-video-player__thumbnail", onClick: handlePlay, children: [jsx("img", { src: state.thumbnailUrl, alt: state.title || 'Video thumbnail' }), jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsx(PlayIcon, {}) }), jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : !isPlaying ? (jsxs("div", { className: "ai-chat-video-player__placeholder", onClick: handlePlay, children: [jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsx(PlayIcon, {}) }), jsx("span", { className: "ai-chat-video-player__click-text", children: "Click to play" }), jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : state.provider === 'direct' ? (jsx("video", { src: state.embedUrl, controls: true, autoPlay: true, className: "ai-chat-video-player__video" })) : (jsx("iframe", { src: getEmbedSrc(), className: "ai-chat-video-player__iframe", allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share", allowFullScreen: true, title: state.title || 'Video player' })) }), state.context && (jsx("div", { className: "ai-chat-video-player__context", children: state.context }))] }));
28101
+ return (jsxs("div", { className: "ai-chat-action-card ai-chat-video-player", style: style, children: [jsx("div", { className: "ai-chat-video-player__container", children: isError ? (jsx("div", { className: "ai-chat-video-player__error", children: jsx("span", { children: state.error || 'Could not load video' }) })) : !isPlaying && state.thumbnailUrl ? (jsxs("div", { className: "ai-chat-video-player__thumbnail", onClick: handlePlay, children: [jsx("img", { src: state.thumbnailUrl, alt: state.title || 'Video thumbnail' }), jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsx(PlayIcon, {}) }), jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : !isPlaying ? (jsxs("div", { className: "ai-chat-video-player__placeholder", onClick: handlePlay, children: [jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsx(PlayIcon, {}) }), jsx("span", { className: "ai-chat-video-player__click-text", children: "Click to play" }), jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : state.provider === 'direct' ? (jsx("video", { src: state.embedUrl, controls: true, autoPlay: true, className: "ai-chat-video-player__video" })) : (jsx("iframe", { src: getEmbedSrc(), className: "ai-chat-video-player__iframe", allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share", allowFullScreen: true, title: state.title || 'Video player' })) }), state.context && (jsx("div", { className: "ai-chat-video-player__context", children: state.context }))] }));
27644
28102
  }
27645
28103
 
27646
28104
  function MapPinIcon() {
@@ -27701,7 +28159,9 @@ function LocationItem({ location, settings, accentColor, onDirections, showMap =
27701
28159
  }
27702
28160
  };
27703
28161
  const style = accentColor ? { '--action-accent': accentColor } : undefined;
27704
- return (jsxs("div", { className: `ai-chat-location-card ${compact ? 'ai-chat-location-card--compact' : ''}`, style: style, children: [showMap && !compact && settings.showMap !== false && (jsx("div", { className: "ai-chat-location-card__map", style: { height: mapHeight }, children: jsx("iframe", { src: getMapEmbedUrl(), allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade", title: `Map of ${location.name}` }) })), jsxs("div", { className: "ai-chat-location-card__content", children: [jsxs("div", { className: "ai-chat-location-card__header", children: [jsx("h4", { className: "ai-chat-location-card__name", children: location.name }), location.type && (jsx("span", { className: "ai-chat-location-card__type", children: location.type })), openStatus !== null && (jsx("span", { className: `ai-chat-location-card__status ai-chat-location-card__status--${openStatus ? 'open' : 'closed'}`, children: openStatus ? 'Open' : 'Closed' }))] }), jsxs("p", { className: "ai-chat-location-card__address", children: [jsx(MapPinIcon, {}), location.address] }), location.description && (jsx("p", { className: "ai-chat-location-card__description", children: location.description })), settings.showHours !== false && location.hours && location.hours.length > 0 && (jsx(HoursDisplay, { hours: location.hours, compact: compact })), settings.showPhone !== false && location.phone && (jsxs("button", { type: "button", className: "ai-chat-location-card__phone", onClick: handleCall, children: [jsx(PhoneIcon, {}), location.phone] })), jsxs("div", { className: "ai-chat-location-card__actions", children: [settings.showDirectionsButton !== false && (jsxs("button", { type: "button", className: "ai-chat-location-card__button", style: accentColor ? { backgroundColor: accentColor } : undefined, onClick: onDirections, children: [jsx(NavigationIcon, {}), compact ? 'Directions' : 'Get Directions'] })), !compact && location.website && (jsxs("a", { href: location.website, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-location-card__link", children: [jsx(GlobeIcon, {}), "Website"] }))] })] })] }));
28162
+ // Use smaller map height in compact mode
28163
+ const effectiveMapHeight = compact ? Math.min(mapHeight, 140) : mapHeight;
28164
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-location-card ${compact ? 'ai-chat-location-card--compact' : ''}`, style: style, children: [showMap && settings.showMap !== false && (jsx("div", { className: "ai-chat-location-card__map", style: { height: effectiveMapHeight }, children: jsx("iframe", { src: getMapEmbedUrl(), allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade", title: `Map of ${location.name}` }) })), jsxs("div", { className: "ai-chat-location-card__content", children: [jsxs("div", { className: "ai-chat-location-card__header", children: [jsx("h4", { className: "ai-chat-location-card__name", children: location.name }), location.type && (jsx("span", { className: "ai-chat-location-card__type", children: location.type })), openStatus !== null && (jsx("span", { className: `ai-chat-location-card__status ai-chat-location-card__status--${openStatus ? 'open' : 'closed'}`, children: openStatus ? 'Open' : 'Closed' }))] }), jsxs("p", { className: "ai-chat-location-card__address", children: [jsx(MapPinIcon, {}), location.address] }), location.description && (jsx("p", { className: "ai-chat-location-card__description", children: location.description })), settings.showHours !== false && location.hours && location.hours.length > 0 && (jsx(HoursDisplay, { hours: location.hours, compact: compact })), settings.showPhone !== false && location.phone && (jsxs("button", { type: "button", className: "ai-chat-location-card__phone", onClick: handleCall, children: [jsx(PhoneIcon, {}), location.phone] })), jsxs("div", { className: "ai-chat-location-card__actions", children: [settings.showDirectionsButton !== false && (jsxs("button", { type: "button", className: "ai-chat-location-card__button", style: accentColor ? { backgroundColor: accentColor } : undefined, onClick: onDirections, children: [jsx(NavigationIcon, {}), compact ? 'Directions' : 'Get Directions'] })), !compact && location.website && (jsxs("a", { href: location.website, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-location-card__link", children: [jsx(GlobeIcon, {}), "Website"] }))] })] })] }));
27705
28165
  }
27706
28166
  function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
27707
28167
  const rawState = action.state;
@@ -27735,9 +28195,197 @@ function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
27735
28195
  if (isSingleLocation) {
27736
28196
  return (jsx(LocationItem, { location: locations[0], settings: settings, accentColor: accentColor, onDirections: () => handleDirections(locations[0]), showMap: true }));
27737
28197
  }
27738
- return (jsxs("div", { className: `ai-chat-location-card-list ai-chat-location-card-list--${layout}`, children: [jsxs("div", { className: "ai-chat-location-card-list__header", children: [jsx(MapPinIcon, {}), jsxs("span", { children: [locations.length, " Locations"] })] }), layout === 'stack' && (jsx("div", { className: "ai-chat-location-card-list__stack", style: {
28198
+ return (jsxs("div", { className: `ai-chat-location-card-list ai-chat-location-card-list--${layout}`, children: [jsxs("div", { className: "ai-chat-location-card-list__header", children: [jsx(MapPinIcon, {}), jsxs("span", { children: [locations.length, " Locations"] })] }), layout === 'stack' && (jsx("div", { className: `ai-chat-location-card-list__stack ai-chat-location-card-list__stack--cols-${stackColumns}`, children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: settings.showMap !== false, compact: locations.length > 2 }, location.id))) })), layout === 'grid' && (jsx("div", { className: "ai-chat-location-card-list__grid", children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: false, compact: true }, location.id))) })), layout === 'carousel' && (jsx("div", { className: "ai-chat-location-card-list__carousel", children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: true, compact: false }, location.id))) }))] }));
28199
+ }
28200
+
28201
+ function UsersIcon() {
28202
+ return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }), jsx("circle", { cx: "9", cy: "7", r: "4" }), jsx("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87" }), jsx("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })] }));
28203
+ }
28204
+ const AVATAR_COLORS = [
28205
+ { bg: '#E8F5E9', text: '#2E7D32' }, // Green
28206
+ { bg: '#E3F2FD', text: '#1565C0' }, // Blue
28207
+ { bg: '#FFF3E0', text: '#E65100' }, // Orange
28208
+ { bg: '#F3E5F5', text: '#7B1FA2' }, // Purple
28209
+ { bg: '#FFEBEE', text: '#C62828' }, // Red
28210
+ { bg: '#E0F7FA', text: '#00838F' }, // Cyan
28211
+ { bg: '#FFF8E1', text: '#F9A825' }, // Amber
28212
+ { bg: '#FCE4EC', text: '#AD1457' }, // Pink
28213
+ ];
28214
+ function getInitials(name) {
28215
+ const parts = name.trim().split(/\s+/);
28216
+ if (parts.length === 1) {
28217
+ return parts[0].substring(0, 2).toUpperCase();
28218
+ }
28219
+ return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
28220
+ }
28221
+ function getColorFromName(name) {
28222
+ let hash = 0;
28223
+ for (let i = 0; i < name.length; i++) {
28224
+ hash = name.charCodeAt(i) + ((hash << 5) - hash);
28225
+ }
28226
+ return AVATAR_COLORS[Math.abs(hash) % AVATAR_COLORS.length];
28227
+ }
28228
+ function ContactItem({ contact, settings, accentColor, onEmail, onPhone, compact = false, layout = 'vertical', }) {
28229
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28230
+ const layoutClass = layout === 'horizontal'
28231
+ ? 'ai-chat-contact-card--horizontal'
28232
+ : 'ai-chat-contact-card--vertical';
28233
+ return (jsxs("div", { className: `ai-chat-action-card ai-chat-contact-card ${layoutClass} ${compact ? 'ai-chat-contact-card--compact' : ''}`, style: style, children: [jsxs("div", { className: "ai-chat-contact-card__image-section", children: [contact.profilePictureUrl ? (jsx("img", { src: contact.profilePictureUrl, alt: contact.name, className: "ai-chat-contact-card__image", onError: (e) => {
28234
+ e.currentTarget.style.display = 'none';
28235
+ const placeholder = e.currentTarget.parentElement?.querySelector('.ai-chat-contact-card__initials');
28236
+ if (placeholder) {
28237
+ placeholder.style.display = 'flex';
28238
+ }
28239
+ } })) : null, (() => {
28240
+ const colors = getColorFromName(contact.name);
28241
+ return (jsx("div", { className: "ai-chat-contact-card__initials", style: {
28242
+ display: contact.profilePictureUrl ? 'none' : 'flex',
28243
+ backgroundColor: colors.bg,
28244
+ color: colors.text,
28245
+ }, children: getInitials(contact.name) }));
28246
+ })()] }), jsxs("div", { className: "ai-chat-contact-card__info", children: [jsx("h4", { className: "ai-chat-contact-card__name", children: contact.name }), settings.showRole !== false && contact.role && (jsx("p", { className: "ai-chat-contact-card__role", children: contact.role })), jsxs("div", { className: "ai-chat-contact-card__details", children: [settings.showEmail !== false && contact.email && (jsx("a", { href: `mailto:${contact.email}`, className: "ai-chat-contact-card__detail", onClick: onEmail, children: contact.email })), settings.showPhone !== false && contact.phone && (jsx("a", { href: `tel:${contact.phone}`, className: "ai-chat-contact-card__detail", onClick: onPhone, children: contact.phone }))] }), settings.showResponsibilities !== false && contact.responsibilities && contact.responsibilities.length > 0 && !compact && (jsxs("div", { className: "ai-chat-contact-card__responsibilities", children: [contact.responsibilities.slice(0, 3).map((resp, idx) => (jsx("span", { className: "ai-chat-contact-card__responsibility-tag", children: resp }, idx))), contact.responsibilities.length > 3 && (jsxs("span", { className: "ai-chat-contact-card__responsibility-more", children: ["+", contact.responsibilities.length - 3, " more"] }))] }))] })] }));
28247
+ }
28248
+ function ContactCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28249
+ const rawState = action.state;
28250
+ const hasCompletedRef = useRef(false);
28251
+ const state = {
28252
+ contacts: rawState?.contacts || [],
28253
+ settings: rawState?.settings || {},
28254
+ query: rawState?.query,
28255
+ status: rawState?.status || 'displaying',
28256
+ };
28257
+ const { contacts, settings } = state;
28258
+ const isSingleContact = contacts.length === 1;
28259
+ const stackColumns = Math.min(Math.max(contacts.length, 1), maxColumns);
28260
+ useEffect(() => {
28261
+ if (!action.done && !hasCompletedRef.current && onComplete) {
28262
+ hasCompletedRef.current = true;
28263
+ onComplete(action.toolCallId, { ...state, status: 'displaying' });
28264
+ }
28265
+ }, [action.done, action.toolCallId, onComplete, state]);
28266
+ const handleContact = () => {
28267
+ onComplete?.(action.toolCallId, { ...state, status: 'contacted' });
28268
+ };
28269
+ if (contacts.length === 0) {
28270
+ return (jsxs("div", { className: "ai-chat-contact-card ai-chat-contact-card--empty", children: [jsx("div", { className: "ai-chat-contact-card__empty-icon", children: jsx(UsersIcon, {}) }), jsxs("p", { className: "ai-chat-contact-card__empty-text", children: ["No contacts found", state.query ? ` for "${state.query}"` : ''] })] }));
28271
+ }
28272
+ if (isSingleContact) {
28273
+ return (jsx(ContactItem, { contact: contacts[0], settings: settings, accentColor: accentColor, onEmail: handleContact, onPhone: handleContact, layout: settings.layout || 'horizontal' }));
28274
+ }
28275
+ const isWidget = maxColumns === 1;
28276
+ const stackClassName = isWidget
28277
+ ? 'ai-chat-contact-card-list__stack ai-chat-contact-card-list__stack--widget'
28278
+ : 'ai-chat-contact-card-list__stack';
28279
+ return (jsxs("div", { className: "ai-chat-contact-card-list", style: { containerType: 'inline-size' }, children: [jsxs("div", { className: "ai-chat-contact-card-list__header", children: [jsx(UsersIcon, {}), jsxs("span", { children: [contacts.length, " Contacts"] })] }), jsx("div", { className: stackClassName, style: isWidget ? undefined : {
27739
28280
  gridTemplateColumns: `repeat(${stackColumns}, minmax(0, 1fr))`,
27740
- }, children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: settings.showMap !== false, compact: locations.length > 2 }, location.id))) })), layout === 'grid' && (jsx("div", { className: "ai-chat-location-card-list__grid", children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: false, compact: true }, location.id))) })), layout === 'carousel' && (jsx("div", { className: "ai-chat-location-card-list__carousel", children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: true, compact: false }, location.id))) }))] }));
28281
+ }, children: contacts.map((contact) => (jsx(ContactItem, { contact: contact, settings: settings, accentColor: accentColor, onEmail: handleContact, onPhone: handleContact, compact: true, layout: settings.layout || 'vertical' }, contact.id))) })] }));
28282
+ }
28283
+
28284
+ function FormCard({ action, onComplete, accentColor }) {
28285
+ const state = action.state;
28286
+ const [currentStep, setCurrentStep] = useState(0);
28287
+ const [answers, setAnswers] = useState({});
28288
+ const [isSubmitting, setIsSubmitting] = useState(false);
28289
+ const questions = state.questions || [];
28290
+ const currentQuestion = questions[currentStep];
28291
+ const totalQuestions = questions.length;
28292
+ const handleAnswerChange = (questionId, value) => {
28293
+ setAnswers((prev) => ({ ...prev, [questionId]: value }));
28294
+ };
28295
+ const handleNext = () => {
28296
+ if (currentStep < totalQuestions - 1) {
28297
+ setCurrentStep((prev) => prev + 1);
28298
+ }
28299
+ };
28300
+ const handlePrev = () => {
28301
+ if (currentStep > 0) {
28302
+ setCurrentStep((prev) => prev - 1);
28303
+ }
28304
+ };
28305
+ const handleSubmit = () => {
28306
+ if (!onComplete)
28307
+ return;
28308
+ setIsSubmitting(true);
28309
+ const formattedAnswers = Object.entries(answers).map(([questionId, value]) => ({
28310
+ questionId,
28311
+ value,
28312
+ }));
28313
+ onComplete(action.toolCallId, {
28314
+ ...state,
28315
+ status: 'submitted',
28316
+ answers: formattedAnswers,
28317
+ });
28318
+ };
28319
+ const handleSkip = () => {
28320
+ if (!onComplete || !state.settings.allowSkip)
28321
+ return;
28322
+ onComplete(action.toolCallId, {
28323
+ ...state,
28324
+ status: 'skipped',
28325
+ });
28326
+ };
28327
+ const isCurrentAnswered = () => {
28328
+ if (!currentQuestion)
28329
+ return false;
28330
+ const answer = answers[currentQuestion.id];
28331
+ if (!answer)
28332
+ return !currentQuestion.required;
28333
+ if (Array.isArray(answer))
28334
+ return answer.length > 0 || !currentQuestion.required;
28335
+ return answer.trim() !== '' || !currentQuestion.required;
28336
+ };
28337
+ const canSubmit = () => {
28338
+ return questions.every((q) => {
28339
+ const answer = answers[q.id];
28340
+ if (!q.required)
28341
+ return true;
28342
+ if (!answer)
28343
+ return false;
28344
+ if (Array.isArray(answer))
28345
+ return answer.length > 0;
28346
+ return answer.trim() !== '';
28347
+ });
28348
+ };
28349
+ // Error state
28350
+ if (state.status === 'error') {
28351
+ return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--error", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\u26A0\uFE0F" }), jsx("span", { className: "ai-chat-form-card__title", children: "Form Error" })] }), jsx("p", { className: "ai-chat-form-card__error", children: state.error || 'Could not load form' })] }));
28352
+ }
28353
+ // Submitted state
28354
+ if (state.status === 'submitted' || action.done) {
28355
+ return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--submitted", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\u2713" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsx("p", { className: "ai-chat-form-card__success", children: state.settings.successMessage || 'Thank you for your response!' })] }));
28356
+ }
28357
+ // Skipped state
28358
+ if (state.status === 'skipped') {
28359
+ return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--skipped", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\u21B7" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsx("p", { className: "ai-chat-form-card__skipped-text", children: "Form skipped" })] }));
28360
+ }
28361
+ // No questions
28362
+ if (totalQuestions === 0) {
28363
+ return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--empty", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\uD83D\uDCCB" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsx("p", { className: "ai-chat-form-card__empty-text", children: "This form has no questions." })] }));
28364
+ }
28365
+ return (jsxs("div", { className: "ai-chat-form-card", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\uD83D\uDCCB" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), state.description && (jsx("p", { className: "ai-chat-form-card__description", children: state.description })), state.context && (jsx("p", { className: "ai-chat-form-card__context", children: state.context })), state.settings.showProgress && (jsxs("div", { className: "ai-chat-form-card__progress", children: [jsx("div", { className: "ai-chat-form-card__progress-bar", style: {
28366
+ width: `${((currentStep + 1) / totalQuestions) * 100}%`,
28367
+ backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
28368
+ } }), jsxs("span", { className: "ai-chat-form-card__progress-text", children: [currentStep + 1, " of ", totalQuestions] })] })), jsxs("div", { className: "ai-chat-form-card__question", children: [jsxs("p", { className: "ai-chat-form-card__question-text", children: [currentQuestion.text, currentQuestion.required && jsx("span", { className: "ai-chat-form-card__required", children: "*" })] }), jsxs("div", { className: "ai-chat-form-card__answer", children: [currentQuestion.type === 'text' && (jsx("textarea", { className: "ai-chat-form-card__textarea", placeholder: currentQuestion.placeholder || 'Type your answer...', value: answers[currentQuestion.id] || '', onChange: (e) => handleAnswerChange(currentQuestion.id, e.target.value), rows: 3 })), currentQuestion.type === 'single_choice' && currentQuestion.options && (jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => (jsxs("label", { className: "ai-chat-form-card__option", children: [jsx("input", { type: "radio", name: currentQuestion.id, value: option.value, checked: answers[currentQuestion.id] === option.value, onChange: () => handleAnswerChange(currentQuestion.id, option.value) }), jsx("span", { className: "ai-chat-form-card__option-text", children: option.text })] }, option.id))) })), currentQuestion.type === 'multiple_choice' && currentQuestion.options && (jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => {
28369
+ const currentAnswers = answers[currentQuestion.id] || [];
28370
+ const isChecked = currentAnswers.includes(option.value);
28371
+ return (jsxs("label", { className: "ai-chat-form-card__option", children: [jsx("input", { type: "checkbox", value: option.value, checked: isChecked, onChange: () => {
28372
+ const newAnswers = isChecked
28373
+ ? currentAnswers.filter((v) => v !== option.value)
28374
+ : [...currentAnswers, option.value];
28375
+ handleAnswerChange(currentQuestion.id, newAnswers);
28376
+ } }), jsx("span", { className: "ai-chat-form-card__option-text", children: option.text })] }, option.id));
28377
+ }) })), currentQuestion.type === 'rating' && (jsx("div", { className: "ai-chat-form-card__rating", children: Array.from({ length: (currentQuestion.maxRating || 5) - (currentQuestion.minRating || 1) + 1 }, (_, i) => (currentQuestion.minRating || 1) + i).map((rating) => (jsx("button", { type: "button", className: `ai-chat-form-card__rating-btn ${answers[currentQuestion.id] === String(rating) ? 'ai-chat-form-card__rating-btn--selected' : ''}`, onClick: () => handleAnswerChange(currentQuestion.id, String(rating)), style: {
28378
+ borderColor: answers[currentQuestion.id] === String(rating)
28379
+ ? (accentColor || 'var(--ai-chat-accent-color, #3b82f6)')
28380
+ : undefined,
28381
+ backgroundColor: answers[currentQuestion.id] === String(rating)
28382
+ ? (accentColor || 'var(--ai-chat-accent-color, #3b82f6)')
28383
+ : undefined,
28384
+ }, children: rating }, rating))) }))] })] }), jsxs("div", { className: "ai-chat-form-card__actions", children: [currentStep > 0 && (jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--secondary", onClick: handlePrev, children: "Back" })), state.settings.allowSkip && currentStep === 0 && (jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--ghost", onClick: handleSkip, children: "Skip" })), jsx("div", { className: "ai-chat-form-card__actions-spacer" }), currentStep < totalQuestions - 1 ? (jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--primary", onClick: handleNext, disabled: !isCurrentAnswered(), style: {
28385
+ backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
28386
+ }, children: "Next" })) : (jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--primary", onClick: handleSubmit, disabled: !canSubmit() || isSubmitting, style: {
28387
+ backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
28388
+ }, children: isSubmitting ? 'Submitting...' : (state.settings.submitButtonText || 'Submit') }))] })] }));
27741
28389
  }
27742
28390
 
27743
28391
  const pendingResolvers = new Map();
@@ -27750,12 +28398,6 @@ function getFrontendActionHandler(implementation) {
27750
28398
  function getActionRenderer(implementation) {
27751
28399
  return actionRenderers[implementation];
27752
28400
  }
27753
- function getActionPrompt(implementation) {
27754
- if (implementation === "google-calendar-appointment") {
27755
- return "Select a date to continue.";
27756
- }
27757
- return "Action input required.";
27758
- }
27759
28401
  function waitForActionState(toolCallId) {
27760
28402
  return new Promise((resolve) => {
27761
28403
  pendingResolvers.set(toolCallId, resolve);
@@ -27796,7 +28438,7 @@ function registerGoogleCalendarAction() {
27796
28438
  // Register the handler
27797
28439
  registerGoogleCalendarHandler();
27798
28440
  // Register the renderer
27799
- actionRenderers["google-calendar-appointment"] = (message) => {
28441
+ actionRenderers["google-calendar-appointment"] = (message, accentColor) => {
27800
28442
  const action = message.action;
27801
28443
  if (!action)
27802
28444
  return null;
@@ -27810,22 +28452,54 @@ function registerGoogleCalendarAction() {
27810
28452
  input: action.input,
27811
28453
  state: action.state,
27812
28454
  done: action.done ?? false,
27813
- }, onComplete: handleComplete }));
28455
+ }, onComplete: handleComplete, accentColor: accentColor }));
28456
+ };
28457
+ }
28458
+
28459
+ function registerMicrosoftCalendarHandler() {
28460
+ frontendActionHandlers["microsoft-calendar-appointment"] = async (_input, _state, context) => {
28461
+ return waitForActionState(context.toolCallId);
27814
28462
  };
27815
28463
  }
27816
28464
 
27817
28465
  /**
27818
- * Register link-preview action handler and renderer.
28466
+ * Register microsoft-calendar-appointment action handler and renderer.
27819
28467
  * Called by initializeActionHandlers to prevent tree-shaking.
27820
28468
  */
27821
- function registerLinkPreviewAction() {
27822
- // Handler - auto-completes immediately since no user input is needed
27823
- frontendActionHandlers["link-preview"] = async (_input, state, _context) => {
27824
- return { ...state, status: "displaying" };
27825
- };
27826
- // Renderer - displays the link preview card
27827
- actionRenderers["link-preview"] = (message) => {
27828
- const action = message.action;
28469
+ function registerMicrosoftCalendarAction() {
28470
+ // Register the handler
28471
+ registerMicrosoftCalendarHandler();
28472
+ // Register the renderer
28473
+ actionRenderers["microsoft-calendar-appointment"] = (message, accentColor) => {
28474
+ const action = message.action;
28475
+ if (!action)
28476
+ return null;
28477
+ const handleComplete = (toolCallId, newState) => {
28478
+ resolveActionState(toolCallId, newState);
28479
+ };
28480
+ return (jsx(MicrosoftCalendarCard, { action: {
28481
+ implementation: action.implementation,
28482
+ toolCallId: action.toolCallId,
28483
+ actionId: action.actionId,
28484
+ input: action.input,
28485
+ state: action.state,
28486
+ done: action.done ?? false,
28487
+ }, onComplete: handleComplete, accentColor: accentColor }));
28488
+ };
28489
+ }
28490
+
28491
+ /**
28492
+ * Register link-preview action handler and renderer.
28493
+ * Called by initializeActionHandlers to prevent tree-shaking.
28494
+ */
28495
+ function registerLinkPreviewAction() {
28496
+ // Handler - auto-completes immediately since no user input is needed
28497
+ frontendActionHandlers["link-preview"] = async (_input, state, _context) => {
28498
+ return { ...state, status: "displaying" };
28499
+ };
28500
+ // Renderer - displays the link preview card
28501
+ actionRenderers["link-preview"] = (message, accentColor) => {
28502
+ const action = message.action;
27829
28503
  if (!action)
27830
28504
  return null;
27831
28505
  const handleComplete = (toolCallId, newState) => {
@@ -27842,7 +28516,7 @@ function registerLinkPreviewAction() {
27842
28516
  input: action.input,
27843
28517
  state: action.state,
27844
28518
  done: isDone,
27845
- }, onComplete: handleComplete }));
28519
+ }, onComplete: handleComplete, accentColor: accentColor }));
27846
28520
  };
27847
28521
  }
27848
28522
 
@@ -27856,7 +28530,7 @@ function registerVideoPlayerAction() {
27856
28530
  return { ...state, status: "displaying" };
27857
28531
  };
27858
28532
  // Renderer - displays the embedded video player card
27859
- actionRenderers["video-player"] = (message) => {
28533
+ actionRenderers["video-player"] = (message, accentColor) => {
27860
28534
  const action = message.action;
27861
28535
  if (!action)
27862
28536
  return null;
@@ -27874,7 +28548,7 @@ function registerVideoPlayerAction() {
27874
28548
  input: action.input,
27875
28549
  state: action.state,
27876
28550
  done: isDone,
27877
- }, onComplete: handleComplete }));
28551
+ }, onComplete: handleComplete, accentColor: accentColor }));
27878
28552
  };
27879
28553
  }
27880
28554
 
@@ -27888,7 +28562,7 @@ function registerLocationCardAction() {
27888
28562
  return { ...state, status: "displaying" };
27889
28563
  };
27890
28564
  // Renderer - displays the location card
27891
- actionRenderers["location-card"] = (message, accentColor) => {
28565
+ actionRenderers["location-card"] = (message, accentColor, variant) => {
27892
28566
  const action = message.action;
27893
28567
  if (!action)
27894
28568
  return null;
@@ -27906,7 +28580,92 @@ function registerLocationCardAction() {
27906
28580
  input: action.input,
27907
28581
  state: action.state,
27908
28582
  done: isDone,
27909
- }, onComplete: handleComplete, accentColor: accentColor, maxColumns: 1 }));
28583
+ }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28584
+ };
28585
+ }
28586
+
28587
+ function registerContactCardAction() {
28588
+ // Handler - auto-completes immediately since no user input is needed
28589
+ frontendActionHandlers['contact-card'] = async (_input, state, _context) => {
28590
+ return { ...state, status: 'displaying' };
28591
+ };
28592
+ // Renderer - displays the contact card
28593
+ actionRenderers['contact-card'] = (message, accentColor, variant) => {
28594
+ const action = message.action;
28595
+ if (!action)
28596
+ return null;
28597
+ const handleComplete = (toolCallId, newState) => {
28598
+ resolveActionState(toolCallId, newState);
28599
+ };
28600
+ // Check if action state indicates it's already complete
28601
+ const state = action.state;
28602
+ const status = state?.status;
28603
+ const isDone = action.done || status === 'displaying' || status === 'contacted';
28604
+ return (jsx(ContactCard, { action: {
28605
+ implementation: action.implementation,
28606
+ toolCallId: action.toolCallId,
28607
+ actionId: action.actionId,
28608
+ input: action.input,
28609
+ state: action.state,
28610
+ done: isDone,
28611
+ }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28612
+ };
28613
+ }
28614
+
28615
+ function registerQueryContactDirectoryAction() {
28616
+ // Handler - auto-completes immediately since no user input is needed
28617
+ frontendActionHandlers['query-contact-directory'] = async (_input, state, _context) => {
28618
+ return { ...state, status: 'displaying' };
28619
+ };
28620
+ // Renderer - displays the contact card with search results
28621
+ actionRenderers['query-contact-directory'] = (message, accentColor, variant) => {
28622
+ const action = message.action;
28623
+ if (!action)
28624
+ return null;
28625
+ // Handle completion - triggers agent to continue with text response
28626
+ const handleComplete = (toolCallId, newState) => {
28627
+ resolveActionState(toolCallId, newState);
28628
+ };
28629
+ // Check if action state indicates it's already complete
28630
+ const state = action.state;
28631
+ const status = state?.status;
28632
+ const isDone = action.done || status === 'displaying' || status === 'contacted';
28633
+ return (jsx(ContactCard, { action: {
28634
+ implementation: action.implementation,
28635
+ toolCallId: action.toolCallId,
28636
+ actionId: action.actionId,
28637
+ input: action.input,
28638
+ state: action.state,
28639
+ done: isDone,
28640
+ }, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
28641
+ };
28642
+ }
28643
+
28644
+ function registerDisplayFormAction() {
28645
+ // Handler - handles form submission and state updates
28646
+ frontendActionHandlers['display-form'] = async (_input, _state, context) => {
28647
+ return waitForActionState(context.toolCallId);
28648
+ };
28649
+ // Renderer - displays the form card
28650
+ actionRenderers['display-form'] = (message, accentColor, variant) => {
28651
+ const action = message.action;
28652
+ if (!action)
28653
+ return null;
28654
+ const handleComplete = (toolCallId, newState) => {
28655
+ resolveActionState(toolCallId, newState);
28656
+ };
28657
+ // Check if action state indicates it's already complete
28658
+ const state = action.state;
28659
+ const status = state?.status;
28660
+ const isDone = action.done || status === 'completed' || status === 'submitted';
28661
+ return (jsx(FormCard, { action: {
28662
+ implementation: action.implementation,
28663
+ toolCallId: action.toolCallId,
28664
+ actionId: action.actionId,
28665
+ input: action.input,
28666
+ state: action.state,
28667
+ done: isDone,
28668
+ }, onComplete: handleComplete, accentColor: accentColor }));
27910
28669
  };
27911
28670
  }
27912
28671
 
@@ -27923,9 +28682,13 @@ function initializeActionHandlers() {
27923
28682
  initialized = true;
27924
28683
  // Explicitly call each registration function to prevent tree-shaking
27925
28684
  registerGoogleCalendarAction();
28685
+ registerMicrosoftCalendarAction();
27926
28686
  registerLinkPreviewAction();
27927
28687
  registerVideoPlayerAction();
27928
28688
  registerLocationCardAction();
28689
+ registerQueryContactDirectoryAction();
28690
+ registerContactCardAction();
28691
+ registerDisplayFormAction();
27929
28692
  }
27930
28693
 
27931
28694
  /**
@@ -28145,12 +28908,6 @@ function isStorageAvailable() {
28145
28908
  }
28146
28909
  }
28147
28910
 
28148
- /**
28149
- * useChat Hook
28150
- * Main state management for chat functionality
28151
- */
28152
- // Initialize action handlers immediately to prevent tree-shaking
28153
- initializeActionHandlers();
28154
28911
  function hydrateToolNames(messages) {
28155
28912
  const toolCallNameById = new Map();
28156
28913
  for (const entry of messages) {
@@ -28194,118 +28951,77 @@ function hydrateToolNames(messages) {
28194
28951
  };
28195
28952
  });
28196
28953
  }
28197
- function hydrateActionContent(messages) {
28198
- return messages.map((entry) => {
28199
- if (entry.message.role !== "assistant" || !entry.action) {
28200
- return entry;
28201
- }
28202
- const content = typeof entry.message.content === "string" ? entry.message.content : "";
28203
- if (content.trim().length > 0) {
28204
- return entry;
28205
- }
28206
- return {
28207
- ...entry,
28208
- message: { ...entry.message, content: getActionPrompt(entry.action.implementation) },
28209
- };
28210
- });
28954
+ function hydrateMessages(messages) {
28955
+ return hydrateToolNames(messages);
28211
28956
  }
28212
- function hydrateActionDoneStatus(messages) {
28213
- return messages.map((entry) => {
28214
- if (!entry.action) {
28215
- return entry;
28216
- }
28217
- // If action already marked done, skip
28218
- if (entry.action.done) {
28219
- return entry;
28957
+
28958
+ function deriveErrorInfo(error) {
28959
+ if (error instanceof ApiError) {
28960
+ const retryAfterSeconds = typeof error.retryAfterMs === 'number'
28961
+ ? Math.max(1, Math.ceil(error.retryAfterMs / 1000))
28962
+ : undefined;
28963
+ const lowerMessage = (error.message || '').toLowerCase();
28964
+ let message;
28965
+ switch (error.status) {
28966
+ case 429: {
28967
+ const isPerUser = lowerMessage.includes('user');
28968
+ const base = isPerUser
28969
+ ? 'You have reached the per-user rate limit.'
28970
+ : 'This widget has received too many requests.';
28971
+ if (retryAfterSeconds) {
28972
+ message = `${base} Please wait ${retryAfterSeconds} second${retryAfterSeconds === 1 ? '' : 's'} before trying again.`;
28973
+ }
28974
+ else {
28975
+ message = `${base} Please wait a moment and try again.`;
28976
+ }
28977
+ break;
28978
+ }
28979
+ case 401:
28980
+ message = 'Authentication failed. Please refresh the page or verify your API key.';
28981
+ break;
28982
+ case 403:
28983
+ message = 'Access to this widget is restricted. Please contact the site owner if you believe this is an error.';
28984
+ break;
28985
+ case 404:
28986
+ if (lowerMessage.includes('not active')) {
28987
+ message = 'This widget is currently inactive. Please contact the site owner.';
28988
+ }
28989
+ else {
28990
+ message = 'We could not find this widget. It may have been removed.';
28991
+ }
28992
+ break;
28993
+ default:
28994
+ if (error.status >= 500) {
28995
+ message = 'The server encountered an error. Please try again shortly.';
28996
+ }
28997
+ else if (error.status > 0) {
28998
+ message = error.message || 'Something went wrong. Please try again.';
28999
+ }
29000
+ else {
29001
+ message = error.message || 'Unable to connect to the server. Please check your internet connection.';
29002
+ }
28220
29003
  }
28221
- // Check if action state indicates completion
28222
- const state = entry.action.state;
28223
- if (!state) {
28224
- return entry;
29004
+ return { message, retryAfterSeconds, status: error.status };
29005
+ }
29006
+ if (error instanceof Error) {
29007
+ const lower = error.message.toLowerCase();
29008
+ if (lower.includes('network')) {
29009
+ return { message: 'Unable to connect to the server. Please check your internet connection.' };
28225
29010
  }
28226
- // Link-preview: done if status is "displaying" or "clicked"
28227
- if (entry.action.implementation === "link-preview") {
28228
- const status = state.status;
28229
- if (status === "displaying" || status === "clicked") {
28230
- return {
28231
- ...entry,
28232
- action: { ...entry.action, done: true },
28233
- };
28234
- }
29011
+ if (lower.includes('timeout')) {
29012
+ return { message: 'The request timed out. Please try again.' };
28235
29013
  }
28236
- // Google Calendar: done if status indicates completion
28237
- if (entry.action.implementation === "google-calendar-appointment") {
28238
- const status = state.status;
28239
- if (status === "booked" || status === "cancelled" || status === "error") {
28240
- return {
28241
- ...entry,
28242
- action: { ...entry.action, done: true },
28243
- };
28244
- }
29014
+ if (lower.includes('unauthorized') || lower.includes('401')) {
29015
+ return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
28245
29016
  }
28246
- return entry;
28247
- });
28248
- }
28249
- function hydrateMessages(messages) {
28250
- return hydrateActionDoneStatus(hydrateActionContent(hydrateToolNames(messages)));
28251
- }
28252
- function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate) {
28253
- // Find all incomplete actions and register resume callbacks
28254
- for (const message of messages) {
28255
- if (message.action && !message.action.done) {
28256
- const toolCallId = message.action.toolCallId;
28257
- const toolName = message.message.name || message.toolExecuting || "tool";
28258
- registerActionResumeCallback(toolCallId, async (newState) => {
28259
- // When user interacts with the action after reload, continue the stream
28260
- try {
28261
- // Update the action message with the new state
28262
- setState(prev => ({
28263
- ...prev,
28264
- messages: prev.messages.map(m => m.action?.toolCallId === toolCallId
28265
- ? {
28266
- ...m,
28267
- action: m.action ? { ...m.action, state: newState } : undefined,
28268
- }
28269
- : m),
28270
- isTyping: true,
28271
- }));
28272
- const streamState = createStreamState();
28273
- // Continue the agent stream with the new state
28274
- for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
28275
- if (event.type === "done") {
28276
- finalizeToolMessage(streamState, setState, toolCallId, toolName);
28277
- streamState.sources = event.sources;
28278
- streamState.toolCallToActionId = event.tool_call_to_action_id;
28279
- finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
28280
- continue;
28281
- }
28282
- if (event.type === "error") {
28283
- const errorMessage = {
28284
- id: generateMessageId(),
28285
- message: {
28286
- role: "assistant",
28287
- content: "Sorry, an error occurred. Please try again later.",
28288
- },
28289
- timestamp: new Date().toISOString(),
28290
- sources: [],
28291
- isError: true,
28292
- };
28293
- upsertMessage(setState, errorMessage, false);
28294
- setState(prev => ({ ...prev, isTyping: false }));
28295
- return;
28296
- }
28297
- handleStreamEvent(event, streamState, onMessageUpdate, setState);
28298
- }
28299
- setState(prev => ({ ...prev, isTyping: false }));
28300
- }
28301
- catch (error) {
28302
- console.error("[Action Resume] Failed to continue stream:", error);
28303
- setState(prev => ({ ...prev, isTyping: false }));
28304
- }
28305
- });
29017
+ if (lower.includes('internal server error') || lower.includes('500')) {
29018
+ return { message: 'The server encountered an error. Please try again shortly.' };
28306
29019
  }
29020
+ return { message: error.message || 'Something went wrong. Please try again.' };
28307
29021
  }
29022
+ return { message: 'Something went wrong. Please try again.' };
28308
29023
  }
29024
+
28309
29025
  function createStreamState() {
28310
29026
  return {
28311
29027
  currentContent: "",
@@ -28314,6 +29030,7 @@ function createStreamState() {
28314
29030
  newMessageIds: new Set(),
28315
29031
  sources: [],
28316
29032
  toolCallToActionId: {},
29033
+ requestId: generateMessageId(),
28317
29034
  };
28318
29035
  }
28319
29036
  function upsertMessage(setState, message, isTyping) {
@@ -28349,15 +29066,40 @@ function finalizeStreamMessages(setState, messageIds, sources, toolCallToActionI
28349
29066
  return msg;
28350
29067
  }
28351
29068
  // Attach suggestions only to the last assistant message
28352
- if (index === lastAssistantIndex && suggestions && suggestions.length > 0) {
28353
- return { ...msg, sources, toolCallToActionId, suggestions };
28354
- }
28355
- return { ...msg, sources, toolCallToActionId };
29069
+ const withSuggestions = index === lastAssistantIndex && suggestions && suggestions.length > 0
29070
+ ? { suggestions }
29071
+ : {};
29072
+ return { ...msg, sources, toolCallToActionId, ...withSuggestions };
28356
29073
  }),
28357
29074
  isTyping: false,
28358
29075
  };
28359
29076
  });
28360
29077
  }
29078
+ function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
29079
+ setState(prev => {
29080
+ const messages = prev.messages.map((entry) => {
29081
+ const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
29082
+ if (!matchesToolCall) {
29083
+ return entry;
29084
+ }
29085
+ const existingName = entry.message.name || toolName;
29086
+ return {
29087
+ ...entry,
29088
+ message: {
29089
+ role: "tool",
29090
+ content: typeof entry.message.content === "string" ? entry.message.content : "",
29091
+ tool_call_id: toolCallId,
29092
+ name: existingName,
29093
+ },
29094
+ isStreaming: false,
29095
+ toolExecuting: existingName,
29096
+ };
29097
+ });
29098
+ return { ...prev, messages, isTyping: false, isLoading: false };
29099
+ });
29100
+ streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
29101
+ }
29102
+
28361
29103
  function handleContentEvent(event, streamState, onMessageUpdate, setState) {
28362
29104
  streamState.currentContent += event.content;
28363
29105
  const assistantMessage = {
@@ -28404,8 +29146,6 @@ function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
28404
29146
  }
28405
29147
  function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
28406
29148
  streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
28407
- // Update state and mark action as done in a single setState call
28408
- // Keep isTyping: true because the agent may continue generating content after tool completion
28409
29149
  setState(prev => {
28410
29150
  const messages = prev.messages.map((msg) => {
28411
29151
  const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
@@ -28413,7 +29153,26 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
28413
29153
  return msg;
28414
29154
  }
28415
29155
  const existingName = msg.message.name || event.tool_name;
28416
- return {
29156
+ let action = msg.action;
29157
+ if (event.action_id && event.implementation) {
29158
+ action = {
29159
+ implementation: event.implementation,
29160
+ toolCallId: event.tool_call_id,
29161
+ actionId: event.action_id,
29162
+ input: (event.input || {}),
29163
+ state: (event.state || {}),
29164
+ done: event.done,
29165
+ };
29166
+ }
29167
+ else if (action) {
29168
+ action = {
29169
+ ...action,
29170
+ input: event.input ? event.input : action.input,
29171
+ state: event.state ? event.state : action.state,
29172
+ done: event.done,
29173
+ };
29174
+ }
29175
+ const updatedMsg = {
28417
29176
  ...msg,
28418
29177
  message: {
28419
29178
  role: "tool",
@@ -28423,14 +29182,10 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
28423
29182
  },
28424
29183
  isStreaming: false,
28425
29184
  toolExecuting: existingName,
28426
- action: msg.action ? {
28427
- ...msg.action,
28428
- state: event.state || msg.action.state,
28429
- done: true, // Mark action as completed
28430
- } : undefined,
29185
+ action,
28431
29186
  };
29187
+ return updatedMsg;
28432
29188
  });
28433
- // Keep typing indicator visible - it will be hidden by done/finalizeStreamMessages
28434
29189
  return { ...prev, messages, isTyping: true, isLoading: false };
28435
29190
  });
28436
29191
  }
@@ -28462,34 +29217,6 @@ function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
28462
29217
  return { ...prev, messages, isTyping: true, isLoading: false };
28463
29218
  });
28464
29219
  }
28465
- function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
28466
- setState(prev => {
28467
- const messages = prev.messages.map((entry) => {
28468
- const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
28469
- if (!matchesToolCall) {
28470
- return entry;
28471
- }
28472
- const existingName = entry.message.name || toolName;
28473
- return {
28474
- ...entry,
28475
- message: {
28476
- role: "tool",
28477
- content: typeof entry.message.content === "string" ? entry.message.content : "",
28478
- tool_call_id: toolCallId,
28479
- name: existingName,
28480
- },
28481
- isStreaming: false,
28482
- toolExecuting: existingName,
28483
- action: entry.action ? {
28484
- ...entry.action,
28485
- done: true, // Mark action as completed
28486
- } : undefined,
28487
- };
28488
- });
28489
- return { ...prev, messages, isTyping: false, isLoading: false };
28490
- });
28491
- streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
28492
- }
28493
29220
  function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
28494
29221
  streamState.sources = event.sources;
28495
29222
  streamState.toolCallToActionId = event.tool_call_to_action_id;
@@ -28548,6 +29275,7 @@ function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
28548
29275
  console.warn('[Chat] Unknown event type:', event.type);
28549
29276
  }
28550
29277
  }
29278
+
28551
29279
  async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
28552
29280
  let pendingEvent = initialEvent;
28553
29281
  while (pendingEvent) {
@@ -28574,7 +29302,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28574
29302
  actionId: pendingEvent.action_id,
28575
29303
  input: pendingEvent.input,
28576
29304
  state: pendingEvent.state,
28577
- done: false, // Action not yet completed
29305
+ done: pendingEvent.done ?? false,
28578
29306
  },
28579
29307
  };
28580
29308
  if (streamState.activeToolCallCount === 0) {
@@ -28588,7 +29316,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28588
29316
  id: generateMessageId(),
28589
29317
  message: {
28590
29318
  role: "assistant",
28591
- content: "Sorry, an error occurred. Please try again later.",
29319
+ content: "Sorry, an error occurred.",
28592
29320
  },
28593
29321
  timestamp: new Date().toISOString(),
28594
29322
  sources: [],
@@ -28612,7 +29340,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28612
29340
  console.error("[Widget] Frontend action failed:", error);
28613
29341
  const errorMessageEntry = {
28614
29342
  id: generateMessageId(),
28615
- message: { role: "assistant", content: "Sorry, an error occurred. Please try again later." },
29343
+ message: { role: "assistant", content: "Sorry, an error occurred." },
28616
29344
  timestamp: new Date().toISOString(),
28617
29345
  sources: [],
28618
29346
  isError: true,
@@ -28624,12 +29352,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28624
29352
  pendingEvent = null;
28625
29353
  const updatedToolMessage = {
28626
29354
  ...toolMessage,
28627
- action: toolMessage.action
28628
- ? {
28629
- ...toolMessage.action,
28630
- state: nextState,
28631
- }
28632
- : undefined,
29355
+ action: toolMessage.action ? { ...toolMessage.action, state: nextState } : toolMessage.action,
28633
29356
  };
28634
29357
  upsertMessage(setState, updatedToolMessage, true);
28635
29358
  let streamEnded = false;
@@ -28639,22 +29362,20 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28639
29362
  break;
28640
29363
  }
28641
29364
  if (event.type === "done") {
28642
- // Don't extract and update state from done event - the state was already
28643
- // updated by tool_end event or by the user's frontend action.
29365
+ // Finalize tool message and stream messages
28644
29366
  finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
28645
- // Handle the done event but skip the tool finalization part since we already did it
28646
29367
  streamState.sources = event.sources;
28647
29368
  streamState.toolCallToActionId = event.tool_call_to_action_id;
28648
29369
  finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
28649
29370
  streamEnded = true;
28650
- continue; // Skip handleStreamEvent for done events to avoid state conflicts
29371
+ continue;
28651
29372
  }
28652
29373
  if (event.type === "error") {
28653
29374
  const errorMessage = {
28654
29375
  id: generateMessageId(),
28655
29376
  message: {
28656
29377
  role: "assistant",
28657
- content: "Sorry, an error occurred. Please try again later.",
29378
+ content: "Sorry, an error occurred.",
28658
29379
  },
28659
29380
  timestamp: new Date().toISOString(),
28660
29381
  sources: [],
@@ -28665,73 +29386,79 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28665
29386
  }
28666
29387
  handleStreamEvent(event, streamState, onMessageUpdate, setState);
28667
29388
  }
28668
- // If stream ended without a done event (e.g., only tool_end was sent), finalize the tool message
29389
+ // If stream ended without a done event, finalize the tool message
28669
29390
  if (!streamEnded && !pendingEvent) {
28670
29391
  finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
28671
29392
  }
28672
29393
  }
28673
29394
  }
28674
- function deriveErrorInfo(error) {
28675
- if (error instanceof ApiError) {
28676
- const retryAfterSeconds = typeof error.retryAfterMs === 'number'
28677
- ? Math.max(1, Math.ceil(error.retryAfterMs / 1000))
28678
- : undefined;
28679
- const lowerMessage = (error.message || '').toLowerCase();
28680
- let message;
28681
- switch (error.status) {
28682
- case 429: {
28683
- const isPerUser = lowerMessage.includes('user');
28684
- const base = isPerUser
28685
- ? 'You have reached the per-user rate limit.'
28686
- : 'This widget has received too many requests.';
28687
- if (retryAfterSeconds) {
28688
- message = `${base} Please wait ${retryAfterSeconds} second${retryAfterSeconds === 1 ? '' : 's'} before trying again.`;
28689
- }
28690
- else {
28691
- message = `${base} Please wait a moment and try again.`;
28692
- }
28693
- break;
28694
- }
28695
- case 401:
28696
- message = 'Authentication failed. Please refresh the page or verify your API key.';
28697
- break;
28698
- case 403:
28699
- message = 'Access to this widget is restricted. Please contact the site owner if you believe this is an error.';
28700
- break;
28701
- case 404:
28702
- message = 'We could not find this widget. It may have been removed.';
28703
- break;
28704
- default:
28705
- if (error.status >= 500) {
28706
- message = 'The server encountered an error. Please try again shortly.';
28707
- }
28708
- else if (error.status > 0) {
28709
- message = error.message || 'Something went wrong. Please try again.';
29395
+ function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate, createStreamState, registerCallback) {
29396
+ // Find all incomplete actions and register resume callbacks
29397
+ for (const message of messages) {
29398
+ if (message.action && !message.action.done) {
29399
+ const toolCallId = message.action.toolCallId;
29400
+ const toolName = message.message.name || message.toolExecuting || "tool";
29401
+ registerCallback(toolCallId, async (newState) => {
29402
+ // When user interacts with the action after reload, continue the stream
29403
+ try {
29404
+ // Update the action message with the new state and check completion
29405
+ setState(prev => ({
29406
+ ...prev,
29407
+ messages: prev.messages.map(m => {
29408
+ if (m.action?.toolCallId !== toolCallId) {
29409
+ return m;
29410
+ }
29411
+ if (!m.action) {
29412
+ return m;
29413
+ }
29414
+ return { ...m, action: { ...m.action, state: newState } };
29415
+ }),
29416
+ isTyping: true,
29417
+ }));
29418
+ const streamState = createStreamState();
29419
+ // Continue the agent stream with the new state
29420
+ for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
29421
+ if (event.type === "done") {
29422
+ finalizeToolMessage(streamState, setState, toolCallId, toolName);
29423
+ streamState.sources = event.sources;
29424
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
29425
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
29426
+ continue;
29427
+ }
29428
+ if (event.type === "error") {
29429
+ const errorMessage = {
29430
+ id: generateMessageId(),
29431
+ message: {
29432
+ role: "assistant",
29433
+ content: "Sorry, an error occurred. Please try again later.",
29434
+ },
29435
+ timestamp: new Date().toISOString(),
29436
+ sources: [],
29437
+ isError: true,
29438
+ };
29439
+ upsertMessage(setState, errorMessage, false);
29440
+ setState(prev => ({ ...prev, isTyping: false }));
29441
+ return;
29442
+ }
29443
+ handleStreamEvent(event, streamState, onMessageUpdate, setState);
29444
+ }
29445
+ setState(prev => ({ ...prev, isTyping: false }));
28710
29446
  }
28711
- else {
28712
- message = error.message || 'Unable to connect to the server. Please check your internet connection.';
29447
+ catch (error) {
29448
+ console.error("[Action Resume] Failed to continue stream:", error);
29449
+ setState(prev => ({ ...prev, isTyping: false }));
28713
29450
  }
29451
+ });
28714
29452
  }
28715
- return { message, retryAfterSeconds, status: error.status };
28716
- }
28717
- if (error instanceof Error) {
28718
- const lower = error.message.toLowerCase();
28719
- if (lower.includes('network')) {
28720
- return { message: 'Unable to connect to the server. Please check your internet connection.' };
28721
- }
28722
- if (lower.includes('timeout')) {
28723
- return { message: 'The request timed out. Please try again.' };
28724
- }
28725
- if (lower.includes('unauthorized') || lower.includes('401')) {
28726
- return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
28727
- }
28728
- if (lower.includes('internal server error') || lower.includes('500')) {
28729
- return { message: 'The server encountered an error. Please try again shortly.' };
28730
- }
28731
- return { message: error.message || 'Something went wrong. Please try again.' };
28732
29453
  }
28733
- return { message: 'Something went wrong. Please try again.' };
28734
29454
  }
29455
+
29456
+ /**
29457
+ * useChat Hook
29458
+ * Main state management for chat functionality
29459
+ */
29460
+ // Initialize action handlers immediately to prevent tree-shaking
29461
+ initializeActionHandlers();
28735
29462
  function useChat(options) {
28736
29463
  const { widgetId, apiUrl, currentRoute, onMessage, onError, skipInitialization = false, } = options;
28737
29464
  const [state, setState] = useState({
@@ -28740,27 +29467,24 @@ function useChat(options) {
28740
29467
  isLoading: false,
28741
29468
  isTyping: false,
28742
29469
  error: null,
28743
- conversationId: '', // Will be set after loading conversation
29470
+ conversationId: '',
28744
29471
  config: null,
28745
29472
  });
28746
29473
  const stateRef = useRef(state);
28747
29474
  useEffect(() => {
28748
29475
  stateRef.current = state;
28749
29476
  }, [state]);
28750
- // Chat history state
28751
29477
  const [conversations, setConversations] = useState([]);
28752
- // Stream cancellation and rate limiting
28753
29478
  const abortControllerRef = useRef(null);
29479
+ const currentRequestIdRef = useRef(null);
28754
29480
  const lastNewChatTimeRef = useRef(0);
28755
- const NEW_CHAT_COOLDOWN_MS = 5000; // 2 second cooldown between new chats
29481
+ const NEW_CHAT_COOLDOWN_MS = 5000;
28756
29482
  const apiClient = useRef(new WidgetApiClient({ widgetId, apiUrl, currentRoute }));
28757
- // Update API client when currentRoute changes
28758
29483
  useEffect(() => {
28759
29484
  apiClient.current = new WidgetApiClient({ widgetId, apiUrl, currentRoute });
28760
29485
  }, [widgetId, apiUrl, currentRoute]);
28761
29486
  // Load configuration on mount and hydrate with existing conversation if available
28762
29487
  useEffect(() => {
28763
- // Skip initialization in preview mode
28764
29488
  if (skipInitialization) {
28765
29489
  return;
28766
29490
  }
@@ -28797,7 +29521,7 @@ function useChat(options) {
28797
29521
  }));
28798
29522
  // Setup resume callbacks for incomplete actions
28799
29523
  if (conversationId) {
28800
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }));
29524
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
28801
29525
  }
28802
29526
  }
28803
29527
  catch (error) {
@@ -28814,7 +29538,6 @@ function useChat(options) {
28814
29538
  initialize();
28815
29539
  return () => {
28816
29540
  isMounted = false;
28817
- // Cleanup resume callbacks
28818
29541
  state.messages.forEach(message => {
28819
29542
  if (message.action?.toolCallId) {
28820
29543
  unregisterActionResumeCallback(message.action.toolCallId);
@@ -28837,19 +29560,15 @@ function useChat(options) {
28837
29560
  const hasFiles = !!files && files.length > 0;
28838
29561
  if (!trimmedContent && !hasFiles)
28839
29562
  return;
28840
- // Block parallel streams - don't allow sending while already streaming
28841
29563
  if (stateRef.current.isTyping) {
28842
29564
  console.warn('[Widget] Cannot send message while streaming is in progress');
28843
29565
  return;
28844
29566
  }
28845
- // Cancel any existing stream before starting new one
28846
29567
  if (abortControllerRef.current) {
28847
29568
  abortControllerRef.current.abort();
28848
29569
  abortControllerRef.current = null;
28849
29570
  }
28850
- // Create new abort controller for this stream
28851
29571
  abortControllerRef.current = new AbortController();
28852
- // Strip [EXECUTE_ACTION:...] prefix from displayed message (but keep for API)
28853
29572
  const displayContent = trimmedContent.replace(/^\[EXECUTE_ACTION:[^\]]+\]\s*/, '');
28854
29573
  const userMessage = {
28855
29574
  id: generateMessageId(),
@@ -28860,12 +29579,11 @@ function useChat(options) {
28860
29579
  timestamp: new Date().toISOString(),
28861
29580
  sources: [],
28862
29581
  };
28863
- // Add user message immediately
28864
29582
  setState(prev => ({
28865
29583
  ...prev,
28866
29584
  messages: [...prev.messages, userMessage],
28867
- isLoading: false, // Don't show loading, will show typing when stream starts
28868
- isTyping: true, // Show typing indicator immediately
29585
+ isLoading: false,
29586
+ isTyping: true,
28869
29587
  error: null,
28870
29588
  }));
28871
29589
  onMessage?.(userMessage);
@@ -28905,26 +29623,27 @@ function useChat(options) {
28905
29623
  }
28906
29624
  catch (uploadError) {
28907
29625
  console.error('Failed to upload file:', uploadError);
28908
- // Continue with other files
28909
29626
  }
28910
29627
  }
28911
29628
  }
28912
- // Stream the response
28913
29629
  let lastStreamedMessage = null;
28914
29630
  const streamState = createStreamState();
28915
- // Capture the abort controller and conversation ID for this specific stream
29631
+ currentRequestIdRef.current = streamState.requestId;
28916
29632
  const currentAbortController = abortControllerRef.current;
28917
29633
  const streamConversationId = conversationId;
28918
- const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds);
29634
+ const streamRequestId = streamState.requestId;
29635
+ const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds, currentAbortController?.signal);
28919
29636
  for await (const event of stream) {
28920
- // Check if stream was aborted or conversation changed
28921
- if (currentAbortController?.signal.aborted || stateRef.current.conversationId !== streamConversationId) {
28922
- console.log('[Widget] Stream aborted or conversation changed, stopping event processing');
29637
+ if (currentAbortController?.signal.aborted ||
29638
+ stateRef.current.conversationId !== streamConversationId ||
29639
+ currentRequestIdRef.current !== streamRequestId) {
29640
+ console.log('[Widget] Stream aborted, conversation changed, or superseded by new request');
28923
29641
  break;
28924
29642
  }
28925
29643
  if (event.type === "action_request") {
28926
- // Check again before expensive operation
28927
- if (currentAbortController?.signal.aborted || stateRef.current.conversationId !== streamConversationId) {
29644
+ if (currentAbortController?.signal.aborted ||
29645
+ stateRef.current.conversationId !== streamConversationId ||
29646
+ currentRequestIdRef.current !== streamRequestId) {
28928
29647
  break;
28929
29648
  }
28930
29649
  await handleActionLoop(apiClient.current, event, streamState, (message) => {
@@ -28936,30 +29655,26 @@ function useChat(options) {
28936
29655
  lastStreamedMessage = message;
28937
29656
  }, setState);
28938
29657
  }
28939
- // Only finalize if this stream wasn't aborted
28940
- if (currentAbortController?.signal.aborted || stateRef.current.conversationId !== streamConversationId) {
28941
- console.log('[Widget] Stream was aborted, skipping finalization');
29658
+ if (currentAbortController?.signal.aborted ||
29659
+ stateRef.current.conversationId !== streamConversationId ||
29660
+ currentRequestIdRef.current !== streamRequestId) {
29661
+ console.log('[Widget] Stream was aborted or superseded, skipping finalization');
28942
29662
  return;
28943
29663
  }
28944
- // Stream completed - finalize state
28945
29664
  setState(prev => ({
28946
29665
  ...prev,
28947
29666
  isLoading: false,
28948
29667
  isTyping: false,
28949
29668
  }));
28950
- // Notify about final message
28951
29669
  if (lastStreamedMessage) {
28952
29670
  onMessage?.(lastStreamedMessage);
28953
29671
  }
28954
- // Generate follow-up suggestions asynchronously
28955
29672
  const enableFollowUps = state.config?.settings.enableFollowUpSuggestions !== false;
28956
29673
  const actionIds = state.config?.actions || [];
28957
29674
  if (enableFollowUps) {
28958
- // Don't await - let it run in background
28959
29675
  apiClient.current.generateFollowUps(stateRef.current.messages, actionIds)
28960
29676
  .then(suggestions => {
28961
29677
  if (suggestions.length > 0) {
28962
- // Attach suggestions to the last assistant message
28963
29678
  setState(prev => {
28964
29679
  const messages = [...prev.messages];
28965
29680
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -28988,7 +29703,7 @@ function useChat(options) {
28988
29703
  },
28989
29704
  timestamp: new Date().toISOString(),
28990
29705
  sources: [],
28991
- isError: !fallbackMessage, // Only mark as error if using default message
29706
+ isError: !fallbackMessage,
28992
29707
  };
28993
29708
  setState(prev => ({
28994
29709
  ...prev,
@@ -29000,9 +29715,6 @@ function useChat(options) {
29000
29715
  onError?.(err);
29001
29716
  }
29002
29717
  }, [state.conversationId, state.config, state.messages, onMessage, onError]);
29003
- /**
29004
- * Clear all messages
29005
- */
29006
29718
  const clearMessages = useCallback(() => {
29007
29719
  setState(prev => ({
29008
29720
  ...prev,
@@ -29015,9 +29727,6 @@ function useChat(options) {
29015
29727
  clearConversation(widgetId);
29016
29728
  }
29017
29729
  }, [widgetId, state.config?.settings.persistConversation]);
29018
- /**
29019
- * Submit feedback for a message
29020
- */
29021
29730
  const submitFeedback = useCallback(async (messageId, feedback) => {
29022
29731
  try {
29023
29732
  const message = state.messages.find(msg => msg.id === messageId);
@@ -29027,7 +29736,6 @@ function useChat(options) {
29027
29736
  : undefined;
29028
29737
  console.log('Submitting feedback:', { conversationId: state.conversationId, messageId, feedback });
29029
29738
  await apiClient.current.submitFeedback(state.conversationId, messageId, feedback, meta);
29030
- // Update message with feedback
29031
29739
  setState(prev => ({
29032
29740
  ...prev,
29033
29741
  messages: prev.messages.map(msg => msg.id === messageId
@@ -29042,9 +29750,6 @@ function useChat(options) {
29042
29750
  onError?.(err);
29043
29751
  }
29044
29752
  }, [state.conversationId, onError]);
29045
- /**
29046
- * Load conversation history list from localStorage
29047
- */
29048
29753
  const loadConversations = useCallback(() => {
29049
29754
  const persistConversation = state.config?.settings.persistConversation ?? true;
29050
29755
  if (!persistConversation || !isStorageAvailable()) {
@@ -29061,13 +29766,11 @@ function useChat(options) {
29061
29766
  })));
29062
29767
  }, [widgetId, state.config?.settings.persistConversation]);
29063
29768
  const switchConversation = useCallback(async (conversationId) => {
29064
- // Cancel any active stream before switching conversations
29065
29769
  if (abortControllerRef.current) {
29066
29770
  abortControllerRef.current.abort();
29067
29771
  abortControllerRef.current = null;
29068
29772
  }
29069
29773
  const persistConversation = state.config?.settings.persistConversation ?? true;
29070
- // First try to load from localStorage
29071
29774
  if (persistConversation && isStorageAvailable()) {
29072
29775
  const stored = loadConversationById(widgetId, conversationId);
29073
29776
  if (stored) {
@@ -29086,7 +29789,6 @@ function useChat(options) {
29086
29789
  try {
29087
29790
  const conversation = await apiClient.current.getOrCreateConversation(conversationId);
29088
29791
  const hydratedMessages = hydrateMessages(conversation.messages);
29089
- // Clear old resume callbacks
29090
29792
  state.messages.forEach(message => {
29091
29793
  if (message.action?.toolCallId) {
29092
29794
  unregisterActionResumeCallback(message.action.toolCallId);
@@ -29098,9 +29800,7 @@ function useChat(options) {
29098
29800
  messages: hydratedMessages,
29099
29801
  isLoading: false,
29100
29802
  }));
29101
- // Setup new resume callbacks
29102
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }));
29103
- // Save to local storage
29803
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
29104
29804
  if (persistConversation && isStorageAvailable()) {
29105
29805
  saveConversation(widgetId, conversation.id, hydratedMessages);
29106
29806
  }
@@ -29111,19 +29811,16 @@ function useChat(options) {
29111
29811
  }
29112
29812
  }, [widgetId, state.config?.settings.persistConversation]);
29113
29813
  const startNewConversation = useCallback(() => {
29114
- // Rate limiting - prevent spamming new chats
29115
29814
  const now = Date.now();
29116
29815
  if (now - lastNewChatTimeRef.current < NEW_CHAT_COOLDOWN_MS) {
29117
29816
  console.warn('[Widget] New chat rate limited - please wait');
29118
29817
  return;
29119
29818
  }
29120
29819
  lastNewChatTimeRef.current = now;
29121
- // Cancel any active stream before starting new conversation
29122
29820
  if (abortControllerRef.current) {
29123
29821
  abortControllerRef.current.abort();
29124
29822
  abortControllerRef.current = null;
29125
29823
  }
29126
- // Reset typing state if stream was active
29127
29824
  setState(prev => ({
29128
29825
  ...prev,
29129
29826
  messages: [],
@@ -29142,11 +29839,8 @@ function useChat(options) {
29142
29839
  if (!persistConversation || !isStorageAvailable()) {
29143
29840
  return;
29144
29841
  }
29145
- // Delete from storage
29146
29842
  deleteConversation(widgetId, conversationId);
29147
- // Update local state
29148
29843
  setConversations(prev => prev.filter(c => c.id !== conversationId));
29149
- // If we deleted the current conversation, clear it
29150
29844
  if (state.conversationId === conversationId) {
29151
29845
  setState(prev => ({
29152
29846
  ...prev,
@@ -29166,7 +29860,6 @@ function useChat(options) {
29166
29860
  sendMessage,
29167
29861
  clearMessages,
29168
29862
  submitFeedback,
29169
- // Chat history features
29170
29863
  conversations,
29171
29864
  loadConversations,
29172
29865
  switchConversation,
@@ -29175,11 +29868,20 @@ function useChat(options) {
29175
29868
  };
29176
29869
  }
29177
29870
 
29871
+ const ShieldIcon = () => (jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }), jsx("path", { d: "M9 12l2 2 4-4" })] }));
29872
+ const DataPolicyView = ({ config, widgetName, }) => {
29873
+ const headerTitle = widgetName || config?.appearance?.headerTitle || 'AI Assistant';
29874
+ const hasFileUpload = config?.settings?.enableFileUpload ?? false;
29875
+ const persistsConversation = config?.settings?.persistConversation ?? true;
29876
+ return (jsx("div", { className: "ai-chat-data-policy-view", children: jsxs("div", { className: "ai-chat-data-policy-content", children: [jsxs("div", { className: "ai-chat-data-policy-intro", children: [jsx("div", { className: "ai-chat-data-policy-icon", children: jsx(ShieldIcon, {}) }), jsxs("p", { children: ["Dieser Datenschutzhinweis informiert dich gem\u00E4\u00DF Art. 13 DSGVO dar\u00FCber, wie ", 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."] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Verantwortlicher / Kontakt" }), 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." })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Verarbeitete Daten (Kategorien)" }), jsxs("ul", { children: [jsxs("li", { children: [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 && (jsxs("li", { children: [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."] })), jsxs("li", { children: [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."] })] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Zwecke und Rechtsgrundlagen" }), jsxs("ul", { children: [jsxs("li", { children: [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)."] }), jsxs("li", { children: [jsx("strong", { children: "Qualit\u00E4tssicherung, Betrieb und Sicherheit" }), " (Art. 6 Abs. 1 lit. f DSGVO), z.B. zur Stabilit\u00E4t, Missbrauchserkennung und Fehlerbehebung."] }), jsxs("li", { children: [jsx("strong", { children: "Einwilligungsbasierte Verarbeitung" }), " kann erfolgen, sofern der Betreiber dies vorsieht (Art. 6 Abs. 1 lit. a DSGVO)."] })] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Empf\u00E4nger und Auftragsverarbeiter" }), jsxs("ul", { children: [jsxs("li", { children: [jsx("strong", { children: "Hosting/IT-Dienstleister:" }), " Der Betreiber kann Dienstleister f\u00FCr Hosting, Logging, Monitoring und Infrastruktur einsetzen."] }), jsxs("li", { children: [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)."] }), jsxs("li", { children: [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."] })] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Speicherdauer" }), jsxs("ul", { children: [persistsConversation ? (jsxs("li", { children: [jsx("strong", { children: "Chatverlauf:" }), " Der Chatverlauf kann gespeichert werden, um die Unterhaltung \u00FCber mehrere Sitzungen hinweg fortzusetzen."] })) : (jsxs("li", { children: [jsx("strong", { children: "Chatverlauf:" }), " Der Chatverlauf wird nicht dauerhaft gespeichert und wird beim Schlie\u00DFen des Chats beendet."] })), hasFileUpload && (jsxs("li", { children: [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."] })), jsxs("li", { children: [jsx("strong", { children: "Technische Protokolle:" }), " Technische Logdaten k\u00F6nnen f\u00FCr einen begrenzten Zeitraum gespeichert werden, um den sicheren Betrieb zu gew\u00E4hrleisten."] })] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Deine Rechte (Betroffenenrechte)" }), jsxs("ul", { children: [jsxs("li", { children: [jsx("strong", { children: "Auskunft" }), " (Art. 15 DSGVO)"] }), jsxs("li", { children: [jsx("strong", { children: "Berichtigung" }), " (Art. 16 DSGVO)"] }), jsxs("li", { children: [jsx("strong", { children: "L\u00F6schung" }), " (Art. 17 DSGVO) und ", jsx("strong", { children: "Einschr\u00E4nkung der Verarbeitung" }), " (Art. 18 DSGVO)"] }), jsxs("li", { children: [jsx("strong", { children: "Daten\u00FCbertragbarkeit" }), " (Art. 20 DSGVO), soweit anwendbar"] }), jsxs("li", { children: [jsx("strong", { children: "Widerspruch" }), " gegen Verarbeitungen auf Grundlage berechtigter Interessen (Art. 21 DSGVO)"] }), jsxs("li", { children: [jsx("strong", { children: "Beschwerderecht" }), " bei einer Datenschutzaufsichtsbeh\u00F6rde (Art. 77 DSGVO)"] })] }), 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." })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Wichtiger Hinweis" }), 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." })] })] }) }));
29877
+ };
29878
+
29178
29879
  const MenuIcon = () => (jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "4", y1: "10", x2: "20", y2: "10" }), jsx("line", { x1: "10", y1: "14", x2: "20", y2: "14" })] }));
29179
29880
  const PlusIcon = () => (jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })] }));
29180
29881
  const TrashIcon = () => (jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M3 6h18" }), jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }), jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })] }));
29181
29882
  const CloseIcon = () => (jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }));
29182
- const ChatWindow = ({ messages, isLoading, isTyping, error, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick,
29883
+ const BackIcon = () => (jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M19 12H5" }), jsx("path", { d: "M12 19l-7-7 7-7" })] }));
29884
+ const ChatWindow = ({ messages, isLoading, isTyping, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick,
29183
29885
  // Chat history props (only active when persistConversation is true)
29184
29886
  conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
29185
29887
  // Override props for live preview
@@ -29196,6 +29898,8 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
29196
29898
  const inputPlaceholder = placeholderOverride ?? appearance?.placeholder ?? 'Ask me anything...';
29197
29899
  // Track if history panel is open
29198
29900
  const [showHistory, setShowHistory] = useState(false);
29901
+ // Track if data policy view is open
29902
+ const [showDataPolicy, setShowDataPolicy] = useState(false);
29199
29903
  // Scroll button state (managed by MessageList)
29200
29904
  const [showScrollButton, setShowScrollButton] = useState(false);
29201
29905
  const [scrollToBottom, setScrollToBottom] = useState(null);
@@ -29205,6 +29909,13 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
29205
29909
  }, []);
29206
29910
  // History exit animation when starting a new chat from overview
29207
29911
  const [isHistoryExiting, setIsHistoryExiting] = useState(false);
29912
+ // Handle data policy click
29913
+ const handleDataPolicyClick = useCallback(() => {
29914
+ setShowDataPolicy(true);
29915
+ }, []);
29916
+ const handleDataPolicyBack = useCallback(() => {
29917
+ setShowDataPolicy(false);
29918
+ }, []);
29208
29919
  // Load conversations when history panel opens
29209
29920
  const handleOpenHistory = () => {
29210
29921
  setShowHistory(true);
@@ -29252,10 +29963,22 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
29252
29963
  // The backend will detect and trigger the action based on the message
29253
29964
  onSendMessage(question);
29254
29965
  };
29255
- return (jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''}`, children: showHistory ? (jsxs(Fragment, { children: [jsx("div", { className: "ai-chat-title", children: headerTitle }), jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsx(PlusIcon, {}) })] })) : (jsxs(Fragment, { children: [jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxs("div", { className: "ai-chat-header-actions", children: [canShowHistory && (jsx("button", { className: "ai-chat-header-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsx(MenuIcon, {}) })), jsx("button", { className: "ai-chat-close-button header-close-button", onClick: _onClose, "aria-label": "Close chat", children: jsx(CloseIcon, {}) })] })] })) }), showHistory ? (jsxs("div", { className: "ai-chat-history-panel", children: [conversations.length === 0 ? (jsx("div", { className: "ai-chat-history-empty", children: "No previous conversations" })) : (jsx("div", { className: `ai-chat-history-list ${isHistoryExiting ? 'exiting' : ''}`, children: conversations.map((conv) => (jsx("div", { className: `ai-chat-history-item ${conv.id === currentConversationId ? 'active' : ''}`, onClick: () => handleSelectConversation(conv.id), children: jsxs("div", { className: "ai-chat-history-item-content", children: [jsx("div", { className: "ai-chat-history-item-preview", children: conv.preview }), onDeleteConversation && (jsx("button", { className: "ai-chat-history-item-delete", onClick: (e) => {
29966
+ return (jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''} ${showDataPolicy ? 'is-data-policy' : ''}`, children: showDataPolicy ? (jsxs(Fragment, { children: [jsx("button", { className: "ai-chat-header-button", onClick: handleDataPolicyBack, "aria-label": "Back to chat", children: jsx(BackIcon, {}) }), jsx("div", { className: "ai-chat-title", children: "Datenschutzhinweis" })] })) : showHistory ? (jsxs(Fragment, { children: [jsx("div", { className: "ai-chat-title", children: headerTitle }), jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsx(PlusIcon, {}) })] })) : (jsxs(Fragment, { children: [jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxs("div", { className: "ai-chat-header-actions", children: [canShowHistory && (jsx("button", { className: "ai-chat-header-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsx(MenuIcon, {}) })), jsx("button", { className: "ai-chat-close-button header-close-button", onClick: _onClose, "aria-label": "Close chat", children: jsx(CloseIcon, {}) })] })] })) }), showDataPolicy ? (jsx(DataPolicyView, { config: config, onBack: handleDataPolicyBack, widgetName: headerTitle })) : showHistory ? (
29967
+ /* History Panel */
29968
+ jsxs("div", { className: "ai-chat-history-panel", children: [conversations.length === 0 ? (jsx("div", { className: "ai-chat-history-empty", children: "No previous conversations" })) : (jsx("div", { className: `ai-chat-history-list ${isHistoryExiting ? 'exiting' : ''}`, children: conversations.map((conv) => (jsx("div", { className: `ai-chat-history-item ${conv.id === currentConversationId ? 'active' : ''}`, onClick: () => handleSelectConversation(conv.id), children: jsxs("div", { className: "ai-chat-history-item-content", children: [jsx("div", { className: "ai-chat-history-item-preview", children: conv.preview }), onDeleteConversation && (jsx("button", { className: "ai-chat-history-item-delete", onClick: (e) => {
29256
29969
  e.stopPropagation();
29257
29970
  onDeleteConversation(conv.id);
29258
- }, "aria-label": "Delete conversation", children: jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload })] })) : (jsxs(Fragment, { children: [error && (jsx("div", { className: "ai-chat-error", role: "alert", children: error })), maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), jsx(MessageList, { messages: messages, isTyping: isTyping, showTypingIndicator: settings?.showTypingIndicator, showTimestamps: settings?.showTimestamps, showToolCalls: settings?.showToolCalls, enableFeedback: settings?.enableFeedback, welcomeTitle: welcomeTitle || 'Welcome Message', welcomeMessage: welcomeMessage, suggestedQuestions: suggestedQuestionsOverride ?? settings?.suggestedQuestions, accentColor: appearance?.primaryColor, onSuggestedQuestionClick: handleQuestionClick, onActionClick: onActionClick, onFeedback: onFeedback, onScrollStateChange: handleScrollStateChange, getActionRenderer: getActionRenderer }), jsx(ScrollButton, { onClick: () => scrollToBottom?.(), visible: showScrollButton }), jsx(MessageInput, { onSend: onSendMessage, placeholder: isLimitReached ? 'Message limit reached' : (isTyping ? 'Waiting for response...' : inputPlaceholder), disabled: isLoading || isTyping || isLimitReached, enableFileUpload: settings?.enableFileUpload })] }))] }));
29971
+ }, "aria-label": "Delete conversation", children: jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick })] })) : (jsxs(Fragment, { children: [maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), (() => {
29972
+ console.log('[DEBUG ChatWindow] Rendering MessageList with', messages.length, 'messages');
29973
+ messages.forEach((m, i) => {
29974
+ console.log(`[DEBUG ChatWindow] msg ${i}:`, { role: m.message.role, hasAction: !!m.action, impl: m.action?.implementation });
29975
+ });
29976
+ console.log('[DEBUG ChatWindow] getActionRenderer available:', !!getActionRenderer);
29977
+ if (getActionRenderer) {
29978
+ console.log('[DEBUG ChatWindow] Testing renderer for query-contact-directory:', !!getActionRenderer('query-contact-directory'));
29979
+ }
29980
+ return null;
29981
+ })(), jsx(MessageList, { messages: messages, isTyping: isTyping, showTypingIndicator: settings?.showTypingIndicator, showTimestamps: settings?.showTimestamps, showToolCalls: settings?.showToolCalls, enableFeedback: settings?.enableFeedback, welcomeTitle: welcomeTitle || 'Welcome Message', welcomeMessage: welcomeMessage, suggestedQuestions: suggestedQuestionsOverride ?? settings?.suggestedQuestions, accentColor: appearance?.primaryColor, onSuggestedQuestionClick: handleQuestionClick, onActionClick: onActionClick, onFeedback: onFeedback, onScrollStateChange: handleScrollStateChange, getActionRenderer: getActionRenderer }), jsx(ScrollButton, { onClick: () => scrollToBottom?.(), visible: showScrollButton }), jsx(MessageInput, { onSend: onSendMessage, placeholder: isLimitReached ? 'Message limit reached' : (isTyping ? 'Waiting for response...' : inputPlaceholder), disabled: isLoading || isTyping || isLimitReached, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick })] }))] }));
29259
29982
  };
29260
29983
 
29261
29984
  /**
@@ -29661,7 +30384,7 @@ function styleInject(css, ref) {
29661
30384
  if ( ref === void 0 ) ref = {};
29662
30385
  var insertAt = ref.insertAt;
29663
30386
 
29664
- if (typeof document === 'undefined') { return; }
30387
+ if (!css || typeof document === 'undefined') { return; }
29665
30388
 
29666
30389
  var head = document.head || document.getElementsByTagName('head')[0];
29667
30390
  var style = document.createElement('style');
@@ -29684,7 +30407,10 @@ function styleInject(css, ref) {
29684
30407
  }
29685
30408
  }
29686
30409
 
29687
- var css_248z = ".ai-chat-message{animation:ai-chat-message-appear .2s var(--chat-ease-bounce);max-width:85%}.ai-chat-message-content{border-radius:var(--chat-radius-bubble,14px);font-size:var(--chat-text-md,15px);line-height:var(--chat-line-relaxed,1.6);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-message.user .ai-chat-message-content{background:var(--chat-user-bg,#f4f3f0);border-bottom-right-radius:var(--chat-radius-sm,4px);color:var(--chat-user-text,#000)}.ai-chat-message.assistant .ai-chat-message-content{background:var(--chat-assistant-bg,transparent);color:var(--chat-assistant-text,#000)}.ai-chat-message-timestamp{color:var(--chat-text-muted,#71717a);font-size:var(--chat-text-xs,12px);margin-top:var(--chat-space-xs,4px);padding:0 var(--chat-space-xs,4px)}.ai-chat-message.streaming .ai-chat-message-content:after{animation:ai-chat-cursor-blink .8s infinite;content:\"▋\";margin-left:2px;opacity:.7}@keyframes ai-chat-message-appear{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-cursor-blink{0%,50%{opacity:1}51%,to{opacity:0}}.ai-chat-message.fullpage .ai-chat-message-content{font-size:var(--chat-text-lg,18px);padding:var(--chat-space-md,16px) var(--chat-space-lg,24px)}.ai-chat-typing{gap:var(--chat-space-xs,4px);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-typing-dot{background:var(--chat-text-muted,#71717a)}.ai-chat-tool-gear{color:var(--text-primary,#3e3e3e)}.ai-chat-tool-gear.spinning{animation:ai-chat-spin 1.5s linear infinite}.ai-chat-tool-badge{border-radius:8px}.ai-chat-tool-badge.loading{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-tool-badge.error{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-tool-check{color:#22c55e;flex-shrink:0}.ai-chat-tool-error{color:#ef4444;flex-shrink:0}.ai-chat-tool-badge .tool-name{max-width:150px;overflow:hidden;text-overflow:ellipsis}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear{color:#fff}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-badge.error,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge.error,.dark .ai-chat-tool-badge.error,[data-theme=dark] .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}.chakra-ui-dark .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.chakra-ui-dark .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.chakra-ui-dark .ai-chat-tool-badge.error,html.dark .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}@keyframes ai-chat-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.ai-chat-action-skeleton-item{animation:ai-chat-skeleton-pulse 1.5s ease-in-out infinite;background:var(--bg-secondary,#e5e7eb)}.ai-chat-widget.dark .ai-chat-action-skeleton-item,.chakra-ui-dark .ai-chat-action-skeleton-item,.dark .ai-chat-action-skeleton-item,[data-theme=dark] .ai-chat-action-skeleton-item{background:hsla(0,0%,100%,.1)}.ai-chat-action-skeleton-content{display:flex;flex-direction:column;gap:16px}.ai-chat-action-skeleton-header{align-items:center;display:flex;gap:10px}.ai-chat-action-skeleton-box{background:rgba(0,0,0,.08);border-radius:10px;display:flex;flex-direction:column;gap:8px;padding:14px}.ai-chat-widget.dark .ai-chat-action-skeleton-box,.chakra-ui-dark .ai-chat-action-skeleton-box,.dark .ai-chat-action-skeleton-box,[data-theme=dark] .ai-chat-action-skeleton-box{background:rgba(0,0,0,.25)}.ai-chat-action-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border:none;border-radius:var(--radius-lg,12px);box-sizing:border-box;margin-top:var(--space-sm,8px);max-width:100%;padding:var(--space-md,16px);transition:all var(--duration-normal,.25s) ease;width:100%}.ai-chat-widget.dark .ai-chat-action-card,.chakra-ui-dark .ai-chat-action-card,.dark .ai-chat-action-card,[data-theme=dark] .ai-chat-action-card{background:var(--bg-secondary,#3a3a3a)}.ai-chat-action-booked{background:var(--bg-secondary,#f4f4f4);border:none}.ai-chat-widget.dark .ai-chat-action-booked,.chakra-ui-dark .ai-chat-action-booked,.dark .ai-chat-action-booked,[data-theme=dark] .ai-chat-action-booked{background:var(--bg-secondary,#3a3a3a)}.ai-chat-action-header{align-items:center;color:var(--text-primary,#3e3e3e);display:flex;font-size:var(--text-md,15px);font-weight:var(--font-weight-semibold,600);gap:var(--space-sm,8px);margin-bottom:var(--space-md,16px)}.ai-chat-widget.dark .ai-chat-action-header,.chakra-ui-dark .ai-chat-action-header,.dark .ai-chat-action-header,[data-theme=dark] .ai-chat-action-header{color:var(--text-primary,#fff)}.ai-chat-action-icon{color:var(--action-accent,var(--primary-color,#3b82f6));flex-shrink:0;height:20px;width:20px}.ai-chat-action-success-icon-wrapper{align-items:center;background:var(--action-accent,var(--primary-color,#22c55e));border-radius:50%;color:#fff;display:flex;flex-shrink:0;height:24px;justify-content:center;width:24px}.ai-chat-action-icon-success{color:currentColor;height:14px;width:14px}.ai-chat-action-detail-box{background:var(--bg-primary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-md,8px);display:flex;flex-direction:column;gap:4px;padding:12px 16px}.ai-chat-widget.dark .ai-chat-action-detail-box,.chakra-ui-dark .ai-chat-action-detail-box,.dark .ai-chat-action-detail-box,[data-theme=dark] .ai-chat-action-detail-box{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.05)}.ai-chat-action-label-small{color:var(--text-muted,#71717a);font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.ai-chat-action-value-large{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:500}.ai-chat-widget.dark .ai-chat-action-value-large,.chakra-ui-dark .ai-chat-action-value-large,.dark .ai-chat-action-value-large,[data-theme=dark] .ai-chat-action-value-large{color:#fff}.ai-chat-action-link-button{align-items:center;background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;box-sizing:border-box;color:#fff;display:flex;font-size:14px;font-weight:600;gap:6px;justify-content:center;margin-top:8px;padding:12px;text-decoration:none;transition:all .2s ease;width:100%}.ai-chat-action-link-button:hover{opacity:.9;transform:translateY(-1px)}.ai-chat-action-body{display:flex;flex-direction:column;gap:var(--space-md,16px)}.ai-chat-action-field{display:flex;flex-direction:column;gap:var(--space-xs,6px)}.ai-chat-action-label{color:var(--text-secondary,#6b7280);font-size:var(--text-sm,13px);font-weight:var(--font-weight-medium,500)}.ai-chat-widget.dark .ai-chat-action-label,.chakra-ui-dark .ai-chat-action-label,.dark .ai-chat-action-label,[data-theme=dark] .ai-chat-action-label{color:var(--text-secondary,#a1a1aa)}.ai-chat-action-input{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);font-size:var(--text-sm,13px);outline:none;padding:10px 12px;transition:border-color .2s ease,box-shadow .2s ease}.ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-action-input::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-action-input,.chakra-ui-dark .ai-chat-action-input,.dark .ai-chat-action-input,[data-theme=dark] .ai-chat-action-input{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-input:focus,.chakra-ui-dark .ai-chat-action-input:focus,.dark .ai-chat-action-input:focus,[data-theme=dark] .ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-action-date-grid{display:grid;gap:var(--space-xs,6px);grid-template-columns:repeat(auto-fill,minmax(90px,1fr))}.ai-chat-action-date-btn{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;font-size:var(--text-xs,12px);font-weight:var(--font-weight-medium,500);padding:8px 10px;text-align:center;transition:all .15s ease}.ai-chat-action-date-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-date-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-action-date-btn,.chakra-ui-dark .ai-chat-action-date-btn,.dark .ai-chat-action-date-btn,[data-theme=dark] .ai-chat-action-date-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-date-btn:hover,.chakra-ui-dark .ai-chat-action-date-btn:hover,.dark .ai-chat-action-date-btn:hover,[data-theme=dark] .ai-chat-action-date-btn:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-action-date-btn.active,.chakra-ui-dark .ai-chat-action-date-btn.active,.dark .ai-chat-action-date-btn.active,[data-theme=dark] .ai-chat-action-date-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-action-time-grid{display:grid;gap:var(--space-xs,6px);grid-template-columns:repeat(auto-fill,minmax(100px,1fr))}.ai-chat-action-time-btn{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;font-size:var(--text-xs,12px);font-weight:var(--font-weight-medium,500);padding:8px 10px;text-align:center;transition:all .15s ease}.ai-chat-action-time-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-time-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-action-time-btn,.chakra-ui-dark .ai-chat-action-time-btn,.dark .ai-chat-action-time-btn,[data-theme=dark] .ai-chat-action-time-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-time-btn:hover,.chakra-ui-dark .ai-chat-action-time-btn:hover,.dark .ai-chat-action-time-btn:hover,[data-theme=dark] .ai-chat-action-time-btn:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-action-time-btn.active,.chakra-ui-dark .ai-chat-action-time-btn.active,.dark .ai-chat-action-time-btn.active,[data-theme=dark] .ai-chat-action-time-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-action-button{background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;color:#fff;cursor:pointer;font-size:var(--text-sm,13px);font-weight:var(--font-weight-semibold,600);padding:12px 16px;transition:all .2s ease;width:100%}.ai-chat-action-button:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}.ai-chat-action-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-action-error{background:rgba(239,68,68,.1);border-radius:var(--radius-md,8px);color:#dc2626;font-size:var(--text-sm,13px);padding:10px 12px}.ai-chat-widget.dark .ai-chat-action-error,.chakra-ui-dark .ai-chat-action-error,.dark .ai-chat-action-error,[data-theme=dark] .ai-chat-action-error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-action-hint{color:var(--text-muted,#9ca3af);font-size:var(--text-sm,13px);padding:var(--space-sm,8px);text-align:center}.ai-chat-link-preview{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-lg,12px);cursor:pointer;display:flex;flex-direction:column;margin-top:var(--space-sm,8px);overflow:hidden;position:relative;transition:border-color .2s,box-shadow .2s,transform .2s}.ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 8px rgba(0,0,0,.1);transform:translateY(-1px)}.ai-chat-link-preview:focus{border-color:var(--action-accent);box-shadow:0 0 0 2px rgba(59,130,246,.2);outline:none}.ai-chat-widget.dark .ai-chat-link-preview,.chakra-ui-dark .ai-chat-link-preview,.dark .ai-chat-link-preview,[data-theme=dark] .ai-chat-link-preview{background:var(--bg-secondary,#3a3a3a);border-color:hsla(0,0%,100%,.08)}.ai-chat-widget.dark .ai-chat-link-preview:hover,.chakra-ui-dark .ai-chat-link-preview:hover,.dark .ai-chat-link-preview:hover,[data-theme=dark] .ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 12px rgba(0,0,0,.3)}.ai-chat-link-preview__image{aspect-ratio:1.91/1;background:var(--bg-muted,#e5e7eb);overflow:hidden;width:100%}.ai-chat-widget.dark .ai-chat-link-preview__image,.chakra-ui-dark .ai-chat-link-preview__image,.dark .ai-chat-link-preview__image,[data-theme=dark] .ai-chat-link-preview__image{background:hsla(0,0%,100%,.05)}.ai-chat-link-preview__image img{height:100%;object-fit:cover;width:100%}.ai-chat-link-preview__content{flex:1;padding:12px}.ai-chat-link-preview__site{align-items:center;display:flex;gap:6px;margin-bottom:6px}.ai-chat-link-preview__favicon{border-radius:2px;flex-shrink:0;height:16px;width:16px}.ai-chat-link-preview__domain{color:var(--text-muted,#71717a);font-size:12px;letter-spacing:.5px;overflow:hidden;text-overflow:ellipsis;text-transform:uppercase;white-space:nowrap}.ai-chat-link-preview__title{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-primary,#3e3e3e);display:-webkit-box;font-size:15px;font-weight:600;line-height:1.3;margin:0 0 4px;overflow:hidden}.ai-chat-widget.dark .ai-chat-link-preview__title,.chakra-ui-dark .ai-chat-link-preview__title,.dark .ai-chat-link-preview__title,[data-theme=dark] .ai-chat-link-preview__title{color:#fff}.ai-chat-link-preview__description{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-muted,#71717a);display:-webkit-box;font-size:13px;line-height:1.4;margin:0;overflow:hidden}.ai-chat-link-preview__context{border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin:8px 0 0;padding-top:8px}.ai-chat-widget.dark .ai-chat-link-preview__context,.chakra-ui-dark .ai-chat-link-preview__context,.dark .ai-chat-link-preview__context,[data-theme=dark] .ai-chat-link-preview__context{border-color:hsla(0,0%,100%,.08)}.ai-chat-link-preview__arrow{align-items:center;background:var(--bg-primary,#fff);border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.1);color:var(--text-muted,#71717a);display:flex;height:28px;justify-content:center;opacity:0;position:absolute;right:12px;top:12px;transition:opacity .2s,background .2s;width:28px}.ai-chat-link-preview:hover .ai-chat-link-preview__arrow{opacity:1}.ai-chat-widget.dark .ai-chat-link-preview__arrow,.chakra-ui-dark .ai-chat-link-preview__arrow,.dark .ai-chat-link-preview__arrow,[data-theme=dark] .ai-chat-link-preview__arrow{background:hsla(0,0%,100%,.1);color:#fff}.ai-chat-link-preview--error{border-color:rgba(239,68,68,.3)}.ai-chat-link-preview--error:hover{border-color:rgba(239,68,68,.5)}.ai-chat-link-preview__error-text{color:#dc2626;font-size:12px;margin:4px 0 0}.ai-chat-widget.dark .ai-chat-link-preview__error-text,.chakra-ui-dark .ai-chat-link-preview__error-text,.dark .ai-chat-link-preview__error-text,[data-theme=dark] .ai-chat-link-preview__error-text{color:#fca5a5}.ai-chat-video-player{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border-radius:var(--radius-lg,12px);display:flex;flex-direction:column;margin-top:var(--space-sm,8px);overflow:hidden}.ai-chat-widget.dark .ai-chat-video-player,.chakra-ui-dark .ai-chat-video-player,.dark .ai-chat-video-player,[data-theme=dark] .ai-chat-video-player{background:var(--bg-secondary,#3a3a3a)}.ai-chat-video-player__header{align-items:center;color:var(--action-accent,var(--primary-color,#3b82f6));display:flex;gap:8px;padding:12px 12px 8px}.ai-chat-video-player__title{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:600}.ai-chat-widget.dark .ai-chat-video-player__title,.chakra-ui-dark .ai-chat-video-player__title,.dark .ai-chat-video-player__title,[data-theme=dark] .ai-chat-video-player__title{color:#fff}.ai-chat-video-player__container{aspect-ratio:16/9;background:#000;position:relative;width:100%}.ai-chat-video-player__thumbnail{cursor:pointer;height:100%;position:relative;width:100%}.ai-chat-video-player__thumbnail img{height:100%;object-fit:cover;width:100%}.ai-chat-video-player__placeholder{align-items:center;background:linear-gradient(135deg,#1a1a2e,#16213e);cursor:pointer;display:flex;flex-direction:column;gap:8px;height:100%;justify-content:center;position:relative;width:100%}.ai-chat-video-player__click-text{color:hsla(0,0%,100%,.7);font-size:13px}.ai-chat-video-player__play-btn{align-items:center;background:rgba(0,0,0,.7);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:64px;justify-content:center;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s,transform .2s;width:64px}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn{left:auto;position:relative;top:auto;transform:none}.ai-chat-video-player__play-btn:hover{background:rgba(0,0,0,.9);transform:translate(-50%,-50%) scale(1.05)}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn:hover{transform:scale(1.05)}.ai-chat-video-player__provider-badge{background:rgba(0,0,0,.8);border-radius:4px;bottom:8px;color:#fff;font-size:11px;font-weight:600;letter-spacing:.5px;padding:4px 8px;position:absolute;right:8px;text-transform:uppercase}.ai-chat-video-player__iframe,.ai-chat-video-player__video{border:none;height:100%;left:0;position:absolute;top:0;width:100%}.ai-chat-video-player__error{align-items:center;background:rgba(239,68,68,.1);color:#dc2626;display:flex;font-size:13px;height:100%;justify-content:center;padding:16px;text-align:center;width:100%}.ai-chat-widget.dark .ai-chat-video-player__error,.chakra-ui-dark .ai-chat-video-player__error,.dark .ai-chat-video-player__error,[data-theme=dark] .ai-chat-video-player__error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-video-player__context{border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-muted,#71717a);font-size:12px;font-style:italic;padding:10px 12px}.ai-chat-widget.dark .ai-chat-video-player__context,.chakra-ui-dark .ai-chat-video-player__context,.dark .ai-chat-video-player__context,[data-theme=dark] .ai-chat-video-player__context{border-color:hsla(0,0%,100%,.08)}.ai-chat-location-card{background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:12px;overflow:hidden}.ai-chat-widget.dark .ai-chat-location-card,.chakra-ui-dark .ai-chat-location-card,.dark .ai-chat-location-card,[data-theme=dark] .ai-chat-location-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-location-card--compact{border-radius:10px}.ai-chat-location-card--error{color:var(--text-muted,#71717a);padding:16px;text-align:center}.ai-chat-location-card__map{background:var(--bg-muted,#f4f4f5);position:relative;width:100%}.ai-chat-widget.dark .ai-chat-location-card__map,.chakra-ui-dark .ai-chat-location-card__map,.dark .ai-chat-location-card__map,[data-theme=dark] .ai-chat-location-card__map{background:rgba(0,0,0,.2)}.ai-chat-location-card__map iframe{border:none;display:block;height:100%;width:100%}.ai-chat-location-card__content{padding:14px}.ai-chat-location-card--compact .ai-chat-location-card__content{padding:12px}.ai-chat-location-card__header{align-items:center;display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.ai-chat-location-card__name{color:var(--text-primary,#18181b);flex:1;font-size:16px;font-weight:600;margin:0;min-width:0}.ai-chat-widget.dark .ai-chat-location-card__name,.chakra-ui-dark .ai-chat-location-card__name,.dark .ai-chat-location-card__name,[data-theme=dark] .ai-chat-location-card__name{color:#fff}.ai-chat-location-card--compact .ai-chat-location-card__name{font-size:14px}.ai-chat-location-card__type{background:var(--bg-muted,#f4f4f5);border-radius:10px;color:var(--text-muted,#71717a);font-size:11px;font-weight:500;letter-spacing:.5px;padding:2px 8px;text-transform:uppercase}.ai-chat-widget.dark .ai-chat-location-card__type,.chakra-ui-dark .ai-chat-location-card__type,.dark .ai-chat-location-card__type,[data-theme=dark] .ai-chat-location-card__type{background:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.7)}.ai-chat-location-card__status{border-radius:12px;font-size:12px;font-weight:500;padding:2px 8px}.ai-chat-location-card__status--open{background:#dcfce7;color:#16a34a}.ai-chat-location-card__status--closed{background:#fef2f2;color:#dc2626}.ai-chat-widget.dark .ai-chat-location-card__status--open,.chakra-ui-dark .ai-chat-location-card__status--open,.dark .ai-chat-location-card__status--open,[data-theme=dark] .ai-chat-location-card__status--open{background:rgba(34,197,94,.2);color:#4ade80}.ai-chat-widget.dark .ai-chat-location-card__status--closed,.chakra-ui-dark .ai-chat-location-card__status--closed,.dark .ai-chat-location-card__status--closed,[data-theme=dark] .ai-chat-location-card__status--closed{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-location-card__address{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__address svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__hours{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;margin-bottom:8px}.ai-chat-location-card__hours svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__hours-list{flex:1}.ai-chat-location-card__hours-toggle{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;font:inherit;gap:4px;padding:0}.ai-chat-location-card__hours-toggle:hover{text-decoration:underline}.ai-chat-location-card__hours-full{list-style:none;margin:8px 0 0;padding:0}.ai-chat-location-card__hours-full li{display:flex;font-size:12px;justify-content:space-between;padding:4px 0}.ai-chat-location-card__hours-today{color:var(--text-primary,#18181b);font-weight:600}.ai-chat-widget.dark .ai-chat-location-card__hours-today,.chakra-ui-dark .ai-chat-location-card__hours-today,.dark .ai-chat-location-card__hours-today,[data-theme=dark] .ai-chat-location-card__hours-today{color:#fff}.ai-chat-location-card__phone{align-items:center;background:none;border:none;color:var(--action-accent,#3b82f6);cursor:pointer;display:flex;font-size:13px;gap:6px;margin-bottom:12px;padding:0}.ai-chat-location-card__phone:hover{text-decoration:underline}.ai-chat-location-card__actions{display:flex;gap:8px;justify-content:flex-start;width:100%}.ai-chat-location-card__button{align-items:center;background:var(--action-accent,#3b82f6);border:none;border-radius:20px;color:#fff;cursor:pointer;display:flex;flex:1;font-size:13px;font-weight:500;gap:6px;justify-content:center;padding:10px 16px;transition:opacity .2s}.ai-chat-location-card__button:hover{opacity:.9}.ai-chat-location-card--compact .ai-chat-location-card__button{font-size:12px;padding:8px 12px}.ai-chat-location-card__link{align-items:center;background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:20px;color:var(--text-primary,#18181b);display:flex;font-size:13px;gap:6px;padding:10px 16px;text-decoration:none;transition:border-color .2s}.ai-chat-widget.dark .ai-chat-location-card__link,.chakra-ui-dark .ai-chat-location-card__link,.dark .ai-chat-location-card__link,[data-theme=dark] .ai-chat-location-card__link{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-location-card__link:hover{border-color:var(--action-accent,#3b82f6)}.ai-chat-location-card-list{display:flex;flex-direction:column;gap:8px}.ai-chat-location-card-list__header{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:13px;font-weight:500;gap:6px;margin-bottom:4px;padding:0 4px}.ai-chat-location-card-list__stack{display:grid;gap:12px;grid-template-columns:repeat(3,minmax(0,1fr))}@media (max-width:1200px){.ai-chat-location-card-list__stack{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:768px){.ai-chat-location-card-list__stack{grid-template-columns:1fr}}@media (max-width:520px){.ai-chat-location-card-list__stack{grid-template-columns:1fr!important}}@media (min-width:521px) and (max-width:900px){.ai-chat-location-card-list__stack{grid-template-columns:repeat(2,minmax(0,1fr))!important}}.ai-chat-location-card-list__grid{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}@media (max-width:400px){.ai-chat-location-card-list__grid{grid-template-columns:1fr}}.ai-chat-location-card-list__carousel{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;scroll-snap-type:x mandatory;scrollbar-width:none}.ai-chat-location-card-list__carousel::-webkit-scrollbar{display:none}.ai-chat-location-card-list__carousel>.ai-chat-location-card{flex:0 0 280px;scroll-snap-align:start}.ai-chat-widget,.chat-ui{--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--radius-2xl:18px;--radius-pill:9999px;--radius-window-top:22px;--radius-window-bottom:44px;--radius-window-gutter:16px;--radius-chat-bubble:14px;--radius-preset-badge:13px;--radius-history-item:14px;--radius-action-badge:8px;--radius-input:62px;--space-xs:4px;--space-sm:8px;--space-md:16px;--space-lg:24px;--space-xl:32px;--text-xs:12px;--text-sm:14px;--text-md:15px;--text-lg:18px;--text-xl:22px;--text-2xl:28px;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--line-height-tight:1.3;--line-height-normal:1.4;--line-height-relaxed:1.6;--bg-primary:#fff;--bg-secondary:#f4f4f4;--bg-tertiary:#e5e7eb;--bg-hover:#e5e7eb;--text-primary:#3e3e3e;--text-secondary:#000;--text-muted:#71717a;--text-placeholder:#a1a1aa;--border-default:#d3d3d3;--border-subtle:#e5e7eb;--border-muted:#f4f4f5;--user-bg:#f4f3f0;--user-text:#000;--user-bg-hover:#e8e7e4;--agent-bg:transparent;--agent-text:#000;--input-bg:#f4f4f4;--input-border:#d3d3d3;--input-text:#000;--btn-primary-bg:#151515;--btn-primary-text:#f4f4f4;--btn-secondary-bg:transparent;--btn-secondary-text:#71717a;--spring-bounce:cubic-bezier(0.34,1.56,0.64,1);--spring-smooth:cubic-bezier(0.4,0,0.2,1);--spring-snappy:cubic-bezier(0.2,0,0,1);--duration-fast:0.15s;--duration-normal:0.25s;--duration-slow:0.35s;--shadow-sm:0 1px 2px rgba(0,0,0,.05);--shadow-md:0 2px 8px rgba(0,0,0,.1);--shadow-lg:0 4px 16px rgba(0,0,0,.12);--shadow-window:0px 0px 15px 9px rgba(0,0,0,.1);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03)}.ai-chat-widget.dark,.chat-ui.dark{--bg-primary:#282625;--bg-secondary:#4a4846;--bg-tertiary:#484848;--bg-hover:#484848;--text-primary:#fff;--text-secondary:#fff;--text-muted:#a1a1aa;--text-placeholder:#71717a;--border-default:#5d5b5b;--border-subtle:#5d5b5b;--border-muted:#5d5b5b;--user-bg:#484848;--user-text:#fff;--user-bg-hover:#5a5a5a;--agent-bg:transparent;--agent-text:#fff;--input-bg:#4a4846;--input-border:#5d5b5b;--input-text:#fff;--btn-primary-bg:#fff;--btn-primary-text:#312f2d;--btn-secondary-bg:transparent;--btn-secondary-text:#a1a1aa;--shadow-window:0px 0px 15px 9px rgba(0,0,0,.2);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03);--shadow-input:0px 0px 10px rgba(0,0,0,.15)}.ai-chat-widget,.chat-ui{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.ai-chat-widget-container{font-size:var(--text-sm);line-height:1.5;position:fixed;z-index:9999}.ai-chat-widget-container.bottom-right{bottom:20px;right:20px}.ai-chat-widget-container.bottom-left{bottom:20px;left:20px}.ai-chat-widget-container.top-right{right:20px;top:20px}.ai-chat-widget-container.top-left{left:20px;top:20px}@keyframes ai-chat-window-open{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes ai-chat-window-close{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.9) translateY(20px)}}@keyframes ai-chat-message-slide-in{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-welcome-fade-in{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-typing-pulse{0%,60%,to{opacity:.4;transform:translateY(0) scale(1)}30%{opacity:1;transform:translateY(-4px) scale(1.1)}}@keyframes ai-chat-gear-spin{to{transform:rotate(1turn)}}@keyframes ai-chat-tool-active{0%,to{background:var(--bg-secondary);opacity:1}50%{background:var(--bg-tertiary);opacity:1}}@keyframes ai-chat-feedback-morph{0%{opacity:.5;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes ai-chat-checkmark-pop{0%{opacity:0;transform:scale(0) rotate(-45deg)}50%{transform:scale(1.3) rotate(0deg)}to{opacity:1;transform:scale(1) rotate(0deg)}}@keyframes ai-chat-history-exit{to{opacity:0;transform:translateY(-18px)}}@keyframes ai-chat-tool-gradient{0%{background-position:200% 0}to{background-position:-200% 0}}@media (max-width:480px){.ai-chat-widget-container.is-open{height:100vh!important;inset:0!important;width:100vw!important}.ai-chat-widget-container.is-open .ai-chat-window{animation:none!important;border-radius:0!important;height:100%!important;inset:0!important;max-height:100%!important;max-width:100%!important;position:absolute!important;width:100%!important}.ai-chat-widget-container.is-open .ai-chat-button{display:none!important;visibility:hidden!important}.ai-chat-header{padding-top:max(16px,env(safe-area-inset-top))}.ai-chat-input-container{padding-bottom:max(20px,env(safe-area-inset-bottom))}}.ai-chat-window{animation:ai-chat-window-open var(--duration-slow,.35s) var(--spring-bounce);background:var(--bg-primary,#fff);border:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) var(--radius-window-bottom,44px) var(--radius-window-bottom,44px);box-shadow:var(--shadow-window,0 0 15px 5px rgba(0,0,0,.08));display:flex;flex-direction:column;overflow:hidden;position:absolute;transform-origin:bottom right;z-index:2}.ai-chat-widget.dark .ai-chat-window{background:var(--bg-primary,#282625);border-color:var(--border-default,#5d5b5b);border-width:.7px}.ai-chat-window.closing{animation:ai-chat-window-close var(--duration-normal) var(--spring-smooth) forwards}.ai-chat-window.size-small{height:500px;width:380px}.ai-chat-window.size-medium,.ai-chat-window.size-small{max-height:calc(100vh - 100px);max-width:calc(100vw - 40px)}.ai-chat-window.size-medium{height:600px;width:420px}.ai-chat-window.size-large{height:700px;max-height:calc(100vh - 100px);max-width:calc(100vw - 40px);width:480px}.ai-chat-widget-container.bottom-right .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);right:0}.ai-chat-widget-container.bottom-left .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);left:0}.ai-chat-widget-container.top-right .ai-chat-window{right:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-widget-container.top-left .ai-chat-window{left:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-header{align-items:center;background:var(--bg-primary,#fff);border-bottom:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) 0 0;display:flex;justify-content:space-between;padding:18px var(--space-md,16px);position:relative;z-index:10}.ai-chat-widget.dark .ai-chat-header{background:var(--bg-primary,#282625);border-bottom-color:var(--border-default,#5d5b5b);border-bottom-width:.7px}.ai-chat-header.is-history{padding-left:var(--space-md)}.ai-chat-header.is-history .ai-chat-title{flex:1;min-width:0;overflow:hidden;padding-right:var(--space-lg);text-overflow:ellipsis;white-space:nowrap}.ai-chat-header-content{align-items:center;display:flex;flex:1;gap:var(--space-lg)}.ai-chat-header-actions{align-items:center;display:flex;gap:var(--space-sm)}.ai-chat-logo{border-radius:10px;height:36px;object-fit:cover;width:36px}.ai-chat-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-xl,22px);font-weight:var(--font-weight-bold,700);letter-spacing:-.02em}.ai-chat-widget.dark .ai-chat-title{color:var(--text-primary,#fff)}.ai-chat-close-button,.ai-chat-header-button{align-items:center;background:transparent;border:none;border-radius:var(--radius-md);color:var(--text-muted);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:32px}.ai-chat-close-button:hover,.ai-chat-header-button:hover{color:var(--text-primary)}.ai-chat-close-button:active,.ai-chat-header-button:active{transform:scale(.95)}.ai-chat-close-button svg,.ai-chat-header-button svg{height:22px;width:22px}.ai-chat-button{align-items:center;background:var(--button-color,var(--btn-primary-bg));border:1px solid var(--border-default,#d3d3d3);border-radius:50%;box-shadow:var(--shadow-button,0 0 15px 9px rgba(0,0,0,.03));color:var(--button-icon-color,var(--btn-primary-text));cursor:pointer;display:flex;height:var(--button-size,56px);justify-content:center;overflow:hidden;position:relative;transition:opacity var(--duration-fast) ease;width:var(--button-size,56px);z-index:1}.ai-chat-button:hover{opacity:.9}.ai-chat-button:active{opacity:.8}.ai-chat-button-svg{height:50%;min-height:24px;min-width:24px;transition:transform var(--duration-fast) ease;width:50%}.ai-chat-button.is-open .ai-chat-button-svg{transform:rotate(0deg)}.ai-chat-button-icon{font-size:1.5em;line-height:1}.ai-chat-input-container{background:linear-gradient(to bottom,transparent 0,var(--bg-primary,#fff) 50%,var(--bg-primary,#fff) 100%);bottom:0;left:0;padding-top:30px;position:absolute;right:0;z-index:10}.ai-chat-widget.dark .ai-chat-input-container{background:linear-gradient(to bottom,transparent 0,var(--bg-primary,#282625) 50%,var(--bg-primary,#282625) 100%)}.ai-chat-input-container.separate{padding:0 var(--radius-window-gutter,16px) var(--radius-window-gutter,16px);padding-top:30px}.ai-chat-input-wrapper{align-items:flex-end;background:var(--input-bg,#f4f4f4);border:1px solid var(--input-border,#d3d3d3);border-radius:var(--radius-input,62px);box-sizing:border-box;display:flex;gap:0;height:52px;overflow:hidden;padding:6px 6px 6px 16px;position:relative;transition:all var(--duration-fast,.15s) ease;z-index:5}.ai-chat-input-wrapper.multiline{border-radius:14px!important;min-height:64px;padding:10px 10px 10px 14px}.ai-chat-widget.dark .ai-chat-input-wrapper{background:var(--input-bg,#4a4846);border-color:var(--input-border,#5d5b5b);border-width:.7px;box-shadow:var(--shadow-input,0 0 10px rgba(0,0,0,.15))}.ai-chat-input-wrapper:focus-within{border-color:var(--text-muted,#a1a1aa)}.ai-chat-input{word-wrap:break-word!important;background:transparent!important;border:none!important;border-radius:0!important;box-shadow:none!important;box-sizing:border-box!important;color:var(--input-text,#000)!important;flex:1!important;font-family:inherit!important;font-size:var(--text-md,15px)!important;height:40px!important;line-height:20px!important;margin:0!important;max-height:40px!important;min-height:40px!important;min-width:0!important;outline:none!important;overflow-wrap:anywhere!important;overflow-x:hidden!important;overflow-y:auto!important;padding:10px var(--space-sm,8px)!important;resize:none!important;white-space:pre-wrap!important;width:0!important;word-break:break-word!important}.ai-chat-widget.dark .ai-chat-input{color:var(--input-text,#fff)}.ai-chat-input::placeholder{color:var(--text-placeholder,#a1a1aa)}.ai-chat-widget.dark .ai-chat-input::placeholder{color:var(--text-placeholder,#52525b)}.ai-chat-file-button{align-items:center;align-self:center;background:transparent;border:none;color:var(--text-placeholder);cursor:pointer;display:flex;flex-shrink:0;height:28px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:28px}.ai-chat-file-button:hover{color:var(--text-secondary)}.ai-chat-file-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-send-button{align-items:center;align-self:center;background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));border:none;border-radius:50%;color:var(--button-icon-color,var(--btn-primary-text,#f4f4f4));cursor:pointer;display:flex;flex-shrink:0;height:40px;justify-content:center;min-height:40px;min-width:40px;padding:0;transition:all var(--duration-fast,.15s) ease;width:40px}.ai-chat-widget.dark .ai-chat-send-button{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));color:var(--button-icon-color,var(--btn-primary-text,#f4f4f4))}.ai-chat-widget.dark .ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button:hover:not(:disabled){opacity:.8}.ai-chat-send-button:active:not(:disabled){transform:scale(.95)}.ai-chat-send-button:disabled{cursor:not-allowed;opacity:.3}.ai-chat-file-list{display:flex;flex-wrap:wrap;gap:var(--space-sm);padding:var(--space-sm) var(--space-sm)}.ai-chat-file-item{align-items:center;background:rgba(0,0,0,.05);border-radius:6px;display:flex;font-size:var(--text-xs);gap:var(--space-sm);padding:6px 10px}.ai-chat-file-extension{background:var(--btn-primary-bg);border-radius:3px;color:var(--btn-primary-text);display:inline-block;font-size:10px;font-weight:var(--font-weight-semibold);min-width:40px;padding:2px 6px;text-align:center;text-transform:uppercase}.ai-chat-file-info{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.ai-chat-file-name{font-weight:var(--font-weight-medium);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-file-size{color:var(--text-muted);font-size:10px;opacity:.7}.ai-chat-file-remove{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;justify-content:center;opacity:.5;padding:var(--space-xs);transition:opacity var(--duration-fast) ease}.ai-chat-file-remove:hover{opacity:1}.ai-chat-messages{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;align-items:stretch;background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;gap:var(--space-md,16px);justify-content:flex-start;overflow-x:hidden;overflow-y:auto;padding:var(--space-lg,24px) var(--space-md,16px) 100px;position:relative;scroll-behavior:smooth;scrollbar-width:none}.ai-chat-widget.dark .ai-chat-messages{background:var(--bg-primary,#18181b)}.ai-chat-messages::-webkit-scrollbar{display:none}.ai-chat-message{animation:ai-chat-message-slide-in .2s var(--spring-bounce);display:flex;flex-direction:column;max-width:90%}.ai-chat-message.user{align-items:flex-end;align-self:flex-end}.ai-chat-message.assistant{align-items:flex-start;align-self:flex-start;max-width:100%}.ai-chat-message.tool{align-self:flex-start;margin:0 -16px;max-width:100%;padding:0;width:calc(100% + 32px)}.ai-chat-message-content{word-wrap:break-word;border-radius:18px;font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);overflow-wrap:break-word;padding:8px 14px}.ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#f4f3f0);border-radius:18px;color:var(--user-text,#000)}.ai-chat-widget.dark .ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#484848);color:var(--user-text,#fff)}.ai-chat-message.assistant .ai-chat-message-content{background:var(--agent-bg,transparent);color:var(--agent-text,#000);padding:0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content{color:var(--agent-text,#fff)}.ai-chat-message-timestamp{color:var(--text-muted,#71717a);font-size:var(--text-xs,12px);margin-top:var(--space-xs,4px);padding:0 var(--space-xs,4px)}.ai-chat-welcome{animation:ai-chat-welcome-fade-in .3s var(--spring-smooth);display:flex;flex-direction:column;gap:var(--space-md,16px);padding:var(--space-lg,24px) 0}.ai-chat-welcome-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-2xl,28px);font-weight:var(--font-weight-bold,700);line-height:var(--line-height-tight,1.3)}.ai-chat-widget.dark .ai-chat-welcome-title{color:var(--text-primary,#fff)}.ai-chat-welcome-text{color:var(--text-secondary,#000);font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);max-width:100%}.ai-chat-widget.dark .ai-chat-welcome-text{color:var(--text-secondary,#fff)}.ai-chat-typing{align-items:center;display:flex;gap:var(--space-xs,4px);padding:var(--space-sm,8px) var(--space-md,16px)}.ai-chat-typing-dot{animation:ai-chat-typing-bounce 1.4s ease-in-out infinite both;background:var(--text-muted,#71717a);border-radius:50%;height:8px;width:8px}.ai-chat-typing-dot:first-child{animation-delay:-.32s}.ai-chat-typing-dot:nth-child(2){animation-delay:-.16s}.ai-chat-typing-dot:nth-child(3){animation-delay:0s}@keyframes ai-chat-typing-bounce{0%,80%,to{opacity:.4;transform:scale(.6)}40%{opacity:1;transform:scale(1)}}.ai-chat-scroll-button{align-items:center;background:var(--bg-secondary,#f4f4f5);border:1px solid var(--border-subtle,rgba(0,0,0,.1));border-radius:50%;bottom:80px;box-shadow:0 2px 8px rgba(0,0,0,.1);color:var(--text-secondary,#71717a);cursor:pointer;display:flex;height:36px;justify-content:center;left:50%;opacity:0;pointer-events:none;position:absolute;transform:translateX(-50%);transition:background .15s ease,box-shadow .15s ease,opacity .15s ease,visibility .15s ease;visibility:hidden;width:36px;z-index:15}.ai-chat-scroll-button.visible{opacity:1;pointer-events:auto;visibility:visible}.ai-chat-scroll-button:hover{background:var(--bg-tertiary,#e4e4e7);box-shadow:0 4px 12px rgba(0,0,0,.15)}.ai-chat-scroll-button:active{background:var(--bg-tertiary,#d4d4d8)}.ai-chat-widget.dark .ai-chat-scroll-button{background:var(--bg-secondary,#3f3f46);border-color:var(--border-subtle,hsla(0,0%,100%,.1));box-shadow:0 2px 8px rgba(0,0,0,.3);color:var(--text-secondary,#a1a1aa)}.ai-chat-widget.dark .ai-chat-scroll-button:hover{background:var(--bg-tertiary,#52525b);box-shadow:0 4px 12px rgba(0,0,0,.4)}.ai-chat-error{background:var(--bg-secondary);border-radius:var(--radius-chat-bubble);color:var(--text-primary);font-size:var(--text-md);margin:0 auto;padding:10px var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content p{margin:0 0 var(--space-sm) 0}.ai-chat-message.assistant .ai-chat-message-content p:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content ol,.ai-chat-message.assistant .ai-chat-message-content ul{margin:var(--space-sm) 0;padding-left:var(--space-lg)}.ai-chat-message.assistant .ai-chat-message-content li{margin-bottom:var(--space-xs)}.ai-chat-message.assistant .ai-chat-message-content code{background:rgba(0,0,0,.05);border-radius:var(--radius-sm);font-family:SF Mono,Monaco,Cascadia Code,monospace;font-size:.9em;padding:2px 6px}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content code{background:hsla(0,0%,100%,.1)}.ai-chat-message.assistant .ai-chat-message-content pre{background:rgba(0,0,0,.05);border-radius:var(--radius-md);margin:var(--space-sm) 0;overflow-x:auto;padding:var(--space-sm)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content pre{background:hsla(0,0%,100%,.05)}.ai-chat-message.assistant .ai-chat-message-content pre code{background:transparent;padding:0}.ai-chat-message.assistant .ai-chat-message-content a{color:var(--btn-primary-bg);text-decoration:underline}.ai-chat-message.assistant .ai-chat-message-content strong{font-weight:var(--font-weight-semibold)}.ai-chat-message.assistant .ai-chat-message-content blockquote{border-left:3px solid var(--border-default);color:var(--text-muted);margin:var(--space-sm) 0;padding-left:var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content hr{border:none;border-top:1px solid var(--border-subtle,rgba(0,0,0,.1));margin:var(--space-lg,24px) 0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content hr{border-top-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content table{border-collapse:collapse;font-size:var(--text-sm);margin:var(--space-sm) 0;width:100%}.ai-chat-message.assistant .ai-chat-message-content td,.ai-chat-message.assistant .ai-chat-message-content th{border:1px solid var(--border-subtle);padding:var(--space-sm);text-align:left}.ai-chat-message.assistant .ai-chat-message-content th{font-weight:var(--font-weight-semibold);white-space:nowrap}.ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:rgba(0,0,0,.02)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:hsla(0,0%,100%,.03)}.ai-chat-suggested-questions{align-self:flex-end;margin:0;padding:16px 0 0;width:100%}.ai-chat-suggested-questions-list{align-items:center;display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.ai-chat-suggested-question{align-items:center;background:transparent;border:1px solid var(--border-default,#d4d4d8);border-radius:var(--radius-preset-badge,18px);color:var(--text-primary,#18181b);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:background .15s ease,border-color .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-widget.dark .ai-chat-suggested-question{background:transparent;border-color:var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}.ai-chat-suggested-question-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-suggested-question:hover{background:var(--bg-hover,#f4f4f5);border-color:var(--border-default,#d4d4d8)}.ai-chat-widget.dark .ai-chat-suggested-question:hover{background:var(--bg-hover,#3f3f46);border-color:var(--border-subtle,#52525b)}.ai-chat-suggested-question:active{transform:scale(.98)}.ai-chat-suggested-question.action-type{border:none}.ai-chat-suggested-question.action-type,.ai-chat-widget.dark .ai-chat-suggested-question.action-type{background:var(--primary-color,var(--button-color,#ef4444));color:var(--button-icon-color,#fff)}.ai-chat-suggested-question.action-type:hover{background:var(--primary-color,var(--button-color,#ef4444));opacity:.9}.ai-chat-suggested-question-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-suggested-question:not(.action-type) .ai-chat-suggested-question-icon{display:none}.ai-chat-follow-up-suggestions{box-sizing:border-box;margin:0;padding:8px 16px 0;width:100%}.ai-chat-follow-up-list{align-items:flex-end;display:flex;flex-direction:column;gap:6px}.ai-chat-follow-up-item{align-items:center;border:none;border-radius:var(--radius-preset-badge,18px);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:opacity .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-follow-up-item,.ai-chat-widget.dark .ai-chat-follow-up-item{background:var(--primary-color,var(--button-color,#07f));color:var(--button-icon-color,#fff)}.ai-chat-follow-up-item:hover{opacity:.9}.ai-chat-follow-up-item:active{transform:scale(.98)}.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-default,#d4d4d8);color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type,.dark .ai-chat-follow-up-item.question-type,[data-theme=dark] .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}}.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#f4f4f5);opacity:1}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type:hover,.dark .ai-chat-follow-up-item.question-type:hover,[data-theme=dark] .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}}.ai-chat-follow-up-item.action-type{background:var(--primary-color,var(--button-color,#07f));border:none;color:var(--button-icon-color,#fff)}.ai-chat-follow-up-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-follow-up-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-feedback-buttons{align-items:center;display:flex;gap:var(--space-xs)}.ai-chat-feedback{align-items:center;display:inline-flex;gap:0;height:20px}.ai-chat-feedback-button{align-items:center;background:transparent!important;border:none;border-radius:var(--radius-sm);color:var(--text-placeholder);cursor:pointer;display:flex;font-size:var(--text-sm);height:20px;justify-content:center;padding:var(--space-xs);transition:all var(--duration-fast) var(--spring-bounce)}.ai-chat-feedback-button:hover:not(:disabled){background:none!important;color:var(--text-secondary)}.ai-chat-feedback-button:active:not(:disabled){transform:scale(.9)}.ai-chat-feedback-button:disabled{cursor:not-allowed;opacity:.4}.ai-chat-feedback-button.active{background:none!important;color:var(--text-primary)}.ai-chat-feedback.submitted{align-items:center;animation:ai-chat-feedback-morph .3s var(--spring-bounce);gap:var(--space-xs)}.ai-chat-feedback-message{align-items:center;display:flex;gap:4px;margin-left:var(--space-xxs)}.ai-chat-feedback-checkmark{animation:ai-chat-checkmark-pop .3s var(--spring-bounce);color:#10b981;font-size:var(--text-md);font-weight:700}.ai-chat-feedback-text{color:#10b981;font-size:var(--text-xs);font-weight:var(--font-weight-medium)}.ai-chat-history-panel{background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;overflow:hidden}.ai-chat-widget.dark .ai-chat-history-panel{background:var(--bg-primary,#18181b)}.ai-chat-history-empty,.ai-chat-history-loading{align-items:center;color:var(--text-muted);display:flex;flex:1;font-size:var(--text-sm);justify-content:center;padding:var(--space-lg);text-align:center}.ai-chat-history-list{-ms-overflow-style:none;display:flex;flex:1;flex-direction:column;gap:var(--space-sm);overflow-y:auto;padding:var(--space-xs) var(--space-md) 120px;scrollbar-width:none}.ai-chat-history-list::-webkit-scrollbar{display:none}.ai-chat-history-list.exiting{animation:ai-chat-history-exit .22s var(--spring-smooth) forwards}.ai-chat-history-item{align-items:center;background:var(--user-bg,#f4f4f5);border-radius:var(--radius-history-item,15px);display:flex;flex:0 0 auto;flex-direction:row;height:var(--history-item-height,36px);margin:0;overflow:hidden;transition:background var(--duration-fast,.15s) ease;width:100%}.ai-chat-history-item-content{align-items:center;background:transparent;border:none;cursor:pointer;display:flex;flex:1;flex-direction:row;height:100%;min-width:0;padding:0 var(--space-xs,4px) 0 var(--space-md,16px);text-align:left}.ai-chat-widget.dark .ai-chat-history-item{background:var(--user-bg,#27272a)}.ai-chat-history-item:hover{background:var(--user-bg-hover,#e5e7eb)}.ai-chat-widget.dark .ai-chat-history-item:hover{background:var(--user-bg-hover,#3f3f46)}.ai-chat-history-item.active{background:var(--user-bg-hover,#e5e7eb)}.ai-chat-widget.dark .ai-chat-history-item.active{background:var(--user-bg-hover,#3f3f46)}.ai-chat-history-item-preview{color:var(--text-primary,#18181b);flex:1;font-size:var(--text-sm,14px);font-weight:var(--font-weight-medium,500);line-height:var(--line-height-normal,1.4);margin-bottom:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-widget.dark .ai-chat-history-item-preview{color:var(--text-primary,#fafafa)}.ai-chat-history-item.active .ai-chat-history-item-preview{font-weight:var(--font-weight-medium)}.ai-chat-history-item-meta{display:none}.ai-chat-history-item-delete{align-items:center;background:transparent;border:none;border-radius:var(--radius-sm,6px);color:var(--text-muted,#71717a);cursor:pointer;display:flex;flex-shrink:0;height:24px;justify-content:center;margin-left:auto;margin-right:var(--space-xs,4px);opacity:0;transition:opacity var(--duration-fast,.15s) ease,background var(--duration-fast,.15s) ease,color var(--duration-fast,.15s) ease;width:24px}.ai-chat-history-item-delete svg{height:14px;width:14px}.ai-chat-history-item:hover .ai-chat-history-item-delete{opacity:1}.ai-chat-history-item-delete:hover{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-widget.dark .ai-chat-history-item-delete:hover{background:rgba(239,68,68,.2);color:#f87171}.ai-chat-tool-row{align-items:center;display:flex;gap:10px;margin:2px 0;padding:0 16px}.ai-chat-tool-gear{color:#1f2937;flex-shrink:0;height:20px;width:20px}.ai-chat-tool-gear.spinning{animation:ai-chat-gear-spin 1.5s linear infinite}.ai-chat-tool-badges{align-items:center;display:flex;flex-wrap:wrap;gap:8px}.ai-chat-tool-badge{align-items:center;background:#e5e7eb;border:1px solid #d1d5db;border-radius:var(--radius-action-badge,8px);color:#1f2937;display:inline-flex;font-size:12px;font-weight:500;gap:4px;line-height:1.2;padding:5px 12px;transition:all .2s ease;white-space:nowrap}.ai-chat-tool-badge.loading{animation:ai-chat-tool-gradient 2s linear infinite;background:linear-gradient(90deg,var(--tool-loading-bg-1,#e0e0e0) 0,var(--tool-loading-bg-2,#f0f0f0) 25%,var(--tool-loading-bg-3,#fff) 50%,var(--tool-loading-bg-2,#f0f0f0) 75%,var(--tool-loading-bg-1,#e0e0e0) 100%);background-size:200% 100%;color:var(--tool-loading-text,#1a1a1a);position:relative}.ai-chat-widget:not(.dark) .ai-chat-tool-badge.loading{--tool-loading-bg-1:#2a2a2a;--tool-loading-bg-2:#3a3a3a;--tool-loading-bg-3:#4a4a4a;--tool-loading-text:#fff}.ai-chat-tool-badge.completed{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.chakra-ui-dark .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.chakra-ui-dark .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.ai-chat-tool-badge.error{background:var(--tool-error-bg,rgba(239,68,68,.15));color:var(--tool-error-text,#ef4444)}.ai-chat-tool-badge .ai-chat-tool-check{color:#fff;flex-shrink:0}.ai-chat-tool-badge .ai-chat-tool-error{color:#ef4444;flex-shrink:0}.tool-name{font-weight:500;line-height:1.2;white-space:nowrap}.ai-chat-tool-action{box-sizing:border-box;padding:0 16px;width:100%}";
30410
+ 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)}}";
30411
+ styleInject(css_248z$1);
30412
+
30413
+ 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}";
29688
30414
  styleInject(css_248z);
29689
30415
 
29690
30416
  // Icon components mapping
@@ -29692,9 +30418,10 @@ const iconComponents = {
29692
30418
  FiMessageCircle: () => (jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" }) })),
29693
30419
  FiChevronDown: () => (jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "6 9 12 15 18 9" }) })),
29694
30420
  };
29695
- const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = false, previewConfig, position = 'bottom-right', primaryColor, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, theme, suggestedQuestions, customStyles, currentRoute, defaultOpen = false, zIndex, onOpen, onClose, onMessage, onError, mode = 'bubble', }) => {
30421
+ 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', }) => {
29696
30422
  const [isOpen, setIsOpen] = useState(defaultOpen);
29697
30423
  const [autoDetectedTheme, setAutoDetectedTheme] = useState('light');
30424
+ const [showWelcomeBubble, setShowWelcomeBubble] = useState(false);
29698
30425
  const widgetRef = useRef(null);
29699
30426
  const containerRef = useRef(null);
29700
30427
  // Determine mode
@@ -29716,6 +30443,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29716
30443
  showChatHistory: true,
29717
30444
  showTimestamps: true,
29718
30445
  showTypingIndicator: true,
30446
+ showToolCalls: false,
29719
30447
  enableFileUpload: false,
29720
30448
  enableFeedback: true,
29721
30449
  },
@@ -29754,7 +30482,6 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29754
30482
  const messages = previewMode ? [] : chatHook.messages;
29755
30483
  const isLoading = previewMode ? false : chatHook.isLoading;
29756
30484
  const isTyping = previewMode ? false : chatHook.isTyping;
29757
- const error = previewMode ? null : chatHook.error;
29758
30485
  const config = previewMode ? mergedPreviewConfig : chatHook.config;
29759
30486
  const sendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
29760
30487
  const submitFeedback = previewMode ? (() => Promise.resolve()) : chatHook.submitFeedback;
@@ -29789,8 +30516,13 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29789
30516
  mediaQuery.removeEventListener('change', handleMediaChange);
29790
30517
  };
29791
30518
  }, [config]);
29792
- // Handle auto-open (only for bubble mode)
30519
+ // Check if device is mobile
30520
+ const isMobile = typeof window !== 'undefined' && window.innerWidth <= 480;
30521
+ // Handle auto-open (only for bubble mode, disabled on mobile)
29793
30522
  useEffect(() => {
30523
+ // Never auto-open on mobile devices
30524
+ if (isMobile)
30525
+ return undefined;
29794
30526
  if (!isEmbedded && config?.settings.autoOpen) {
29795
30527
  const delay = config.settings.autoOpenDelay || 0;
29796
30528
  const timer = setTimeout(() => {
@@ -29800,7 +30532,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29800
30532
  return () => clearTimeout(timer);
29801
30533
  }
29802
30534
  return undefined;
29803
- }, [config, onOpen, isEmbedded]);
30535
+ }, [config, onOpen, isEmbedded, isMobile]);
29804
30536
  // Handle close on Escape key (only for bubble mode)
29805
30537
  useEffect(() => {
29806
30538
  if (!isOpen || isEmbedded)
@@ -29814,6 +30546,37 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29814
30546
  document.addEventListener('keydown', handleEscapeKey);
29815
30547
  return () => document.removeEventListener('keydown', handleEscapeKey);
29816
30548
  }, [isOpen, onClose, isEmbedded]);
30549
+ // Handle body scroll lock on mobile when widget is open
30550
+ useEffect(() => {
30551
+ if (!isOpen || isEmbedded)
30552
+ return;
30553
+ // Only apply scroll lock on mobile
30554
+ const checkMobile = window.innerWidth <= 480;
30555
+ if (!checkMobile)
30556
+ return;
30557
+ // Add class to body to lock scrolling
30558
+ document.body.classList.add('ai-chat-widget-open');
30559
+ return () => {
30560
+ document.body.classList.remove('ai-chat-widget-open');
30561
+ };
30562
+ }, [isOpen, isEmbedded]);
30563
+ // Handle welcome bubble visibility per session
30564
+ // Shows on each new session if welcomeBubbleText is configured
30565
+ useEffect(() => {
30566
+ if (isEmbedded || previewMode)
30567
+ return;
30568
+ const bubbleText = welcomeBubbleText ?? config?.appearance?.welcomeBubbleText;
30569
+ if (!bubbleText) {
30570
+ setShowWelcomeBubble(false);
30571
+ return;
30572
+ }
30573
+ // Check if bubble was already dismissed this session
30574
+ const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
30575
+ const wasDismissed = sessionStorage.getItem(storageKey) === 'true';
30576
+ if (!wasDismissed && !isOpen) {
30577
+ setShowWelcomeBubble(true);
30578
+ }
30579
+ }, [widgetId, welcomeBubbleText, config, isOpen, isEmbedded, previewMode]);
29817
30580
  // Determine theme - use prop override if provided, otherwise auto-detect
29818
30581
  const appearanceConfig = config?.appearance;
29819
30582
  const effectiveTheme = theme ?? autoDetectedTheme;
@@ -29827,6 +30590,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29827
30590
  const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? '';
29828
30591
  const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? '';
29829
30592
  const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? '';
30593
+ const effectiveWelcomeBubbleText = welcomeBubbleText ?? appearanceConfig?.welcomeBubbleText ?? '';
29830
30594
  // Generate styles using simplified theme system
29831
30595
  const simpleAppearance = {
29832
30596
  accentColor};
@@ -29848,6 +30612,18 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29848
30612
  return;
29849
30613
  const newState = !isOpen;
29850
30614
  setIsOpen(newState);
30615
+ // Dismiss welcome bubble when chat is opened
30616
+ if (newState && showWelcomeBubble) {
30617
+ setShowWelcomeBubble(false);
30618
+ // Store in sessionStorage so it doesn't show again this session
30619
+ const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
30620
+ try {
30621
+ sessionStorage.setItem(storageKey, 'true');
30622
+ }
30623
+ catch {
30624
+ // Ignore storage errors
30625
+ }
30626
+ }
29851
30627
  if (newState) {
29852
30628
  onOpen?.();
29853
30629
  }
@@ -29878,13 +30654,13 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29878
30654
  const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
29879
30655
  // Embedded mode renders directly without wrapper positioning
29880
30656
  if (isEmbedded) {
29881
- return (jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage, onClose: () => { }, onFeedback: handleFeedback, onActionClick: handleActionClick, conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions }) }));
30657
+ return (jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage: sendMessage, onClose: () => { }, onFeedback: handleFeedback, onActionClick: handleActionClick, conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions }) }));
29882
30658
  }
29883
- return (jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition} ${isOpen ? 'is-open' : ''}`, children: [isOpen && (jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback, onActionClick: handleActionClick,
30659
+ return (jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition} ${isOpen ? 'is-open' : ''} ${containerMode ? 'container-mode' : ''}`, children: [isOpen && (jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback, onActionClick: handleActionClick,
29884
30660
  // Chat history props (only active when persistConversation is true)
29885
30661
  conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId,
29886
30662
  // Override props for live preview
29887
- headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsx("div", { className: "ai-chat-button-svg", children: jsx(IconComponent, {}) }) })] }) }));
30663
+ headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), !isOpen && effectiveWelcomeBubbleText && (previewMode || showWelcomeBubble) && (jsx("div", { className: "ai-chat-welcome-bubble", onClick: handleToggle, children: jsx("span", { children: effectiveWelcomeBubbleText }) })), jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsx("div", { className: "ai-chat-button-svg", children: jsx(IconComponent, {}) }) })] }) }));
29888
30664
  };
29889
30665
 
29890
30666
  export { ApiError, ChatWidget, useChat };