@chatwidgetai/chat-widget 0.3.1 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-chat-widget.umd.js +1890 -1018
- package/dist/ai-chat-widget.umd.js.map +1 -1
- package/dist/api/client.d.ts +21 -2
- package/dist/api/client.d.ts.map +1 -1
- package/dist/components/ChatWidget/hooks/useWidgetAppearance.d.ts +37 -0
- package/dist/components/ChatWidget/hooks/useWidgetAppearance.d.ts.map +1 -0
- package/dist/components/ChatWidget/icons.d.ts +2 -0
- package/dist/components/ChatWidget/icons.d.ts.map +1 -0
- package/dist/components/ChatWidget/parts/WidgetTriggers.d.ts +25 -0
- package/dist/components/ChatWidget/parts/WidgetTriggers.d.ts.map +1 -0
- package/dist/components/ChatWidget.d.ts.map +1 -1
- package/dist/components/ChatWindow.d.ts +5 -1
- package/dist/components/ChatWindow.d.ts.map +1 -1
- package/dist/components/DataPolicyView.d.ts.map +1 -1
- package/dist/components/WelcomeBubble.d.ts +12 -0
- package/dist/components/WelcomeBubble.d.ts.map +1 -0
- package/dist/components/icons.d.ts +21 -0
- package/dist/components/icons.d.ts.map +1 -0
- package/dist/components/triggers/ButtonTrigger.d.ts +11 -0
- package/dist/components/triggers/ButtonTrigger.d.ts.map +1 -0
- package/dist/components/triggers/InputBarTrigger.d.ts +18 -0
- package/dist/components/triggers/InputBarTrigger.d.ts.map +1 -0
- package/dist/components/triggers/PillTrigger.d.ts +12 -0
- package/dist/components/triggers/PillTrigger.d.ts.map +1 -0
- package/dist/components/triggers/index.d.ts +8 -0
- package/dist/components/triggers/index.d.ts.map +1 -0
- package/dist/hooks/useChat/action-handler.d.ts +17 -1
- package/dist/hooks/useChat/action-handler.d.ts.map +1 -1
- package/dist/hooks/useChat/action-lifecycle.d.ts.map +1 -1
- package/dist/hooks/useChat/index.d.ts +7 -0
- package/dist/hooks/useChat/index.d.ts.map +1 -1
- package/dist/hooks/useChat/message-hydration.d.ts.map +1 -1
- package/dist/hooks/useChat/stream-buffer.d.ts +18 -0
- package/dist/hooks/useChat/stream-buffer.d.ts.map +1 -0
- package/dist/hooks/useChat/stream-handlers.d.ts +3 -3
- package/dist/hooks/useChat/stream-handlers.d.ts.map +1 -1
- package/dist/hooks/useChat/stream-state.d.ts.map +1 -1
- package/dist/hooks/useChat/types.d.ts +2 -0
- package/dist/hooks/useChat/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +1891 -1019
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1891 -1018
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +12 -85
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -16898,31 +16898,83 @@
|
|
|
16898
16898
|
return typeof data === 'object' && data !== null && 'type' in data;
|
|
16899
16899
|
});
|
|
16900
16900
|
}
|
|
16901
|
-
async *
|
|
16901
|
+
async *dismissAgentMessageStream(conversationId, toolCallId, signal) {
|
|
16902
16902
|
const headers = {
|
|
16903
16903
|
'Content-Type': 'application/json',
|
|
16904
16904
|
};
|
|
16905
16905
|
if (this.config.currentRoute) {
|
|
16906
16906
|
headers['X-Current-Route'] = this.config.currentRoute;
|
|
16907
16907
|
}
|
|
16908
|
-
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/
|
|
16908
|
+
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/dismiss`, {
|
|
16909
16909
|
method: 'POST',
|
|
16910
16910
|
headers,
|
|
16911
16911
|
body: JSON.stringify({
|
|
16912
16912
|
conversationId: conversationId,
|
|
16913
16913
|
toolCallId,
|
|
16914
|
-
|
|
16914
|
+
reason: "user",
|
|
16915
|
+
}),
|
|
16916
|
+
signal,
|
|
16917
|
+
});
|
|
16918
|
+
if (response.status === 204) {
|
|
16919
|
+
return;
|
|
16920
|
+
}
|
|
16921
|
+
if (!response.ok) {
|
|
16922
|
+
throw await buildApiError(response, 'Failed to dismiss action');
|
|
16923
|
+
}
|
|
16924
|
+
yield* parseSSEStream(response, (data) => {
|
|
16925
|
+
return typeof data === 'object' && data !== null && 'type' in data;
|
|
16926
|
+
});
|
|
16927
|
+
}
|
|
16928
|
+
/**
|
|
16929
|
+
* Continue agent after halting action completes
|
|
16930
|
+
* Call this when frontend completes an action and wants to pass result back to agent
|
|
16931
|
+
*/
|
|
16932
|
+
async *continueAgentAction(conversationId, toolCallId, body, signal) {
|
|
16933
|
+
const headers = {
|
|
16934
|
+
'Content-Type': 'application/json',
|
|
16935
|
+
};
|
|
16936
|
+
if (this.config.currentRoute) {
|
|
16937
|
+
headers['X-Current-Route'] = this.config.currentRoute;
|
|
16938
|
+
}
|
|
16939
|
+
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/continue`, {
|
|
16940
|
+
method: 'POST',
|
|
16941
|
+
headers,
|
|
16942
|
+
body: JSON.stringify({
|
|
16943
|
+
conversationId,
|
|
16944
|
+
toolCallId,
|
|
16945
|
+
body,
|
|
16915
16946
|
timeZone: this.getTimeZone(),
|
|
16916
16947
|
}),
|
|
16917
16948
|
signal,
|
|
16918
16949
|
});
|
|
16919
16950
|
if (!response.ok) {
|
|
16920
|
-
throw await buildApiError(response, 'Failed to continue agent');
|
|
16951
|
+
throw await buildApiError(response, 'Failed to continue agent action');
|
|
16921
16952
|
}
|
|
16922
16953
|
yield* parseSSEStream(response, (data) => {
|
|
16923
16954
|
return typeof data === 'object' && data !== null && 'type' in data;
|
|
16924
16955
|
});
|
|
16925
16956
|
}
|
|
16957
|
+
/**
|
|
16958
|
+
* NEW: Call action endpoint (frontend-owned flow)
|
|
16959
|
+
* Used for multi-step actions like booking appointments
|
|
16960
|
+
*/
|
|
16961
|
+
async callActionEndpoint(actionId, endpoint, input, token) {
|
|
16962
|
+
const headers = {
|
|
16963
|
+
'Content-Type': 'application/json',
|
|
16964
|
+
};
|
|
16965
|
+
if (token) {
|
|
16966
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
16967
|
+
}
|
|
16968
|
+
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/actions/${actionId}/${endpoint}`, {
|
|
16969
|
+
method: 'POST',
|
|
16970
|
+
headers,
|
|
16971
|
+
body: JSON.stringify(input),
|
|
16972
|
+
});
|
|
16973
|
+
if (!response.ok) {
|
|
16974
|
+
throw await buildApiError(response, `Action endpoint '${endpoint}' failed`);
|
|
16975
|
+
}
|
|
16976
|
+
return response.json();
|
|
16977
|
+
}
|
|
16926
16978
|
/**
|
|
16927
16979
|
* Submit feedback for a message
|
|
16928
16980
|
*/
|
|
@@ -16953,7 +17005,8 @@
|
|
|
16953
17005
|
}
|
|
16954
17006
|
/**
|
|
16955
17007
|
* Generate follow-up suggestions based on conversation context and available actions.
|
|
16956
|
-
*
|
|
17008
|
+
* @deprecated Follow-ups are now generated server-side in parallel and included in the done event.
|
|
17009
|
+
* This method is kept for backwards compatibility but is no longer called by the widget.
|
|
16957
17010
|
*/
|
|
16958
17011
|
async generateFollowUps(messages, actionIds) {
|
|
16959
17012
|
try {
|
|
@@ -16985,6 +17038,27 @@
|
|
|
16985
17038
|
return [];
|
|
16986
17039
|
}
|
|
16987
17040
|
}
|
|
17041
|
+
/**
|
|
17042
|
+
* Create a demo conversation with preset messages
|
|
17043
|
+
* Used when demo animation completes to persist the demo conversation to the database
|
|
17044
|
+
*/
|
|
17045
|
+
async createDemoConversation(userMessage, assistantMessage) {
|
|
17046
|
+
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/demo-conversation`, {
|
|
17047
|
+
method: 'POST',
|
|
17048
|
+
headers: {
|
|
17049
|
+
'Content-Type': 'application/json',
|
|
17050
|
+
},
|
|
17051
|
+
body: JSON.stringify({
|
|
17052
|
+
userMessage,
|
|
17053
|
+
assistantMessage,
|
|
17054
|
+
timeZone: this.getTimeZone(),
|
|
17055
|
+
}),
|
|
17056
|
+
});
|
|
17057
|
+
if (!response.ok) {
|
|
17058
|
+
throw await buildApiError(response, 'Failed to create demo conversation');
|
|
17059
|
+
}
|
|
17060
|
+
return response.json();
|
|
17061
|
+
}
|
|
16988
17062
|
/**
|
|
16989
17063
|
* Validate widget access
|
|
16990
17064
|
*/
|
|
@@ -43796,7 +43870,7 @@
|
|
|
43796
43870
|
}
|
|
43797
43871
|
|
|
43798
43872
|
// Styles are provided by global messages.css - no component-specific CSS needed
|
|
43799
|
-
function ChevronDownIcon() {
|
|
43873
|
+
function ChevronDownIcon$1() {
|
|
43800
43874
|
return (jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "6 9 12 15 18 9" }) }));
|
|
43801
43875
|
}
|
|
43802
43876
|
function ScrollButton({ onClick, visible, className = '' }) {
|
|
@@ -43805,24 +43879,35 @@
|
|
|
43805
43879
|
visible && 'visible',
|
|
43806
43880
|
className,
|
|
43807
43881
|
].filter(Boolean).join(' ');
|
|
43808
|
-
return (jsxRuntimeExports.jsx("button", { type: "button", className: classes, onClick: onClick, "aria-label": "Scroll to bottom", children: jsxRuntimeExports.jsx(ChevronDownIcon, {}) }));
|
|
43882
|
+
return (jsxRuntimeExports.jsx("button", { type: "button", className: classes, onClick: onClick, "aria-label": "Scroll to bottom", children: jsxRuntimeExports.jsx(ChevronDownIcon$1, {}) }));
|
|
43809
43883
|
}
|
|
43810
43884
|
|
|
43811
43885
|
const formatToolName = (name) => {
|
|
43812
43886
|
return name
|
|
43813
43887
|
.replace(/^(action_|tool_)/, '')
|
|
43888
|
+
.replace(/-/g, '_')
|
|
43814
43889
|
.split('_')
|
|
43815
43890
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
43816
43891
|
.join(' ');
|
|
43817
43892
|
};
|
|
43818
43893
|
function ToolIndicator({ badges, className = '' }) {
|
|
43819
|
-
|
|
43894
|
+
// Consolidate multiple badges into a single status indicator
|
|
43895
|
+
const hasLoading = badges.some(b => b.status === 'loading');
|
|
43896
|
+
const hasError = badges.some(b => b.status === 'error');
|
|
43897
|
+
const status = hasLoading ? 'loading' : hasError ? 'error' : 'completed';
|
|
43898
|
+
// Show only the most relevant badge name, or count if multiple
|
|
43899
|
+
const displayName = badges.length === 1
|
|
43900
|
+
? formatToolName(badges[0].name)
|
|
43901
|
+
: badges.length > 1
|
|
43902
|
+
? `${badges.length} actions`
|
|
43903
|
+
: 'Processing';
|
|
43904
|
+
return (jsxRuntimeExports.jsx("div", { className: `ai-chat-tool-row ${className}`, children: jsxRuntimeExports.jsx("div", { className: "ai-chat-tool-badges", children: jsxRuntimeExports.jsx("div", { className: `ai-chat-tool-badge ${status}`, children: jsxRuntimeExports.jsx("span", { className: "tool-name", children: displayName }) }) }) }));
|
|
43820
43905
|
}
|
|
43821
43906
|
|
|
43822
43907
|
// SVG Icon components
|
|
43823
43908
|
const ThumbsUpIcon = () => (jsxRuntimeExports.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.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" }) }));
|
|
43824
43909
|
const ThumbsDownIcon = () => (jsxRuntimeExports.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.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" }) }));
|
|
43825
|
-
const CheckIcon$
|
|
43910
|
+
const CheckIcon$1 = () => (jsxRuntimeExports.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "20 6 9 17 4 12" }) }));
|
|
43826
43911
|
const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
|
|
43827
43912
|
const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
|
|
43828
43913
|
const [submitted, setSubmitted] = reactExports.useState(false);
|
|
@@ -43843,7 +43928,7 @@
|
|
|
43843
43928
|
setIsSubmitting(false);
|
|
43844
43929
|
}
|
|
43845
43930
|
};
|
|
43846
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsxRuntimeExports.jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsxRuntimeExports.jsx(ThumbsUpIcon, {}) }), jsxRuntimeExports.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: jsxRuntimeExports.jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-feedback-checkmark", children: jsxRuntimeExports.jsx(CheckIcon$
|
|
43931
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsxRuntimeExports.jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsxRuntimeExports.jsx(ThumbsUpIcon, {}) }), jsxRuntimeExports.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: jsxRuntimeExports.jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-feedback-checkmark", children: jsxRuntimeExports.jsx(CheckIcon$1, {}) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-feedback-text", children: "Thanks for feedback" })] }))] }));
|
|
43847
43932
|
};
|
|
43848
43933
|
|
|
43849
43934
|
const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, }) => {
|
|
@@ -43872,9 +43957,11 @@
|
|
|
43872
43957
|
const hasContent = aiContent.trim().length > 0;
|
|
43873
43958
|
if (!hasContent)
|
|
43874
43959
|
return null;
|
|
43875
|
-
|
|
43960
|
+
// Only show timestamp and feedback when message is complete (not streaming)
|
|
43961
|
+
const isComplete = !message.isStreaming;
|
|
43962
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''} ${message.isStreaming ? 'streaming' : ''}`, children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-message-content", children: jsxRuntimeExports.jsx(Markdown, { remarkPlugins: [remarkGfm], components: {
|
|
43876
43963
|
table: ({ children, ...props }) => (jsxRuntimeExports.jsx("div", { className: "table-wrapper", children: jsxRuntimeExports.jsx("div", { className: "table-scroll", children: jsxRuntimeExports.jsx("table", { ...props, children: children }) }) })),
|
|
43877
|
-
}, children: aiContent }) }), showTimestamp && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-message-meta", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsxRuntimeExports.jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
|
|
43964
|
+
}, children: aiContent }) }), showTimestamp && isComplete && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-message-meta", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsxRuntimeExports.jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
|
|
43878
43965
|
}
|
|
43879
43966
|
// System message rendering
|
|
43880
43967
|
if (isSystem) {
|
|
@@ -43894,7 +43981,7 @@
|
|
|
43894
43981
|
return false;
|
|
43895
43982
|
const TERMINAL_STATUSES = [
|
|
43896
43983
|
'completed', 'booked', 'scheduled', 'cancelled', 'failed', 'error',
|
|
43897
|
-
'displaying', 'clicked', 'contacted', 'submitted', 'sent'
|
|
43984
|
+
'displaying', 'displayed', 'clicked', 'contacted', 'submitted', 'sent'
|
|
43898
43985
|
];
|
|
43899
43986
|
const status = state.status;
|
|
43900
43987
|
if (typeof status === 'string' && TERMINAL_STATUSES.includes(status)) {
|
|
@@ -43913,11 +44000,12 @@
|
|
|
43913
44000
|
return false;
|
|
43914
44001
|
if (message.isStreaming)
|
|
43915
44002
|
return true;
|
|
43916
|
-
const
|
|
43917
|
-
return !isActionComplete(
|
|
44003
|
+
const input = message.action.input;
|
|
44004
|
+
return !isActionComplete(input);
|
|
43918
44005
|
}
|
|
43919
|
-
const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant }) => {
|
|
43920
|
-
const
|
|
44006
|
+
const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant, onActionDismiss, onCallEndpoint, }) => {
|
|
44007
|
+
const visibleMessages = messages.filter(message => !message.action?.hidden);
|
|
44008
|
+
const actionMessages = visibleMessages.filter(message => message.action);
|
|
43921
44009
|
// Debug logging
|
|
43922
44010
|
console.log('[DEBUG ToolMessageGroup] ========================================');
|
|
43923
44011
|
console.log('[DEBUG ToolMessageGroup] Total messages:', messages.length);
|
|
@@ -43939,14 +44027,14 @@
|
|
|
43939
44027
|
implementation: impl,
|
|
43940
44028
|
hasRenderer: !!renderer,
|
|
43941
44029
|
rendererType: renderer ? typeof renderer : 'undefined',
|
|
43942
|
-
|
|
44030
|
+
input: msg.action?.input,
|
|
43943
44031
|
});
|
|
43944
44032
|
});
|
|
43945
44033
|
// If tool indicator is hidden AND there are no action cards to render, don't render anything
|
|
43946
44034
|
if (!showToolIndicator && actionMessages.length === 0) {
|
|
43947
44035
|
return null;
|
|
43948
44036
|
}
|
|
43949
|
-
const badges =
|
|
44037
|
+
const badges = visibleMessages.map((message) => {
|
|
43950
44038
|
const toolName = message.toolExecuting || message.message.name || 'Tool';
|
|
43951
44039
|
const hasError = message.isError || false;
|
|
43952
44040
|
const loading = isActionLoading(message);
|
|
@@ -43966,7 +44054,7 @@
|
|
|
43966
44054
|
console.log('[ToolMessageGroup] No renderer for:', message.action.implementation);
|
|
43967
44055
|
return null;
|
|
43968
44056
|
}
|
|
43969
|
-
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant) }, `action-${message.id}`));
|
|
44057
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant, onActionDismiss, onCallEndpoint) }, `action-${message.id}`));
|
|
43970
44058
|
})] }));
|
|
43971
44059
|
};
|
|
43972
44060
|
|
|
@@ -44000,12 +44088,29 @@
|
|
|
44000
44088
|
};
|
|
44001
44089
|
|
|
44002
44090
|
const MAX_TEXT_LENGTH = 40;
|
|
44091
|
+
const STAGGER_DELAY_MS = 200; // Delay between each suggestion appearing
|
|
44003
44092
|
const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, accentColor, }) => {
|
|
44004
|
-
|
|
44005
|
-
return null;
|
|
44006
|
-
}
|
|
44093
|
+
const [visibleIndices, setVisibleIndices] = reactExports.useState(new Set());
|
|
44007
44094
|
// Filter out empty suggestions
|
|
44008
|
-
const validSuggestions = suggestions
|
|
44095
|
+
const validSuggestions = suggestions?.filter(s => s && s.text && s.text.trim()) || [];
|
|
44096
|
+
// Create a stable key for the current suggestions set
|
|
44097
|
+
const suggestionsKey = validSuggestions.map(s => s.id).join(',');
|
|
44098
|
+
// Stagger reveal each suggestion one at a time
|
|
44099
|
+
reactExports.useEffect(() => {
|
|
44100
|
+
// Reset when suggestions change
|
|
44101
|
+
setVisibleIndices(new Set());
|
|
44102
|
+
if (validSuggestions.length === 0)
|
|
44103
|
+
return;
|
|
44104
|
+
const timers = [];
|
|
44105
|
+
// Reveal each suggestion one by one
|
|
44106
|
+
validSuggestions.slice(0, 5).forEach((_, index) => {
|
|
44107
|
+
const timer = setTimeout(() => {
|
|
44108
|
+
setVisibleIndices(prev => new Set([...prev, index]));
|
|
44109
|
+
}, (index + 1) * STAGGER_DELAY_MS);
|
|
44110
|
+
timers.push(timer);
|
|
44111
|
+
});
|
|
44112
|
+
return () => timers.forEach(t => clearTimeout(t));
|
|
44113
|
+
}, [suggestionsKey]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
44009
44114
|
if (validSuggestions.length === 0) {
|
|
44010
44115
|
return null;
|
|
44011
44116
|
}
|
|
@@ -44013,8 +44118,12 @@
|
|
|
44013
44118
|
? { "--primary-color": accentColor }
|
|
44014
44119
|
: undefined;
|
|
44015
44120
|
const trimText = (text) => text.length > MAX_TEXT_LENGTH ? `${text.slice(0, MAX_TEXT_LENGTH)}...` : text;
|
|
44016
|
-
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-follow-up-suggestions", style: containerStyle, children: jsxRuntimeExports.jsx("div", { className: "ai-chat-follow-up-list", children: validSuggestions.slice(0, 5).map((suggestion) => {
|
|
44121
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-follow-up-suggestions", style: containerStyle, children: jsxRuntimeExports.jsx("div", { className: "ai-chat-follow-up-list", children: validSuggestions.slice(0, 5).map((suggestion, index) => {
|
|
44017
44122
|
const isActionSuggestion = suggestion.type === 'action';
|
|
44123
|
+
const isVisible = visibleIndices.has(index);
|
|
44124
|
+
// Only render if visible - this adds items one by one instead of showing all at once
|
|
44125
|
+
if (!isVisible)
|
|
44126
|
+
return null;
|
|
44018
44127
|
const className = `ai-chat-follow-up-item ${isActionSuggestion ? 'action-type' : 'question-type'}`;
|
|
44019
44128
|
const handleClick = () => {
|
|
44020
44129
|
if (isActionSuggestion && onActionClick) {
|
|
@@ -44028,39 +44137,47 @@
|
|
|
44028
44137
|
};
|
|
44029
44138
|
|
|
44030
44139
|
const MessageList = (props) => {
|
|
44031
|
-
const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onFeedback, onScrollStateChange, getActionRenderer, variant, } = props;
|
|
44140
|
+
const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onActionDismiss, onFeedback, onScrollStateChange, getActionRenderer, onCallEndpoint, variant, } = props;
|
|
44032
44141
|
const containerRef = reactExports.useRef(null);
|
|
44033
44142
|
const messagesEndRef = reactExports.useRef(null);
|
|
44034
44143
|
const [showScrollButton, setShowScrollButton] = reactExports.useState(false);
|
|
44035
44144
|
const prevMessageCountRef = reactExports.useRef(0);
|
|
44145
|
+
const visibleMessages = reactExports.useMemo(() => messages.filter((message) => !message.action?.hidden), [messages]);
|
|
44036
44146
|
const hasActiveAction = reactExports.useMemo(() => {
|
|
44037
44147
|
// Find the last tool message and check if its action is still active (not done)
|
|
44038
|
-
const lastToolMsg = [...
|
|
44148
|
+
const lastToolMsg = [...visibleMessages].reverse().find(msg => msg.message.role === 'tool');
|
|
44039
44149
|
return lastToolMsg?.action && lastToolMsg.action.done !== true;
|
|
44040
|
-
}, [
|
|
44041
|
-
const checkScrollPosition = reactExports.useCallback(() => {
|
|
44042
|
-
const c = containerRef.current;
|
|
44043
|
-
if (!c)
|
|
44044
|
-
return;
|
|
44045
|
-
const pb = parseInt(getComputedStyle(c).paddingBottom || '0', 10);
|
|
44046
|
-
setShowScrollButton(c.scrollHeight - c.scrollTop - c.clientHeight - pb > 24);
|
|
44047
|
-
}, []);
|
|
44150
|
+
}, [visibleMessages]);
|
|
44048
44151
|
const scrollToBottom = reactExports.useCallback(() => {
|
|
44049
44152
|
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
44050
44153
|
}, []);
|
|
44051
|
-
|
|
44154
|
+
// Use IntersectionObserver to detect when the end marker is visible
|
|
44155
|
+
// This is more reliable than scroll position calculations
|
|
44052
44156
|
reactExports.useEffect(() => {
|
|
44053
|
-
const
|
|
44054
|
-
|
|
44157
|
+
const endMarker = messagesEndRef.current;
|
|
44158
|
+
const container = containerRef.current;
|
|
44159
|
+
if (!endMarker || !container)
|
|
44055
44160
|
return;
|
|
44056
|
-
|
|
44057
|
-
|
|
44058
|
-
|
|
44161
|
+
const observer = new IntersectionObserver((entries) => {
|
|
44162
|
+
// If the end marker is intersecting (visible), hide the button
|
|
44163
|
+
// If it's not visible, show the button
|
|
44164
|
+
const isAtBottom = entries[0]?.isIntersecting ?? false;
|
|
44165
|
+
setShowScrollButton(!isAtBottom);
|
|
44166
|
+
}, {
|
|
44167
|
+
root: container,
|
|
44168
|
+
// rootMargin adds extra space - if end marker is within 100px of viewport, consider it "visible"
|
|
44169
|
+
rootMargin: '0px 0px 100px 0px',
|
|
44170
|
+
threshold: 0,
|
|
44171
|
+
});
|
|
44172
|
+
observer.observe(endMarker);
|
|
44173
|
+
return () => observer.disconnect();
|
|
44174
|
+
}, []);
|
|
44175
|
+
reactExports.useEffect(() => { onScrollStateChange?.(showScrollButton, scrollToBottom); }, [showScrollButton, scrollToBottom, onScrollStateChange]);
|
|
44059
44176
|
reactExports.useEffect(() => {
|
|
44060
44177
|
const c = containerRef.current;
|
|
44061
44178
|
if (!c)
|
|
44062
44179
|
return;
|
|
44063
|
-
const count =
|
|
44180
|
+
const count = visibleMessages.length;
|
|
44064
44181
|
const isNew = count > prevMessageCountRef.current;
|
|
44065
44182
|
prevMessageCountRef.current = count;
|
|
44066
44183
|
if (count === 0) {
|
|
@@ -44070,32 +44187,18 @@
|
|
|
44070
44187
|
if ((isNew || isTyping) && c.scrollHeight - c.scrollTop - c.clientHeight < 150) {
|
|
44071
44188
|
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
44072
44189
|
}
|
|
44073
|
-
|
|
44074
|
-
}, [messages, isTyping, checkScrollPosition]);
|
|
44190
|
+
}, [visibleMessages, isTyping]);
|
|
44075
44191
|
const groupedMessages = reactExports.useMemo(() => {
|
|
44076
|
-
console.log('[DEBUG MessageList] ========================================');
|
|
44077
|
-
console.log('[DEBUG MessageList] Processing messages:', messages.length);
|
|
44078
|
-
messages.forEach((m, i) => {
|
|
44079
|
-
console.log(`[DEBUG MessageList] Message ${i}:`, {
|
|
44080
|
-
id: m.id,
|
|
44081
|
-
role: m.message.role,
|
|
44082
|
-
hasAction: !!m.action,
|
|
44083
|
-
actionImpl: m.action?.implementation,
|
|
44084
|
-
content: (m.message.content || '').substring(0, 50),
|
|
44085
|
-
});
|
|
44086
|
-
});
|
|
44087
44192
|
const result = [];
|
|
44088
44193
|
let toolGroup = [];
|
|
44089
44194
|
const flush = () => {
|
|
44090
44195
|
if (toolGroup.length) {
|
|
44091
|
-
console.log('[DEBUG MessageList] Flushing tool group with', toolGroup.length, 'messages');
|
|
44092
44196
|
result.push({ type: 'tool-group', messages: [...toolGroup] });
|
|
44093
44197
|
toolGroup = [];
|
|
44094
44198
|
}
|
|
44095
44199
|
};
|
|
44096
|
-
for (const m of
|
|
44200
|
+
for (const m of visibleMessages) {
|
|
44097
44201
|
if (m.message.role === 'tool') {
|
|
44098
|
-
console.log('[DEBUG MessageList] Adding to tool group:', m.id);
|
|
44099
44202
|
toolGroup.push(m);
|
|
44100
44203
|
}
|
|
44101
44204
|
else if (m.message.role === 'user') {
|
|
@@ -44117,27 +44220,26 @@
|
|
|
44117
44220
|
}
|
|
44118
44221
|
}
|
|
44119
44222
|
flush();
|
|
44120
|
-
console.log('[DEBUG MessageList] Final grouped result:', result.length, 'items');
|
|
44121
|
-
result.forEach((item, i) => {
|
|
44122
|
-
if (item.type === 'tool-group') {
|
|
44123
|
-
console.log(`[DEBUG MessageList] Group ${i}: tool-group with ${item.messages.length} messages`);
|
|
44124
|
-
}
|
|
44125
|
-
else {
|
|
44126
|
-
console.log(`[DEBUG MessageList] Group ${i}: message (${item.message.message.role})`);
|
|
44127
|
-
}
|
|
44128
|
-
});
|
|
44129
44223
|
return result;
|
|
44130
|
-
}, [
|
|
44131
|
-
|
|
44224
|
+
}, [visibleMessages]);
|
|
44225
|
+
// Get the last assistant message's suggestions for rendering at the end
|
|
44226
|
+
const lastAssistantSuggestions = reactExports.useMemo(() => {
|
|
44227
|
+
for (let i = groupedMessages.length - 1; i >= 0; i--) {
|
|
44228
|
+
const item = groupedMessages[i];
|
|
44229
|
+
if (item.type === 'message' && item.message.message.role === 'assistant') {
|
|
44230
|
+
return item.message.suggestions;
|
|
44231
|
+
}
|
|
44232
|
+
}
|
|
44233
|
+
return undefined;
|
|
44234
|
+
}, [groupedMessages]);
|
|
44235
|
+
const hasSuggestions = visibleMessages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
|
|
44132
44236
|
const showWelcome = welcomeTitle || welcomeMessage || hasSuggestions;
|
|
44133
44237
|
return (jsxRuntimeExports.jsxs("div", { ref: containerRef, className: "ai-chat-messages", role: "log", "aria-live": "polite", children: [showWelcome && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-welcome", children: [welcomeTitle && jsxRuntimeExports.jsx("div", { className: "ai-chat-welcome-title", children: welcomeTitle }), welcomeMessage && jsxRuntimeExports.jsx("div", { className: "ai-chat-welcome-text", children: welcomeMessage }), hasSuggestions && jsxRuntimeExports.jsx(SuggestedQuestions, { questions: suggestedQuestions, onQuestionClick: onSuggestedQuestionClick })] })), groupedMessages.map((item, i) => {
|
|
44134
44238
|
if (item.type === 'tool-group') {
|
|
44135
|
-
return jsxRuntimeExports.jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant }, `tg-${i}`);
|
|
44239
|
+
return (jsxRuntimeExports.jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant, onActionDismiss: onActionDismiss, onCallEndpoint: onCallEndpoint }, `tg-${i}`));
|
|
44136
44240
|
}
|
|
44137
|
-
|
|
44138
|
-
|
|
44139
|
-
return (jsxRuntimeExports.jsxs(React.Fragment, { children: [jsxRuntimeExports.jsx(Message, { message: item.message, showTimestamp: showTimestamps, onFeedback: onFeedback, getActionRenderer: getActionRenderer, accentColor: accentColor }), hasFollowUp && onSuggestedQuestionClick && jsxRuntimeExports.jsx(FollowUpSuggestions, { suggestions: item.message.suggestions, onQuestionClick: onSuggestedQuestionClick, onActionClick: onActionClick, accentColor: accentColor })] }, item.message.id));
|
|
44140
|
-
}), isTyping && showTypingIndicator && !hasActiveAction && messages.length > 0 && jsxRuntimeExports.jsx(TypingIndicator, {}), jsxRuntimeExports.jsx("div", { ref: messagesEndRef })] }));
|
|
44241
|
+
return (jsxRuntimeExports.jsx(Message, { message: item.message, showTimestamp: showTimestamps, enableFeedback: enableFeedback, onFeedback: onFeedback, getActionRenderer: getActionRenderer, accentColor: accentColor }, item.message.id));
|
|
44242
|
+
}), !isTyping && lastAssistantSuggestions?.length && onSuggestedQuestionClick && (jsxRuntimeExports.jsx(FollowUpSuggestions, { suggestions: lastAssistantSuggestions, onQuestionClick: onSuggestedQuestionClick, onActionClick: onActionClick, accentColor: accentColor })), isTyping && showTypingIndicator && !hasActiveAction && visibleMessages.length > 0 && jsxRuntimeExports.jsx(TypingIndicator, {}), jsxRuntimeExports.jsx("div", { ref: messagesEndRef })] }));
|
|
44141
44243
|
};
|
|
44142
44244
|
|
|
44143
44245
|
const ALLOWED_EXTENSIONS = ['.pdf', '.doc', '.docx', '.txt', '.md', '.csv'];
|
|
@@ -44151,7 +44253,7 @@
|
|
|
44151
44253
|
return (bytes / 1024).toFixed(1) + ' KB';
|
|
44152
44254
|
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
|
44153
44255
|
};
|
|
44154
|
-
const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, showDataPolicy = true, onDataPolicyClick, }) => {
|
|
44256
|
+
const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, showDataPolicy = true, onDataPolicyClick, onInputFocus, }) => {
|
|
44155
44257
|
const [value, setValue] = reactExports.useState('');
|
|
44156
44258
|
const [selectedFiles, setSelectedFiles] = reactExports.useState([]);
|
|
44157
44259
|
const textareaRef = reactExports.useRef(null);
|
|
@@ -44186,481 +44288,15 @@
|
|
|
44186
44288
|
}
|
|
44187
44289
|
};
|
|
44188
44290
|
const canSend = value.trim() || selectedFiles.length > 0;
|
|
44189
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxRuntimeExports.jsxs("div", { className: "ai-chat-file-item", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-file-info", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-file-name", children: file.name }), jsxRuntimeExports.jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsxRuntimeExports.jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsxRuntimeExports.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsxRuntimeExports.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsxRuntimeExports.jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsxRuntimeExports.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntimeExports.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" }) }) })] })), jsxRuntimeExports.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" }), jsxRuntimeExports.jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxRuntimeExports.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsxRuntimeExports.jsx("path", { d: "M12 19V5" }), jsxRuntimeExports.jsx("path", { d: "M5 12l7-7 7 7" })] }) })] }), showDataPolicy && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy", children: [jsxRuntimeExports.jsx("span", { children: "
|
|
44291
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxRuntimeExports.jsxs("div", { className: "ai-chat-file-item", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-file-info", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-file-name", children: file.name }), jsxRuntimeExports.jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsxRuntimeExports.jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsxRuntimeExports.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsxRuntimeExports.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsxRuntimeExports.jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsxRuntimeExports.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntimeExports.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" }) }) })] })), jsxRuntimeExports.jsx("textarea", { ref: textareaRef, className: "ai-chat-input", value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleKeyDown, onFocus: onInputFocus, placeholder: placeholder, disabled: disabled, rows: 2, wrap: "soft", "aria-label": "Message input" }), jsxRuntimeExports.jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxRuntimeExports.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsxRuntimeExports.jsx("path", { d: "M12 19V5" }), jsxRuntimeExports.jsx("path", { d: "M5 12l7-7 7 7" })] }) })] }), showDataPolicy && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy", children: [jsxRuntimeExports.jsx("span", { children: "AI-generated responses may be inaccurate." }), onDataPolicyClick && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [' ', jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-data-policy-link", onClick: onDataPolicyClick, children: "Privacy Notice" })] }))] }))] }));
|
|
44190
44292
|
};
|
|
44191
44293
|
|
|
44192
|
-
function
|
|
44193
|
-
const grouped = new Map();
|
|
44194
|
-
for (const slot of slots) {
|
|
44195
|
-
if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
|
|
44196
|
-
continue;
|
|
44197
|
-
}
|
|
44198
|
-
const date = slot.startTime.slice(0, 10);
|
|
44199
|
-
if (!grouped.has(date)) {
|
|
44200
|
-
grouped.set(date, []);
|
|
44201
|
-
}
|
|
44202
|
-
grouped.get(date).push(slot);
|
|
44203
|
-
}
|
|
44204
|
-
return grouped;
|
|
44205
|
-
}
|
|
44206
|
-
function formatDate$1(dateStr) {
|
|
44207
|
-
try {
|
|
44208
|
-
const date = new Date(dateStr);
|
|
44209
|
-
return new Intl.DateTimeFormat("en-US", {
|
|
44210
|
-
weekday: "short",
|
|
44211
|
-
month: "short",
|
|
44212
|
-
day: "numeric",
|
|
44213
|
-
}).format(date);
|
|
44214
|
-
}
|
|
44215
|
-
catch {
|
|
44216
|
-
return dateStr;
|
|
44217
|
-
}
|
|
44218
|
-
}
|
|
44219
|
-
function CalendarIcon$1() {
|
|
44220
|
-
return (jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.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" }) }));
|
|
44221
|
-
}
|
|
44222
|
-
function CheckIcon$1() {
|
|
44223
|
-
return (jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.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" }) }));
|
|
44224
|
-
}
|
|
44225
|
-
function ExternalLinkIcon$2() {
|
|
44226
|
-
return (jsxRuntimeExports.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntimeExports.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntimeExports.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
|
|
44227
|
-
}
|
|
44228
|
-
function Skeleton$1({ width, height, borderRadius = '4px' }) {
|
|
44229
|
-
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
|
|
44230
|
-
}
|
|
44231
|
-
function GoogleCalendarCard({ action, onComplete, accentColor, className = '' }) {
|
|
44232
|
-
const state = action.state;
|
|
44233
|
-
const rawSlots = state.availableSlots;
|
|
44234
|
-
const availableSlots = Array.isArray(rawSlots)
|
|
44235
|
-
? rawSlots.filter((slot) => slot !== null &&
|
|
44236
|
-
slot !== undefined &&
|
|
44237
|
-
typeof slot === "object" &&
|
|
44238
|
-
"startTime" in slot &&
|
|
44239
|
-
"endTime" in slot &&
|
|
44240
|
-
typeof slot.startTime === "string" &&
|
|
44241
|
-
typeof slot.endTime === "string")
|
|
44242
|
-
: [];
|
|
44243
|
-
const allowTopic = state.allowTopic !== false;
|
|
44244
|
-
const isBooked = state.status === "booked";
|
|
44245
|
-
const slotsByDate = groupSlotsByDate$1(availableSlots);
|
|
44246
|
-
const dates = Array.from(slotsByDate.keys()).sort();
|
|
44247
|
-
const [selectedDate, setSelectedDate] = reactExports.useState(dates[0] ?? "");
|
|
44248
|
-
const [selectedSlot, setSelectedSlot] = reactExports.useState(null);
|
|
44249
|
-
const [topic, setTopic] = reactExports.useState("");
|
|
44250
|
-
const [error, setError] = reactExports.useState(null);
|
|
44251
|
-
const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
|
|
44252
|
-
const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
|
|
44253
|
-
const onConfirm = () => {
|
|
44254
|
-
if (!selectedSlot) {
|
|
44255
|
-
setError("Please select a time slot.");
|
|
44256
|
-
return;
|
|
44257
|
-
}
|
|
44258
|
-
if (allowTopic && !topic.trim()) {
|
|
44259
|
-
setError("Please enter a topic for the meeting.");
|
|
44260
|
-
return;
|
|
44261
|
-
}
|
|
44262
|
-
setError(null);
|
|
44263
|
-
onComplete?.(action.toolCallId, {
|
|
44264
|
-
...action.state,
|
|
44265
|
-
selectedSlot: {
|
|
44266
|
-
startTime: selectedSlot.startTime,
|
|
44267
|
-
endTime: selectedSlot.endTime,
|
|
44268
|
-
},
|
|
44269
|
-
topic: allowTopic ? topic.trim() : null,
|
|
44270
|
-
});
|
|
44271
|
-
};
|
|
44272
|
-
// Booked state
|
|
44273
|
-
if (isBooked) {
|
|
44274
|
-
const bookedSlot = state.selectedSlot;
|
|
44275
|
-
const bookedTopic = state.topic;
|
|
44276
|
-
const eventLink = state.bookedEventLink;
|
|
44277
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsxRuntimeExports.jsx(CheckIcon$1, {}) }), "Appointment Confirmed"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), eventLink && (jsxRuntimeExports.jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Google Calendar", jsxRuntimeExports.jsx(ExternalLinkIcon$2, {})] }))] })] }));
|
|
44278
|
-
}
|
|
44279
|
-
// Skeleton loading state - show when waiting for backend after user confirms
|
|
44280
|
-
const isWaitingForBackend = !action.done && state.selectedSlot && !isBooked;
|
|
44281
|
-
if (isWaitingForBackend) {
|
|
44282
|
-
return (jsxRuntimeExports.jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsxRuntimeExports.jsx(Skeleton$1, { width: "28px", height: "28px", borderRadius: "50%" }), jsxRuntimeExports.jsx(Skeleton$1, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntimeExports.jsx(Skeleton$1, { width: "60px", height: "12px", borderRadius: "4px" }), jsxRuntimeExports.jsx(Skeleton$1, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntimeExports.jsx(Skeleton$1, { width: "50px", height: "12px", borderRadius: "4px" }), jsxRuntimeExports.jsx(Skeleton$1, { width: "200px", height: "18px", borderRadius: "4px" })] }), jsxRuntimeExports.jsx(Skeleton$1, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
|
|
44283
|
-
}
|
|
44284
|
-
// Booking form
|
|
44285
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-google-calendar ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(CalendarIcon$1, {}), "Schedule an Appointment"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsxRuntimeExports.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) })] })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsxRuntimeExports.jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
|
|
44286
|
-
setSelectedDate(date);
|
|
44287
|
-
setSelectedSlot(null);
|
|
44288
|
-
}, children: formatDate$1(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsxRuntimeExports.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 && jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: error }), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: onConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
|
|
44289
|
-
}
|
|
44290
|
-
|
|
44291
|
-
function groupSlotsByDate(slots) {
|
|
44292
|
-
const grouped = new Map();
|
|
44293
|
-
for (const slot of slots) {
|
|
44294
|
-
if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
|
|
44295
|
-
continue;
|
|
44296
|
-
}
|
|
44297
|
-
const date = slot.startTime.slice(0, 10);
|
|
44298
|
-
if (!grouped.has(date)) {
|
|
44299
|
-
grouped.set(date, []);
|
|
44300
|
-
}
|
|
44301
|
-
grouped.get(date).push(slot);
|
|
44302
|
-
}
|
|
44303
|
-
return grouped;
|
|
44304
|
-
}
|
|
44305
|
-
function formatDate(dateStr) {
|
|
44306
|
-
try {
|
|
44307
|
-
const date = new Date(dateStr);
|
|
44308
|
-
return new Intl.DateTimeFormat("en-US", {
|
|
44309
|
-
weekday: "short",
|
|
44310
|
-
month: "short",
|
|
44311
|
-
day: "numeric",
|
|
44312
|
-
}).format(date);
|
|
44313
|
-
}
|
|
44314
|
-
catch {
|
|
44315
|
-
return dateStr;
|
|
44316
|
-
}
|
|
44317
|
-
}
|
|
44318
|
-
function CalendarIcon() {
|
|
44319
|
-
return (jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.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" }) }));
|
|
44320
|
-
}
|
|
44321
|
-
function MailIcon() {
|
|
44322
|
-
return (jsxRuntimeExports.jsxs("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: [jsxRuntimeExports.jsx("path", { d: "M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z" }), jsxRuntimeExports.jsx("path", { d: "M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z" })] }));
|
|
44323
|
-
}
|
|
44324
|
-
function CheckIcon() {
|
|
44325
|
-
return (jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.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" }) }));
|
|
44326
|
-
}
|
|
44327
|
-
function ErrorIcon() {
|
|
44328
|
-
return (jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon-error", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.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" }) }));
|
|
44329
|
-
}
|
|
44330
|
-
function ExternalLinkIcon$1() {
|
|
44331
|
-
return (jsxRuntimeExports.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntimeExports.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntimeExports.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
|
|
44332
|
-
}
|
|
44333
|
-
function Skeleton({ width, height, borderRadius = '4px' }) {
|
|
44334
|
-
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
|
|
44335
|
-
}
|
|
44336
|
-
function PinInputGroup({ values, onChange, disabled }) {
|
|
44337
|
-
const inputRefs = reactExports.useRef([]);
|
|
44338
|
-
const handleChange = (index, value) => {
|
|
44339
|
-
// Only allow digits
|
|
44340
|
-
const digit = value.replace(/[^0-9]/g, '');
|
|
44341
|
-
const newValues = [...values];
|
|
44342
|
-
newValues[index] = digit.slice(-1);
|
|
44343
|
-
onChange(newValues);
|
|
44344
|
-
// Auto-focus next input
|
|
44345
|
-
if (digit && index < 5) {
|
|
44346
|
-
inputRefs.current[index + 1]?.focus();
|
|
44347
|
-
}
|
|
44348
|
-
};
|
|
44349
|
-
const handleKeyDown = (index, e) => {
|
|
44350
|
-
if (e.key === 'Backspace' && !values[index] && index > 0) {
|
|
44351
|
-
inputRefs.current[index - 1]?.focus();
|
|
44352
|
-
}
|
|
44353
|
-
};
|
|
44354
|
-
const handlePaste = (e) => {
|
|
44355
|
-
e.preventDefault();
|
|
44356
|
-
const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, 6);
|
|
44357
|
-
const newValues = pastedData.split('').concat(Array(6 - pastedData.length).fill(''));
|
|
44358
|
-
onChange(newValues);
|
|
44359
|
-
// Focus the next empty input or the last one
|
|
44360
|
-
const nextIndex = Math.min(pastedData.length, 5);
|
|
44361
|
-
inputRefs.current[nextIndex]?.focus();
|
|
44362
|
-
};
|
|
44363
|
-
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-pin-input-group", children: values.map((value, index) => (jsxRuntimeExports.jsx("input", { ref: (el) => {
|
|
44364
|
-
inputRefs.current[index] = el;
|
|
44365
|
-
}, 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))) }));
|
|
44366
|
-
}
|
|
44367
|
-
function MicrosoftCalendarCard({ action, onComplete, accentColor, className = '' }) {
|
|
44368
|
-
const state = action.state;
|
|
44369
|
-
const phase = state.phase || "awaiting_email";
|
|
44370
|
-
const allowTopic = state.allowTopic !== false;
|
|
44371
|
-
const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
|
|
44372
|
-
// Debug: Log state changes
|
|
44373
|
-
const prevStateRef = reactExports.useRef(null);
|
|
44374
|
-
reactExports.useEffect(() => {
|
|
44375
|
-
if (JSON.stringify(prevStateRef.current) !== JSON.stringify(state)) {
|
|
44376
|
-
console.log('[MicrosoftCalendarCard] State updated:', {
|
|
44377
|
-
phase: state.phase,
|
|
44378
|
-
hasError: !!state.errorMessage,
|
|
44379
|
-
error: state.errorMessage,
|
|
44380
|
-
slotsCount: state.availableSlots?.length || 0
|
|
44381
|
-
});
|
|
44382
|
-
prevStateRef.current = state;
|
|
44383
|
-
}
|
|
44384
|
-
}, [state]);
|
|
44385
|
-
// Email phase state
|
|
44386
|
-
const [email, setEmail] = reactExports.useState("");
|
|
44387
|
-
const [emailError, setEmailError] = reactExports.useState(null);
|
|
44388
|
-
// OTP phase state
|
|
44389
|
-
const [otpValues, setOtpValues] = reactExports.useState(Array(6).fill(''));
|
|
44390
|
-
const [otpError, setOtpError] = reactExports.useState(null);
|
|
44391
|
-
// Loading states
|
|
44392
|
-
const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
|
|
44393
|
-
// Reset loading state when phase changes (backend has responded)
|
|
44394
|
-
// Use useEffect for reliable re-rendering
|
|
44395
|
-
reactExports.useEffect(() => {
|
|
44396
|
-
console.log('[MicrosoftCalendarCard] Phase changed to:', phase);
|
|
44397
|
-
setIsSubmitting(false);
|
|
44398
|
-
// Clear errors when transitioning to new phase
|
|
44399
|
-
if (phase === "awaiting_email") {
|
|
44400
|
-
setEmailError(null);
|
|
44401
|
-
setOtpError(null);
|
|
44402
|
-
setSelectionError(null);
|
|
44403
|
-
}
|
|
44404
|
-
else if (phase === "awaiting_otp") {
|
|
44405
|
-
setOtpError(state.errorMessage || null);
|
|
44406
|
-
setEmailError(null);
|
|
44407
|
-
setSelectionError(null);
|
|
44408
|
-
// Clear OTP input for fresh attempt
|
|
44409
|
-
setOtpValues(Array(6).fill(''));
|
|
44410
|
-
}
|
|
44411
|
-
else if (phase === "awaiting_options") {
|
|
44412
|
-
setEmailError(null);
|
|
44413
|
-
setOtpError(null);
|
|
44414
|
-
setSelectionError(null);
|
|
44415
|
-
}
|
|
44416
|
-
else if (phase === "awaiting_booking") {
|
|
44417
|
-
setSelectionError(state.errorMessage || null);
|
|
44418
|
-
setEmailError(null);
|
|
44419
|
-
setOtpError(null);
|
|
44420
|
-
}
|
|
44421
|
-
else if (phase === "booked" || phase === "cancelled" || phase === "error") {
|
|
44422
|
-
setEmailError(null);
|
|
44423
|
-
setOtpError(null);
|
|
44424
|
-
setSelectionError(null);
|
|
44425
|
-
setSelectedId(null); // Reset selection
|
|
44426
|
-
}
|
|
44427
|
-
}, [phase, state.errorMessage]);
|
|
44428
|
-
// Selection phase state
|
|
44429
|
-
const rawSlots = state.availableSlots;
|
|
44430
|
-
const availableSlots = Array.isArray(rawSlots)
|
|
44431
|
-
? rawSlots.filter((slot) => slot !== null &&
|
|
44432
|
-
slot !== undefined &&
|
|
44433
|
-
typeof slot === "object" &&
|
|
44434
|
-
"startTime" in slot &&
|
|
44435
|
-
"endTime" in slot &&
|
|
44436
|
-
typeof slot.startTime === "string" &&
|
|
44437
|
-
typeof slot.endTime === "string")
|
|
44438
|
-
: [];
|
|
44439
|
-
const slotsByDate = groupSlotsByDate(availableSlots);
|
|
44440
|
-
const dates = Array.from(slotsByDate.keys()).sort();
|
|
44441
|
-
const [selectedDate, setSelectedDate] = reactExports.useState(dates[0] ?? "");
|
|
44442
|
-
const [selectedSlot, setSelectedSlot] = reactExports.useState(null);
|
|
44443
|
-
const [topic, setTopic] = reactExports.useState("");
|
|
44444
|
-
const [selectionError, setSelectionError] = reactExports.useState(null);
|
|
44445
|
-
// Cancellation phase state
|
|
44446
|
-
const [selectedId, setSelectedId] = reactExports.useState(null);
|
|
44447
|
-
const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
|
|
44448
|
-
// Phase 1: Email Input
|
|
44449
|
-
const handleEmailSubmit = () => {
|
|
44450
|
-
const trimmedEmail = email.trim();
|
|
44451
|
-
if (!trimmedEmail) {
|
|
44452
|
-
setEmailError("Please enter your email address");
|
|
44453
|
-
return;
|
|
44454
|
-
}
|
|
44455
|
-
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmedEmail)) {
|
|
44456
|
-
setEmailError("Please enter a valid email address");
|
|
44457
|
-
return;
|
|
44458
|
-
}
|
|
44459
|
-
setEmailError(null);
|
|
44460
|
-
setIsSubmitting(true);
|
|
44461
|
-
console.log('[MicrosoftCalendarCard] Submitting email:', trimmedEmail);
|
|
44462
|
-
setTimeout(() => {
|
|
44463
|
-
onComplete?.(action.toolCallId, {
|
|
44464
|
-
...action.state,
|
|
44465
|
-
email: trimmedEmail,
|
|
44466
|
-
});
|
|
44467
|
-
}, 50);
|
|
44468
|
-
};
|
|
44469
|
-
// Phase 2: OTP Verification
|
|
44470
|
-
const handleOtpSubmit = () => {
|
|
44471
|
-
const otpCode = otpValues.join('');
|
|
44472
|
-
if (otpCode.length !== 6) {
|
|
44473
|
-
setOtpError("Please enter the 6-digit code");
|
|
44474
|
-
return;
|
|
44475
|
-
}
|
|
44476
|
-
setOtpError(null);
|
|
44477
|
-
setIsSubmitting(true);
|
|
44478
|
-
console.log('[MicrosoftCalendarCard] Submitting OTP code');
|
|
44479
|
-
setTimeout(() => {
|
|
44480
|
-
onComplete?.(action.toolCallId, {
|
|
44481
|
-
...action.state,
|
|
44482
|
-
otpCode,
|
|
44483
|
-
});
|
|
44484
|
-
}, 50);
|
|
44485
|
-
};
|
|
44486
|
-
// Phase 3: Appointment Selection
|
|
44487
|
-
const handleAppointmentConfirm = () => {
|
|
44488
|
-
if (!selectedSlot) {
|
|
44489
|
-
setSelectionError("Please select a time slot");
|
|
44490
|
-
return;
|
|
44491
|
-
}
|
|
44492
|
-
if (allowTopic && !topic.trim()) {
|
|
44493
|
-
setSelectionError("Please enter a meeting topic");
|
|
44494
|
-
return;
|
|
44495
|
-
}
|
|
44496
|
-
setSelectionError(null);
|
|
44497
|
-
setIsSubmitting(true);
|
|
44498
|
-
console.log('[MicrosoftCalendarCard] Confirming appointment:', {
|
|
44499
|
-
slot: selectedSlot,
|
|
44500
|
-
topic: topic.trim()
|
|
44501
|
-
});
|
|
44502
|
-
setTimeout(() => {
|
|
44503
|
-
onComplete?.(action.toolCallId, {
|
|
44504
|
-
...action.state,
|
|
44505
|
-
selectedSlot: {
|
|
44506
|
-
startTime: selectedSlot.startTime,
|
|
44507
|
-
endTime: selectedSlot.endTime,
|
|
44508
|
-
},
|
|
44509
|
-
topic: allowTopic ? topic.trim() : null,
|
|
44510
|
-
});
|
|
44511
|
-
}, 50);
|
|
44512
|
-
};
|
|
44513
|
-
// Handle "Use different email" button
|
|
44514
|
-
const handleUseDifferentEmail = () => {
|
|
44515
|
-
setEmail("");
|
|
44516
|
-
setEmailError(null);
|
|
44517
|
-
setOtpValues(Array(6).fill(''));
|
|
44518
|
-
setOtpError(null);
|
|
44519
|
-
onComplete?.(action.toolCallId, {
|
|
44520
|
-
phase: "awaiting_email",
|
|
44521
|
-
email: null,
|
|
44522
|
-
otpVerified: false,
|
|
44523
|
-
otpAttempts: 0,
|
|
44524
|
-
availableSlots: [],
|
|
44525
|
-
selectedSlot: null,
|
|
44526
|
-
topic: null,
|
|
44527
|
-
bookedEventId: null,
|
|
44528
|
-
bookedEventLink: null,
|
|
44529
|
-
allowTopic,
|
|
44530
|
-
errorMessage: null,
|
|
44531
|
-
});
|
|
44532
|
-
};
|
|
44533
|
-
// Phase 5: Booked Confirmation
|
|
44534
|
-
if (phase === "booked") {
|
|
44535
|
-
const bookedSlot = state.selectedSlot;
|
|
44536
|
-
const bookedTopic = state.topic;
|
|
44537
|
-
const eventLink = state.bookedEventLink;
|
|
44538
|
-
const bookedEmail = state.email;
|
|
44539
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsxRuntimeExports.jsx(CheckIcon, {}) }), "Appointment Confirmed"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), bookedEmail && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-hint", children: ["A calendar invitation has been sent to ", bookedEmail] })), eventLink && (jsxRuntimeExports.jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Outlook Calendar", jsxRuntimeExports.jsx(ExternalLinkIcon$1, {})] }))] })] }));
|
|
44540
|
-
}
|
|
44541
|
-
// Phase 6: Cancelled Confirmation
|
|
44542
|
-
if (phase === "cancelled") {
|
|
44543
|
-
const cancelledSubject = state.cancelledEventSubject;
|
|
44544
|
-
const userEmail = state.email;
|
|
44545
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsxRuntimeExports.jsx(CheckIcon, {}) }), "Appointment Cancelled"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [cancelledSubject && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label-small", children: "CANCELLED" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value-large", children: cancelledSubject })] })), userEmail && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-hint", children: ["A cancellation notice has been sent to ", userEmail] }))] })] }));
|
|
44546
|
-
}
|
|
44547
|
-
// Error State
|
|
44548
|
-
if (phase === "error") {
|
|
44549
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-error ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(ErrorIcon, {}), "Error"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error-message", children: state.errorMessage || "An error occurred. Please try again." }), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
|
|
44550
|
-
setEmail("");
|
|
44551
|
-
setEmailError(null);
|
|
44552
|
-
setOtpValues(Array(6).fill(''));
|
|
44553
|
-
setOtpError(null);
|
|
44554
|
-
onComplete?.(action.toolCallId, {
|
|
44555
|
-
phase: "awaiting_email",
|
|
44556
|
-
email: null,
|
|
44557
|
-
otpVerified: false,
|
|
44558
|
-
otpAttempts: 0,
|
|
44559
|
-
availableSlots: [],
|
|
44560
|
-
selectedSlot: null,
|
|
44561
|
-
topic: null,
|
|
44562
|
-
bookedEventId: null,
|
|
44563
|
-
bookedEventLink: null,
|
|
44564
|
-
allowTopic,
|
|
44565
|
-
errorMessage: null,
|
|
44566
|
-
});
|
|
44567
|
-
}, children: "Start Over" })] })] }));
|
|
44568
|
-
}
|
|
44569
|
-
// Loading State
|
|
44570
|
-
if (isSubmitting) {
|
|
44571
|
-
return (jsxRuntimeExports.jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsxRuntimeExports.jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsxRuntimeExports.jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntimeExports.jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsxRuntimeExports.jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxRuntimeExports.jsx(Skeleton, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
|
|
44572
|
-
}
|
|
44573
|
-
// Phase 1: Email Input
|
|
44574
|
-
if (phase === "awaiting_email") {
|
|
44575
|
-
const displayError = state.errorMessage || emailError;
|
|
44576
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(CalendarIcon, {}), "Schedule an Appointment"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-hint", children: "We'll send a verification code to your email" }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { htmlFor: `email-${action.toolCallId}`, className: "ai-chat-action-label", children: "Email Address" }), jsxRuntimeExports.jsx("input", { id: `email-${action.toolCallId}`, type: "email", className: "ai-chat-action-input", placeholder: "your@email.com", value: email, onChange: (e) => {
|
|
44577
|
-
setEmail(e.target.value);
|
|
44578
|
-
setEmailError(null);
|
|
44579
|
-
}, onKeyPress: (e) => {
|
|
44580
|
-
if (e.key === 'Enter') {
|
|
44581
|
-
handleEmailSubmit();
|
|
44582
|
-
}
|
|
44583
|
-
}, autoFocus: true })] }), displayError && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleEmailSubmit, children: "Continue" })] })] }));
|
|
44584
|
-
}
|
|
44585
|
-
// Phase 2: OTP Input
|
|
44586
|
-
if (phase === "awaiting_otp") {
|
|
44587
|
-
const displayError = state.errorMessage || otpError;
|
|
44588
|
-
const userEmail = state.email;
|
|
44589
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(MailIcon, {}), "Verify Your Email"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-hint", children: ["We sent a 6-digit code to ", jsxRuntimeExports.jsx("strong", { children: userEmail })] }), jsxRuntimeExports.jsx(PinInputGroup, { values: otpValues, onChange: (newValues) => {
|
|
44590
|
-
setOtpValues(newValues);
|
|
44591
|
-
setOtpError(null);
|
|
44592
|
-
// Auto-submit when all 6 digits are entered
|
|
44593
|
-
if (newValues.every(v => v.length === 1)) {
|
|
44594
|
-
console.log('[MicrosoftCalendarCard] Auto-submitting OTP (all 6 digits entered)');
|
|
44595
|
-
setIsSubmitting(true);
|
|
44596
|
-
const code = newValues.join('');
|
|
44597
|
-
setTimeout(() => {
|
|
44598
|
-
onComplete?.(action.toolCallId, {
|
|
44599
|
-
...action.state,
|
|
44600
|
-
otpCode: code,
|
|
44601
|
-
});
|
|
44602
|
-
}, 100);
|
|
44603
|
-
}
|
|
44604
|
-
}, disabled: isSubmitting }), displayError && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleOtpSubmit, disabled: otpValues.join('').length !== 6, children: "Verify Code" }), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: handleUseDifferentEmail, children: "Use different email" })] })] }));
|
|
44605
|
-
}
|
|
44606
|
-
// Phase 3: Options Menu (with inline cancel buttons and confirmation)
|
|
44607
|
-
if (phase === "awaiting_options") {
|
|
44608
|
-
const userAppointments = state.userAppointments || [];
|
|
44609
|
-
const maxAppointments = state.maxAppointmentsPerUser || 3;
|
|
44610
|
-
const appointmentCount = userAppointments.length;
|
|
44611
|
-
const canBook = appointmentCount < maxAppointments;
|
|
44612
|
-
const hasAppointments = appointmentCount > 0;
|
|
44613
|
-
const displayError = state.errorMessage || selectionError;
|
|
44614
|
-
// If confirming cancellation, show confirmation dialog
|
|
44615
|
-
if (selectedId) {
|
|
44616
|
-
const appointmentToCancel = userAppointments.find(appt => appt.id === selectedId);
|
|
44617
|
-
if (!appointmentToCancel) {
|
|
44618
|
-
setSelectedId(null); // Reset if appointment not found
|
|
44619
|
-
}
|
|
44620
|
-
else {
|
|
44621
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(CalendarIcon, {}), "Confirm Cancellation"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-hint", children: "Are you sure you want to cancel this appointment?" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-appointment-item", style: { marginBottom: '16px' }, children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-appointment-subject", children: appointmentToCancel.subject }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-appointment-time", children: appointmentToCancel.displayTime })] }) }), displayError && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-button-group", children: [jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
|
|
44622
|
-
setIsSubmitting(true);
|
|
44623
|
-
onComplete?.(action.toolCallId, {
|
|
44624
|
-
...action.state,
|
|
44625
|
-
selectedOption: "cancel",
|
|
44626
|
-
selectedAppointmentId: selectedId,
|
|
44627
|
-
});
|
|
44628
|
-
}, disabled: isSubmitting, children: isSubmitting ? 'Cancelling...' : 'Confirm Cancellation' }), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
|
|
44629
|
-
setSelectedId(null);
|
|
44630
|
-
setSelectionError(null);
|
|
44631
|
-
}, disabled: isSubmitting, children: "Go Back" })] })] })] }));
|
|
44632
|
-
}
|
|
44633
|
-
}
|
|
44634
|
-
// Normal view with inline cancel buttons
|
|
44635
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(CalendarIcon, {}), "Manage Your Appointments"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntimeExports.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 && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-appointment-list", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-label", children: "Your Upcoming Appointments" }), userAppointments.map((appt) => (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-appointment-item", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-appointment-subject", children: appt.subject }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-appointment-time", children: appt.displayTime })] }), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
|
|
44636
|
-
setSelectedId(appt.id);
|
|
44637
|
-
setSelectionError(null);
|
|
44638
|
-
}, children: "Cancel" })] }, appt.id)))] })), displayError && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: displayError })), canBook && (jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
|
|
44639
|
-
setIsSubmitting(true);
|
|
44640
|
-
onComplete?.(action.toolCallId, {
|
|
44641
|
-
...action.state,
|
|
44642
|
-
selectedOption: "book",
|
|
44643
|
-
});
|
|
44644
|
-
}, disabled: isSubmitting, children: isSubmitting ? 'Loading...' : 'Book New Appointment' })), !canBook && !hasAppointments && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-hint", children: "No appointments found." }))] })] }));
|
|
44645
|
-
}
|
|
44646
|
-
// Phase 4: Appointment Selection (Booking)
|
|
44647
|
-
if (phase === "awaiting_booking") {
|
|
44648
|
-
const displayError = state.errorMessage || selectionError;
|
|
44649
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(CalendarIcon, {}), "Select Appointment Time"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsxRuntimeExports.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) })] })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsxRuntimeExports.jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
|
|
44650
|
-
setSelectedDate(date);
|
|
44651
|
-
setSelectedSlot(null);
|
|
44652
|
-
}, children: formatDate(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsxRuntimeExports.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 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleAppointmentConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
|
|
44653
|
-
}
|
|
44654
|
-
// Fallback
|
|
44655
|
-
return null;
|
|
44656
|
-
}
|
|
44657
|
-
|
|
44658
|
-
function truncate(text, maxLength) {
|
|
44294
|
+
function truncate$1(text, maxLength) {
|
|
44659
44295
|
if (text.length <= maxLength)
|
|
44660
44296
|
return text;
|
|
44661
44297
|
return text.slice(0, maxLength).trim() + '...';
|
|
44662
44298
|
}
|
|
44663
|
-
function ExternalLinkIcon() {
|
|
44299
|
+
function ExternalLinkIcon$2() {
|
|
44664
44300
|
return (jsxRuntimeExports.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntimeExports.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntimeExports.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
|
|
44665
44301
|
}
|
|
44666
44302
|
function SingleLinkPreview({ link, onLinkClick, accentColor }) {
|
|
@@ -44679,10 +44315,10 @@
|
|
|
44679
44315
|
e.currentTarget.parentElement.style.display = 'none';
|
|
44680
44316
|
} }) })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-link-preview__content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-link-preview__site", children: [link.favicon && (jsxRuntimeExports.jsx("img", { src: link.favicon, alt: "", className: "ai-chat-link-preview__favicon", onError: (e) => {
|
|
44681
44317
|
e.currentTarget.style.display = 'none';
|
|
44682
|
-
} })), jsxRuntimeExports.jsx("span", { className: "ai-chat-link-preview__domain", children: link.siteName || domain })] }), jsxRuntimeExports.jsx("h4", { className: "ai-chat-link-preview__title", children: link.title }), link.description && (jsxRuntimeExports.jsx("p", { className: "ai-chat-link-preview__description", children: truncate(link.description, 120) }))] }), jsxRuntimeExports.jsx("div", { className: "ai-chat-link-preview__arrow", children: jsxRuntimeExports.jsx(ExternalLinkIcon, {}) })] }));
|
|
44318
|
+
} })), jsxRuntimeExports.jsx("span", { className: "ai-chat-link-preview__domain", children: link.siteName || domain })] }), jsxRuntimeExports.jsx("h4", { className: "ai-chat-link-preview__title", children: link.title }), link.description && (jsxRuntimeExports.jsx("p", { className: "ai-chat-link-preview__description", children: truncate$1(link.description, 120) }))] }), jsxRuntimeExports.jsx("div", { className: "ai-chat-link-preview__arrow", children: jsxRuntimeExports.jsx(ExternalLinkIcon$2, {}) })] }));
|
|
44683
44319
|
}
|
|
44684
44320
|
function LinkPreviewCard({ action, onComplete, accentColor }) {
|
|
44685
|
-
const rawState = action.
|
|
44321
|
+
const rawState = action.input;
|
|
44686
44322
|
const hasCompletedRef = reactExports.useRef(false);
|
|
44687
44323
|
// Provide safe defaults if state is missing
|
|
44688
44324
|
const state = {
|
|
@@ -44712,11 +44348,12 @@
|
|
|
44712
44348
|
if (state.links.length === 0) {
|
|
44713
44349
|
return null;
|
|
44714
44350
|
}
|
|
44715
|
-
|
|
44716
|
-
|
|
44717
|
-
|
|
44718
|
-
|
|
44719
|
-
|
|
44351
|
+
const gridClass = state.links.length === 1
|
|
44352
|
+
? 'ai-chat-link-preview-grid ai-chat-link-preview-grid--single'
|
|
44353
|
+
: state.links.length === 2
|
|
44354
|
+
? 'ai-chat-link-preview-grid ai-chat-link-preview-grid--double'
|
|
44355
|
+
: 'ai-chat-link-preview-grid ai-chat-link-preview-grid--triple';
|
|
44356
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-link-preview-container", children: [state.context && (jsxRuntimeExports.jsx("p", { className: "ai-chat-link-preview__context", style: { marginBottom: '8px', fontSize: '0.9em', color: 'var(--ai-chat-fg-muted)' }, children: state.context })), jsxRuntimeExports.jsx("div", { className: gridClass, children: state.links.map((link, index) => (jsxRuntimeExports.jsx(SingleLinkPreview, { link: link, onLinkClick: () => handleLinkClick(link.url), accentColor: accentColor }, index))) })] }));
|
|
44720
44357
|
}
|
|
44721
44358
|
|
|
44722
44359
|
function PlayIcon() {
|
|
@@ -44737,7 +44374,7 @@
|
|
|
44737
44374
|
}
|
|
44738
44375
|
}
|
|
44739
44376
|
function VideoPlayerCard({ action, onComplete, accentColor }) {
|
|
44740
|
-
const rawState = action.
|
|
44377
|
+
const rawState = action.input;
|
|
44741
44378
|
const hasCompletedRef = reactExports.useRef(false);
|
|
44742
44379
|
const [isPlaying, setIsPlaying] = reactExports.useState(false);
|
|
44743
44380
|
// Provide safe defaults if state is missing
|
|
@@ -44848,7 +44485,7 @@
|
|
|
44848
44485
|
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-location-card ${compact ? 'ai-chat-location-card--compact' : ''}`, style: style, children: [showMap && settings.showMap !== false && (jsxRuntimeExports.jsx("div", { className: "ai-chat-location-card__map", style: { height: effectiveMapHeight }, children: jsxRuntimeExports.jsx("iframe", { src: getMapEmbedUrl(), allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade", title: `Map of ${location.name}` }) })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-location-card__content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-location-card__header", children: [jsxRuntimeExports.jsx("h4", { className: "ai-chat-location-card__name", children: location.name }), location.type && (jsxRuntimeExports.jsx("span", { className: "ai-chat-location-card__type", children: location.type })), openStatus !== null && (jsxRuntimeExports.jsx("span", { className: `ai-chat-location-card__status ai-chat-location-card__status--${openStatus ? 'open' : 'closed'}`, children: openStatus ? 'Open' : 'Closed' }))] }), jsxRuntimeExports.jsxs("p", { className: "ai-chat-location-card__address", children: [jsxRuntimeExports.jsx(MapPinIcon, {}), location.address] }), location.description && (jsxRuntimeExports.jsx("p", { className: "ai-chat-location-card__description", children: location.description })), settings.showHours !== false && location.hours && location.hours.length > 0 && (jsxRuntimeExports.jsx(HoursDisplay, { hours: location.hours, compact: compact })), settings.showPhone !== false && location.phone && (jsxRuntimeExports.jsxs("button", { type: "button", className: "ai-chat-location-card__phone", onClick: handleCall, children: [jsxRuntimeExports.jsx(PhoneIcon, {}), location.phone] })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-location-card__actions", children: [settings.showDirectionsButton !== false && (jsxRuntimeExports.jsxs("button", { type: "button", className: "ai-chat-location-card__button", style: accentColor ? { backgroundColor: accentColor } : undefined, onClick: onDirections, children: [jsxRuntimeExports.jsx(NavigationIcon, {}), compact ? 'Directions' : 'Get Directions'] })), !compact && location.website && (jsxRuntimeExports.jsxs("a", { href: location.website, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-location-card__link", children: [jsxRuntimeExports.jsx(GlobeIcon, {}), "Website"] }))] })] })] }));
|
|
44849
44486
|
}
|
|
44850
44487
|
function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
|
|
44851
|
-
const rawState = action.
|
|
44488
|
+
const rawState = action.input;
|
|
44852
44489
|
const hasCompletedRef = reactExports.useRef(false);
|
|
44853
44490
|
const state = {
|
|
44854
44491
|
locations: rawState?.locations || [],
|
|
@@ -44930,7 +44567,7 @@
|
|
|
44930
44567
|
})()] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-contact-card__info", children: [jsxRuntimeExports.jsx("h4", { className: "ai-chat-contact-card__name", children: contact.name }), settings.showRole !== false && contact.role && (jsxRuntimeExports.jsx("p", { className: "ai-chat-contact-card__role", children: contact.role })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-contact-card__details", children: [settings.showEmail !== false && contact.email && (jsxRuntimeExports.jsx("a", { href: `mailto:${contact.email}`, className: "ai-chat-contact-card__detail", onClick: onEmail, children: contact.email })), settings.showPhone !== false && contact.phone && (jsxRuntimeExports.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 && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-contact-card__responsibilities", children: [contact.responsibilities.slice(0, 3).map((resp, idx) => (jsxRuntimeExports.jsx("span", { className: "ai-chat-contact-card__responsibility-tag", children: resp }, idx))), contact.responsibilities.length > 3 && (jsxRuntimeExports.jsxs("span", { className: "ai-chat-contact-card__responsibility-more", children: ["+", contact.responsibilities.length - 3, " more"] }))] }))] })] }));
|
|
44931
44568
|
}
|
|
44932
44569
|
function ContactCard({ action, onComplete, accentColor, maxColumns = 3 }) {
|
|
44933
|
-
const rawState = action.
|
|
44570
|
+
const rawState = action.input;
|
|
44934
44571
|
const hasCompletedRef = reactExports.useRef(false);
|
|
44935
44572
|
const state = {
|
|
44936
44573
|
contacts: rawState?.contacts || [],
|
|
@@ -44965,11 +44602,37 @@
|
|
|
44965
44602
|
}, children: contacts.map((contact) => (jsxRuntimeExports.jsx(ContactItem, { contact: contact, settings: settings, accentColor: accentColor, onEmail: handleContact, onPhone: handleContact, compact: true, layout: settings.layout || 'vertical' }, contact.id))) })] }));
|
|
44966
44603
|
}
|
|
44967
44604
|
|
|
44968
|
-
|
|
44969
|
-
|
|
44605
|
+
const CloseButton = ({ onClick, className = "", ariaLabel = "Close", }) => {
|
|
44606
|
+
return (jsxRuntimeExports.jsx("button", { type: "button", className: `ai-chat-action-close-btn ${className}`, onClick: onClick, "aria-label": ariaLabel, children: jsxRuntimeExports.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntimeExports.jsx("path", { d: "M1 1L13 13M1 13L13 1" }) }) }));
|
|
44607
|
+
};
|
|
44608
|
+
|
|
44609
|
+
function FormIcon(props) {
|
|
44610
|
+
return (jsxRuntimeExports.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntimeExports.jsx("path", { d: "M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" }), jsxRuntimeExports.jsx("polyline", { points: "14,2 14,8 20,8" }), jsxRuntimeExports.jsx("line", { x1: "16", y1: "13", x2: "8", y2: "13" }), jsxRuntimeExports.jsx("line", { x1: "16", y1: "17", x2: "8", y2: "17" }), jsxRuntimeExports.jsx("line", { x1: "10", y1: "9", x2: "8", y2: "9" })] }));
|
|
44611
|
+
}
|
|
44612
|
+
function CheckIcon(props) {
|
|
44613
|
+
return (jsxRuntimeExports.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: jsxRuntimeExports.jsx("polyline", { points: "20,6 9,17 4,12" }) }));
|
|
44614
|
+
}
|
|
44615
|
+
function WarningIcon(props) {
|
|
44616
|
+
return (jsxRuntimeExports.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntimeExports.jsx("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }), jsxRuntimeExports.jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }), jsxRuntimeExports.jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })] }));
|
|
44617
|
+
}
|
|
44618
|
+
function SkipIcon(props) {
|
|
44619
|
+
return (jsxRuntimeExports.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntimeExports.jsx("polygon", { points: "5,4 15,12 5,20 5,4" }), jsxRuntimeExports.jsx("line", { x1: "19", y1: "5", x2: "19", y2: "19" })] }));
|
|
44620
|
+
}
|
|
44621
|
+
function BackArrowIcon(props) {
|
|
44622
|
+
return (jsxRuntimeExports.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: jsxRuntimeExports.jsx("polyline", { points: "15,18 9,12 15,6" }) }));
|
|
44623
|
+
}
|
|
44624
|
+
|
|
44625
|
+
function FormCard({ action, onComplete, onDismiss, accentColor }) {
|
|
44626
|
+
const state = action.input;
|
|
44970
44627
|
const [currentStep, setCurrentStep] = reactExports.useState(0);
|
|
44971
44628
|
const [answers, setAnswers] = reactExports.useState({});
|
|
44972
44629
|
const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
|
|
44630
|
+
const [localStatus, setLocalStatus] = reactExports.useState(null);
|
|
44631
|
+
// If action is already done, show simple completion indicator
|
|
44632
|
+
// The agent's response will convey what happened
|
|
44633
|
+
if (action.done) {
|
|
44634
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-form-card ai-chat-form-card--completed", children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntimeExports.jsx(CheckIcon, {}) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__title", children: "Form completed" })] }) }));
|
|
44635
|
+
}
|
|
44973
44636
|
const questions = state.questions || [];
|
|
44974
44637
|
const currentQuestion = questions[currentStep];
|
|
44975
44638
|
const totalQuestions = questions.length;
|
|
@@ -44990,6 +44653,7 @@
|
|
|
44990
44653
|
if (!onComplete)
|
|
44991
44654
|
return;
|
|
44992
44655
|
setIsSubmitting(true);
|
|
44656
|
+
setLocalStatus('submitted');
|
|
44993
44657
|
const formattedAnswers = Object.entries(answers).map(([questionId, value]) => ({
|
|
44994
44658
|
questionId,
|
|
44995
44659
|
value,
|
|
@@ -45003,6 +44667,7 @@
|
|
|
45003
44667
|
const handleSkip = () => {
|
|
45004
44668
|
if (!onComplete || !state.settings.allowSkip)
|
|
45005
44669
|
return;
|
|
44670
|
+
setLocalStatus('skipped');
|
|
45006
44671
|
onComplete(action.toolCallId, {
|
|
45007
44672
|
...state,
|
|
45008
44673
|
status: 'skipped',
|
|
@@ -45030,23 +44695,29 @@
|
|
|
45030
44695
|
return answer.trim() !== '';
|
|
45031
44696
|
});
|
|
45032
44697
|
};
|
|
44698
|
+
const handleDismiss = () => {
|
|
44699
|
+
onDismiss?.(action.toolCallId);
|
|
44700
|
+
};
|
|
44701
|
+
// Use local status if available (for immediate UI feedback), otherwise use state.status
|
|
44702
|
+
const effectiveStatus = localStatus || state.status;
|
|
45033
44703
|
// Error state
|
|
45034
|
-
if (
|
|
45035
|
-
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--error", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children:
|
|
44704
|
+
if (effectiveStatus === 'error') {
|
|
44705
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--error", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntimeExports.jsx(WarningIcon, {}) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__title", children: "Form Error" })] }), jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__error", children: state.error || 'Could not load form' })] }));
|
|
45036
44706
|
}
|
|
45037
44707
|
// Submitted state
|
|
45038
|
-
if (
|
|
45039
|
-
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--submitted", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children:
|
|
44708
|
+
if (effectiveStatus === 'submitted') {
|
|
44709
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--submitted", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntimeExports.jsx(CheckIcon, {}) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__success", children: state.settings.successMessage || 'Thank you for your response!' })] }));
|
|
45040
44710
|
}
|
|
45041
44711
|
// Skipped state
|
|
45042
|
-
if (
|
|
45043
|
-
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--skipped", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children:
|
|
44712
|
+
if (effectiveStatus === 'skipped') {
|
|
44713
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--skipped", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntimeExports.jsx(SkipIcon, {}) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__skipped-text", children: "Form skipped" })] }));
|
|
45044
44714
|
}
|
|
45045
44715
|
// No questions
|
|
45046
44716
|
if (totalQuestions === 0) {
|
|
45047
|
-
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--empty", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children:
|
|
44717
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--empty", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntimeExports.jsx(FormIcon, {}) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__empty-text", children: "This form has no questions." })] }));
|
|
45048
44718
|
}
|
|
45049
|
-
|
|
44719
|
+
const showCloseButton = effectiveStatus === "displaying" && !action.done && Boolean(onDismiss);
|
|
44720
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-form-card${showCloseButton ? " ai-chat-form-card--closable" : ""}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children: jsxRuntimeExports.jsx(FormIcon, {}) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__title", children: state.title }), showCloseButton && (jsxRuntimeExports.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Close form" }))] }), state.description && (jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__description", children: state.description })), state.context && (jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__context", children: state.context })), state.settings.showProgress && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__progress", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-form-card__progress-bar", style: {
|
|
45050
44721
|
width: `${((currentStep + 1) / totalQuestions) * 100}%`,
|
|
45051
44722
|
backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
|
|
45052
44723
|
} }), jsxRuntimeExports.jsxs("span", { className: "ai-chat-form-card__progress-text", children: [currentStep + 1, " of ", totalQuestions] })] })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__question", children: [jsxRuntimeExports.jsxs("p", { className: "ai-chat-form-card__question-text", children: [currentQuestion.text, currentQuestion.required && jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__required", children: "*" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__answer", children: [currentQuestion.type === 'text' && (jsxRuntimeExports.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 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => (jsxRuntimeExports.jsxs("label", { className: "ai-chat-form-card__option", children: [jsxRuntimeExports.jsx("input", { type: "radio", name: currentQuestion.id, value: option.value, checked: answers[currentQuestion.id] === option.value, onChange: () => handleAnswerChange(currentQuestion.id, option.value) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__option-text", children: option.text })] }, option.id))) })), currentQuestion.type === 'multiple_choice' && currentQuestion.options && (jsxRuntimeExports.jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => {
|
|
@@ -45072,104 +44743,915 @@
|
|
|
45072
44743
|
}, children: isSubmitting ? 'Submitting...' : (state.settings.submitButtonText || 'Submit') }))] })] }));
|
|
45073
44744
|
}
|
|
45074
44745
|
|
|
45075
|
-
|
|
45076
|
-
|
|
45077
|
-
|
|
45078
|
-
|
|
45079
|
-
|
|
45080
|
-
|
|
45081
|
-
|
|
45082
|
-
|
|
45083
|
-
|
|
45084
|
-
|
|
45085
|
-
|
|
45086
|
-
|
|
45087
|
-
|
|
45088
|
-
|
|
45089
|
-
|
|
45090
|
-
|
|
45091
|
-
const
|
|
45092
|
-
|
|
45093
|
-
|
|
45094
|
-
|
|
45095
|
-
|
|
45096
|
-
|
|
45097
|
-
|
|
45098
|
-
|
|
45099
|
-
|
|
45100
|
-
console.error("[Action] Failed to resume action:", error);
|
|
45101
|
-
});
|
|
45102
|
-
}
|
|
45103
|
-
}
|
|
45104
|
-
function registerActionResumeCallback(toolCallId, callback) {
|
|
45105
|
-
resumeCallbacks.set(toolCallId, callback);
|
|
45106
|
-
}
|
|
45107
|
-
function unregisterActionResumeCallback(toolCallId) {
|
|
45108
|
-
resumeCallbacks.delete(toolCallId);
|
|
44746
|
+
function EmailPhase({ accentColor, onDismiss, showCloseButton, onSubmit, isLoading, error, }) {
|
|
44747
|
+
const [emailInput, setEmailInput] = reactExports.useState('');
|
|
44748
|
+
const [localError, setLocalError] = reactExports.useState(null);
|
|
44749
|
+
const handleSubmit = () => {
|
|
44750
|
+
const trimmedEmail = emailInput.trim();
|
|
44751
|
+
if (!trimmedEmail) {
|
|
44752
|
+
setLocalError('Please enter your email address');
|
|
44753
|
+
return;
|
|
44754
|
+
}
|
|
44755
|
+
if (!trimmedEmail.includes('@')) {
|
|
44756
|
+
setLocalError('Please enter a valid email address');
|
|
44757
|
+
return;
|
|
44758
|
+
}
|
|
44759
|
+
setLocalError(null);
|
|
44760
|
+
onSubmit(trimmedEmail);
|
|
44761
|
+
};
|
|
44762
|
+
const displayError = localError || error;
|
|
44763
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Enter Your Email" }), showCloseButton && onDismiss && jsxRuntimeExports.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__description", children: "Please enter your email address to start the booking process." }), displayError && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), jsxRuntimeExports.jsx("input", { type: "email", className: "ai-chat-booking-card__input", placeholder: "your@email.com", value: emailInput, onChange: (e) => {
|
|
44764
|
+
setEmailInput(e.target.value);
|
|
44765
|
+
setLocalError(null);
|
|
44766
|
+
}, onKeyDown: (e) => {
|
|
44767
|
+
if (e.key === 'Enter' && !isLoading) {
|
|
44768
|
+
handleSubmit();
|
|
44769
|
+
}
|
|
44770
|
+
}, disabled: isLoading }), jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleSubmit, disabled: !emailInput.trim() || isLoading, children: isLoading ? 'Sending...' : 'Continue' })] })] }));
|
|
45109
44771
|
}
|
|
45110
44772
|
|
|
45111
|
-
function
|
|
45112
|
-
|
|
45113
|
-
|
|
44773
|
+
function Skeleton({ width, height, borderRadius = '4px' }) {
|
|
44774
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
|
|
44775
|
+
}
|
|
44776
|
+
|
|
44777
|
+
function PinInputGroup({ values, onChange, disabled }) {
|
|
44778
|
+
const inputRefs = reactExports.useRef([]);
|
|
44779
|
+
const handleChange = (index, value) => {
|
|
44780
|
+
// Only allow digits
|
|
44781
|
+
const digit = value.replace(/[^0-9]/g, '');
|
|
44782
|
+
const newValues = [...values];
|
|
44783
|
+
newValues[index] = digit.slice(-1);
|
|
44784
|
+
onChange(newValues);
|
|
44785
|
+
// Auto-focus next input
|
|
44786
|
+
if (digit && index < 5) {
|
|
44787
|
+
inputRefs.current[index + 1]?.focus();
|
|
44788
|
+
}
|
|
44789
|
+
};
|
|
44790
|
+
const handleKeyDown = (index, e) => {
|
|
44791
|
+
if (e.key === 'Backspace' && !values[index] && index > 0) {
|
|
44792
|
+
inputRefs.current[index - 1]?.focus();
|
|
44793
|
+
}
|
|
44794
|
+
};
|
|
44795
|
+
const handlePaste = (e) => {
|
|
44796
|
+
e.preventDefault();
|
|
44797
|
+
const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, 6);
|
|
44798
|
+
const newValues = pastedData.split('').concat(Array(6 - pastedData.length).fill(''));
|
|
44799
|
+
onChange(newValues);
|
|
44800
|
+
// Focus the next empty input or the last one
|
|
44801
|
+
const nextIndex = Math.min(pastedData.length, 5);
|
|
44802
|
+
inputRefs.current[nextIndex]?.focus();
|
|
44803
|
+
};
|
|
44804
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-pin-input-group", children: values.map((value, index) => (jsxRuntimeExports.jsx("input", { ref: (el) => {
|
|
44805
|
+
inputRefs.current[index] = el;
|
|
44806
|
+
}, 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))) }));
|
|
44807
|
+
}
|
|
44808
|
+
|
|
44809
|
+
function OtpPhase({ accentColor, onDismiss, showCloseButton, email, onSubmit, onResend, isLoading, error, }) {
|
|
44810
|
+
const [otpValues, setOtpValues] = reactExports.useState(Array(6).fill(''));
|
|
44811
|
+
const [localError, setLocalError] = reactExports.useState(null);
|
|
44812
|
+
const [isResending, setIsResending] = reactExports.useState(false);
|
|
44813
|
+
const handleSubmit = () => {
|
|
44814
|
+
const code = otpValues.join('');
|
|
44815
|
+
if (code.length !== 6) {
|
|
44816
|
+
setLocalError('Please enter the 6-digit code');
|
|
44817
|
+
return;
|
|
44818
|
+
}
|
|
44819
|
+
setLocalError(null);
|
|
44820
|
+
onSubmit(code);
|
|
44821
|
+
};
|
|
44822
|
+
const handleResend = async () => {
|
|
44823
|
+
setIsResending(true);
|
|
44824
|
+
setLocalError(null);
|
|
44825
|
+
try {
|
|
44826
|
+
await onResend();
|
|
44827
|
+
}
|
|
44828
|
+
finally {
|
|
44829
|
+
setIsResending(false);
|
|
44830
|
+
}
|
|
45114
44831
|
};
|
|
44832
|
+
const displayError = localError || error;
|
|
44833
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Verify Your Email" }), showCloseButton && onDismiss && jsxRuntimeExports.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntimeExports.jsxs("p", { className: "ai-chat-booking-card__description", children: ["Enter the verification code sent to ", jsxRuntimeExports.jsx("strong", { children: email })] }), jsxRuntimeExports.jsx(PinInputGroup, { values: otpValues, onChange: (newValues) => {
|
|
44834
|
+
setOtpValues(newValues);
|
|
44835
|
+
setLocalError(null);
|
|
44836
|
+
// Auto-submit when all 6 digits are entered
|
|
44837
|
+
if (newValues.every((value) => value.length === 1) && !isLoading) {
|
|
44838
|
+
onSubmit(newValues.join(''));
|
|
44839
|
+
}
|
|
44840
|
+
}, disabled: isLoading }), displayError && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleSubmit, disabled: otpValues.join('').length !== 6 || isLoading, children: isLoading ? 'Verifying...' : 'Verify' }), jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: handleResend, disabled: isLoading || isResending, children: isResending ? 'Sending...' : 'Resend Code' })] })] }));
|
|
44841
|
+
}
|
|
44842
|
+
|
|
44843
|
+
function ContactSelectionPhase({ accentColor, onDismiss, showCloseButton, contacts, onSelect, }) {
|
|
44844
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Select Contact" }), showCloseButton && onDismiss && jsxRuntimeExports.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__description", children: "Choose who you would like to book an appointment with:" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__list", children: contacts.map((contact) => (jsxRuntimeExports.jsxs("button", { className: "ai-chat-booking-card__list-item", onClick: () => onSelect(contact.id), children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__list-item-content", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__list-item-name", children: contact.name }), contact.role && (jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__list-item-role", children: contact.role }))] }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__list-item-arrow", "aria-hidden": "true" })] }, contact.id))) })] })] }));
|
|
44845
|
+
}
|
|
44846
|
+
|
|
44847
|
+
// Calendar icon SVG
|
|
44848
|
+
const CalendarIcon = () => (jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), jsxRuntimeExports.jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }), jsxRuntimeExports.jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }), jsxRuntimeExports.jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })] }));
|
|
44849
|
+
// List icon SVG
|
|
44850
|
+
const ListIcon = () => (jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "8", y1: "6", x2: "21", y2: "6" }), jsxRuntimeExports.jsx("line", { x1: "8", y1: "12", x2: "21", y2: "12" }), jsxRuntimeExports.jsx("line", { x1: "8", y1: "18", x2: "21", y2: "18" }), jsxRuntimeExports.jsx("line", { x1: "3", y1: "6", x2: "3.01", y2: "6" }), jsxRuntimeExports.jsx("line", { x1: "3", y1: "12", x2: "3.01", y2: "12" }), jsxRuntimeExports.jsx("line", { x1: "3", y1: "18", x2: "3.01", y2: "18" })] }));
|
|
44851
|
+
function OptionsPhase({ onDismiss, showCloseButton, appointments, maxAppointments, onBookNew, onViewAppointments, isCancelling, }) {
|
|
44852
|
+
const activeAppointments = appointments.filter(a => a.status !== 'cancelled' && a.status !== 'declined');
|
|
44853
|
+
const canBookNew = activeAppointments.length < maxAppointments;
|
|
44854
|
+
const hasAppointments = appointments.length > 0;
|
|
44855
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Booking Options" }), showCloseButton && onDismiss && jsxRuntimeExports.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [!canBookNew && (jsxRuntimeExports.jsxs("p", { className: "ai-chat-booking-card__warning", children: ["You have reached the maximum number of appointments (", maxAppointments, "). Please cancel an existing appointment to book a new one."] })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__options", children: [jsxRuntimeExports.jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: onBookNew, disabled: !canBookNew || isCancelling, children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__option-icon", children: jsxRuntimeExports.jsx(CalendarIcon, {}) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__option-text", children: "Book New Appointment" })] }), hasAppointments && (jsxRuntimeExports.jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: onViewAppointments, disabled: isCancelling, children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__option-icon", children: jsxRuntimeExports.jsx(ListIcon, {}) }), jsxRuntimeExports.jsxs("span", { className: "ai-chat-booking-card__option-text", children: ["View My Appointments (", activeAppointments.length, ")"] })] }))] })] })] }));
|
|
44856
|
+
}
|
|
44857
|
+
|
|
44858
|
+
function ViewAppointmentsPhase({ accentColor, onDismiss, showCloseButton, appointments, onBack, onCancelAppointment, isCancelling, }) {
|
|
44859
|
+
const [cancellingId, setCancellingId] = reactExports.useState(null);
|
|
44860
|
+
const handleCancel = async (appointmentId) => {
|
|
44861
|
+
setCancellingId(appointmentId);
|
|
44862
|
+
await onCancelAppointment(appointmentId);
|
|
44863
|
+
setCancellingId(null);
|
|
44864
|
+
};
|
|
44865
|
+
const activeAppointments = appointments.filter(a => a.status !== 'cancelled');
|
|
44866
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__back-btn", onClick: onBack, children: "Back" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "My Appointments" }), showCloseButton && onDismiss && jsxRuntimeExports.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__content", children: activeAppointments.length === 0 ? (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__empty", children: "No appointments found." })) : (jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__appointments", children: activeAppointments.map((apt) => (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__appointment", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__appointment-info", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__appointment-subject", children: apt.subject }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__appointment-contact", children: apt.contactName }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__appointment-time", children: apt.displayTime }), jsxRuntimeExports.jsx("span", { className: `ai-chat-booking-card__appointment-status ai-chat-booking-card__appointment-status--${apt.status}`, children: apt.status === 'pending' ? 'Pending Approval' : apt.status })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__appointment-actions", children: [apt.teamsLink && (jsxRuntimeExports.jsx("a", { href: apt.teamsLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__appointment-link", children: "Join Meeting" })), apt.googleMeetLink && (jsxRuntimeExports.jsx("a", { href: apt.googleMeetLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__appointment-link", children: "Join Meeting" })), jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__appointment-cancel", onClick: () => handleCancel(apt.id), disabled: isCancelling || cancellingId === apt.id, children: cancellingId === apt.id ? 'Cancelling...' : 'Cancel' })] })] }, apt.id))) })) })] }));
|
|
44867
|
+
}
|
|
44868
|
+
|
|
44869
|
+
function SlotSelectionPhase({ onDismiss, showCloseButton, slots, contactName, onSelect, onBack, isLoading, error, }) {
|
|
44870
|
+
// Group slots by date
|
|
44871
|
+
const slotsByDate = reactExports.useMemo(() => {
|
|
44872
|
+
const grouped = {};
|
|
44873
|
+
for (const slot of slots) {
|
|
44874
|
+
const date = slot.displayDate;
|
|
44875
|
+
if (!grouped[date]) {
|
|
44876
|
+
grouped[date] = [];
|
|
44877
|
+
}
|
|
44878
|
+
grouped[date].push(slot);
|
|
44879
|
+
}
|
|
44880
|
+
return grouped;
|
|
44881
|
+
}, [slots]);
|
|
44882
|
+
const dates = Object.keys(slotsByDate);
|
|
44883
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__back-btn", onClick: onBack, children: "Back" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Select Time Slot" }), showCloseButton && onDismiss && jsxRuntimeExports.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [contactName && (jsxRuntimeExports.jsxs("p", { className: "ai-chat-booking-card__description", children: ["Available times for ", jsxRuntimeExports.jsx("strong", { children: contactName }), ":"] })), error && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: error })), slots.length === 0 ? (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__empty", children: "No available time slots found. Please try again later." })) : (jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__slots-container", children: dates.map((date) => (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__date-group", children: [jsxRuntimeExports.jsx("h4", { className: "ai-chat-booking-card__date-header", children: date }), jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__slots", children: slotsByDate[date].map((slot) => (jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__slot", onClick: () => onSelect({ startTime: slot.startTime, endTime: slot.endTime }), disabled: isLoading, children: slot.displayTime }, `${slot.startTime}-${slot.endTime}`))) })] }, date))) }))] })] }));
|
|
44884
|
+
}
|
|
44885
|
+
|
|
44886
|
+
function ConfirmationPhase({ onDismiss, showCloseButton, contactName, slotDisplay, subjectMode, predefinedSubjects, onConfirm, onBack, isLoading, error, }) {
|
|
44887
|
+
const [subject, setSubject] = reactExports.useState('');
|
|
44888
|
+
const [selectedPredefined, setSelectedPredefined] = reactExports.useState('');
|
|
44889
|
+
const [localError, setLocalError] = reactExports.useState(null);
|
|
44890
|
+
const handleConfirm = () => {
|
|
44891
|
+
const finalSubject = subjectMode === 'predefined' ? selectedPredefined : subject.trim();
|
|
44892
|
+
if (!finalSubject) {
|
|
44893
|
+
setLocalError('Please enter a subject for your appointment');
|
|
44894
|
+
return;
|
|
44895
|
+
}
|
|
44896
|
+
setLocalError(null);
|
|
44897
|
+
onConfirm(finalSubject);
|
|
44898
|
+
};
|
|
44899
|
+
const displayError = localError || error;
|
|
44900
|
+
const isValid = subjectMode === 'predefined' ? !!selectedPredefined : !!subject.trim();
|
|
44901
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-booking-card${showCloseButton ? ' ai-chat-booking-card--closable' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__back-btn", onClick: onBack, "aria-label": "Go back", children: jsxRuntimeExports.jsx(BackArrowIcon, {}) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Confirm Booking" }), showCloseButton && onDismiss && jsxRuntimeExports.jsx(CloseButton, { onClick: onDismiss, ariaLabel: "Cancel booking" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary", children: [contactName && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "With:" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-value", children: contactName })] })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "When:" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-value", children: slotDisplay })] })] }), displayError && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), subjectMode === 'predefined' ? (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-booking-card__label", children: "Select a topic:" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__subject-options", children: predefinedSubjects.map((subj) => (jsxRuntimeExports.jsx("button", { className: `ai-chat-booking-card__subject-option ${selectedPredefined === subj ? 'ai-chat-booking-card__subject-option--selected' : ''}`, onClick: () => {
|
|
44902
|
+
setSelectedPredefined(subj);
|
|
44903
|
+
setLocalError(null);
|
|
44904
|
+
}, disabled: isLoading, children: subj }, subj))) })] })) : (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-booking-card__label", children: "What would you like to discuss?" }), jsxRuntimeExports.jsx("input", { type: "text", className: "ai-chat-booking-card__input", placeholder: "Enter appointment subject...", value: subject, onChange: (e) => {
|
|
44905
|
+
setSubject(e.target.value);
|
|
44906
|
+
setLocalError(null);
|
|
44907
|
+
}, onKeyDown: (e) => {
|
|
44908
|
+
if (e.key === 'Enter' && isValid && !isLoading) {
|
|
44909
|
+
handleConfirm();
|
|
44910
|
+
}
|
|
44911
|
+
}, disabled: isLoading })] })), jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleConfirm, disabled: !isValid || isLoading, children: isLoading ? 'Booking...' : 'Confirm Booking' })] })] }));
|
|
44912
|
+
}
|
|
44913
|
+
|
|
44914
|
+
function BookedPhase({ subject, contactName, meetingLink, meetingProvider, }) {
|
|
44915
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--success", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__header", children: jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Booked" }) }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__success-icon", "aria-hidden": "true" }), jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__success-message", children: "Your appointment has been successfully scheduled." }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Subject:" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-value", children: subject })] }), contactName && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "With:" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-value", children: contactName })] }))] }), meetingLink && (jsxRuntimeExports.jsx("a", { href: meetingLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", style: {
|
|
44916
|
+
textDecoration: 'none',
|
|
44917
|
+
display: 'inline-block',
|
|
44918
|
+
textAlign: 'center',
|
|
44919
|
+
}, children: meetingProvider === 'google' ? 'Join Google Meet' : 'Join Teams Meeting' }))] })] }));
|
|
44920
|
+
}
|
|
44921
|
+
|
|
44922
|
+
function PendingApprovalPhase({ subject, contactName }) {
|
|
44923
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--pending", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__status-icon ai-chat-booking-card__status-icon--pending" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Awaiting Approval" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__pending-text", children: "Your appointment request has been sent and is awaiting approval." }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Subject:" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-value", children: subject })] }), contactName && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "With:" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-value", children: contactName })] }))] })] })] }));
|
|
45115
44924
|
}
|
|
45116
44925
|
|
|
45117
44926
|
/**
|
|
45118
|
-
*
|
|
45119
|
-
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
44927
|
+
* Cancelled Phase Component (terminal state)
|
|
45120
44928
|
*/
|
|
45121
|
-
function
|
|
45122
|
-
|
|
45123
|
-
|
|
45124
|
-
|
|
45125
|
-
|
|
45126
|
-
|
|
45127
|
-
|
|
45128
|
-
|
|
45129
|
-
|
|
45130
|
-
|
|
45131
|
-
|
|
45132
|
-
|
|
45133
|
-
|
|
45134
|
-
|
|
45135
|
-
|
|
45136
|
-
|
|
45137
|
-
|
|
45138
|
-
|
|
45139
|
-
|
|
44929
|
+
function CancelledPhase() {
|
|
44930
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--cancelled", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__status-icon ai-chat-booking-card__status-icon--cancelled" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Cancelled" })] }), jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__content", children: jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__description", children: "This appointment has been cancelled." }) })] }));
|
|
44931
|
+
}
|
|
44932
|
+
|
|
44933
|
+
function ErrorPhase({ error, onRetry }) {
|
|
44934
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--error", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__status-icon ai-chat-booking-card__status-icon--error" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Booking Error" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: error }), onRetry && (jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: onRetry, children: "Try Again" }))] })] }));
|
|
44935
|
+
}
|
|
44936
|
+
|
|
44937
|
+
function CompletedPhase() {
|
|
44938
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card ai-chat-booking-card--completed", children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__completed-indicator", children: [jsxRuntimeExports.jsx(CheckIcon, {}), jsxRuntimeExports.jsx("span", { children: "Booking action completed" })] }) }));
|
|
44939
|
+
}
|
|
44940
|
+
|
|
44941
|
+
function LoadingPhase() {
|
|
44942
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card", children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsxRuntimeExports.jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsxRuntimeExports.jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntimeExports.jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsxRuntimeExports.jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxRuntimeExports.jsx(Skeleton, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
|
|
44943
|
+
}
|
|
44944
|
+
|
|
44945
|
+
/**
|
|
44946
|
+
* Core action lifecycle handlers for booking flow
|
|
44947
|
+
*/
|
|
44948
|
+
function useBookingAction({ onComplete, onDismiss, toolCallId, }) {
|
|
44949
|
+
const handleDismiss = reactExports.useCallback(() => {
|
|
44950
|
+
onDismiss?.(toolCallId);
|
|
44951
|
+
}, [onDismiss, toolCallId]);
|
|
44952
|
+
const finishAction = reactExports.useCallback((body) => {
|
|
44953
|
+
if (!onComplete)
|
|
44954
|
+
return;
|
|
44955
|
+
onComplete(toolCallId, body);
|
|
44956
|
+
}, [onComplete, toolCallId]);
|
|
44957
|
+
return {
|
|
44958
|
+
handleDismiss,
|
|
44959
|
+
finishAction,
|
|
45140
44960
|
};
|
|
45141
44961
|
}
|
|
45142
44962
|
|
|
45143
|
-
|
|
45144
|
-
|
|
45145
|
-
|
|
44963
|
+
/**
|
|
44964
|
+
* Helper functions for accessing booking data
|
|
44965
|
+
*/
|
|
44966
|
+
function useBookingHelpers({ contacts, slots, bookingMode, }) {
|
|
44967
|
+
const getContactName = reactExports.useCallback((contactId) => {
|
|
44968
|
+
if (!contactId)
|
|
44969
|
+
return bookingMode === 'general' ? 'Shared Calendar' : null;
|
|
44970
|
+
const contact = contacts.find(c => c.id === contactId);
|
|
44971
|
+
return contact?.name || null;
|
|
44972
|
+
}, [contacts, bookingMode]);
|
|
44973
|
+
const getSlotDisplay = reactExports.useCallback((slot) => {
|
|
44974
|
+
if (!slot)
|
|
44975
|
+
return '';
|
|
44976
|
+
const slotData = slots.find(s => s.startTime === slot.startTime && s.endTime === slot.endTime);
|
|
44977
|
+
return slotData ? `${slotData.displayDate} ${slotData.displayTime}` : '';
|
|
44978
|
+
}, [slots]);
|
|
44979
|
+
return {
|
|
44980
|
+
getContactName,
|
|
44981
|
+
getSlotDisplay,
|
|
45146
44982
|
};
|
|
45147
44983
|
}
|
|
45148
44984
|
|
|
45149
44985
|
/**
|
|
45150
|
-
*
|
|
45151
|
-
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
44986
|
+
* OTP-related operations for email verification
|
|
45152
44987
|
*/
|
|
45153
|
-
function
|
|
45154
|
-
|
|
45155
|
-
|
|
45156
|
-
|
|
45157
|
-
|
|
45158
|
-
|
|
45159
|
-
|
|
45160
|
-
|
|
45161
|
-
|
|
45162
|
-
|
|
44988
|
+
function useBookingOtp({ onCallEndpoint, state, setState, config, }) {
|
|
44989
|
+
const handleSendOtp = reactExports.useCallback(async (email) => {
|
|
44990
|
+
if (!onCallEndpoint) {
|
|
44991
|
+
setState(prev => ({ ...prev, error: 'Endpoint not available' }));
|
|
44992
|
+
return;
|
|
44993
|
+
}
|
|
44994
|
+
setState(prev => ({ ...prev, isLoading: true, error: null, email }));
|
|
44995
|
+
try {
|
|
44996
|
+
await onCallEndpoint('send-otp', { email });
|
|
44997
|
+
setState(prev => ({ ...prev, isLoading: false, step: 'otp' }));
|
|
44998
|
+
}
|
|
44999
|
+
catch (err) {
|
|
45000
|
+
const message = err instanceof Error ? err.message : 'Failed to send verification code';
|
|
45001
|
+
setState(prev => ({ ...prev, isLoading: false, error: message }));
|
|
45002
|
+
}
|
|
45003
|
+
}, [onCallEndpoint, setState]);
|
|
45004
|
+
const handleVerifyOtp = reactExports.useCallback(async (code) => {
|
|
45005
|
+
if (!onCallEndpoint) {
|
|
45006
|
+
setState(prev => ({ ...prev, error: 'Endpoint not available' }));
|
|
45007
|
+
return;
|
|
45008
|
+
}
|
|
45009
|
+
setState(prev => ({ ...prev, isLoading: true, error: null }));
|
|
45010
|
+
try {
|
|
45011
|
+
const result = await onCallEndpoint('verify-otp', {
|
|
45012
|
+
email: state.email,
|
|
45013
|
+
code,
|
|
45014
|
+
bookingMode: config.bookingMode,
|
|
45015
|
+
timeZone: config.timeZone,
|
|
45016
|
+
});
|
|
45017
|
+
const nextStep = config.bookingMode === 'general'
|
|
45018
|
+
? 'options'
|
|
45019
|
+
: result.contacts.length === 1
|
|
45020
|
+
? 'options'
|
|
45021
|
+
: 'contact_selection';
|
|
45022
|
+
setState(prev => ({
|
|
45023
|
+
...prev,
|
|
45024
|
+
isLoading: false,
|
|
45025
|
+
token: result.token,
|
|
45026
|
+
contacts: result.contacts,
|
|
45027
|
+
appointments: result.appointments,
|
|
45028
|
+
selectedContactId: result.contacts.length === 1 ? result.contacts[0].id : null,
|
|
45029
|
+
step: nextStep,
|
|
45030
|
+
}));
|
|
45031
|
+
}
|
|
45032
|
+
catch (err) {
|
|
45033
|
+
const message = err instanceof Error ? err.message : 'Invalid verification code';
|
|
45034
|
+
setState(prev => ({ ...prev, isLoading: false, error: message }));
|
|
45035
|
+
}
|
|
45036
|
+
}, [onCallEndpoint, state.email, config.bookingMode, config.timeZone, setState]);
|
|
45037
|
+
const handleResendOtp = reactExports.useCallback(async () => {
|
|
45038
|
+
await handleSendOtp(state.email);
|
|
45039
|
+
}, [handleSendOtp, state.email]);
|
|
45040
|
+
return {
|
|
45041
|
+
handleSendOtp,
|
|
45042
|
+
handleVerifyOtp,
|
|
45043
|
+
handleResendOtp,
|
|
45044
|
+
};
|
|
45045
|
+
}
|
|
45046
|
+
|
|
45047
|
+
/**
|
|
45048
|
+
* Navigation and flow control handlers for booking steps
|
|
45049
|
+
*/
|
|
45050
|
+
function useBookingNavigation({ onCallEndpoint, state, setState, config, }) {
|
|
45051
|
+
const handleSelectContact = reactExports.useCallback((contactId) => {
|
|
45052
|
+
setState(prev => ({
|
|
45053
|
+
...prev,
|
|
45054
|
+
selectedContactId: contactId,
|
|
45055
|
+
step: 'options',
|
|
45056
|
+
}));
|
|
45057
|
+
}, [setState]);
|
|
45058
|
+
const handleBookNew = reactExports.useCallback(async () => {
|
|
45059
|
+
if (!onCallEndpoint || !state.token) {
|
|
45060
|
+
setState(prev => ({ ...prev, error: 'Not authenticated' }));
|
|
45061
|
+
return;
|
|
45062
|
+
}
|
|
45063
|
+
setState(prev => ({ ...prev, isLoading: true, error: null }));
|
|
45064
|
+
try {
|
|
45065
|
+
const result = await onCallEndpoint('get-slots', {
|
|
45066
|
+
contactId: state.selectedContactId,
|
|
45067
|
+
daysAhead: config.daysAhead,
|
|
45068
|
+
timeZone: config.timeZone,
|
|
45069
|
+
}, { token: state.token });
|
|
45070
|
+
setState(prev => ({
|
|
45071
|
+
...prev,
|
|
45072
|
+
isLoading: false,
|
|
45073
|
+
slots: result.slots,
|
|
45074
|
+
step: 'slot_selection',
|
|
45075
|
+
}));
|
|
45076
|
+
}
|
|
45077
|
+
catch (err) {
|
|
45078
|
+
const message = err instanceof Error ? err.message : 'Failed to load available slots';
|
|
45079
|
+
setState(prev => ({ ...prev, isLoading: false, error: message }));
|
|
45080
|
+
}
|
|
45081
|
+
}, [onCallEndpoint, state.token, state.selectedContactId, config.daysAhead, config.timeZone, setState]);
|
|
45082
|
+
const handleViewAppointments = reactExports.useCallback(() => {
|
|
45083
|
+
setState(prev => ({ ...prev, step: 'view_appointments' }));
|
|
45084
|
+
}, [setState]);
|
|
45085
|
+
const handleBackToOptions = reactExports.useCallback(() => {
|
|
45086
|
+
setState(prev => ({ ...prev, step: 'options', error: null }));
|
|
45087
|
+
}, [setState]);
|
|
45088
|
+
const handleSelectSlot = reactExports.useCallback((slot) => {
|
|
45089
|
+
setState(prev => ({
|
|
45090
|
+
...prev,
|
|
45091
|
+
selectedSlot: slot,
|
|
45092
|
+
step: 'confirmation',
|
|
45093
|
+
}));
|
|
45094
|
+
}, [setState]);
|
|
45095
|
+
const handleBackToSlots = reactExports.useCallback(() => {
|
|
45096
|
+
setState(prev => ({ ...prev, step: 'slot_selection', error: null }));
|
|
45097
|
+
}, [setState]);
|
|
45098
|
+
return {
|
|
45099
|
+
handleSelectContact,
|
|
45100
|
+
handleBookNew,
|
|
45101
|
+
handleViewAppointments,
|
|
45102
|
+
handleBackToOptions,
|
|
45103
|
+
handleSelectSlot,
|
|
45104
|
+
handleBackToSlots,
|
|
45105
|
+
};
|
|
45106
|
+
}
|
|
45107
|
+
|
|
45108
|
+
/**
|
|
45109
|
+
* Core booking operations (confirm and cancel)
|
|
45110
|
+
*/
|
|
45111
|
+
function useBookingOperations({ onCallEndpoint, state, setState, config, getContactName, finishAction, }) {
|
|
45112
|
+
const [isCancelling, setIsCancelling] = reactExports.useState(false);
|
|
45113
|
+
const handleConfirmBooking = reactExports.useCallback(async (subject) => {
|
|
45114
|
+
if (!onCallEndpoint || !state.token || !state.selectedSlot) {
|
|
45115
|
+
setState(prev => ({ ...prev, error: 'Missing required data' }));
|
|
45116
|
+
return;
|
|
45117
|
+
}
|
|
45118
|
+
setState(prev => ({ ...prev, isLoading: true, error: null, subject }));
|
|
45119
|
+
try {
|
|
45120
|
+
const result = await onCallEndpoint('book', {
|
|
45121
|
+
contactId: state.selectedContactId,
|
|
45122
|
+
slot: state.selectedSlot,
|
|
45123
|
+
subject,
|
|
45124
|
+
timeZone: config.timeZone,
|
|
45125
|
+
}, { token: state.token });
|
|
45126
|
+
const contactName = getContactName(state.selectedContactId);
|
|
45127
|
+
if (result.status === 'pending_approval') {
|
|
45128
|
+
setState(prev => ({
|
|
45129
|
+
...prev,
|
|
45130
|
+
isLoading: false,
|
|
45131
|
+
step: 'pending_approval',
|
|
45132
|
+
}));
|
|
45133
|
+
// Finish with pending status
|
|
45134
|
+
finishAction({
|
|
45135
|
+
status: 'pending_approval',
|
|
45136
|
+
subject,
|
|
45137
|
+
contactName,
|
|
45138
|
+
message: `Appointment request "${subject}" submitted and awaiting approval.`,
|
|
45139
|
+
});
|
|
45140
|
+
}
|
|
45141
|
+
else {
|
|
45142
|
+
setState(prev => ({
|
|
45143
|
+
...prev,
|
|
45144
|
+
isLoading: false,
|
|
45145
|
+
bookedMeetingLink: result.meetingLink || null,
|
|
45146
|
+
bookedMeetingProvider: result.meetingProvider || null,
|
|
45147
|
+
step: 'booked',
|
|
45148
|
+
}));
|
|
45149
|
+
// Finish with booked status
|
|
45150
|
+
finishAction({
|
|
45151
|
+
status: 'booked',
|
|
45152
|
+
subject,
|
|
45153
|
+
contactName,
|
|
45154
|
+
meetingLink: result.meetingLink,
|
|
45155
|
+
message: `Successfully booked appointment "${subject}"${contactName ? ` with ${contactName}` : ''}.`,
|
|
45156
|
+
});
|
|
45157
|
+
}
|
|
45158
|
+
}
|
|
45159
|
+
catch (err) {
|
|
45160
|
+
const message = err instanceof Error ? err.message : 'Failed to book appointment';
|
|
45161
|
+
setState(prev => ({ ...prev, isLoading: false, error: message }));
|
|
45162
|
+
}
|
|
45163
|
+
}, [onCallEndpoint, state.token, state.selectedSlot, state.selectedContactId, config.timeZone, getContactName, finishAction, setState]);
|
|
45164
|
+
const handleCancelAppointment = reactExports.useCallback(async (appointmentId) => {
|
|
45165
|
+
if (!onCallEndpoint || !state.token) {
|
|
45166
|
+
setState(prev => ({ ...prev, error: 'Not authenticated' }));
|
|
45167
|
+
return;
|
|
45168
|
+
}
|
|
45169
|
+
setIsCancelling(true);
|
|
45170
|
+
try {
|
|
45171
|
+
await onCallEndpoint('cancel', { appointmentId }, { token: state.token });
|
|
45172
|
+
// Update local appointments list
|
|
45173
|
+
setState(prev => ({
|
|
45174
|
+
...prev,
|
|
45175
|
+
appointments: prev.appointments.map(apt => apt.id === appointmentId ? { ...apt, status: 'cancelled' } : apt),
|
|
45176
|
+
}));
|
|
45177
|
+
}
|
|
45178
|
+
catch (err) {
|
|
45179
|
+
const message = err instanceof Error ? err.message : 'Failed to cancel appointment';
|
|
45180
|
+
setState(prev => ({ ...prev, error: message }));
|
|
45181
|
+
}
|
|
45182
|
+
finally {
|
|
45183
|
+
setIsCancelling(false);
|
|
45184
|
+
}
|
|
45185
|
+
}, [onCallEndpoint, state.token, setState]);
|
|
45186
|
+
return {
|
|
45187
|
+
handleConfirmBooking,
|
|
45188
|
+
handleCancelAppointment,
|
|
45189
|
+
isCancelling,
|
|
45190
|
+
};
|
|
45191
|
+
}
|
|
45192
|
+
|
|
45193
|
+
// Default config values
|
|
45194
|
+
const DEFAULT_CONFIG = {
|
|
45195
|
+
bookingMode: 'per-contact',
|
|
45196
|
+
timeZone: 'UTC',
|
|
45197
|
+
maxAppointmentsPerUser: 3,
|
|
45198
|
+
daysAhead: 14,
|
|
45199
|
+
subjectMode: 'user_defined',
|
|
45200
|
+
predefinedSubjects: [],
|
|
45201
|
+
};
|
|
45202
|
+
// Initial UI state
|
|
45203
|
+
const createInitialState = () => ({
|
|
45204
|
+
step: 'email',
|
|
45205
|
+
email: '',
|
|
45206
|
+
selectedContactId: null,
|
|
45207
|
+
selectedSlot: null,
|
|
45208
|
+
subject: '',
|
|
45209
|
+
token: null,
|
|
45210
|
+
contacts: [],
|
|
45211
|
+
appointments: [],
|
|
45212
|
+
slots: [],
|
|
45213
|
+
bookedMeetingLink: null,
|
|
45214
|
+
bookedMeetingProvider: null,
|
|
45215
|
+
isLoading: false,
|
|
45216
|
+
error: null,
|
|
45217
|
+
});
|
|
45218
|
+
function BookContactAppointmentCard({ action, onComplete, onDismiss, onCallEndpoint, accentColor, }) {
|
|
45219
|
+
// Parse config from input (from getInitialClientState)
|
|
45220
|
+
const initialState = action.input;
|
|
45221
|
+
const config = {
|
|
45222
|
+
bookingMode: initialState.bookingMode || DEFAULT_CONFIG.bookingMode,
|
|
45223
|
+
timeZone: initialState.timeZone || DEFAULT_CONFIG.timeZone,
|
|
45224
|
+
maxAppointmentsPerUser: initialState.maxAppointmentsPerUser || DEFAULT_CONFIG.maxAppointmentsPerUser,
|
|
45225
|
+
daysAhead: initialState.daysAhead || DEFAULT_CONFIG.daysAhead,
|
|
45226
|
+
subjectMode: initialState.subjectMode || DEFAULT_CONFIG.subjectMode,
|
|
45227
|
+
predefinedSubjects: initialState.predefinedSubjects || DEFAULT_CONFIG.predefinedSubjects,
|
|
45228
|
+
};
|
|
45229
|
+
// Local UI state
|
|
45230
|
+
const [state, setState] = reactExports.useState(createInitialState);
|
|
45231
|
+
// Check if action is already done (from server state)
|
|
45232
|
+
const isDone = action.done;
|
|
45233
|
+
// Determine if dismiss should be available
|
|
45234
|
+
const isInteractiveStep = ['email', 'otp', 'contact_selection', 'options', 'view_appointments', 'slot_selection', 'confirmation'].includes(state.step);
|
|
45235
|
+
const showCloseButton = !isDone && isInteractiveStep && Boolean(onDismiss);
|
|
45236
|
+
// =========================================================================
|
|
45237
|
+
// Custom Hooks
|
|
45238
|
+
// =========================================================================
|
|
45239
|
+
// Core action lifecycle
|
|
45240
|
+
const { handleDismiss, finishAction } = useBookingAction({
|
|
45241
|
+
onComplete,
|
|
45242
|
+
onDismiss,
|
|
45243
|
+
toolCallId: action.toolCallId,
|
|
45244
|
+
});
|
|
45245
|
+
// Helper functions
|
|
45246
|
+
const { getContactName, getSlotDisplay } = useBookingHelpers({
|
|
45247
|
+
contacts: state.contacts,
|
|
45248
|
+
slots: state.slots,
|
|
45249
|
+
bookingMode: config.bookingMode,
|
|
45250
|
+
});
|
|
45251
|
+
// OTP operations
|
|
45252
|
+
const { handleSendOtp, handleVerifyOtp, handleResendOtp, } = useBookingOtp({
|
|
45253
|
+
onCallEndpoint,
|
|
45254
|
+
state: { email: state.email },
|
|
45255
|
+
setState,
|
|
45256
|
+
config: {
|
|
45257
|
+
bookingMode: config.bookingMode,
|
|
45258
|
+
timeZone: config.timeZone,
|
|
45259
|
+
},
|
|
45260
|
+
});
|
|
45261
|
+
// Navigation handlers
|
|
45262
|
+
const { handleSelectContact, handleBookNew, handleViewAppointments, handleBackToOptions, handleSelectSlot, handleBackToSlots, } = useBookingNavigation({
|
|
45263
|
+
onCallEndpoint,
|
|
45264
|
+
state,
|
|
45265
|
+
setState,
|
|
45266
|
+
config: {
|
|
45267
|
+
daysAhead: config.daysAhead,
|
|
45268
|
+
timeZone: config.timeZone,
|
|
45269
|
+
},
|
|
45270
|
+
});
|
|
45271
|
+
// Booking operations
|
|
45272
|
+
const { handleConfirmBooking, handleCancelAppointment, isCancelling, } = useBookingOperations({
|
|
45273
|
+
onCallEndpoint,
|
|
45274
|
+
state,
|
|
45275
|
+
setState,
|
|
45276
|
+
config: {
|
|
45277
|
+
timeZone: config.timeZone,
|
|
45278
|
+
},
|
|
45279
|
+
getContactName,
|
|
45280
|
+
finishAction,
|
|
45281
|
+
});
|
|
45282
|
+
// =========================================================================
|
|
45283
|
+
// Render
|
|
45284
|
+
// =========================================================================
|
|
45285
|
+
// If action is already done, show a simple completion indicator
|
|
45286
|
+
// The agent's response will convey what happened - no need to reconstruct terminal state
|
|
45287
|
+
if (isDone) {
|
|
45288
|
+
return jsxRuntimeExports.jsx(CompletedPhase, {});
|
|
45289
|
+
}
|
|
45290
|
+
// Show loading when making API calls
|
|
45291
|
+
if (state.isLoading) {
|
|
45292
|
+
return jsxRuntimeExports.jsx(LoadingPhase, {});
|
|
45293
|
+
}
|
|
45294
|
+
// Render based on current step
|
|
45295
|
+
switch (state.step) {
|
|
45296
|
+
case 'email':
|
|
45297
|
+
return (jsxRuntimeExports.jsx(EmailPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, onSubmit: handleSendOtp, isLoading: state.isLoading, error: state.error }));
|
|
45298
|
+
case 'otp':
|
|
45299
|
+
return (jsxRuntimeExports.jsx(OtpPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, email: state.email, onSubmit: handleVerifyOtp, onResend: handleResendOtp, isLoading: state.isLoading, error: state.error }));
|
|
45300
|
+
case 'contact_selection':
|
|
45301
|
+
return (jsxRuntimeExports.jsx(ContactSelectionPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, contacts: state.contacts, onSelect: handleSelectContact }));
|
|
45302
|
+
case 'options':
|
|
45303
|
+
return (jsxRuntimeExports.jsx(OptionsPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, appointments: state.appointments.filter(a => a.status !== 'cancelled'), maxAppointments: config.maxAppointmentsPerUser, onBookNew: handleBookNew, onViewAppointments: handleViewAppointments, onCancelAppointment: handleCancelAppointment, isCancelling: isCancelling }));
|
|
45304
|
+
case 'view_appointments':
|
|
45305
|
+
return (jsxRuntimeExports.jsx(ViewAppointmentsPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, appointments: state.appointments, onBack: handleBackToOptions, onCancelAppointment: handleCancelAppointment, isCancelling: isCancelling }));
|
|
45306
|
+
case 'slot_selection':
|
|
45307
|
+
return (jsxRuntimeExports.jsx(SlotSelectionPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, slots: state.slots, contactName: getContactName(state.selectedContactId), onSelect: handleSelectSlot, onBack: handleBackToOptions, isLoading: state.isLoading, error: state.error }));
|
|
45308
|
+
case 'confirmation':
|
|
45309
|
+
return (jsxRuntimeExports.jsx(ConfirmationPhase, { accentColor: accentColor, onDismiss: handleDismiss, showCloseButton: showCloseButton, contactName: getContactName(state.selectedContactId), slot: state.selectedSlot, slotDisplay: getSlotDisplay(state.selectedSlot), subjectMode: config.subjectMode, predefinedSubjects: config.predefinedSubjects, onConfirm: handleConfirmBooking, onBack: handleBackToSlots, isLoading: state.isLoading, error: state.error }));
|
|
45310
|
+
case 'booked':
|
|
45311
|
+
return (jsxRuntimeExports.jsx(BookedPhase, { subject: state.subject, contactName: getContactName(state.selectedContactId), meetingLink: state.bookedMeetingLink, meetingProvider: state.bookedMeetingProvider }));
|
|
45312
|
+
case 'pending_approval':
|
|
45313
|
+
return (jsxRuntimeExports.jsx(PendingApprovalPhase, { subject: state.subject, contactName: getContactName(state.selectedContactId) }));
|
|
45314
|
+
case 'cancelled':
|
|
45315
|
+
return jsxRuntimeExports.jsx(CancelledPhase, {});
|
|
45316
|
+
case 'error':
|
|
45317
|
+
return jsxRuntimeExports.jsx(ErrorPhase, { error: state.error || 'An error occurred' });
|
|
45318
|
+
default:
|
|
45319
|
+
return jsxRuntimeExports.jsx(ErrorPhase, { error: "Unknown state" });
|
|
45320
|
+
}
|
|
45321
|
+
}
|
|
45322
|
+
|
|
45323
|
+
function ExternalLinkIcon$1() {
|
|
45324
|
+
return (jsxRuntimeExports.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntimeExports.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntimeExports.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
|
|
45325
|
+
}
|
|
45326
|
+
function ImageCard({ item, accentColor, showOverlay = true, onClick, onLinkClick }) {
|
|
45327
|
+
const [imageError, setImageError] = reactExports.useState(false);
|
|
45328
|
+
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
45329
|
+
const hasMetadata = item.title || item.description || item.link;
|
|
45330
|
+
const handleLinkClick = (e) => {
|
|
45331
|
+
e.stopPropagation();
|
|
45332
|
+
if (item.link) {
|
|
45333
|
+
onLinkClick?.(item.link);
|
|
45334
|
+
window.open(item.link, '_blank', 'noopener,noreferrer');
|
|
45335
|
+
}
|
|
45336
|
+
};
|
|
45337
|
+
const handleImageClick = () => {
|
|
45338
|
+
if (onClick) {
|
|
45339
|
+
onClick();
|
|
45340
|
+
}
|
|
45341
|
+
};
|
|
45342
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-image-card", style: style, onClick: handleImageClick, children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-image-card__media", children: !imageError ? (jsxRuntimeExports.jsx("img", { src: item.url, alt: item.alt || item.title || 'Image', className: "ai-chat-image-card__image", onError: () => setImageError(true) })) : (jsxRuntimeExports.jsx("div", { className: "ai-chat-image-card__image-error", children: jsxRuntimeExports.jsx("span", { children: "Failed to load image" }) })) }), hasMetadata && showOverlay && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-image-card__content", children: [item.title && (jsxRuntimeExports.jsx("h4", { className: "ai-chat-image-card__title", children: item.title })), item.description && (jsxRuntimeExports.jsx("p", { className: "ai-chat-image-card__description", children: item.description })), item.link && (jsxRuntimeExports.jsxs("button", { className: "ai-chat-image-card__link-btn", onClick: handleLinkClick, children: [item.linkText || 'View More', jsxRuntimeExports.jsx(ExternalLinkIcon$1, {})] }))] }))] }));
|
|
45343
|
+
}
|
|
45344
|
+
|
|
45345
|
+
function ImageGallery({ items, columns = 2, accentColor }) {
|
|
45346
|
+
const [imageErrors, setImageErrors] = reactExports.useState(new Set());
|
|
45347
|
+
const imageItems = items;
|
|
45348
|
+
if (imageItems.length === 0)
|
|
45349
|
+
return null;
|
|
45350
|
+
// Determine if first item should span full width (for odd counts > 1)
|
|
45351
|
+
const itemCount = imageItems.length;
|
|
45352
|
+
const isOddCount = itemCount > 1 && itemCount % 2 === 1;
|
|
45353
|
+
const style = {
|
|
45354
|
+
...(accentColor ? { '--action-accent': accentColor } : {}),
|
|
45355
|
+
'--gallery-item-count': itemCount,
|
|
45356
|
+
};
|
|
45357
|
+
const handleImageError = (index) => {
|
|
45358
|
+
setImageErrors(prev => new Set(prev).add(index));
|
|
45359
|
+
};
|
|
45360
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-image-gallery", style: style, "data-item-count": itemCount, children: jsxRuntimeExports.jsx("div", { className: `ai-chat-image-gallery__grid ${isOddCount ? 'odd-count' : ''}`, "data-count": itemCount, children: imageItems.map((item, index) => (jsxRuntimeExports.jsx("div", { className: `ai-chat-image-gallery__item ${isOddCount && index === 0 ? 'span-full' : ''}`, children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-image-gallery__item-media", children: [!imageErrors.has(index) ? (jsxRuntimeExports.jsx("img", { src: item.url, alt: item.alt || item.title || `Image ${index + 1}`, onError: () => handleImageError(index) })) : (jsxRuntimeExports.jsx("div", { className: "ai-chat-image-gallery__error", children: jsxRuntimeExports.jsx("span", { children: "Failed to load" }) })), item.title && (jsxRuntimeExports.jsx("div", { className: "ai-chat-image-gallery__item-overlay", children: jsxRuntimeExports.jsx("span", { className: "ai-chat-image-gallery__item-title", children: item.title }) }))] }) }, index))) }) }));
|
|
45361
|
+
}
|
|
45362
|
+
|
|
45363
|
+
function ExternalLinkIcon() {
|
|
45364
|
+
return (jsxRuntimeExports.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntimeExports.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntimeExports.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
|
|
45365
|
+
}
|
|
45366
|
+
function truncate(text, maxLength) {
|
|
45367
|
+
if (text.length <= maxLength)
|
|
45368
|
+
return text;
|
|
45369
|
+
return text.slice(0, maxLength).trim() + '...';
|
|
45370
|
+
}
|
|
45371
|
+
function ProjectCard({ item, accentColor, onLinkClick, variant }) {
|
|
45372
|
+
const [imageError, setImageError] = reactExports.useState(false);
|
|
45373
|
+
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
45374
|
+
const imageUrl = item.url;
|
|
45375
|
+
// Determine variant based on content if not specified
|
|
45376
|
+
const hasTextContent = item.title || item.description;
|
|
45377
|
+
const effectiveVariant = variant || (hasTextContent ? 'full' : 'image-only');
|
|
45378
|
+
const handleCardClick = () => {
|
|
45379
|
+
if (item.link) {
|
|
45380
|
+
onLinkClick?.(item.link);
|
|
45381
|
+
window.open(item.link, '_blank', 'noopener,noreferrer');
|
|
45382
|
+
}
|
|
45383
|
+
};
|
|
45384
|
+
// Image-only variant - just the image with optional hover effect
|
|
45385
|
+
if (effectiveVariant === 'image-only') {
|
|
45386
|
+
return (jsxRuntimeExports.jsx("div", { className: `ai-chat-project-card ai-chat-project-card--image-only ${item.link ? 'clickable' : ''}`, style: style, onClick: item.link ? handleCardClick : undefined, role: item.link ? 'link' : undefined, tabIndex: item.link ? 0 : undefined, onKeyDown: (e) => e.key === 'Enter' && item.link && handleCardClick(), children: jsxRuntimeExports.jsx("div", { className: "ai-chat-project-card__media", children: imageUrl && !imageError ? (jsxRuntimeExports.jsx("img", { src: imageUrl, alt: item.alt || 'Image', onError: () => setImageError(true) })) : (jsxRuntimeExports.jsx("div", { className: "ai-chat-project-card__placeholder", children: imageError ? 'Failed to load' : 'No image' })) }) }));
|
|
45387
|
+
}
|
|
45388
|
+
// Overlay variant - title overlaid on image
|
|
45389
|
+
if (effectiveVariant === 'overlay') {
|
|
45390
|
+
return (jsxRuntimeExports.jsx("div", { className: `ai-chat-project-card ai-chat-project-card--overlay ${item.link ? 'clickable' : ''}`, style: style, onClick: item.link ? handleCardClick : undefined, role: item.link ? 'link' : undefined, tabIndex: item.link ? 0 : undefined, onKeyDown: (e) => e.key === 'Enter' && item.link && handleCardClick(), children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-project-card__media", children: [imageUrl && !imageError ? (jsxRuntimeExports.jsx("img", { src: imageUrl, alt: item.alt || item.title || 'Image', onError: () => setImageError(true) })) : (jsxRuntimeExports.jsx("div", { className: "ai-chat-project-card__placeholder", children: imageError ? 'Failed to load' : 'No image' })), item.title && (jsxRuntimeExports.jsx("div", { className: "ai-chat-project-card__overlay", children: jsxRuntimeExports.jsx("h4", { className: "ai-chat-project-card__overlay-title", children: truncate(item.title, 50) }) }))] }) }));
|
|
45391
|
+
}
|
|
45392
|
+
// Full variant - image with separate content section below
|
|
45393
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-project-card ai-chat-project-card--full ${item.link ? 'clickable' : ''}`, style: style, onClick: item.link ? handleCardClick : undefined, role: item.link ? 'link' : undefined, tabIndex: item.link ? 0 : undefined, onKeyDown: (e) => e.key === 'Enter' && item.link && handleCardClick(), children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-project-card__media", children: imageUrl && !imageError ? (jsxRuntimeExports.jsx("img", { src: imageUrl, alt: item.alt || item.title || 'Project image', onError: () => setImageError(true) })) : (jsxRuntimeExports.jsx("div", { className: "ai-chat-project-card__placeholder", children: imageError ? 'Failed to load' : 'No image' })) }), hasTextContent && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-project-card__content", children: [item.title && (jsxRuntimeExports.jsx("h4", { className: "ai-chat-project-card__title", children: truncate(item.title, 60) })), item.description && (jsxRuntimeExports.jsx("p", { className: "ai-chat-project-card__description", children: truncate(item.description, 120) })), item.link && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-project-card__link", children: [jsxRuntimeExports.jsx("span", { children: item.linkText || 'View' }), jsxRuntimeExports.jsx(ExternalLinkIcon, {})] }))] }))] }));
|
|
45394
|
+
}
|
|
45395
|
+
|
|
45396
|
+
/**
|
|
45397
|
+
* URL validation utilities for images, cards, and links
|
|
45398
|
+
* Prevents 404 errors by validating URLs before display
|
|
45399
|
+
*/
|
|
45400
|
+
/**
|
|
45401
|
+
* Validate a single URL by attempting to load it
|
|
45402
|
+
*/
|
|
45403
|
+
/**
|
|
45404
|
+
* Validate an image URL by attempting to load it as an Image
|
|
45405
|
+
*/
|
|
45406
|
+
async function validateImageUrl(url, timeout = 5000) {
|
|
45407
|
+
if (!url || typeof url !== 'string') {
|
|
45408
|
+
return { isValid: false, error: 'Invalid URL format' };
|
|
45409
|
+
}
|
|
45410
|
+
try {
|
|
45411
|
+
new URL(url);
|
|
45412
|
+
}
|
|
45413
|
+
catch (e) {
|
|
45414
|
+
return { isValid: false, error: 'Invalid URL structure' };
|
|
45415
|
+
}
|
|
45416
|
+
return new Promise((resolve) => {
|
|
45417
|
+
const img = new Image();
|
|
45418
|
+
const timeoutId = setTimeout(() => {
|
|
45419
|
+
img.src = '';
|
|
45420
|
+
resolve({ isValid: false, error: 'Image load timeout' });
|
|
45421
|
+
}, timeout);
|
|
45422
|
+
img.onload = () => {
|
|
45423
|
+
clearTimeout(timeoutId);
|
|
45424
|
+
resolve({ isValid: true });
|
|
45163
45425
|
};
|
|
45164
|
-
|
|
45165
|
-
|
|
45166
|
-
|
|
45167
|
-
|
|
45168
|
-
|
|
45169
|
-
|
|
45170
|
-
|
|
45171
|
-
|
|
45426
|
+
img.onerror = () => {
|
|
45427
|
+
clearTimeout(timeoutId);
|
|
45428
|
+
resolve({ isValid: false, error: 'Failed to load image' });
|
|
45429
|
+
};
|
|
45430
|
+
img.src = url;
|
|
45431
|
+
});
|
|
45432
|
+
}
|
|
45433
|
+
/**
|
|
45434
|
+
* Validate multiple image URLs concurrently
|
|
45435
|
+
*/
|
|
45436
|
+
async function validateImageUrls(urls, timeout = 5000, maxConcurrent = 10) {
|
|
45437
|
+
const results = new Map();
|
|
45438
|
+
// Process in batches to limit concurrent requests
|
|
45439
|
+
for (let i = 0; i < urls.length; i += maxConcurrent) {
|
|
45440
|
+
const batch = urls.slice(i, i + maxConcurrent);
|
|
45441
|
+
const batchResults = await Promise.all(batch.map(async (url) => {
|
|
45442
|
+
const result = await validateImageUrl(url, timeout);
|
|
45443
|
+
return { url, result };
|
|
45444
|
+
}));
|
|
45445
|
+
batchResults.forEach(({ url, result }) => {
|
|
45446
|
+
results.set(url, result);
|
|
45447
|
+
});
|
|
45448
|
+
}
|
|
45449
|
+
return results;
|
|
45450
|
+
}
|
|
45451
|
+
/**
|
|
45452
|
+
* Validate image items and separate valid from invalid
|
|
45453
|
+
*/
|
|
45454
|
+
async function validateImageItems(items, timeout = 5000) {
|
|
45455
|
+
const urls = items.map(item => item.url).filter(Boolean);
|
|
45456
|
+
if (urls.length === 0) {
|
|
45457
|
+
return { validItems: [], invalidItems: items };
|
|
45458
|
+
}
|
|
45459
|
+
const validationResults = await validateImageUrls(urls, timeout);
|
|
45460
|
+
const validItems = [];
|
|
45461
|
+
const invalidItems = [];
|
|
45462
|
+
items.forEach(item => {
|
|
45463
|
+
if (!item.url) {
|
|
45464
|
+
invalidItems.push({
|
|
45465
|
+
...item,
|
|
45466
|
+
isValid: false,
|
|
45467
|
+
validationError: 'Missing URL',
|
|
45468
|
+
});
|
|
45469
|
+
return;
|
|
45470
|
+
}
|
|
45471
|
+
const result = validationResults.get(item.url);
|
|
45472
|
+
if (result?.isValid) {
|
|
45473
|
+
validItems.push({
|
|
45474
|
+
...item,
|
|
45475
|
+
isValid: true,
|
|
45476
|
+
});
|
|
45477
|
+
}
|
|
45478
|
+
else {
|
|
45479
|
+
invalidItems.push({
|
|
45480
|
+
...item,
|
|
45481
|
+
isValid: false,
|
|
45482
|
+
validationError: result?.error || 'Unknown error',
|
|
45483
|
+
});
|
|
45484
|
+
}
|
|
45485
|
+
});
|
|
45486
|
+
return { validItems, invalidItems };
|
|
45487
|
+
}
|
|
45488
|
+
/**
|
|
45489
|
+
* Preload and validate images before rendering
|
|
45490
|
+
* Returns items with validation status
|
|
45491
|
+
*/
|
|
45492
|
+
async function preloadAndValidateImages(items, timeout = 5000) {
|
|
45493
|
+
const { validItems, invalidItems } = await validateImageItems(items, timeout);
|
|
45494
|
+
if (invalidItems.length > 0) {
|
|
45495
|
+
console.warn('[URLValidator] Invalid image URLs detected:', invalidItems.map(i => ({
|
|
45496
|
+
url: i.url,
|
|
45497
|
+
error: i.validationError,
|
|
45498
|
+
})));
|
|
45499
|
+
}
|
|
45500
|
+
return [...validItems, ...invalidItems];
|
|
45501
|
+
}
|
|
45502
|
+
|
|
45503
|
+
function determineLayout(items, requestedLayout) {
|
|
45504
|
+
// Single item always uses single layout
|
|
45505
|
+
if (items.length === 1) {
|
|
45506
|
+
return 'single';
|
|
45507
|
+
}
|
|
45508
|
+
// For multiple items, use gallery (which now supports overlay titles)
|
|
45509
|
+
// Cards and gallery are now visually the same - 2-column grid with overlay titles
|
|
45510
|
+
return 'gallery';
|
|
45511
|
+
}
|
|
45512
|
+
function determineColumns(itemCount, maxColumns = 2) {
|
|
45513
|
+
if (itemCount === 1)
|
|
45514
|
+
return 1;
|
|
45515
|
+
return Math.min(2, maxColumns);
|
|
45516
|
+
}
|
|
45517
|
+
function StructuredImageDisplay({ action, onComplete, accentColor, maxColumns = 3 }) {
|
|
45518
|
+
const rawState = action.input;
|
|
45519
|
+
const hasCompletedRef = reactExports.useRef(false);
|
|
45520
|
+
const [validatedItems, setValidatedItems] = reactExports.useState([]);
|
|
45521
|
+
const [isValidating, setIsValidating] = reactExports.useState(true);
|
|
45522
|
+
const [validationErrors, setValidationErrors] = reactExports.useState([]);
|
|
45523
|
+
// Provide safe defaults if state is missing
|
|
45524
|
+
const state = {
|
|
45525
|
+
items: rawState?.items || [],
|
|
45526
|
+
layout: rawState?.layout || 'single',
|
|
45527
|
+
context: rawState?.context,
|
|
45528
|
+
columns: rawState?.columns,
|
|
45529
|
+
status: rawState?.status || 'displaying',
|
|
45530
|
+
error: rawState?.error,
|
|
45172
45531
|
};
|
|
45532
|
+
const isError = state.status === 'error';
|
|
45533
|
+
// Validate URLs before displaying
|
|
45534
|
+
reactExports.useEffect(() => {
|
|
45535
|
+
if (state.items.length === 0) {
|
|
45536
|
+
setIsValidating(false);
|
|
45537
|
+
return;
|
|
45538
|
+
}
|
|
45539
|
+
let isMounted = true;
|
|
45540
|
+
const validateItems = async () => {
|
|
45541
|
+
try {
|
|
45542
|
+
const validated = await preloadAndValidateImages(state.items, 3000);
|
|
45543
|
+
if (!isMounted)
|
|
45544
|
+
return;
|
|
45545
|
+
const valid = validated.filter(item => item.isValid !== false);
|
|
45546
|
+
const invalid = validated.filter(item => item.isValid === false);
|
|
45547
|
+
setValidatedItems(valid);
|
|
45548
|
+
if (invalid.length > 0) {
|
|
45549
|
+
const errors = invalid.map(item => `${item.url}: ${item.validationError || 'Failed to load'}`);
|
|
45550
|
+
setValidationErrors(errors);
|
|
45551
|
+
console.warn('[StructuredImageDisplay] Filtered invalid URLs:', errors);
|
|
45552
|
+
}
|
|
45553
|
+
}
|
|
45554
|
+
catch (error) {
|
|
45555
|
+
console.error('[StructuredImageDisplay] Validation error:', error);
|
|
45556
|
+
// Fallback to unvalidated items on error
|
|
45557
|
+
if (isMounted) {
|
|
45558
|
+
setValidatedItems(state.items);
|
|
45559
|
+
}
|
|
45560
|
+
}
|
|
45561
|
+
finally {
|
|
45562
|
+
if (isMounted) {
|
|
45563
|
+
setIsValidating(false);
|
|
45564
|
+
}
|
|
45565
|
+
}
|
|
45566
|
+
};
|
|
45567
|
+
validateItems();
|
|
45568
|
+
return () => {
|
|
45569
|
+
isMounted = false;
|
|
45570
|
+
};
|
|
45571
|
+
}, [state.items]);
|
|
45572
|
+
// Auto-complete on mount so AI can continue generating text response
|
|
45573
|
+
reactExports.useEffect(() => {
|
|
45574
|
+
if (!action.done && !hasCompletedRef.current && onComplete && state.items.length > 0) {
|
|
45575
|
+
hasCompletedRef.current = true;
|
|
45576
|
+
onComplete(action.toolCallId, { ...state, status: 'displaying' });
|
|
45577
|
+
}
|
|
45578
|
+
}, [action.done, action.toolCallId, onComplete, state]);
|
|
45579
|
+
const handleInteraction = () => {
|
|
45580
|
+
onComplete?.(action.toolCallId, { ...state, status: 'interacted' });
|
|
45581
|
+
};
|
|
45582
|
+
const handleLinkClick = (url) => {
|
|
45583
|
+
handleInteraction();
|
|
45584
|
+
};
|
|
45585
|
+
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
45586
|
+
// Error state
|
|
45587
|
+
if (isError) {
|
|
45588
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-structured-image ai-chat-structured-image--error", style: style, children: jsxRuntimeExports.jsx("div", { className: "ai-chat-structured-image__error", children: state.error || 'Failed to load media' }) }));
|
|
45589
|
+
}
|
|
45590
|
+
// Loading state
|
|
45591
|
+
if (isValidating) {
|
|
45592
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-structured-image", style: style, children: [state.context && (jsxRuntimeExports.jsx("p", { className: "ai-chat-structured-image__context", children: state.context })), jsxRuntimeExports.jsx("div", { className: "ai-chat-structured-image__loading", children: "Validating images..." })] }));
|
|
45593
|
+
}
|
|
45594
|
+
// No valid items after validation
|
|
45595
|
+
if (validatedItems.length === 0) {
|
|
45596
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-structured-image", style: style, children: [state.context && (jsxRuntimeExports.jsx("p", { className: "ai-chat-structured-image__context", children: state.context })), validationErrors.length > 0 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-structured-image__error", children: "All images failed to load. Please check the URLs." }))] }));
|
|
45597
|
+
}
|
|
45598
|
+
const layout = determineLayout(validatedItems, state.layout);
|
|
45599
|
+
const columns = state.columns || determineColumns(validatedItems.length, maxColumns);
|
|
45600
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-structured-image", style: style, children: [state.context && (jsxRuntimeExports.jsx("p", { className: "ai-chat-structured-image__context", children: state.context })), validationErrors.length > 0 && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-structured-image__warning", children: [validationErrors.length, " image(s) could not be loaded and were filtered."] })), layout === 'single' && validatedItems[0] && (jsxRuntimeExports.jsx(ImageCard, { item: validatedItems[0], accentColor: accentColor, onLinkClick: handleLinkClick })), layout === 'gallery' && (jsxRuntimeExports.jsx(ImageGallery, { items: validatedItems, columns: columns, accentColor: accentColor, maxColumns: maxColumns })), layout === 'cards' && (jsxRuntimeExports.jsx("div", { className: "ai-chat-structured-image__cards", style: { '--card-columns': validatedItems.length === 1 ? 1 : 2 }, children: validatedItems.map((item, index) => (jsxRuntimeExports.jsx(ProjectCard, { item: item, accentColor: accentColor, onLinkClick: handleLinkClick, variant: "overlay" }, index))) })), layout === 'carousel' && (jsxRuntimeExports.jsx(ImageCarousel, { items: validatedItems, accentColor: accentColor, onLinkClick: handleLinkClick }))] }));
|
|
45601
|
+
}
|
|
45602
|
+
function ChevronLeftIcon() {
|
|
45603
|
+
return (jsxRuntimeExports.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "15 18 9 12 15 6" }) }));
|
|
45604
|
+
}
|
|
45605
|
+
function ChevronRightIcon() {
|
|
45606
|
+
return (jsxRuntimeExports.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "9 18 15 12 9 6" }) }));
|
|
45607
|
+
}
|
|
45608
|
+
function ImageCarousel({ items, accentColor, onLinkClick }) {
|
|
45609
|
+
const [currentIndex, setCurrentIndex] = React.useState(0);
|
|
45610
|
+
const containerRef = reactExports.useRef(null);
|
|
45611
|
+
const goToPrevious = () => {
|
|
45612
|
+
setCurrentIndex(prev => prev === 0 ? items.length - 1 : prev - 1);
|
|
45613
|
+
};
|
|
45614
|
+
const goToNext = () => {
|
|
45615
|
+
setCurrentIndex(prev => prev === items.length - 1 ? 0 : prev + 1);
|
|
45616
|
+
};
|
|
45617
|
+
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
45618
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-image-carousel", style: style, ref: containerRef, children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-image-carousel__track", style: { transform: `translateX(-${currentIndex * 100}%)` }, children: items.map((item, index) => (jsxRuntimeExports.jsx("div", { className: "ai-chat-image-carousel__slide", children: jsxRuntimeExports.jsx(ProjectCard, { item: item, accentColor: accentColor, onLinkClick: onLinkClick }) }, index))) }), items.length > 1 && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("button", { className: "ai-chat-image-carousel__nav prev", onClick: goToPrevious, "aria-label": "Previous", children: jsxRuntimeExports.jsx(ChevronLeftIcon, {}) }), jsxRuntimeExports.jsx("button", { className: "ai-chat-image-carousel__nav next", onClick: goToNext, "aria-label": "Next", children: jsxRuntimeExports.jsx(ChevronRightIcon, {}) }), jsxRuntimeExports.jsx("div", { className: "ai-chat-image-carousel__dots", children: items.map((_, index) => (jsxRuntimeExports.jsx("button", { className: `ai-chat-image-carousel__dot ${index === currentIndex ? 'active' : ''}`, onClick: () => setCurrentIndex(index), "aria-label": `Go to slide ${index + 1}` }, index))) })] }))] }));
|
|
45619
|
+
}
|
|
45620
|
+
|
|
45621
|
+
const pendingResolvers = new Map();
|
|
45622
|
+
const resumeCallbacks = new Map();
|
|
45623
|
+
const frontendActionHandlers = {};
|
|
45624
|
+
const actionRenderers = {};
|
|
45625
|
+
function getFrontendActionHandler(implementation) {
|
|
45626
|
+
return frontendActionHandlers[implementation];
|
|
45627
|
+
}
|
|
45628
|
+
function getActionRenderer(implementation) {
|
|
45629
|
+
return actionRenderers[implementation];
|
|
45630
|
+
}
|
|
45631
|
+
function waitForActionState(toolCallId) {
|
|
45632
|
+
return new Promise((resolve) => {
|
|
45633
|
+
pendingResolvers.set(toolCallId, resolve);
|
|
45634
|
+
});
|
|
45635
|
+
}
|
|
45636
|
+
function resolveActionState(toolCallId, state) {
|
|
45637
|
+
const resolver = pendingResolvers.get(toolCallId);
|
|
45638
|
+
if (resolver) {
|
|
45639
|
+
pendingResolvers.delete(toolCallId);
|
|
45640
|
+
resolver(state);
|
|
45641
|
+
return;
|
|
45642
|
+
}
|
|
45643
|
+
const resumeCallback = resumeCallbacks.get(toolCallId);
|
|
45644
|
+
if (resumeCallback) {
|
|
45645
|
+
resumeCallback(state).catch((error) => {
|
|
45646
|
+
console.error("[Action] Failed to resume action:", error);
|
|
45647
|
+
});
|
|
45648
|
+
}
|
|
45649
|
+
}
|
|
45650
|
+
function registerActionResumeCallback(toolCallId, callback) {
|
|
45651
|
+
resumeCallbacks.set(toolCallId, callback);
|
|
45652
|
+
}
|
|
45653
|
+
function unregisterActionResumeCallback(toolCallId) {
|
|
45654
|
+
resumeCallbacks.delete(toolCallId);
|
|
45173
45655
|
}
|
|
45174
45656
|
|
|
45175
45657
|
/**
|
|
@@ -45177,9 +45659,15 @@
|
|
|
45177
45659
|
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
45178
45660
|
*/
|
|
45179
45661
|
function registerLinkPreviewAction() {
|
|
45180
|
-
// Handler - auto-completes immediately
|
|
45662
|
+
// Handler - auto-completes immediately, returns body for agent
|
|
45181
45663
|
frontendActionHandlers["link-preview"] = async (_input, state, _context) => {
|
|
45182
|
-
|
|
45664
|
+
const links = state?.links || [];
|
|
45665
|
+
// Return body directly - sent to backend via continueAgentAction
|
|
45666
|
+
return {
|
|
45667
|
+
status: "displayed",
|
|
45668
|
+
linkCount: links.length,
|
|
45669
|
+
message: `Displayed ${links.length} link preview${links.length > 1 ? 's' : ''}.`,
|
|
45670
|
+
};
|
|
45183
45671
|
};
|
|
45184
45672
|
// Renderer - displays the link preview card
|
|
45185
45673
|
actionRenderers["link-preview"] = (message, accentColor) => {
|
|
@@ -45189,16 +45677,15 @@
|
|
|
45189
45677
|
const handleComplete = (toolCallId, newState) => {
|
|
45190
45678
|
resolveActionState(toolCallId, newState);
|
|
45191
45679
|
};
|
|
45192
|
-
// Check if action
|
|
45193
|
-
const
|
|
45194
|
-
const status =
|
|
45195
|
-
const isDone = action.done || status === "displaying" || status === "clicked";
|
|
45680
|
+
// Check if action input indicates it's already complete (displaying or clicked)
|
|
45681
|
+
const input = action.input;
|
|
45682
|
+
const status = input?.status;
|
|
45683
|
+
const isDone = action.done || status === "displaying" || status === "displayed" || status === "clicked";
|
|
45196
45684
|
return (jsxRuntimeExports.jsx(LinkPreviewCard, { action: {
|
|
45197
45685
|
implementation: action.implementation,
|
|
45198
45686
|
toolCallId: action.toolCallId,
|
|
45199
45687
|
actionId: action.actionId,
|
|
45200
45688
|
input: action.input,
|
|
45201
|
-
state: action.state,
|
|
45202
45689
|
done: isDone,
|
|
45203
45690
|
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
45204
45691
|
};
|
|
@@ -45209,9 +45696,15 @@
|
|
|
45209
45696
|
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
45210
45697
|
*/
|
|
45211
45698
|
function registerVideoPlayerAction() {
|
|
45212
|
-
// Handler - auto-completes immediately
|
|
45699
|
+
// Handler - auto-completes immediately, returns body for agent
|
|
45213
45700
|
frontendActionHandlers["video-player"] = async (_input, state, _context) => {
|
|
45214
|
-
|
|
45701
|
+
const videos = state?.videos || [];
|
|
45702
|
+
// Return body directly - sent to backend via continueAgentAction
|
|
45703
|
+
return {
|
|
45704
|
+
status: "displayed",
|
|
45705
|
+
videoCount: videos.length,
|
|
45706
|
+
message: `Displayed ${videos.length} video${videos.length !== 1 ? 's' : ''}.`,
|
|
45707
|
+
};
|
|
45215
45708
|
};
|
|
45216
45709
|
// Renderer - displays the embedded video player card
|
|
45217
45710
|
actionRenderers["video-player"] = (message, accentColor) => {
|
|
@@ -45221,16 +45714,15 @@
|
|
|
45221
45714
|
const handleComplete = (toolCallId, newState) => {
|
|
45222
45715
|
resolveActionState(toolCallId, newState);
|
|
45223
45716
|
};
|
|
45224
|
-
// Check if action
|
|
45225
|
-
const
|
|
45226
|
-
const status =
|
|
45227
|
-
const isDone = action.done || status === "displaying" || status === "played";
|
|
45717
|
+
// Check if action input indicates it's already complete (displaying or played)
|
|
45718
|
+
const input = action.input;
|
|
45719
|
+
const status = input?.status;
|
|
45720
|
+
const isDone = action.done || status === "displaying" || status === "displayed" || status === "played";
|
|
45228
45721
|
return (jsxRuntimeExports.jsx(VideoPlayerCard, { action: {
|
|
45229
45722
|
implementation: action.implementation,
|
|
45230
45723
|
toolCallId: action.toolCallId,
|
|
45231
45724
|
actionId: action.actionId,
|
|
45232
45725
|
input: action.input,
|
|
45233
|
-
state: action.state,
|
|
45234
45726
|
done: isDone,
|
|
45235
45727
|
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
45236
45728
|
};
|
|
@@ -45241,9 +45733,15 @@
|
|
|
45241
45733
|
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
45242
45734
|
*/
|
|
45243
45735
|
function registerLocationCardAction() {
|
|
45244
|
-
// Handler - auto-completes immediately
|
|
45736
|
+
// Handler - auto-completes immediately, returns body for agent
|
|
45245
45737
|
frontendActionHandlers["location-card"] = async (_input, state, _context) => {
|
|
45246
|
-
|
|
45738
|
+
const locations = state?.locations || [];
|
|
45739
|
+
// Return body directly - sent to backend via continueAgentAction
|
|
45740
|
+
return {
|
|
45741
|
+
status: "displayed",
|
|
45742
|
+
locationCount: locations.length,
|
|
45743
|
+
message: `Displayed ${locations.length} location${locations.length !== 1 ? 's' : ''}.`,
|
|
45744
|
+
};
|
|
45247
45745
|
};
|
|
45248
45746
|
// Renderer - displays the location card
|
|
45249
45747
|
actionRenderers["location-card"] = (message, accentColor, variant) => {
|
|
@@ -45253,25 +45751,30 @@
|
|
|
45253
45751
|
const handleComplete = (toolCallId, newState) => {
|
|
45254
45752
|
resolveActionState(toolCallId, newState);
|
|
45255
45753
|
};
|
|
45256
|
-
// Check if action
|
|
45257
|
-
const
|
|
45258
|
-
const status =
|
|
45259
|
-
const isDone = action.done || status === "displaying" || status === "directions_opened";
|
|
45754
|
+
// Check if action input indicates it's already complete
|
|
45755
|
+
const input = action.input;
|
|
45756
|
+
const status = input?.status;
|
|
45757
|
+
const isDone = action.done || status === "displaying" || status === "displayed" || status === "directions_opened";
|
|
45260
45758
|
return (jsxRuntimeExports.jsx(LocationCard, { action: {
|
|
45261
45759
|
implementation: action.implementation,
|
|
45262
45760
|
toolCallId: action.toolCallId,
|
|
45263
45761
|
actionId: action.actionId,
|
|
45264
45762
|
input: action.input,
|
|
45265
|
-
state: action.state,
|
|
45266
45763
|
done: isDone,
|
|
45267
45764
|
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
|
|
45268
45765
|
};
|
|
45269
45766
|
}
|
|
45270
45767
|
|
|
45271
45768
|
function registerContactCardAction() {
|
|
45272
|
-
// Handler - auto-completes immediately
|
|
45769
|
+
// Handler - auto-completes immediately, returns body for agent
|
|
45273
45770
|
frontendActionHandlers['contact-card'] = async (_input, state, _context) => {
|
|
45274
|
-
|
|
45771
|
+
const contacts = state?.contacts || [];
|
|
45772
|
+
// Return body directly - sent to backend via continueAgentAction
|
|
45773
|
+
return {
|
|
45774
|
+
status: 'displayed',
|
|
45775
|
+
contactCount: contacts.length,
|
|
45776
|
+
message: `Displayed ${contacts.length} contact${contacts.length !== 1 ? 's' : ''}.`,
|
|
45777
|
+
};
|
|
45275
45778
|
};
|
|
45276
45779
|
// Renderer - displays the contact card
|
|
45277
45780
|
actionRenderers['contact-card'] = (message, accentColor, variant) => {
|
|
@@ -45281,16 +45784,15 @@
|
|
|
45281
45784
|
const handleComplete = (toolCallId, newState) => {
|
|
45282
45785
|
resolveActionState(toolCallId, newState);
|
|
45283
45786
|
};
|
|
45284
|
-
// Check if action
|
|
45285
|
-
const
|
|
45286
|
-
const status =
|
|
45287
|
-
const isDone = action.done || status === 'displaying' || status === 'contacted';
|
|
45787
|
+
// Check if action input indicates it's already complete
|
|
45788
|
+
const input = action.input;
|
|
45789
|
+
const status = input?.status;
|
|
45790
|
+
const isDone = action.done || status === 'displaying' || status === 'displayed' || status === 'contacted';
|
|
45288
45791
|
return (jsxRuntimeExports.jsx(ContactCard, { action: {
|
|
45289
45792
|
implementation: action.implementation,
|
|
45290
45793
|
toolCallId: action.toolCallId,
|
|
45291
45794
|
actionId: action.actionId,
|
|
45292
45795
|
input: action.input,
|
|
45293
|
-
state: action.state,
|
|
45294
45796
|
done: isDone,
|
|
45295
45797
|
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
|
|
45296
45798
|
};
|
|
@@ -45301,55 +45803,133 @@
|
|
|
45301
45803
|
frontendActionHandlers['query-contact-directory'] = async (_input, state, _context) => {
|
|
45302
45804
|
return { ...state, status: 'displaying' };
|
|
45303
45805
|
};
|
|
45304
|
-
// Renderer - displays the contact card with search results
|
|
45305
|
-
actionRenderers['query-contact-directory'] = (message, accentColor, variant) => {
|
|
45806
|
+
// Renderer - displays the contact card with search results
|
|
45807
|
+
actionRenderers['query-contact-directory'] = (message, accentColor, variant) => {
|
|
45808
|
+
const action = message.action;
|
|
45809
|
+
if (!action)
|
|
45810
|
+
return null;
|
|
45811
|
+
// Handle completion - triggers agent to continue with text response
|
|
45812
|
+
const handleComplete = (toolCallId, newState) => {
|
|
45813
|
+
resolveActionState(toolCallId, newState);
|
|
45814
|
+
};
|
|
45815
|
+
// Check if action input indicates it's already complete
|
|
45816
|
+
const input = action.input;
|
|
45817
|
+
const status = input?.status;
|
|
45818
|
+
const isDone = action.done || status === 'displaying' || status === 'contacted';
|
|
45819
|
+
return (jsxRuntimeExports.jsx(ContactCard, { action: {
|
|
45820
|
+
implementation: action.implementation,
|
|
45821
|
+
toolCallId: action.toolCallId,
|
|
45822
|
+
actionId: action.actionId,
|
|
45823
|
+
input: action.input,
|
|
45824
|
+
done: isDone,
|
|
45825
|
+
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
|
|
45826
|
+
};
|
|
45827
|
+
}
|
|
45828
|
+
|
|
45829
|
+
function registerDisplayFormAction() {
|
|
45830
|
+
// Handler - handles form submission and state updates
|
|
45831
|
+
frontendActionHandlers['display-form'] = async (_input, _state, context) => {
|
|
45832
|
+
return waitForActionState(context.toolCallId);
|
|
45833
|
+
};
|
|
45834
|
+
// Renderer - displays the form card
|
|
45835
|
+
// Rendering is based only on action.input and action.done
|
|
45836
|
+
// When done=true, FormCard shows a simple completion indicator
|
|
45837
|
+
actionRenderers['display-form'] = (message, accentColor, _variant, onActionDismiss) => {
|
|
45838
|
+
const action = message.action;
|
|
45839
|
+
if (!action)
|
|
45840
|
+
return null;
|
|
45841
|
+
const handleComplete = (toolCallId, newState) => {
|
|
45842
|
+
resolveActionState(toolCallId, newState);
|
|
45843
|
+
};
|
|
45844
|
+
const handleDismiss = onActionDismiss
|
|
45845
|
+
? (toolCallId) => onActionDismiss(toolCallId)
|
|
45846
|
+
: undefined;
|
|
45847
|
+
return (jsxRuntimeExports.jsx(FormCard, { action: {
|
|
45848
|
+
implementation: action.implementation,
|
|
45849
|
+
toolCallId: action.toolCallId,
|
|
45850
|
+
actionId: action.actionId,
|
|
45851
|
+
input: action.input,
|
|
45852
|
+
done: action.done ?? false,
|
|
45853
|
+
}, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
|
|
45854
|
+
};
|
|
45855
|
+
}
|
|
45856
|
+
|
|
45857
|
+
/**
|
|
45858
|
+
* Book Contact Appointment Handler
|
|
45859
|
+
* Frontend action handler that waits for action completion
|
|
45860
|
+
*/
|
|
45861
|
+
function registerBookContactAppointmentHandler() {
|
|
45862
|
+
frontendActionHandlers["book-contact-appointment"] = async (_input, _state, context) => {
|
|
45863
|
+
return waitForActionState(context.toolCallId);
|
|
45864
|
+
};
|
|
45865
|
+
}
|
|
45866
|
+
|
|
45867
|
+
/**
|
|
45868
|
+
* Register book-contact-appointment action handler and renderer.
|
|
45869
|
+
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
45870
|
+
*/
|
|
45871
|
+
function registerBookContactAppointmentAction() {
|
|
45872
|
+
// Register the handler
|
|
45873
|
+
registerBookContactAppointmentHandler();
|
|
45874
|
+
// Register the renderer
|
|
45875
|
+
actionRenderers['book-contact-appointment'] = (message, accentColor, _variant, _onActionDismiss, onCallEndpoint) => {
|
|
45306
45876
|
const action = message.action;
|
|
45307
45877
|
if (!action)
|
|
45308
45878
|
return null;
|
|
45309
|
-
// Handle completion - triggers agent to continue with text response
|
|
45310
45879
|
const handleComplete = (toolCallId, newState) => {
|
|
45311
45880
|
resolveActionState(toolCallId, newState);
|
|
45312
45881
|
};
|
|
45313
|
-
//
|
|
45314
|
-
|
|
45315
|
-
const
|
|
45316
|
-
|
|
45317
|
-
|
|
45882
|
+
// Create action-specific endpoint callback
|
|
45883
|
+
// Include toolCallId for done flag enforcement (server rejects calls for completed actions)
|
|
45884
|
+
const handleCallEndpoint = onCallEndpoint
|
|
45885
|
+
? async (endpoint, input, options) => {
|
|
45886
|
+
return onCallEndpoint(action.actionId, endpoint, input, { ...options, toolCallId: action.toolCallId });
|
|
45887
|
+
}
|
|
45888
|
+
: undefined;
|
|
45889
|
+
// Create dismiss handler
|
|
45890
|
+
const handleDismiss = _onActionDismiss
|
|
45891
|
+
? (toolCallId) => _onActionDismiss(toolCallId)
|
|
45892
|
+
: undefined;
|
|
45893
|
+
return (jsxRuntimeExports.jsx(BookContactAppointmentCard, { action: {
|
|
45318
45894
|
implementation: action.implementation,
|
|
45319
45895
|
toolCallId: action.toolCallId,
|
|
45320
45896
|
actionId: action.actionId,
|
|
45321
45897
|
input: action.input,
|
|
45322
|
-
|
|
45323
|
-
|
|
45324
|
-
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
|
|
45898
|
+
done: action.done ?? false,
|
|
45899
|
+
}, onComplete: handleComplete, onDismiss: handleDismiss, onCallEndpoint: handleCallEndpoint, accentColor: accentColor }));
|
|
45325
45900
|
};
|
|
45326
45901
|
}
|
|
45327
45902
|
|
|
45328
|
-
function
|
|
45329
|
-
// Handler -
|
|
45330
|
-
frontendActionHandlers['
|
|
45331
|
-
|
|
45903
|
+
function registerStructuredImageAction() {
|
|
45904
|
+
// Handler - auto-completes immediately, returns body for agent
|
|
45905
|
+
frontendActionHandlers['structured-image'] = async (_input, state, _context) => {
|
|
45906
|
+
const images = state?.images || [];
|
|
45907
|
+
// Return body directly - sent to backend via continueAgentAction
|
|
45908
|
+
return {
|
|
45909
|
+
status: 'displayed',
|
|
45910
|
+
imageCount: images.length,
|
|
45911
|
+
message: `Displayed ${images.length} image${images.length !== 1 ? 's' : ''}.`,
|
|
45912
|
+
};
|
|
45332
45913
|
};
|
|
45333
|
-
// Renderer - displays the
|
|
45334
|
-
actionRenderers['
|
|
45914
|
+
// Renderer - displays the image content
|
|
45915
|
+
actionRenderers['structured-image'] = (message, accentColor, variant, onActionDismiss) => {
|
|
45335
45916
|
const action = message.action;
|
|
45336
45917
|
if (!action)
|
|
45337
45918
|
return null;
|
|
45338
45919
|
const handleComplete = (toolCallId, newState) => {
|
|
45339
45920
|
resolveActionState(toolCallId, newState);
|
|
45340
45921
|
};
|
|
45341
|
-
// Check if action
|
|
45342
|
-
const
|
|
45343
|
-
const status =
|
|
45344
|
-
const isDone = action.done || status === '
|
|
45345
|
-
return (jsxRuntimeExports.jsx(
|
|
45922
|
+
// Check if action input indicates it's already complete
|
|
45923
|
+
const input = action.input;
|
|
45924
|
+
const status = input?.status;
|
|
45925
|
+
const isDone = action.done || status === 'displaying' || status === 'displayed' || status === 'interacted';
|
|
45926
|
+
return (jsxRuntimeExports.jsx(StructuredImageDisplay, { action: {
|
|
45346
45927
|
implementation: action.implementation,
|
|
45347
45928
|
toolCallId: action.toolCallId,
|
|
45348
45929
|
actionId: action.actionId,
|
|
45349
45930
|
input: action.input,
|
|
45350
|
-
state: action.state,
|
|
45351
45931
|
done: isDone,
|
|
45352
|
-
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
45932
|
+
}, onComplete: handleComplete, onDismiss: onActionDismiss ? () => onActionDismiss(action.toolCallId) : undefined, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 2 }));
|
|
45353
45933
|
};
|
|
45354
45934
|
}
|
|
45355
45935
|
|
|
@@ -45365,14 +45945,14 @@
|
|
|
45365
45945
|
return;
|
|
45366
45946
|
initialized = true;
|
|
45367
45947
|
// Explicitly call each registration function to prevent tree-shaking
|
|
45368
|
-
registerGoogleCalendarAction();
|
|
45369
|
-
registerMicrosoftCalendarAction();
|
|
45370
45948
|
registerLinkPreviewAction();
|
|
45371
45949
|
registerVideoPlayerAction();
|
|
45372
45950
|
registerLocationCardAction();
|
|
45373
45951
|
registerQueryContactDirectoryAction();
|
|
45374
45952
|
registerContactCardAction();
|
|
45375
45953
|
registerDisplayFormAction();
|
|
45954
|
+
registerBookContactAppointmentAction();
|
|
45955
|
+
registerStructuredImageAction();
|
|
45376
45956
|
}
|
|
45377
45957
|
|
|
45378
45958
|
/**
|
|
@@ -45635,8 +46215,49 @@
|
|
|
45635
46215
|
};
|
|
45636
46216
|
});
|
|
45637
46217
|
}
|
|
46218
|
+
/**
|
|
46219
|
+
* Clean up messages that were interrupted during streaming.
|
|
46220
|
+
* - Marks streaming messages as complete
|
|
46221
|
+
* - Removes empty assistant messages
|
|
46222
|
+
* - Marks incomplete tool calls as done
|
|
46223
|
+
*/
|
|
46224
|
+
function cleanupInterruptedMessages(messages) {
|
|
46225
|
+
return messages
|
|
46226
|
+
.map((msg) => {
|
|
46227
|
+
// Mark streaming messages as complete
|
|
46228
|
+
if (msg.isStreaming) {
|
|
46229
|
+
msg = { ...msg, isStreaming: false };
|
|
46230
|
+
}
|
|
46231
|
+
// Mark incomplete tool calls as done (they were interrupted)
|
|
46232
|
+
if (msg.message.role === 'tool' && msg.action && !msg.action.done) {
|
|
46233
|
+
msg = {
|
|
46234
|
+
...msg,
|
|
46235
|
+
action: {
|
|
46236
|
+
...msg.action,
|
|
46237
|
+
done: true,
|
|
46238
|
+
// Mark as interrupted so UI can show appropriate state
|
|
46239
|
+
input: {
|
|
46240
|
+
...msg.action.input,
|
|
46241
|
+
_interrupted: true,
|
|
46242
|
+
},
|
|
46243
|
+
},
|
|
46244
|
+
};
|
|
46245
|
+
}
|
|
46246
|
+
return msg;
|
|
46247
|
+
})
|
|
46248
|
+
// Remove empty assistant messages (streaming was interrupted before content)
|
|
46249
|
+
.filter((msg) => {
|
|
46250
|
+
if (msg.message.role === 'assistant') {
|
|
46251
|
+
const content = msg.message.content;
|
|
46252
|
+
return content && typeof content === 'string' && content.trim().length > 0;
|
|
46253
|
+
}
|
|
46254
|
+
return true;
|
|
46255
|
+
});
|
|
46256
|
+
}
|
|
45638
46257
|
function hydrateMessages(messages) {
|
|
45639
|
-
|
|
46258
|
+
const visibleMessages = messages.filter((message) => !message.action?.hidden);
|
|
46259
|
+
const cleanedMessages = cleanupInterruptedMessages(visibleMessages);
|
|
46260
|
+
return hydrateToolNames(cleanedMessages);
|
|
45640
46261
|
}
|
|
45641
46262
|
|
|
45642
46263
|
function deriveErrorInfo(error) {
|
|
@@ -45706,6 +46327,75 @@
|
|
|
45706
46327
|
return { message: 'Something went wrong. Please try again.' };
|
|
45707
46328
|
}
|
|
45708
46329
|
|
|
46330
|
+
/**
|
|
46331
|
+
* Stream Buffer
|
|
46332
|
+
* Smooths out streaming text rendering by buffering words and draining them
|
|
46333
|
+
* with requestAnimationFrame for a fluid typing effect.
|
|
46334
|
+
*/
|
|
46335
|
+
function createStreamBuffer() {
|
|
46336
|
+
return {
|
|
46337
|
+
pendingWords: [],
|
|
46338
|
+
displayedContent: '',
|
|
46339
|
+
streamEnded: false,
|
|
46340
|
+
rafHandle: null,
|
|
46341
|
+
};
|
|
46342
|
+
}
|
|
46343
|
+
function appendToBuffer(buffer, content) {
|
|
46344
|
+
// Split by whitespace while preserving the whitespace characters
|
|
46345
|
+
const words = content.split(/(\s+)/);
|
|
46346
|
+
buffer.pendingWords.push(...words.filter(w => w.length > 0));
|
|
46347
|
+
}
|
|
46348
|
+
function startBufferDrain(buffer, onContentUpdate) {
|
|
46349
|
+
if (buffer.rafHandle !== null) {
|
|
46350
|
+
return; // Already draining
|
|
46351
|
+
}
|
|
46352
|
+
const drainLoop = () => {
|
|
46353
|
+
if (buffer.pendingWords.length === 0) {
|
|
46354
|
+
if (buffer.streamEnded) {
|
|
46355
|
+
buffer.rafHandle = null;
|
|
46356
|
+
return;
|
|
46357
|
+
}
|
|
46358
|
+
// No words to render, wait for more
|
|
46359
|
+
buffer.rafHandle = requestAnimationFrame(drainLoop);
|
|
46360
|
+
return;
|
|
46361
|
+
}
|
|
46362
|
+
// Adaptive: render more words if buffer is filling up
|
|
46363
|
+
const wordsToRender = buffer.pendingWords.length > 20 ? 3 : 1;
|
|
46364
|
+
const chunk = buffer.pendingWords.splice(0, wordsToRender).join('');
|
|
46365
|
+
buffer.displayedContent += chunk;
|
|
46366
|
+
onContentUpdate(buffer.displayedContent);
|
|
46367
|
+
buffer.rafHandle = requestAnimationFrame(drainLoop);
|
|
46368
|
+
};
|
|
46369
|
+
buffer.rafHandle = requestAnimationFrame(drainLoop);
|
|
46370
|
+
}
|
|
46371
|
+
function flushBuffer(buffer) {
|
|
46372
|
+
buffer.streamEnded = true;
|
|
46373
|
+
if (buffer.rafHandle !== null) {
|
|
46374
|
+
cancelAnimationFrame(buffer.rafHandle);
|
|
46375
|
+
buffer.rafHandle = null;
|
|
46376
|
+
}
|
|
46377
|
+
const remaining = buffer.pendingWords.join('');
|
|
46378
|
+
buffer.displayedContent += remaining;
|
|
46379
|
+
buffer.pendingWords = [];
|
|
46380
|
+
return buffer.displayedContent;
|
|
46381
|
+
}
|
|
46382
|
+
function cancelBuffer(buffer) {
|
|
46383
|
+
if (buffer.rafHandle !== null) {
|
|
46384
|
+
cancelAnimationFrame(buffer.rafHandle);
|
|
46385
|
+
buffer.rafHandle = null;
|
|
46386
|
+
}
|
|
46387
|
+
buffer.streamEnded = true;
|
|
46388
|
+
}
|
|
46389
|
+
function resetBuffer(buffer) {
|
|
46390
|
+
if (buffer.rafHandle !== null) {
|
|
46391
|
+
cancelAnimationFrame(buffer.rafHandle);
|
|
46392
|
+
buffer.rafHandle = null;
|
|
46393
|
+
}
|
|
46394
|
+
buffer.pendingWords = [];
|
|
46395
|
+
buffer.displayedContent = '';
|
|
46396
|
+
buffer.streamEnded = false;
|
|
46397
|
+
}
|
|
46398
|
+
|
|
45709
46399
|
function createStreamState() {
|
|
45710
46400
|
return {
|
|
45711
46401
|
currentContent: "",
|
|
@@ -45715,6 +46405,7 @@
|
|
|
45715
46405
|
sources: [],
|
|
45716
46406
|
toolCallToActionId: {},
|
|
45717
46407
|
requestId: generateMessageId(),
|
|
46408
|
+
buffer: createStreamBuffer(),
|
|
45718
46409
|
};
|
|
45719
46410
|
}
|
|
45720
46411
|
function upsertMessage(setState, message, isTyping) {
|
|
@@ -45777,6 +46468,8 @@
|
|
|
45777
46468
|
},
|
|
45778
46469
|
isStreaming: false,
|
|
45779
46470
|
toolExecuting: existingName,
|
|
46471
|
+
// Mark action as done when tool message is finalized
|
|
46472
|
+
action: entry.action ? { ...entry.action, done: true } : undefined,
|
|
45780
46473
|
};
|
|
45781
46474
|
});
|
|
45782
46475
|
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
@@ -45785,26 +46478,34 @@
|
|
|
45785
46478
|
}
|
|
45786
46479
|
|
|
45787
46480
|
function handleContentEvent(event, streamState, onMessageUpdate, setState) {
|
|
46481
|
+
// Track full content for finalization
|
|
45788
46482
|
streamState.currentContent += event.content;
|
|
45789
|
-
|
|
45790
|
-
|
|
45791
|
-
|
|
45792
|
-
|
|
45793
|
-
|
|
45794
|
-
|
|
45795
|
-
|
|
45796
|
-
|
|
45797
|
-
|
|
45798
|
-
|
|
45799
|
-
|
|
45800
|
-
|
|
45801
|
-
|
|
46483
|
+
// Add to buffer for smooth rendering
|
|
46484
|
+
appendToBuffer(streamState.buffer, event.content);
|
|
46485
|
+
// Start drain loop if not already running
|
|
46486
|
+
startBufferDrain(streamState.buffer, (displayedContent) => {
|
|
46487
|
+
const assistantMessage = {
|
|
46488
|
+
id: streamState.currentMessageId,
|
|
46489
|
+
message: { role: "assistant", content: displayedContent },
|
|
46490
|
+
timestamp: new Date().toISOString(),
|
|
46491
|
+
sources: streamState.sources,
|
|
46492
|
+
isStreaming: true,
|
|
46493
|
+
};
|
|
46494
|
+
streamState.newMessageIds.add(assistantMessage.id);
|
|
46495
|
+
onMessageUpdate(assistantMessage);
|
|
46496
|
+
const hasContent = displayedContent.trim().length > 0;
|
|
46497
|
+
const isToolExecuting = streamState.activeToolCallCount > 0;
|
|
46498
|
+
const isTyping = (!hasContent && assistantMessage.isStreaming) || isToolExecuting;
|
|
46499
|
+
upsertMessage(setState, assistantMessage, isTyping);
|
|
46500
|
+
});
|
|
45802
46501
|
}
|
|
45803
46502
|
function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
|
|
45804
|
-
|
|
46503
|
+
// Flush buffer before tool starts
|
|
46504
|
+
const flushedContent = flushBuffer(streamState.buffer);
|
|
46505
|
+
if (flushedContent.trim()) {
|
|
45805
46506
|
const finalAssistant = {
|
|
45806
46507
|
id: streamState.currentMessageId,
|
|
45807
|
-
message: { role: "assistant", content:
|
|
46508
|
+
message: { role: "assistant", content: flushedContent },
|
|
45808
46509
|
timestamp: new Date().toISOString(),
|
|
45809
46510
|
sources: streamState.sources,
|
|
45810
46511
|
isStreaming: false,
|
|
@@ -45815,6 +46516,8 @@
|
|
|
45815
46516
|
streamState.currentContent = "";
|
|
45816
46517
|
streamState.currentMessageId = generateMessageId();
|
|
45817
46518
|
}
|
|
46519
|
+
// Reset buffer for post-tool content
|
|
46520
|
+
resetBuffer(streamState.buffer);
|
|
45818
46521
|
const toolMessageId = event.tool_call_id;
|
|
45819
46522
|
streamState.activeToolCallCount += 1;
|
|
45820
46523
|
streamState.newMessageIds.add(toolMessageId);
|
|
@@ -45832,43 +46535,22 @@
|
|
|
45832
46535
|
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
45833
46536
|
setState(prev => {
|
|
45834
46537
|
const messages = prev.messages.map((msg) => {
|
|
45835
|
-
|
|
45836
|
-
if (!matchesToolCall) {
|
|
46538
|
+
if (msg.message.role !== "tool" || msg.message.tool_call_id !== event.tool_call_id) {
|
|
45837
46539
|
return msg;
|
|
45838
46540
|
}
|
|
45839
|
-
const
|
|
45840
|
-
|
|
45841
|
-
|
|
45842
|
-
|
|
45843
|
-
|
|
45844
|
-
|
|
45845
|
-
|
|
45846
|
-
input: (event.input || {}),
|
|
45847
|
-
state: (event.state || {}),
|
|
45848
|
-
done: event.done,
|
|
45849
|
-
};
|
|
45850
|
-
}
|
|
45851
|
-
else if (action) {
|
|
45852
|
-
action = {
|
|
45853
|
-
...action,
|
|
45854
|
-
input: event.input ? event.input : action.input,
|
|
45855
|
-
state: event.state ? event.state : action.state,
|
|
45856
|
-
done: event.done,
|
|
45857
|
-
};
|
|
45858
|
-
}
|
|
45859
|
-
const updatedMsg = {
|
|
46541
|
+
const toolName = msg.message.name || event.tool_name;
|
|
46542
|
+
// For actions: just mark as done, preserve existing input (display data is immutable)
|
|
46543
|
+
// For non-action tools: update normally
|
|
46544
|
+
const action = msg.action
|
|
46545
|
+
? { ...msg.action, done: event.done }
|
|
46546
|
+
: undefined;
|
|
46547
|
+
return {
|
|
45860
46548
|
...msg,
|
|
45861
|
-
message: {
|
|
45862
|
-
role: "tool",
|
|
45863
|
-
content: event.state ? JSON.stringify(event.state) : (typeof msg.message.content === "string" ? msg.message.content : ""),
|
|
45864
|
-
tool_call_id: event.tool_call_id,
|
|
45865
|
-
name: existingName,
|
|
45866
|
-
},
|
|
46549
|
+
message: { ...msg.message, name: toolName },
|
|
45867
46550
|
isStreaming: false,
|
|
45868
|
-
toolExecuting:
|
|
46551
|
+
toolExecuting: toolName,
|
|
45869
46552
|
action,
|
|
45870
46553
|
};
|
|
45871
|
-
return updatedMsg;
|
|
45872
46554
|
});
|
|
45873
46555
|
return { ...prev, messages, isTyping: true, isLoading: false };
|
|
45874
46556
|
});
|
|
@@ -45901,11 +46583,6 @@
|
|
|
45901
46583
|
return { ...prev, messages, isTyping: true, isLoading: false };
|
|
45902
46584
|
});
|
|
45903
46585
|
}
|
|
45904
|
-
function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
|
|
45905
|
-
streamState.sources = event.sources;
|
|
45906
|
-
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
45907
|
-
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
|
|
45908
|
-
}
|
|
45909
46586
|
function handleHaltEvent(event, _streamState, onMessageUpdate, setState) {
|
|
45910
46587
|
const toolNames = event.tool_calls.map(call => call.name).join(", ");
|
|
45911
46588
|
const notice = toolNames
|
|
@@ -45920,7 +46597,8 @@
|
|
|
45920
46597
|
};
|
|
45921
46598
|
onMessageUpdate(haltMessage);
|
|
45922
46599
|
upsertMessage(setState, haltMessage, false);
|
|
45923
|
-
|
|
46600
|
+
// Stop loading/typing state when halted
|
|
46601
|
+
setState(prev => ({ ...prev, isLoading: false, isTyping: false, error: "Awaiting external tool handling." }));
|
|
45924
46602
|
}
|
|
45925
46603
|
function handleErrorEvent(_event, _streamState, onMessageUpdate, setState) {
|
|
45926
46604
|
const errorMessage = {
|
|
@@ -45932,6 +46610,8 @@
|
|
|
45932
46610
|
};
|
|
45933
46611
|
onMessageUpdate(errorMessage);
|
|
45934
46612
|
upsertMessage(setState, errorMessage, false);
|
|
46613
|
+
// Stop loading/typing state on error
|
|
46614
|
+
setState(prev => ({ ...prev, isLoading: false, isTyping: false }));
|
|
45935
46615
|
}
|
|
45936
46616
|
const eventHandlers = {
|
|
45937
46617
|
content: handleContentEvent,
|
|
@@ -45959,7 +46639,37 @@
|
|
|
45959
46639
|
console.warn('[Chat] Unknown event type:', event.type);
|
|
45960
46640
|
}
|
|
45961
46641
|
}
|
|
46642
|
+
function handleDoneEvent(event, streamState, onMessageUpdate, setState) {
|
|
46643
|
+
// Flush any remaining buffered content
|
|
46644
|
+
const flushedContent = flushBuffer(streamState.buffer);
|
|
46645
|
+
// Update the final message with complete content if there was content
|
|
46646
|
+
if (flushedContent.trim()) {
|
|
46647
|
+
const finalMessage = {
|
|
46648
|
+
id: streamState.currentMessageId,
|
|
46649
|
+
message: { role: "assistant", content: flushedContent },
|
|
46650
|
+
timestamp: new Date().toISOString(),
|
|
46651
|
+
sources: event.sources,
|
|
46652
|
+
isStreaming: false,
|
|
46653
|
+
};
|
|
46654
|
+
streamState.newMessageIds.add(finalMessage.id);
|
|
46655
|
+
onMessageUpdate(finalMessage);
|
|
46656
|
+
upsertMessage(setState, finalMessage, false);
|
|
46657
|
+
}
|
|
46658
|
+
streamState.sources = event.sources;
|
|
46659
|
+
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
46660
|
+
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
|
|
46661
|
+
}
|
|
45962
46662
|
|
|
46663
|
+
/**
|
|
46664
|
+
* Handle the action loop for halting actions.
|
|
46665
|
+
*
|
|
46666
|
+
* Flow:
|
|
46667
|
+
* 1. Display the action in UI
|
|
46668
|
+
* 2. Call the frontend handler (which waits for user interaction or returns immediately for display actions)
|
|
46669
|
+
* 3. Handler returns body when complete
|
|
46670
|
+
* 4. Send body to backend via continueAgentAction
|
|
46671
|
+
* 5. Process any subsequent events (may include new action_request for chained actions)
|
|
46672
|
+
*/
|
|
45963
46673
|
async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
|
|
45964
46674
|
let pendingEvent = initialEvent;
|
|
45965
46675
|
while (pendingEvent) {
|
|
@@ -45985,7 +46695,6 @@
|
|
|
45985
46695
|
toolCallId: pendingEvent.tool_call_id,
|
|
45986
46696
|
actionId: pendingEvent.action_id,
|
|
45987
46697
|
input: pendingEvent.input,
|
|
45988
|
-
state: pendingEvent.state,
|
|
45989
46698
|
done: pendingEvent.done ?? false,
|
|
45990
46699
|
},
|
|
45991
46700
|
};
|
|
@@ -46010,9 +46719,13 @@
|
|
|
46010
46719
|
upsertMessage(setState, errorMessage, false);
|
|
46011
46720
|
return;
|
|
46012
46721
|
}
|
|
46013
|
-
|
|
46722
|
+
// Handler returns body when complete (for display actions this is immediate,
|
|
46723
|
+
// for interactive actions this waits for user completion)
|
|
46724
|
+
// Note: For halting actions, input contains the transformed data from getInitialClientState
|
|
46725
|
+
let body;
|
|
46014
46726
|
try {
|
|
46015
|
-
|
|
46727
|
+
body = await handler(pendingEvent.input, pendingEvent.input, // Input now contains the display data for halting actions
|
|
46728
|
+
{
|
|
46016
46729
|
widgetId,
|
|
46017
46730
|
conversationId,
|
|
46018
46731
|
toolCallId: pendingEvent.tool_call_id,
|
|
@@ -46034,19 +46747,16 @@
|
|
|
46034
46747
|
return;
|
|
46035
46748
|
}
|
|
46036
46749
|
pendingEvent = null;
|
|
46037
|
-
|
|
46038
|
-
|
|
46039
|
-
action: toolMessage.action ? { ...toolMessage.action, state: nextState } : toolMessage.action,
|
|
46040
|
-
};
|
|
46041
|
-
upsertMessage(setState, updatedToolMessage, true);
|
|
46750
|
+
// Send body to backend and continue agent
|
|
46751
|
+
// No need to update message - input is immutable and already contains display data
|
|
46042
46752
|
let streamEnded = false;
|
|
46043
|
-
for await (const event of client.
|
|
46753
|
+
for await (const event of client.continueAgentAction(conversationId, resumeToolCallId, body)) {
|
|
46044
46754
|
if (event.type === "action_request") {
|
|
46755
|
+
// Chained action - continue the loop
|
|
46045
46756
|
pendingEvent = event;
|
|
46046
46757
|
break;
|
|
46047
46758
|
}
|
|
46048
46759
|
if (event.type === "done") {
|
|
46049
|
-
// Finalize tool message and stream messages
|
|
46050
46760
|
finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
|
|
46051
46761
|
streamState.sources = event.sources;
|
|
46052
46762
|
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
@@ -46076,57 +46786,118 @@
|
|
|
46076
46786
|
}
|
|
46077
46787
|
}
|
|
46078
46788
|
}
|
|
46079
|
-
|
|
46789
|
+
/**
|
|
46790
|
+
* Setup resume callbacks for incomplete actions after page reload.
|
|
46791
|
+
*
|
|
46792
|
+
* When a page reloads with an incomplete action, this sets up callbacks
|
|
46793
|
+
* so when the user completes the action, we can continue the agent flow.
|
|
46794
|
+
*/
|
|
46795
|
+
function setupActionResumeCallbacks(messages, client, conversationId, widgetId, setState, onMessageUpdate, createStreamState, registerCallback) {
|
|
46080
46796
|
// Find all incomplete actions and register resume callbacks
|
|
46081
46797
|
for (const message of messages) {
|
|
46082
|
-
if (message.action && !message.action.done) {
|
|
46083
|
-
const
|
|
46084
|
-
const
|
|
46085
|
-
registerCallback(
|
|
46086
|
-
// When user
|
|
46798
|
+
if (message.action && !message.action.done && !message.action.hidden) {
|
|
46799
|
+
const initialToolCallId = message.action.toolCallId;
|
|
46800
|
+
const initialToolName = message.message.name || message.toolExecuting || "tool";
|
|
46801
|
+
registerCallback(initialToolCallId, async (body) => {
|
|
46802
|
+
// When user completes the action after reload, continue the stream
|
|
46087
46803
|
try {
|
|
46088
|
-
// Update the action message with the new state and check completion
|
|
46089
46804
|
setState(prev => ({
|
|
46090
46805
|
...prev,
|
|
46091
|
-
messages: prev.messages.map(m => {
|
|
46092
|
-
if (m.action?.toolCallId !== toolCallId) {
|
|
46093
|
-
return m;
|
|
46094
|
-
}
|
|
46095
|
-
if (!m.action) {
|
|
46096
|
-
return m;
|
|
46097
|
-
}
|
|
46098
|
-
return { ...m, action: { ...m.action, state: newState } };
|
|
46099
|
-
}),
|
|
46100
46806
|
isTyping: true,
|
|
46101
46807
|
}));
|
|
46102
46808
|
const streamState = createStreamState();
|
|
46103
|
-
|
|
46104
|
-
|
|
46105
|
-
|
|
46106
|
-
|
|
46107
|
-
|
|
46108
|
-
|
|
46109
|
-
|
|
46110
|
-
|
|
46809
|
+
let currentToolCallId = initialToolCallId;
|
|
46810
|
+
let currentToolName = initialToolName;
|
|
46811
|
+
let currentBody = body;
|
|
46812
|
+
// Loop to handle chained action_requests
|
|
46813
|
+
while (true) {
|
|
46814
|
+
let nextActionRequest = null;
|
|
46815
|
+
// Continue the agent with the body
|
|
46816
|
+
for await (const event of client.continueAgentAction(conversationId, currentToolCallId, currentBody)) {
|
|
46817
|
+
if (event.type === "action_request") {
|
|
46818
|
+
// Chained action - need to handle the new action request
|
|
46819
|
+
nextActionRequest = event;
|
|
46820
|
+
break;
|
|
46821
|
+
}
|
|
46822
|
+
if (event.type === "done") {
|
|
46823
|
+
finalizeToolMessage(streamState, setState, currentToolCallId, currentToolName);
|
|
46824
|
+
streamState.sources = event.sources;
|
|
46825
|
+
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
46826
|
+
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
|
|
46827
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
46828
|
+
return;
|
|
46829
|
+
}
|
|
46830
|
+
if (event.type === "error") {
|
|
46831
|
+
const errorMessage = {
|
|
46832
|
+
id: generateMessageId(),
|
|
46833
|
+
message: {
|
|
46834
|
+
role: "assistant",
|
|
46835
|
+
content: "Sorry, an error occurred. Please try again later.",
|
|
46836
|
+
},
|
|
46837
|
+
timestamp: new Date().toISOString(),
|
|
46838
|
+
sources: [],
|
|
46839
|
+
isError: true,
|
|
46840
|
+
};
|
|
46841
|
+
upsertMessage(setState, errorMessage, false);
|
|
46842
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
46843
|
+
return;
|
|
46844
|
+
}
|
|
46845
|
+
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
46846
|
+
}
|
|
46847
|
+
// If no action_request, stream ended normally
|
|
46848
|
+
if (!nextActionRequest) {
|
|
46849
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
46850
|
+
return;
|
|
46111
46851
|
}
|
|
46112
|
-
|
|
46113
|
-
|
|
46114
|
-
|
|
46115
|
-
|
|
46116
|
-
|
|
46117
|
-
|
|
46118
|
-
|
|
46119
|
-
|
|
46120
|
-
|
|
46121
|
-
|
|
46122
|
-
|
|
46123
|
-
|
|
46852
|
+
// Update UI with new action for the chained action
|
|
46853
|
+
const toolMessage = {
|
|
46854
|
+
id: nextActionRequest.tool_call_id,
|
|
46855
|
+
sources: [],
|
|
46856
|
+
message: {
|
|
46857
|
+
role: "tool",
|
|
46858
|
+
content: "",
|
|
46859
|
+
tool_call_id: nextActionRequest.tool_call_id,
|
|
46860
|
+
name: currentToolName,
|
|
46861
|
+
},
|
|
46862
|
+
timestamp: new Date().toISOString(),
|
|
46863
|
+
isStreaming: true,
|
|
46864
|
+
toolExecuting: currentToolName,
|
|
46865
|
+
action: {
|
|
46866
|
+
implementation: nextActionRequest.implementation,
|
|
46867
|
+
toolCallId: nextActionRequest.tool_call_id,
|
|
46868
|
+
actionId: nextActionRequest.action_id,
|
|
46869
|
+
input: nextActionRequest.input,
|
|
46870
|
+
done: nextActionRequest.done ?? false,
|
|
46871
|
+
},
|
|
46872
|
+
};
|
|
46873
|
+
upsertMessage(setState, toolMessage, true);
|
|
46874
|
+
// Wait for user to complete the chained action
|
|
46875
|
+
const handler = getFrontendActionHandler(nextActionRequest.implementation);
|
|
46876
|
+
if (!handler) {
|
|
46877
|
+
console.error("[Action Resume] No handler for implementation:", nextActionRequest.implementation);
|
|
46878
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
46879
|
+
return;
|
|
46880
|
+
}
|
|
46881
|
+
let handlerResult;
|
|
46882
|
+
try {
|
|
46883
|
+
handlerResult = await handler(nextActionRequest.input, nextActionRequest.input, // Input contains display data for halting actions
|
|
46884
|
+
{
|
|
46885
|
+
widgetId,
|
|
46886
|
+
conversationId,
|
|
46887
|
+
toolCallId: nextActionRequest.tool_call_id,
|
|
46888
|
+
actionId: nextActionRequest.action_id,
|
|
46889
|
+
implementation: nextActionRequest.implementation,
|
|
46890
|
+
});
|
|
46891
|
+
}
|
|
46892
|
+
catch (handlerError) {
|
|
46893
|
+
console.error("[Action Resume] Handler failed:", handlerError);
|
|
46124
46894
|
setState(prev => ({ ...prev, isTyping: false }));
|
|
46125
46895
|
return;
|
|
46126
46896
|
}
|
|
46127
|
-
|
|
46897
|
+
// Continue loop with new body
|
|
46898
|
+
currentToolCallId = nextActionRequest.tool_call_id;
|
|
46899
|
+
currentBody = handlerResult;
|
|
46128
46900
|
}
|
|
46129
|
-
setState(prev => ({ ...prev, isTyping: false }));
|
|
46130
46901
|
}
|
|
46131
46902
|
catch (error) {
|
|
46132
46903
|
console.error("[Action Resume] Failed to continue stream:", error);
|
|
@@ -46205,7 +46976,7 @@
|
|
|
46205
46976
|
}));
|
|
46206
46977
|
// Setup resume callbacks for incomplete actions
|
|
46207
46978
|
if (conversationId) {
|
|
46208
|
-
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
|
|
46979
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, widgetId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
|
|
46209
46980
|
}
|
|
46210
46981
|
}
|
|
46211
46982
|
catch (error) {
|
|
@@ -46228,7 +46999,7 @@
|
|
|
46228
46999
|
}
|
|
46229
47000
|
});
|
|
46230
47001
|
};
|
|
46231
|
-
}, [widgetId, apiUrl, onError]);
|
|
47002
|
+
}, [widgetId, apiUrl, onError, skipInitialization]);
|
|
46232
47003
|
// Save conversation when messages change
|
|
46233
47004
|
reactExports.useEffect(() => {
|
|
46234
47005
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
@@ -46239,6 +47010,21 @@
|
|
|
46239
47010
|
saveConversation(widgetId, state.conversationId, state.messages);
|
|
46240
47011
|
}
|
|
46241
47012
|
}, [widgetId, state.messages, state.conversationId, state.config?.settings.persistConversation]);
|
|
47013
|
+
// Save conversation on page unload to preserve streaming state
|
|
47014
|
+
reactExports.useEffect(() => {
|
|
47015
|
+
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
47016
|
+
if (!persistConversation || !isStorageAvailable())
|
|
47017
|
+
return;
|
|
47018
|
+
const handleBeforeUnload = () => {
|
|
47019
|
+
const currentState = stateRef.current;
|
|
47020
|
+
if (currentState.messages.length > 0 && currentState.conversationId) {
|
|
47021
|
+
// Force save current state before page closes
|
|
47022
|
+
saveConversation(widgetId, currentState.conversationId, currentState.messages);
|
|
47023
|
+
}
|
|
47024
|
+
};
|
|
47025
|
+
window.addEventListener('beforeunload', handleBeforeUnload);
|
|
47026
|
+
return () => window.removeEventListener('beforeunload', handleBeforeUnload);
|
|
47027
|
+
}, [widgetId, state.config?.settings.persistConversation]);
|
|
46242
47028
|
const sendMessage = reactExports.useCallback(async (content, files) => {
|
|
46243
47029
|
const trimmedContent = content.trim();
|
|
46244
47030
|
const hasFiles = !!files && files.length > 0;
|
|
@@ -46322,12 +47108,14 @@
|
|
|
46322
47108
|
stateRef.current.conversationId !== streamConversationId ||
|
|
46323
47109
|
currentRequestIdRef.current !== streamRequestId) {
|
|
46324
47110
|
console.log('[Widget] Stream aborted, conversation changed, or superseded by new request');
|
|
47111
|
+
cancelBuffer(streamState.buffer);
|
|
46325
47112
|
break;
|
|
46326
47113
|
}
|
|
46327
47114
|
if (event.type === "action_request") {
|
|
46328
47115
|
if (currentAbortController?.signal.aborted ||
|
|
46329
47116
|
stateRef.current.conversationId !== streamConversationId ||
|
|
46330
47117
|
currentRequestIdRef.current !== streamRequestId) {
|
|
47118
|
+
cancelBuffer(streamState.buffer);
|
|
46331
47119
|
break;
|
|
46332
47120
|
}
|
|
46333
47121
|
await handleActionLoop(apiClient.current, event, streamState, (message) => {
|
|
@@ -46353,26 +47141,8 @@
|
|
|
46353
47141
|
if (lastStreamedMessage) {
|
|
46354
47142
|
onMessage?.(lastStreamedMessage);
|
|
46355
47143
|
}
|
|
46356
|
-
|
|
46357
|
-
|
|
46358
|
-
if (enableFollowUps) {
|
|
46359
|
-
apiClient.current.generateFollowUps(stateRef.current.messages, actionIds)
|
|
46360
|
-
.then(suggestions => {
|
|
46361
|
-
if (suggestions.length > 0) {
|
|
46362
|
-
setState(prev => {
|
|
46363
|
-
const messages = [...prev.messages];
|
|
46364
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
46365
|
-
if (messages[i].message.role === 'assistant' && !messages[i].isError) {
|
|
46366
|
-
messages[i] = { ...messages[i], suggestions };
|
|
46367
|
-
break;
|
|
46368
|
-
}
|
|
46369
|
-
}
|
|
46370
|
-
return { ...prev, messages };
|
|
46371
|
-
});
|
|
46372
|
-
}
|
|
46373
|
-
})
|
|
46374
|
-
.catch(err => console.warn('[Widget] Follow-up generation failed:', err));
|
|
46375
|
-
}
|
|
47144
|
+
// Follow-up suggestions are now generated server-side in parallel and included in the done event
|
|
47145
|
+
// They are automatically attached to the last assistant message by finalizeStreamMessages()
|
|
46376
47146
|
}
|
|
46377
47147
|
catch (error) {
|
|
46378
47148
|
console.error("[Widget] sendMessage error:", error);
|
|
@@ -46434,6 +47204,51 @@
|
|
|
46434
47204
|
onError?.(err);
|
|
46435
47205
|
}
|
|
46436
47206
|
}, [state.conversationId, onError]);
|
|
47207
|
+
const dismissAction = reactExports.useCallback(async (toolCallId) => {
|
|
47208
|
+
if (!toolCallId)
|
|
47209
|
+
return;
|
|
47210
|
+
const dismissedAt = new Date().toISOString();
|
|
47211
|
+
setState(prev => ({
|
|
47212
|
+
...prev,
|
|
47213
|
+
messages: prev.messages.map((message) => {
|
|
47214
|
+
if (message.action?.toolCallId !== toolCallId) {
|
|
47215
|
+
return message;
|
|
47216
|
+
}
|
|
47217
|
+
if (!message.action) {
|
|
47218
|
+
return message;
|
|
47219
|
+
}
|
|
47220
|
+
return {
|
|
47221
|
+
...message,
|
|
47222
|
+
action: {
|
|
47223
|
+
...message.action,
|
|
47224
|
+
hidden: true,
|
|
47225
|
+
dismissedAt,
|
|
47226
|
+
dismissedBy: "user",
|
|
47227
|
+
done: true,
|
|
47228
|
+
},
|
|
47229
|
+
};
|
|
47230
|
+
}),
|
|
47231
|
+
isTyping: true,
|
|
47232
|
+
isLoading: false,
|
|
47233
|
+
}));
|
|
47234
|
+
unregisterActionResumeCallback(toolCallId);
|
|
47235
|
+
const conversationId = stateRef.current.conversationId;
|
|
47236
|
+
if (!conversationId) {
|
|
47237
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
47238
|
+
return;
|
|
47239
|
+
}
|
|
47240
|
+
try {
|
|
47241
|
+
const streamState = createStreamState();
|
|
47242
|
+
for await (const event of apiClient.current.dismissAgentMessageStream(conversationId, toolCallId)) {
|
|
47243
|
+
handleStreamEvent(event, streamState, onMessage ?? (() => { }), setState);
|
|
47244
|
+
}
|
|
47245
|
+
setState(prev => ({ ...prev, isTyping: false, isLoading: false }));
|
|
47246
|
+
}
|
|
47247
|
+
catch (error) {
|
|
47248
|
+
console.error("[Widget] dismissAction error:", error);
|
|
47249
|
+
setState(prev => ({ ...prev, isTyping: false, isLoading: false }));
|
|
47250
|
+
}
|
|
47251
|
+
}, [onMessage]);
|
|
46437
47252
|
const loadConversations = reactExports.useCallback(() => {
|
|
46438
47253
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
46439
47254
|
if (!persistConversation || !isStorageAvailable()) {
|
|
@@ -46484,7 +47299,7 @@
|
|
|
46484
47299
|
messages: hydratedMessages,
|
|
46485
47300
|
isLoading: false,
|
|
46486
47301
|
}));
|
|
46487
|
-
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
|
|
47302
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, widgetId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
|
|
46488
47303
|
if (persistConversation && isStorageAvailable()) {
|
|
46489
47304
|
saveConversation(widgetId, conversation.id, hydratedMessages);
|
|
46490
47305
|
}
|
|
@@ -46534,6 +47349,53 @@
|
|
|
46534
47349
|
}));
|
|
46535
47350
|
}
|
|
46536
47351
|
}, [widgetId, state.config?.settings.persistConversation, state.conversationId]);
|
|
47352
|
+
const createDemoConversation = reactExports.useCallback(async (userMessage, assistantMessage) => {
|
|
47353
|
+
try {
|
|
47354
|
+
const result = await apiClient.current.createDemoConversation(userMessage, assistantMessage);
|
|
47355
|
+
if (result.success && result.id) {
|
|
47356
|
+
// Update state with the new conversation ID
|
|
47357
|
+
setState(prev => ({
|
|
47358
|
+
...prev,
|
|
47359
|
+
conversationId: result.id,
|
|
47360
|
+
}));
|
|
47361
|
+
// Save to local storage if persistence is enabled
|
|
47362
|
+
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
47363
|
+
if (persistConversation && isStorageAvailable()) {
|
|
47364
|
+
const demoMessages = [
|
|
47365
|
+
{
|
|
47366
|
+
id: generateMessageId(),
|
|
47367
|
+
message: { role: 'user', content: userMessage },
|
|
47368
|
+
timestamp: new Date().toISOString(),
|
|
47369
|
+
sources: [],
|
|
47370
|
+
},
|
|
47371
|
+
{
|
|
47372
|
+
id: generateMessageId(),
|
|
47373
|
+
message: { role: 'assistant', content: assistantMessage },
|
|
47374
|
+
timestamp: new Date(Date.now() + 1000).toISOString(),
|
|
47375
|
+
sources: [],
|
|
47376
|
+
},
|
|
47377
|
+
];
|
|
47378
|
+
saveConversation(widgetId, result.id, demoMessages);
|
|
47379
|
+
}
|
|
47380
|
+
return result.id;
|
|
47381
|
+
}
|
|
47382
|
+
return null;
|
|
47383
|
+
}
|
|
47384
|
+
catch (error) {
|
|
47385
|
+
console.error('[useChat] Failed to create demo conversation:', error);
|
|
47386
|
+
return null;
|
|
47387
|
+
}
|
|
47388
|
+
}, [widgetId, state.config?.settings.persistConversation]);
|
|
47389
|
+
// Call an action endpoint directly (frontend-owned flow)
|
|
47390
|
+
// Auto-injects conversationId and toolCallId for done flag enforcement
|
|
47391
|
+
const callActionEndpoint = reactExports.useCallback(async (actionId, endpoint, input, options) => {
|
|
47392
|
+
const enrichedInput = {
|
|
47393
|
+
...input,
|
|
47394
|
+
conversationId: state.conversationId,
|
|
47395
|
+
toolCallId: options?.toolCallId,
|
|
47396
|
+
};
|
|
47397
|
+
return apiClient.current.callActionEndpoint(actionId, endpoint, enrichedInput, options?.token);
|
|
47398
|
+
}, [state.conversationId]);
|
|
46537
47399
|
return {
|
|
46538
47400
|
messages: state.messages,
|
|
46539
47401
|
isLoading: state.isLoading,
|
|
@@ -46544,20 +47406,22 @@
|
|
|
46544
47406
|
sendMessage,
|
|
46545
47407
|
clearMessages,
|
|
46546
47408
|
submitFeedback,
|
|
47409
|
+
dismissAction,
|
|
46547
47410
|
conversations,
|
|
46548
47411
|
loadConversations,
|
|
46549
47412
|
switchConversation,
|
|
46550
47413
|
startNewConversation,
|
|
46551
47414
|
deleteConversation: deleteConversation$1,
|
|
47415
|
+
createDemoConversation,
|
|
47416
|
+
callActionEndpoint,
|
|
46552
47417
|
};
|
|
46553
47418
|
}
|
|
46554
47419
|
|
|
46555
|
-
const ShieldIcon = () => (jsxRuntimeExports.jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }), jsxRuntimeExports.jsx("path", { d: "M9 12l2 2 4-4" })] }));
|
|
46556
47420
|
const DataPolicyView = ({ config, widgetName, }) => {
|
|
46557
47421
|
const headerTitle = widgetName || config?.appearance?.headerTitle || 'AI Assistant';
|
|
46558
47422
|
const hasFileUpload = config?.settings?.enableFileUpload ?? false;
|
|
46559
47423
|
const persistsConversation = config?.settings?.persistConversation ?? true;
|
|
46560
|
-
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-data-policy-view", children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-content", children: [jsxRuntimeExports.
|
|
47424
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-data-policy-view", children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-content", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-data-policy-intro", children: jsxRuntimeExports.jsxs("p", { children: ["This privacy notice informs you pursuant to Art. 13 GDPR about how ", jsxRuntimeExports.jsx("strong", { children: headerTitle }), " processes data when you use this chat. Please note that the specific scope of processing depends on the operator of this website/application (the controller) and on the respective activated functions."] }) }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Controller / Contact" }), jsxRuntimeExports.jsx("p", { children: "The controller within the meaning of Art. 4 No. 7 GDPR is the operator of this website/application. The contact details (and, if applicable, the contact details of a data protection officer) can be found in the privacy policy or in the legal notice of the website into which this chat widget is embedded." })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Processed Data" }), jsxRuntimeExports.jsxs("p", { children: ["The chat processes the following categories of data. ", jsxRuntimeExports.jsx("strong", { children: "Chat Content" }), " comprises messages (text) and, if applicable, context information that you provide in the chat. This content is processed to generate responses and provide the conversation."] }), hasFileUpload && (jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Uploaded Files" }), " that you transmit to the chat are processed to handle your request. Processing may include extracting text or information."] })), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Technical Usage Data" }), " includes timestamps, session or request information, as well as technical metadata required for operation, security (abuse prevention), and error analysis."] }), jsxRuntimeExports.jsx("p", { children: "Please do not enter special categories of personal data (e.g., health data), passwords, credit card or bank data, or confidential business secrets in the chat. AI-generated responses may be inaccurate and should be checked independently before use." })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Purposes and Legal Bases" }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Provision of the chat and answering of inquiries" }), " is based on Art. 6 Para. 1 lit. b GDPR, insofar as contractual or pre-contractual measures apply; otherwise on Art. 6 Para. 1 lit. f GDPR (legitimate interest in efficient communication and support)."] }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Quality assurance, operation and security" }), " are based on Art. 6 Para. 1 lit. f GDPR, for example for stability, abuse detection, and troubleshooting."] }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Consent-based processing" }), " may occur if the operator provides for this (Art. 6 Para. 1 lit. a GDPR)."] })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Recipients and Processors" }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Hosting/IT Service Providers" }), " may be used by the operator for hosting, logging, monitoring, and infrastructure."] }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "AI Service Providers" }), " may receive chat content to generate responses. Where required, this is done on the basis of a data processing agreement (Art. 28 GDPR)."] }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Third-Country Transfer" }), " may occur if recipients are located outside the EU/EEA. In this case, appropriate safeguards (e.g., EU Standard Contractual Clauses) are used where required."] })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Retention Period" }), persistsConversation ? (jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Chat History" }), " may be stored to continue the conversation across multiple sessions."] })) : (jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Chat History" }), " is not permanently stored and ends when the chat is closed."] })), hasFileUpload && (jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Files" }), " are processed only as long as necessary to handle the request and are then deleted, unless longer retention is legally required."] })), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Technical Logs" }), " may be stored for a limited period to ensure secure operation."] })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Your Rights (Data Subject Rights)" }), jsxRuntimeExports.jsx("p", { children: "You have the following rights under the GDPR: Right to Information (Art. 15), Right to Rectification (Art. 16), Right to Erasure (Art. 17) and Restriction of Processing (Art. 18), Right to Data Portability (Art. 20), Right to Objection to processing based on legitimate interests (Art. 21), and Right to Complain to a supervisory authority (Art. 77)." }), jsxRuntimeExports.jsx("p", { children: "Note: Without clear identification features, the operator may not be able to assign individual chat histories to a person. For inquiries, please contact the operator of this website/application." })] })] }) }));
|
|
46561
47425
|
};
|
|
46562
47426
|
|
|
46563
47427
|
const MenuIcon = () => (jsxRuntimeExports.jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "4", y1: "10", x2: "20", y2: "10" }), jsxRuntimeExports.jsx("line", { x1: "10", y1: "14", x2: "20", y2: "14" })] }));
|
|
@@ -46565,17 +47429,19 @@
|
|
|
46565
47429
|
const TrashIcon = () => (jsxRuntimeExports.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M3 6h18" }), jsxRuntimeExports.jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }), jsxRuntimeExports.jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })] }));
|
|
46566
47430
|
const CloseIcon = () => (jsxRuntimeExports.jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsxRuntimeExports.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }));
|
|
46567
47431
|
const BackIcon = () => (jsxRuntimeExports.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M19 12H5" }), jsxRuntimeExports.jsx("path", { d: "M12 19l-7-7 7-7" })] }));
|
|
46568
|
-
const ChatWindow = ({ messages, isLoading, isTyping, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick,
|
|
47432
|
+
const ChatWindow = ({ messages, isLoading, isTyping, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick, onActionDismiss, onCallEndpoint,
|
|
46569
47433
|
// Chat history props (only active when persistConversation is true)
|
|
46570
47434
|
conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
|
|
46571
47435
|
// Override props for live preview
|
|
46572
|
-
headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride,
|
|
47436
|
+
sizeOverride, headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride,
|
|
47437
|
+
// Demo mode
|
|
47438
|
+
onInputFocus, }) => {
|
|
46573
47439
|
const appearance = config?.appearance;
|
|
46574
47440
|
const settings = config?.settings;
|
|
46575
47441
|
// Check if chat history should be shown (requires both persistConversation AND showChatHistory)
|
|
46576
47442
|
const canShowHistory = (settings?.persistConversation ?? true) && (settings?.showChatHistory ?? true);
|
|
46577
47443
|
// Apply overrides for live preview (overrides take priority over saved config)
|
|
46578
|
-
const size = appearance?.size
|
|
47444
|
+
const size = sizeOverride ?? appearance?.size ?? 'medium';
|
|
46579
47445
|
const headerTitle = headerTitleOverride ?? appearance?.headerTitle ?? 'AI Assistant';
|
|
46580
47446
|
const welcomeTitle = welcomeTitleOverride ?? appearance?.welcomeTitle ?? '';
|
|
46581
47447
|
const welcomeMessage = welcomeMessageOverride ?? appearance?.welcomeMessage ?? '';
|
|
@@ -46647,12 +47513,12 @@
|
|
|
46647
47513
|
// The backend will detect and trigger the action based on the message
|
|
46648
47514
|
onSendMessage(question);
|
|
46649
47515
|
};
|
|
46650
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsxRuntimeExports.jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''} ${showDataPolicy ? 'is-data-policy' : ''}`, children: showDataPolicy ? (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("button", { className: "ai-chat-header-button", onClick: handleDataPolicyBack, "aria-label": "Back to chat", children: jsxRuntimeExports.jsx(BackIcon, {}) }), jsxRuntimeExports.jsx("div", { className: "ai-chat-title", children: "
|
|
47516
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsxRuntimeExports.jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''} ${showDataPolicy ? 'is-data-policy' : ''}`, children: showDataPolicy ? (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("button", { className: "ai-chat-header-button", onClick: handleDataPolicyBack, "aria-label": "Back to chat", children: jsxRuntimeExports.jsx(BackIcon, {}) }), jsxRuntimeExports.jsx("div", { className: "ai-chat-title", children: "Privacy Notice" })] })) : showHistory ? (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-title", children: headerTitle }), jsxRuntimeExports.jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsxRuntimeExports.jsx(PlusIcon, {}) })] })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsxRuntimeExports.jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsxRuntimeExports.jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-header-actions", children: [canShowHistory && (jsxRuntimeExports.jsx("button", { className: "ai-chat-header-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsxRuntimeExports.jsx(MenuIcon, {}) })), jsxRuntimeExports.jsx("button", { className: "ai-chat-close-button header-close-button", onClick: _onClose, "aria-label": "Close chat", children: jsxRuntimeExports.jsx(CloseIcon, {}) })] })] })) }), showDataPolicy ? (jsxRuntimeExports.jsx(DataPolicyView, { config: config, onBack: handleDataPolicyBack, widgetName: headerTitle })) : showHistory ? (
|
|
46651
47517
|
/* History Panel */
|
|
46652
47518
|
jsxRuntimeExports.jsxs("div", { className: "ai-chat-history-panel", children: [conversations.length === 0 ? (jsxRuntimeExports.jsx("div", { className: "ai-chat-history-empty", children: "No previous conversations" })) : (jsxRuntimeExports.jsx("div", { className: `ai-chat-history-list ${isHistoryExiting ? 'exiting' : ''}`, children: conversations.map((conv) => (jsxRuntimeExports.jsx("div", { className: `ai-chat-history-item ${conv.id === currentConversationId ? 'active' : ''}`, onClick: () => handleSelectConversation(conv.id), children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-history-item-content", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-history-item-preview", children: conv.preview }), onDeleteConversation && (jsxRuntimeExports.jsx("button", { className: "ai-chat-history-item-delete", onClick: (e) => {
|
|
46653
47519
|
e.stopPropagation();
|
|
46654
47520
|
onDeleteConversation(conv.id);
|
|
46655
|
-
}, "aria-label": "Delete conversation", children: jsxRuntimeExports.jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsxRuntimeExports.jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick })] })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsxRuntimeExports.jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), (() => {
|
|
47521
|
+
}, "aria-label": "Delete conversation", children: jsxRuntimeExports.jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsxRuntimeExports.jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick, onInputFocus: onInputFocus })] })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsxRuntimeExports.jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), (() => {
|
|
46656
47522
|
console.log('[DEBUG ChatWindow] Rendering MessageList with', messages.length, 'messages');
|
|
46657
47523
|
messages.forEach((m, i) => {
|
|
46658
47524
|
console.log(`[DEBUG ChatWindow] msg ${i}:`, { role: m.message.role, hasAction: !!m.action, impl: m.action?.implementation });
|
|
@@ -46662,7 +47528,15 @@
|
|
|
46662
47528
|
console.log('[DEBUG ChatWindow] Testing renderer for query-contact-directory:', !!getActionRenderer('query-contact-directory'));
|
|
46663
47529
|
}
|
|
46664
47530
|
return null;
|
|
46665
|
-
})(), jsxRuntimeExports.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 }), jsxRuntimeExports.jsx(ScrollButton, { onClick: () => scrollToBottom?.(), visible: showScrollButton }), jsxRuntimeExports.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 })] }))] }));
|
|
47531
|
+
})(), jsxRuntimeExports.jsx(MessageList, { messages: messages, isTyping: isTyping, showTypingIndicator: settings?.showTypingIndicator, showTimestamps: settings?.showTimestamps, showToolCalls: settings?.showToolCalls, enableFeedback: settings?.enableFeedback, welcomeTitle: welcomeTitle || 'Welcome Message', welcomeMessage: welcomeMessage, suggestedQuestions: suggestedQuestionsOverride ?? settings?.suggestedQuestions, accentColor: appearance?.primaryColor, onSuggestedQuestionClick: handleQuestionClick, onActionClick: onActionClick, onActionDismiss: onActionDismiss, onFeedback: onFeedback, onScrollStateChange: handleScrollStateChange, getActionRenderer: getActionRenderer, onCallEndpoint: onCallEndpoint }), settings?.showDataPolicy && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-page-disclaimer", children: [jsxRuntimeExports.jsx("span", { children: "AI-generated responses may be inaccurate." }), jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-page-disclaimer-link", onClick: handleDataPolicyClick, children: "Privacy Notice" })] })), jsxRuntimeExports.jsx(ScrollButton, { onClick: () => scrollToBottom?.(), visible: showScrollButton }), jsxRuntimeExports.jsx(MessageInput, { onSend: onSendMessage, placeholder: isLimitReached ? 'Message limit reached' : (isTyping ? 'Waiting for response...' : inputPlaceholder), disabled: isLoading || isTyping || isLimitReached, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick, onInputFocus: onInputFocus })] }))] }));
|
|
47532
|
+
};
|
|
47533
|
+
|
|
47534
|
+
const MessageCircleIcon = () => (jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.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" }) }));
|
|
47535
|
+
const ChevronDownIcon = () => (jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "6 9 12 15 18 9" }) }));
|
|
47536
|
+
// Icon components mapping for dynamic lookup
|
|
47537
|
+
const iconComponents = {
|
|
47538
|
+
FiMessageCircle: MessageCircleIcon,
|
|
47539
|
+
FiChevronDown: ChevronDownIcon,
|
|
46666
47540
|
};
|
|
46667
47541
|
|
|
46668
47542
|
/**
|
|
@@ -46960,108 +47834,60 @@
|
|
|
46960
47834
|
return styles;
|
|
46961
47835
|
}
|
|
46962
47836
|
|
|
46963
|
-
|
|
46964
|
-
|
|
46965
|
-
|
|
46966
|
-
|
|
46967
|
-
|
|
46968
|
-
|
|
46969
|
-
|
|
46970
|
-
* Uses multiple sampling points for accuracy
|
|
46971
|
-
*/
|
|
46972
|
-
function sampleBackgroundColor(element) {
|
|
46973
|
-
const rect = element.getBoundingClientRect();
|
|
46974
|
-
const centerX = rect.left + rect.width / 2;
|
|
46975
|
-
const centerY = rect.top + rect.height / 2;
|
|
46976
|
-
// Try to get the element behind our widget
|
|
46977
|
-
// Temporarily hide the element to sample what's behind
|
|
46978
|
-
const originalVisibility = element.style.visibility;
|
|
46979
|
-
element.style.visibility = 'hidden';
|
|
46980
|
-
// Sample the center point
|
|
46981
|
-
const elementBehind = document.elementFromPoint(centerX, centerY);
|
|
46982
|
-
// Restore visibility
|
|
46983
|
-
element.style.visibility = originalVisibility;
|
|
46984
|
-
if (!elementBehind) {
|
|
46985
|
-
return '#ffffff'; // Default to white
|
|
46986
|
-
}
|
|
46987
|
-
// Get computed background color
|
|
46988
|
-
const computedStyle = window.getComputedStyle(elementBehind);
|
|
46989
|
-
let bgColor = computedStyle.backgroundColor;
|
|
46990
|
-
// If transparent, walk up the DOM tree
|
|
46991
|
-
if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
|
|
46992
|
-
let parent = elementBehind.parentElement;
|
|
46993
|
-
while (parent) {
|
|
46994
|
-
const parentStyle = window.getComputedStyle(parent);
|
|
46995
|
-
bgColor = parentStyle.backgroundColor;
|
|
46996
|
-
if (bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent') {
|
|
46997
|
-
break;
|
|
46998
|
-
}
|
|
46999
|
-
parent = parent.parentElement;
|
|
47000
|
-
}
|
|
47001
|
-
}
|
|
47002
|
-
// If still transparent, check body/html
|
|
47003
|
-
if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
|
|
47004
|
-
const bodyStyle = window.getComputedStyle(document.body);
|
|
47005
|
-
bgColor = bodyStyle.backgroundColor;
|
|
47006
|
-
if (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent') {
|
|
47007
|
-
return '#ffffff'; // Default to white
|
|
47837
|
+
function useWidgetAppearance({ containerRef, config, theme, primaryColor, position, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, welcomeBubbleText, triggerType, triggerText, customStyles, zIndex, previewMode: _previewMode, }) {
|
|
47838
|
+
// Use theme prop directly - no dynamic detection
|
|
47839
|
+
const effectiveTheme = theme ?? "light";
|
|
47840
|
+
// Set data attribute for CSS styling
|
|
47841
|
+
reactExports.useEffect(() => {
|
|
47842
|
+
if (containerRef.current) {
|
|
47843
|
+
containerRef.current.setAttribute('data-theme', effectiveTheme);
|
|
47008
47844
|
}
|
|
47009
|
-
}
|
|
47010
|
-
|
|
47011
|
-
|
|
47012
|
-
|
|
47013
|
-
|
|
47014
|
-
|
|
47015
|
-
|
|
47016
|
-
|
|
47017
|
-
const
|
|
47018
|
-
|
|
47019
|
-
|
|
47020
|
-
const
|
|
47021
|
-
const
|
|
47022
|
-
|
|
47023
|
-
|
|
47024
|
-
|
|
47025
|
-
|
|
47026
|
-
|
|
47027
|
-
|
|
47028
|
-
|
|
47029
|
-
|
|
47030
|
-
|
|
47031
|
-
|
|
47032
|
-
const
|
|
47033
|
-
return
|
|
47034
|
-
|
|
47035
|
-
|
|
47036
|
-
|
|
47037
|
-
|
|
47038
|
-
|
|
47039
|
-
|
|
47040
|
-
|
|
47845
|
+
}, [effectiveTheme, containerRef]);
|
|
47846
|
+
const appearanceConfig = config?.appearance;
|
|
47847
|
+
const effectivePosition = position || appearanceConfig?.position || "bottom-right";
|
|
47848
|
+
const accentColor = primaryColor !== undefined ? primaryColor : appearanceConfig?.primaryColor ?? "";
|
|
47849
|
+
const effectiveSize = size || appearanceConfig?.size || "small";
|
|
47850
|
+
const effectiveHeaderTitle = headerTitle ?? appearanceConfig?.headerTitle ?? "";
|
|
47851
|
+
const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? "";
|
|
47852
|
+
const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? "";
|
|
47853
|
+
const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? "";
|
|
47854
|
+
const effectiveWelcomeBubbleText = welcomeBubbleText ?? appearanceConfig?.welcomeBubbleText ?? "";
|
|
47855
|
+
const effectiveTriggerType = triggerType ?? appearanceConfig?.triggerType ?? "button";
|
|
47856
|
+
const effectiveTriggerText = triggerText ?? appearanceConfig?.triggerText ?? "Chat";
|
|
47857
|
+
const simpleAppearance = {
|
|
47858
|
+
accentColor};
|
|
47859
|
+
const generatedStyles = generateThemeStyles(simpleAppearance, effectiveTheme);
|
|
47860
|
+
const legacyStyles = appearanceConfig ? applyAppearanceStyles(appearanceConfig) : {};
|
|
47861
|
+
const mergedStyles = {
|
|
47862
|
+
...legacyStyles,
|
|
47863
|
+
...generatedStyles,
|
|
47864
|
+
...customStyles,
|
|
47865
|
+
...(zIndex !== undefined ? { "--widget-z-index": String(zIndex) } : {}),
|
|
47866
|
+
};
|
|
47867
|
+
// Compute icon contrast color for inline button styling (prevents FOUC)
|
|
47868
|
+
const iconContrastColor = accentColor ? getContrastText(accentColor) : undefined;
|
|
47869
|
+
return {
|
|
47870
|
+
effectiveTheme,
|
|
47871
|
+
effectivePosition,
|
|
47872
|
+
accentColor,
|
|
47873
|
+
iconContrastColor,
|
|
47874
|
+
effectiveSize,
|
|
47875
|
+
effectiveHeaderTitle,
|
|
47876
|
+
effectiveWelcomeTitle,
|
|
47877
|
+
effectiveWelcomeMessage,
|
|
47878
|
+
effectivePlaceholder,
|
|
47879
|
+
effectiveWelcomeBubbleText,
|
|
47880
|
+
effectiveTriggerType,
|
|
47881
|
+
effectiveTriggerText,
|
|
47882
|
+
mergedStyles,
|
|
47883
|
+
};
|
|
47041
47884
|
}
|
|
47042
|
-
|
|
47043
|
-
|
|
47044
|
-
|
|
47045
|
-
|
|
47046
|
-
|
|
47047
|
-
|
|
47048
|
-
const theme = detectTheme(element);
|
|
47049
|
-
if (theme !== lastTheme) {
|
|
47050
|
-
lastTheme = theme;
|
|
47051
|
-
callback(theme);
|
|
47052
|
-
}
|
|
47053
|
-
});
|
|
47054
|
-
// Observe body for class/style changes (common for theme switching)
|
|
47055
|
-
observer.observe(document.body, {
|
|
47056
|
-
attributes: true,
|
|
47057
|
-
attributeFilter: ['class', 'style', 'data-theme', 'data-bs-theme'],
|
|
47058
|
-
});
|
|
47059
|
-
// Also observe html element
|
|
47060
|
-
observer.observe(document.documentElement, {
|
|
47061
|
-
attributes: true,
|
|
47062
|
-
attributeFilter: ['class', 'style', 'data-theme', 'data-bs-theme'],
|
|
47063
|
-
});
|
|
47064
|
-
return observer;
|
|
47885
|
+
|
|
47886
|
+
function WidgetTriggers({ triggerType, isOpen, onToggle, triggerText, placeholder, IconComponent, showWelcomeBubble, welcomeBubbleText, previewMode, onDismissBubble, isInputBarCollapsed, setIsInputBarCollapsed, inputBarValue, setInputBarValue, onSubmitInputBar, accentColor, iconColor, }) {
|
|
47887
|
+
// Inline button styles to prevent flash of unstyled content (FOUC)
|
|
47888
|
+
// Applied directly to button elements, bypassing CSS variable cascade timing
|
|
47889
|
+
const buttonStyle = accentColor ? { background: accentColor, color: iconColor } : undefined;
|
|
47890
|
+
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [triggerType === "button" && !isOpen && welcomeBubbleText && (previewMode || showWelcomeBubble) && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-welcome-bubble", onClick: onToggle, children: [jsxRuntimeExports.jsx("span", { children: welcomeBubbleText }), jsxRuntimeExports.jsx("button", { className: "ai-chat-welcome-bubble-close", onClick: onDismissBubble, "aria-label": "Dismiss", children: jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsxRuntimeExports.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) }), jsxRuntimeExports.jsx("div", { className: "ai-chat-welcome-bubble-arrow" })] })), triggerType === "button" && (jsxRuntimeExports.jsx("button", { className: `ai-chat-button ${isOpen ? "is-open" : ""}`, onClick: onToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", style: buttonStyle, children: jsxRuntimeExports.jsx("div", { className: "ai-chat-button-svg", children: jsxRuntimeExports.jsx(IconComponent, {}) }) })), triggerType === "pill-text" && (jsxRuntimeExports.jsxs("button", { className: `ai-chat-trigger-pill ${isOpen ? "is-open" : ""}`, onClick: onToggle, "aria-label": isOpen ? "Close chat" : "Open chat", style: isOpen ? buttonStyle : undefined, children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-trigger-pill-icon", children: jsxRuntimeExports.jsx(IconComponent, {}) }), !isOpen && jsxRuntimeExports.jsx("span", { children: triggerText })] })), triggerType === "input-bar" && !isOpen && (jsxRuntimeExports.jsx("div", { className: "ai-chat-trigger-input-container", children: isInputBarCollapsed ? (jsxRuntimeExports.jsxs("div", { className: "ai-chat-trigger-input-row", children: [jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-trigger-collapse-toggle", onClick: () => setIsInputBarCollapsed(false), "aria-label": "Expand input bar", children: jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "15 18 9 12 15 6" }) }) }), jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-button", onClick: onToggle, "aria-label": "Open chat", style: buttonStyle, children: jsxRuntimeExports.jsx("div", { className: "ai-chat-button-svg", children: jsxRuntimeExports.jsx(IconComponent, {}) }) })] })) : (jsxRuntimeExports.jsxs("div", { className: "ai-chat-trigger-input-row", children: [jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-trigger-collapse-toggle", onClick: () => setIsInputBarCollapsed(true), "aria-label": "Collapse input bar", children: jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "9 18 15 12 9 6" }) }) }), jsxRuntimeExports.jsxs("form", { className: "ai-chat-trigger-input-wrapper", onSubmit: onSubmitInputBar, children: [jsxRuntimeExports.jsx("input", { type: "text", className: "ai-chat-trigger-input", placeholder: placeholder || "Ask me anything...", value: inputBarValue, onChange: (event) => setInputBarValue(event.target.value), "aria-label": "Chat input" }), jsxRuntimeExports.jsx("button", { type: "submit", className: "ai-chat-trigger-input-btn", disabled: !inputBarValue.trim(), "aria-label": "Send message", style: buttonStyle, children: jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "12", y1: "19", x2: "12", y2: "5" }), jsxRuntimeExports.jsx("polyline", { points: "5 12 12 5 19 12" })] }) })] }), jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-trigger-input-expand", onClick: onToggle, "aria-label": "Open chat", children: jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "18 15 12 9 6 15" }) }) })] })) }))] }));
|
|
47065
47891
|
}
|
|
47066
47892
|
|
|
47067
47893
|
function styleInject(css, ref) {
|
|
@@ -47091,21 +47917,17 @@
|
|
|
47091
47917
|
}
|
|
47092
47918
|
}
|
|
47093
47919
|
|
|
47094
|
-
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)}}";
|
|
47920
|
+
var css_248z$1 = ".ai-chat-message{animation:ai-chat-message-appear .2s var(--chat-ease-bounce);max-width:85%}.ai-chat-message-content{border-radius:var(--chat-radius-bubble,14px);font-size:var(--chat-text-md,15px);line-height:var(--chat-line-relaxed,1.6);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-message.user .ai-chat-message-content{background:var(--chat-user-bg,#f4f3f0);border-bottom-right-radius:var(--chat-radius-sm,4px);color:var(--chat-user-text,#000)}.ai-chat-message.assistant .ai-chat-message-content{background:var(--chat-assistant-bg,transparent);color:var(--chat-assistant-text,#000)}.ai-chat-message-timestamp{color:var(--chat-text-muted,#71717a);font-size:var(--chat-text-xs,12px);margin-top:var(--chat-space-xs,4px);padding:0 var(--chat-space-xs,4px)}@keyframes ai-chat-message-appear{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.ai-chat-message.fullpage .ai-chat-message-content{font-size:var(--chat-text-lg,18px);padding:var(--chat-space-md,16px) var(--chat-space-lg,24px)}.ai-chat-typing{gap:var(--chat-space-xs,4px);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-typing-dot{background:var(--chat-text-muted,#71717a)}.ai-chat-tool-row{padding:0 16px}.ai-chat-tool-gear{color:var(--text-primary,#3e3e3e)}.ai-chat-tool-badge{border-radius:8px}.ai-chat-tool-badge.loading{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-tool-badge.error{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-tool-check{color:#22c55e;flex-shrink:0}.ai-chat-tool-error{color:#ef4444;flex-shrink:0}.ai-chat-tool-badge .tool-name{max-width:150px;overflow:hidden;text-overflow:ellipsis}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear{color:#fff}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-badge.error,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge.error,.dark .ai-chat-tool-badge.error,[data-theme=dark] .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}.chakra-ui-dark .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.chakra-ui-dark .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.chakra-ui-dark .ai-chat-tool-badge.error,html.dark .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}.ai-chat-widget,.chat-ui{--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--radius-2xl:18px;--radius-pill:9999px;--radius-window-top:22px;--radius-window-bottom:44px;--radius-window-gutter:16px;--radius-chat-bubble:14px;--radius-preset-badge:13px;--radius-history-item:14px;--radius-action-badge:8px;--radius-input:62px;--space-xs:4px;--space-sm:8px;--space-md:16px;--space-lg:24px;--space-xl:32px;--text-xs:12px;--text-sm:14px;--text-md:15px;--text-lg:18px;--text-xl:22px;--text-2xl:28px;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--line-height-tight:1.3;--line-height-normal:1.4;--line-height-relaxed:1.6;--breakpoint-mobile:480px;--breakpoint-tablet:768px;--breakpoint-desktop:769px;--bg-primary:#fff;--bg-secondary:#f4f4f4;--bg-tertiary:#e5e7eb;--bg-hover:#e5e7eb;--text-primary:#3e3e3e;--text-secondary:#000;--text-muted:#71717a;--text-placeholder:#a1a1aa;--border-default:#d3d3d3;--border-subtle:#e5e7eb;--border-muted:#f4f4f5;--user-bg:#f4f3f0;--user-text:#000;--user-bg-hover:#e8e7e4;--agent-bg:transparent;--agent-text:#000;--input-bg:#f4f4f4;--input-border:#d3d3d3;--input-text:#000;--btn-primary-bg:#151515;--btn-primary-text:#f4f4f4;--btn-secondary-bg:transparent;--btn-secondary-text:#71717a;--spring-bounce:cubic-bezier(0.34,1.56,0.64,1);--spring-smooth:cubic-bezier(0.4,0,0.2,1);--spring-snappy:cubic-bezier(0.2,0,0,1);--duration-fast:0.15s;--duration-normal:0.25s;--duration-slow:0.35s;--shadow-sm:0 1px 2px rgba(0,0,0,.05);--shadow-md:0 2px 8px rgba(0,0,0,.1);--shadow-lg:0 4px 16px rgba(0,0,0,.12);--shadow-window:0px 0px 15px 9px rgba(0,0,0,.1);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03)}.ai-chat-widget.dark,.chat-ui.dark{--bg-primary:#282625;--bg-secondary:#4a4846;--bg-tertiary:#484848;--bg-hover:#484848;--text-primary:#fff;--text-secondary:#fff;--text-muted:#a1a1aa;--text-placeholder:#71717a;--border-default:#5d5b5b;--border-subtle:#5d5b5b;--border-muted:#5d5b5b;--user-bg:#484848;--user-text:#fff;--user-bg-hover:#5a5a5a;--agent-bg:transparent;--agent-text:#fff;--input-bg:#4a4846;--input-border:#5d5b5b;--input-text:#fff;--btn-primary-bg:#fff;--btn-primary-text:#312f2d;--btn-secondary-bg:transparent;--btn-secondary-text:#a1a1aa;--shadow-window:0px 0px 15px 9px rgba(0,0,0,.2);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03);--shadow-input:0px 0px 10px rgba(0,0,0,.15)}.ai-chat-widget,.chat-ui{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.ai-chat-widget-container{font-size:var(--text-sm);line-height:1.5;position:fixed;z-index:var(--widget-z-index,2147483647)!important}.ai-chat-widget-container.bottom-right{bottom:20px;right:20px}.ai-chat-widget-container.bottom-left{bottom:20px;left:20px}.ai-chat-widget-container.top-right{right:20px;top:20px}.ai-chat-widget-container.top-left{left:20px;top:20px}.ai-chat-widget-container.container-mode{height:100%;inset:0;pointer-events:none;position:absolute;width:100%}.ai-chat-widget-container.container-mode .ai-chat-button,.ai-chat-widget-container.container-mode .ai-chat-trigger-button,.ai-chat-widget-container.container-mode .ai-chat-trigger-input-container,.ai-chat-widget-container.container-mode .ai-chat-window{pointer-events:auto}.ai-chat-widget-container.container-mode:not(.trigger-input-bar) .ai-chat-button{position:absolute}.ai-chat-widget-container.container-mode:not(.trigger-input-bar).bottom-right .ai-chat-button{bottom:20px;left:auto;right:20px;top:auto}.ai-chat-widget-container.container-mode:not(.trigger-input-bar).bottom-left .ai-chat-button{bottom:20px;left:20px;right:auto;top:auto}.ai-chat-widget-container.container-mode:not(.trigger-input-bar).top-right .ai-chat-button{bottom:auto;left:auto;right:20px;top:20px}.ai-chat-widget-container.container-mode:not(.trigger-input-bar).top-left .ai-chat-button{bottom:auto;left:20px;right:auto;top:20px}@keyframes ai-chat-window-open{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes ai-chat-window-close{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.9) translateY(20px)}}@keyframes ai-chat-message-slide-in{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-user-message-sent{0%{opacity:0;transform:translateX(20px) scale(.95)}60%{opacity:1;transform:translateX(-4px) scale(1.02)}to{opacity:1;transform:translateX(0) scale(1)}}@keyframes ai-chat-welcome-fade-in{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-typing-pulse{0%,60%,to{opacity:.4;transform:translateY(0) scale(1)}30%{opacity:1;transform:translateY(-4px) scale(1.1)}}@keyframes ai-chat-gear-spin{to{transform:rotate(1turn)}}@keyframes ai-chat-tool-active{0%,to{background:var(--bg-secondary);opacity:1}50%{background:var(--bg-tertiary);opacity:1}}@keyframes ai-chat-feedback-morph{0%{opacity:.5;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes ai-chat-checkmark-pop{0%{opacity:0;transform:scale(0) rotate(-45deg)}50%{transform:scale(1.3) rotate(0deg)}to{opacity:1;transform:scale(1) rotate(0deg)}}@keyframes ai-chat-history-exit{to{opacity:0;transform:translateY(-18px)}}@keyframes ai-chat-tool-gradient{0%{background-position:200% 0}to{background-position:-200% 0}}.ai-chat-window{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;animation:ai-chat-window-open var(--duration-slow,.35s) var(--spring-bounce);-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--bg-primary,#fff);border:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) var(--radius-window-bottom,44px) var(--radius-window-bottom,44px);box-shadow:var(--shadow-window,0 0 15px 5px rgba(0,0,0,.08));display:flex;flex-direction:column;overflow:hidden;position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0);transform-origin:bottom right;will-change:transform,opacity;z-index:2147483647!important}.ai-chat-widget.dark .ai-chat-window{background:var(--bg-primary,#282625);border-color:var(--border-default,#5d5b5b);border-width:.7px}.ai-chat-window.closing{animation:ai-chat-window-close var(--duration-normal) var(--spring-smooth) forwards}.ai-chat-window.size-small{height:500px;max-height:calc(100vh - 100px);max-width:calc(100vw - 40px);min-width:320px;width:380px}.ai-chat-window.size-medium{height:calc(100vh - 140px);max-height:680px;max-width:calc(100vw - 40px);min-width:380px;width:440px}.ai-chat-window.size-large{height:calc(100vh - 48px);max-height:calc(100vh - 48px);max-width:560px;min-width:440px;width:33vw}.ai-chat-widget-container.bottom-right .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);right:0}.ai-chat-widget-container.bottom-left .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);left:0}.ai-chat-widget-container.top-right .ai-chat-window{right:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-widget-container.top-left .ai-chat-window{left:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-widget-container.trigger-button.size-large.bottom-left .ai-chat-window,.ai-chat-widget-container.trigger-button.size-large.bottom-right .ai-chat-window{bottom:0}.ai-chat-widget-container.trigger-button.size-large.top-left .ai-chat-window,.ai-chat-widget-container.trigger-button.size-large.top-right .ai-chat-window{top:0}.ai-chat-widget-container.trigger-pill-text.size-large.bottom-left .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.size-large.bottom-right .ai-chat-window{bottom:72px;height:calc(100vh - 120px);max-height:calc(100vh - 120px)}.ai-chat-widget-container.trigger-pill-text.size-large.top-left .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.size-large.top-right .ai-chat-window{height:calc(100vh - 120px);max-height:calc(100vh - 120px);top:72px}.ai-chat-widget-container.trigger-input-bar.size-large.bottom-left .ai-chat-window,.ai-chat-widget-container.trigger-input-bar.size-large.bottom-right .ai-chat-window{bottom:72px;height:calc(100vh - 120px);max-height:calc(100vh - 120px)}.ai-chat-widget-container.trigger-input-bar.size-large.top-left .ai-chat-window,.ai-chat-widget-container.trigger-input-bar.size-large.top-right .ai-chat-window{height:calc(100vh - 120px);max-height:calc(100vh - 120px);top:72px}.ai-chat-widget-container.container-mode.bottom-right .ai-chat-window{bottom:20px;left:auto;right:20px;top:auto}.ai-chat-widget-container.container-mode.bottom-left .ai-chat-window{bottom:20px;left:20px;right:auto;top:auto}.ai-chat-widget-container.container-mode.top-right .ai-chat-window{bottom:auto;left:auto;right:20px;top:20px}.ai-chat-widget-container.container-mode.top-left .ai-chat-window{bottom:auto;left:20px;right:auto;top:20px}.ai-chat-widget-container.container-mode.size-small .ai-chat-window{height:min(500px,50%);max-height:calc(100% - 100px);max-width:calc(100% - 40px);min-height:300px;min-width:280px;width:min(380px,calc(100% - 40px))}.ai-chat-widget-container.container-mode.size-medium .ai-chat-window{height:min(680px,70%);max-height:calc(100% - 80px);max-width:calc(100% - 40px);min-height:400px;min-width:320px;width:min(440px,calc(100% - 40px))}.ai-chat-widget-container.container-mode.size-large .ai-chat-window{height:90%;max-height:calc(100% - 60px);max-width:calc(100% - 40px);min-height:500px;min-width:380px;width:min(560px,calc(100% - 40px))}.ai-chat-widget-container.trigger-button.container-mode.bottom-left .ai-chat-window,.ai-chat-widget-container.trigger-button.container-mode.bottom-right .ai-chat-window{bottom:88px}.ai-chat-widget-container.trigger-pill-text.container-mode.bottom-left .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.container-mode.bottom-right .ai-chat-window{bottom:80px}.ai-chat-widget-container.trigger-button.container-mode.size-medium .ai-chat-window,.ai-chat-widget-container.trigger-button.container-mode.size-small .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.container-mode.size-medium .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.container-mode.size-small .ai-chat-window{max-height:calc(100% - 108px)}.ai-chat-widget-container.trigger-button.container-mode.size-large .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.container-mode.size-large .ai-chat-window{height:calc(100% - 108px);max-height:calc(100% - 108px)}.ai-chat-widget-container.trigger-button.container-mode.top-left .ai-chat-window,.ai-chat-widget-container.trigger-button.container-mode.top-right .ai-chat-window{bottom:auto;top:88px}.ai-chat-widget-container.trigger-pill-text.container-mode.top-left .ai-chat-window,.ai-chat-widget-container.trigger-pill-text.container-mode.top-right .ai-chat-window{bottom:auto;top:80px}.ai-chat-widget-container.container-mode.mobile-mode.is-open{margin:0!important;padding:0!important}.ai-chat-widget-container.container-mode.mobile-mode.is-open,.ai-chat-widget-container.container-mode.mobile-mode.is-open .ai-chat-window{bottom:0!important;height:100%!important;left:0!important;position:absolute!important;right:0!important;top:0!important;width:100%!important}.ai-chat-widget-container.container-mode.mobile-mode.is-open .ai-chat-window{animation:none!important;border:none!important;border-radius:0!important;box-shadow:none!important;max-height:100%!important;max-width:100%!important;min-height:100%!important;min-width:100%!important}.ai-chat-widget-container.container-mode.mobile-mode.is-open .ai-chat-button,.ai-chat-widget-container.container-mode.mobile-mode.is-open .ai-chat-trigger-input-container,.ai-chat-widget-container.container-mode.mobile-mode.is-open .ai-chat-trigger-pill{display:none!important}.ai-chat-header{align-items:center;background:var(--bg-primary,#fff);border-bottom:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) 0 0;display:flex;justify-content:space-between;padding:12px var(--space-md,16px);position:relative;z-index:10}.ai-chat-widget.dark .ai-chat-header{background:var(--bg-primary,#282625);border-bottom-color:var(--border-default,#5d5b5b);border-bottom-width:.7px}.ai-chat-header.is-history{padding-left:var(--space-md)}.ai-chat-header.is-history .ai-chat-title{flex:1;min-width:0;overflow:hidden;padding-right:var(--space-lg);text-overflow:ellipsis;white-space:nowrap}.ai-chat-header-content{align-items:center;display:flex;flex:1;gap:var(--space-lg)}.ai-chat-header-actions{align-items:center;display:flex;gap:var(--space-sm)}.ai-chat-logo{border-radius:10px;height:36px;object-fit:cover;width:36px}.ai-chat-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-xl,22px);font-weight:var(--font-weight-bold,700);letter-spacing:-.02em}.ai-chat-widget.dark .ai-chat-title{color:var(--text-primary,#fff)}.ai-chat-close-button,.ai-chat-header-button{align-items:center;background:transparent;border:none;border-radius:var(--radius-md);color:var(--text-muted);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:32px}.ai-chat-close-button:hover,.ai-chat-header-button:hover{color:var(--text-primary)}.ai-chat-close-button:active,.ai-chat-header-button:active{transform:scale(.95)}.ai-chat-close-button svg,.ai-chat-header-button svg{height:22px;width:22px}.ai-chat-button{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:center;-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--button-color,var(--btn-primary-bg));border:1px solid var(--border-default,#d3d3d3);border-radius:50%;box-shadow:var(--shadow-button,0 0 15px 9px rgba(0,0,0,.03));color:var(--button-icon-color,var(--btn-primary-text));cursor:pointer;display:flex;height:var(--button-size,56px);justify-content:center;overflow:hidden;position:relative;-webkit-transform:translateZ(0);transform:translateZ(0);transition:transform var(--duration-fast) ease;width:var(--button-size,56px);will-change:transform;z-index:2147483647!important}.ai-chat-button:hover{transform:scale(1.05)}.ai-chat-button:active{transform:scale(.98)}.ai-chat-button-svg{height:50%;min-height:24px;min-width:24px;transition:transform var(--duration-fast) ease;width:50%}.ai-chat-button.is-open .ai-chat-button-svg{transform:rotate(0deg)}.ai-chat-button-icon{font-size:1.5em;line-height:1}.ai-chat-welcome-bubble{animation:ai-chat-bubble-fade-in .3s ease-out;background:var(--button-color,var(--btn-primary-bg,#07f));border:none;border-radius:16px;box-shadow:none;box-sizing:border-box;color:var(--button-icon-color,var(--btn-primary-text,#fff));cursor:pointer;font-size:13px;font-weight:500;line-height:1.5;max-width:min(420px,90vw);padding:12px 32px 12px 16px;position:absolute;text-align:left;white-space:normal;width:auto;z-index:2147483647!important}.ai-chat-welcome-bubble-close{align-items:center;background:transparent;border:none;border-radius:50%;color:inherit;cursor:pointer;display:flex;height:20px;justify-content:center;opacity:.8;padding:0;position:absolute;right:8px;top:8px;transition:opacity .15s ease,background .15s ease;width:20px}.ai-chat-welcome-bubble-close:hover{background:hsla(0,0%,100%,.2);opacity:1}.ai-chat-welcome-bubble-close svg{height:12px;width:12px}.ai-chat-welcome-bubble-arrow{border-bottom:8px solid transparent;border-top:8px solid transparent;height:0;position:absolute;width:0}.ai-chat-widget-container.bottom-right .ai-chat-welcome-bubble{bottom:50%;right:calc(100% + 12px);text-align:left;transform:translateY(50%)}.ai-chat-widget-container.bottom-left .ai-chat-welcome-bubble{bottom:50%;left:calc(100% + 12px);text-align:left;transform:translateY(50%)}.ai-chat-widget-container.top-right .ai-chat-welcome-bubble{right:calc(100% + 12px);text-align:left;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble{left:calc(100% + 12px);text-align:left;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.bottom-right .ai-chat-welcome-bubble-arrow{border-left:8px solid var(--button-color,var(--btn-primary-bg,#07f));right:-8px;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.bottom-left .ai-chat-welcome-bubble-arrow{border-right:8px solid var(--button-color,var(--btn-primary-bg,#07f));left:-8px;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.top-right .ai-chat-welcome-bubble-arrow{border-left:8px solid var(--button-color,var(--btn-primary-bg,#07f));right:-8px;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble-arrow{border-right:8px solid var(--button-color,var(--btn-primary-bg,#07f));left:-8px;top:50%;transform:translateY(-50%)}.ai-chat-welcome-bubble:hover{filter:brightness(1.1)}.ai-chat-widget-container.bottom-right .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-bottom-right}@keyframes ai-chat-bubble-fade-in-bottom-right{0%{opacity:0;transform:translateY(50%) translateX(8px)}to{opacity:1;transform:translateY(50%) translateX(0)}}.ai-chat-widget-container.bottom-left .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-bottom-left}@keyframes ai-chat-bubble-fade-in-bottom-left{0%{opacity:0;transform:translateY(50%) translateX(-8px)}to{opacity:1;transform:translateY(50%) translateX(0)}}.ai-chat-widget-container.top-right .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-top-right}@keyframes ai-chat-bubble-fade-in-top-right{0%{opacity:0;transform:translateY(-50%) translateX(8px)}to{opacity:1;transform:translateY(-50%) translateX(0)}}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-top-left}@keyframes ai-chat-bubble-fade-in-top-left{0%{opacity:0;transform:translateY(-50%) translateX(-8px)}to{opacity:1;transform:translateY(-50%) translateX(0)}}.ai-chat-trigger-pill{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:center;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--trigger-bg,rgba(0,0,0,.04));border:1px solid var(--trigger-border,rgba(0,0,0,.12));border-radius:9999px;box-shadow:0 4px 16px rgba(0,0,0,.12);color:var(--trigger-text,#1a1a1a);cursor:pointer;display:flex;font-size:14px;font-weight:500;gap:10px;height:48px;justify-content:center;padding:0 24px;position:relative;-webkit-transform:translateZ(0);transform:translateZ(0);transition:all .3s ease,color .4s ease,background .4s ease,border-color .4s ease;white-space:nowrap;will-change:transform;z-index:2147483647!important}.ai-chat-trigger-pill.is-open{background:var(--button-color,var(--btn-primary-bg));border-color:var(--border-default,#d3d3d3);box-shadow:var(--shadow-button,0 0 15px 9px rgba(0,0,0,.03));color:var(--button-icon-color,var(--btn-primary-text));height:56px;padding:0;width:56px}.ai-chat-trigger-pill.is-open .ai-chat-trigger-pill-icon{height:24px;width:24px}.ai-chat-trigger-pill:hover:not(.is-open){background:var(--trigger-bg-hover,rgba(0,0,0,.08));border-color:var(--trigger-border-hover,rgba(0,0,0,.2))}.ai-chat-trigger-pill.is-open:hover{transform:scale(1.05)}.ai-chat-trigger-pill:active{transform:scale(.98)}.ai-chat-trigger-pill-icon{flex-shrink:0;height:20px;transition:all .3s ease;width:20px}.ai-chat-widget-container.trigger-pill-text.container-mode .ai-chat-trigger-pill{position:absolute}.ai-chat-widget-container.trigger-pill-text.container-mode.bottom-right .ai-chat-trigger-pill{bottom:20px;left:auto;right:20px;top:auto}.ai-chat-widget-container.trigger-pill-text.container-mode.bottom-left .ai-chat-trigger-pill{bottom:20px;left:20px;right:auto;top:auto}.ai-chat-widget-container.trigger-pill-text.container-mode.top-right .ai-chat-trigger-pill{bottom:auto;left:auto;right:20px;top:20px}.ai-chat-widget-container.trigger-pill-text.container-mode.top-left .ai-chat-trigger-pill{bottom:auto;left:20px;right:auto;top:20px}.ai-chat-widget-container.trigger-pill-text.container-mode .ai-chat-trigger-pill{pointer-events:auto}.ai-chat-trigger-input-container{align-items:flex-end;display:flex;flex-direction:column;gap:8px;z-index:2147483647!important}.ai-chat-widget-container.bottom-left .ai-chat-trigger-input-container,.ai-chat-widget-container.top-left .ai-chat-trigger-input-container{align-items:flex-start}.ai-chat-trigger-input-row{align-items:center;display:flex;gap:8px;transition:gap .4s cubic-bezier(.4,0,.2,1),width .4s cubic-bezier(.4,0,.2,1)}.ai-chat-widget-container.trigger-input-bar.is-collapsed .ai-chat-trigger-input-row{gap:4px}.ai-chat-trigger-input-expand{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:center;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--trigger-bg,rgba(0,0,0,.04));border:1px solid var(--trigger-border,rgba(0,0,0,.12));border-radius:50%;box-shadow:0 2px 12px rgba(0,0,0,.12);color:var(--trigger-text-muted,rgba(0,0,0,.5));cursor:pointer;display:flex;flex-shrink:0;height:48px;justify-content:center;padding:0;-webkit-transform:translateZ(0);transform:translateZ(0);transition:all .2s ease,color .4s ease,background .4s ease,border-color .4s ease;width:48px;will-change:transform}.ai-chat-trigger-input-expand:hover{background:var(--trigger-bg-hover,rgba(0,0,0,.08));color:var(--trigger-text,#1a1a1a);transform:translateY(-2px)}.ai-chat-trigger-input-expand:active{transform:translateY(0)}.ai-chat-trigger-input-expand svg{stroke-width:2.5;height:20px;width:20px}.ai-chat-trigger-input-wrapper{flex:1;min-width:120px;position:relative;transform-origin:right center;transition:flex .4s cubic-bezier(.4,0,.2,1),width .4s cubic-bezier(.4,0,.2,1),opacity .3s cubic-bezier(.4,0,.2,1),transform .4s cubic-bezier(.4,0,.2,1);z-index:1}.ai-chat-widget-container.bottom-left .ai-chat-trigger-input-wrapper,.ai-chat-widget-container.top-left .ai-chat-trigger-input-wrapper{transform-origin:left center}.ai-chat-trigger-input{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--trigger-bg,rgba(0,0,0,.04));border:1px solid var(--trigger-border,rgba(0,0,0,.12));border-radius:var(--radius-input,62px);box-shadow:0 4px 24px rgba(0,0,0,.15);box-sizing:border-box;color:var(--trigger-text,#1a1a1a);font-size:var(--text-md,15px);height:48px;outline:none;padding:6px 52px 6px 16px;-webkit-transform:translateZ(0);transform:translateZ(0);transition:all .2s ease,color .4s ease,background .4s ease,border-color .4s ease;width:100%}.ai-chat-trigger-input::placeholder{color:var(--trigger-text-muted,rgba(0,0,0,.5))}.ai-chat-trigger-input:focus{background:var(--trigger-bg-hover,rgba(0,0,0,.08));border-color:var(--trigger-border-hover,rgba(0,0,0,.2))}.ai-chat-trigger-input-btn{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:center;-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--primary-color,var(--button-color,#07f));border:none;border-radius:50%;box-shadow:0 2px 8px rgba(0,119,255,.3);color:var(--send-button-icon-color,var(--button-icon-color,#fff));cursor:pointer;display:flex;height:38px;justify-content:center;position:absolute;right:4px;top:50%;transform:translateY(-50%);transition:all .2s ease;width:38px;will-change:transform}.ai-chat-trigger-input-btn:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,119,255,.4);transform:translateY(-50%) scale(1.05)}.ai-chat-trigger-input-btn:active:not(:disabled){transform:translateY(-50%) scale(.95)}.ai-chat-trigger-input-btn:disabled{box-shadow:none;cursor:not-allowed;opacity:.4}.ai-chat-trigger-input-btn svg{height:18px;width:18px}.ai-chat-widget-container.trigger-input-bar .ai-chat-trigger-input-row{width:min(380px,calc(100vw - 40px))}.ai-chat-widget-container.trigger-input-bar.size-medium .ai-chat-trigger-input-row{width:min(440px,calc(100vw - 40px))}.ai-chat-widget-container.trigger-input-bar.size-large .ai-chat-trigger-input-row{width:min(560px,calc(100vw - 40px))}.ai-chat-widget-container.trigger-input-bar .ai-chat-trigger-input-wrapper{flex:1;min-width:160px}.ai-chat-widget-container.trigger-input-bar.container-mode .ai-chat-trigger-input-container{position:absolute;width:min(380px,calc(100% - 40px))}.ai-chat-widget-container.trigger-input-bar.container-mode.size-small .ai-chat-trigger-input-container{width:min(380px,calc(100% - 40px))}.ai-chat-widget-container.trigger-input-bar.container-mode.size-medium .ai-chat-trigger-input-container{width:min(440px,calc(100% - 40px))}.ai-chat-widget-container.trigger-input-bar.container-mode.size-large .ai-chat-trigger-input-container{width:min(560px,calc(100% - 40px))}.ai-chat-widget-container.trigger-input-bar.container-mode.bottom-right .ai-chat-trigger-input-container{bottom:20px;left:auto;right:20px;top:auto}.ai-chat-widget-container.trigger-input-bar.container-mode.bottom-left .ai-chat-trigger-input-container{bottom:20px;left:20px;right:auto;top:auto}.ai-chat-widget-container.trigger-input-bar.container-mode.top-right .ai-chat-trigger-input-container{bottom:auto;left:auto;right:20px;top:20px}.ai-chat-widget-container.trigger-input-bar.container-mode.top-left .ai-chat-trigger-input-container{bottom:auto;left:20px;right:auto;top:20px}.ai-chat-widget-container.trigger-input-bar.container-mode .ai-chat-trigger-input-row{width:100%}.ai-chat-widget-container.trigger-input-bar.container-mode .ai-chat-trigger-input-wrapper{flex:1;min-width:120px}.ai-chat-widget-container.trigger-input-bar.is-collapsed .ai-chat-trigger-input-wrapper{opacity:0;overflow:hidden;pointer-events:none;transform:scaleX(0);width:0}.ai-chat-widget-container.trigger-input-bar{align-items:flex-end;display:flex;flex-direction:column;gap:12px}.ai-chat-widget-container.trigger-input-bar.bottom-left,.ai-chat-widget-container.trigger-input-bar.top-left{align-items:flex-start}.ai-chat-widget-container.trigger-input-bar .ai-chat-window{bottom:auto;left:auto;order:-1;position:relative;right:auto;top:auto}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-small{max-width:calc(100vw - 40px);min-width:320px;width:380px}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-medium{max-width:calc(100vw - 40px);min-width:380px;width:440px}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-large{max-width:calc(100vw - 40px);min-width:440px;width:560px}.ai-chat-widget-container.trigger-input-bar.container-mode .ai-chat-window{max-width:calc(100% - 40px);position:absolute}.ai-chat-widget-container.trigger-input-bar.container-mode.bottom-right .ai-chat-window{bottom:20px;left:auto;right:20px;top:auto}.ai-chat-widget-container.trigger-input-bar.container-mode.bottom-left .ai-chat-window{bottom:20px;left:20px;right:auto;top:auto}.ai-chat-widget-container.trigger-input-bar.container-mode.top-right .ai-chat-window{bottom:auto;left:auto;right:20px;top:20px}.ai-chat-widget-container.trigger-input-bar.container-mode.top-left .ai-chat-window{bottom:auto;left:20px;right:auto;top:20px}.ai-chat-widget-container.trigger-input-bar.container-mode.size-small .ai-chat-window{max-width:calc(100% - 40px);width:380px}.ai-chat-widget-container.trigger-input-bar.container-mode.size-medium .ai-chat-window{max-width:calc(100% - 40px);width:440px}.ai-chat-widget-container.trigger-input-bar.container-mode.size-large .ai-chat-window{max-width:calc(100% - 40px);width:560px}.ai-chat-widget-container.trigger-input-bar.mobile-mode .ai-chat-trigger-input-container{width:calc(100% - 40px)}.ai-chat-widget-container.trigger-input-bar.mobile-mode .ai-chat-trigger-input-row{width:100%}.ai-chat-widget-container.trigger-input-bar.mobile-mode .ai-chat-trigger-input-wrapper{flex:1;min-width:120px}.ai-chat-widget-container.trigger-input-bar.mobile-mode.is-collapsed .ai-chat-trigger-input-container{width:auto}.ai-chat-widget-container.trigger-input-bar.mobile-mode.is-collapsed .ai-chat-trigger-input-row{gap:8px;justify-content:flex-end}.ai-chat-trigger-collapse-toggle{align-items:center;background:transparent;border:none;border-radius:50%;color:var(--trigger-text-muted,rgba(0,0,0,.5));cursor:pointer;display:flex;flex-shrink:0;height:24px;justify-content:center;margin-right:-4px;order:-1;padding:0;transition:all .2s ease;width:24px}.ai-chat-trigger-collapse-toggle:hover{color:var(--trigger-text,#1a1a1a)}.ai-chat-trigger-collapse-toggle svg{stroke-width:2.5;height:20px;transition:transform .4s cubic-bezier(.4,0,.2,1);width:20px}.ai-chat-widget-container.trigger-input-bar.bottom-left .ai-chat-trigger-collapse-toggle svg,.ai-chat-widget-container.trigger-input-bar.top-left .ai-chat-trigger-collapse-toggle svg{transform:rotate(180deg)}.ai-chat-trigger-input-expand{margin-left:-4px;order:1;transition:transform .2s ease,opacity .3s ease}.ai-chat-widget-container.container-mode .ai-chat-trigger-input-expand{margin-left:0}.ai-chat-trigger-input-expand svg{transition:transform .4s cubic-bezier(.4,0,.2,1)}.ai-chat-widget-container.trigger-input-bar .ai-chat-trigger-input-expand svg{transform:rotate(0deg)}.ai-chat-widget-container.bottom-left .ai-chat-trigger-collapse-toggle,.ai-chat-widget-container.top-left .ai-chat-trigger-collapse-toggle{margin-left:-4px;margin-right:0;order:1}.ai-chat-widget-container.bottom-left .ai-chat-trigger-input-expand,.ai-chat-widget-container.top-left .ai-chat-trigger-input-expand{margin-left:0;margin-right:-4px;order:-1}.ai-chat-widget-container.trigger-input-bar .ai-chat-trigger-input-row .ai-chat-button{order:1}.ai-chat-widget-container.trigger-input-bar.bottom-left .ai-chat-trigger-input-row .ai-chat-button,.ai-chat-widget-container.trigger-input-bar.top-left .ai-chat-trigger-input-row .ai-chat-button{order:-1}.ai-chat-widget-container.trigger-input-bar.is-collapsed.bottom-right .ai-chat-button,.ai-chat-widget-container.trigger-input-bar.is-collapsed.top-right .ai-chat-button{margin-right:16px}.ai-chat-widget-container.trigger-input-bar.is-collapsed.bottom-left .ai-chat-button,.ai-chat-widget-container.trigger-input-bar.is-collapsed.top-left .ai-chat-button{margin-left:16px}.ai-chat-widget-container.trigger-input-bar.is-collapsed .ai-chat-trigger-input-row{flex-direction:row;justify-content:flex-end}.ai-chat-widget-container.trigger-input-bar.is-collapsed.bottom-left .ai-chat-trigger-input-row,.ai-chat-widget-container.trigger-input-bar.is-collapsed.top-left .ai-chat-trigger-input-row{justify-content:flex-start}.ai-chat-widget-container.trigger-input-bar .ai-chat-button{display:flex;opacity:1;transform:scale(1);transition:transform .4s cubic-bezier(.4,0,.2,1),opacity .3s cubic-bezier(.4,0,.2,1),width .4s cubic-bezier(.4,0,.2,1),height .4s cubic-bezier(.4,0,.2,1)}.ai-chat-widget-container.trigger-input-bar:not(.is-collapsed) .ai-chat-button{border:none;height:0;margin:0;min-width:0;opacity:0;overflow:hidden;padding:0;pointer-events:none;transform:scale(0);width:0}.ai-chat-widget-container.trigger-pill-text .ai-chat-button{display:none}.ai-chat-widget-container.trigger-pill-text.is-open{gap:8px}.ai-chat-widget.light .ai-chat-trigger-pill:not(.is-open){backdrop-filter:none;-webkit-backdrop-filter:none;background:#fff;border:1px solid rgba(0,0,0,.15);box-shadow:0 2px 8px rgba(0,0,0,.08);color:#18181b}.ai-chat-widget.light .ai-chat-trigger-pill:not(.is-open):hover{background:#fafafa;border-color:rgba(0,0,0,.2)}.ai-chat-widget.light .ai-chat-trigger-input-expand{backdrop-filter:none;-webkit-backdrop-filter:none;background:#fff;border:1px solid rgba(0,0,0,.15);box-shadow:0 2px 8px rgba(0,0,0,.08);color:#52525b}.ai-chat-widget.light .ai-chat-trigger-input-expand:hover{background:#fafafa;color:#18181b}.ai-chat-widget.light .ai-chat-trigger-input{backdrop-filter:none;-webkit-backdrop-filter:none;background:#fff;border:1px solid rgba(0,0,0,.15);box-shadow:0 2px 8px rgba(0,0,0,.08);color:#18181b}.ai-chat-widget.light .ai-chat-trigger-input::placeholder{color:#71717a}.ai-chat-widget.light .ai-chat-trigger-input:focus{background:#fff;border-color:rgba(0,0,0,.25)}.ai-chat-widget.light .ai-chat-trigger-collapse-toggle{color:#71717a}.ai-chat-widget.light .ai-chat-trigger-collapse-toggle:hover{color:#18181b}.ai-chat-widget.dark .ai-chat-trigger-pill:not(.is-open){backdrop-filter:none;-webkit-backdrop-filter:none;background:#27272a;border:1px solid hsla(0,0%,100%,.15);box-shadow:0 2px 8px rgba(0,0,0,.3);color:#fafafa}.ai-chat-widget.dark .ai-chat-trigger-pill:not(.is-open):hover{background:#3f3f46;border-color:hsla(0,0%,100%,.25)}.ai-chat-widget.dark .ai-chat-trigger-input-expand{backdrop-filter:none;-webkit-backdrop-filter:none;background:#27272a;border:1px solid hsla(0,0%,100%,.15);box-shadow:0 2px 8px rgba(0,0,0,.3);color:#a1a1aa}.ai-chat-widget.dark .ai-chat-trigger-input-expand:hover{background:#3f3f46;color:#fafafa}.ai-chat-widget.dark .ai-chat-trigger-input{backdrop-filter:none;-webkit-backdrop-filter:none;background:#27272a;border:1px solid hsla(0,0%,100%,.15);box-shadow:0 2px 8px rgba(0,0,0,.3);color:#fafafa}.ai-chat-widget.dark .ai-chat-trigger-input::placeholder{color:#71717a}.ai-chat-widget.dark .ai-chat-trigger-input:focus{background:#27272a;border-color:hsla(0,0%,100%,.25)}.ai-chat-widget.dark .ai-chat-trigger-collapse-toggle{color:#71717a}.ai-chat-widget.dark .ai-chat-trigger-collapse-toggle:hover{color:#fafafa}.ai-chat-input-container{background:var(--bg-primary,#fff);bottom:0;left:0;padding:8px 0 16px;position:absolute;right:0;z-index:10}.ai-chat-widget.dark .ai-chat-input-container{background:var(--bg-primary,#282625)}.ai-chat-input-container.separate{padding:0 var(--radius-window-gutter,16px) var(--radius-window-gutter,16px)}.ai-chat-input-wrapper{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:flex-end;-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--input-bg,#f4f4f4);border:1px solid var(--input-border,#d3d3d3);border-radius:var(--radius-input,62px);box-sizing:border-box;display:flex;gap:0;height:52px;overflow:hidden;padding:6px 6px 6px 16px;position:relative;-webkit-transform:translateZ(0);transform:translateZ(0);transition:all var(--duration-fast,.15s) ease;will-change:transform;z-index:5}.ai-chat-input-wrapper.multiline{border-radius:14px!important;min-height:64px;padding:10px 10px 10px 14px}.ai-chat-widget.dark .ai-chat-input-wrapper{background:var(--input-bg,#4a4846);border-color:var(--input-border,#5d5b5b);border-width:.7px;box-shadow:var(--shadow-input,0 0 10px rgba(0,0,0,.15))}.ai-chat-input-wrapper:focus-within{border-color:var(--text-muted,#a1a1aa)}.ai-chat-input{word-wrap:break-word!important;background:transparent!important;border:none!important;border-radius:0!important;box-shadow:none!important;box-sizing:border-box!important;color:var(--input-text,#000)!important;flex:1!important;font-family:inherit!important;font-size:16px!important;height:40px!important;line-height:20px!important;margin:0!important;max-height:40px!important;min-height:40px!important;min-width:0!important;outline:none!important;overflow-wrap:anywhere!important;overflow-x:hidden!important;overflow-y:auto!important;padding:10px var(--space-sm,8px)!important;resize:none!important;white-space:pre-wrap!important;width:0!important;word-break:break-word!important}.ai-chat-widget.dark .ai-chat-input{color:var(--input-text,#fff)}.ai-chat-input::placeholder{color:var(--text-placeholder,#a1a1aa)}.ai-chat-widget.dark .ai-chat-input::placeholder{color:var(--text-placeholder,#52525b)}.ai-chat-file-button{align-items:center;align-self:center;background:transparent;border:none;color:var(--text-placeholder);cursor:pointer;display:flex;flex-shrink:0;height:28px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:28px}.ai-chat-file-button:hover{color:var(--text-secondary)}.ai-chat-file-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-send-button{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto;align-items:center;align-self:center;-webkit-backface-visibility:hidden;backface-visibility:hidden;background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));border:none;border-radius:50%;color:var(--send-button-icon-color,var(--button-icon-color,var(--btn-primary-text,#f4f4f4)));cursor:pointer;display:flex;flex-shrink:0;height:40px;justify-content:center;min-height:40px;min-width:40px;padding:0;-webkit-transform:translateZ(0);transform:translateZ(0);transition:all var(--duration-fast,.15s) ease;width:40px;will-change:transform,opacity}.ai-chat-widget.dark .ai-chat-send-button{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--send-button-icon-color,var(--button-icon-color,var(--btn-primary-text,#312f2d)))}.ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));color:var(--send-button-icon-color,var(--button-icon-color,var(--btn-primary-text,#f4f4f4)))}.ai-chat-widget.dark .ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--send-button-icon-color,var(--button-icon-color,var(--btn-primary-text,#312f2d)))}.ai-chat-send-button:hover:not(:disabled){opacity:.8}.ai-chat-send-button:active:not(:disabled){transform:scale(.95)}.ai-chat-send-button:disabled{cursor:not-allowed;opacity:.3}.ai-chat-file-list{display:flex;flex-wrap:wrap;gap:var(--space-sm);padding:var(--space-sm) var(--space-sm)}.ai-chat-file-item{align-items:center;background:rgba(0,0,0,.05);border-radius:6px;display:flex;font-size:var(--text-xs);gap:var(--space-sm);padding:6px 10px}.ai-chat-file-extension{background:var(--btn-primary-bg);border-radius:3px;color:var(--btn-primary-text);display:inline-block;font-size:10px;font-weight:var(--font-weight-semibold);min-width:40px;padding:2px 6px;text-align:center;text-transform:uppercase}.ai-chat-file-info{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.ai-chat-file-name{font-weight:var(--font-weight-medium);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-file-size{color:var(--text-muted);font-size:10px;opacity:.7}.ai-chat-file-remove{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;justify-content:center;opacity:.5;padding:var(--space-xs);transition:opacity var(--duration-fast) ease}.ai-chat-file-remove:hover{opacity:1}.ai-chat-data-policy{bottom:2px;color:var(--text-muted,#71717a);font-size:9px;left:0;line-height:1.4;opacity:.5;pointer-events:auto;position:absolute;right:0;text-align:center}.ai-chat-widget.dark .ai-chat-data-policy{color:var(--text-muted,#a1a1aa)}.ai-chat-data-policy-link{background:none;border:none;color:var(--text-muted,#71717a);cursor:pointer;font-family:inherit;font-size:inherit;margin:0;padding:0;text-decoration:underline;text-underline-offset:2px;transition:color .15s ease}.ai-chat-data-policy-link:hover{color:var(--text-secondary,#52525b)}.ai-chat-widget.dark .ai-chat-data-policy-link{color:var(--text-muted,#a1a1aa)}.ai-chat-widget.dark .ai-chat-data-policy-link:hover{color:var(--text-secondary,#d4d4d8)}.ai-chat-page-disclaimer{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:10px;gap:4px;justify-content:center;line-height:1.4;opacity:.7;padding:8px 16px;text-align:center}.ai-chat-widget.dark .ai-chat-page-disclaimer{color:var(--text-muted,#a1a1aa)}.ai-chat-page-disclaimer-link{background:none;border:none;color:var(--text-muted,#71717a);cursor:pointer;font-family:inherit;font-size:inherit;margin:0;padding:0;text-decoration:underline;text-underline-offset:2px;transition:color .15s ease}.ai-chat-page-disclaimer-link:hover{color:var(--text-secondary,#52525b)}.ai-chat-widget.dark .ai-chat-page-disclaimer-link{color:var(--text-muted,#a1a1aa)}.ai-chat-widget.dark .ai-chat-page-disclaimer-link:hover{color:var(--text-secondary,#d4d4d8)}.ai-chat-messages{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;align-items:stretch;background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;gap:var(--space-md,16px);justify-content:flex-start;min-height:0;overflow-x:hidden;overflow-y:auto;padding:0 var(--space-md,16px) 100px;position:relative;scroll-behavior:smooth;scrollbar-width:none}.ai-chat-widget.dark .ai-chat-messages{background:var(--bg-primary,#18181b)}.ai-chat-messages::-webkit-scrollbar{display:none}.ai-chat-message{animation:ai-chat-message-slide-in .2s var(--spring-bounce);display:flex;flex-direction:column;max-width:90%}.ai-chat-message.user{align-items:flex-end;align-self:flex-end;animation:ai-chat-user-message-sent .35s var(--spring-bounce)}.ai-chat-message.assistant{align-items:flex-start;align-self:flex-start;max-width:100%;width:100%}.ai-chat-message.tool{align-self:stretch;max-width:none;padding:0}.ai-chat-message-content{word-wrap:break-word;border-radius:18px;font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);max-width:100%;overflow-wrap:break-word;padding:8px 14px;word-break:break-word}.ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#f4f3f0);border-radius:18px;color:var(--user-text,#000)}.ai-chat-widget.dark .ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#484848);color:var(--user-text,#fff)}.ai-chat-message.assistant .ai-chat-message-content{background:var(--agent-bg,transparent);box-sizing:border-box;color:var(--agent-text,#000);padding:0;width:100%}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content{color:var(--agent-text,#fff)}.ai-chat-message-meta{align-items:center;display:flex;gap:var(--space-sm,8px);margin-top:var(--space-xs,4px);padding:0 var(--space-xs,4px)}.ai-chat-message.user .ai-chat-message-meta{justify-content:flex-end}.ai-chat-message.assistant .ai-chat-message-meta{justify-content:flex-start}.ai-chat-message-timestamp{color:var(--text-muted,#71717a);font-size:var(--text-xs,12px)}.ai-chat-welcome{animation:ai-chat-welcome-fade-in .3s var(--spring-smooth);display:flex;flex-direction:column;gap:var(--space-md,16px);padding:var(--space-lg,24px) 0}.ai-chat-welcome-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-2xl,28px);font-weight:var(--font-weight-bold,700);line-height:var(--line-height-tight,1.3)}.ai-chat-widget.dark .ai-chat-welcome-title{color:var(--text-primary,#fff)}.ai-chat-welcome-text{color:var(--text-secondary,#000);font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);max-width:100%}.ai-chat-widget.dark .ai-chat-welcome-text{color:var(--text-secondary,#fff)}.ai-chat-typing{align-items:center;display:flex;gap:var(--space-xs,4px);padding:var(--space-sm,8px) var(--space-md,16px)}.ai-chat-typing-dot{animation:ai-chat-typing-bounce 1.4s ease-in-out infinite both;background:var(--text-muted,#71717a);border-radius:50%;height:8px;width:8px}.ai-chat-typing-dot:first-child{animation-delay:-.32s}.ai-chat-typing-dot:nth-child(2){animation-delay:-.16s}.ai-chat-typing-dot:nth-child(3){animation-delay:0s}@keyframes ai-chat-typing-bounce{0%,80%,to{opacity:.4;transform:scale(.6)}40%{opacity:1;transform:scale(1)}}.ai-chat-scroll-button{align-items:center;background:var(--bg-secondary,#f4f4f5);border:1px solid var(--border-subtle,rgba(0,0,0,.1));border-radius:50%;bottom:80px;box-shadow:0 2px 8px rgba(0,0,0,.1);color:var(--text-secondary,#71717a);cursor:pointer;display:flex;height:36px;justify-content:center;left:50%;opacity:0;pointer-events:none;position:absolute;transform:translateX(-50%);transition:background .15s ease,box-shadow .15s ease,opacity .15s ease,visibility .15s ease;visibility:hidden;width:36px;z-index:15}.ai-chat-scroll-button.visible{opacity:1;pointer-events:auto;visibility:visible}.ai-chat-scroll-button:hover{background:var(--bg-tertiary,#e4e4e7);box-shadow:0 4px 12px rgba(0,0,0,.15)}.ai-chat-scroll-button:active{background:var(--bg-tertiary,#d4d4d8)}.ai-chat-widget.dark .ai-chat-scroll-button{background:var(--bg-secondary,#3f3f46);border-color:var(--border-subtle,hsla(0,0%,100%,.1));box-shadow:0 2px 8px rgba(0,0,0,.3);color:var(--text-secondary,#a1a1aa)}.ai-chat-widget.dark .ai-chat-scroll-button:hover{background:var(--bg-tertiary,#52525b);box-shadow:0 4px 12px rgba(0,0,0,.4)}.ai-chat-error{background:var(--bg-secondary);border-radius:var(--radius-chat-bubble);color:var(--text-primary);font-size:var(--text-md);margin:0 auto;padding:10px var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content p{margin:0 0 var(--space-sm) 0}.ai-chat-message.assistant .ai-chat-message-content p:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content h1{font-size:1.5em}.ai-chat-message.assistant .ai-chat-message-content h1,.ai-chat-message.assistant .ai-chat-message-content h2{color:var(--text-primary,#3e3e3e);font-weight:var(--font-weight-bold,700);line-height:var(--line-height-tight,1.3);margin:var(--space-md,16px) 0 var(--space-sm,8px) 0}.ai-chat-message.assistant .ai-chat-message-content h2{font-size:1.3em}.ai-chat-message.assistant .ai-chat-message-content h3{color:var(--text-primary,#3e3e3e);font-size:1.15em;font-weight:var(--font-weight-semibold,600);line-height:var(--line-height-tight,1.3);margin:var(--space-sm,8px) 0 var(--space-xs,4px) 0}.ai-chat-message.assistant .ai-chat-message-content h4,.ai-chat-message.assistant .ai-chat-message-content h5,.ai-chat-message.assistant .ai-chat-message-content h6{color:var(--text-primary,#3e3e3e);font-size:1em;font-weight:var(--font-weight-semibold,600);line-height:var(--line-height-tight,1.3);margin:var(--space-sm,8px) 0 var(--space-xs,4px) 0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h1,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h2,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h3,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h4,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h5,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h6{color:var(--text-primary,#fff)}.ai-chat-message.assistant .ai-chat-message-content>h1:first-child,.ai-chat-message.assistant .ai-chat-message-content>h2:first-child,.ai-chat-message.assistant .ai-chat-message-content>h3:first-child,.ai-chat-message.assistant .ai-chat-message-content>h4:first-child,.ai-chat-message.assistant .ai-chat-message-content>h5:first-child,.ai-chat-message.assistant .ai-chat-message-content>h6:first-child{margin-top:0}.ai-chat-message.assistant .ai-chat-message-content ul{list-style-type:disc;margin:var(--space-sm,8px) 0;padding-left:var(--space-lg,24px)}.ai-chat-message.assistant .ai-chat-message-content ul ul{list-style-type:circle;margin:var(--space-xs,4px) 0}.ai-chat-message.assistant .ai-chat-message-content ul ul ul{list-style-type:square}.ai-chat-message.assistant .ai-chat-message-content ol{list-style-type:decimal;margin:var(--space-sm,8px) 0;padding-left:var(--space-lg,24px)}.ai-chat-message.assistant .ai-chat-message-content ol ol{list-style-type:lower-alpha;margin:var(--space-xs,4px) 0}.ai-chat-message.assistant .ai-chat-message-content ol ol ol{list-style-type:lower-roman}.ai-chat-message.assistant .ai-chat-message-content li{margin-bottom:var(--space-xs,4px);padding-left:var(--space-xs,4px)}.ai-chat-message.assistant .ai-chat-message-content li:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content li>ol,.ai-chat-message.assistant .ai-chat-message-content li>ul{margin-top:var(--space-xs,4px)}.ai-chat-message.assistant .ai-chat-message-content code{background:rgba(0,0,0,.05);border-radius:var(--radius-sm);font-family:SF Mono,Monaco,Cascadia Code,monospace;font-size:.9em;padding:2px 6px}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content code{background:hsla(0,0%,100%,.1)}.ai-chat-message.assistant .ai-chat-message-content pre{background:rgba(0,0,0,.05);border-radius:var(--radius-md);margin:var(--space-sm) 0;overflow-x:auto;padding:var(--space-sm)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content pre{background:hsla(0,0%,100%,.05)}.ai-chat-message.assistant .ai-chat-message-content pre code{background:transparent;padding:0}.ai-chat-message.assistant .ai-chat-message-content a{color:var(--btn-primary-bg);text-decoration:underline}.ai-chat-message.assistant .ai-chat-message-content strong{font-weight:var(--font-weight-semibold)}.ai-chat-message.assistant .ai-chat-message-content blockquote{border-left:3px solid var(--border-default);color:var(--text-muted);margin:var(--space-sm) 0;padding-left:var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content hr{border:none;border-top:1px solid var(--border-subtle,rgba(0,0,0,.1));margin:var(--space-lg,24px) 0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content hr{border-top-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content .table-wrapper{border:1px solid var(--border-subtle,rgba(0,0,0,.1));border-radius:var(--radius-md,8px);box-sizing:border-box;display:block;margin:var(--space-sm) var(--space-sm);max-width:100%;overflow:hidden;width:auto}.ai-chat-message.assistant .ai-chat-message-content .table-scroll{max-width:100%;overflow-x:auto;overflow-y:hidden;width:100%}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content .table-wrapper{border-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content table{border-collapse:collapse;font-size:var(--text-sm);min-width:100%;width:max-content}.ai-chat-message.assistant .ai-chat-message-content td,.ai-chat-message.assistant .ai-chat-message-content th{border-bottom:1px solid var(--border-subtle,rgba(0,0,0,.1));border-right:1px solid var(--border-subtle,rgba(0,0,0,.1));padding:var(--space-sm);text-align:left}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content td,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content th{border-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content td:last-child,.ai-chat-message.assistant .ai-chat-message-content th:last-child{border-right:none}.ai-chat-message.assistant .ai-chat-message-content tr:last-child td{border-bottom:none}.ai-chat-message.assistant .ai-chat-message-content th{background:rgba(0,0,0,.03);font-weight:var(--font-weight-semibold);white-space:nowrap}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content th{background:hsla(0,0%,100%,.05)}.ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:rgba(0,0,0,.02)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:hsla(0,0%,100%,.03)}.ai-chat-message.assistant.streaming .ai-chat-message-content>ol:last-child>li:last-child,.ai-chat-message.assistant.streaming .ai-chat-message-content>p:last-child,.ai-chat-message.assistant.streaming .ai-chat-message-content>ul:last-child>li:last-child{animation:ai-chat-text-fade-in .3s ease-out}@keyframes ai-chat-text-fade-in{0%{opacity:0}to{opacity:1}}.ai-chat-suggested-questions{align-self:flex-end;margin:0;padding:16px 0 0;width:100%}.ai-chat-suggested-questions-list{align-items:center;display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.ai-chat-suggested-question{align-items:center;background:transparent;border:1px solid var(--border-default,#d4d4d8);border-radius:var(--radius-preset-badge,18px);color:var(--text-primary,#18181b);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:background .15s ease,border-color .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-widget.dark .ai-chat-suggested-question{background:transparent;border-color:var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}.ai-chat-suggested-question-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-suggested-question:hover{background:var(--bg-hover,#f4f4f5);border-color:var(--border-default,#d4d4d8)}.ai-chat-widget.dark .ai-chat-suggested-question:hover{background:var(--bg-hover,#3f3f46);border-color:var(--border-subtle,#52525b)}.ai-chat-suggested-question:active{transform:scale(.98)}.ai-chat-suggested-question.action-type{border:none}.ai-chat-suggested-question.action-type,.ai-chat-widget.dark .ai-chat-suggested-question.action-type{background:var(--primary-color,var(--button-color,#ef4444));color:var(--button-icon-color,#fff)}.ai-chat-suggested-question.action-type:hover{background:var(--primary-color,var(--button-color,#ef4444));opacity:.9}.ai-chat-suggested-question-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-suggested-question:not(.action-type) .ai-chat-suggested-question-icon{display:none}.ai-chat-widget-container.container-mode.trigger-input-bar .ai-chat-suggested-questions{box-sizing:border-box;margin:0;padding:16px 0 0;width:100%}.ai-chat-widget-container.container-mode.trigger-input-bar .ai-chat-suggested-questions-list{box-sizing:border-box;display:flex;flex-wrap:wrap;gap:6px}.ai-chat-widget-container.container-mode.trigger-input-bar.bottom-right .ai-chat-suggested-questions-list,.ai-chat-widget-container.container-mode.trigger-input-bar.top-right .ai-chat-suggested-questions-list{justify-content:flex-end;margin-left:auto;margin-right:0;padding-right:0}.ai-chat-widget-container.container-mode.trigger-input-bar.bottom-left .ai-chat-suggested-questions-list,.ai-chat-widget-container.container-mode.trigger-input-bar.top-left .ai-chat-suggested-questions-list{justify-content:flex-start;margin-left:0;margin-right:auto;padding-left:0}.ai-chat-widget-container.container-mode.trigger-input-bar.size-small .ai-chat-suggested-questions-list{max-width:calc(100% - 132px);width:348px}.ai-chat-widget-container.container-mode.trigger-input-bar.size-medium .ai-chat-suggested-questions-list{max-width:calc(100% - 132px);width:408px}.ai-chat-widget-container.container-mode.trigger-input-bar.size-large .ai-chat-suggested-questions-list{max-width:calc(100% - 132px);width:528px}.ai-chat-follow-up-suggestions{box-sizing:border-box;margin:0;padding:8px 16px 0;width:100%}.ai-chat-follow-up-list{align-items:flex-end;display:flex;flex-direction:column;gap:6px}.ai-chat-follow-up-item{align-items:center;animation:followUpFadeIn .25s ease-out forwards;background:var(--primary-color,var(--button-color,#07f));border:none;border-radius:var(--radius-preset-badge,18px);color:var(--button-icon-color,#fff);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;white-space:nowrap}@keyframes followUpFadeIn{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.ai-chat-widget.dark .ai-chat-follow-up-item{background:var(--primary-color,var(--button-color,#07f));color:var(--button-icon-color,#fff)}.ai-chat-follow-up-item:hover{opacity:.9}.ai-chat-follow-up-item:active{transform:scale(.98)}.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-default,#d4d4d8);color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type,.dark .ai-chat-follow-up-item.question-type,[data-color-mode=dark] .ai-chat-follow-up-item.question-type,[data-theme=dark] .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}}.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#f4f4f5);opacity:1}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type:hover,.dark .ai-chat-follow-up-item.question-type:hover,[data-color-mode=dark] .ai-chat-follow-up-item.question-type:hover,[data-theme=dark] .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}}.ai-chat-follow-up-item.action-type{background:var(--primary-color,var(--button-color,#07f));border:none;color:var(--button-icon-color,#fff)}.ai-chat-follow-up-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-follow-up-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-feedback-buttons{align-items:center;display:flex;gap:var(--space-xs)}.ai-chat-feedback{align-items:center;display:inline-flex;gap:0;height:20px}.ai-chat-feedback-button{align-items:center;background:transparent!important;border:none;border-radius:var(--radius-sm);color:var(--text-placeholder);cursor:pointer;display:flex;font-size:var(--text-sm);height:20px;justify-content:center;padding:var(--space-xs);transition:all var(--duration-fast) var(--spring-bounce)}.ai-chat-feedback-button:hover:not(:disabled){background:none!important;color:var(--text-secondary)}.ai-chat-feedback-button:active:not(:disabled){transform:scale(.9)}.ai-chat-feedback-button:disabled{cursor:not-allowed;opacity:.4}.ai-chat-feedback-button.active{background:none!important;color:var(--text-primary)}.ai-chat-feedback.submitted{align-items:center;animation:ai-chat-feedback-morph .3s var(--spring-bounce);gap:var(--space-xs)}.ai-chat-feedback-message{align-items:center;display:flex;gap:4px;margin-left:var(--space-xxs)}.ai-chat-feedback-checkmark{animation:ai-chat-checkmark-pop .3s var(--spring-bounce);color:#10b981;font-size:var(--text-md);font-weight:700}.ai-chat-feedback-text{color:#10b981;font-size:var(--text-xs);font-weight:var(--font-weight-medium)}.ai-chat-history-panel{background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;overflow:hidden}.ai-chat-widget.dark .ai-chat-history-panel{background:var(--bg-primary,#18181b)}.ai-chat-history-empty,.ai-chat-history-loading{align-items:center;color:var(--text-muted);display:flex;flex:1;font-size:var(--text-sm);justify-content:center;padding:var(--space-lg);text-align:center}.ai-chat-history-list{-ms-overflow-style:none;display:flex;flex:1;flex-direction:column;gap:var(--space-sm);overflow-y:auto;padding:var(--space-xs) var(--space-md) 120px;scrollbar-width:none}.ai-chat-history-list::-webkit-scrollbar{display:none}.ai-chat-history-list.exiting{animation:ai-chat-history-exit .22s var(--spring-smooth) forwards}.ai-chat-history-item{align-items:center;background:var(--user-bg,#f4f4f5);border-radius:var(--radius-history-item,15px);display:flex;flex:0 0 auto;flex-direction:row;height:var(--history-item-height,36px);margin:0;overflow:hidden;transition:background var(--duration-fast,.15s) ease;width:100%}.ai-chat-history-item-content{align-items:center;background:transparent;border:none;cursor:pointer;display:flex;flex:1;flex-direction:row;height:100%;min-width:0;padding:0 var(--space-xs,4px) 0 var(--space-md,16px);text-align:left}.ai-chat-widget.dark .ai-chat-history-item{background:var(--user-bg,#27272a)}.ai-chat-history-item:hover{background:var(--user-bg-hover,#e5e7eb)}.ai-chat-widget.dark .ai-chat-history-item:hover{background:var(--user-bg-hover,#3f3f46)}.ai-chat-history-item.active{background:var(--user-bg-hover,#e5e7eb)}.ai-chat-widget.dark .ai-chat-history-item.active{background:var(--user-bg-hover,#3f3f46)}.ai-chat-history-item-preview{color:var(--text-primary,#18181b);flex:1;font-size:var(--text-sm,14px);font-weight:var(--font-weight-medium,500);line-height:var(--line-height-normal,1.4);margin-bottom:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-widget.dark .ai-chat-history-item-preview{color:var(--text-primary,#fafafa)}.ai-chat-history-item.active .ai-chat-history-item-preview{font-weight:var(--font-weight-medium)}.ai-chat-history-item-meta{display:none}.ai-chat-history-item-delete{align-items:center;background:transparent;border:none;border-radius:var(--radius-sm,6px);color:var(--text-muted,#71717a);cursor:pointer;display:flex;flex-shrink:0;height:24px;justify-content:center;margin-left:auto;margin-right:var(--space-xs,4px);opacity:0;transition:opacity var(--duration-fast,.15s) ease,background var(--duration-fast,.15s) ease,color var(--duration-fast,.15s) ease;width:24px}.ai-chat-history-item-delete svg{height:14px;width:14px}.ai-chat-history-item:hover .ai-chat-history-item-delete{opacity:1}.ai-chat-history-item-delete:hover{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-widget.dark .ai-chat-history-item-delete:hover{background:rgba(239,68,68,.2);color:#f87171}.ai-chat-tool-row{align-items:center;display:flex;gap:10px;margin:2px 0;padding:0}.ai-chat-tool-gear{color:#1f2937;flex-shrink:0;height:20px;width:20px}.ai-chat-tool-gear.spinning{animation:ai-chat-gear-spin 1.5s linear infinite}.ai-chat-tool-badges{align-items:center;display:flex;flex-wrap:wrap;gap:8px}.ai-chat-tool-badge{align-items:center;background:#e5e7eb;border:1px solid #d1d5db;border-radius:var(--radius-action-badge,8px);color:#1f2937;display:inline-flex;font-size:12px;font-weight:500;gap:4px;line-height:1.2;padding:5px 12px;transition:all .2s ease;white-space:nowrap}.ai-chat-tool-badge.loading{animation:ai-chat-tool-gradient 2s linear infinite;background:linear-gradient(90deg,var(--tool-loading-bg-1,#e0e0e0) 0,var(--tool-loading-bg-2,#f0f0f0) 25%,var(--tool-loading-bg-3,#fff) 50%,var(--tool-loading-bg-2,#f0f0f0) 75%,var(--tool-loading-bg-1,#e0e0e0) 100%);background-size:200% 100%;color:var(--tool-loading-text,#1a1a1a);position:relative}.ai-chat-widget:not(.dark) .ai-chat-tool-badge.loading{--tool-loading-bg-1:#2a2a2a;--tool-loading-bg-2:#3a3a3a;--tool-loading-bg-3:#4a4a4a;--tool-loading-text:#fff}.ai-chat-tool-badge.completed{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.chakra-ui-dark .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.chakra-ui-dark .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.ai-chat-tool-badge.error{background:var(--tool-error-bg,rgba(239,68,68,.15));color:var(--tool-error-text,#ef4444)}.ai-chat-tool-badge .ai-chat-tool-check{color:#fff;flex-shrink:0}.ai-chat-tool-badge .ai-chat-tool-error{color:#ef4444;flex-shrink:0}.tool-name{font-weight:500;line-height:1.2;white-space:nowrap}.ai-chat-tool-action{box-sizing:border-box;padding:0;width:100%}@keyframes ai-chat-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.ai-chat-action-skeleton-item{animation:ai-chat-skeleton-pulse 1.5s ease-in-out infinite;background:var(--bg-secondary,#e5e7eb)}.ai-chat-widget.dark .ai-chat-action-skeleton-item,.chakra-ui-dark .ai-chat-action-skeleton-item,.dark .ai-chat-action-skeleton-item,[data-theme=dark] .ai-chat-action-skeleton-item{background:hsla(0,0%,100%,.1)}.ai-chat-action-skeleton-content{display:flex;flex-direction:column;gap:16px}.ai-chat-action-skeleton-header{align-items:center;display:flex;gap:10px}.ai-chat-action-skeleton-box{background:rgba(0,0,0,.08);border-radius:10px;display:flex;flex-direction:column;gap:8px;padding:14px}.ai-chat-widget.dark .ai-chat-action-skeleton-box,.chakra-ui-dark .ai-chat-action-skeleton-box,.dark .ai-chat-action-skeleton-box,[data-theme=dark] .ai-chat-action-skeleton-box{background:rgba(0,0,0,.25)}.ai-chat-action-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f9fafb);border:1px solid var(--border-subtle,rgba(0,0,0,.06));border-radius:12px;box-sizing:border-box;margin-top:4px;padding:16px;transition:all .2s ease;width:100%}.ai-chat-widget.dark .ai-chat-action-card,.chakra-ui-dark .ai-chat-action-card,.dark .ai-chat-action-card,[data-theme=dark] .ai-chat-action-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-action-booked{background:var(--bg-secondary,#f9fafb);border:1px solid var(--border-subtle,rgba(0,0,0,.06))}.ai-chat-widget.dark .ai-chat-action-booked,.chakra-ui-dark .ai-chat-action-booked,.dark .ai-chat-action-booked,[data-theme=dark] .ai-chat-action-booked{background:var(--bg-secondary,#3a3a3a)}.ai-chat-action-header{align-items:center;color:var(--text-primary,#3e3e3e);display:flex;font-size:var(--text-md,15px);font-weight:var(--font-weight-semibold,600);gap:var(--space-sm,8px);margin-bottom:var(--space-md,16px)}.ai-chat-widget.dark .ai-chat-action-header,.chakra-ui-dark .ai-chat-action-header,.dark .ai-chat-action-header,[data-theme=dark] .ai-chat-action-header{color:var(--text-primary,#fff)}.ai-chat-action-icon{color:var(--action-accent,var(--primary-color,#3b82f6));flex-shrink:0;height:20px;width:20px}.ai-chat-action-success-icon-wrapper{align-items:center;background:var(--action-accent,var(--primary-color,#22c55e));border-radius:50%;color:#fff;display:flex;flex-shrink:0;height:24px;justify-content:center;width:24px}.ai-chat-action-icon-success{color:currentColor;height:14px;width:14px}.ai-chat-action-detail-box{background:var(--bg-primary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-md,8px);display:flex;flex-direction:column;gap:4px;padding:12px 16px}.ai-chat-widget.dark .ai-chat-action-detail-box,.chakra-ui-dark .ai-chat-action-detail-box,.dark .ai-chat-action-detail-box,[data-theme=dark] .ai-chat-action-detail-box{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.05)}.ai-chat-action-label-small{color:var(--text-muted,#71717a);font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.ai-chat-action-value-large{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:500}.ai-chat-widget.dark .ai-chat-action-value-large,.chakra-ui-dark .ai-chat-action-value-large,.dark .ai-chat-action-value-large,[data-theme=dark] .ai-chat-action-value-large{color:#fff}.ai-chat-action-body{display:flex;flex-direction:column;gap:var(--space-md,16px)}.ai-chat-action-close-btn{align-items:center;background:transparent;border:none;border-radius:6px;color:var(--ai-chat-fg-muted,#6b7280);cursor:pointer;display:flex;height:28px;justify-content:center;padding:0;position:absolute;right:12px;top:12px;transition:all .15s ease;width:28px;z-index:10}.ai-chat-action-close-btn:hover{background:var(--ai-chat-bg-muted,#f3f4f6);color:var(--ai-chat-fg,#1f2937)}.ai-chat-action-close-btn:active{transform:scale(.95)}.ai-chat-action-close-btn:focus-visible{outline:2px solid var(--ai-chat-accent,#2563eb);outline-offset:2px}.ai-chat-action-card--closable,.ai-chat-form-card--closable{position:relative}.ai-chat-action-card--closable .ai-chat-action-header,.ai-chat-form-card--closable .ai-chat-form-card__header{padding-right:40px}.ai-chat-widget.dark .ai-chat-action-close-btn:hover,.chakra-ui-dark .ai-chat-action-close-btn:hover,.dark .ai-chat-action-close-btn:hover,[data-theme=dark] .ai-chat-action-close-btn:hover{background:hsla(0,0%,100%,.1);color:var(--ai-chat-fg,#f3f4f6)}.ai-chat-action-field{display:flex;flex-direction:column;gap:var(--space-xs,6px)}.ai-chat-action-label{color:var(--text-secondary,#6b7280);font-size:var(--text-sm,13px);font-weight:var(--font-weight-medium,500)}.ai-chat-widget.dark .ai-chat-action-label,.chakra-ui-dark .ai-chat-action-label,.dark .ai-chat-action-label,[data-theme=dark] .ai-chat-action-label{color:var(--text-secondary,#a1a1aa)}.ai-chat-action-input{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);font-size:var(--text-sm,13px);outline:none;padding:10px 12px;transition:border-color .2s ease,box-shadow .2s ease}.ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-action-input::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-action-input,.chakra-ui-dark .ai-chat-action-input,.dark .ai-chat-action-input,[data-theme=dark] .ai-chat-action-input{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-input:focus,.chakra-ui-dark .ai-chat-action-input:focus,.dark .ai-chat-action-input:focus,[data-theme=dark] .ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-action-button{background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;color:#fff;cursor:pointer;font-size:var(--text-sm,13px);font-weight:var(--font-weight-semibold,600);padding:12px 16px;transition:all .2s ease;width:100%}.ai-chat-action-button:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}.ai-chat-action-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-action-link-button{align-items:center;background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;box-sizing:border-box;color:#fff;display:flex;font-size:14px;font-weight:600;gap:6px;justify-content:center;margin-top:8px;padding:12px;text-decoration:none;transition:all .2s ease;width:100%}.ai-chat-action-link-button:hover{opacity:.9;transform:translateY(-1px)}.ai-chat-action-error{background:rgba(239,68,68,.1);border-radius:var(--radius-md,8px);color:#dc2626;font-size:var(--text-sm,13px);padding:10px 12px}.ai-chat-widget.dark .ai-chat-action-error,.chakra-ui-dark .ai-chat-action-error,.dark .ai-chat-action-error,[data-theme=dark] .ai-chat-action-error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-action-hint{color:var(--text-muted,#9ca3af);font-size:var(--text-sm,13px);padding:var(--space-sm,8px);text-align:center}@media (max-width:480px){.ai-chat-action-card{padding:12px}.ai-chat-action-header{font-size:var(--text-sm,14px);margin-bottom:var(--space-sm,12px)}.ai-chat-action-button{font-size:13px;padding:10px 14px}.ai-chat-action-link-button{font-size:13px;padding:10px}}.ai-chat-link-preview{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-lg,12px);cursor:pointer;display:flex;flex-direction:column;margin-top:4px;overflow:hidden;padding:0!important;position:relative;transition:border-color .2s,box-shadow .2s,transform .2s}.ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 8px rgba(0,0,0,.1);transform:translateY(-1px)}.ai-chat-link-preview:focus{border-color:var(--action-accent);box-shadow:0 0 0 2px rgba(59,130,246,.2);outline:none}.ai-chat-widget.dark .ai-chat-link-preview,.chakra-ui-dark .ai-chat-link-preview,.dark .ai-chat-link-preview,[data-theme=dark] .ai-chat-link-preview{background:var(--bg-secondary,#3a3a3a);border-color:hsla(0,0%,100%,.08)}.ai-chat-widget.dark .ai-chat-link-preview:hover,.chakra-ui-dark .ai-chat-link-preview:hover,.dark .ai-chat-link-preview:hover,[data-theme=dark] .ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 12px rgba(0,0,0,.3)}.ai-chat-link-preview__image{aspect-ratio:1.91/1;background:var(--bg-muted,#e5e7eb);overflow:hidden;width:100%}.ai-chat-widget.dark .ai-chat-link-preview__image,.chakra-ui-dark .ai-chat-link-preview__image,.dark .ai-chat-link-preview__image,[data-theme=dark] .ai-chat-link-preview__image{background:hsla(0,0%,100%,.05)}.ai-chat-link-preview__image img{height:100%;object-fit:cover;width:100%}.ai-chat-link-preview__content{flex:1;padding:8px 10px}.ai-chat-link-preview__site{align-items:center;display:flex;gap:6px;margin-bottom:6px}.ai-chat-link-preview__favicon{border-radius:2px;flex-shrink:0;height:16px;width:16px}.ai-chat-link-preview__domain{color:var(--text-muted,#71717a);font-size:12px;letter-spacing:.5px;overflow:hidden;text-overflow:ellipsis;text-transform:uppercase;white-space:nowrap}.ai-chat-link-preview__title{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-primary,#3e3e3e);display:-webkit-box;font-size:15px;font-weight:600;line-height:1.3;margin:0 0 4px;overflow:hidden}.ai-chat-widget.dark .ai-chat-link-preview__title,.chakra-ui-dark .ai-chat-link-preview__title,.dark .ai-chat-link-preview__title,[data-theme=dark] .ai-chat-link-preview__title{color:#fff}.ai-chat-link-preview__description{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-muted,#71717a);display:-webkit-box;font-size:13px;line-height:1.4;margin:0;overflow:hidden}.ai-chat-link-preview__context{border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin:8px 0 0;padding-top:8px}.ai-chat-widget.dark .ai-chat-link-preview__context,.chakra-ui-dark .ai-chat-link-preview__context,.dark .ai-chat-link-preview__context,[data-theme=dark] .ai-chat-link-preview__context{border-color:hsla(0,0%,100%,.08)}.ai-chat-link-preview__arrow{align-items:center;background:var(--bg-primary,#fff);border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.1);color:var(--text-muted,#71717a);display:flex;height:28px;justify-content:center;opacity:0;position:absolute;right:12px;top:12px;transition:opacity .2s,background .2s;width:28px}.ai-chat-link-preview:hover .ai-chat-link-preview__arrow{opacity:1}.ai-chat-widget.dark .ai-chat-link-preview__arrow,.chakra-ui-dark .ai-chat-link-preview__arrow,.dark .ai-chat-link-preview__arrow,[data-theme=dark] .ai-chat-link-preview__arrow{background:hsla(0,0%,100%,.1);color:#fff}.ai-chat-link-preview--error{border-color:rgba(239,68,68,.3)}.ai-chat-link-preview--error:hover{border-color:rgba(239,68,68,.5)}.ai-chat-link-preview__error-text{color:#dc2626;font-size:12px;margin:4px 0 0}.ai-chat-widget.dark .ai-chat-link-preview__error-text,.chakra-ui-dark .ai-chat-link-preview__error-text,.dark .ai-chat-link-preview__error-text,[data-theme=dark] .ai-chat-link-preview__error-text{color:#fca5a5}.ai-chat-link-preview-grid{display:grid;gap:12px}.ai-chat-link-preview-grid--single{grid-template-columns:1fr}.ai-chat-link-preview-grid--double{grid-template-columns:repeat(2,1fr)}.ai-chat-link-preview-grid--triple{grid-template-columns:repeat(3,1fr)}@media (max-width:768px){.ai-chat-link-preview-grid--triple{grid-template-columns:repeat(2,1fr)}}@media (max-width:480px){.ai-chat-link-preview-grid--double,.ai-chat-link-preview-grid--triple{grid-template-columns:1fr}}.ai-chat-video-player{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border-radius:var(--radius-lg,12px);display:flex;flex-direction:column;gap:0;margin-top:4px;overflow:hidden;padding:0!important}.ai-chat-widget.dark .ai-chat-video-player,.chakra-ui-dark .ai-chat-video-player,.dark .ai-chat-video-player,[data-theme=dark] .ai-chat-video-player{background:var(--bg-secondary,#3a3a3a)}.ai-chat-video-player__header{align-items:center;color:var(--action-accent,var(--primary-color,#3b82f6));display:flex;gap:8px}.ai-chat-video-player__title{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:600}.ai-chat-widget.dark .ai-chat-video-player__title,.chakra-ui-dark .ai-chat-video-player__title,.dark .ai-chat-video-player__title,[data-theme=dark] .ai-chat-video-player__title{color:#fff}.ai-chat-video-player__container{aspect-ratio:16/9;background:#000;border-radius:8px;overflow:hidden;position:relative;width:100%}.ai-chat-video-player__thumbnail{cursor:pointer;height:100%;position:relative;width:100%}.ai-chat-video-player__thumbnail img{height:100%;object-fit:cover;width:100%}.ai-chat-video-player__placeholder{align-items:center;background:linear-gradient(135deg,#1a1a2e,#16213e);cursor:pointer;display:flex;flex-direction:column;gap:8px;height:100%;justify-content:center;position:relative;width:100%}.ai-chat-video-player__click-text{color:hsla(0,0%,100%,.7);font-size:13px}.ai-chat-video-player__play-btn{align-items:center;background:rgba(0,0,0,.7);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:64px;justify-content:center;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s,transform .2s;width:64px}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn{left:auto;position:relative;top:auto;transform:none}.ai-chat-video-player__play-btn:hover{background:rgba(0,0,0,.9);transform:translate(-50%,-50%) scale(1.05)}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn:hover{transform:scale(1.05)}.ai-chat-video-player__provider-badge{background:rgba(0,0,0,.8);border-radius:4px;bottom:8px;color:#fff;font-size:11px;font-weight:600;letter-spacing:.5px;padding:4px 8px;position:absolute;right:8px;text-transform:uppercase}.ai-chat-video-player__iframe,.ai-chat-video-player__video{border:none;height:100%;left:0;position:absolute;top:0;width:100%}.ai-chat-video-player__error{align-items:center;background:rgba(239,68,68,.1);color:#dc2626;display:flex;font-size:13px;height:100%;justify-content:center;padding:16px;text-align:center;width:100%}.ai-chat-widget.dark .ai-chat-video-player__error,.chakra-ui-dark .ai-chat-video-player__error,.dark .ai-chat-video-player__error,[data-theme=dark] .ai-chat-video-player__error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-video-player__context{color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin-top:4px;padding:8px 12px 12px}@media (max-width:480px){.ai-chat-video-player__play-btn{height:56px;width:56px}.ai-chat-video-player__provider-badge{font-size:10px;padding:3px 6px}}.ai-chat-location-card{background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:12px;overflow:hidden;padding:0}.ai-chat-widget.dark .ai-chat-location-card,.chakra-ui-dark .ai-chat-location-card,.dark .ai-chat-location-card,[data-theme=dark] .ai-chat-location-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-location-card--compact{border-radius:10px}.ai-chat-location-card--error{color:var(--text-muted,#71717a);padding:16px;text-align:center}.ai-chat-location-card__map{background:var(--bg-muted,#f4f4f5);position:relative;width:100%}.ai-chat-widget.dark .ai-chat-location-card__map,.chakra-ui-dark .ai-chat-location-card__map,.dark .ai-chat-location-card__map,[data-theme=dark] .ai-chat-location-card__map{background:rgba(0,0,0,.2)}.ai-chat-location-card__map iframe{border:none;display:block;height:100%;width:100%}.ai-chat-location-card__content{padding:12px}.ai-chat-location-card--compact .ai-chat-location-card__content{padding:10px}.ai-chat-location-card__header{align-items:center;display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.ai-chat-location-card__name{color:var(--text-primary,#18181b);flex:1;font-size:16px;font-weight:600;margin:0;min-width:0}.ai-chat-widget.dark .ai-chat-location-card__name,.chakra-ui-dark .ai-chat-location-card__name,.dark .ai-chat-location-card__name,[data-theme=dark] .ai-chat-location-card__name{color:#fff}.ai-chat-location-card--compact .ai-chat-location-card__name{font-size:14px}.ai-chat-location-card__type{background:var(--bg-muted,#f4f4f5);border-radius:10px;color:var(--text-muted,#71717a);font-size:11px;font-weight:500;letter-spacing:.5px;padding:2px 8px;text-transform:uppercase}.ai-chat-widget.dark .ai-chat-location-card__type,.chakra-ui-dark .ai-chat-location-card__type,.dark .ai-chat-location-card__type,[data-theme=dark] .ai-chat-location-card__type{background:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.7)}.ai-chat-location-card__status{border-radius:12px;font-size:12px;font-weight:500;padding:2px 8px}.ai-chat-location-card__status--open{background:#dcfce7;color:#16a34a}.ai-chat-location-card__status--closed{background:#fef2f2;color:#dc2626}.ai-chat-widget.dark .ai-chat-location-card__status--open,.chakra-ui-dark .ai-chat-location-card__status--open,.dark .ai-chat-location-card__status--open,[data-theme=dark] .ai-chat-location-card__status--open{background:rgba(34,197,94,.2);color:#4ade80}.ai-chat-widget.dark .ai-chat-location-card__status--closed,.chakra-ui-dark .ai-chat-location-card__status--closed,.dark .ai-chat-location-card__status--closed,[data-theme=dark] .ai-chat-location-card__status--closed{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-location-card__address{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__address svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__hours{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;margin-bottom:8px}.ai-chat-location-card__hours svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__hours-list{flex:1}.ai-chat-location-card__hours-toggle{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;font:inherit;gap:4px;padding:0}.ai-chat-location-card__hours-toggle:hover{text-decoration:underline}.ai-chat-location-card__hours-full{list-style:none;margin:8px 0 0;padding:0}.ai-chat-location-card__hours-full li{display:flex;font-size:12px;justify-content:space-between;padding:4px 0}.ai-chat-location-card__hours-today{color:var(--text-primary,#18181b);font-weight:600}.ai-chat-widget.dark .ai-chat-location-card__hours-today,.chakra-ui-dark .ai-chat-location-card__hours-today,.dark .ai-chat-location-card__hours-today,[data-theme=dark] .ai-chat-location-card__hours-today{color:#fff}.ai-chat-location-card__phone{align-items:center;background:none;border:none;color:var(--action-accent,#3b82f6);cursor:pointer;display:flex;font-size:13px;gap:6px;margin-bottom:12px;padding:0}.ai-chat-location-card__phone:hover{text-decoration:underline}.ai-chat-location-card__actions{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-start;width:100%}@media (max-width:380px){.ai-chat-location-card__actions{flex-direction:column}.ai-chat-location-card__button,.ai-chat-location-card__link{flex:none;justify-content:center;width:100%}}.ai-chat-location-card__button{align-items:center;background:var(--action-accent,#3b82f6);border:none;border-radius:20px;color:#fff;cursor:pointer;display:flex;flex:1;font-size:13px;font-weight:500;gap:6px;justify-content:center;padding:10px 16px;transition:opacity .2s}.ai-chat-location-card__button:hover{opacity:.9}.ai-chat-location-card--compact .ai-chat-location-card__button{font-size:12px;padding:8px 12px}.ai-chat-location-card__link{align-items:center;background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:20px;color:var(--text-primary,#18181b);display:flex;font-size:13px;gap:6px;padding:10px 16px;text-decoration:none;transition:border-color .2s}.ai-chat-widget.dark .ai-chat-location-card__link,.chakra-ui-dark .ai-chat-location-card__link,.dark .ai-chat-location-card__link,[data-theme=dark] .ai-chat-location-card__link{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-location-card__link:hover{border-color:var(--action-accent,#3b82f6)}.ai-chat-location-card-list{display:flex;flex-direction:column;gap:8px}.ai-chat-location-card-list__header{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:13px;font-weight:500;gap:6px;margin-bottom:4px;padding:0 4px}.ai-chat-location-card-list__stack{display:grid;gap:12px;grid-template-columns:1fr}.ai-chat-location-card-list__stack--cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ai-chat-location-card-list__stack--cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}@media (max-width:1000px){.ai-chat-location-card-list__stack--cols-3{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:640px){.ai-chat-location-card-list__stack--cols-2,.ai-chat-location-card-list__stack--cols-3{grid-template-columns:1fr}}.ai-chat-location-card-list__grid{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}@media (max-width:400px){.ai-chat-location-card-list__grid{grid-template-columns:1fr}}.ai-chat-location-card-list__carousel{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;scroll-snap-type:x mandatory;scrollbar-width:none}.ai-chat-location-card-list__carousel::-webkit-scrollbar{display:none}.ai-chat-location-card-list__carousel>.ai-chat-location-card{flex:0 0 280px;scroll-snap-align:start}@media (max-width:480px){.ai-chat-location-card__content{padding:10px}.ai-chat-location-card__name{font-size:14px}.ai-chat-location-card__address,.ai-chat-location-card__description,.ai-chat-location-card__hours{font-size:12px}.ai-chat-location-card__button,.ai-chat-location-card__link{font-size:12px;padding:8px 12px}.ai-chat-location-card-list__carousel>.ai-chat-location-card{flex:0 0 240px}}.ai-chat-contact-card{background:#fff;border:1px solid rgba(0,0,0,.08);border-radius:16px;overflow:hidden;padding:0;position:relative}.ai-chat-widget.dark .ai-chat-contact-card,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card,.chakra-ui-dark .ai-chat-contact-card,.dark .ai-chat-contact-card,[data-theme=dark] .ai-chat-contact-card,html.dark .ai-chat-contact-card{background:#4a4a4a;border-color:hsla(0,0%,100%,.08)}.ai-chat-contact-card-list{gap:12px;width:100%}.ai-chat-contact-card--compact{border-radius:12px}.ai-chat-contact-card--empty{align-items:center;background:var(--bg-secondary,#f4f4f5);display:flex;flex-direction:column;gap:8px;justify-content:center;padding:24px 16px;text-align:center}.ai-chat-widget.dark .ai-chat-contact-card--empty,.chakra-ui-dark .ai-chat-contact-card--empty,.dark .ai-chat-contact-card--empty,[data-theme=dark] .ai-chat-contact-card--empty{background:#3a3a3a}.ai-chat-contact-card__empty-icon{color:var(--text-muted,#71717a);opacity:.6}.ai-chat-contact-card__empty-text{color:var(--text-muted,#71717a);font-size:14px;margin:0}.ai-chat-contact-card--vertical{display:flex;flex-direction:column}.ai-chat-contact-card--vertical .ai-chat-contact-card__image-section{aspect-ratio:3/2;overflow:hidden;width:100%}.ai-chat-contact-card--vertical .ai-chat-contact-card__image{height:100%;object-fit:cover;width:100%}.ai-chat-contact-card--vertical .ai-chat-contact-card__image-placeholder{align-items:center;background:linear-gradient(135deg,#5a5a5a,#3a3a3a);color:hsla(0,0%,100%,.5);display:flex;height:100%;justify-content:center;width:100%}.ai-chat-contact-card--vertical .ai-chat-contact-card__image-placeholder svg{height:48px;width:48px}.ai-chat-contact-card--vertical .ai-chat-contact-card__info{padding:16px;text-align:center}.ai-chat-contact-card--horizontal{display:flex;flex-direction:row}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-section{height:160px;min-width:140px;overflow:hidden;width:140px}.ai-chat-contact-card--horizontal.ai-chat-contact-card--compact .ai-chat-contact-card__image-section{height:120px;min-width:100px;width:100px}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image{height:100%;object-fit:cover;width:100%}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-placeholder{align-items:center;background:linear-gradient(135deg,#5a5a5a,#3a3a3a);color:hsla(0,0%,100%,.5);display:flex;height:100%;justify-content:center;width:100%}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-placeholder svg{height:36px;width:36px}.ai-chat-contact-card--horizontal .ai-chat-contact-card__info{display:flex;flex:1;flex-direction:column;justify-content:center;padding:16px}.ai-chat-contact-card__name{color:var(--action-accent,#ef4444);font-size:18px;font-weight:600;line-height:1.3;margin:0}.ai-chat-contact-card--compact .ai-chat-contact-card__name{font-size:15px}.ai-chat-contact-card__role{color:rgba(0,0,0,.7);font-size:14px;font-weight:400;margin:2px 0 0}.ai-chat-widget.dark .ai-chat-contact-card__role,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__role,.chakra-ui-dark .ai-chat-contact-card__role,.dark .ai-chat-contact-card__role,[data-theme=dark] .ai-chat-contact-card__role,html.dark .ai-chat-contact-card__role{color:hsla(0,0%,100%,.9)}.ai-chat-contact-card--compact .ai-chat-contact-card__role{font-size:13px}.ai-chat-contact-card__details{display:flex;flex-direction:column;gap:2px;margin-top:12px}.ai-chat-contact-card__detail{color:rgba(0,0,0,.6);display:block;font-size:14px;line-height:1.5;margin:0;text-decoration:none}.ai-chat-contact-card__detail:hover{color:#000;text-decoration:underline}.ai-chat-widget.dark .ai-chat-contact-card__detail,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__detail,.chakra-ui-dark .ai-chat-contact-card__detail,.dark .ai-chat-contact-card__detail,[data-theme=dark] .ai-chat-contact-card__detail,html.dark .ai-chat-contact-card__detail{color:hsla(0,0%,100%,.7)}.ai-chat-widget.dark .ai-chat-contact-card__detail:hover,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__detail:hover,.chakra-ui-dark .ai-chat-contact-card__detail:hover,.dark .ai-chat-contact-card__detail:hover,[data-theme=dark] .ai-chat-contact-card__detail:hover,html.dark .ai-chat-contact-card__detail:hover{color:#fff}.ai-chat-contact-card--compact .ai-chat-contact-card__detail{font-size:13px}.ai-chat-contact-card__responsibilities{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}.ai-chat-contact-card__responsibility-tag{background:rgba(0,0,0,.08);border-radius:10px;color:rgba(0,0,0,.8);font-size:11px;font-weight:500;padding:3px 10px}.ai-chat-widget.dark .ai-chat-contact-card__responsibility-tag,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__responsibility-tag,.chakra-ui-dark .ai-chat-contact-card__responsibility-tag,.dark .ai-chat-contact-card__responsibility-tag,[data-theme=dark] .ai-chat-contact-card__responsibility-tag,html.dark .ai-chat-contact-card__responsibility-tag{background:hsla(0,0%,100%,.15);color:hsla(0,0%,100%,.9)}.ai-chat-contact-card__responsibility-more{color:rgba(0,0,0,.5);font-size:11px;padding:3px 4px}.ai-chat-widget.dark .ai-chat-contact-card__responsibility-more,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__responsibility-more,.chakra-ui-dark .ai-chat-contact-card__responsibility-more,.dark .ai-chat-contact-card__responsibility-more,[data-theme=dark] .ai-chat-contact-card__responsibility-more,html.dark .ai-chat-contact-card__responsibility-more{color:hsla(0,0%,100%,.5)}.ai-chat-contact-card__actions{display:flex;flex-wrap:wrap;gap:8px;padding:0 12px 12px}@media (max-width:380px){.ai-chat-contact-card__actions{flex-direction:column}.ai-chat-contact-card__button{flex:none;width:100%}}.ai-chat-contact-card--compact .ai-chat-contact-card__actions{gap:6px;padding:0 10px 10px}.ai-chat-contact-card__button{align-items:center;border:none;border-radius:9999px;cursor:pointer;display:flex;font-size:14px;font-weight:600;gap:8px;justify-content:center;padding:12px 20px;transition:all .15s ease;white-space:nowrap}.ai-chat-contact-card--compact .ai-chat-contact-card__button{font-size:13px;padding:10px 16px}.ai-chat-contact-card__button:hover{box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.ai-chat-contact-card__button:active{transform:translateY(0)}.ai-chat-contact-card__button--primary{background:var(--action-accent,#3b82f6);color:#fff;flex:1}.ai-chat-contact-card__button--primary:hover{background:color-mix(in srgb,var(--action-accent,#3b82f6) 90%,#000)}.ai-chat-contact-card__button--secondary{background:var(--bg-muted,#f4f4f5);border:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-primary,#18181b);flex:1}.ai-chat-contact-card__button--secondary:hover{background:var(--bg-hover,#e4e4e7)}.ai-chat-widget.dark .ai-chat-contact-card__button--secondary,.chakra-ui-dark .ai-chat-contact-card__button--secondary,.dark .ai-chat-contact-card__button--secondary,[data-theme=dark] .ai-chat-contact-card__button--secondary{background:hsla(0,0%,100%,.1);border-color:hsla(0,0%,100%,.15);color:#fff}.ai-chat-widget.dark .ai-chat-contact-card__button--secondary:hover,.chakra-ui-dark .ai-chat-contact-card__button--secondary:hover,.dark .ai-chat-contact-card__button--secondary:hover,[data-theme=dark] .ai-chat-contact-card__button--secondary:hover{background:hsla(0,0%,100%,.15)}.ai-chat-contact-card-list{display:flex;flex-direction:column;gap:8px}.ai-chat-contact-card-list__header{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:13px;font-weight:500;gap:6px;margin-bottom:2px;margin-top:8px;padding:0 4px}.ai-chat-contact-card-list__stack{display:grid;gap:12px;grid-template-columns:repeat(3,minmax(0,1fr))}@media (max-width:900px){.ai-chat-contact-card-list__stack{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:600px){.ai-chat-contact-card-list__stack{grid-template-columns:1fr}}.ai-chat-contact-card-list__stack--widget{grid-template-columns:1fr}@container (min-width: 380px){.ai-chat-contact-card-list__stack--widget{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:520px){.ai-chat-contact-card-list__stack{grid-template-columns:1fr!important}.ai-chat-contact-card--horizontal{flex-direction:column}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-section{aspect-ratio:3/2;height:auto;min-width:100%;width:100%}}.ai-chat-contact-card__initials{align-items:center;display:flex;font-size:48px;font-weight:600;height:100%;justify-content:center;letter-spacing:.05em;text-transform:uppercase;width:100%}.ai-chat-contact-card--compact .ai-chat-contact-card__initials{font-size:32px}.ai-chat-contact-card--horizontal .ai-chat-contact-card__initials{font-size:28px}.ai-chat-contact-card--horizontal.ai-chat-contact-card--compact .ai-chat-contact-card__initials{font-size:22px}@media (max-width:480px){.ai-chat-contact-card__name{font-size:16px}.ai-chat-contact-card__detail,.ai-chat-contact-card__role{font-size:13px}.ai-chat-contact-card__button{font-size:13px;padding:10px 16px}.ai-chat-contact-card--horizontal .ai-chat-contact-card__info,.ai-chat-contact-card--vertical .ai-chat-contact-card__info{padding:12px}}.ai-chat-form-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f9fafb);border:1px solid var(--border-subtle,rgba(0,0,0,.06));border-radius:12px;box-sizing:border-box;margin:6px 0;overflow:hidden;padding:16px;width:100%}.ai-chat-widget.dark .ai-chat-form-card,.chakra-ui-dark .ai-chat-form-card,.dark .ai-chat-form-card,[data-theme=dark] .ai-chat-form-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-form-card--completed,.ai-chat-form-card--empty,.ai-chat-form-card--error,.ai-chat-form-card--skipped,.ai-chat-form-card--submitted{padding:12px 16px}.ai-chat-form-card--completed .ai-chat-form-card__header{margin-bottom:0}.ai-chat-form-card--completed .ai-chat-form-card__icon svg{color:#10b981}.ai-chat-form-card__header{align-items:center;display:flex;gap:8px;margin-bottom:12px}.ai-chat-form-card__icon{align-items:center;display:inline-flex;justify-content:center}.ai-chat-form-card__icon svg{color:var(--text-primary,#3e3e3e);height:18px;width:18px}.ai-chat-widget.dark .ai-chat-form-card__icon svg,.chakra-ui-dark .ai-chat-form-card__icon svg,.dark .ai-chat-form-card__icon svg,[data-theme=dark] .ai-chat-form-card__icon svg{color:#fff}.ai-chat-form-card__title{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:600}.ai-chat-widget.dark .ai-chat-form-card__title,.chakra-ui-dark .ai-chat-form-card__title,.dark .ai-chat-form-card__title,[data-theme=dark] .ai-chat-form-card__title{color:#fff}.ai-chat-form-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0 0 12px}.ai-chat-form-card__context{color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin:0 0 12px}.ai-chat-form-card--error .ai-chat-form-card__icon svg{color:#dc2626}.ai-chat-form-card--submitted .ai-chat-form-card__icon svg{color:#16a34a}.ai-chat-widget.dark .ai-chat-form-card--error .ai-chat-form-card__icon svg,.chakra-ui-dark .ai-chat-form-card--error .ai-chat-form-card__icon svg,.dark .ai-chat-form-card--error .ai-chat-form-card__icon svg,[data-theme=dark] .ai-chat-form-card--error .ai-chat-form-card__icon svg{color:#fca5a5}.ai-chat-widget.dark .ai-chat-form-card--submitted .ai-chat-form-card__icon svg,.chakra-ui-dark .ai-chat-form-card--submitted .ai-chat-form-card__icon svg,.dark .ai-chat-form-card--submitted .ai-chat-form-card__icon svg,[data-theme=dark] .ai-chat-form-card--submitted .ai-chat-form-card__icon svg{color:#4ade80}.ai-chat-form-card__error{color:#dc2626;font-size:13px;margin:0}.ai-chat-widget.dark .ai-chat-form-card__error,.chakra-ui-dark .ai-chat-form-card__error,.dark .ai-chat-form-card__error,[data-theme=dark] .ai-chat-form-card__error{color:#fca5a5}.ai-chat-form-card__success{color:#16a34a;font-size:13px;margin:0}.ai-chat-widget.dark .ai-chat-form-card__success,.chakra-ui-dark .ai-chat-form-card__success,.dark .ai-chat-form-card__success,[data-theme=dark] .ai-chat-form-card__success{color:#4ade80}.ai-chat-form-card__empty-text,.ai-chat-form-card__skipped-text{color:var(--text-muted,#71717a);font-size:13px;margin:0}.ai-chat-form-card__progress{align-items:center;display:flex;gap:12px;margin-bottom:16px}.ai-chat-form-card__progress-bar{background:var(--action-accent,var(--primary-color,#3b82f6));border-radius:2px;flex:1;height:4px;transition:width .3s ease}.ai-chat-form-card__progress-text{color:var(--text-muted,#71717a);font-size:12px;white-space:nowrap}.ai-chat-form-card__question{margin-bottom:16px}.ai-chat-form-card__question-text{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500;line-height:1.4;margin:0 0 12px}.ai-chat-widget.dark .ai-chat-form-card__question-text,.chakra-ui-dark .ai-chat-form-card__question-text,.dark .ai-chat-form-card__question-text,[data-theme=dark] .ai-chat-form-card__question-text{color:#fff}.ai-chat-form-card__required{color:#dc2626;margin-left:2px}.ai-chat-form-card__answer{margin-top:8px}.ai-chat-form-card__textarea{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);box-sizing:border-box;color:var(--text-primary,#3e3e3e);font-family:inherit;font-size:14px;min-height:80px;outline:none;padding:10px 12px;resize:vertical;transition:border-color .2s ease,box-shadow .2s ease;width:100%}.ai-chat-form-card__textarea:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-form-card__textarea::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-form-card__textarea,.chakra-ui-dark .ai-chat-form-card__textarea,.dark .ai-chat-form-card__textarea,[data-theme=dark] .ai-chat-form-card__textarea{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-form-card__textarea:focus,.chakra-ui-dark .ai-chat-form-card__textarea:focus,.dark .ai-chat-form-card__textarea:focus,[data-theme=dark] .ai-chat-form-card__textarea:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-form-card__options{display:flex;flex-direction:column;gap:8px}.ai-chat-form-card__option{align-items:center;background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);cursor:pointer;display:flex;gap:10px;padding:10px 12px;transition:border-color .15s,background .15s}.ai-chat-form-card__option:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-form-card__option,.chakra-ui-dark .ai-chat-form-card__option,.dark .ai-chat-form-card__option,[data-theme=dark] .ai-chat-form-card__option{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1)}.ai-chat-widget.dark .ai-chat-form-card__option:hover,.chakra-ui-dark .ai-chat-form-card__option:hover,.dark .ai-chat-form-card__option:hover,[data-theme=dark] .ai-chat-form-card__option:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-form-card__option input{accent-color:var(--action-accent,var(--primary-color,#3b82f6));margin:0}.ai-chat-form-card__option-text{color:var(--text-primary,#3e3e3e);font-size:14px}.ai-chat-widget.dark .ai-chat-form-card__option-text,.chakra-ui-dark .ai-chat-form-card__option-text,.dark .ai-chat-form-card__option-text,[data-theme=dark] .ai-chat-form-card__option-text{color:#fff}.ai-chat-form-card__rating{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-start}@media (max-width:380px){.ai-chat-form-card__rating{gap:6px}.ai-chat-form-card__rating-btn{font-size:13px;height:36px;width:36px}}.ai-chat-form-card__rating-btn{align-items:center;background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;display:flex;font-size:14px;font-weight:500;height:40px;justify-content:center;transition:all .15s ease;width:40px}.ai-chat-form-card__rating-btn--selected,.ai-chat-form-card__rating-btn:hover{border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-form-card__rating-btn--selected{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-form-card__rating-btn,.chakra-ui-dark .ai-chat-form-card__rating-btn,.dark .ai-chat-form-card__rating-btn,[data-theme=dark] .ai-chat-form-card__rating-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-form-card__rating-btn:hover,.chakra-ui-dark .ai-chat-form-card__rating-btn:hover,.dark .ai-chat-form-card__rating-btn:hover,[data-theme=dark] .ai-chat-form-card__rating-btn:hover{border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-form-card__rating-btn--selected,.chakra-ui-dark .ai-chat-form-card__rating-btn--selected,.dark .ai-chat-form-card__rating-btn--selected,[data-theme=dark] .ai-chat-form-card__rating-btn--selected{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-form-card__actions{align-items:center;border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));display:flex;flex-wrap:wrap;gap:8px;margin-top:16px;padding-top:16px}@media (max-width:380px){.ai-chat-form-card__actions{align-items:stretch;flex-direction:column}.ai-chat-form-card__actions-spacer{display:none}.ai-chat-form-card__btn{width:100%}}.ai-chat-widget.dark .ai-chat-form-card__actions,.chakra-ui-dark .ai-chat-form-card__actions,.dark .ai-chat-form-card__actions,[data-theme=dark] .ai-chat-form-card__actions{border-color:hsla(0,0%,100%,.08)}.ai-chat-form-card__actions-spacer{flex:1}.ai-chat-form-card__btn{border:none;border-radius:9999px;cursor:pointer;font-family:inherit;font-size:13px;font-weight:500;padding:8px 16px;transition:all .2s ease}.ai-chat-form-card__btn:disabled{cursor:not-allowed;opacity:.5}.ai-chat-form-card__btn--primary{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-form-card__btn--primary:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}.ai-chat-form-card__btn--secondary{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);color:var(--text-primary,#3e3e3e)}.ai-chat-form-card__btn--secondary:hover:not(:disabled){border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-form-card__btn--secondary,.chakra-ui-dark .ai-chat-form-card__btn--secondary,.dark .ai-chat-form-card__btn--secondary,[data-theme=dark] .ai-chat-form-card__btn--secondary{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-form-card__btn--ghost{background:transparent;color:var(--text-muted,#71717a)}.ai-chat-form-card__btn--ghost:hover:not(:disabled){background:rgba(0,0,0,.05);color:var(--text-primary,#3e3e3e)}.ai-chat-widget.dark .ai-chat-form-card__btn--ghost:hover:not(:disabled),.chakra-ui-dark .ai-chat-form-card__btn--ghost:hover:not(:disabled),.dark .ai-chat-form-card__btn--ghost:hover:not(:disabled),[data-theme=dark] .ai-chat-form-card__btn--ghost:hover:not(:disabled){background:hsla(0,0%,100%,.05);color:#fff}@media (max-width:480px){.ai-chat-form-card{padding:12px}.ai-chat-form-card__title{font-size:14px}.ai-chat-form-card__context,.ai-chat-form-card__description{font-size:12px}.ai-chat-form-card__question-text{font-size:13px}.ai-chat-form-card__textarea{font-size:13px;min-height:70px}.ai-chat-form-card__option{padding:8px 10px}.ai-chat-form-card__option-text{font-size:13px}}.ai-chat-booking-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f5f5f5);border-radius:12px;box-sizing:border-box;margin:6px 0;padding:16px;width:100%}.ai-chat-widget.dark .ai-chat-booking-card,.chakra-ui-dark .ai-chat-booking-card,.dark .ai-chat-booking-card,[data-theme=dark] .ai-chat-booking-card{background:hsla(0,0%,100%,.06)}.ai-chat-booking-card__header{align-items:center;display:flex;gap:8px;margin-bottom:12px}.ai-chat-booking-card__back-btn{align-items:center;background:rgba(0,0,0,.05);border:none;border-radius:6px;color:var(--text-secondary,#6b7280);cursor:pointer;display:flex;font-family:inherit;font-size:13px;font-weight:500;justify-content:center;padding:6px;transition:background .15s ease,color .15s ease}.ai-chat-booking-card__back-btn svg{height:16px;width:16px}.ai-chat-booking-card__back-btn:hover{background:rgba(0,0,0,.1);color:var(--text-primary,#3e3e3e)}.ai-chat-widget.dark .ai-chat-booking-card__back-btn,.chakra-ui-dark .ai-chat-booking-card__back-btn,.dark .ai-chat-booking-card__back-btn,[data-theme=dark] .ai-chat-booking-card__back-btn{background:hsla(0,0%,100%,.08);color:var(--text-secondary,#a1a1aa)}.ai-chat-widget.dark .ai-chat-booking-card__back-btn:hover,.chakra-ui-dark .ai-chat-booking-card__back-btn:hover,.dark .ai-chat-booking-card__back-btn:hover,[data-theme=dark] .ai-chat-booking-card__back-btn:hover{background:hsla(0,0%,100%,.15);color:#fff}.ai-chat-booking-card__title{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:600}.ai-chat-widget.dark .ai-chat-booking-card__title,.chakra-ui-dark .ai-chat-booking-card__title,.dark .ai-chat-booking-card__title,[data-theme=dark] .ai-chat-booking-card__title{color:#fff}.ai-chat-booking-card__status-icon{align-items:center;border-radius:50%;display:flex;flex-shrink:0;height:20px;justify-content:center;position:relative;width:20px}.ai-chat-booking-card__status-icon--pending{background:#6b7280}.ai-chat-booking-card__status-icon--pending:before{background:#fff;border-radius:1px;content:\"\";height:6px;position:absolute;top:5px;width:2px}.ai-chat-booking-card__status-icon--pending:after{background:#fff;border-radius:1px;content:\"\";height:2px;left:9px;position:absolute;top:9px;width:4px}.ai-chat-booking-card__status-icon--cancelled{background:#6b7280}.ai-chat-booking-card__status-icon--cancelled:after,.ai-chat-booking-card__status-icon--cancelled:before{background:#fff;border-radius:1px;content:\"\";height:2px;position:absolute;width:10px}.ai-chat-booking-card__status-icon--cancelled:before{transform:rotate(45deg)}.ai-chat-booking-card__status-icon--cancelled:after{transform:rotate(-45deg)}.ai-chat-booking-card__status-icon--error{background:#6b7280}.ai-chat-booking-card__status-icon--error:after{color:#fff;content:\"!\";font-size:12px;font-weight:700}.ai-chat-booking-card__content{display:flex;flex-direction:column;gap:12px}.ai-chat-booking-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0}.ai-chat-booking-card__empty{color:var(--text-muted,#71717a);font-size:13px;padding:16px;text-align:center}.ai-chat-booking-card__warning{background:rgba(0,0,0,.04);border-radius:8px;color:var(--text-secondary,#6b7280);font-size:13px;margin:0;padding:10px 12px}.ai-chat-widget.dark .ai-chat-booking-card__warning,.chakra-ui-dark .ai-chat-booking-card__warning,.dark .ai-chat-booking-card__warning,[data-theme=dark] .ai-chat-booking-card__warning{background:hsla(0,0%,100%,.06);color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__input{background:rgba(0,0,0,.05);border:none;border-radius:8px;box-sizing:border-box;color:var(--text-primary,#3e3e3e);font-family:inherit;font-size:14px;outline:none;padding:10px 12px;transition:background .15s ease,box-shadow .15s ease;width:100%}.ai-chat-booking-card__input:focus{background:rgba(0,0,0,.08);box-shadow:0 0 0 2px var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-booking-card__input::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-booking-card__input,.chakra-ui-dark .ai-chat-booking-card__input,.dark .ai-chat-booking-card__input,[data-theme=dark] .ai-chat-booking-card__input{background:hsla(0,0%,100%,.08);color:#fff}.ai-chat-widget.dark .ai-chat-booking-card__input:focus,.chakra-ui-dark .ai-chat-booking-card__input:focus,.dark .ai-chat-booking-card__input:focus,[data-theme=dark] .ai-chat-booking-card__input:focus{background:hsla(0,0%,100%,.12)}.ai-chat-booking-card__field{display:flex;flex-direction:column;gap:8px}.ai-chat-booking-card__label{color:var(--text-secondary,#6b7280);display:block;font-size:13px;font-weight:500;margin-bottom:4px}.ai-chat-widget.dark .ai-chat-booking-card__label,.chakra-ui-dark .ai-chat-booking-card__label,.dark .ai-chat-booking-card__label,[data-theme=dark] .ai-chat-booking-card__label{color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__btn{border:none;border-radius:9999px;box-sizing:border-box;cursor:pointer;font-family:inherit;font-size:13px;font-weight:500;padding:10px 16px;transition:all .15s ease;width:100%}.ai-chat-booking-card__btn:disabled{cursor:not-allowed;opacity:.5}.ai-chat-booking-card__btn--primary{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-booking-card__btn--primary:hover:not(:disabled){filter:brightness(1.1);transform:translateY(-1px)}.ai-chat-booking-card__btn--secondary{background:rgba(0,0,0,.06);color:var(--text-primary,#3e3e3e)}.ai-chat-booking-card__btn--secondary:hover:not(:disabled){background:rgba(0,0,0,.1)}.ai-chat-widget.dark .ai-chat-booking-card__btn--secondary,.chakra-ui-dark .ai-chat-booking-card__btn--secondary,.dark .ai-chat-booking-card__btn--secondary,[data-theme=dark] .ai-chat-booking-card__btn--secondary{background:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-booking-card__btn--secondary:hover:not(:disabled),.chakra-ui-dark .ai-chat-booking-card__btn--secondary:hover:not(:disabled),.dark .ai-chat-booking-card__btn--secondary:hover:not(:disabled),[data-theme=dark] .ai-chat-booking-card__btn--secondary:hover:not(:disabled){background:hsla(0,0%,100%,.15)}.ai-chat-booking-card__btn--danger{background:rgba(220,38,38,.1);color:#dc2626}.ai-chat-booking-card__btn--danger:hover:not(:disabled){background:rgba(220,38,38,.18)}.ai-chat-widget.dark .ai-chat-booking-card__btn--danger,.chakra-ui-dark .ai-chat-booking-card__btn--danger,.dark .ai-chat-booking-card__btn--danger,[data-theme=dark] .ai-chat-booking-card__btn--danger{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-booking-card__btn--inline{font-size:12px;margin-top:8px;padding:6px 12px;width:auto}.ai-chat-booking-card__options{display:flex;flex-direction:column;gap:8px}.ai-chat-booking-card__option-btn{align-items:center;background:rgba(0,0,0,.04);border:none;border-radius:10px;box-sizing:border-box;cursor:pointer;display:flex;font-family:inherit;gap:12px;padding:14px 16px;text-align:left;transition:background .15s ease;width:100%}.ai-chat-booking-card__option-btn:hover:not(:disabled){background:rgba(0,0,0,.08)}.ai-chat-booking-card__option-btn:disabled{cursor:not-allowed;opacity:.5}.ai-chat-widget.dark .ai-chat-booking-card__option-btn,.chakra-ui-dark .ai-chat-booking-card__option-btn,.dark .ai-chat-booking-card__option-btn,[data-theme=dark] .ai-chat-booking-card__option-btn{background:hsla(0,0%,100%,.06)}.ai-chat-widget.dark .ai-chat-booking-card__option-btn:hover:not(:disabled),.chakra-ui-dark .ai-chat-booking-card__option-btn:hover:not(:disabled),.dark .ai-chat-booking-card__option-btn:hover:not(:disabled),[data-theme=dark] .ai-chat-booking-card__option-btn:hover:not(:disabled){background:hsla(0,0%,100%,.1)}.ai-chat-booking-card__option-icon{align-items:center;background:var(--action-accent,var(--primary-color,#3b82f6));border-radius:8px;color:#fff;display:flex;flex-shrink:0;height:32px;justify-content:center;width:32px}.ai-chat-booking-card__option-icon svg{height:16px;width:16px}.ai-chat-booking-card__option-text{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500}.ai-chat-widget.dark .ai-chat-booking-card__option-text,.chakra-ui-dark .ai-chat-booking-card__option-text,.dark .ai-chat-booking-card__option-text,[data-theme=dark] .ai-chat-booking-card__option-text{color:#fff}.ai-chat-booking-card__list{display:flex;flex-direction:column;gap:6px}.ai-chat-booking-card__list-item{align-items:center;background:rgba(0,0,0,.04);border:none;border-radius:10px;box-sizing:border-box;cursor:pointer;display:flex;font-family:inherit;justify-content:space-between;padding:12px 14px;text-align:left;transition:background .15s ease;width:100%}.ai-chat-booking-card__list-item:hover{background:rgba(0,0,0,.08)}.ai-chat-widget.dark .ai-chat-booking-card__list-item,.chakra-ui-dark .ai-chat-booking-card__list-item,.dark .ai-chat-booking-card__list-item,[data-theme=dark] .ai-chat-booking-card__list-item{background:hsla(0,0%,100%,.06)}.ai-chat-widget.dark .ai-chat-booking-card__list-item:hover,.chakra-ui-dark .ai-chat-booking-card__list-item:hover,.dark .ai-chat-booking-card__list-item:hover,[data-theme=dark] .ai-chat-booking-card__list-item:hover{background:hsla(0,0%,100%,.1)}.ai-chat-booking-card__list-item-content{display:flex;flex-direction:column;gap:2px}.ai-chat-booking-card__list-item-name{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500}.ai-chat-widget.dark .ai-chat-booking-card__list-item-name,.chakra-ui-dark .ai-chat-booking-card__list-item-name,.dark .ai-chat-booking-card__list-item-name,[data-theme=dark] .ai-chat-booking-card__list-item-name{color:#fff}.ai-chat-booking-card__list-item-role{color:var(--text-muted,#71717a);font-size:12px}.ai-chat-booking-card__list-item-arrow{flex-shrink:0;height:16px;position:relative;width:16px}.ai-chat-booking-card__list-item-arrow:before{border-width:medium;border-bottom:2px solid var(--text-muted,#9ca3af);border-left:0 solid var(--text-muted,#9ca3af);border-right:2px solid var(--text-muted,#9ca3af);border-top:0 solid var(--text-muted,#9ca3af);content:\"\";height:6px;left:50%;position:absolute;top:50%;transform:translate(-70%,-50%) rotate(-45deg);width:6px}.ai-chat-booking-card__slots-container{display:flex;flex-direction:column;gap:12px;max-height:280px;overflow-y:auto}.ai-chat-booking-card__date-group{display:flex;flex-direction:column;gap:8px}.ai-chat-booking-card__date-header{color:var(--text-muted,#71717a);font-size:12px;font-weight:600;letter-spacing:.5px;margin:0;padding-left:2px;text-transform:uppercase}.ai-chat-booking-card__slots{display:flex;flex-wrap:wrap;gap:6px}.ai-chat-booking-card__slot{background:rgba(0,0,0,.05);border:none;border-radius:20px;color:var(--text-primary,#3e3e3e);cursor:pointer;flex:0 0 auto;font-family:inherit;font-size:13px;font-weight:500;padding:8px 14px;transition:background .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-booking-card__slot:hover:not(:disabled){background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-booking-card__slot:active:not(:disabled){transform:scale(.97)}.ai-chat-booking-card__slot:disabled{cursor:not-allowed;opacity:.5}.ai-chat-widget.dark .ai-chat-booking-card__slot,.chakra-ui-dark .ai-chat-booking-card__slot,.dark .ai-chat-booking-card__slot,[data-theme=dark] .ai-chat-booking-card__slot{background:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-booking-card__slot:hover:not(:disabled),.chakra-ui-dark .ai-chat-booking-card__slot:hover:not(:disabled),.dark .ai-chat-booking-card__slot:hover:not(:disabled),[data-theme=dark] .ai-chat-booking-card__slot:hover:not(:disabled){background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-booking-card__subject-options{display:flex;flex-direction:column;gap:6px}.ai-chat-booking-card__subject-option{background:rgba(0,0,0,.04);border:none;border-radius:10px;color:var(--text-primary,#3e3e3e);cursor:pointer;font-family:inherit;font-size:14px;font-weight:500;padding:12px 14px;text-align:left;transition:background .15s ease,filter .15s ease}.ai-chat-booking-card__subject-option:hover:not(.ai-chat-booking-card__subject-option--selected){background:rgba(0,0,0,.08)}.ai-chat-booking-card__subject-option--selected,.ai-chat-booking-card__subject-option--selected:hover{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-booking-card__subject-option--selected:hover{filter:brightness(1.1)}.ai-chat-widget.dark .ai-chat-booking-card__subject-option,.chakra-ui-dark .ai-chat-booking-card__subject-option,.dark .ai-chat-booking-card__subject-option,[data-theme=dark] .ai-chat-booking-card__subject-option{background:hsla(0,0%,100%,.06);color:#fff}.ai-chat-widget.dark .ai-chat-booking-card__subject-option:hover:not(.ai-chat-booking-card__subject-option--selected),.chakra-ui-dark .ai-chat-booking-card__subject-option:hover:not(.ai-chat-booking-card__subject-option--selected),.dark .ai-chat-booking-card__subject-option:hover:not(.ai-chat-booking-card__subject-option--selected),[data-theme=dark] .ai-chat-booking-card__subject-option:hover:not(.ai-chat-booking-card__subject-option--selected){background:hsla(0,0%,100%,.1)}.ai-chat-widget.dark .ai-chat-booking-card__subject-option--selected,.ai-chat-widget.dark .ai-chat-booking-card__subject-option--selected:hover,.chakra-ui-dark .ai-chat-booking-card__subject-option--selected,.chakra-ui-dark .ai-chat-booking-card__subject-option--selected:hover,.dark .ai-chat-booking-card__subject-option--selected,.dark .ai-chat-booking-card__subject-option--selected:hover,[data-theme=dark] .ai-chat-booking-card__subject-option--selected,[data-theme=dark] .ai-chat-booking-card__subject-option--selected:hover{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-booking-card__appointments{display:flex;flex-direction:column;gap:8px}.ai-chat-booking-card__appointment{background:rgba(0,0,0,.04);border-radius:10px;padding:12px 14px}.ai-chat-widget.dark .ai-chat-booking-card__appointment,.chakra-ui-dark .ai-chat-booking-card__appointment,.dark .ai-chat-booking-card__appointment,[data-theme=dark] .ai-chat-booking-card__appointment{background:hsla(0,0%,100%,.06)}.ai-chat-booking-card__appointment-header{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:6px}.ai-chat-booking-card__appointment-subject{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500}.ai-chat-widget.dark .ai-chat-booking-card__appointment-subject,.chakra-ui-dark .ai-chat-booking-card__appointment-subject,.dark .ai-chat-booking-card__appointment-subject,[data-theme=dark] .ai-chat-booking-card__appointment-subject{color:#fff}.ai-chat-booking-card__appointment-status{border-radius:10px;font-size:11px;font-weight:600;padding:3px 8px;text-transform:uppercase}.ai-chat-booking-card__appointment-status--confirmed{background:rgba(59,130,246,.15);color:#3b82f6}.ai-chat-booking-card__appointment-status--pending{background:hsla(220,9%,46%,.15);color:#6b7280}.ai-chat-widget.dark .ai-chat-booking-card__appointment-status--confirmed,.chakra-ui-dark .ai-chat-booking-card__appointment-status--confirmed,.dark .ai-chat-booking-card__appointment-status--confirmed,[data-theme=dark] .ai-chat-booking-card__appointment-status--confirmed{background:rgba(59,130,246,.25);color:#60a5fa}.ai-chat-widget.dark .ai-chat-booking-card__appointment-status--pending,.chakra-ui-dark .ai-chat-booking-card__appointment-status--pending,.dark .ai-chat-booking-card__appointment-status--pending,[data-theme=dark] .ai-chat-booking-card__appointment-status--pending{background:hsla(220,9%,46%,.25);color:#9ca3af}.ai-chat-booking-card__appointment-status--cancelled{background:hsla(220,9%,46%,.15);color:#6b7280}.ai-chat-booking-card__appointment-time{color:var(--text-secondary,#6b7280);font-size:13px;margin-bottom:4px}.ai-chat-widget.dark .ai-chat-booking-card__appointment-time,.chakra-ui-dark .ai-chat-booking-card__appointment-time,.dark .ai-chat-booking-card__appointment-time,[data-theme=dark] .ai-chat-booking-card__appointment-time{color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__appointment-contact{color:var(--text-muted,#71717a);font-size:12px}.ai-chat-booking-card__appointment-info{display:flex;flex-direction:column;gap:4px;margin-bottom:10px}.ai-chat-booking-card__appointment-actions{display:flex;flex-wrap:wrap;gap:8px}@media (max-width:380px){.ai-chat-booking-card__appointment-actions{flex-direction:column}.ai-chat-booking-card__appointment-cancel,.ai-chat-booking-card__appointment-link{justify-content:center;text-align:center;width:100%}}.ai-chat-booking-card__appointment-link{background:var(--action-accent,var(--primary-color,#3b82f6));border-radius:6px;color:#fff;display:inline-block;font-size:12px;font-weight:500;padding:6px 12px;text-decoration:none;transition:filter .15s ease}.ai-chat-booking-card__appointment-link:hover{filter:brightness(1.1);text-decoration:none}.ai-chat-booking-card__appointment-cancel{background:rgba(220,38,38,.1);border:none;border-radius:6px;color:#dc2626;cursor:pointer;font-family:inherit;font-size:12px;font-weight:500;padding:6px 12px;transition:background .15s ease}.ai-chat-booking-card__appointment-cancel:hover:not(:disabled){background:rgba(220,38,38,.18)}.ai-chat-booking-card__appointment-cancel:disabled{cursor:not-allowed;opacity:.5}.ai-chat-widget.dark .ai-chat-booking-card__appointment-cancel,.chakra-ui-dark .ai-chat-booking-card__appointment-cancel,.dark .ai-chat-booking-card__appointment-cancel,[data-theme=dark] .ai-chat-booking-card__appointment-cancel{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-booking-card__summary{background:rgba(0,0,0,.04);border-radius:10px;padding:12px 14px}.ai-chat-widget.dark .ai-chat-booking-card__summary,.chakra-ui-dark .ai-chat-booking-card__summary,.dark .ai-chat-booking-card__summary,[data-theme=dark] .ai-chat-booking-card__summary{background:hsla(0,0%,100%,.06)}.ai-chat-booking-card__summary-row{align-items:center;display:flex;gap:8px;justify-content:space-between;padding:6px 0}@media (max-width:380px){.ai-chat-booking-card__summary-row{align-items:flex-start;flex-direction:column;gap:2px}.ai-chat-booking-card__summary-value{text-align:left}}.ai-chat-booking-card__summary-row:not(:last-child){border-bottom:1px solid rgba(0,0,0,.06)}.ai-chat-widget.dark .ai-chat-booking-card__summary-row:not(:last-child),.chakra-ui-dark .ai-chat-booking-card__summary-row:not(:last-child),.dark .ai-chat-booking-card__summary-row:not(:last-child),[data-theme=dark] .ai-chat-booking-card__summary-row:not(:last-child){border-bottom-color:hsla(0,0%,100%,.08)}.ai-chat-booking-card__summary-label{color:var(--text-muted,#71717a);font-size:12px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.ai-chat-booking-card__summary-value{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500;text-align:right}.ai-chat-widget.dark .ai-chat-booking-card__summary-value,.chakra-ui-dark .ai-chat-booking-card__summary-value,.dark .ai-chat-booking-card__summary-value,[data-theme=dark] .ai-chat-booking-card__summary-value{color:#fff}.ai-chat-booking-card__success-icon{align-items:center;background:var(--action-accent,var(--primary-color,#3b82f6));border-radius:50%;display:flex;height:40px;justify-content:center;margin:0 auto 12px;position:relative;width:40px}.ai-chat-booking-card__success-icon:after{border:solid #fff;border-width:0 3px 3px 0;content:\"\";height:16px;margin-bottom:4px;transform:rotate(45deg);width:10px}.ai-chat-booking-card__success-message{color:var(--text-secondary,#6b7280);font-size:14px;margin:0 0 12px;text-align:center}.ai-chat-widget.dark .ai-chat-booking-card__success-message,.chakra-ui-dark .ai-chat-booking-card__success-message,.dark .ai-chat-booking-card__success-message,[data-theme=dark] .ai-chat-booking-card__success-message{color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__link{display:inline-block;font-size:13px;font-weight:500;margin-top:8px;text-decoration:none;transition:opacity .15s ease}.ai-chat-booking-card__link:hover{opacity:.8;text-decoration:underline}.ai-chat-booking-card--success{background:rgba(59,130,246,.08)}.ai-chat-widget.dark .ai-chat-booking-card--success,.chakra-ui-dark .ai-chat-booking-card--success,.dark .ai-chat-booking-card--success,[data-theme=dark] .ai-chat-booking-card--success{background:rgba(59,130,246,.12)}.ai-chat-booking-card--pending{background:hsla(220,9%,46%,.08)}.ai-chat-widget.dark .ai-chat-booking-card--pending,.chakra-ui-dark .ai-chat-booking-card--pending,.dark .ai-chat-booking-card--pending,[data-theme=dark] .ai-chat-booking-card--pending{background:hsla(220,9%,46%,.12)}.ai-chat-booking-card--cancelled{background:hsla(220,9%,46%,.08)}.ai-chat-widget.dark .ai-chat-booking-card--cancelled,.chakra-ui-dark .ai-chat-booking-card--cancelled,.dark .ai-chat-booking-card--cancelled,[data-theme=dark] .ai-chat-booking-card--cancelled{background:hsla(220,9%,46%,.12)}.ai-chat-booking-card--error{background:hsla(220,9%,46%,.08)}.ai-chat-widget.dark .ai-chat-booking-card--error,.chakra-ui-dark .ai-chat-booking-card--error,.dark .ai-chat-booking-card--error,[data-theme=dark] .ai-chat-booking-card--error{background:hsla(220,9%,46%,.12)}.ai-chat-booking-card__pending-text,.ai-chat-booking-card__success-text{color:var(--text-secondary,#6b7280);font-size:13px;margin:0}.ai-chat-widget.dark .ai-chat-booking-card__pending-text,.ai-chat-widget.dark .ai-chat-booking-card__success-text,.chakra-ui-dark .ai-chat-booking-card__pending-text,.chakra-ui-dark .ai-chat-booking-card__success-text,.dark .ai-chat-booking-card__pending-text,.dark .ai-chat-booking-card__success-text,[data-theme=dark] .ai-chat-booking-card__pending-text,[data-theme=dark] .ai-chat-booking-card__success-text{color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__error{background:rgba(220,38,38,.08);border-radius:8px;color:#dc2626;font-size:13px;margin:0;padding:10px 12px}.ai-chat-widget.dark .ai-chat-booking-card__error,.chakra-ui-dark .ai-chat-booking-card__error,.dark .ai-chat-booking-card__error,[data-theme=dark] .ai-chat-booking-card__error{background:rgba(239,68,68,.15);color:#fca5a5}.ai-chat-booking-card--closable{position:relative}.ai-chat-booking-card--closable .ai-chat-booking-card__header{padding-right:40px}.ai-chat-pin-input-group{display:flex;flex-wrap:wrap;gap:8px;justify-content:center}@media (max-width:320px){.ai-chat-pin-input-group{gap:6px}}.ai-chat-pin-input{background:rgba(0,0,0,.05);border:none;border-radius:8px;box-sizing:border-box;color:var(--text-primary,#3e3e3e);font-family:inherit;font-size:20px;font-weight:600;height:48px;outline:none;padding:0;text-align:center;transition:background .15s ease,box-shadow .15s ease;width:42px}@media (max-width:320px){.ai-chat-pin-input{font-size:18px;height:42px;width:36px}}.ai-chat-pin-input:focus{background:rgba(0,0,0,.08);box-shadow:0 0 0 2px var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-pin-input::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-pin-input:disabled{cursor:not-allowed;opacity:.5}.ai-chat-widget.dark .ai-chat-pin-input,.chakra-ui-dark .ai-chat-pin-input,.dark .ai-chat-pin-input,[data-theme=dark] .ai-chat-pin-input{background:hsla(0,0%,100%,.08);color:#fff}.ai-chat-widget.dark .ai-chat-pin-input:focus,.chakra-ui-dark .ai-chat-pin-input:focus,.dark .ai-chat-pin-input:focus,[data-theme=dark] .ai-chat-pin-input:focus{background:hsla(0,0%,100%,.12)}@media (max-width:480px){.ai-chat-booking-card{padding:12px}.ai-chat-booking-card__title{font-size:14px}.ai-chat-booking-card__option-btn{padding:12px 14px}.ai-chat-booking-card__option-icon{height:28px;width:28px}.ai-chat-booking-card__option-icon svg{height:14px;width:14px}.ai-chat-booking-card__option-text{font-size:13px}.ai-chat-booking-card__slots-container{max-height:240px}.ai-chat-booking-card__slot{font-size:12px;padding:6px 12px}}.ai-chat-structured-image{--action-accent:var(--primary-color,#3b82f6);display:flex;flex-direction:column;gap:8px;width:100%}.ai-chat-structured-image__context{color:var(--text-primary,#3e3e3e);font-size:13px;line-height:1.4;margin:0 0 4px}.ai-chat-widget.dark .ai-chat-structured-image__context,.chakra-ui-dark .ai-chat-structured-image__context,.dark .ai-chat-structured-image__context,[data-theme=dark] .ai-chat-structured-image__context{color:var(--text-primary,#fff)}.ai-chat-structured-image__error{background:rgba(239,68,68,.1);border-radius:var(--radius-md,8px);color:#dc2626;font-size:13px;padding:12px 16px;text-align:center}.ai-chat-widget.dark .ai-chat-structured-image__error,.chakra-ui-dark .ai-chat-structured-image__error,.dark .ai-chat-structured-image__error,[data-theme=dark] .ai-chat-structured-image__error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-structured-image__cards{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}.ai-chat-structured-image__cards:has(.ai-chat-project-card:only-child){grid-template-columns:1fr}@supports not selector(:has(*)){.ai-chat-structured-image__cards{grid-template-columns:repeat(var(--card-columns,2),1fr)}}@media (max-width:480px){.ai-chat-structured-image__cards{grid-template-columns:1fr}}.ai-chat-media-display{--action-accent:var(--primary-color,#3b82f6);display:flex;flex-direction:column;gap:8px;margin-top:4px;padding:0!important}.ai-chat-media-display__context{color:var(--text-muted,#71717a);font-size:13px;margin:0 0 4px;padding:0 4px}.ai-chat-media-display__error{background:rgba(239,68,68,.1);border-radius:var(--radius-lg,12px);color:#dc2626;font-size:13px;padding:16px;text-align:center}.ai-chat-widget.dark .ai-chat-media-display__error,.chakra-ui-dark .ai-chat-media-display__error,.dark .ai-chat-media-display__error,[data-theme=dark] .ai-chat-media-display__error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-media-display__cards{display:grid;gap:12px;grid-template-columns:repeat(var(--card-columns,1),1fr)}.ai-chat-image-card{--action-accent:var(--primary-color,#3b82f6);background:transparent;display:flex;flex-direction:column}.ai-chat-image-card,.ai-chat-image-card__media{border-radius:var(--radius-lg,12px);overflow:hidden}.ai-chat-image-card__media{position:relative;width:100%}.ai-chat-image-card__image{border-radius:var(--radius-lg,12px);display:block;height:auto;max-height:300px;object-fit:cover;width:100%}.ai-chat-image-card__image-error{align-items:center;background:var(--bg-muted,#e5e7eb);border-radius:var(--radius-lg,12px);color:var(--text-muted,#71717a);display:flex;font-size:13px;height:150px;justify-content:center;width:100%}.ai-chat-image-card__content{padding:10px 0 0}.ai-chat-image-card__title{color:var(--text-primary,#1a1a1a);font-size:14px;font-weight:600;line-height:1.3;margin:0 0 4px}.ai-chat-widget.dark .ai-chat-image-card__title,.dark .ai-chat-image-card__title,[data-theme=dark] .ai-chat-image-card__title{color:#fff}.ai-chat-image-card__description{color:var(--text-muted,#6b7280);font-size:13px;line-height:1.4;margin:0 0 8px}.ai-chat-image-card__link-btn{align-items:center;background:transparent;border:none;color:var(--action-accent);cursor:pointer;display:inline-flex;font-size:13px;font-weight:500;gap:4px;padding:0;transition:opacity .2s}.ai-chat-image-card__link-btn:hover{opacity:.8}.ai-chat-media-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-lg,12px);display:flex;flex-direction:column;overflow:hidden}.ai-chat-widget.dark .ai-chat-media-card,.chakra-ui-dark .ai-chat-media-card,.dark .ai-chat-media-card,[data-theme=dark] .ai-chat-media-card{background:var(--bg-secondary,#3a3a3a);border-color:hsla(0,0%,100%,.08)}.ai-chat-media-card__media{background:#000;position:relative;width:100%}.ai-chat-media-card__media.video{aspect-ratio:16/9}.ai-chat-media-card__media.image{aspect-ratio:auto;max-height:400px}.ai-chat-media-card__image{display:block;height:100%;object-fit:cover;width:100%}.ai-chat-media-card__image-error{align-items:center;background:var(--bg-muted,#e5e7eb);color:var(--text-muted,#71717a);display:flex;font-size:13px;height:200px;justify-content:center;width:100%}.ai-chat-media-card__video-placeholder{cursor:pointer;height:100%;position:relative;width:100%}.ai-chat-media-card__video-placeholder img{height:100%;object-fit:cover;width:100%}.ai-chat-media-card__video-bg{background:linear-gradient(135deg,#1a1a2e,#16213e);height:100%;width:100%}.ai-chat-media-card__play-btn{align-items:center;background:rgba(0,0,0,.7);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:56px;justify-content:center;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s,transform .2s;width:56px}.ai-chat-media-card__play-btn:hover{background:rgba(0,0,0,.9);transform:translate(-50%,-50%) scale(1.05)}.ai-chat-media-card__provider-badge{background:rgba(0,0,0,.8);border-radius:4px;bottom:8px;color:#fff;font-size:11px;font-weight:600;letter-spacing:.5px;padding:4px 8px;position:absolute;right:8px;text-transform:uppercase}.ai-chat-media-card__iframe,.ai-chat-media-card__video{border:none;height:100%;left:0;position:absolute;top:0;width:100%}.ai-chat-media-card__content{padding:12px}.ai-chat-media-card__title{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:600;line-height:1.3;margin:0 0 4px}.ai-chat-widget.dark .ai-chat-media-card__title,.chakra-ui-dark .ai-chat-media-card__title,.dark .ai-chat-media-card__title,[data-theme=dark] .ai-chat-media-card__title{color:#fff}.ai-chat-media-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0 0 8px}.ai-chat-media-card__link-btn{align-items:center;background:var(--action-accent);border:none;border-radius:6px;color:#fff;cursor:pointer;display:inline-flex;font-size:13px;font-weight:500;gap:6px;padding:6px 12px;transition:opacity .2s}.ai-chat-media-card__link-btn:hover{opacity:.9}.ai-chat-image-gallery{--action-accent:var(--primary-color,#3b82f6)}.ai-chat-image-gallery__grid{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}@media (max-width:480px){.ai-chat-image-gallery__grid{grid-template-columns:1fr}.ai-chat-image-gallery__grid .ai-chat-image-gallery__item:first-child{grid-column:span 1}}.ai-chat-image-gallery__grid:has(.ai-chat-image-gallery__item:only-child){grid-template-columns:1fr}.ai-chat-image-gallery__grid:has(.ai-chat-image-gallery__item:nth-child(3):last-child) .ai-chat-image-gallery__item:first-child{grid-column:span 2}.ai-chat-image-gallery__grid:has(.ai-chat-image-gallery__item:nth-child(5):last-child) .ai-chat-image-gallery__item:first-child{grid-column:span 2}.ai-chat-image-gallery__grid:has(.ai-chat-image-gallery__item:nth-child(7):last-child) .ai-chat-image-gallery__item:first-child{grid-column:span 2}.ai-chat-image-gallery__item.span-full{grid-column:span 2}.ai-chat-image-gallery[data-item-count=\"1\"] .ai-chat-image-gallery__grid{grid-template-columns:1fr}.ai-chat-image-gallery__item{position:relative}.ai-chat-image-gallery__item-media{aspect-ratio:4/3;background:var(--bg-muted,#e5e7eb);border-radius:var(--radius-lg,12px);overflow:hidden;position:relative}.ai-chat-image-gallery__item-media img{height:100%;object-fit:cover;width:100%}.ai-chat-image-gallery__item-overlay{background:linear-gradient(0deg,rgba(0,0,0,.85) 0,rgba(0,0,0,.4) 60%,transparent);border-radius:0 0 var(--radius-lg,12px) var(--radius-lg,12px);bottom:0;left:0;padding:24px 12px 10px;position:absolute;right:0}.ai-chat-image-gallery__item-title{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:#fff;display:-webkit-box;font-size:12px;font-weight:600;line-height:1.3;margin:0;overflow:hidden;text-shadow:0 1px 3px rgba(0,0,0,.5)}.ai-chat-image-gallery__error{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:12px;height:100%;justify-content:center;width:100%}.ai-chat-media-gallery{--action-accent:var(--primary-color,#3b82f6)}.ai-chat-media-gallery__grid{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}.ai-chat-image-gallery__lightbox,.ai-chat-media-gallery__lightbox{align-items:center;background:rgba(0,0,0,.95);bottom:0;display:flex;justify-content:center;left:0;padding:40px;position:fixed;right:0;top:0;z-index:10000}.ai-chat-image-gallery__lightbox-close,.ai-chat-media-gallery__lightbox-close{align-items:center;background:hsla(0,0%,100%,.1);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:40px;justify-content:center;position:absolute;right:16px;top:16px;transition:background .2s;width:40px}.ai-chat-image-gallery__lightbox-close:hover,.ai-chat-media-gallery__lightbox-close:hover{background:hsla(0,0%,100%,.2)}.ai-chat-image-gallery__lightbox-nav,.ai-chat-media-gallery__lightbox-nav{align-items:center;background:hsla(0,0%,100%,.1);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:48px;justify-content:center;position:absolute;top:50%;transform:translateY(-50%);transition:background .2s;width:48px}.ai-chat-image-gallery__lightbox-nav:hover,.ai-chat-media-gallery__lightbox-nav:hover{background:hsla(0,0%,100%,.2)}.ai-chat-image-gallery__lightbox-nav.prev,.ai-chat-media-gallery__lightbox-nav.prev{left:16px}.ai-chat-image-gallery__lightbox-nav.next,.ai-chat-media-gallery__lightbox-nav.next{right:16px}.ai-chat-image-gallery__lightbox-content,.ai-chat-media-gallery__lightbox-content{align-items:center;display:flex;flex-direction:column;max-height:80vh;max-width:90vw}.ai-chat-image-gallery__lightbox-content img,.ai-chat-media-gallery__lightbox-content img{border-radius:4px;max-height:70vh;max-width:100%;object-fit:contain}.ai-chat-image-gallery__lightbox-caption,.ai-chat-media-gallery__lightbox-caption{color:#fff;margin-top:16px;text-align:center}.ai-chat-image-gallery__lightbox-caption h4,.ai-chat-media-gallery__lightbox-caption h4{font-size:16px;font-weight:600;margin:0 0 4px}.ai-chat-image-gallery__lightbox-caption p,.ai-chat-media-gallery__lightbox-caption p{color:hsla(0,0%,100%,.7);font-size:14px;margin:0}.ai-chat-image-gallery__lightbox-counter,.ai-chat-media-gallery__lightbox-counter{background:rgba(0,0,0,.6);border-radius:20px;bottom:16px;color:#fff;font-size:13px;left:50%;padding:6px 12px;position:absolute;transform:translateX(-50%)}.ai-chat-project-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-lg,12px);display:flex;flex-direction:column;overflow:hidden;transition:border-color .2s,box-shadow .2s,transform .2s}.ai-chat-project-card.clickable{cursor:pointer}.ai-chat-project-card.clickable:hover{border-color:var(--action-accent);box-shadow:0 4px 12px rgba(0,0,0,.1);transform:translateY(-2px)}.ai-chat-widget.dark .ai-chat-project-card,.chakra-ui-dark .ai-chat-project-card,.dark .ai-chat-project-card,[data-theme=dark] .ai-chat-project-card{background:var(--bg-secondary,#2a2a2a);border-color:hsla(0,0%,100%,.1)}.ai-chat-widget.dark .ai-chat-project-card.clickable:hover,.chakra-ui-dark .ai-chat-project-card.clickable:hover,.dark .ai-chat-project-card.clickable:hover,[data-theme=dark] .ai-chat-project-card.clickable:hover{border-color:var(--action-accent);box-shadow:0 4px 16px rgba(0,0,0,.3)}.ai-chat-project-card--image-only{background:transparent;border:none}.ai-chat-project-card--image-only .ai-chat-project-card__media{aspect-ratio:16/9;border-radius:var(--radius-lg,12px)}.ai-chat-project-card--image-only.clickable:hover{border:none;box-shadow:0 4px 16px rgba(0,0,0,.2)}.ai-chat-project-card--overlay{background:transparent;border:none;border-radius:var(--radius-lg,12px);overflow:hidden}.ai-chat-project-card--overlay .ai-chat-project-card__media{aspect-ratio:4/3;border-radius:var(--radius-lg,12px)}.ai-chat-project-card__overlay{background:linear-gradient(0deg,rgba(0,0,0,.85) 0,rgba(0,0,0,.5) 50%,transparent);border-radius:0 0 var(--radius-lg,12px) var(--radius-lg,12px);bottom:0;left:0;padding:10px 12px;position:absolute;right:0}.ai-chat-project-card__overlay-title{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:#fff;display:-webkit-box;font-size:12px;font-weight:600;line-height:1.3;margin:0;overflow:hidden;text-shadow:0 1px 3px rgba(0,0,0,.5)}.ai-chat-project-card--full .ai-chat-project-card__media{aspect-ratio:16/10;border-bottom:1px solid var(--border-subtle,rgba(0,0,0,.06))}.ai-chat-widget.dark .ai-chat-project-card--full .ai-chat-project-card__media,.chakra-ui-dark .ai-chat-project-card--full .ai-chat-project-card__media,.dark .ai-chat-project-card--full .ai-chat-project-card__media,[data-theme=dark] .ai-chat-project-card--full .ai-chat-project-card__media{border-bottom-color:hsla(0,0%,100%,.08)}.ai-chat-project-card__media{aspect-ratio:16/10;background:var(--bg-muted,#e5e7eb);overflow:hidden;position:relative;width:100%}.ai-chat-widget.dark .ai-chat-project-card__media,.chakra-ui-dark .ai-chat-project-card__media,.dark .ai-chat-project-card__media,[data-theme=dark] .ai-chat-project-card__media{background:hsla(0,0%,100%,.05)}.ai-chat-project-card__media img{height:100%;object-fit:cover;transition:transform .3s ease;width:100%}.ai-chat-project-card.clickable:hover .ai-chat-project-card__media img{transform:scale(1.03)}.ai-chat-project-card__iframe,.ai-chat-project-card__video{border:none;height:100%;left:0;position:absolute;top:0;width:100%}.ai-chat-project-card__placeholder{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:13px;height:100%;justify-content:center;width:100%}.ai-chat-project-card__play-btn{align-items:center;background:rgba(0,0,0,.7);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:48px;justify-content:center;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s,transform .2s;width:48px}.ai-chat-project-card__play-btn:hover{background:rgba(0,0,0,.9);transform:translate(-50%,-50%) scale(1.1)}.ai-chat-project-card__content{background:var(--bg-secondary,#f4f4f4);padding:12px 14px 14px}.ai-chat-widget.dark .ai-chat-project-card__content,.chakra-ui-dark .ai-chat-project-card__content,.dark .ai-chat-project-card__content,[data-theme=dark] .ai-chat-project-card__content{background:var(--bg-secondary,#2a2a2a)}.ai-chat-project-card__title{color:var(--text-primary,#1a1a1a);font-size:14px;font-weight:600;line-height:1.35;margin:0 0 6px}.ai-chat-widget.dark .ai-chat-project-card__title,.chakra-ui-dark .ai-chat-project-card__title,.dark .ai-chat-project-card__title,[data-theme=dark] .ai-chat-project-card__title{color:#fff}.ai-chat-project-card__description{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-muted,#6b7280);display:-webkit-box;font-size:13px;line-height:1.45;margin:0 0 10px;overflow:hidden}.ai-chat-project-card__link{align-items:center;color:var(--action-accent);display:inline-flex;font-size:13px;font-weight:500;gap:4px;transition:opacity .2s}.ai-chat-project-card__link:hover{opacity:.8}.ai-chat-media-carousel{--action-accent:var(--primary-color,#3b82f6);border-radius:var(--radius-lg,12px);overflow:hidden;position:relative}.ai-chat-media-carousel__track{display:flex;transition:transform .3s ease-out}.ai-chat-media-carousel__slide{flex:0 0 100%;min-width:0}.ai-chat-media-carousel__slide .ai-chat-project-card{border-radius:var(--radius-md,8px);margin:0 4px}.ai-chat-media-carousel__nav{align-items:center;background:hsla(0,0%,100%,.9);border:none;border-radius:50%;box-shadow:0 2px 8px rgba(0,0,0,.15);color:#333;cursor:pointer;display:flex;height:32px;justify-content:center;position:absolute;top:50%;transform:translateY(-50%);transition:background .2s;width:32px;z-index:2}.ai-chat-media-carousel__nav:hover{background:#fff}.ai-chat-media-carousel__nav.prev{left:8px}.ai-chat-media-carousel__nav.next{right:8px}.ai-chat-widget.dark .ai-chat-media-carousel__nav,.chakra-ui-dark .ai-chat-media-carousel__nav,.dark .ai-chat-media-carousel__nav,[data-theme=dark] .ai-chat-media-carousel__nav{background:rgba(0,0,0,.7);color:#fff}.ai-chat-widget.dark .ai-chat-media-carousel__nav:hover,.chakra-ui-dark .ai-chat-media-carousel__nav:hover,.dark .ai-chat-media-carousel__nav:hover,[data-theme=dark] .ai-chat-media-carousel__nav:hover{background:rgba(0,0,0,.9)}.ai-chat-media-carousel__dots{display:flex;gap:6px;justify-content:center;padding:12px 0 4px}.ai-chat-media-carousel__dot{background:var(--border-subtle,rgba(0,0,0,.2));border:none;border-radius:50%;cursor:pointer;height:8px;padding:0;transition:background .2s,transform .2s;width:8px}.ai-chat-media-carousel__dot:hover{transform:scale(1.2)}.ai-chat-media-carousel__dot.active{background:var(--action-accent)}.ai-chat-widget.dark .ai-chat-media-carousel__dot,.chakra-ui-dark .ai-chat-media-carousel__dot,.dark .ai-chat-media-carousel__dot,[data-theme=dark] .ai-chat-media-carousel__dot{background:hsla(0,0%,100%,.3)}.ai-chat-widget.dark .ai-chat-media-carousel__dot.active,.chakra-ui-dark .ai-chat-media-carousel__dot.active,.dark .ai-chat-media-carousel__dot.active,[data-theme=dark] .ai-chat-media-carousel__dot.active{background:var(--action-accent)}@media (max-width:480px){.ai-chat-media-carousel__nav{height:28px;width:28px}.ai-chat-media-carousel__nav.prev{left:4px}.ai-chat-media-carousel__nav.next{right:4px}.ai-chat-image-gallery__lightbox-nav,.ai-chat-media-gallery__lightbox-nav{height:40px;width:40px}.ai-chat-image-gallery__lightbox,.ai-chat-media-gallery__lightbox{padding:16px}.ai-chat-project-card__content{padding:10px 12px 12px}.ai-chat-project-card__title{font-size:13px}.ai-chat-project-card__description{font-size:12px}}.chat-fullpage{--fp-max-width:800px;--fp-padding-x:16px;--fp-padding-top-mobile:64px;--fp-padding-top-desktop:24px;--fp-padding-bottom:200px;--fp-input-bottom:0}.chat-fullpage .ai-chat-messages{background:transparent;flex:1 1 auto;height:auto;justify-content:flex-start;margin:0 auto;max-height:none;max-width:var(--fp-max-width);min-height:0!important;overflow-x:hidden!important;overflow-y:scroll!important;padding:var(--fp-padding-top-desktop) var(--fp-padding-x) var(--fp-padding-bottom);position:relative}@media (max-width:767px){.chat-fullpage .ai-chat-messages{padding-top:var(--fp-padding-top-mobile)!important}}@media (max-width:480px){.chat-fullpage .ai-chat-messages{padding-top:calc(var(--fp-padding-top-mobile) + env(safe-area-inset-top, 0px))}}.chat-fullpage .ai-chat-messages>.ai-chat-message:first-child,.chat-fullpage .ai-chat-messages>.ai-chat-welcome:first-child{margin-top:0}.chat-fullpage .ai-chat-message{animation:none}.chat-fullpage .ai-chat-message.user{max-width:85%}.chat-fullpage .ai-chat-message.user .ai-chat-message-content{background:var(--bg-muted,#f4f4f5);border-radius:24px;color:#000;padding:8px 16px}.chat-fullpage.dark .ai-chat-message.user .ai-chat-message-content{background:var(--bg-muted,#27272a);color:#fff}.chat-fullpage .ai-chat-message.assistant{width:100%}.chat-fullpage .ai-chat-message.assistant .ai-chat-message-content{color:#000;padding:8px 16px}.chat-fullpage.dark .ai-chat-message.assistant .ai-chat-message-content{color:#fff}.chat-fullpage .ai-chat-message.tool{margin:0;padding:0;width:100%}.chat-fullpage .ai-chat-welcome{align-items:center;display:flex;flex-direction:column;gap:24px;justify-content:center;min-height:60vh;padding:24px;text-align:center}.chat-fullpage .ai-chat-welcome-title{font-size:32px;font-weight:600}.chat-fullpage .ai-chat-welcome-text{color:var(--text-muted,#71717a);font-size:18px;max-width:400px}.chat-fullpage .ai-chat-input-container{background:transparent;bottom:0;left:0;padding:16px 16px calc(16px + env(safe-area-inset-bottom));position:fixed;right:0;z-index:20}.chat-fullpage .ai-chat-input-container:after{background:var(--bg-primary,#fff);bottom:0;content:\"\";height:calc(40% + 16px);left:0;pointer-events:none;position:absolute;right:0;z-index:-1}.chat-fullpage.dark .ai-chat-input-container:after{background:var(--bg-primary,#18181b)}@media (min-width:769px){.chat-fullpage .ai-chat-input-container{background:transparent;bottom:var(--fp-input-bottom);left:50%;max-width:var(--fp-max-width);padding:12px 0 0;position:absolute;right:auto;transform:translateX(-50%);width:100%}}.chat-fullpage .ai-chat-input-wrapper{background:var(--bg-muted,#f4f4f5);border:1px solid var(--border-muted,#e4e4e7);border-radius:24px;box-shadow:0 1px 8px rgba(0,0,0,.06);margin:0 auto;max-width:var(--fp-max-width)}.chat-fullpage.dark .ai-chat-input-wrapper{background:var(--bg-muted,#27272a);border-color:var(--border-muted,#3f3f46);box-shadow:0 1px 12px rgba(0,0,0,.25)}.chat-fullpage .ai-chat-scroll-button{bottom:100px}@media (min-width:769px){.chat-fullpage .ai-chat-scroll-button{bottom:110px}}.chat-fullpage .ai-chat-suggested-questions{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;max-width:600px}.chat-fullpage .ai-chat-suggested-question{border-radius:9999px;font-size:14px;padding:8px 16px}.chat-fullpage .ai-chat-follow-up-suggestions{margin-top:12px}.chat-fullpage .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-default,#d4d4d8);color:#000}.chat-fullpage .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#f4f4f5)}.chat-fullpage.dark .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:#fff}.chat-fullpage.dark .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46)}.chat-fullpage .ai-chat-typing{padding:8px 16px}.chat-fullpage .ai-chat-message-meta{align-items:center;display:flex;gap:8px;margin-top:4px;padding:0 16px}.chat-fullpage .ai-chat-message-timestamp{color:var(--text-muted,#71717a);font-size:12px}.chat-fullpage .ai-chat-feedback{display:inline-flex}.chat-fullpage .ai-chat-feedback-button{display:flex}@media (max-width:480px){body.ai-chat-widget-open{height:100%!important;overflow:hidden!important;position:fixed!important;touch-action:none!important;width:100%!important}.ai-chat-widget-container:not(.is-open).bottom-right .ai-chat-button{bottom:12px!important;right:12px!important}.ai-chat-widget-container:not(.is-open).bottom-left .ai-chat-button{bottom:12px!important;left:12px!important}.ai-chat-widget-container:not(.is-open).top-right .ai-chat-button{right:12px!important;top:12px!important}.ai-chat-widget-container:not(.is-open).top-left .ai-chat-button{left:12px!important;top:12px!important}.ai-chat-widget-container.trigger-pill-text.container-mode:not(.is-open).bottom-right .ai-chat-trigger-pill{bottom:12px!important;right:12px!important}.ai-chat-widget-container.trigger-pill-text.container-mode:not(.is-open).bottom-left .ai-chat-trigger-pill{bottom:12px!important;left:12px!important}.ai-chat-widget-container.trigger-pill-text.container-mode:not(.is-open).top-right .ai-chat-trigger-pill{right:12px!important;top:12px!important}.ai-chat-widget-container.trigger-pill-text.container-mode:not(.is-open).top-left .ai-chat-trigger-pill{left:12px!important;top:12px!important}.ai-chat-widget-container.trigger-input-bar.container-mode:not(.is-open) .ai-chat-trigger-input-container{bottom:12px!important;left:12px!important;right:12px!important;width:calc(100% - 24px)!important}.ai-chat-widget-container.trigger-input-bar:not(.is-open) .ai-chat-trigger-input-wrapper{max-width:100%!important;width:100%!important}.ai-chat-widget-container.trigger-input-bar:not(.is-open) .ai-chat-trigger-input-row{display:flex;gap:8px;max-width:calc(100vw - 24px)!important;width:calc(100vw - 24px)!important}.ai-chat-widget-container.trigger-input-bar.is-collapsed:not(.is-open) .ai-chat-trigger-input-container{bottom:12px!important;right:12px!important;width:auto!important}.ai-chat-widget-container.trigger-input-bar.is-collapsed:not(.is-open) .ai-chat-button{margin-left:0!important;margin-right:0!important}.ai-chat-widget-container.is-open{height:100vh!important;height:100dvh!important;width:100vw!important;z-index:var(--widget-z-index,2147483647)!important}.ai-chat-widget-container.is-open,.ai-chat-widget-container.is-open .ai-chat-window{bottom:0!important;left:0!important;position:fixed!important;right:0!important;top:0!important}.ai-chat-widget-container.is-open .ai-chat-window{animation:none!important;border:none!important;border-radius:0!important;box-shadow:none!important;height:100%!important;max-height:100%!important;max-width:100%!important;outline:none!important;transform:none!important;width:100%!important}.ai-chat-widget-container.is-open .ai-chat-button{display:none!important;pointer-events:none!important;visibility:hidden!important}.ai-chat-widget-container.is-open .ai-chat-header{border-radius:0!important;flex-shrink:0;padding-left:max(16px,env(safe-area-inset-left));padding-right:max(16px,env(safe-area-inset-right));padding-top:max(12px,env(safe-area-inset-top));position:relative;z-index:100}.ai-chat-widget-container.is-open .ai-chat-messages{-webkit-overflow-scrolling:touch;flex:1;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;padding-bottom:120px;padding-left:max(16px,env(safe-area-inset-left));padding-right:max(16px,env(safe-area-inset-right));touch-action:pan-y}.ai-chat-widget-container.is-open .ai-chat-input-container{background:var(--bg-primary,#fff);bottom:0!important;left:0!important;padding:8px max(12px,env(safe-area-inset-right)) max(16px,calc(env(safe-area-inset-bottom) + 8px)) max(12px,env(safe-area-inset-left));position:fixed!important;right:0!important;z-index:100}.ai-chat-widget.dark .ai-chat-widget-container.is-open .ai-chat-input-container{background:var(--bg-primary,#282625)}.ai-chat-widget-container.is-open .ai-chat-input-container:after{display:none}.ai-chat-widget-container.is-open .ai-chat-input-wrapper{margin:0;max-width:100%}.ai-chat-widget-container.is-open .ai-chat-scroll-button{bottom:calc(80px + env(safe-area-inset-bottom))}.ai-chat-widget-container.is-open .ai-chat-welcome{padding:16px 0}.ai-chat-widget-container.is-open .ai-chat-welcome-title{font-size:24px}.ai-chat-widget-container.is-open .ai-chat-suggested-questions{align-items:stretch;flex-direction:column}.ai-chat-widget-container.is-open .ai-chat-suggested-question{text-align:center;width:100%}.ai-chat-widget-container.is-open .ai-chat-message-meta{align-items:center;display:flex;gap:8px;margin-top:4px}.ai-chat-widget-container.is-open .ai-chat-message-timestamp{font-size:11px}.ai-chat-widget-container.is-open .ai-chat-feedback{display:inline-flex}.ai-chat-widget-container.is-open .ai-chat-feedback-button{display:flex;padding:4px}.ai-chat-widget-container.is-open .ai-chat-input{font-size:16px!important}}@media (min-width:481px) and (max-width:768px){.ai-chat-widget-container.is-open .ai-chat-window{border-radius:22px 22px 44px 44px;max-height:calc(100vh - 100px);max-width:calc(100vw - 32px)}}.ai-chat-widget-container.desktop-mode.container-mode.is-open{height:100%!important;inset:0!important;position:absolute!important;width:100%!important}.ai-chat-widget-container.desktop-mode.container-mode.is-open .ai-chat-window{border:1px solid var(--border-color,rgba(0,0,0,.08))!important;border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) var(--radius-window-bottom,44px) var(--radius-window-bottom,44px)!important;box-shadow:var(--window-shadow,0 20px 60px -10px rgba(0,0,0,.25))!important;position:absolute!important}.ai-chat-widget-container.desktop-mode.container-mode.size-small.is-open .ai-chat-window{height:min(500px,calc(100% - 120px))!important;max-height:500px!important;max-width:380px!important;min-height:300px!important;min-width:280px!important;width:min(380px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.size-medium.is-open .ai-chat-window{height:min(65%,calc(100% - 120px))!important;max-height:680px!important;max-width:440px!important;min-height:400px!important;min-width:320px!important;width:min(440px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.size-large.is-open .ai-chat-window{height:calc(100% - 100px)!important;max-height:calc(100% - 100px)!important;max-width:560px!important;min-height:500px!important;min-width:380px!important;width:min(560px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.is-open.bottom-right .ai-chat-window{bottom:88px!important;left:auto!important;right:20px!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode.is-open.bottom-left .ai-chat-window{bottom:88px!important;left:20px!important;right:auto!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode.is-open.top-right .ai-chat-window{bottom:auto!important;left:auto!important;right:20px!important;top:88px!important}.ai-chat-widget-container.desktop-mode.container-mode.is-open.top-left .ai-chat-window{bottom:auto!important;left:20px!important;right:auto!important;top:88px!important}.ai-chat-widget-container.desktop-mode.is-open .ai-chat-button{display:flex!important;opacity:1!important;pointer-events:auto!important;visibility:visible!important}.ai-chat-widget-container.desktop-mode.container-mode:not(.trigger-input-bar).bottom-right .ai-chat-button{bottom:20px!important;left:auto!important;right:20px!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode:not(.trigger-input-bar).bottom-left .ai-chat-button{bottom:20px!important;left:20px!important;right:auto!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode:not(.trigger-input-bar).top-right .ai-chat-button{bottom:auto!important;left:auto!important;right:20px!important;top:20px!important}.ai-chat-widget-container.desktop-mode.container-mode:not(.trigger-input-bar).top-left .ai-chat-button{bottom:auto!important;left:20px!important;right:auto!important;top:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.bottom-right .ai-chat-trigger-input-container{bottom:20px!important;left:auto!important;right:20px!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.bottom-left .ai-chat-trigger-input-container{bottom:20px!important;left:20px!important;right:auto!important;top:auto!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.top-right .ai-chat-trigger-input-container{bottom:auto!important;left:auto!important;right:20px!important;top:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.top-left .ai-chat-trigger-input-container{bottom:auto!important;left:20px!important;right:auto!important;top:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.size-small .ai-chat-trigger-input-container{width:min(380px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.size-medium .ai-chat-trigger-input-container{width:min(440px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.size-large .ai-chat-trigger-input-container{width:min(560px,calc(100% - 40px))!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.bottom-left .ai-chat-window,.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.bottom-right .ai-chat-window{bottom:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.top-left .ai-chat-window,.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.top-right .ai-chat-window{top:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.bottom-right .ai-chat-window,.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.top-right .ai-chat-window{left:auto!important;right:20px!important}.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.bottom-left .ai-chat-window,.ai-chat-widget-container.desktop-mode.container-mode.trigger-input-bar.is-open.top-left .ai-chat-window{left:20px!important;right:auto!important}";
|
|
47095
47921
|
styleInject(css_248z$1);
|
|
47096
47922
|
|
|
47097
|
-
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{
|
|
47923
|
+
var css_248z = ".ai-chat-data-policy-view{display:flex;flex:1;flex-direction:column;min-height:0;overflow:hidden}.ai-chat-data-policy-content{-webkit-overflow-scrolling:touch;flex:1;overflow-y:auto;padding:20px 16px 40px}.ai-chat-data-policy-intro{margin-bottom:24px}.ai-chat-data-policy-intro p{color:var(--text-primary,#18181b);font-size:13px;line-height:1.6;margin:0;text-align:left}.ai-chat-widget.dark .ai-chat-data-policy-intro p{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-intro strong{color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-data-policy-intro strong{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section{margin-bottom:20px}.ai-chat-data-policy-section h3{color:var(--text-primary,#18181b);font-size:14px;font-weight:600;margin:0 0 12px}.ai-chat-widget.dark .ai-chat-data-policy-section h3{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section p{color:var(--text-secondary,#52525b);font-size:12px;line-height:1.6;margin:0 0 12px;text-align:justify;text-justify:inter-word}.ai-chat-widget.dark .ai-chat-data-policy-section p{color:var(--text-secondary,#a1a1aa)}.ai-chat-data-policy-section p strong{color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-data-policy-section p strong{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section p:last-child{margin-bottom:0}.ai-chat-widget-embedded .ai-chat-data-policy-view{-webkit-overflow-scrolling:touch;overflow-y:auto}.ai-chat-widget-embedded .ai-chat-data-policy-content{margin:0 auto;max-width:640px;overflow-y:visible;padding:32px 24px 60px}.ai-chat-widget-embedded .ai-chat-data-policy-intro p{font-size:14px;line-height:1.7}.ai-chat-widget-embedded .ai-chat-data-policy-section h3{font-size:15px;margin-bottom:14px}.ai-chat-widget-embedded .ai-chat-data-policy-section p{font-size:13px;line-height:1.7}.ai-chat-widget-embedded.dark .ai-chat-data-policy-intro p,.ai-chat-widget-embedded.dark .ai-chat-data-policy-intro strong,.ai-chat-widget-embedded.dark .ai-chat-data-policy-section h3{color:var(--text-primary,#fafafa)}.ai-chat-widget-embedded.dark .ai-chat-data-policy-section p{color:var(--text-secondary,#a1a1aa)}.ai-chat-widget-embedded.dark .ai-chat-data-policy-section p strong{color:var(--text-primary,#fafafa)}";
|
|
47098
47924
|
styleInject(css_248z);
|
|
47099
47925
|
|
|
47100
|
-
|
|
47101
|
-
const iconComponents = {
|
|
47102
|
-
FiMessageCircle: () => (jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.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" }) })),
|
|
47103
|
-
FiChevronDown: () => (jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "6 9 12 15 18 9" }) })),
|
|
47104
|
-
};
|
|
47105
|
-
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', }) => {
|
|
47926
|
+
const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = false, previewConfig, position = 'bottom-right', primaryColor, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, welcomeBubbleText, triggerType, triggerText, theme, suggestedQuestions, customStyles, currentRoute, defaultOpen = false, zIndex, containerMode = false, mobileMode = false, desktopMode = false, onOpen, onClose, onMessage, onError, mode = 'bubble', }) => {
|
|
47106
47927
|
const [isOpen, setIsOpen] = reactExports.useState(defaultOpen);
|
|
47107
|
-
const [
|
|
47928
|
+
const [inputBarValue, setInputBarValue] = reactExports.useState('');
|
|
47108
47929
|
const [showWelcomeBubble, setShowWelcomeBubble] = reactExports.useState(false);
|
|
47930
|
+
const [isInputBarCollapsed, setIsInputBarCollapsed] = reactExports.useState(false);
|
|
47109
47931
|
const widgetRef = reactExports.useRef(null);
|
|
47110
47932
|
const containerRef = reactExports.useRef(null);
|
|
47111
47933
|
// Determine mode
|
|
@@ -47154,13 +47976,14 @@
|
|
|
47154
47976
|
},
|
|
47155
47977
|
};
|
|
47156
47978
|
// Always call useChat hook (React rules), but skip initialization in preview mode
|
|
47979
|
+
const shouldSkipInit = previewMode;
|
|
47157
47980
|
const chatHook = useChat({
|
|
47158
47981
|
widgetId: previewMode ? '__preview__' : (widgetId || '__preview__'),
|
|
47159
47982
|
apiUrl,
|
|
47160
47983
|
currentRoute,
|
|
47161
|
-
onMessage:
|
|
47162
|
-
onError:
|
|
47163
|
-
skipInitialization:
|
|
47984
|
+
onMessage: shouldSkipInit ? undefined : onMessage,
|
|
47985
|
+
onError: shouldSkipInit ? undefined : onError,
|
|
47986
|
+
skipInitialization: shouldSkipInit,
|
|
47164
47987
|
});
|
|
47165
47988
|
// Extract values from hook or use preview defaults
|
|
47166
47989
|
const messages = previewMode ? [] : chatHook.messages;
|
|
@@ -47169,37 +47992,32 @@
|
|
|
47169
47992
|
const config = previewMode ? mergedPreviewConfig : chatHook.config;
|
|
47170
47993
|
const sendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
|
|
47171
47994
|
const submitFeedback = previewMode ? (() => Promise.resolve()) : chatHook.submitFeedback;
|
|
47995
|
+
const dismissAction = previewMode ? (() => Promise.resolve()) : chatHook.dismissAction;
|
|
47172
47996
|
const conversations = previewMode ? [] : chatHook.conversations;
|
|
47173
47997
|
const loadConversations = previewMode ? (() => { }) : chatHook.loadConversations;
|
|
47174
47998
|
const switchConversation = previewMode ? (() => Promise.resolve()) : chatHook.switchConversation;
|
|
47175
47999
|
const startNewConversation = previewMode ? (() => { }) : chatHook.startNewConversation;
|
|
47176
48000
|
const deleteConversation = previewMode ? (() => { }) : chatHook.deleteConversation;
|
|
47177
48001
|
const conversationId = previewMode ? '' : chatHook.conversationId;
|
|
47178
|
-
|
|
47179
|
-
|
|
47180
|
-
|
|
47181
|
-
|
|
47182
|
-
|
|
47183
|
-
|
|
47184
|
-
|
|
47185
|
-
|
|
47186
|
-
|
|
47187
|
-
|
|
47188
|
-
|
|
47189
|
-
|
|
47190
|
-
|
|
47191
|
-
|
|
47192
|
-
|
|
47193
|
-
|
|
47194
|
-
|
|
47195
|
-
|
|
47196
|
-
|
|
47197
|
-
mediaQuery.addEventListener('change', handleMediaChange);
|
|
47198
|
-
return () => {
|
|
47199
|
-
observer.disconnect();
|
|
47200
|
-
mediaQuery.removeEventListener('change', handleMediaChange);
|
|
47201
|
-
};
|
|
47202
|
-
}, [config]);
|
|
48002
|
+
const callActionEndpoint = previewMode ? (async () => { throw new Error('Not available in preview mode'); }) : chatHook.callActionEndpoint;
|
|
48003
|
+
const { effectiveTheme, effectivePosition, accentColor, iconContrastColor, effectiveSize, effectiveHeaderTitle, effectiveWelcomeTitle, effectiveWelcomeMessage, effectivePlaceholder, effectiveWelcomeBubbleText, effectiveTriggerType, effectiveTriggerText, mergedStyles, } = useWidgetAppearance({
|
|
48004
|
+
containerRef,
|
|
48005
|
+
config,
|
|
48006
|
+
theme,
|
|
48007
|
+
primaryColor,
|
|
48008
|
+
position,
|
|
48009
|
+
size,
|
|
48010
|
+
headerTitle,
|
|
48011
|
+
welcomeTitle,
|
|
48012
|
+
welcomeMessage,
|
|
48013
|
+
placeholder,
|
|
48014
|
+
welcomeBubbleText,
|
|
48015
|
+
triggerType,
|
|
48016
|
+
triggerText,
|
|
48017
|
+
customStyles,
|
|
48018
|
+
zIndex,
|
|
48019
|
+
previewMode,
|
|
48020
|
+
});
|
|
47203
48021
|
// Check if device is mobile
|
|
47204
48022
|
const isMobile = typeof window !== 'undefined' && window.innerWidth <= 480;
|
|
47205
48023
|
// Handle auto-open (only for bubble mode, disabled on mobile)
|
|
@@ -47244,8 +48062,8 @@
|
|
|
47244
48062
|
document.body.classList.remove('ai-chat-widget-open');
|
|
47245
48063
|
};
|
|
47246
48064
|
}, [isOpen, isEmbedded]);
|
|
47247
|
-
// Handle welcome bubble visibility
|
|
47248
|
-
//
|
|
48065
|
+
// Handle welcome bubble visibility based on frequency setting
|
|
48066
|
+
// Frequency options: 'always' (every page visit), 'session', 'weekly', 'monthly'
|
|
47249
48067
|
reactExports.useEffect(() => {
|
|
47250
48068
|
if (isEmbedded || previewMode)
|
|
47251
48069
|
return;
|
|
@@ -47254,42 +48072,72 @@
|
|
|
47254
48072
|
setShowWelcomeBubble(false);
|
|
47255
48073
|
return;
|
|
47256
48074
|
}
|
|
47257
|
-
|
|
48075
|
+
const frequency = config?.appearance?.welcomeBubbleFrequency ?? 'session';
|
|
47258
48076
|
const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
|
|
47259
|
-
|
|
47260
|
-
|
|
48077
|
+
// Check if bubble should be shown based on frequency
|
|
48078
|
+
const shouldShowBubble = () => {
|
|
48079
|
+
if (frequency === 'always') {
|
|
48080
|
+
// Always show on every page visit (no storage check)
|
|
48081
|
+
return true;
|
|
48082
|
+
}
|
|
48083
|
+
if (frequency === 'session') {
|
|
48084
|
+
// Show once per session
|
|
48085
|
+
return sessionStorage.getItem(storageKey) !== 'true';
|
|
48086
|
+
}
|
|
48087
|
+
// For weekly/monthly, use localStorage with timestamp
|
|
48088
|
+
try {
|
|
48089
|
+
const stored = localStorage.getItem(storageKey);
|
|
48090
|
+
if (!stored)
|
|
48091
|
+
return true;
|
|
48092
|
+
const dismissedAt = parseInt(stored, 10);
|
|
48093
|
+
if (isNaN(dismissedAt))
|
|
48094
|
+
return true;
|
|
48095
|
+
const now = Date.now();
|
|
48096
|
+
const weekMs = 7 * 24 * 60 * 60 * 1000;
|
|
48097
|
+
const monthMs = 30 * 24 * 60 * 60 * 1000;
|
|
48098
|
+
if (frequency === 'weekly') {
|
|
48099
|
+
return now - dismissedAt > weekMs;
|
|
48100
|
+
}
|
|
48101
|
+
if (frequency === 'monthly') {
|
|
48102
|
+
return now - dismissedAt > monthMs;
|
|
48103
|
+
}
|
|
48104
|
+
}
|
|
48105
|
+
catch {
|
|
48106
|
+
return true;
|
|
48107
|
+
}
|
|
48108
|
+
return true;
|
|
48109
|
+
};
|
|
48110
|
+
if (shouldShowBubble() && !isOpen) {
|
|
47261
48111
|
setShowWelcomeBubble(true);
|
|
47262
48112
|
}
|
|
47263
48113
|
}, [widgetId, welcomeBubbleText, config, isOpen, isEmbedded, previewMode]);
|
|
47264
|
-
|
|
47265
|
-
|
|
47266
|
-
|
|
47267
|
-
|
|
47268
|
-
|
|
47269
|
-
|
|
47270
|
-
|
|
47271
|
-
|
|
47272
|
-
|
|
47273
|
-
|
|
47274
|
-
|
|
47275
|
-
|
|
47276
|
-
|
|
47277
|
-
|
|
47278
|
-
|
|
47279
|
-
|
|
47280
|
-
|
|
47281
|
-
|
|
47282
|
-
|
|
47283
|
-
|
|
47284
|
-
|
|
47285
|
-
|
|
47286
|
-
|
|
47287
|
-
|
|
47288
|
-
|
|
47289
|
-
|
|
47290
|
-
|
|
47291
|
-
...customStyles,
|
|
47292
|
-
...(zIndex !== undefined ? { '--widget-z-index': String(zIndex) } : {}),
|
|
48114
|
+
const handleStartNewConversation = reactExports.useCallback(() => {
|
|
48115
|
+
startNewConversation();
|
|
48116
|
+
}, [startNewConversation]);
|
|
48117
|
+
const handleSendMessage = reactExports.useCallback((content) => {
|
|
48118
|
+
sendMessage(content);
|
|
48119
|
+
}, [sendMessage]);
|
|
48120
|
+
// Dismiss bubble and store based on frequency setting
|
|
48121
|
+
const dismissBubble = () => {
|
|
48122
|
+
setShowWelcomeBubble(false);
|
|
48123
|
+
const frequency = config?.appearance?.welcomeBubbleFrequency ?? 'session';
|
|
48124
|
+
const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
|
|
48125
|
+
try {
|
|
48126
|
+
if (frequency === 'always') {
|
|
48127
|
+
// For 'always', use sessionStorage so it only hides until page refresh
|
|
48128
|
+
sessionStorage.setItem(storageKey, 'true');
|
|
48129
|
+
}
|
|
48130
|
+
else if (frequency === 'session') {
|
|
48131
|
+
sessionStorage.setItem(storageKey, 'true');
|
|
48132
|
+
}
|
|
48133
|
+
else {
|
|
48134
|
+
// For weekly/monthly, store timestamp in localStorage
|
|
48135
|
+
localStorage.setItem(storageKey, String(Date.now()));
|
|
48136
|
+
}
|
|
48137
|
+
}
|
|
48138
|
+
catch {
|
|
48139
|
+
// Ignore storage errors
|
|
48140
|
+
}
|
|
47293
48141
|
};
|
|
47294
48142
|
const handleToggle = () => {
|
|
47295
48143
|
if (isEmbedded)
|
|
@@ -47298,15 +48146,7 @@
|
|
|
47298
48146
|
setIsOpen(newState);
|
|
47299
48147
|
// Dismiss welcome bubble when chat is opened
|
|
47300
48148
|
if (newState && showWelcomeBubble) {
|
|
47301
|
-
|
|
47302
|
-
// Store in sessionStorage so it doesn't show again this session
|
|
47303
|
-
const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
|
|
47304
|
-
try {
|
|
47305
|
-
sessionStorage.setItem(storageKey, 'true');
|
|
47306
|
-
}
|
|
47307
|
-
catch {
|
|
47308
|
-
// Ignore storage errors
|
|
47309
|
-
}
|
|
48149
|
+
dismissBubble();
|
|
47310
48150
|
}
|
|
47311
48151
|
if (newState) {
|
|
47312
48152
|
onOpen?.();
|
|
@@ -47315,6 +48155,24 @@
|
|
|
47315
48155
|
onClose?.();
|
|
47316
48156
|
}
|
|
47317
48157
|
};
|
|
48158
|
+
const handleDismissBubble = (e) => {
|
|
48159
|
+
e.stopPropagation();
|
|
48160
|
+
dismissBubble();
|
|
48161
|
+
};
|
|
48162
|
+
// Handle input bar submit - opens widget and sends message
|
|
48163
|
+
const handleInputBarSubmit = reactExports.useCallback((e) => {
|
|
48164
|
+
e.preventDefault();
|
|
48165
|
+
if (!inputBarValue.trim() || previewMode)
|
|
48166
|
+
return;
|
|
48167
|
+
// Open the widget
|
|
48168
|
+
setIsOpen(true);
|
|
48169
|
+
onOpen?.();
|
|
48170
|
+
// Send the message after a brief delay to allow widget to open
|
|
48171
|
+
setTimeout(() => {
|
|
48172
|
+
sendMessage(inputBarValue.trim());
|
|
48173
|
+
setInputBarValue('');
|
|
48174
|
+
}, 100);
|
|
48175
|
+
}, [inputBarValue, previewMode, onOpen, sendMessage]);
|
|
47318
48176
|
const handleFeedback = async (messageId, feedback) => {
|
|
47319
48177
|
await submitFeedback(messageId, feedback);
|
|
47320
48178
|
};
|
|
@@ -47330,21 +48188,35 @@
|
|
|
47330
48188
|
sendMessage(actionInstruction);
|
|
47331
48189
|
};
|
|
47332
48190
|
// Don't render until config is loaded to avoid flash of unstyled content
|
|
48191
|
+
// Exceptions that allow immediate rendering:
|
|
48192
|
+
// 1. triggerType prop provided - user wants specific trigger shown immediately
|
|
48193
|
+
// 2. primaryColor prop provided - we have initial styling, no flash will occur
|
|
48194
|
+
// This improves perceived loading speed - users see the correctly styled trigger while config loads
|
|
47333
48195
|
// In preview mode, config is always available
|
|
47334
|
-
|
|
48196
|
+
const hasInitialStyling = !!primaryColor;
|
|
48197
|
+
const canRenderWithoutConfig = !!triggerType || hasInitialStyling;
|
|
48198
|
+
if (!config && !previewMode && !canRenderWithoutConfig) {
|
|
47335
48199
|
return null;
|
|
47336
48200
|
}
|
|
47337
48201
|
// Get button icon based on state
|
|
47338
48202
|
const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
|
|
47339
48203
|
// Embedded mode renders directly without wrapper positioning
|
|
47340
48204
|
if (isEmbedded) {
|
|
47341
|
-
return (jsxRuntimeExports.jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsxRuntimeExports.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage:
|
|
47342
|
-
}
|
|
47343
|
-
|
|
48205
|
+
return (jsxRuntimeExports.jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsxRuntimeExports.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage: handleSendMessage, onClose: () => { }, onFeedback: handleFeedback, onActionClick: handleActionClick, onActionDismiss: dismissAction, onCallEndpoint: callActionEndpoint, conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: handleStartNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, sizeOverride: effectiveSize, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions }) }));
|
|
48206
|
+
}
|
|
48207
|
+
// Determine trigger class for container
|
|
48208
|
+
const triggerClass = effectiveTriggerType === 'pill-text'
|
|
48209
|
+
? 'trigger-pill-text'
|
|
48210
|
+
: effectiveTriggerType === 'input-bar'
|
|
48211
|
+
? 'trigger-input-bar'
|
|
48212
|
+
: 'trigger-button';
|
|
48213
|
+
// Size class for CSS targeting (used by input-bar trigger for width matching)
|
|
48214
|
+
const sizeClass = `size-${effectiveSize}`;
|
|
48215
|
+
// Collapsed class for input bar
|
|
48216
|
+
const collapsedClass = isInputBarCollapsed ? 'is-collapsed' : '';
|
|
48217
|
+
return (jsxRuntimeExports.jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxRuntimeExports.jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition} ${isOpen ? 'is-open' : ''} ${containerMode ? 'container-mode' : ''} ${mobileMode ? 'mobile-mode' : ''} ${desktopMode ? 'desktop-mode' : ''} ${triggerClass} ${sizeClass} ${collapsedClass}`, children: [isOpen && (jsxRuntimeExports.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage: handleSendMessage, onClose: handleToggle, onFeedback: handleFeedback, onActionClick: handleActionClick, onActionDismiss: dismissAction, onCallEndpoint: callActionEndpoint,
|
|
47344
48218
|
// Chat history props (only active when persistConversation is true)
|
|
47345
|
-
conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation:
|
|
47346
|
-
// Override props for live preview
|
|
47347
|
-
headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), !isOpen && effectiveWelcomeBubbleText && (previewMode || showWelcomeBubble) && (jsxRuntimeExports.jsx("div", { className: "ai-chat-welcome-bubble", onClick: handleToggle, children: jsxRuntimeExports.jsx("span", { children: effectiveWelcomeBubbleText }) })), jsxRuntimeExports.jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsxRuntimeExports.jsx("div", { className: "ai-chat-button-svg", children: jsxRuntimeExports.jsx(IconComponent, {}) }) })] }) }));
|
|
48219
|
+
conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: handleStartNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, sizeOverride: effectiveSize, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), jsxRuntimeExports.jsx(WidgetTriggers, { triggerType: effectiveTriggerType, isOpen: isOpen, onToggle: handleToggle, triggerText: effectiveTriggerText, placeholder: effectivePlaceholder, IconComponent: IconComponent, showWelcomeBubble: showWelcomeBubble, welcomeBubbleText: effectiveWelcomeBubbleText, previewMode: previewMode, onDismissBubble: handleDismissBubble, isInputBarCollapsed: isInputBarCollapsed, setIsInputBarCollapsed: setIsInputBarCollapsed, inputBarValue: inputBarValue, setInputBarValue: setInputBarValue, onSubmitInputBar: handleInputBarSubmit, accentColor: accentColor, iconColor: iconContrastColor })] }) }));
|
|
47348
48220
|
};
|
|
47349
48221
|
|
|
47350
48222
|
/**
|