@courseecho/ai-core-sdk 1.0.28 → 1.0.30
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/communication-service.d.ts +45 -1
- package/dist/communication-service.js +94 -0
- package/dist/models.d.ts +30 -0
- package/dist/sdk.d.ts +15 -2
- package/dist/sdk.js +22 -1
- package/dist/widget-css.d.ts +1 -1
- package/dist/widget-css.js +17 -1
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* AI Widget SDK - Core Communication Service
|
|
3
3
|
* Handle HTTP requests to backend API
|
|
4
4
|
*/
|
|
5
|
-
import { AiQueryRequest, AiQueryResponse, QuotaInfo } from './models';
|
|
5
|
+
import { AiQueryRequest, AiQueryResponse, QuotaInfo, ChatHistoryMessage } from './models';
|
|
6
6
|
export declare class AiCommunicationService {
|
|
7
7
|
private apiEndpoint;
|
|
8
8
|
private apiKey?;
|
|
@@ -16,14 +16,58 @@ export declare class AiCommunicationService {
|
|
|
16
16
|
private lastRequestAt;
|
|
17
17
|
/** Minimum ms between requests (default 1 500 — human typing speed floor) */
|
|
18
18
|
private minRequestIntervalMs;
|
|
19
|
+
/**
|
|
20
|
+
* Browser-generated UUID persisted in sessionStorage.
|
|
21
|
+
* Clears when the browser tab closes — so anonymous users get session-only history.
|
|
22
|
+
* Logged-in users are identified by `userId` instead.
|
|
23
|
+
*/
|
|
24
|
+
private readonly anonymousId;
|
|
25
|
+
/**
|
|
26
|
+
* Customer's end-user ID. Set via `setUser()` when the user logs into the
|
|
27
|
+
* customer's application. When set, chat history is stored in the DB and
|
|
28
|
+
* persists across sessions.
|
|
29
|
+
*/
|
|
30
|
+
private userId;
|
|
19
31
|
constructor(apiEndpoint: string, apiKey?: string, minRequestIntervalMs?: number);
|
|
20
32
|
/** Override the minimum request interval at runtime. */
|
|
21
33
|
setMinRequestInterval(ms: number): void;
|
|
34
|
+
/** Returns the anonymous session UUID (sessionStorage — resets on browser close). */
|
|
35
|
+
getAnonymousId(): string;
|
|
36
|
+
/** Returns the current end-user ID, or null if not logged in. */
|
|
37
|
+
getUserId(): string | null;
|
|
38
|
+
/**
|
|
39
|
+
* Identify the logged-in user.
|
|
40
|
+
* - Sets the userId so every subsequent query is tagged with it in the DB.
|
|
41
|
+
* - Does NOT automatically sync anonymous history — call `syncSession()` for that.
|
|
42
|
+
*/
|
|
43
|
+
setUser(userId: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Migrate anonymous session messages to the logged-in user.
|
|
46
|
+
* Call this immediately after the user logs in (before or after setUser).
|
|
47
|
+
* Updates all Conversation rows that share the anonymousId to carry the userId.
|
|
48
|
+
*/
|
|
49
|
+
syncSession(userId: string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Fetch chat history from the DB.
|
|
52
|
+
*
|
|
53
|
+
* - Logged-in users (userId set) → queries by userId → full persistent history
|
|
54
|
+
* - Anonymous users (no userId) → queries by anonymousId → session history only
|
|
55
|
+
*
|
|
56
|
+
* Returns messages in chronological order (oldest first).
|
|
57
|
+
* Returns an empty array on error rather than throwing.
|
|
58
|
+
*/
|
|
59
|
+
loadHistory(limit?: number): Promise<ChatHistoryMessage[]>;
|
|
22
60
|
/**
|
|
23
61
|
* Generate a random session identifier (UUID v4-like) that persists for the
|
|
24
62
|
* lifetime of the communication-service instance (= one widget mount).
|
|
25
63
|
*/
|
|
26
64
|
private static generateSessionId;
|
|
65
|
+
/**
|
|
66
|
+
* Retrieve (or create) a stable anonymous browser session ID from sessionStorage.
|
|
67
|
+
* Stored in sessionStorage so it resets when the browser tab closes — giving
|
|
68
|
+
* anonymous users session-scoped history only (not persistent like logged-in users).
|
|
69
|
+
*/
|
|
70
|
+
private static getOrCreateAnonymousId;
|
|
27
71
|
/**
|
|
28
72
|
* Build a stable, non-PII browser fingerprint string.
|
|
29
73
|
* This is NOT a tracking fingerprint — it only helps the backend distinguish
|
|
@@ -46,6 +46,12 @@ export class AiCommunicationService {
|
|
|
46
46
|
this.lastQuotaInfo = null;
|
|
47
47
|
/** Timestamp of the last outgoing AI query (ms) */
|
|
48
48
|
this.lastRequestAt = 0;
|
|
49
|
+
/**
|
|
50
|
+
* Customer's end-user ID. Set via `setUser()` when the user logs into the
|
|
51
|
+
* customer's application. When set, chat history is stored in the DB and
|
|
52
|
+
* persists across sessions.
|
|
53
|
+
*/
|
|
54
|
+
this.userId = null;
|
|
49
55
|
if (!apiEndpoint) {
|
|
50
56
|
throw new Error('apiEndpoint is required');
|
|
51
57
|
}
|
|
@@ -54,11 +60,77 @@ export class AiCommunicationService {
|
|
|
54
60
|
this.minRequestIntervalMs = minRequestIntervalMs;
|
|
55
61
|
this.sessionId = AiCommunicationService.generateSessionId();
|
|
56
62
|
this.clientFingerprint = AiCommunicationService.generateFingerprint();
|
|
63
|
+
this.anonymousId = AiCommunicationService.getOrCreateAnonymousId();
|
|
57
64
|
}
|
|
58
65
|
/** Override the minimum request interval at runtime. */
|
|
59
66
|
setMinRequestInterval(ms) {
|
|
60
67
|
this.minRequestIntervalMs = ms;
|
|
61
68
|
}
|
|
69
|
+
// ── User identity + chat history ─────────────────────────────────────
|
|
70
|
+
/** Returns the anonymous session UUID (sessionStorage — resets on browser close). */
|
|
71
|
+
getAnonymousId() { return this.anonymousId; }
|
|
72
|
+
/** Returns the current end-user ID, or null if not logged in. */
|
|
73
|
+
getUserId() { return this.userId; }
|
|
74
|
+
/**
|
|
75
|
+
* Identify the logged-in user.
|
|
76
|
+
* - Sets the userId so every subsequent query is tagged with it in the DB.
|
|
77
|
+
* - Does NOT automatically sync anonymous history — call `syncSession()` for that.
|
|
78
|
+
*/
|
|
79
|
+
setUser(userId) {
|
|
80
|
+
this.userId = userId || null;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Migrate anonymous session messages to the logged-in user.
|
|
84
|
+
* Call this immediately after the user logs in (before or after setUser).
|
|
85
|
+
* Updates all Conversation rows that share the anonymousId to carry the userId.
|
|
86
|
+
*/
|
|
87
|
+
async syncSession(userId) {
|
|
88
|
+
try {
|
|
89
|
+
this.userId = userId;
|
|
90
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
91
|
+
if (this.jwtToken)
|
|
92
|
+
headers['Authorization'] = `Bearer ${this.jwtToken}`;
|
|
93
|
+
else if (this.apiKey)
|
|
94
|
+
headers['X-API-Key'] = this.apiKey;
|
|
95
|
+
await fetch(`${this.apiEndpoint}/api/chat/sync`, {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
headers,
|
|
98
|
+
body: JSON.stringify({ anonymousId: this.anonymousId, userId }),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
catch { /* non-fatal — history sync is best-effort */ }
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Fetch chat history from the DB.
|
|
105
|
+
*
|
|
106
|
+
* - Logged-in users (userId set) → queries by userId → full persistent history
|
|
107
|
+
* - Anonymous users (no userId) → queries by anonymousId → session history only
|
|
108
|
+
*
|
|
109
|
+
* Returns messages in chronological order (oldest first).
|
|
110
|
+
* Returns an empty array on error rather than throwing.
|
|
111
|
+
*/
|
|
112
|
+
async loadHistory(limit = 30) {
|
|
113
|
+
try {
|
|
114
|
+
const params = new URLSearchParams({ limit: String(limit) });
|
|
115
|
+
if (this.userId)
|
|
116
|
+
params.set('userId', this.userId);
|
|
117
|
+
else
|
|
118
|
+
params.set('anonymousId', this.anonymousId);
|
|
119
|
+
const headers = {};
|
|
120
|
+
if (this.jwtToken)
|
|
121
|
+
headers['Authorization'] = `Bearer ${this.jwtToken}`;
|
|
122
|
+
else if (this.apiKey)
|
|
123
|
+
headers['X-API-Key'] = this.apiKey;
|
|
124
|
+
const res = await fetch(`${this.apiEndpoint}/api/chat/history?${params}`, { headers });
|
|
125
|
+
if (!res.ok)
|
|
126
|
+
return [];
|
|
127
|
+
const data = await res.json();
|
|
128
|
+
return (data.messages ?? []);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
62
134
|
// ── Session / fingerprint helpers ─────────────────────────────────────
|
|
63
135
|
/**
|
|
64
136
|
* Generate a random session identifier (UUID v4-like) that persists for the
|
|
@@ -74,6 +146,26 @@ export class AiCommunicationService {
|
|
|
74
146
|
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
|
|
75
147
|
});
|
|
76
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Retrieve (or create) a stable anonymous browser session ID from sessionStorage.
|
|
151
|
+
* Stored in sessionStorage so it resets when the browser tab closes — giving
|
|
152
|
+
* anonymous users session-scoped history only (not persistent like logged-in users).
|
|
153
|
+
*/
|
|
154
|
+
static getOrCreateAnonymousId() {
|
|
155
|
+
const KEY = 'ce_anon_id';
|
|
156
|
+
try {
|
|
157
|
+
let id = typeof sessionStorage !== 'undefined' ? sessionStorage.getItem(KEY) : null;
|
|
158
|
+
if (!id) {
|
|
159
|
+
id = AiCommunicationService.generateSessionId();
|
|
160
|
+
if (typeof sessionStorage !== 'undefined')
|
|
161
|
+
sessionStorage.setItem(KEY, id);
|
|
162
|
+
}
|
|
163
|
+
return id;
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return AiCommunicationService.generateSessionId();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
77
169
|
/**
|
|
78
170
|
* Build a stable, non-PII browser fingerprint string.
|
|
79
171
|
* This is NOT a tracking fingerprint — it only helps the backend distinguish
|
|
@@ -158,6 +250,8 @@ export class AiCommunicationService {
|
|
|
158
250
|
pageText: request.pageText ?? capturePageText(8000),
|
|
159
251
|
pageUrl: request.pageUrl ?? (typeof window !== 'undefined' ? window.location.href : undefined),
|
|
160
252
|
pageTitle: request.pageTitle ?? (typeof window !== 'undefined' ? document.title : undefined),
|
|
253
|
+
anonymousId: this.anonymousId,
|
|
254
|
+
endUserId: this.userId ?? undefined,
|
|
161
255
|
};
|
|
162
256
|
try {
|
|
163
257
|
const response = await fetch(`${this.apiEndpoint}/api/aiorchestrator/query`, {
|
package/dist/models.d.ts
CHANGED
|
@@ -145,6 +145,20 @@ export interface AiContextConfig {
|
|
|
145
145
|
* Default: false
|
|
146
146
|
*/
|
|
147
147
|
showUsageCounter?: boolean;
|
|
148
|
+
/**
|
|
149
|
+
* Customer's end-user ID — when set, chat history is loaded from the DB
|
|
150
|
+
* and persists across sessions. Leave unset for anonymous (session-only) mode.
|
|
151
|
+
*
|
|
152
|
+
* Example: userId: currentUser.id
|
|
153
|
+
*/
|
|
154
|
+
userId?: string;
|
|
155
|
+
/**
|
|
156
|
+
* Widget config identifier — when a tenant has multiple widget configs (one per website),
|
|
157
|
+
* this tells the backend which website's scraped data to use for AI answers.
|
|
158
|
+
* Matches the configId in the Deploy-tab embed snippet (data-config-id attribute).
|
|
159
|
+
* Defaults to "default" on the backend if omitted.
|
|
160
|
+
*/
|
|
161
|
+
configId?: string;
|
|
148
162
|
/**
|
|
149
163
|
* Client-side abuse prevention settings.
|
|
150
164
|
* These defend against scripted quota-exhaustion attacks on behalf of your
|
|
@@ -210,8 +224,24 @@ export interface AiQueryRequest {
|
|
|
210
224
|
* and is not available in the server-side crawl.
|
|
211
225
|
*/
|
|
212
226
|
pageText?: string;
|
|
227
|
+
/** Browser-generated UUID from sessionStorage — identifies anonymous sessions. */
|
|
228
|
+
anonymousId?: string;
|
|
229
|
+
/** Customer's own end-user ID — set when the user is logged into the customer's app. */
|
|
230
|
+
endUserId?: string;
|
|
231
|
+
/**
|
|
232
|
+
* Widget config identifier — routes the query to the correct website's scraped data.
|
|
233
|
+
* Sent from the widget SDK; matches the configId in the Deploy-tab embed snippet.
|
|
234
|
+
* Defaults to "default" on the backend if omitted.
|
|
235
|
+
*/
|
|
236
|
+
configId?: string;
|
|
213
237
|
[key: string]: any;
|
|
214
238
|
}
|
|
239
|
+
/** A single message returned by GET /api/chat/history */
|
|
240
|
+
export interface ChatHistoryMessage {
|
|
241
|
+
role: 'user' | 'assistant';
|
|
242
|
+
content: string;
|
|
243
|
+
createdAt: string;
|
|
244
|
+
}
|
|
215
245
|
export interface AiQueryResponse {
|
|
216
246
|
sessionId: string;
|
|
217
247
|
response: string;
|
package/dist/sdk.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { AiCommunicationService } from './communication-service';
|
|
6
6
|
import { ChatStateManager, ContextStateManager, ChartManager, SuggestionManager } from './state-manager';
|
|
7
|
-
import { AiContextConfig, AiMessage, AiSuggestion } from './models';
|
|
7
|
+
import { AiContextConfig, AiMessage, AiSuggestion, ChatHistoryMessage } from './models';
|
|
8
8
|
import { PageContentScanner, AiSuggestionGenerator } from './auto-suggestion-generator';
|
|
9
9
|
export declare class AiWidgetSDK {
|
|
10
10
|
private communicationService;
|
|
@@ -43,8 +43,21 @@ export declare class AiWidgetSDK {
|
|
|
43
43
|
/** Get the currently stored JWT token (if any). */
|
|
44
44
|
getJwtToken(): string | undefined;
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
46
|
+
* Identify the logged-in user.
|
|
47
|
+
* 1. Persists userId for future queries.
|
|
48
|
+
* 2. Syncs any anonymous session messages to DB under this userId.
|
|
47
49
|
*/
|
|
50
|
+
setUser(userId: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Load chat history from the backend.
|
|
53
|
+
* For logged-in users fetches by userId; for anonymous users by anonymousId.
|
|
54
|
+
* @param limit Maximum number of messages to return (default 30).
|
|
55
|
+
*/
|
|
56
|
+
loadHistory(limit?: number): Promise<ChatHistoryMessage[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Get the current anonymous session ID (browser session-scoped UUID).
|
|
59
|
+
*/
|
|
60
|
+
getAnonymousId(): string;
|
|
48
61
|
sendQuery(userQuery: string): Promise<AiMessage>;
|
|
49
62
|
/**
|
|
50
63
|
* Update context
|
package/dist/sdk.js
CHANGED
|
@@ -116,8 +116,28 @@ export class AiWidgetSDK {
|
|
|
116
116
|
return this.communicationService.getJwtToken();
|
|
117
117
|
}
|
|
118
118
|
/**
|
|
119
|
-
*
|
|
119
|
+
* Identify the logged-in user.
|
|
120
|
+
* 1. Persists userId for future queries.
|
|
121
|
+
* 2. Syncs any anonymous session messages to DB under this userId.
|
|
120
122
|
*/
|
|
123
|
+
async setUser(userId) {
|
|
124
|
+
this.communicationService.setUser(userId);
|
|
125
|
+
await this.communicationService.syncSession(userId);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Load chat history from the backend.
|
|
129
|
+
* For logged-in users fetches by userId; for anonymous users by anonymousId.
|
|
130
|
+
* @param limit Maximum number of messages to return (default 30).
|
|
131
|
+
*/
|
|
132
|
+
async loadHistory(limit = 30) {
|
|
133
|
+
return this.communicationService.loadHistory(limit);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get the current anonymous session ID (browser session-scoped UUID).
|
|
137
|
+
*/
|
|
138
|
+
getAnonymousId() {
|
|
139
|
+
return this.communicationService.getAnonymousId();
|
|
140
|
+
}
|
|
121
141
|
async sendQuery(userQuery) {
|
|
122
142
|
try {
|
|
123
143
|
this.chatStateManager.setLoading(true);
|
|
@@ -136,6 +156,7 @@ export class AiWidgetSDK {
|
|
|
136
156
|
pageType: this.contextStateManager.getContext().pageType,
|
|
137
157
|
entityId: this.contextStateManager.getContext().entityId,
|
|
138
158
|
contextData: this.contextStateManager.getContext().customData,
|
|
159
|
+
configId: this.config.configId,
|
|
139
160
|
};
|
|
140
161
|
// Send to backend
|
|
141
162
|
const response = await this.communicationService.sendQuery(request);
|
package/dist/widget-css.d.ts
CHANGED
|
@@ -11,4 +11,4 @@
|
|
|
11
11
|
* Each package is responsible for loading the Inter font into document <head>
|
|
12
12
|
* separately (React: ensureFont(), jQuery: injectFontLink()).
|
|
13
13
|
*/
|
|
14
|
-
export declare const WIDGET_CSS = "\n/* \u2500\u2500 Shadow-DOM host isolation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n:host {\n all: initial !important;\n display: block !important;\n}\n\n/* Scoped box-model reset \u2014 only touches widget elements, not all of shadow DOM */\n.aiwg-root *, .aiwg-root *::before, .aiwg-root *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n/* \u2500\u2500 Container \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-root {\n --aiwg-primary: #6366f1;\n --aiwg-primary-dark: #8b5cf6;\n --aiwg-fg-color: #ffffff;\n --aiwg-bg-color: #ffffff;\n --aiwg-chat-bg: #f1f5f9;\n\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 14px;\n line-height: 1.5;\n color: #1a1a2e;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n border-radius: 16px;\n background: var(--aiwg-bg-color);\n position: fixed !important;\n bottom: 24px;\n right: 24px;\n width: 380px !important;\n max-width: calc(100vw - 48px) !important;\n z-index: 99999;\n transition: height 0.25s ease;\n box-shadow: 0 24px 64px rgba(0,0,0,0.18);\n}\n\n/* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-header {\n background: linear-gradient(135deg, var(--aiwg-primary) 0%, var(--aiwg-primary-dark) 100%);\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n position: relative;\n overflow: hidden;\n}\n.aiwg-header::before {\n content: '';\n position: absolute;\n width: 140px; height: 140px;\n background: rgba(255,255,255,0.08);\n border-radius: 50%;\n top: -50px; right: -30px;\n}\n.aiwg-avatar {\n width: 40px; height: 40px;\n background: rgba(255,255,255,0.25);\n border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n border: 2px solid rgba(255,255,255,0.4);\n}\n.aiwg-header-info { flex: 1; }\n.aiwg-title { color: #fff; font-weight: 600; font-size: 15px; }\n.aiwg-subtitle {\n color: rgba(255,255,255,0.75);\n font-size: 12px;\n display: flex; align-items: center; gap: 5px;\n}\n.aiwg-online-dot {\n width: 7px; height: 7px;\n background: #4ade80;\n border-radius: 50%;\n display: inline-block;\n animation: aiwg-pulse 2s ease-in-out infinite;\n}\n@keyframes aiwg-pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.6; transform: scale(0.85); }\n}\n.aiwg-minimize-btn {\n width: 36px; height: 36px;\n background: rgba(255,255,255,0.18);\n border: 1.5px solid rgba(255,255,255,0.3);\n border-radius: 50%;\n color: #fff; cursor: pointer;\n display: flex; align-items: center; justify-content: center;\n font-size: 18px; line-height: 1;\n transition: background 0.15s, transform 0.15s;\n flex-shrink: 0;\n position: relative; z-index: 2;\n}\n.aiwg-minimize-btn * { cursor: pointer !important; pointer-events: none; }\n.aiwg-minimize-btn:hover { background: rgba(255,255,255,0.32); transform: scale(1.08); }\n\n/* \u2500\u2500 Messages area \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-messages {\n flex: 1;\n overflow-y: auto;\n padding: 20px 16px 8px;\n scroll-behavior: smooth;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.aiwg-messages::-webkit-scrollbar { width: 4px; }\n.aiwg-messages::-webkit-scrollbar-thumb { background: #e2e8f0; border-radius: 99px; }\n\n/* \u2500\u2500 Welcome card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-welcome {\n text-align: center;\n padding: 24px 16px;\n display: flex; flex-direction: column; align-items: center; gap: 8px;\n}\n.aiwg-welcome-icon { font-size: 36px; margin-bottom: 4px; }\n.aiwg-welcome h4 { font-size: 15px; font-weight: 600; color: #1a1a2e; }\n.aiwg-welcome p { font-size: 13px; color: #64748b; }\n\n/* \u2500\u2500 Message bubbles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-msg {\n display: flex;\n gap: 8px;\n align-items: flex-end;\n animation: aiwg-fade-up 0.2s ease both;\n}\n@keyframes aiwg-fade-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.aiwg-msg--user { flex-direction: row-reverse; }\n.aiwg-msg-avatar {\n width: 28px; height: 28px; border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 13px; flex-shrink: 0;\n margin-bottom: 2px;\n}\n.aiwg-msg--bot .aiwg-msg-avatar { background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark)); color: var(--aiwg-fg-color); }\n.aiwg-msg--user .aiwg-msg-avatar { background: #e2e8f0; color: #64748b; }\n.aiwg-msg-body { max-width: 78%; }\n.aiwg-msg-bubble {\n padding: 10px 14px;\n border-radius: 18px;\n font-size: 14px;\n line-height: 1.55;\n word-break: break-word;\n}\n.aiwg-msg--bot .aiwg-msg-bubble { background: var(--aiwg-chat-bg); color: #1a1a2e; border-bottom-left-radius: 4px; }\n.aiwg-msg--user .aiwg-msg-bubble { background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark)); color: var(--aiwg-fg-color); border-bottom-right-radius: 4px; }\n.aiwg-msg-time { font-size: 10px; color: #94a3b8; margin-top: 4px; text-align: right; padding: 0 4px; }\n.aiwg-msg--bot .aiwg-msg-time { text-align: left; }\n\n/* \u2500\u2500 Typing indicator \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-typing { padding: 10px 14px; }\n.aiwg-typing-dots { display: flex; gap: 4px; align-items: center; }\n.aiwg-typing-dots span {\n width: 7px; height: 7px;\n background: #94a3b8; border-radius: 50%;\n animation: aiwg-bounce 1.2s ease-in-out infinite;\n}\n.aiwg-typing-dots span:nth-child(2) { animation-delay: 0.2s; }\n.aiwg-typing-dots span:nth-child(3) { animation-delay: 0.4s; }\n@keyframes aiwg-bounce {\n 0%, 80%, 100% { transform: translateY(0); }\n 40% { transform: translateY(-6px); }\n}\n\n/* \u2500\u2500 Quick-reply chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-chip-row {\n padding: 6px 16px 2px;\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n flex-shrink: 0;\n}\n.aiwg-chip {\n background: #f1f5f9;\n border: 1px solid #e2e8f0;\n border-radius: 99px;\n padding: 4px 12px;\n font-size: 12px;\n color: #4f46e5;\n cursor: pointer;\n transition: all 0.15s;\n white-space: nowrap;\n font-weight: 500;\n}\n.aiwg-chip:hover { background: #ede9fe; border-color: #a5b4fc; }\n.aiwg-chip-shimmer {\n background: linear-gradient(90deg, #e2e8f0 25%, #f1f5f9 50%, #e2e8f0 75%);\n background-size: 200% 100%;\n border: 1px solid transparent;\n border-radius: 99px;\n padding: 4px 34px;\n animation: aiwg-shimmer 1.4s ease-in-out infinite;\n cursor: default;\n pointer-events: none;\n}\n.aiwg-chip-ai-badge {\n display: inline-block;\n font-size: 9px; font-weight: 700;\n background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark));\n color: #fff;\n padding: 1px 5px;\n border-radius: 99px;\n margin-left: 5px;\n vertical-align: middle;\n letter-spacing: 0.04em;\n}\n@keyframes aiwg-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* \u2500\u2500 Input area \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-input-area {\n padding: 12px 16px 16px;\n flex-shrink: 0;\n background: #fff;\n border-top: 1px solid #f1f5f9;\n position: relative;\n}\n.aiwg-input-row { display: flex; gap: 8px; align-items: flex-end; }\n.aiwg-input {\n flex: 1;\n border: 1.5px solid #e2e8f0;\n border-radius: 12px;\n padding: 10px 14px;\n font-size: 14px;\n font-family: inherit;\n outline: none;\n resize: none;\n background: #f8fafc;\n color: #1a1a2e;\n transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;\n line-height: 1.4;\n max-height: 120px;\n overflow-y: auto;\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n.aiwg-input::-webkit-scrollbar { display: none; }\n.aiwg-input::placeholder { color: #94a3b8; }\n.aiwg-input:focus {\n border-color: var(--aiwg-primary-dark);\n background: #fff;\n box-shadow: 0 0 0 3px rgba(139,92,246,0.1);\n}\n.aiwg-send-btn {\n width: 42px; height: 42px;\n background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark));\n border: none; border-radius: 12px;\n color: var(--aiwg-fg-color); cursor: pointer;\n display: flex; align-items: center; justify-content: center;\n flex-shrink: 0;\n transition: transform 0.15s, box-shadow 0.15s, opacity 0.15s;\n box-shadow: 0 4px 12px rgba(99,102,241,0.35);\n}\n.aiwg-send-btn svg { width: 18px; height: 18px; }\n.aiwg-send-btn:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(99,102,241,0.4); }\n.aiwg-send-btn:active { transform: translateY(0); }\n.aiwg-send-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }\n\n/* \u2500\u2500 Autocomplete suggestions dropdown \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-suggestions {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 16px; right: 16px;\n background: #fff;\n border: 1px solid #e2e8f0;\n border-radius: 12px;\n box-shadow: 0 8px 24px rgba(0,0,0,0.12);\n overflow: hidden;\n z-index: 100;\n animation: aiwg-fade-up 0.15s ease both;\n}\n.aiwg-suggestions-header {\n padding: 8px 14px 4px;\n font-size: 11px; font-weight: 600;\n color: #94a3b8;\n text-transform: uppercase; letter-spacing: 0.06em;\n border-bottom: 1px solid #f1f5f9;\n}\n.aiwg-suggestion-item {\n display: flex; align-items: center; gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s;\n border-bottom: 1px solid #f8fafc;\n}\n.aiwg-suggestion-item:last-child { border-bottom: none; }\n.aiwg-suggestion-item:hover,\n.aiwg-suggestion-item.aiwg-active { background: #f5f3ff; }\n.aiwg-suggestion-icon { font-size: 16px; flex-shrink: 0; }\n.aiwg-suggestion-main { flex: 1; min-width: 0; }\n.aiwg-suggestion-text { font-size: 13px; font-weight: 500; color: #1a1a2e; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.aiwg-suggestion-text mark { background: none; color: #6366f1; font-weight: 600; }\n.aiwg-suggestion-desc { font-size: 11px; color: #94a3b8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.aiwg-suggestion-badge { font-size: 10px; font-weight: 600; padding: 2px 8px; border-radius: 99px; background: #ede9fe; color: #6366f1; flex-shrink: 0; }\n.aiwg-kbd-hint {\n padding: 6px 14px;\n font-size: 11px; color: #cbd5e1; background: #f8fafc;\n display: flex; justify-content: flex-end; gap: 10px;\n}\n.aiwg-kbd-hint kbd { font-family: inherit; background: #e2e8f0; border-radius: 4px; padding: 1px 5px; font-size: 10px; color: #64748b; }\n\n/* \u2500\u2500 Error toast \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-error {\n margin: 0 16px 8px;\n padding: 8px 12px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n font-size: 12px;\n color: #dc2626;\n}\n\n/* \u2500\u2500 Minimized state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-root.aiwg-minimized .aiwg-messages,\n.aiwg-root.aiwg-minimized .aiwg-chip-row,\n.aiwg-root.aiwg-minimized .aiwg-error,\n.aiwg-root.aiwg-minimized .aiwg-input-area,\n.aiwg-root.aiwg-minimized .aiwg-powered { display: none !important; }\n.aiwg-root.aiwg-minimized .aiwg-minimize-btn { display: none !important; }\n.aiwg-root.aiwg-minimized { cursor: pointer; box-shadow: 0 8px 32px rgba(0,0,0,0.28); }\n.aiwg-root.aiwg-minimized .aiwg-header { cursor: pointer !important; }\n\n/* \u2500\u2500 Powered-by footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-powered {\n text-align: center;\n padding: 6px 16px 10px;\n font-size: 11px; color: #94a3b8;\n flex-shrink: 0;\n border-top: 1px solid #f1f5f9;\n background: #fff;\n}\n.aiwg-powered a { color: #6366f1; text-decoration: none; font-weight: 500; }\n.aiwg-powered a:hover { text-decoration: underline; }\n\n/* \u2500\u2500 Markdown rendering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-msg-bubble strong { font-weight: 600; }\n.aiwg-msg-bubble em { font-style: italic; }\n.aiwg-msg-bubble code { background: rgba(0,0,0,0.08); padding: 1px 5px; border-radius: 4px; font-family: 'Fira Code','Consolas',monospace; font-size: 0.9em; }\n.aiwg-msg--user .aiwg-msg-bubble code { background: rgba(255,255,255,0.2); }\n.aiwg-msg-bubble ol, .aiwg-msg-bubble ul { padding-left: 18px; margin: 6px 0; display: flex; flex-direction: column; gap: 3px; }\n.aiwg-msg-bubble ol { list-style: decimal; }\n.aiwg-msg-bubble ul { list-style: disc; }\n.aiwg-msg-bubble li { line-height: 1.5; }\n.aiwg-msg-bubble h3, .aiwg-msg-bubble h4 { font-weight: 600; margin: 8px 0 4px; }\n.aiwg-msg-bubble p { margin: 2px 0; }\n\n/* \u2500\u2500 Dark theme \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-root.aiwg-dark { background: #0f172a; color: #e2e8f0; }\n.aiwg-dark .aiwg-msg--bot .aiwg-msg-bubble { background: #1e293b; color: #e2e8f0; }\n.aiwg-dark .aiwg-input-area { background: #0f172a; border-top-color: #1e293b; }\n.aiwg-dark .aiwg-input { background: #1e293b; border-color: #334155; color: #e2e8f0; }\n.aiwg-dark .aiwg-input:focus { border-color: #8b5cf6; background: #1e293b; box-shadow: 0 0 0 3px rgba(139,92,246,0.2); }\n.aiwg-dark .aiwg-suggestions { background: #1e293b; border-color: #334155; }\n.aiwg-dark .aiwg-suggestions-header { color: #64748b; border-bottom-color: #334155; }\n.aiwg-dark .aiwg-suggestion-item { border-bottom-color: #0f172a; }\n.aiwg-dark .aiwg-suggestion-item:hover,\n.aiwg-dark .aiwg-suggestion-item.aiwg-active { background: #2d1b69; }\n.aiwg-dark .aiwg-suggestion-text { color: #e2e8f0; }\n.aiwg-dark .aiwg-chip { background: #1e293b; border-color: #334155; }\n.aiwg-dark .aiwg-chip:hover { background: #2d1b69; }\n.aiwg-dark .aiwg-chip-shimmer { background: linear-gradient(90deg, #1e293b 25%, #334155 50%, #1e293b 75%); background-size: 200% 100%; }\n.aiwg-dark .aiwg-kbd-hint { background: #1e293b; }\n.aiwg-dark .aiwg-welcome h4 { color: #e2e8f0; }\n.aiwg-dark .aiwg-powered { background: #0f172a; border-top-color: #1e293b; }\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n STREAMING \u2014 Typewriter / word-reveal effect\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/* Blinking text cursor shown while AI response is streaming */\n.aiwg-stream-cursor {\n display: inline-block;\n width: 2px;\n height: 1em;\n background: #6366f1;\n margin-left: 2px;\n vertical-align: text-bottom;\n border-radius: 1px;\n animation: aiwg-cursor-blink 0.65s step-end infinite;\n}\n@keyframes aiwg-cursor-blink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0; }\n}\n\n/* Streaming bubble gets a subtle shimmer border while words are appearing */\n.aiwg-msg-bubble--streaming {\n background: linear-gradient(135deg, #f8fafc, #f1f5f9) !important;\n border: 1.5px solid #e2e8f0 !important;\n position: relative;\n overflow: hidden;\n}\n.aiwg-msg-bubble--streaming::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(90deg, transparent 0%, rgba(99,102,241,0.06) 50%, transparent 100%);\n background-size: 200% 100%;\n animation: aiwg-bubble-shimmer 1.4s ease infinite;\n pointer-events: none;\n}\n@keyframes aiwg-bubble-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n USAGE / QUOTA \u2014 Header badge + progress bar\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/* 3-px progress bar immediately under the header */\n.aiwg-usage-bar {\n height: 3px;\n background: rgba(255,255,255,0.18);\n flex-shrink: 0;\n overflow: hidden;\n}\n.aiwg-usage-bar-fill {\n height: 100%;\n border-radius: 0 2px 2px 0;\n transition: width 0.5s cubic-bezier(0.4,0,0.2,1), background 0.5s ease;\n}\n.aiwg-usage-bar-fill--ok { background: linear-gradient(90deg, #4ade80, #22c55e); }\n.aiwg-usage-bar-fill--warn { background: linear-gradient(90deg, #fbbf24, #f59e0b); }\n.aiwg-usage-bar-fill--exhausted { background: linear-gradient(90deg, #f87171, #ef4444); }\n\n/* Compact X/Y badge in header */\n.aiwg-quota-badge {\n background: rgba(255,255,255,0.15);\n border: 1px solid rgba(255,255,255,0.25);\n border-radius: 99px;\n padding: 2px 8px;\n font-size: 10px;\n font-weight: 600;\n color: rgba(255,255,255,0.9);\n white-space: nowrap;\n flex-shrink: 0;\n}\n.aiwg-quota-badge--warn { background: rgba(251,191,36,0.2); border-color: rgba(251,191,36,0.4); color: #fde68a; }\n.aiwg-quota-badge--exhausted { background: rgba(239,68,68,0.2); border-color: rgba(239,68,68,0.4); color: #fca5a5; }\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n LIMIT EXPIRED \u2014 Softwall banner\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.aiwg-limit-banner {\n margin: 8px 12px 0;\n padding: 10px 14px;\n background: linear-gradient(135deg, #fefce8, #fef3c7);\n border: 1px solid #fde68a;\n border-radius: 10px;\n display: flex;\n align-items: flex-start;\n gap: 10px;\n flex-shrink: 0;\n animation: aiwg-fade-up 0.3s ease both;\n}\n.aiwg-limit-banner-icon { font-size: 18px; flex-shrink: 0; margin-top: 1px; line-height: 1; }\n.aiwg-limit-banner-body { flex: 1; min-width: 0; }\n.aiwg-limit-banner-title { font-size: 12px; font-weight: 700; color: #78350f; margin-bottom: 2px; }\n.aiwg-limit-banner-text { font-size: 11px; color: #92400e; line-height: 1.5; }\n.aiwg-limit-banner-actions { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }\n\n.aiwg-limit-btn {\n padding: 4px 12px;\n border-radius: 99px;\n font-size: 11px;\n font-weight: 600;\n border: none;\n cursor: pointer;\n transition: transform 0.15s ease, box-shadow 0.15s ease, filter 0.15s;\n line-height: 1.5;\n}\n.aiwg-limit-btn--primary {\n background: linear-gradient(135deg, #6366f1, #8b5cf6);\n color: #fff;\n box-shadow: 0 2px 8px rgba(99,102,241,0.3);\n}\n.aiwg-limit-btn--secondary {\n background: rgba(99,102,241,0.08);\n color: #6366f1;\n border: 1px solid rgba(99,102,241,0.2);\n}\n.aiwg-limit-btn:hover { transform: translateY(-1px); filter: brightness(1.08); }\n.aiwg-limit-btn:active { transform: translateY(0); }\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n OFFLINE PANEL \u2014 Slide-up overlay: Form + Booking tabs\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.aiwg-offline-overlay {\n position: absolute;\n inset: 0;\n background: #fff;\n border-radius: 16px;\n display: flex;\n flex-direction: column;\n z-index: 20;\n animation: aiwg-slide-up 0.32s cubic-bezier(0.34, 1.4, 0.64, 1) both;\n overflow: hidden;\n}\n@keyframes aiwg-slide-up {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n.aiwg-offline-header {\n padding: 16px 16px 0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-shrink: 0;\n}\n.aiwg-offline-header-left h4 { font-size: 15px; font-weight: 700; color: #1a1a2e; margin-bottom: 2px; }\n.aiwg-offline-header-left p { font-size: 12px; color: #64748b; line-height: 1.4; }\n.aiwg-offline-close-btn {\n background: #f1f5f9;\n border: none;\n border-radius: 50%;\n width: 30px; height: 30px;\n display: flex; align-items: center; justify-content: center;\n cursor: pointer;\n font-size: 14px; color: #64748b;\n transition: background 0.15s;\n flex-shrink: 0;\n}\n.aiwg-offline-close-btn:hover { background: #e2e8f0; }\n\n/* Tab switcher */\n.aiwg-mode-tabs {\n display: flex;\n gap: 0;\n background: #f1f5f9;\n border-radius: 10px;\n padding: 3px;\n margin: 12px 16px 0;\n flex-shrink: 0;\n}\n.aiwg-mode-tab {\n flex: 1;\n padding: 7px 6px;\n border: none;\n background: transparent;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n color: #64748b;\n transition: all 0.15s;\n display: flex; align-items: center; justify-content: center; gap: 5px;\n}\n.aiwg-mode-tab.aiwg-active {\n background: #fff;\n color: #6366f1;\n font-weight: 700;\n box-shadow: 0 1px 4px rgba(0,0,0,0.08);\n}\n\n/* Scrollable body */\n.aiwg-offline-body {\n flex: 1;\n overflow-y: auto;\n padding: 14px 16px 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n/* \u2500\u2500 Offline Form \u2500\u2500 */\n.aiwg-offline-form { display: flex; flex-direction: column; gap: 10px; }\n.aiwg-offline-field { display: flex; flex-direction: column; gap: 4px; }\n.aiwg-offline-label { font-size: 12px; font-weight: 600; color: #475569; }\n.aiwg-offline-label .aiwg-required { color: #ef4444; }\n.aiwg-offline-control,\n.aiwg-offline-textarea {\n padding: 9px 12px;\n border: 1.5px solid #e2e8f0;\n border-radius: 8px;\n font-size: 13px;\n font-family: inherit;\n outline: none;\n background: #f8fafc;\n color: #1a1a2e;\n transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;\n width: 100%;\n box-sizing: border-box;\n}\n.aiwg-offline-control:focus,\n.aiwg-offline-textarea:focus {\n border-color: #6366f1;\n box-shadow: 0 0 0 3px rgba(99,102,241,0.1);\n background: #fff;\n}\n.aiwg-offline-textarea { resize: none; min-height: 75px; }\n.aiwg-offline-submit {\n padding: 11px;\n background: linear-gradient(135deg, #6366f1, #8b5cf6);\n color: #fff;\n border: none;\n border-radius: 10px;\n font-size: 13px;\n font-weight: 700;\n cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n box-shadow: 0 4px 12px rgba(99,102,241,0.3);\n letter-spacing: 0.01em;\n}\n.aiwg-offline-submit:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(99,102,241,0.4); }\n.aiwg-offline-submit:active:not(:disabled) { transform: translateY(0); }\n.aiwg-offline-submit:disabled { opacity: 0.55; cursor: not-allowed; transform: none; box-shadow: none; }\n\n/* Success state */\n.aiwg-offline-success {\n text-align: center;\n padding: 20px 12px;\n background: #f0fdf4;\n border: 1px solid #86efac;\n border-radius: 12px;\n animation: aiwg-fade-up 0.3s ease both;\n}\n.aiwg-offline-success-icon { font-size: 36px; margin-bottom: 8px; }\n.aiwg-offline-success h4 { font-size: 15px; font-weight: 700; color: #166534; margin-bottom: 4px; }\n.aiwg-offline-success p { font-size: 12px; color: #4ade80; line-height: 1.5; }\n\n/* \u2500\u2500 Booking card \u2500\u2500 */\n.aiwg-booking-card {\n background: linear-gradient(135deg, #f5f3ff, #ede9fe);\n border: 1px solid #ddd6fe;\n border-radius: 14px;\n padding: 20px 16px;\n text-align: center;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n}\n.aiwg-booking-icon { font-size: 40px; line-height: 1.1; }\n.aiwg-booking-title { font-size: 15px; font-weight: 700; color: #4c1d95; }\n.aiwg-booking-desc { font-size: 12px; color: #6d28d9; line-height: 1.5; }\n.aiwg-booking-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 10px 22px;\n background: linear-gradient(135deg, #6366f1, #8b5cf6);\n color: #fff;\n border: none;\n border-radius: 99px;\n font-size: 13px;\n font-weight: 700;\n cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n box-shadow: 0 4px 14px rgba(99,102,241,0.35);\n text-decoration: none;\n letter-spacing: 0.01em;\n}\n.aiwg-booking-btn:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(99,102,241,0.45); }\n.aiwg-booking-btn:active { transform: translateY(0); }\n\n/* \u2500\u2500 Shared fade-up used by banner + success \u2500\u2500 */\n@keyframes aiwg-fade-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n DARK THEME \u2014 overrides for new elements\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.aiwg-dark .aiwg-stream-cursor { background: #a78bfa; }\n.aiwg-dark .aiwg-msg-bubble--streaming { background: linear-gradient(135deg, #1e293b, #0f172a) !important; border-color: #334155 !important; color: #e2e8f0; }\n.aiwg-dark .aiwg-limit-banner { background: linear-gradient(135deg, #292202, #261e01); border-color: #a16207; }\n.aiwg-dark .aiwg-limit-banner-title { color: #fde68a; }\n.aiwg-dark .aiwg-limit-banner-text { color: #fcd34d; }\n.aiwg-dark .aiwg-limit-btn--secondary { background: rgba(139,92,246,0.15); color: #a78bfa; border-color: rgba(139,92,246,0.3); }\n.aiwg-dark .aiwg-offline-overlay { background: #0f172a; }\n.aiwg-dark .aiwg-offline-header-left h4 { color: #e2e8f0; }\n.aiwg-dark .aiwg-offline-header-left p { color: #64748b; }\n.aiwg-dark .aiwg-offline-close-btn { background: #1e293b; color: #94a3b8; }\n.aiwg-dark .aiwg-offline-close-btn:hover { background: #334155; }\n.aiwg-dark .aiwg-mode-tabs { background: #1e293b; }\n.aiwg-dark .aiwg-mode-tab { color: #94a3b8; }\n.aiwg-dark .aiwg-mode-tab.aiwg-active { background: #0f172a; color: #a78bfa; }\n.aiwg-dark .aiwg-offline-label { color: #94a3b8; }\n.aiwg-dark .aiwg-offline-control,\n.aiwg-dark .aiwg-offline-textarea { background: #1e293b; border-color: #334155; color: #e2e8f0; }\n.aiwg-dark .aiwg-offline-control:focus,\n.aiwg-dark .aiwg-offline-textarea:focus { border-color: #8b5cf6; box-shadow: 0 0 0 3px rgba(139,92,246,0.2); background: #1e293b; }\n.aiwg-dark .aiwg-booking-card { background: linear-gradient(135deg, #2d1b69, #1a0f3c); border-color: #4c1d95; }\n.aiwg-dark .aiwg-booking-title { color: #c4b5fd; }\n.aiwg-dark .aiwg-booking-desc { color: #a78bfa; }\n.aiwg-dark .aiwg-quota-badge { color: rgba(255,255,255,0.85); background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.2); }\n";
|
|
14
|
+
export declare const WIDGET_CSS = "\n/* \u2500\u2500 Shadow-DOM host isolation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n:host {\n all: initial !important;\n display: block !important;\n}\n\n/* Scoped box-model reset \u2014 only touches widget elements, not all of shadow DOM */\n.aiwg-root *, .aiwg-root *::before, .aiwg-root *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n/* \u2500\u2500 Container \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-root {\n --aiwg-primary: #6366f1;\n --aiwg-primary-dark: #8b5cf6;\n --aiwg-fg-color: #ffffff;\n --aiwg-bg-color: #ffffff;\n --aiwg-chat-bg: #f1f5f9;\n\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 14px;\n line-height: 1.5;\n color: #1a1a2e;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n border-radius: 16px;\n background: var(--aiwg-bg-color);\n position: fixed !important;\n bottom: 24px;\n right: 24px;\n width: 380px !important;\n max-width: calc(100vw - 48px) !important;\n z-index: 99999;\n transition: height 0.25s ease;\n box-shadow: 0 24px 64px rgba(0,0,0,0.18);\n}\n\n/* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-header {\n background: linear-gradient(135deg, var(--aiwg-primary) 0%, var(--aiwg-primary-dark) 100%);\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n position: relative;\n overflow: hidden;\n}\n.aiwg-header::before {\n content: '';\n position: absolute;\n width: 140px; height: 140px;\n background: rgba(255,255,255,0.08);\n border-radius: 50%;\n top: -50px; right: -30px;\n}\n.aiwg-avatar {\n width: 40px; height: 40px;\n background: rgba(255,255,255,0.25);\n border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n border: 2px solid rgba(255,255,255,0.4);\n}\n.aiwg-header-info { flex: 1; }\n.aiwg-title { color: #fff; font-weight: 600; font-size: 15px; }\n.aiwg-subtitle {\n color: rgba(255,255,255,0.75);\n font-size: 12px;\n display: flex; align-items: center; gap: 5px;\n}\n.aiwg-online-dot {\n width: 7px; height: 7px;\n background: #4ade80;\n border-radius: 50%;\n display: inline-block;\n animation: aiwg-pulse 2s ease-in-out infinite;\n}\n@keyframes aiwg-pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.6; transform: scale(0.85); }\n}\n.aiwg-minimize-btn {\n width: 36px; height: 36px;\n background: rgba(255,255,255,0.18);\n border: 1.5px solid rgba(255,255,255,0.3);\n border-radius: 50%;\n color: #fff; cursor: pointer;\n display: flex; align-items: center; justify-content: center;\n font-size: 18px; line-height: 1;\n transition: background 0.15s, transform 0.15s;\n flex-shrink: 0;\n position: relative; z-index: 2;\n}\n.aiwg-minimize-btn * { cursor: pointer !important; pointer-events: none; }\n.aiwg-minimize-btn:hover { background: rgba(255,255,255,0.32); transform: scale(1.08); }\n\n/* \u2500\u2500 Messages area \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-messages {\n flex: 1;\n overflow-y: auto;\n padding: 20px 16px 8px;\n scroll-behavior: smooth;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.aiwg-messages::-webkit-scrollbar { width: 4px; }\n.aiwg-messages::-webkit-scrollbar-thumb { background: #e2e8f0; border-radius: 99px; }\n\n/* \u2500\u2500 Welcome card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-welcome {\n text-align: center;\n padding: 24px 16px;\n display: flex; flex-direction: column; align-items: center; gap: 8px;\n}\n.aiwg-welcome-icon { font-size: 36px; margin-bottom: 4px; }\n.aiwg-welcome h4 { font-size: 15px; font-weight: 600; color: #1a1a2e; }\n.aiwg-welcome p { font-size: 13px; color: #64748b; }\n\n/* \u2500\u2500 Message bubbles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-msg {\n display: flex;\n gap: 8px;\n align-items: flex-end;\n animation: aiwg-fade-up 0.2s ease both;\n}\n@keyframes aiwg-fade-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.aiwg-msg--user { flex-direction: row-reverse; }\n.aiwg-msg-avatar {\n width: 28px; height: 28px; border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 13px; flex-shrink: 0;\n margin-bottom: 2px;\n}\n.aiwg-msg--bot .aiwg-msg-avatar { background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark)); color: var(--aiwg-fg-color); }\n.aiwg-msg--user .aiwg-msg-avatar { background: #e2e8f0; color: #64748b; }\n.aiwg-msg-body { max-width: 78%; }\n.aiwg-msg-bubble {\n padding: 10px 14px;\n border-radius: 18px;\n font-size: 14px;\n line-height: 1.55;\n word-break: break-word;\n}\n.aiwg-msg--bot .aiwg-msg-bubble { background: var(--aiwg-chat-bg); color: #1a1a2e; border-bottom-left-radius: 4px; }\n.aiwg-msg--user .aiwg-msg-bubble { background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark)); color: var(--aiwg-fg-color); border-bottom-right-radius: 4px; }\n.aiwg-msg-time { font-size: 10px; color: #94a3b8; margin-top: 4px; text-align: right; padding: 0 4px; }\n.aiwg-msg--bot .aiwg-msg-time { text-align: left; }\n\n/* \u2500\u2500 Typing indicator \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-typing { padding: 10px 14px; }\n.aiwg-typing-dots { display: flex; gap: 4px; align-items: center; }\n.aiwg-typing-dots span {\n width: 7px; height: 7px;\n background: #94a3b8; border-radius: 50%;\n animation: aiwg-bounce 1.2s ease-in-out infinite;\n}\n.aiwg-typing-dots span:nth-child(2) { animation-delay: 0.2s; }\n.aiwg-typing-dots span:nth-child(3) { animation-delay: 0.4s; }\n@keyframes aiwg-bounce {\n 0%, 80%, 100% { transform: translateY(0); }\n 40% { transform: translateY(-6px); }\n}\n\n/* \u2500\u2500 Quick-reply chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-chip-row {\n padding: 6px 16px 2px;\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n flex-shrink: 0;\n}\n.aiwg-chip {\n background: #f1f5f9;\n border: 1px solid #e2e8f0;\n border-radius: 99px;\n padding: 4px 12px;\n font-size: 12px;\n color: #4f46e5;\n cursor: pointer;\n transition: all 0.15s;\n white-space: nowrap;\n font-weight: 500;\n}\n.aiwg-chip:hover { background: #ede9fe; border-color: #a5b4fc; }\n.aiwg-chip-shimmer {\n background: linear-gradient(90deg, #e2e8f0 25%, #f1f5f9 50%, #e2e8f0 75%);\n background-size: 200% 100%;\n border: 1px solid transparent;\n border-radius: 99px;\n padding: 4px 34px;\n animation: aiwg-shimmer 1.4s ease-in-out infinite;\n cursor: default;\n pointer-events: none;\n}\n.aiwg-chip-ai-badge {\n display: inline-block;\n font-size: 9px; font-weight: 700;\n background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark));\n color: #fff;\n padding: 1px 5px;\n border-radius: 99px;\n margin-left: 5px;\n vertical-align: middle;\n letter-spacing: 0.04em;\n}\n@keyframes aiwg-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* \u2500\u2500 Input area \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-input-area {\n padding: 12px 16px 16px;\n flex-shrink: 0;\n background: #fff;\n border-top: 1px solid #f1f5f9;\n position: relative;\n}\n.aiwg-input-row { display: flex; gap: 8px; align-items: flex-end; }\n.aiwg-input {\n flex: 1;\n border: 1.5px solid #e2e8f0;\n border-radius: 12px;\n padding: 10px 14px;\n font-size: 14px;\n font-family: inherit;\n outline: none;\n resize: none;\n background: #f8fafc;\n color: #1a1a2e;\n transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;\n line-height: 1.4;\n max-height: 120px;\n overflow-y: auto;\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n.aiwg-input::-webkit-scrollbar { display: none; }\n.aiwg-input::placeholder { color: #94a3b8; }\n.aiwg-input:focus {\n border-color: var(--aiwg-primary-dark);\n background: #fff;\n box-shadow: 0 0 0 3px rgba(139,92,246,0.1);\n}\n.aiwg-send-btn {\n width: 42px; height: 42px;\n background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark));\n border: none; border-radius: 12px;\n color: var(--aiwg-fg-color); cursor: pointer;\n display: flex; align-items: center; justify-content: center;\n flex-shrink: 0;\n transition: transform 0.15s, box-shadow 0.15s, opacity 0.15s;\n box-shadow: 0 4px 12px rgba(99,102,241,0.35);\n}\n.aiwg-send-btn svg { width: 18px; height: 18px; }\n.aiwg-send-btn:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(99,102,241,0.4); }\n.aiwg-send-btn:active { transform: translateY(0); }\n.aiwg-send-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }\n\n/* \u2500\u2500 Autocomplete suggestions dropdown \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-suggestions {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 16px; right: 16px;\n background: #fff;\n border: 1px solid #e2e8f0;\n border-radius: 12px;\n box-shadow: 0 8px 24px rgba(0,0,0,0.12);\n overflow: hidden;\n z-index: 100;\n animation: aiwg-fade-up 0.15s ease both;\n}\n.aiwg-suggestions-header {\n padding: 8px 14px 4px;\n font-size: 11px; font-weight: 600;\n color: #94a3b8;\n text-transform: uppercase; letter-spacing: 0.06em;\n border-bottom: 1px solid #f1f5f9;\n}\n.aiwg-suggestion-item {\n display: flex; align-items: center; gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s;\n border-bottom: 1px solid #f8fafc;\n}\n.aiwg-suggestion-item:last-child { border-bottom: none; }\n.aiwg-suggestion-item:hover,\n.aiwg-suggestion-item.aiwg-active { background: #f5f3ff; }\n.aiwg-suggestion-icon { font-size: 16px; flex-shrink: 0; }\n.aiwg-suggestion-main { flex: 1; min-width: 0; }\n.aiwg-suggestion-text { font-size: 13px; font-weight: 500; color: #1a1a2e; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.aiwg-suggestion-text mark { background: none; color: #6366f1; font-weight: 600; }\n.aiwg-suggestion-desc { font-size: 11px; color: #94a3b8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.aiwg-suggestion-badge { font-size: 10px; font-weight: 600; padding: 2px 8px; border-radius: 99px; background: #ede9fe; color: #6366f1; flex-shrink: 0; }\n.aiwg-kbd-hint {\n padding: 6px 14px;\n font-size: 11px; color: #cbd5e1; background: #f8fafc;\n display: flex; justify-content: flex-end; gap: 10px;\n}\n.aiwg-kbd-hint kbd { font-family: inherit; background: #e2e8f0; border-radius: 4px; padding: 1px 5px; font-size: 10px; color: #64748b; }\n\n/* \u2500\u2500 Error toast \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-error {\n margin: 0 16px 8px;\n padding: 8px 12px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n font-size: 12px;\n color: #dc2626;\n}\n\n/* \u2500\u2500 Minimized state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-root.aiwg-minimized .aiwg-messages,\n.aiwg-root.aiwg-minimized .aiwg-chip-row,\n.aiwg-root.aiwg-minimized .aiwg-error,\n.aiwg-root.aiwg-minimized .aiwg-input-area,\n.aiwg-root.aiwg-minimized .aiwg-powered { display: none !important; }\n.aiwg-root.aiwg-minimized .aiwg-minimize-btn { display: none !important; }\n.aiwg-root.aiwg-minimized { cursor: pointer; box-shadow: 0 8px 32px rgba(0,0,0,0.28); }\n.aiwg-root.aiwg-minimized .aiwg-header { cursor: pointer !important; }\n\n/* \u2500\u2500 Powered-by footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-powered {\n text-align: center;\n padding: 6px 16px 10px;\n font-size: 11px; color: #94a3b8;\n flex-shrink: 0;\n border-top: 1px solid #f1f5f9;\n background: #fff;\n}\n.aiwg-powered a { color: #6366f1; text-decoration: none; font-weight: 500; }\n.aiwg-powered a:hover { text-decoration: underline; }\n\n/* \u2500\u2500 Markdown rendering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-msg-bubble strong { font-weight: 600; }\n.aiwg-msg-bubble em { font-style: italic; }\n.aiwg-msg-bubble code { background: rgba(0,0,0,0.08); padding: 1px 5px; border-radius: 4px; font-family: 'Fira Code','Consolas',monospace; font-size: 0.9em; }\n.aiwg-msg--user .aiwg-msg-bubble code { background: rgba(255,255,255,0.2); }\n.aiwg-msg-bubble ol, .aiwg-msg-bubble ul { padding-left: 18px; margin: 6px 0; display: flex; flex-direction: column; gap: 3px; }\n.aiwg-msg-bubble ol { list-style: decimal; }\n.aiwg-msg-bubble ul { list-style: disc; }\n.aiwg-msg-bubble li { line-height: 1.5; }\n.aiwg-msg-bubble h3, .aiwg-msg-bubble h4 { font-weight: 600; margin: 8px 0 4px; }\n.aiwg-msg-bubble p { margin: 2px 0; }\n.aiwg-msg-bubble hr { border: none; border-top: 1px solid rgba(0,0,0,0.15); margin: 8px 0; }\n/* Links */\n.aiwg-msg-bubble a { color: #6366f1; text-decoration: underline; word-break: break-all; }\n.aiwg-msg--user .aiwg-msg-bubble a { color: #e0e7ff; }\n.aiwg-msg-bubble a:hover { opacity: 0.8; }\n/* Images */\n.aiwg-msg-bubble .aiwg-img { max-width: 100%; border-radius: 8px; margin: 6px 0; display: block; }\n/* Fenced code blocks */\n.aiwg-msg-bubble pre { background: #1e293b; color: #e2e8f0; border-radius: 8px; padding: 10px 12px; margin: 6px 0; overflow-x: auto; font-size: 0.85em; }\n.aiwg-msg-bubble pre code { background: none; padding: 0; font-size: inherit; color: inherit; }\n/* Tables */\n.aiwg-msg-bubble .aiwg-table { width: 100%; border-collapse: collapse; font-size: 0.85em; margin: 8px 0; }\n.aiwg-msg-bubble .aiwg-table th,\n.aiwg-msg-bubble .aiwg-table td { border: 1px solid rgba(0,0,0,0.15); padding: 5px 8px; text-align: left; }\n.aiwg-msg-bubble .aiwg-table th { background: rgba(99,102,241,0.12); font-weight: 600; }\n.aiwg-msg-bubble .aiwg-table tr:nth-child(even) { background: rgba(0,0,0,0.04); }\n\n/* \u2500\u2500 Dark theme \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-root.aiwg-dark { background: #0f172a; color: #e2e8f0; }\n.aiwg-dark .aiwg-msg--bot .aiwg-msg-bubble { background: #1e293b; color: #e2e8f0; }\n.aiwg-dark .aiwg-input-area { background: #0f172a; border-top-color: #1e293b; }\n.aiwg-dark .aiwg-input { background: #1e293b; border-color: #334155; color: #e2e8f0; }\n.aiwg-dark .aiwg-input:focus { border-color: #8b5cf6; background: #1e293b; box-shadow: 0 0 0 3px rgba(139,92,246,0.2); }\n.aiwg-dark .aiwg-suggestions { background: #1e293b; border-color: #334155; }\n.aiwg-dark .aiwg-suggestions-header { color: #64748b; border-bottom-color: #334155; }\n.aiwg-dark .aiwg-suggestion-item { border-bottom-color: #0f172a; }\n.aiwg-dark .aiwg-suggestion-item:hover,\n.aiwg-dark .aiwg-suggestion-item.aiwg-active { background: #2d1b69; }\n.aiwg-dark .aiwg-suggestion-text { color: #e2e8f0; }\n.aiwg-dark .aiwg-chip { background: #1e293b; border-color: #334155; }\n.aiwg-dark .aiwg-chip:hover { background: #2d1b69; }\n.aiwg-dark .aiwg-chip-shimmer { background: linear-gradient(90deg, #1e293b 25%, #334155 50%, #1e293b 75%); background-size: 200% 100%; }\n.aiwg-dark .aiwg-kbd-hint { background: #1e293b; }\n.aiwg-dark .aiwg-welcome h4 { color: #e2e8f0; }\n.aiwg-dark .aiwg-powered { background: #0f172a; border-top-color: #1e293b; }\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n STREAMING \u2014 Typewriter / word-reveal effect\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/* Blinking text cursor shown while AI response is streaming */\n.aiwg-stream-cursor {\n display: inline-block;\n width: 2px;\n height: 1em;\n background: #6366f1;\n margin-left: 2px;\n vertical-align: text-bottom;\n border-radius: 1px;\n animation: aiwg-cursor-blink 0.65s step-end infinite;\n}\n@keyframes aiwg-cursor-blink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0; }\n}\n\n/* Streaming bubble gets a subtle shimmer border while words are appearing */\n.aiwg-msg-bubble--streaming {\n background: linear-gradient(135deg, #f8fafc, #f1f5f9) !important;\n border: 1.5px solid #e2e8f0 !important;\n position: relative;\n overflow: hidden;\n}\n.aiwg-msg-bubble--streaming::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(90deg, transparent 0%, rgba(99,102,241,0.06) 50%, transparent 100%);\n background-size: 200% 100%;\n animation: aiwg-bubble-shimmer 1.4s ease infinite;\n pointer-events: none;\n}\n@keyframes aiwg-bubble-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n USAGE / QUOTA \u2014 Header badge + progress bar\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/* 3-px progress bar immediately under the header */\n.aiwg-usage-bar {\n height: 3px;\n background: rgba(255,255,255,0.18);\n flex-shrink: 0;\n overflow: hidden;\n}\n.aiwg-usage-bar-fill {\n height: 100%;\n border-radius: 0 2px 2px 0;\n transition: width 0.5s cubic-bezier(0.4,0,0.2,1), background 0.5s ease;\n}\n.aiwg-usage-bar-fill--ok { background: linear-gradient(90deg, #4ade80, #22c55e); }\n.aiwg-usage-bar-fill--warn { background: linear-gradient(90deg, #fbbf24, #f59e0b); }\n.aiwg-usage-bar-fill--exhausted { background: linear-gradient(90deg, #f87171, #ef4444); }\n\n/* Compact X/Y badge in header */\n.aiwg-quota-badge {\n background: rgba(255,255,255,0.15);\n border: 1px solid rgba(255,255,255,0.25);\n border-radius: 99px;\n padding: 2px 8px;\n font-size: 10px;\n font-weight: 600;\n color: rgba(255,255,255,0.9);\n white-space: nowrap;\n flex-shrink: 0;\n}\n.aiwg-quota-badge--warn { background: rgba(251,191,36,0.2); border-color: rgba(251,191,36,0.4); color: #fde68a; }\n.aiwg-quota-badge--exhausted { background: rgba(239,68,68,0.2); border-color: rgba(239,68,68,0.4); color: #fca5a5; }\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n LIMIT EXPIRED \u2014 Softwall banner\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.aiwg-limit-banner {\n margin: 8px 12px 0;\n padding: 10px 14px;\n background: linear-gradient(135deg, #fefce8, #fef3c7);\n border: 1px solid #fde68a;\n border-radius: 10px;\n display: flex;\n align-items: flex-start;\n gap: 10px;\n flex-shrink: 0;\n animation: aiwg-fade-up 0.3s ease both;\n}\n.aiwg-limit-banner-icon { font-size: 18px; flex-shrink: 0; margin-top: 1px; line-height: 1; }\n.aiwg-limit-banner-body { flex: 1; min-width: 0; }\n.aiwg-limit-banner-title { font-size: 12px; font-weight: 700; color: #78350f; margin-bottom: 2px; }\n.aiwg-limit-banner-text { font-size: 11px; color: #92400e; line-height: 1.5; }\n.aiwg-limit-banner-actions { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }\n\n.aiwg-limit-btn {\n padding: 4px 12px;\n border-radius: 99px;\n font-size: 11px;\n font-weight: 600;\n border: none;\n cursor: pointer;\n transition: transform 0.15s ease, box-shadow 0.15s ease, filter 0.15s;\n line-height: 1.5;\n}\n.aiwg-limit-btn--primary {\n background: linear-gradient(135deg, #6366f1, #8b5cf6);\n color: #fff;\n box-shadow: 0 2px 8px rgba(99,102,241,0.3);\n}\n.aiwg-limit-btn--secondary {\n background: rgba(99,102,241,0.08);\n color: #6366f1;\n border: 1px solid rgba(99,102,241,0.2);\n}\n.aiwg-limit-btn:hover { transform: translateY(-1px); filter: brightness(1.08); }\n.aiwg-limit-btn:active { transform: translateY(0); }\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n OFFLINE PANEL \u2014 Slide-up overlay: Form + Booking tabs\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.aiwg-offline-overlay {\n position: absolute;\n inset: 0;\n background: #fff;\n border-radius: 16px;\n display: flex;\n flex-direction: column;\n z-index: 20;\n animation: aiwg-slide-up 0.32s cubic-bezier(0.34, 1.4, 0.64, 1) both;\n overflow: hidden;\n}\n@keyframes aiwg-slide-up {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n.aiwg-offline-header {\n padding: 16px 16px 0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-shrink: 0;\n}\n.aiwg-offline-header-left h4 { font-size: 15px; font-weight: 700; color: #1a1a2e; margin-bottom: 2px; }\n.aiwg-offline-header-left p { font-size: 12px; color: #64748b; line-height: 1.4; }\n.aiwg-offline-close-btn {\n background: #f1f5f9;\n border: none;\n border-radius: 50%;\n width: 30px; height: 30px;\n display: flex; align-items: center; justify-content: center;\n cursor: pointer;\n font-size: 14px; color: #64748b;\n transition: background 0.15s;\n flex-shrink: 0;\n}\n.aiwg-offline-close-btn:hover { background: #e2e8f0; }\n\n/* Tab switcher */\n.aiwg-mode-tabs {\n display: flex;\n gap: 0;\n background: #f1f5f9;\n border-radius: 10px;\n padding: 3px;\n margin: 12px 16px 0;\n flex-shrink: 0;\n}\n.aiwg-mode-tab {\n flex: 1;\n padding: 7px 6px;\n border: none;\n background: transparent;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n color: #64748b;\n transition: all 0.15s;\n display: flex; align-items: center; justify-content: center; gap: 5px;\n}\n.aiwg-mode-tab.aiwg-active {\n background: #fff;\n color: #6366f1;\n font-weight: 700;\n box-shadow: 0 1px 4px rgba(0,0,0,0.08);\n}\n\n/* Scrollable body */\n.aiwg-offline-body {\n flex: 1;\n overflow-y: auto;\n padding: 14px 16px 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n/* \u2500\u2500 Offline Form \u2500\u2500 */\n.aiwg-offline-form { display: flex; flex-direction: column; gap: 10px; }\n.aiwg-offline-field { display: flex; flex-direction: column; gap: 4px; }\n.aiwg-offline-label { font-size: 12px; font-weight: 600; color: #475569; }\n.aiwg-offline-label .aiwg-required { color: #ef4444; }\n.aiwg-offline-control,\n.aiwg-offline-textarea {\n padding: 9px 12px;\n border: 1.5px solid #e2e8f0;\n border-radius: 8px;\n font-size: 13px;\n font-family: inherit;\n outline: none;\n background: #f8fafc;\n color: #1a1a2e;\n transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;\n width: 100%;\n box-sizing: border-box;\n}\n.aiwg-offline-control:focus,\n.aiwg-offline-textarea:focus {\n border-color: #6366f1;\n box-shadow: 0 0 0 3px rgba(99,102,241,0.1);\n background: #fff;\n}\n.aiwg-offline-textarea { resize: none; min-height: 75px; }\n.aiwg-offline-submit {\n padding: 11px;\n background: linear-gradient(135deg, #6366f1, #8b5cf6);\n color: #fff;\n border: none;\n border-radius: 10px;\n font-size: 13px;\n font-weight: 700;\n cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n box-shadow: 0 4px 12px rgba(99,102,241,0.3);\n letter-spacing: 0.01em;\n}\n.aiwg-offline-submit:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(99,102,241,0.4); }\n.aiwg-offline-submit:active:not(:disabled) { transform: translateY(0); }\n.aiwg-offline-submit:disabled { opacity: 0.55; cursor: not-allowed; transform: none; box-shadow: none; }\n\n/* Success state */\n.aiwg-offline-success {\n text-align: center;\n padding: 20px 12px;\n background: #f0fdf4;\n border: 1px solid #86efac;\n border-radius: 12px;\n animation: aiwg-fade-up 0.3s ease both;\n}\n.aiwg-offline-success-icon { font-size: 36px; margin-bottom: 8px; }\n.aiwg-offline-success h4 { font-size: 15px; font-weight: 700; color: #166534; margin-bottom: 4px; }\n.aiwg-offline-success p { font-size: 12px; color: #4ade80; line-height: 1.5; }\n\n/* \u2500\u2500 Booking card \u2500\u2500 */\n.aiwg-booking-card {\n background: linear-gradient(135deg, #f5f3ff, #ede9fe);\n border: 1px solid #ddd6fe;\n border-radius: 14px;\n padding: 20px 16px;\n text-align: center;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n}\n.aiwg-booking-icon { font-size: 40px; line-height: 1.1; }\n.aiwg-booking-title { font-size: 15px; font-weight: 700; color: #4c1d95; }\n.aiwg-booking-desc { font-size: 12px; color: #6d28d9; line-height: 1.5; }\n.aiwg-booking-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 10px 22px;\n background: linear-gradient(135deg, #6366f1, #8b5cf6);\n color: #fff;\n border: none;\n border-radius: 99px;\n font-size: 13px;\n font-weight: 700;\n cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n box-shadow: 0 4px 14px rgba(99,102,241,0.35);\n text-decoration: none;\n letter-spacing: 0.01em;\n}\n.aiwg-booking-btn:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(99,102,241,0.45); }\n.aiwg-booking-btn:active { transform: translateY(0); }\n\n/* \u2500\u2500 Shared fade-up used by banner + success \u2500\u2500 */\n@keyframes aiwg-fade-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n DARK THEME \u2014 overrides for new elements\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.aiwg-dark .aiwg-stream-cursor { background: #a78bfa; }\n.aiwg-dark .aiwg-msg-bubble--streaming { background: linear-gradient(135deg, #1e293b, #0f172a) !important; border-color: #334155 !important; color: #e2e8f0; }\n.aiwg-dark .aiwg-limit-banner { background: linear-gradient(135deg, #292202, #261e01); border-color: #a16207; }\n.aiwg-dark .aiwg-limit-banner-title { color: #fde68a; }\n.aiwg-dark .aiwg-limit-banner-text { color: #fcd34d; }\n.aiwg-dark .aiwg-limit-btn--secondary { background: rgba(139,92,246,0.15); color: #a78bfa; border-color: rgba(139,92,246,0.3); }\n.aiwg-dark .aiwg-offline-overlay { background: #0f172a; }\n.aiwg-dark .aiwg-offline-header-left h4 { color: #e2e8f0; }\n.aiwg-dark .aiwg-offline-header-left p { color: #64748b; }\n.aiwg-dark .aiwg-offline-close-btn { background: #1e293b; color: #94a3b8; }\n.aiwg-dark .aiwg-offline-close-btn:hover { background: #334155; }\n.aiwg-dark .aiwg-mode-tabs { background: #1e293b; }\n.aiwg-dark .aiwg-mode-tab { color: #94a3b8; }\n.aiwg-dark .aiwg-mode-tab.aiwg-active { background: #0f172a; color: #a78bfa; }\n.aiwg-dark .aiwg-offline-label { color: #94a3b8; }\n.aiwg-dark .aiwg-offline-control,\n.aiwg-dark .aiwg-offline-textarea { background: #1e293b; border-color: #334155; color: #e2e8f0; }\n.aiwg-dark .aiwg-offline-control:focus,\n.aiwg-dark .aiwg-offline-textarea:focus { border-color: #8b5cf6; box-shadow: 0 0 0 3px rgba(139,92,246,0.2); background: #1e293b; }\n.aiwg-dark .aiwg-booking-card { background: linear-gradient(135deg, #2d1b69, #1a0f3c); border-color: #4c1d95; }\n.aiwg-dark .aiwg-booking-title { color: #c4b5fd; }\n.aiwg-dark .aiwg-booking-desc { color: #a78bfa; }\n.aiwg-dark .aiwg-quota-badge { color: rgba(255,255,255,0.85); background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.2); }\n";
|
package/dist/widget-css.js
CHANGED
|
@@ -356,7 +356,7 @@ export const WIDGET_CSS = `
|
|
|
356
356
|
.aiwg-powered a { color: #6366f1; text-decoration: none; font-weight: 500; }
|
|
357
357
|
.aiwg-powered a:hover { text-decoration: underline; }
|
|
358
358
|
|
|
359
|
-
/* ── Markdown rendering
|
|
359
|
+
/* ── Markdown rendering ────────────────────────────────────────────────── */
|
|
360
360
|
.aiwg-msg-bubble strong { font-weight: 600; }
|
|
361
361
|
.aiwg-msg-bubble em { font-style: italic; }
|
|
362
362
|
.aiwg-msg-bubble code { background: rgba(0,0,0,0.08); padding: 1px 5px; border-radius: 4px; font-family: 'Fira Code','Consolas',monospace; font-size: 0.9em; }
|
|
@@ -367,6 +367,22 @@ export const WIDGET_CSS = `
|
|
|
367
367
|
.aiwg-msg-bubble li { line-height: 1.5; }
|
|
368
368
|
.aiwg-msg-bubble h3, .aiwg-msg-bubble h4 { font-weight: 600; margin: 8px 0 4px; }
|
|
369
369
|
.aiwg-msg-bubble p { margin: 2px 0; }
|
|
370
|
+
.aiwg-msg-bubble hr { border: none; border-top: 1px solid rgba(0,0,0,0.15); margin: 8px 0; }
|
|
371
|
+
/* Links */
|
|
372
|
+
.aiwg-msg-bubble a { color: #6366f1; text-decoration: underline; word-break: break-all; }
|
|
373
|
+
.aiwg-msg--user .aiwg-msg-bubble a { color: #e0e7ff; }
|
|
374
|
+
.aiwg-msg-bubble a:hover { opacity: 0.8; }
|
|
375
|
+
/* Images */
|
|
376
|
+
.aiwg-msg-bubble .aiwg-img { max-width: 100%; border-radius: 8px; margin: 6px 0; display: block; }
|
|
377
|
+
/* Fenced code blocks */
|
|
378
|
+
.aiwg-msg-bubble pre { background: #1e293b; color: #e2e8f0; border-radius: 8px; padding: 10px 12px; margin: 6px 0; overflow-x: auto; font-size: 0.85em; }
|
|
379
|
+
.aiwg-msg-bubble pre code { background: none; padding: 0; font-size: inherit; color: inherit; }
|
|
380
|
+
/* Tables */
|
|
381
|
+
.aiwg-msg-bubble .aiwg-table { width: 100%; border-collapse: collapse; font-size: 0.85em; margin: 8px 0; }
|
|
382
|
+
.aiwg-msg-bubble .aiwg-table th,
|
|
383
|
+
.aiwg-msg-bubble .aiwg-table td { border: 1px solid rgba(0,0,0,0.15); padding: 5px 8px; text-align: left; }
|
|
384
|
+
.aiwg-msg-bubble .aiwg-table th { background: rgba(99,102,241,0.12); font-weight: 600; }
|
|
385
|
+
.aiwg-msg-bubble .aiwg-table tr:nth-child(even) { background: rgba(0,0,0,0.04); }
|
|
370
386
|
|
|
371
387
|
/* ── Dark theme ───────────────────────────────────────────────────────────── */
|
|
372
388
|
.aiwg-root.aiwg-dark { background: #0f172a; color: #e2e8f0; }
|