@chatwidgetai/chat-widget 0.2.9 → 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 (37) hide show
  1. package/dist/ai-chat-widget.umd.js +1546 -331
  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.d.ts +1 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.esm.js +1546 -331
  30. package/dist/index.esm.js.map +1 -1
  31. package/dist/index.js +1546 -331
  32. package/dist/index.js.map +1 -1
  33. package/dist/types/index.d.ts +10 -3
  34. package/dist/types/index.d.ts.map +1 -1
  35. package/dist/utils/sse-parser.d.ts.map +1 -1
  36. package/package.json +7 -3
  37. package/dist/hooks/useChat.d.ts.map +0 -1
package/dist/index.esm.js CHANGED
@@ -8,11 +8,14 @@ async function* parseSSEStream(response, validator) {
8
8
  const reader = response.body.getReader();
9
9
  const decoder = new TextDecoder();
10
10
  let buffer = "";
11
+ let eventCount = 0;
11
12
  try {
12
13
  while (true) {
13
14
  const { done, value } = await reader.read();
14
- if (done)
15
+ if (done) {
16
+ console.log(`[SSE Parser] Stream ended normally after ${eventCount} events`);
15
17
  break;
18
+ }
16
19
  buffer += decoder.decode(value, { stream: true });
17
20
  const chunks = buffer.split("\n\n");
18
21
  buffer = chunks.pop() || "";
@@ -24,6 +27,7 @@ async function* parseSSEStream(response, validator) {
24
27
  const data = JSON.parse(line.slice(6));
25
28
  if (validator) {
26
29
  if (validator(data)) {
30
+ eventCount++;
27
31
  yield data;
28
32
  }
29
33
  else {
@@ -31,6 +35,7 @@ async function* parseSSEStream(response, validator) {
31
35
  }
32
36
  }
33
37
  else {
38
+ eventCount++;
34
39
  yield data;
35
40
  }
36
41
  }
@@ -43,6 +48,10 @@ async function* parseSSEStream(response, validator) {
43
48
  }
44
49
  }
45
50
  }
51
+ catch (error) {
52
+ console.error(`[SSE Parser] Stream error after ${eventCount} events:`, error);
53
+ throw error;
54
+ }
46
55
  finally {
47
56
  reader.releaseLock();
48
57
  }
@@ -176,7 +185,7 @@ class WidgetApiClient {
176
185
  const result = await response.json();
177
186
  return result.file;
178
187
  }
179
- async *sendAgentMessageStream(conversationId, message, fileIds) {
188
+ async *sendAgentMessageStream(conversationId, message, fileIds, signal) {
180
189
  const headers = {
181
190
  'Content-Type': 'application/json',
182
191
  };
@@ -192,6 +201,7 @@ class WidgetApiClient {
192
201
  fileIds,
193
202
  timeZone: this.getTimeZone(),
194
203
  }),
204
+ signal,
195
205
  });
196
206
  if (!response.ok) {
197
207
  throw await buildApiError(response, 'Failed to send agent message');
@@ -200,7 +210,7 @@ class WidgetApiClient {
200
210
  return typeof data === 'object' && data !== null && 'type' in data;
201
211
  });
202
212
  }
203
- async *continueAgentMessageStream(conversationId, toolCallId, state) {
213
+ async *continueAgentMessageStream(conversationId, toolCallId, state, signal) {
204
214
  const headers = {
205
215
  'Content-Type': 'application/json',
206
216
  };
@@ -216,6 +226,7 @@ class WidgetApiClient {
216
226
  state,
217
227
  timeZone: this.getTimeZone(),
218
228
  }),
229
+ signal,
219
230
  });
220
231
  if (!response.ok) {
221
232
  throw await buildApiError(response, 'Failed to continue agent');
@@ -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,17 +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" })] }))] }));
27156
- };
27157
-
27158
- const Sources = ({ sources, displayMode = 'with-score' }) => {
27159
- const [isExpanded, setIsExpanded] = useState(false);
27160
- if (!sources || sources.length === 0 || displayMode === 'none')
27161
- return null;
27162
- return (jsxs("div", { className: "ai-chat-sources", children: [jsxs("button", { className: "ai-chat-sources-toggle", onClick: () => setIsExpanded(!isExpanded), "aria-expanded": isExpanded, children: [jsx("span", { className: "ai-chat-sources-icon", children: isExpanded ? '▼' : '▶' }), jsxs("span", { className: "ai-chat-sources-title", children: [sources.length, " source", sources.length > 1 ? 's' : ''] })] }), isExpanded && displayMode !== 'minimal' && (jsx("div", { className: "ai-chat-sources-list", children: sources.map((source, index) => (jsxs("div", { className: "ai-chat-source-item", children: [jsxs("div", { className: "ai-chat-source-number", children: [index + 1, "."] }), jsxs("div", { className: "ai-chat-source-details", children: [displayMode === 'with-score' && source.score && (jsxs("div", { className: "ai-chat-source-score", children: ["Score: ", (source.score * 100).toFixed(0), "%"] })), (displayMode === 'with-content' || displayMode === 'full') && source.doc.pageContent && (jsxs("div", { className: "ai-chat-source-content", children: [source.doc.pageContent.substring(0, 100), source.doc.pageContent.length > 100 ? '...' : ''] })), displayMode === 'full' && (jsxs(Fragment, { children: [source.score && (jsxs("div", { className: "ai-chat-source-score", children: ["Score: ", (source.score * 100).toFixed(0), "%"] })), source.doc.metadata && Object.keys(source.doc.metadata).length > 0 && (jsx("div", { className: "ai-chat-source-metadata", children: Object.entries(source.doc.metadata).map(([key, value]) => (jsxs("span", { className: "ai-chat-source-meta-item", children: [key, ": ", String(value)] }, key))) }))] }))] })] }, `${source.kbId}-${source.doc.id}-${index}`))) }))] }));
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" })] }))] }));
27163
27163
  };
27164
27164
 
27165
- const Message = ({ message, showTimestamp = true, enableFeedback = true, showSources = true, sourceDisplayMode = 'with-score', onFeedback, getActionRenderer, }) => {
27165
+ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, }) => {
27166
27166
  const formatTime = (timestamp) => {
27167
27167
  const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;
27168
27168
  return date.toLocaleTimeString('en-US', {
@@ -27182,15 +27182,15 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSou
27182
27182
  return null;
27183
27183
  }
27184
27184
  // AI message rendering
27185
+ // Note: Actions are rendered by ToolMessageGroup for tool messages, not here
27185
27186
  if (isAssistant) {
27186
27187
  const aiContent = message.message.content || '';
27187
27188
  const hasContent = aiContent.trim().length > 0;
27188
27189
  if (!hasContent)
27189
27190
  return null;
27190
- const actionRenderer = message.action && getActionRenderer
27191
- ? getActionRenderer(message.action.implementation)
27192
- : undefined;
27193
- 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), 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 }))] })), showSources && message.sources?.length > 0 && (jsx(Sources, { sources: message.sources, displayMode: sourceDisplayMode }))] }));
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 }))] }))] }));
27194
27194
  }
27195
27195
  // System message rendering
27196
27196
  if (isSystem) {
@@ -27204,30 +27204,85 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSou
27204
27204
  return null;
27205
27205
  };
27206
27206
 
27207
- const ToolMessageGroup = ({ messages, getActionRenderer }) => {
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 }) => {
27208
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
+ });
27261
+ // If tool indicator is hidden AND there are no action cards to render, don't render anything
27262
+ if (!showToolIndicator && actionMessages.length === 0) {
27263
+ return null;
27264
+ }
27209
27265
  const badges = messages.map((message) => {
27210
27266
  const toolName = message.toolExecuting || message.message.name || 'Tool';
27211
27267
  const hasError = message.isError || false;
27212
- const actionState = message.action?.state;
27213
- const actionStatus = actionState?.status;
27214
- const terminalStatuses = ['completed', 'booked', 'scheduled', 'failed', 'cancelled'];
27215
- const isTerminalStatus = actionStatus && terminalStatuses.includes(actionStatus);
27216
- const isDone = message.action ? (message.action.done ?? isTerminalStatus ?? false) : !message.isStreaming;
27217
- const isLoading = !isDone;
27268
+ const loading = isActionLoading(message);
27218
27269
  return {
27219
27270
  id: message.id,
27220
27271
  name: toolName,
27221
- status: isLoading ? 'loading' : hasError ? 'error' : 'completed',
27272
+ status: loading ? 'loading' : hasError ? 'error' : 'completed',
27222
27273
  };
27223
27274
  });
27224
- return (jsxs("div", { className: "ai-chat-message tool", children: [jsx(ToolIndicator, { badges: badges }), actionMessages.map((message) => {
27225
- if (!message.action || !getActionRenderer)
27275
+ return (jsxs("div", { className: "ai-chat-message tool", children: [showToolIndicator && jsx(ToolIndicator, { badges: badges }), actionMessages.map((message) => {
27276
+ if (!message.action || !getActionRenderer) {
27277
+ console.log('[ToolMessageGroup] Skipping - no action or renderer:', { hasAction: !!message.action, hasGetRenderer: !!getActionRenderer });
27226
27278
  return null;
27279
+ }
27227
27280
  const renderer = getActionRenderer(message.action.implementation);
27228
- if (!renderer)
27281
+ if (!renderer) {
27282
+ console.log('[ToolMessageGroup] No renderer for:', message.action.implementation);
27229
27283
  return null;
27230
- return (jsx("div", { className: "ai-chat-tool-action", children: renderer(message) }, `action-${message.id}`));
27284
+ }
27285
+ return (jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant) }, `action-${message.id}`));
27231
27286
  })] }));
27232
27287
  };
27233
27288
 
@@ -27289,12 +27344,16 @@ const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, acce
27289
27344
  };
27290
27345
 
27291
27346
  const MessageList = (props) => {
27292
- const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, enableFeedback = true, showSources = true, sourceDisplayMode = 'with-score', 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;
27293
27348
  const containerRef = useRef(null);
27294
27349
  const messagesEndRef = useRef(null);
27295
27350
  const [showScrollButton, setShowScrollButton] = useState(false);
27296
27351
  const prevMessageCountRef = useRef(0);
27297
- 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]);
27298
27357
  const checkScrollPosition = useCallback(() => {
27299
27358
  const c = containerRef.current;
27300
27359
  if (!c)
@@ -27330,39 +27389,70 @@ const MessageList = (props) => {
27330
27389
  checkScrollPosition();
27331
27390
  }, [messages, isTyping, checkScrollPosition]);
27332
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
+ });
27333
27403
  const result = [];
27334
27404
  let toolGroup = [];
27335
- const flush = () => { if (toolGroup.length) {
27336
- result.push({ type: 'tool-group', messages: [...toolGroup] });
27337
- toolGroup = [];
27338
- } };
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
+ };
27339
27412
  for (const m of messages) {
27340
- if (m.message.role === 'tool')
27413
+ if (m.message.role === 'tool') {
27414
+ console.log('[DEBUG MessageList] Adding to tool group:', m.id);
27341
27415
  toolGroup.push(m);
27416
+ }
27342
27417
  else if (m.message.role === 'user') {
27343
27418
  flush();
27344
27419
  result.push({ type: 'message', message: m });
27345
27420
  }
27346
- else if (m.message.role === 'assistant' && (m.message.content || '').trim()) {
27347
- flush();
27348
- result.push({ type: 'message', message: m });
27421
+ else if (m.message.role === 'assistant') {
27422
+ // Include assistant messages if they have content OR are still streaming (content may arrive)
27423
+ const hasContent = (m.message.content || '').trim().length > 0;
27424
+ if (hasContent || m.isStreaming) {
27425
+ flush();
27426
+ result.push({ type: 'message', message: m });
27427
+ }
27428
+ // Don't flush on empty assistant messages - let tools continue grouping
27349
27429
  }
27350
- else if (m.message.role !== 'assistant') {
27430
+ else {
27351
27431
  flush();
27352
27432
  result.push({ type: 'message', message: m });
27353
27433
  }
27354
27434
  }
27355
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
+ });
27356
27445
  return result;
27357
27446
  }, [messages]);
27358
27447
  const hasSuggestions = messages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
27359
27448
  const showWelcome = welcomeTitle || welcomeMessage || hasSuggestions;
27360
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) => {
27361
- if (item.type === 'tool-group')
27362
- return jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer }, `tg-${i}`);
27450
+ if (item.type === 'tool-group') {
27451
+ return jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant }, `tg-${i}`);
27452
+ }
27363
27453
  const isLast = i === groupedMessages.length - 1;
27364
27454
  const hasFollowUp = item.message.message.role === 'assistant' && item.message.suggestions?.length && isLast && !isTyping;
27365
- return (jsxs(React.Fragment, { children: [jsx(Message, { message: item.message, showTimestamp: showTimestamps, enableFeedback: enableFeedback, showSources: showSources, sourceDisplayMode: sourceDisplayMode, onFeedback: onFeedback, getActionRenderer: getActionRenderer }), hasFollowUp && onSuggestedQuestionClick && jsx(FollowUpSuggestions, { suggestions: item.message.suggestions, onQuestionClick: onSuggestedQuestionClick, onActionClick: onActionClick, accentColor: accentColor })] }, item.message.id));
27455
+ return (jsxs(React.Fragment, { children: [jsx(Message, { message: item.message, showTimestamp: showTimestamps, onFeedback: onFeedback, getActionRenderer: getActionRenderer, accentColor: accentColor }), hasFollowUp && onSuggestedQuestionClick && jsx(FollowUpSuggestions, { suggestions: item.message.suggestions, onQuestionClick: onSuggestedQuestionClick, onActionClick: onActionClick, accentColor: accentColor })] }, item.message.id));
27366
27456
  }), isTyping && showTypingIndicator && !hasActiveAction && messages.length > 0 && jsx(TypingIndicator, {}), jsx("div", { ref: messagesEndRef })] }));
27367
27457
  };
27368
27458
 
@@ -27377,7 +27467,7 @@ const formatFileSize = (bytes) => {
27377
27467
  return (bytes / 1024).toFixed(1) + ' KB';
27378
27468
  return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
27379
27469
  };
27380
- 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, }) => {
27381
27471
  const [value, setValue] = useState('');
27382
27472
  const [selectedFiles, setSelectedFiles] = useState([]);
27383
27473
  const textareaRef = useRef(null);
@@ -27412,10 +27502,10 @@ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled =
27412
27502
  }
27413
27503
  };
27414
27504
  const canSend = value.trim() || selectedFiles.length > 0;
27415
- 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" })] }))] }))] }));
27416
27506
  };
27417
27507
 
27418
- function groupSlotsByDate(slots) {
27508
+ function groupSlotsByDate$1(slots) {
27419
27509
  const grouped = new Map();
27420
27510
  for (const slot of slots) {
27421
27511
  if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
@@ -27429,7 +27519,7 @@ function groupSlotsByDate(slots) {
27429
27519
  }
27430
27520
  return grouped;
27431
27521
  }
27432
- function formatDate(dateStr) {
27522
+ function formatDate$1(dateStr) {
27433
27523
  try {
27434
27524
  const date = new Date(dateStr);
27435
27525
  return new Intl.DateTimeFormat("en-US", {
@@ -27442,16 +27532,16 @@ function formatDate(dateStr) {
27442
27532
  return dateStr;
27443
27533
  }
27444
27534
  }
27445
- function CalendarIcon() {
27535
+ function CalendarIcon$1() {
27446
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" }) }));
27447
27537
  }
27448
- function CheckIcon() {
27538
+ function CheckIcon$1() {
27449
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" }) }));
27450
27540
  }
27451
- function ExternalLinkIcon() {
27541
+ function ExternalLinkIcon$2() {
27452
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" })] }));
27453
27543
  }
27454
- function Skeleton({ width, height, borderRadius = '4px' }) {
27544
+ function Skeleton$1({ width, height, borderRadius = '4px' }) {
27455
27545
  return (jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
27456
27546
  }
27457
27547
  function GoogleCalendarCard({ action, onComplete, accentColor, className = '' }) {
@@ -27468,13 +27558,12 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
27468
27558
  : [];
27469
27559
  const allowTopic = state.allowTopic !== false;
27470
27560
  const isBooked = state.status === "booked";
27471
- const slotsByDate = groupSlotsByDate(availableSlots);
27561
+ const slotsByDate = groupSlotsByDate$1(availableSlots);
27472
27562
  const dates = Array.from(slotsByDate.keys()).sort();
27473
27563
  const [selectedDate, setSelectedDate] = useState(dates[0] ?? "");
27474
27564
  const [selectedSlot, setSelectedSlot] = useState(null);
27475
27565
  const [topic, setTopic] = useState("");
27476
27566
  const [error, setError] = useState(null);
27477
- const [isSubmitting, setIsSubmitting] = useState(false);
27478
27567
  const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
27479
27568
  const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
27480
27569
  const onConfirm = () => {
@@ -27487,8 +27576,245 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
27487
27576
  return;
27488
27577
  }
27489
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);
27490
27813
  setIsSubmitting(true);
27491
- // Small delay to ensure UI updates
27814
+ console.log('[MicrosoftCalendarCard] Confirming appointment:', {
27815
+ slot: selectedSlot,
27816
+ topic: topic.trim()
27817
+ });
27492
27818
  setTimeout(() => {
27493
27819
  onComplete?.(action.toolCallId, {
27494
27820
  ...action.state,
@@ -27500,22 +27826,566 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
27500
27826
  });
27501
27827
  }, 50);
27502
27828
  };
27503
- // Booked state
27504
- 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") {
27505
27851
  const bookedSlot = state.selectedSlot;
27506
27852
  const bookedTopic = state.topic;
27507
27853
  const eventLink = state.bookedEventLink;
27508
- 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, {})] }))] })] }));
27509
- }
27510
- // 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
27511
27886
  if (isSubmitting) {
27512
- 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" })] }) }));
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;
27972
+ }
27973
+
27974
+ function truncate(text, maxLength) {
27975
+ if (text.length <= maxLength)
27976
+ return text;
27977
+ return text.slice(0, maxLength).trim() + '...';
27978
+ }
27979
+ function ExternalLinkIcon() {
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" })] }));
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
+ }
28000
+ function LinkPreviewCard({ action, onComplete, accentColor }) {
28001
+ const rawState = action.state;
28002
+ const hasCompletedRef = useRef(false);
28003
+ // Provide safe defaults if state is missing
28004
+ const state = {
28005
+ links: rawState?.links || [],
28006
+ context: rawState?.context,
28007
+ status: rawState?.status || 'displaying',
28008
+ error: rawState?.error,
28009
+ };
28010
+ const isError = state.status === 'error';
28011
+ // Auto-complete on mount so AI can continue generating text response
28012
+ useEffect(() => {
28013
+ if (!action.done && !hasCompletedRef.current && onComplete && state.links.length > 0) {
28014
+ hasCompletedRef.current = true;
28015
+ // Signal completion immediately - the card is displayed, AI can continue
28016
+ onComplete(action.toolCallId, { ...state, status: 'displaying' });
28017
+ }
28018
+ }, [action.done, action.toolCallId, onComplete, state]);
28019
+ const handleLinkClick = (url) => {
28020
+ if (url) {
28021
+ window.open(url, '_blank', 'noopener,noreferrer');
28022
+ }
28023
+ onComplete?.(action.toolCallId, { ...state, status: 'clicked' });
28024
+ };
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' }) }) }));
27513
28027
  }
27514
- // Booking form
27515
- 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: () => {
27516
- setSelectedDate(date);
27517
- setSelectedSlot(null);
27518
- }, 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." }))] })] }));
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))) })] }));
28036
+ }
28037
+
28038
+ function PlayIcon() {
28039
+ return (jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "currentColor", stroke: "none", children: jsx("path", { d: "M8 5v14l11-7z" }) }));
28040
+ }
28041
+ function getProviderLabel(provider) {
28042
+ switch (provider) {
28043
+ case 'youtube':
28044
+ return 'YouTube';
28045
+ case 'vimeo':
28046
+ return 'Vimeo';
28047
+ case 'loom':
28048
+ return 'Loom';
28049
+ case 'direct':
28050
+ return 'Video';
28051
+ default:
28052
+ return 'Video';
28053
+ }
28054
+ }
28055
+ function VideoPlayerCard({ action, onComplete, accentColor }) {
28056
+ const rawState = action.state;
28057
+ const hasCompletedRef = useRef(false);
28058
+ const [isPlaying, setIsPlaying] = useState(false);
28059
+ // Provide safe defaults if state is missing
28060
+ const state = {
28061
+ url: rawState?.url || '',
28062
+ title: rawState?.title,
28063
+ context: rawState?.context,
28064
+ provider: rawState?.provider || 'direct',
28065
+ embedUrl: rawState?.embedUrl || '',
28066
+ thumbnailUrl: rawState?.thumbnailUrl,
28067
+ videoId: rawState?.videoId,
28068
+ status: rawState?.status || 'displaying',
28069
+ error: rawState?.error,
28070
+ };
28071
+ const isError = state.status === 'error';
28072
+ // Auto-complete on mount so AI can continue generating text response
28073
+ useEffect(() => {
28074
+ if (!action.done && !hasCompletedRef.current && onComplete && state.embedUrl) {
28075
+ hasCompletedRef.current = true;
28076
+ onComplete(action.toolCallId, { ...state, status: 'displaying' });
28077
+ }
28078
+ }, [action.done, action.toolCallId, onComplete, state]);
28079
+ const handlePlay = () => {
28080
+ setIsPlaying(true);
28081
+ onComplete?.(action.toolCallId, { ...state, status: 'played' });
28082
+ };
28083
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
28084
+ // Build embed URL with autoplay when playing
28085
+ const getEmbedSrc = () => {
28086
+ if (!isPlaying)
28087
+ return '';
28088
+ let src = state.embedUrl;
28089
+ const separator = src.includes('?') ? '&' : '?';
28090
+ switch (state.provider) {
28091
+ case 'youtube':
28092
+ return `${src}${separator}autoplay=1&rel=0`;
28093
+ case 'vimeo':
28094
+ return `${src}${separator}autoplay=1`;
28095
+ case 'loom':
28096
+ return `${src}${separator}autoplay=1`;
28097
+ default:
28098
+ return src;
28099
+ }
28100
+ };
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 }))] }));
28102
+ }
28103
+
28104
+ function MapPinIcon() {
28105
+ return (jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" }), jsx("circle", { cx: "12", cy: "10", r: "3" })] }));
28106
+ }
28107
+ function PhoneIcon() {
28108
+ return (jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }) }));
28109
+ }
28110
+ function ClockIcon() {
28111
+ return (jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("circle", { cx: "12", cy: "12", r: "10" }), jsx("polyline", { points: "12 6 12 12 16 14" })] }));
28112
+ }
28113
+ function NavigationIcon() {
28114
+ return (jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polygon", { points: "3 11 22 2 13 21 11 13 3 11" }) }));
28115
+ }
28116
+ function GlobeIcon() {
28117
+ return (jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("circle", { cx: "12", cy: "12", r: "10" }), jsx("line", { x1: "2", y1: "12", x2: "22", y2: "12" }), jsx("path", { d: "M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" })] }));
28118
+ }
28119
+ function ChevronIcon({ direction }) {
28120
+ return (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { transform: direction === 'up' ? 'rotate(180deg)' : 'none' }, children: jsx("polyline", { points: "6 9 12 15 18 9" }) }));
28121
+ }
28122
+ function getOpenStatus(hours) {
28123
+ if (!hours || hours.length === 0)
28124
+ return null;
28125
+ const now = new Date();
28126
+ const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
28127
+ const today = dayNames[now.getDay()];
28128
+ const todayHours = hours.find(h => h.day === today);
28129
+ if (!todayHours || todayHours.closed)
28130
+ return false;
28131
+ const currentTime = now.getHours() * 100 + now.getMinutes();
28132
+ const openTime = parseInt(todayHours.open.replace(':', ''));
28133
+ const closeTime = parseInt(todayHours.close.replace(':', ''));
28134
+ return currentTime >= openTime && currentTime < closeTime;
28135
+ }
28136
+ function HoursDisplay({ hours, compact = false }) {
28137
+ const [expanded, setExpanded] = useState(false);
28138
+ const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
28139
+ const today = dayNames[new Date().getDay()];
28140
+ const todayHours = hours.find(h => h.day === today);
28141
+ if (compact && !expanded) {
28142
+ return (jsxs("div", { className: "ai-chat-location-card__hours", children: [jsx(ClockIcon, {}), jsx("span", { children: todayHours?.closed ? 'Closed today' : `${todayHours?.open} - ${todayHours?.close}` })] }));
28143
+ }
28144
+ return (jsxs("div", { className: "ai-chat-location-card__hours", children: [jsx(ClockIcon, {}), jsxs("div", { className: "ai-chat-location-card__hours-list", children: [jsxs("button", { type: "button", onClick: () => setExpanded(!expanded), className: "ai-chat-location-card__hours-toggle", children: ["Today: ", todayHours?.closed ? 'Closed' : `${todayHours?.open} - ${todayHours?.close}`, jsx(ChevronIcon, { direction: expanded ? 'up' : 'down' })] }), expanded && (jsx("ul", { className: "ai-chat-location-card__hours-full", children: hours.map(h => (jsxs("li", { className: h.day === today ? 'ai-chat-location-card__hours-today' : '', children: [jsx("span", { children: h.day }), jsx("span", { children: h.closed ? 'Closed' : `${h.open} - ${h.close}` })] }, h.day))) }))] })] }));
28145
+ }
28146
+ function LocationItem({ location, settings, accentColor, onDirections, showMap = true, compact = false, }) {
28147
+ const openStatus = getOpenStatus(location.hours);
28148
+ const mapHeight = settings.mapHeight || 180;
28149
+ const mapZoom = settings.mapZoom || 15;
28150
+ const getMapEmbedUrl = () => {
28151
+ const query = location.lat && location.lng
28152
+ ? `${location.lat},${location.lng}`
28153
+ : encodeURIComponent(location.address);
28154
+ return `https://www.google.com/maps/embed/v1/place?key=AIzaSyBFw0Qbyq9zTFTd-tUY6dZWTgaQzuU17R8&q=${query}&zoom=${mapZoom}`;
28155
+ };
28156
+ const handleCall = () => {
28157
+ if (location.phone) {
28158
+ window.location.href = `tel:${location.phone}`;
28159
+ }
28160
+ };
28161
+ const style = accentColor ? { '--action-accent': accentColor } : undefined;
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"] }))] })] })] }));
28165
+ }
28166
+ function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
28167
+ const rawState = action.state;
28168
+ const hasCompletedRef = useRef(false);
28169
+ const state = {
28170
+ locations: rawState?.locations || [],
28171
+ settings: rawState?.settings || {},
28172
+ matchInfo: rawState?.matchInfo,
28173
+ status: rawState?.status || 'displaying',
28174
+ };
28175
+ const { locations, settings } = state;
28176
+ const layout = settings.multiLocationLayout || 'stack';
28177
+ const isSingleLocation = locations.length === 1;
28178
+ const stackColumns = Math.min(Math.max(locations.length, 1), maxColumns);
28179
+ useEffect(() => {
28180
+ if (!action.done && !hasCompletedRef.current && onComplete && locations.length > 0) {
28181
+ hasCompletedRef.current = true;
28182
+ onComplete(action.toolCallId, { ...state, status: 'displaying' });
28183
+ }
28184
+ }, [action.done, action.toolCallId, onComplete, state, locations.length]);
28185
+ const handleDirections = (location) => {
28186
+ const url = location.lat && location.lng
28187
+ ? `https://www.google.com/maps/dir/?api=1&destination=${location.lat},${location.lng}`
28188
+ : `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(location.address)}`;
28189
+ window.open(url, '_blank', 'noopener,noreferrer');
28190
+ onComplete?.(action.toolCallId, { ...state, status: 'directions_opened' });
28191
+ };
28192
+ if (locations.length === 0) {
28193
+ return (jsx("div", { className: "ai-chat-location-card ai-chat-location-card--error", children: jsx("p", { children: "No locations to display" }) }));
28194
+ }
28195
+ if (isSingleLocation) {
28196
+ return (jsx(LocationItem, { location: locations[0], settings: settings, accentColor: accentColor, onDirections: () => handleDirections(locations[0]), showMap: true }));
28197
+ }
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 : {
28280
+ gridTemplateColumns: `repeat(${stackColumns}, minmax(0, 1fr))`,
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') }))] })] }));
27519
28389
  }
27520
28390
 
27521
28391
  const pendingResolvers = new Map();
@@ -27528,12 +28398,6 @@ function getFrontendActionHandler(implementation) {
27528
28398
  function getActionRenderer(implementation) {
27529
28399
  return actionRenderers[implementation];
27530
28400
  }
27531
- function getActionPrompt(implementation) {
27532
- if (implementation === "google-calendar-appointment") {
27533
- return "Select a date to continue.";
27534
- }
27535
- return "Action input required.";
27536
- }
27537
28401
  function waitForActionState(toolCallId) {
27538
28402
  return new Promise((resolve) => {
27539
28403
  pendingResolvers.set(toolCallId, resolve);
@@ -27560,26 +28424,272 @@ function unregisterActionResumeCallback(toolCallId) {
27560
28424
  resumeCallbacks.delete(toolCallId);
27561
28425
  }
27562
28426
 
27563
- frontendActionHandlers["google-calendar-appointment"] = async (_input, _state, context) => {
27564
- return waitForActionState(context.toolCallId);
27565
- };
28427
+ function registerGoogleCalendarHandler() {
28428
+ frontendActionHandlers["google-calendar-appointment"] = async (_input, _state, context) => {
28429
+ return waitForActionState(context.toolCallId);
28430
+ };
28431
+ }
27566
28432
 
27567
- actionRenderers["google-calendar-appointment"] = (message) => {
27568
- const action = message.action;
27569
- if (!action)
27570
- return null;
27571
- const handleComplete = (toolCallId, newState) => {
27572
- resolveActionState(toolCallId, newState);
28433
+ /**
28434
+ * Register google-calendar-appointment action handler and renderer.
28435
+ * Called by initializeActionHandlers to prevent tree-shaking.
28436
+ */
28437
+ function registerGoogleCalendarAction() {
28438
+ // Register the handler
28439
+ registerGoogleCalendarHandler();
28440
+ // Register the renderer
28441
+ actionRenderers["google-calendar-appointment"] = (message, accentColor) => {
28442
+ const action = message.action;
28443
+ if (!action)
28444
+ return null;
28445
+ const handleComplete = (toolCallId, newState) => {
28446
+ resolveActionState(toolCallId, newState);
28447
+ };
28448
+ return (jsx(GoogleCalendarCard, { action: {
28449
+ implementation: action.implementation,
28450
+ toolCallId: action.toolCallId,
28451
+ actionId: action.actionId,
28452
+ input: action.input,
28453
+ state: action.state,
28454
+ done: action.done ?? false,
28455
+ }, onComplete: handleComplete, accentColor: accentColor }));
27573
28456
  };
27574
- return (jsx(GoogleCalendarCard, { action: {
27575
- implementation: action.implementation,
27576
- toolCallId: action.toolCallId,
27577
- actionId: action.actionId,
27578
- input: action.input,
27579
- state: action.state,
27580
- done: action.done ?? false,
27581
- }, onComplete: handleComplete }));
27582
- };
28457
+ }
28458
+
28459
+ function registerMicrosoftCalendarHandler() {
28460
+ frontendActionHandlers["microsoft-calendar-appointment"] = async (_input, _state, context) => {
28461
+ return waitForActionState(context.toolCallId);
28462
+ };
28463
+ }
28464
+
28465
+ /**
28466
+ * Register microsoft-calendar-appointment action handler and renderer.
28467
+ * Called by initializeActionHandlers to prevent tree-shaking.
28468
+ */
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;
28503
+ if (!action)
28504
+ return null;
28505
+ const handleComplete = (toolCallId, newState) => {
28506
+ resolveActionState(toolCallId, newState);
28507
+ };
28508
+ // Check if action state indicates it's already complete (displaying or clicked)
28509
+ const state = action.state;
28510
+ const status = state?.status;
28511
+ const isDone = action.done || status === "displaying" || status === "clicked";
28512
+ return (jsx(LinkPreviewCard, { action: {
28513
+ implementation: action.implementation,
28514
+ toolCallId: action.toolCallId,
28515
+ actionId: action.actionId,
28516
+ input: action.input,
28517
+ state: action.state,
28518
+ done: isDone,
28519
+ }, onComplete: handleComplete, accentColor: accentColor }));
28520
+ };
28521
+ }
28522
+
28523
+ /**
28524
+ * Register video-player action handler and renderer.
28525
+ * Called by initializeActionHandlers to prevent tree-shaking.
28526
+ */
28527
+ function registerVideoPlayerAction() {
28528
+ // Handler - auto-completes immediately since no user input is needed
28529
+ frontendActionHandlers["video-player"] = async (_input, state, _context) => {
28530
+ return { ...state, status: "displaying" };
28531
+ };
28532
+ // Renderer - displays the embedded video player card
28533
+ actionRenderers["video-player"] = (message, accentColor) => {
28534
+ const action = message.action;
28535
+ if (!action)
28536
+ return null;
28537
+ const handleComplete = (toolCallId, newState) => {
28538
+ resolveActionState(toolCallId, newState);
28539
+ };
28540
+ // Check if action state indicates it's already complete (displaying or played)
28541
+ const state = action.state;
28542
+ const status = state?.status;
28543
+ const isDone = action.done || status === "displaying" || status === "played";
28544
+ return (jsx(VideoPlayerCard, { action: {
28545
+ implementation: action.implementation,
28546
+ toolCallId: action.toolCallId,
28547
+ actionId: action.actionId,
28548
+ input: action.input,
28549
+ state: action.state,
28550
+ done: isDone,
28551
+ }, onComplete: handleComplete, accentColor: accentColor }));
28552
+ };
28553
+ }
28554
+
28555
+ /**
28556
+ * Register location-card action handler and renderer.
28557
+ * Called by initializeActionHandlers to prevent tree-shaking.
28558
+ */
28559
+ function registerLocationCardAction() {
28560
+ // Handler - auto-completes immediately since no user input is needed
28561
+ frontendActionHandlers["location-card"] = async (_input, state, _context) => {
28562
+ return { ...state, status: "displaying" };
28563
+ };
28564
+ // Renderer - displays the location card
28565
+ actionRenderers["location-card"] = (message, accentColor, variant) => {
28566
+ const action = message.action;
28567
+ if (!action)
28568
+ return null;
28569
+ const handleComplete = (toolCallId, newState) => {
28570
+ resolveActionState(toolCallId, newState);
28571
+ };
28572
+ // Check if action state indicates it's already complete
28573
+ const state = action.state;
28574
+ const status = state?.status;
28575
+ const isDone = action.done || status === "displaying" || status === "directions_opened";
28576
+ return (jsx(LocationCard, { action: {
28577
+ implementation: action.implementation,
28578
+ toolCallId: action.toolCallId,
28579
+ actionId: action.actionId,
28580
+ input: action.input,
28581
+ state: action.state,
28582
+ done: isDone,
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 }));
28669
+ };
28670
+ }
28671
+
28672
+ // Track if handlers have been initialized
28673
+ let initialized = false;
28674
+ /**
28675
+ * Initialize all action handlers.
28676
+ * Call this to ensure handlers are registered (prevents tree-shaking in production builds).
28677
+ * Safe to call multiple times - will only register once.
28678
+ */
28679
+ function initializeActionHandlers() {
28680
+ if (initialized)
28681
+ return;
28682
+ initialized = true;
28683
+ // Explicitly call each registration function to prevent tree-shaking
28684
+ registerGoogleCalendarAction();
28685
+ registerMicrosoftCalendarAction();
28686
+ registerLinkPreviewAction();
28687
+ registerVideoPlayerAction();
28688
+ registerLocationCardAction();
28689
+ registerQueryContactDirectoryAction();
28690
+ registerContactCardAction();
28691
+ registerDisplayFormAction();
28692
+ }
27583
28693
 
27584
28694
  /**
27585
28695
  * Local Storage Utilities
@@ -27798,10 +28908,6 @@ function isStorageAvailable() {
27798
28908
  }
27799
28909
  }
27800
28910
 
27801
- /**
27802
- * useChat Hook
27803
- * Main state management for chat functionality
27804
- */
27805
28911
  function hydrateToolNames(messages) {
27806
28912
  const toolCallNameById = new Map();
27807
28913
  for (const entry of messages) {
@@ -27845,81 +28951,77 @@ function hydrateToolNames(messages) {
27845
28951
  };
27846
28952
  });
27847
28953
  }
27848
- function hydrateActionContent(messages) {
27849
- return messages.map((entry) => {
27850
- if (entry.message.role !== "assistant" || !entry.action) {
27851
- return entry;
27852
- }
27853
- const content = typeof entry.message.content === "string" ? entry.message.content : "";
27854
- if (content.trim().length > 0) {
27855
- return entry;
27856
- }
27857
- return {
27858
- ...entry,
27859
- message: { ...entry.message, content: getActionPrompt(entry.action.implementation) },
27860
- };
27861
- });
27862
- }
27863
28954
  function hydrateMessages(messages) {
27864
- return hydrateActionContent(hydrateToolNames(messages));
28955
+ return hydrateToolNames(messages);
27865
28956
  }
27866
- function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate) {
27867
- // Find all incomplete actions and register resume callbacks
27868
- for (const message of messages) {
27869
- if (message.action && !message.action.done) {
27870
- const toolCallId = message.action.toolCallId;
27871
- const toolName = message.message.name || message.toolExecuting || "tool";
27872
- registerActionResumeCallback(toolCallId, async (newState) => {
27873
- // When user interacts with the action after reload, continue the stream
27874
- try {
27875
- // Update the action message with the new state
27876
- setState(prev => ({
27877
- ...prev,
27878
- messages: prev.messages.map(m => m.action?.toolCallId === toolCallId
27879
- ? {
27880
- ...m,
27881
- action: m.action ? { ...m.action, state: newState } : undefined,
27882
- }
27883
- : m),
27884
- isTyping: true,
27885
- }));
27886
- const streamState = createStreamState();
27887
- // Continue the agent stream with the new state
27888
- for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
27889
- if (event.type === "done") {
27890
- finalizeToolMessage(streamState, setState, toolCallId, toolName);
27891
- streamState.sources = event.sources;
27892
- streamState.toolCallToActionId = event.tool_call_to_action_id;
27893
- finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
27894
- continue;
27895
- }
27896
- if (event.type === "error") {
27897
- const errorMessage = {
27898
- id: generateMessageId(),
27899
- message: {
27900
- role: "assistant",
27901
- content: "Sorry, an error occurred. Please try again later.",
27902
- },
27903
- timestamp: new Date().toISOString(),
27904
- sources: [],
27905
- isError: true,
27906
- };
27907
- upsertMessage(setState, errorMessage, false);
27908
- setState(prev => ({ ...prev, isTyping: false }));
27909
- return;
27910
- }
27911
- handleStreamEvent(event, streamState, onMessageUpdate, setState);
27912
- }
27913
- setState(prev => ({ ...prev, isTyping: false }));
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.`;
27914
28973
  }
27915
- catch (error) {
27916
- console.error("[Action Resume] Failed to continue stream:", error);
27917
- setState(prev => ({ ...prev, isTyping: false }));
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.';
27918
29002
  }
27919
- });
27920
29003
  }
29004
+ return { message, retryAfterSeconds, status: error.status };
27921
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.' };
29010
+ }
29011
+ if (lower.includes('timeout')) {
29012
+ return { message: 'The request timed out. Please try again.' };
29013
+ }
29014
+ if (lower.includes('unauthorized') || lower.includes('401')) {
29015
+ return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
29016
+ }
29017
+ if (lower.includes('internal server error') || lower.includes('500')) {
29018
+ return { message: 'The server encountered an error. Please try again shortly.' };
29019
+ }
29020
+ return { message: error.message || 'Something went wrong. Please try again.' };
29021
+ }
29022
+ return { message: 'Something went wrong. Please try again.' };
27922
29023
  }
29024
+
27923
29025
  function createStreamState() {
27924
29026
  return {
27925
29027
  currentContent: "",
@@ -27928,6 +29030,7 @@ function createStreamState() {
27928
29030
  newMessageIds: new Set(),
27929
29031
  sources: [],
27930
29032
  toolCallToActionId: {},
29033
+ requestId: generateMessageId(),
27931
29034
  };
27932
29035
  }
27933
29036
  function upsertMessage(setState, message, isTyping) {
@@ -27963,15 +29066,40 @@ function finalizeStreamMessages(setState, messageIds, sources, toolCallToActionI
27963
29066
  return msg;
27964
29067
  }
27965
29068
  // Attach suggestions only to the last assistant message
27966
- if (index === lastAssistantIndex && suggestions && suggestions.length > 0) {
27967
- return { ...msg, sources, toolCallToActionId, suggestions };
27968
- }
27969
- return { ...msg, sources, toolCallToActionId };
29069
+ const withSuggestions = index === lastAssistantIndex && suggestions && suggestions.length > 0
29070
+ ? { suggestions }
29071
+ : {};
29072
+ return { ...msg, sources, toolCallToActionId, ...withSuggestions };
27970
29073
  }),
27971
29074
  isTyping: false,
27972
29075
  };
27973
29076
  });
27974
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
+
27975
29103
  function handleContentEvent(event, streamState, onMessageUpdate, setState) {
27976
29104
  streamState.currentContent += event.content;
27977
29105
  const assistantMessage = {
@@ -28018,8 +29146,6 @@ function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
28018
29146
  }
28019
29147
  function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
28020
29148
  streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
28021
- // Update state and mark action as done in a single setState call
28022
- // Keep isTyping: true because the agent may continue generating content after tool completion
28023
29149
  setState(prev => {
28024
29150
  const messages = prev.messages.map((msg) => {
28025
29151
  const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
@@ -28027,7 +29153,26 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
28027
29153
  return msg;
28028
29154
  }
28029
29155
  const existingName = msg.message.name || event.tool_name;
28030
- 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 = {
28031
29176
  ...msg,
28032
29177
  message: {
28033
29178
  role: "tool",
@@ -28037,14 +29182,10 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
28037
29182
  },
28038
29183
  isStreaming: false,
28039
29184
  toolExecuting: existingName,
28040
- action: msg.action ? {
28041
- ...msg.action,
28042
- state: event.state || msg.action.state,
28043
- done: true, // Mark action as completed
28044
- } : undefined,
29185
+ action,
28045
29186
  };
29187
+ return updatedMsg;
28046
29188
  });
28047
- // Keep typing indicator visible - it will be hidden by done/finalizeStreamMessages
28048
29189
  return { ...prev, messages, isTyping: true, isLoading: false };
28049
29190
  });
28050
29191
  }
@@ -28076,34 +29217,6 @@ function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
28076
29217
  return { ...prev, messages, isTyping: true, isLoading: false };
28077
29218
  });
28078
29219
  }
28079
- function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
28080
- setState(prev => {
28081
- const messages = prev.messages.map((entry) => {
28082
- const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
28083
- if (!matchesToolCall) {
28084
- return entry;
28085
- }
28086
- const existingName = entry.message.name || toolName;
28087
- return {
28088
- ...entry,
28089
- message: {
28090
- role: "tool",
28091
- content: typeof entry.message.content === "string" ? entry.message.content : "",
28092
- tool_call_id: toolCallId,
28093
- name: existingName,
28094
- },
28095
- isStreaming: false,
28096
- toolExecuting: existingName,
28097
- action: entry.action ? {
28098
- ...entry.action,
28099
- done: true, // Mark action as completed
28100
- } : undefined,
28101
- };
28102
- });
28103
- return { ...prev, messages, isTyping: false, isLoading: false };
28104
- });
28105
- streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
28106
- }
28107
29220
  function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
28108
29221
  streamState.sources = event.sources;
28109
29222
  streamState.toolCallToActionId = event.tool_call_to_action_id;
@@ -28162,6 +29275,7 @@ function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
28162
29275
  console.warn('[Chat] Unknown event type:', event.type);
28163
29276
  }
28164
29277
  }
29278
+
28165
29279
  async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
28166
29280
  let pendingEvent = initialEvent;
28167
29281
  while (pendingEvent) {
@@ -28188,7 +29302,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28188
29302
  actionId: pendingEvent.action_id,
28189
29303
  input: pendingEvent.input,
28190
29304
  state: pendingEvent.state,
28191
- done: false, // Action not yet completed
29305
+ done: pendingEvent.done ?? false,
28192
29306
  },
28193
29307
  };
28194
29308
  if (streamState.activeToolCallCount === 0) {
@@ -28202,7 +29316,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28202
29316
  id: generateMessageId(),
28203
29317
  message: {
28204
29318
  role: "assistant",
28205
- content: "Sorry, an error occurred. Please try again later.",
29319
+ content: "Sorry, an error occurred.",
28206
29320
  },
28207
29321
  timestamp: new Date().toISOString(),
28208
29322
  sources: [],
@@ -28226,7 +29340,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28226
29340
  console.error("[Widget] Frontend action failed:", error);
28227
29341
  const errorMessageEntry = {
28228
29342
  id: generateMessageId(),
28229
- message: { role: "assistant", content: "Sorry, an error occurred. Please try again later." },
29343
+ message: { role: "assistant", content: "Sorry, an error occurred." },
28230
29344
  timestamp: new Date().toISOString(),
28231
29345
  sources: [],
28232
29346
  isError: true,
@@ -28238,12 +29352,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28238
29352
  pendingEvent = null;
28239
29353
  const updatedToolMessage = {
28240
29354
  ...toolMessage,
28241
- action: toolMessage.action
28242
- ? {
28243
- ...toolMessage.action,
28244
- state: nextState,
28245
- }
28246
- : undefined,
29355
+ action: toolMessage.action ? { ...toolMessage.action, state: nextState } : toolMessage.action,
28247
29356
  };
28248
29357
  upsertMessage(setState, updatedToolMessage, true);
28249
29358
  let streamEnded = false;
@@ -28253,22 +29362,20 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28253
29362
  break;
28254
29363
  }
28255
29364
  if (event.type === "done") {
28256
- // Don't extract and update state from done event - the state was already
28257
- // updated by tool_end event or by the user's frontend action.
29365
+ // Finalize tool message and stream messages
28258
29366
  finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
28259
- // Handle the done event but skip the tool finalization part since we already did it
28260
29367
  streamState.sources = event.sources;
28261
29368
  streamState.toolCallToActionId = event.tool_call_to_action_id;
28262
29369
  finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
28263
29370
  streamEnded = true;
28264
- continue; // Skip handleStreamEvent for done events to avoid state conflicts
29371
+ continue;
28265
29372
  }
28266
29373
  if (event.type === "error") {
28267
29374
  const errorMessage = {
28268
29375
  id: generateMessageId(),
28269
29376
  message: {
28270
29377
  role: "assistant",
28271
- content: "Sorry, an error occurred. Please try again later.",
29378
+ content: "Sorry, an error occurred.",
28272
29379
  },
28273
29380
  timestamp: new Date().toISOString(),
28274
29381
  sources: [],
@@ -28279,73 +29386,79 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
28279
29386
  }
28280
29387
  handleStreamEvent(event, streamState, onMessageUpdate, setState);
28281
29388
  }
28282
- // 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
28283
29390
  if (!streamEnded && !pendingEvent) {
28284
29391
  finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
28285
29392
  }
28286
29393
  }
28287
29394
  }
28288
- function deriveErrorInfo(error) {
28289
- if (error instanceof ApiError) {
28290
- const retryAfterSeconds = typeof error.retryAfterMs === 'number'
28291
- ? Math.max(1, Math.ceil(error.retryAfterMs / 1000))
28292
- : undefined;
28293
- const lowerMessage = (error.message || '').toLowerCase();
28294
- let message;
28295
- switch (error.status) {
28296
- case 429: {
28297
- const isPerUser = lowerMessage.includes('user');
28298
- const base = isPerUser
28299
- ? 'You have reached the per-user rate limit.'
28300
- : 'This widget has received too many requests.';
28301
- if (retryAfterSeconds) {
28302
- message = `${base} Please wait ${retryAfterSeconds} second${retryAfterSeconds === 1 ? '' : 's'} before trying again.`;
28303
- }
28304
- else {
28305
- message = `${base} Please wait a moment and try again.`;
28306
- }
28307
- break;
28308
- }
28309
- case 401:
28310
- message = 'Authentication failed. Please refresh the page or verify your API key.';
28311
- break;
28312
- case 403:
28313
- message = 'Access to this widget is restricted. Please contact the site owner if you believe this is an error.';
28314
- break;
28315
- case 404:
28316
- message = 'We could not find this widget. It may have been removed.';
28317
- break;
28318
- default:
28319
- if (error.status >= 500) {
28320
- message = 'The server encountered an error. Please try again shortly.';
28321
- }
28322
- else if (error.status > 0) {
28323
- 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 }));
28324
29446
  }
28325
- else {
28326
- 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 }));
28327
29450
  }
29451
+ });
28328
29452
  }
28329
- return { message, retryAfterSeconds, status: error.status };
28330
- }
28331
- if (error instanceof Error) {
28332
- const lower = error.message.toLowerCase();
28333
- if (lower.includes('network')) {
28334
- return { message: 'Unable to connect to the server. Please check your internet connection.' };
28335
- }
28336
- if (lower.includes('timeout')) {
28337
- return { message: 'The request timed out. Please try again.' };
28338
- }
28339
- if (lower.includes('unauthorized') || lower.includes('401')) {
28340
- return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
28341
- }
28342
- if (lower.includes('internal server error') || lower.includes('500')) {
28343
- return { message: 'The server encountered an error. Please try again shortly.' };
28344
- }
28345
- return { message: error.message || 'Something went wrong. Please try again.' };
28346
29453
  }
28347
- return { message: 'Something went wrong. Please try again.' };
28348
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();
28349
29462
  function useChat(options) {
28350
29463
  const { widgetId, apiUrl, currentRoute, onMessage, onError, skipInitialization = false, } = options;
28351
29464
  const [state, setState] = useState({
@@ -28354,23 +29467,24 @@ function useChat(options) {
28354
29467
  isLoading: false,
28355
29468
  isTyping: false,
28356
29469
  error: null,
28357
- conversationId: '', // Will be set after loading conversation
29470
+ conversationId: '',
28358
29471
  config: null,
28359
29472
  });
28360
29473
  const stateRef = useRef(state);
28361
29474
  useEffect(() => {
28362
29475
  stateRef.current = state;
28363
29476
  }, [state]);
28364
- // Chat history state
28365
29477
  const [conversations, setConversations] = useState([]);
29478
+ const abortControllerRef = useRef(null);
29479
+ const currentRequestIdRef = useRef(null);
29480
+ const lastNewChatTimeRef = useRef(0);
29481
+ const NEW_CHAT_COOLDOWN_MS = 5000;
28366
29482
  const apiClient = useRef(new WidgetApiClient({ widgetId, apiUrl, currentRoute }));
28367
- // Update API client when currentRoute changes
28368
29483
  useEffect(() => {
28369
29484
  apiClient.current = new WidgetApiClient({ widgetId, apiUrl, currentRoute });
28370
29485
  }, [widgetId, apiUrl, currentRoute]);
28371
29486
  // Load configuration on mount and hydrate with existing conversation if available
28372
29487
  useEffect(() => {
28373
- // Skip initialization in preview mode
28374
29488
  if (skipInitialization) {
28375
29489
  return;
28376
29490
  }
@@ -28407,7 +29521,7 @@ function useChat(options) {
28407
29521
  }));
28408
29522
  // Setup resume callbacks for incomplete actions
28409
29523
  if (conversationId) {
28410
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }));
29524
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
28411
29525
  }
28412
29526
  }
28413
29527
  catch (error) {
@@ -28424,7 +29538,6 @@ function useChat(options) {
28424
29538
  initialize();
28425
29539
  return () => {
28426
29540
  isMounted = false;
28427
- // Cleanup resume callbacks
28428
29541
  state.messages.forEach(message => {
28429
29542
  if (message.action?.toolCallId) {
28430
29543
  unregisterActionResumeCallback(message.action.toolCallId);
@@ -28447,7 +29560,15 @@ function useChat(options) {
28447
29560
  const hasFiles = !!files && files.length > 0;
28448
29561
  if (!trimmedContent && !hasFiles)
28449
29562
  return;
28450
- // Strip [EXECUTE_ACTION:...] prefix from displayed message (but keep for API)
29563
+ if (stateRef.current.isTyping) {
29564
+ console.warn('[Widget] Cannot send message while streaming is in progress');
29565
+ return;
29566
+ }
29567
+ if (abortControllerRef.current) {
29568
+ abortControllerRef.current.abort();
29569
+ abortControllerRef.current = null;
29570
+ }
29571
+ abortControllerRef.current = new AbortController();
28451
29572
  const displayContent = trimmedContent.replace(/^\[EXECUTE_ACTION:[^\]]+\]\s*/, '');
28452
29573
  const userMessage = {
28453
29574
  id: generateMessageId(),
@@ -28458,12 +29579,11 @@ function useChat(options) {
28458
29579
  timestamp: new Date().toISOString(),
28459
29580
  sources: [],
28460
29581
  };
28461
- // Add user message immediately
28462
29582
  setState(prev => ({
28463
29583
  ...prev,
28464
29584
  messages: [...prev.messages, userMessage],
28465
- isLoading: false, // Don't show loading, will show typing when stream starts
28466
- isTyping: true, // Show typing indicator immediately
29585
+ isLoading: false,
29586
+ isTyping: true,
28467
29587
  error: null,
28468
29588
  }));
28469
29589
  onMessage?.(userMessage);
@@ -28503,16 +29623,29 @@ function useChat(options) {
28503
29623
  }
28504
29624
  catch (uploadError) {
28505
29625
  console.error('Failed to upload file:', uploadError);
28506
- // Continue with other files
28507
29626
  }
28508
29627
  }
28509
29628
  }
28510
- // Stream the response
28511
29629
  let lastStreamedMessage = null;
28512
29630
  const streamState = createStreamState();
28513
- const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds);
29631
+ currentRequestIdRef.current = streamState.requestId;
29632
+ const currentAbortController = abortControllerRef.current;
29633
+ const streamConversationId = conversationId;
29634
+ const streamRequestId = streamState.requestId;
29635
+ const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds, currentAbortController?.signal);
28514
29636
  for await (const event of stream) {
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');
29641
+ break;
29642
+ }
28515
29643
  if (event.type === "action_request") {
29644
+ if (currentAbortController?.signal.aborted ||
29645
+ stateRef.current.conversationId !== streamConversationId ||
29646
+ currentRequestIdRef.current !== streamRequestId) {
29647
+ break;
29648
+ }
28516
29649
  await handleActionLoop(apiClient.current, event, streamState, (message) => {
28517
29650
  lastStreamedMessage = message;
28518
29651
  }, setState, widgetId, conversationId, () => stateRef.current.messages);
@@ -28522,25 +29655,26 @@ function useChat(options) {
28522
29655
  lastStreamedMessage = message;
28523
29656
  }, setState);
28524
29657
  }
28525
- // Stream completed - finalize state
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');
29662
+ return;
29663
+ }
28526
29664
  setState(prev => ({
28527
29665
  ...prev,
28528
29666
  isLoading: false,
28529
29667
  isTyping: false,
28530
29668
  }));
28531
- // Notify about final message
28532
29669
  if (lastStreamedMessage) {
28533
29670
  onMessage?.(lastStreamedMessage);
28534
29671
  }
28535
- // Generate follow-up suggestions asynchronously
28536
29672
  const enableFollowUps = state.config?.settings.enableFollowUpSuggestions !== false;
28537
29673
  const actionIds = state.config?.actions || [];
28538
29674
  if (enableFollowUps) {
28539
- // Don't await - let it run in background
28540
29675
  apiClient.current.generateFollowUps(stateRef.current.messages, actionIds)
28541
29676
  .then(suggestions => {
28542
29677
  if (suggestions.length > 0) {
28543
- // Attach suggestions to the last assistant message
28544
29678
  setState(prev => {
28545
29679
  const messages = [...prev.messages];
28546
29680
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -28569,7 +29703,7 @@ function useChat(options) {
28569
29703
  },
28570
29704
  timestamp: new Date().toISOString(),
28571
29705
  sources: [],
28572
- isError: !fallbackMessage, // Only mark as error if using default message
29706
+ isError: !fallbackMessage,
28573
29707
  };
28574
29708
  setState(prev => ({
28575
29709
  ...prev,
@@ -28581,9 +29715,6 @@ function useChat(options) {
28581
29715
  onError?.(err);
28582
29716
  }
28583
29717
  }, [state.conversationId, state.config, state.messages, onMessage, onError]);
28584
- /**
28585
- * Clear all messages
28586
- */
28587
29718
  const clearMessages = useCallback(() => {
28588
29719
  setState(prev => ({
28589
29720
  ...prev,
@@ -28596,9 +29727,6 @@ function useChat(options) {
28596
29727
  clearConversation(widgetId);
28597
29728
  }
28598
29729
  }, [widgetId, state.config?.settings.persistConversation]);
28599
- /**
28600
- * Submit feedback for a message
28601
- */
28602
29730
  const submitFeedback = useCallback(async (messageId, feedback) => {
28603
29731
  try {
28604
29732
  const message = state.messages.find(msg => msg.id === messageId);
@@ -28608,7 +29736,6 @@ function useChat(options) {
28608
29736
  : undefined;
28609
29737
  console.log('Submitting feedback:', { conversationId: state.conversationId, messageId, feedback });
28610
29738
  await apiClient.current.submitFeedback(state.conversationId, messageId, feedback, meta);
28611
- // Update message with feedback
28612
29739
  setState(prev => ({
28613
29740
  ...prev,
28614
29741
  messages: prev.messages.map(msg => msg.id === messageId
@@ -28623,9 +29750,6 @@ function useChat(options) {
28623
29750
  onError?.(err);
28624
29751
  }
28625
29752
  }, [state.conversationId, onError]);
28626
- /**
28627
- * Load conversation history list from localStorage
28628
- */
28629
29753
  const loadConversations = useCallback(() => {
28630
29754
  const persistConversation = state.config?.settings.persistConversation ?? true;
28631
29755
  if (!persistConversation || !isStorageAvailable()) {
@@ -28642,8 +29766,11 @@ function useChat(options) {
28642
29766
  })));
28643
29767
  }, [widgetId, state.config?.settings.persistConversation]);
28644
29768
  const switchConversation = useCallback(async (conversationId) => {
29769
+ if (abortControllerRef.current) {
29770
+ abortControllerRef.current.abort();
29771
+ abortControllerRef.current = null;
29772
+ }
28645
29773
  const persistConversation = state.config?.settings.persistConversation ?? true;
28646
- // First try to load from localStorage
28647
29774
  if (persistConversation && isStorageAvailable()) {
28648
29775
  const stored = loadConversationById(widgetId, conversationId);
28649
29776
  if (stored) {
@@ -28651,16 +29778,17 @@ function useChat(options) {
28651
29778
  ...prev,
28652
29779
  conversationId: stored.conversationId,
28653
29780
  messages: hydrateMessages(stored.messages),
29781
+ isTyping: false,
29782
+ isLoading: false,
28654
29783
  }));
28655
29784
  setActiveConversation(widgetId, conversationId);
28656
29785
  return;
28657
29786
  }
28658
29787
  }
28659
- setState(prev => ({ ...prev, isLoading: true, error: null }));
29788
+ setState(prev => ({ ...prev, isLoading: true, isTyping: false, error: null }));
28660
29789
  try {
28661
29790
  const conversation = await apiClient.current.getOrCreateConversation(conversationId);
28662
29791
  const hydratedMessages = hydrateMessages(conversation.messages);
28663
- // Clear old resume callbacks
28664
29792
  state.messages.forEach(message => {
28665
29793
  if (message.action?.toolCallId) {
28666
29794
  unregisterActionResumeCallback(message.action.toolCallId);
@@ -28672,9 +29800,7 @@ function useChat(options) {
28672
29800
  messages: hydratedMessages,
28673
29801
  isLoading: false,
28674
29802
  }));
28675
- // Setup new resume callbacks
28676
- setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }));
28677
- // Save to local storage
29803
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
28678
29804
  if (persistConversation && isStorageAvailable()) {
28679
29805
  saveConversation(widgetId, conversation.id, hydratedMessages);
28680
29806
  }
@@ -28685,11 +29811,23 @@ function useChat(options) {
28685
29811
  }
28686
29812
  }, [widgetId, state.config?.settings.persistConversation]);
28687
29813
  const startNewConversation = useCallback(() => {
29814
+ const now = Date.now();
29815
+ if (now - lastNewChatTimeRef.current < NEW_CHAT_COOLDOWN_MS) {
29816
+ console.warn('[Widget] New chat rate limited - please wait');
29817
+ return;
29818
+ }
29819
+ lastNewChatTimeRef.current = now;
29820
+ if (abortControllerRef.current) {
29821
+ abortControllerRef.current.abort();
29822
+ abortControllerRef.current = null;
29823
+ }
28688
29824
  setState(prev => ({
28689
29825
  ...prev,
28690
29826
  messages: [],
28691
29827
  conversationId: '',
28692
29828
  error: null,
29829
+ isTyping: false,
29830
+ isLoading: false,
28693
29831
  }));
28694
29832
  const persistConversation = state.config?.settings.persistConversation ?? true;
28695
29833
  if (persistConversation && isStorageAvailable()) {
@@ -28701,11 +29839,8 @@ function useChat(options) {
28701
29839
  if (!persistConversation || !isStorageAvailable()) {
28702
29840
  return;
28703
29841
  }
28704
- // Delete from storage
28705
29842
  deleteConversation(widgetId, conversationId);
28706
- // Update local state
28707
29843
  setConversations(prev => prev.filter(c => c.id !== conversationId));
28708
- // If we deleted the current conversation, clear it
28709
29844
  if (state.conversationId === conversationId) {
28710
29845
  setState(prev => ({
28711
29846
  ...prev,
@@ -28725,7 +29860,6 @@ function useChat(options) {
28725
29860
  sendMessage,
28726
29861
  clearMessages,
28727
29862
  submitFeedback,
28728
- // Chat history features
28729
29863
  conversations,
28730
29864
  loadConversations,
28731
29865
  switchConversation,
@@ -28734,11 +29868,20 @@ function useChat(options) {
28734
29868
  };
28735
29869
  }
28736
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
+
28737
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" })] }));
28738
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" })] }));
28739
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" })] }));
28740
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" })] }));
28741
- 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,
28742
29885
  // Chat history props (only active when persistConversation is true)
28743
29886
  conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
28744
29887
  // Override props for live preview
@@ -28755,6 +29898,8 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
28755
29898
  const inputPlaceholder = placeholderOverride ?? appearance?.placeholder ?? 'Ask me anything...';
28756
29899
  // Track if history panel is open
28757
29900
  const [showHistory, setShowHistory] = useState(false);
29901
+ // Track if data policy view is open
29902
+ const [showDataPolicy, setShowDataPolicy] = useState(false);
28758
29903
  // Scroll button state (managed by MessageList)
28759
29904
  const [showScrollButton, setShowScrollButton] = useState(false);
28760
29905
  const [scrollToBottom, setScrollToBottom] = useState(null);
@@ -28764,6 +29909,13 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
28764
29909
  }, []);
28765
29910
  // History exit animation when starting a new chat from overview
28766
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
+ }, []);
28767
29919
  // Load conversations when history panel opens
28768
29920
  const handleOpenHistory = () => {
28769
29921
  setShowHistory(true);
@@ -28811,10 +29963,22 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
28811
29963
  // The backend will detect and trigger the action based on the message
28812
29964
  onSendMessage(question);
28813
29965
  };
28814
- 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) => {
28815
29969
  e.stopPropagation();
28816
29970
  onDeleteConversation(conv.id);
28817
- }, "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, enableFeedback: settings?.enableFeedback, showSources: settings?.showSources, sourceDisplayMode: settings?.sourceDisplayMode, 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' : inputPlaceholder, disabled: isLoading || 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 })] }))] }));
28818
29982
  };
28819
29983
 
28820
29984
  /**
@@ -29220,7 +30384,7 @@ function styleInject(css, ref) {
29220
30384
  if ( ref === void 0 ) ref = {};
29221
30385
  var insertAt = ref.insertAt;
29222
30386
 
29223
- if (typeof document === 'undefined') { return; }
30387
+ if (!css || typeof document === 'undefined') { return; }
29224
30388
 
29225
30389
  var head = document.head || document.getElementsByTagName('head')[0];
29226
30390
  var style = document.createElement('style');
@@ -29243,7 +30407,10 @@ function styleInject(css, ref) {
29243
30407
  }
29244
30408
  }
29245
30409
 
29246
- 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-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{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{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-md) 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,44px);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,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,8px);color:var(--text-muted,#71717a);cursor:pointer;display:flex;flex-shrink:0;height:32px;justify-content:center;margin-left:auto;margin-right:var(--space-2xs,2px);opacity:0;transition:opacity var(--duration-fast,.15s) ease,background var(--duration-fast,.15s) ease,color var(--duration-fast,.15s) ease;width:32px}.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:#22c55e;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%}.ai-chat-sources{background:rgba(0,0,0,.02);border-radius:6px;font-size:var(--text-xs);margin-top:var(--space-sm);overflow:hidden}.ai-chat-sources-toggle{align-items:center;background:none;border:none;cursor:pointer;display:flex;gap:6px;padding:var(--space-sm) 10px;text-align:left;transition:background var(--duration-fast) ease;width:100%}.ai-chat-sources-toggle:hover{background:rgba(0,0,0,.03)}.ai-chat-sources-icon{color:var(--text-muted);font-size:10px;transition:transform var(--duration-fast) ease}.ai-chat-sources-title{color:var(--text-primary);flex:1;font-size:11px;font-weight:var(--font-weight-semibold);letter-spacing:.5px;text-transform:uppercase}.ai-chat-source-item{border-top:1px solid rgba(0,0,0,.05);color:var(--text-muted);display:flex;gap:var(--space-sm);padding:var(--space-sm) 10px}.ai-chat-source-item:last-child{border-bottom:none}.ai-chat-source-number{color:var(--btn-primary-bg);flex-shrink:0;font-weight:var(--font-weight-semibold)}.ai-chat-source-details{display:flex;flex:1;flex-direction:column;gap:var(--space-xs)}.ai-chat-source-score{color:var(--text-placeholder);font-size:11px}.ai-chat-source-content{color:var(--text-muted);font-size:11px;font-style:italic;line-height:var(--line-height-normal)}.ai-chat-source-metadata{display:flex;flex-wrap:wrap;gap:6px;margin-top:2px}.ai-chat-source-meta-item{background:rgba(0,0,0,.05);border-radius:3px;color:var(--text-muted);font-size:10px;padding:2px 6px}";
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}";
29247
30414
  styleInject(css_248z);
29248
30415
 
29249
30416
  // Icon components mapping
@@ -29251,9 +30418,10 @@ const iconComponents = {
29251
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" }) })),
29252
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" }) })),
29253
30420
  };
29254
- 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', }) => {
29255
30422
  const [isOpen, setIsOpen] = useState(defaultOpen);
29256
30423
  const [autoDetectedTheme, setAutoDetectedTheme] = useState('light');
30424
+ const [showWelcomeBubble, setShowWelcomeBubble] = useState(false);
29257
30425
  const widgetRef = useRef(null);
29258
30426
  const containerRef = useRef(null);
29259
30427
  // Determine mode
@@ -29275,10 +30443,9 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29275
30443
  showChatHistory: true,
29276
30444
  showTimestamps: true,
29277
30445
  showTypingIndicator: true,
30446
+ showToolCalls: false,
29278
30447
  enableFileUpload: false,
29279
30448
  enableFeedback: true,
29280
- showSources: false,
29281
- sourceDisplayMode: 'none',
29282
30449
  },
29283
30450
  behavior: {
29284
30451
  agentic: false,
@@ -29315,7 +30482,6 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29315
30482
  const messages = previewMode ? [] : chatHook.messages;
29316
30483
  const isLoading = previewMode ? false : chatHook.isLoading;
29317
30484
  const isTyping = previewMode ? false : chatHook.isTyping;
29318
- const error = previewMode ? null : chatHook.error;
29319
30485
  const config = previewMode ? mergedPreviewConfig : chatHook.config;
29320
30486
  const sendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
29321
30487
  const submitFeedback = previewMode ? (() => Promise.resolve()) : chatHook.submitFeedback;
@@ -29350,8 +30516,13 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29350
30516
  mediaQuery.removeEventListener('change', handleMediaChange);
29351
30517
  };
29352
30518
  }, [config]);
29353
- // 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)
29354
30522
  useEffect(() => {
30523
+ // Never auto-open on mobile devices
30524
+ if (isMobile)
30525
+ return undefined;
29355
30526
  if (!isEmbedded && config?.settings.autoOpen) {
29356
30527
  const delay = config.settings.autoOpenDelay || 0;
29357
30528
  const timer = setTimeout(() => {
@@ -29361,7 +30532,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29361
30532
  return () => clearTimeout(timer);
29362
30533
  }
29363
30534
  return undefined;
29364
- }, [config, onOpen, isEmbedded]);
30535
+ }, [config, onOpen, isEmbedded, isMobile]);
29365
30536
  // Handle close on Escape key (only for bubble mode)
29366
30537
  useEffect(() => {
29367
30538
  if (!isOpen || isEmbedded)
@@ -29375,6 +30546,37 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29375
30546
  document.addEventListener('keydown', handleEscapeKey);
29376
30547
  return () => document.removeEventListener('keydown', handleEscapeKey);
29377
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]);
29378
30580
  // Determine theme - use prop override if provided, otherwise auto-detect
29379
30581
  const appearanceConfig = config?.appearance;
29380
30582
  const effectiveTheme = theme ?? autoDetectedTheme;
@@ -29388,6 +30590,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29388
30590
  const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? '';
29389
30591
  const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? '';
29390
30592
  const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? '';
30593
+ const effectiveWelcomeBubbleText = welcomeBubbleText ?? appearanceConfig?.welcomeBubbleText ?? '';
29391
30594
  // Generate styles using simplified theme system
29392
30595
  const simpleAppearance = {
29393
30596
  accentColor};
@@ -29409,6 +30612,18 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29409
30612
  return;
29410
30613
  const newState = !isOpen;
29411
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
+ }
29412
30627
  if (newState) {
29413
30628
  onOpen?.();
29414
30629
  }
@@ -29439,13 +30654,13 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
29439
30654
  const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
29440
30655
  // Embedded mode renders directly without wrapper positioning
29441
30656
  if (isEmbedded) {
29442
- 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 }) }));
29443
30658
  }
29444
- 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,
29445
30660
  // Chat history props (only active when persistConversation is true)
29446
30661
  conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId,
29447
30662
  // Override props for live preview
29448
- 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, {}) }) })] }) }));
29449
30664
  };
29450
30665
 
29451
30666
  export { ApiError, ChatWidget, useChat };