@helpway/react 0.1.1 → 0.3.0
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/index.d.ts +29 -1
- package/dist/index.js +130 -54
- package/dist/index.js.map +1 -1
- package/package.json +15 -22
- package/src/themed/styles.css +286 -17
- package/dist/index.css +0 -2865
- package/dist/index.css.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -264,4 +264,32 @@ interface ComposerProps {
|
|
|
264
264
|
/** Widget composer — auto-resize, Enter-to-send, paste/drop attachments */
|
|
265
265
|
declare function Composer({ text, onTextChange, onSubmit, onTyping, isSubmitting, placeholder, compact, attachments, onAddFiles, onRemoveAttachment, disabled, }: ComposerProps): react_jsx_runtime.JSX.Element;
|
|
266
266
|
|
|
267
|
-
|
|
267
|
+
/**
|
|
268
|
+
* Lightweight Markdown → HTML renderer.
|
|
269
|
+
* Zero dependencies. Handles common patterns:
|
|
270
|
+
* headings, bold, italic, code, links, lists, blockquotes, images, hr.
|
|
271
|
+
*
|
|
272
|
+
* Security note: Content is served from Better i18n Content CMS which only
|
|
273
|
+
* accepts authenticated writes (secret API key). The CMS sanitizes content
|
|
274
|
+
* server-side. Additionally, our renderMarkdown escapes HTML entities before
|
|
275
|
+
* processing markdown syntax, preventing injection of raw HTML tags.
|
|
276
|
+
*/
|
|
277
|
+
declare function renderMarkdown(md: string): string;
|
|
278
|
+
/**
|
|
279
|
+
* Convert bare URLs in plain text to clickable links.
|
|
280
|
+
* Used for visitor/team messages (not full markdown).
|
|
281
|
+
* HTML-escaped for safety.
|
|
282
|
+
*/
|
|
283
|
+
declare function linkifyText(text: string): string;
|
|
284
|
+
/**
|
|
285
|
+
* Renders markdown or pre-rendered HTML content.
|
|
286
|
+
* Prefers bodyHtml (server-sanitized by CMS) when available,
|
|
287
|
+
* falls back to client-side markdown rendering (HTML-escaped).
|
|
288
|
+
*/
|
|
289
|
+
declare function MarkdownContent({ bodyHtml, bodyMarkdown, className, }: {
|
|
290
|
+
bodyHtml?: string | null;
|
|
291
|
+
bodyMarkdown?: string | null;
|
|
292
|
+
className?: string;
|
|
293
|
+
}): react_jsx_runtime.JSX.Element | null;
|
|
294
|
+
|
|
295
|
+
export { Composer, DefaultWidget, HelpwayWidget, type HelpwayWidgetProps, type IdentifyData, MarkdownContent, MessageBubble, MessageList, SupportProvider, linkifyText, renderMarkdown, useComposer, useConversations, useIdentify, usePresence, useRealtime, useTimeline, useUnread, useWidget, useWidgetStore };
|
package/dist/index.js
CHANGED
|
@@ -513,7 +513,7 @@ var en = {
|
|
|
513
513
|
// Date separators (today is implicit — never rendered)
|
|
514
514
|
"widget.yesterday": "Yesterday",
|
|
515
515
|
// Sender labels
|
|
516
|
-
"widget.
|
|
516
|
+
"widget.helpway_ai": "Helpway AI",
|
|
517
517
|
"widget.support": "Support",
|
|
518
518
|
// Events
|
|
519
519
|
"widget.joined": "joined the conversation",
|
|
@@ -809,6 +809,9 @@ function SupportProvider({
|
|
|
809
809
|
status: c.status,
|
|
810
810
|
lastMessageText: c.lastMessageText,
|
|
811
811
|
lastMessageAt: c.lastMessageAt,
|
|
812
|
+
lastMessageSenderType: c.lastMessageSenderType,
|
|
813
|
+
lastMessageSenderName: c.lastMessageSenderName,
|
|
814
|
+
lastMessageSenderImage: c.lastMessageSenderImage,
|
|
812
815
|
unreadCount: 0
|
|
813
816
|
})
|
|
814
817
|
)
|
|
@@ -908,7 +911,7 @@ function inferApiUrl() {
|
|
|
908
911
|
}
|
|
909
912
|
|
|
910
913
|
// src/themed/default-widget.tsx
|
|
911
|
-
import { useCallback as useCallback12, useEffect as
|
|
914
|
+
import { useCallback as useCallback12, useEffect as useEffect11, useRef as useRef13, useState as useState12 } from "react";
|
|
912
915
|
|
|
913
916
|
// src/hooks/use-composer.ts
|
|
914
917
|
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
@@ -1113,6 +1116,9 @@ function useConversations() {
|
|
|
1113
1116
|
status: "open",
|
|
1114
1117
|
lastMessageText: text,
|
|
1115
1118
|
lastMessageAt: now,
|
|
1119
|
+
lastMessageSenderType: "visitor",
|
|
1120
|
+
lastMessageSenderName: null,
|
|
1121
|
+
lastMessageSenderImage: null,
|
|
1116
1122
|
unreadCount: 0
|
|
1117
1123
|
});
|
|
1118
1124
|
store2.setMessages(tempConversationId, [optimisticMsg]);
|
|
@@ -1317,16 +1323,40 @@ import {
|
|
|
1317
1323
|
} from "@central-icons-react/round-outlined-radius-2-stroke-2";
|
|
1318
1324
|
|
|
1319
1325
|
// src/themed/message-bubble.tsx
|
|
1320
|
-
import { useCallback as useCallback6, useLayoutEffect, useRef as useRef6, useState as useState6 } from "react";
|
|
1326
|
+
import { useCallback as useCallback6, useEffect as useEffect5, useLayoutEffect, useRef as useRef6, useState as useState6 } from "react";
|
|
1321
1327
|
import { createPortal } from "react-dom";
|
|
1322
1328
|
|
|
1323
1329
|
// src/themed/content/simple-markdown.tsx
|
|
1324
1330
|
import { useEffect as useEffect4, useRef as useRef5 } from "react";
|
|
1325
1331
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1332
|
+
var COPY_ICON = `<svg class="hw-code-copy-icon" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M15 9V4.25C15 3.55964 14.4404 3 13.75 3H4.25C3.55964 3 3 3.55964 3 4.25V13.75C3 14.4404 3.55964 15 4.25 15H9M10.25 9H19.75C20.4404 9 21 9.55964 21 10.25V19.75C21 20.4404 20.4404 21 19.75 21H10.25C9.55964 21 9 20.4404 9 19.75V10.25C9 9.55964 9.55964 9 10.25 9Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
1333
|
+
var CHECK_ICON = `<svg class="hw-code-check-icon" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M8 13L11 16L16 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
1334
|
+
function inferCodeLanguage(code, lang) {
|
|
1335
|
+
if (lang) return lang;
|
|
1336
|
+
const trimmed = code.trim();
|
|
1337
|
+
if (/^(npm|pnpm|yarn|bun|npx|curl|cd|mkdir|cp|mv|rm|export)\b/m.test(trimmed)) return "bash";
|
|
1338
|
+
if (/\b(import|export)\b/.test(trimmed) && /<[A-Z_a-z][\w.:-]*(\s|>)/.test(trimmed)) return "tsx";
|
|
1339
|
+
if (/\b(import|export|const|let|function|type|interface)\b/.test(trimmed)) return "ts";
|
|
1340
|
+
if (/^\s*[{[]/.test(trimmed)) return "json";
|
|
1341
|
+
return "code";
|
|
1342
|
+
}
|
|
1343
|
+
function handleCodeBlockClick(e, root) {
|
|
1344
|
+
const target = e.target;
|
|
1345
|
+
const btn = target?.closest(".hw-code-copy");
|
|
1346
|
+
if (!btn || !root.contains(btn)) return;
|
|
1347
|
+
const block = btn.closest(".hw-code");
|
|
1348
|
+
const code = block?.querySelector("pre code");
|
|
1349
|
+
const text = code?.textContent ?? "";
|
|
1350
|
+
if (!text) return;
|
|
1351
|
+
void navigator.clipboard?.writeText(text).then(
|
|
1352
|
+
() => flashCopied(btn),
|
|
1353
|
+
() => flashCopied(btn, true)
|
|
1354
|
+
);
|
|
1355
|
+
}
|
|
1326
1356
|
function renderMarkdown(md) {
|
|
1327
1357
|
const codeBlocks = [];
|
|
1328
1358
|
const codeBlockPlaceholder = (i) => `\0CODEBLOCK${i}\0`;
|
|
1329
|
-
|
|
1359
|
+
const body = md.replace(
|
|
1330
1360
|
// Eat ALL newlines around the fence (zero-or-more both sides). The
|
|
1331
1361
|
// replacement re-emits its own `\n\n` pair so the paragraph splitter
|
|
1332
1362
|
// cleanly bookends the fence. Without this, `before\n\n` + `\n\n` from
|
|
@@ -1334,11 +1364,11 @@ function renderMarkdown(md) {
|
|
|
1334
1364
|
/\n*```(\w+)?\n?([\s\S]*?)```\n*/g,
|
|
1335
1365
|
(_match, lang, code) => {
|
|
1336
1366
|
const escaped = code.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1337
|
-
const
|
|
1338
|
-
const
|
|
1367
|
+
const langLabel = inferCodeLanguage(code, lang);
|
|
1368
|
+
const className = langLabel !== "code" ? ` class="language-${langLabel}"` : "";
|
|
1339
1369
|
const trimmed = escaped.replace(/\n$/, "");
|
|
1340
1370
|
codeBlocks.push(
|
|
1341
|
-
`<div class="hw-code" data-hw-code="1"><div class="hw-code-header"><span class="hw-code-lang">${langLabel}</span><button type="button" class="hw-code-copy" aria-label="Copy code"
|
|
1371
|
+
`<div class="hw-code" data-hw-code="1"><div class="hw-code-header"><span class="hw-code-lang">${langLabel}</span><div class="hw-code-actions"><button type="button" class="hw-code-action hw-code-copy" aria-label="Copy code" title="Copy code">${COPY_ICON}${CHECK_ICON}<span class="hw-code-copy-label">Copy</span></button></div></div><pre><code${className}>${trimmed}</code></pre></div>`
|
|
1342
1372
|
);
|
|
1343
1373
|
return `
|
|
1344
1374
|
|
|
@@ -1363,10 +1393,7 @@ ${codeBlockPlaceholder(codeBlocks.length - 1)}
|
|
|
1363
1393
|
const i = Number.parseInt(idx, 10);
|
|
1364
1394
|
return codeBlocks[i] ?? "";
|
|
1365
1395
|
});
|
|
1366
|
-
html = html.replace(
|
|
1367
|
-
/<p>(\s*<div class="hw-code"[\s\S]*?<\/div>\s*)<\/p>/g,
|
|
1368
|
-
"$1"
|
|
1369
|
-
);
|
|
1396
|
+
html = html.replace(/<p>(\s*<div class="hw-code"[\s\S]*?<\/div>\s*)<\/p>/g, "$1");
|
|
1370
1397
|
}
|
|
1371
1398
|
return html;
|
|
1372
1399
|
}
|
|
@@ -1387,23 +1414,13 @@ function MarkdownContent({
|
|
|
1387
1414
|
const root = rootRef.current;
|
|
1388
1415
|
if (!root) return;
|
|
1389
1416
|
const handler = (e) => {
|
|
1390
|
-
|
|
1391
|
-
const btn = target?.closest(".hw-code-copy");
|
|
1392
|
-
if (!btn || !root.contains(btn)) return;
|
|
1393
|
-
const block = btn.closest(".hw-code");
|
|
1394
|
-
const code = block?.querySelector("pre code");
|
|
1395
|
-
const text = code?.textContent ?? "";
|
|
1396
|
-
if (!text) return;
|
|
1397
|
-
void navigator.clipboard?.writeText(text).then(
|
|
1398
|
-
() => flashCopied(btn),
|
|
1399
|
-
() => flashCopied(btn, true)
|
|
1400
|
-
);
|
|
1417
|
+
handleCodeBlockClick(e, root);
|
|
1401
1418
|
};
|
|
1402
1419
|
root.addEventListener("click", handler);
|
|
1403
1420
|
return () => {
|
|
1404
1421
|
root.removeEventListener("click", handler);
|
|
1405
1422
|
};
|
|
1406
|
-
}, [
|
|
1423
|
+
}, []);
|
|
1407
1424
|
if (!html) return null;
|
|
1408
1425
|
return /* @__PURE__ */ jsx2(
|
|
1409
1426
|
"div",
|
|
@@ -1430,19 +1447,33 @@ function flashCopied(btn, failed = false) {
|
|
|
1430
1447
|
import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
1431
1448
|
function MessageBubble({ text, sender, senderName, time, parts }) {
|
|
1432
1449
|
const senderClass = `hw-msg--${sender}`;
|
|
1433
|
-
const agentName = useWidgetStore((s) => s.agentConfig?.name) ?? t("widget.
|
|
1450
|
+
const agentName = useWidgetStore((s) => s.agentConfig?.name) ?? t("widget.helpway_ai");
|
|
1434
1451
|
const relativeTime = formatRelativeTime(time);
|
|
1435
1452
|
const meta = sender === "ai" ? `${agentName} \xB7 ${relativeTime}` : relativeTime;
|
|
1453
|
+
const clockTime = formatClockTime(time);
|
|
1454
|
+
const bubbleRef = useRef6(null);
|
|
1436
1455
|
const imageParts = parts?.filter((p) => p.type === "image") ?? [];
|
|
1437
1456
|
const fileParts = parts?.filter((p) => p.type === "file") ?? [];
|
|
1438
1457
|
const hasText = text.length > 0;
|
|
1458
|
+
useEffect5(() => {
|
|
1459
|
+
const bubble = bubbleRef.current;
|
|
1460
|
+
if (!bubble || sender !== "ai" && sender !== "team") return;
|
|
1461
|
+
const handleClick = (event) => {
|
|
1462
|
+
handleCodeBlockClick(event, bubble);
|
|
1463
|
+
};
|
|
1464
|
+
bubble.addEventListener("click", handleClick);
|
|
1465
|
+
return () => {
|
|
1466
|
+
bubble.removeEventListener("click", handleClick);
|
|
1467
|
+
};
|
|
1468
|
+
}, [sender]);
|
|
1439
1469
|
return /* @__PURE__ */ jsx3("div", { className: `hw-msg ${senderClass}`, children: /* @__PURE__ */ jsxs("div", { className: "hw-msg-body", children: [
|
|
1440
1470
|
sender === "team" && /* @__PURE__ */ jsx3("div", { className: "hw-msg-sender", children: senderName ?? t("widget.support") }),
|
|
1441
1471
|
imageParts.length > 0 && /* @__PURE__ */ jsx3("div", { className: "hw-msg-images", children: imageParts.map((img, i) => /* @__PURE__ */ jsx3(PreviewableThumbnail, { src: img.url, type: "image" }, i)) }),
|
|
1442
|
-
hasText && /* @__PURE__ */ jsx3("div", { className: "hw-msg-bubble", children: sender === "ai" || sender === "team" ? /* @__PURE__ */ jsx3("span", { dangerouslySetInnerHTML: { __html: renderMarkdown(text) } }) : /* @__PURE__ */ jsx3("span", { dangerouslySetInnerHTML: { __html: linkifyText(text) } }) }),
|
|
1472
|
+
hasText && /* @__PURE__ */ jsx3("div", { className: "hw-msg-bubble", ref: bubbleRef, children: sender === "ai" || sender === "team" ? /* @__PURE__ */ jsx3("span", { dangerouslySetInnerHTML: { __html: renderMarkdown(text) } }) : /* @__PURE__ */ jsx3("span", { dangerouslySetInnerHTML: { __html: linkifyText(text) } }) }),
|
|
1443
1473
|
fileParts.length > 0 && /* @__PURE__ */ jsx3("div", { className: "hw-msg-files", children: fileParts.map((file, i) => /* @__PURE__ */ jsx3(FileCard, { file }, i)) }),
|
|
1444
1474
|
/* @__PURE__ */ jsxs("div", { className: "hw-msg-meta", children: [
|
|
1445
|
-
|
|
1475
|
+
/* @__PURE__ */ jsx3("span", { className: "hw-msg-time", children: clockTime }),
|
|
1476
|
+
/* @__PURE__ */ jsx3("span", { className: "hw-msg-hover-meta", children: meta }),
|
|
1446
1477
|
hasText && /* @__PURE__ */ jsx3(CopyButton, { text })
|
|
1447
1478
|
] })
|
|
1448
1479
|
] }) });
|
|
@@ -1582,6 +1613,15 @@ function formatFileSize(bytes) {
|
|
|
1582
1613
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} KB`;
|
|
1583
1614
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1584
1615
|
}
|
|
1616
|
+
function formatClockTime(value) {
|
|
1617
|
+
const date = new Date(value);
|
|
1618
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
1619
|
+
return date.toLocaleTimeString(void 0, {
|
|
1620
|
+
hour: "2-digit",
|
|
1621
|
+
hour12: false,
|
|
1622
|
+
minute: "2-digit"
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1585
1625
|
function CopyButton({ text }) {
|
|
1586
1626
|
const [copied, setCopied] = useState6(false);
|
|
1587
1627
|
const handleCopy = useCallback6(
|
|
@@ -1891,7 +1931,7 @@ function extractFiles(data) {
|
|
|
1891
1931
|
}
|
|
1892
1932
|
|
|
1893
1933
|
// src/themed/debug-overlay.tsx
|
|
1894
|
-
import { useEffect as
|
|
1934
|
+
import { useEffect as useEffect6, useMemo, useRef as useRef8, useState as useState8 } from "react";
|
|
1895
1935
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1896
1936
|
var MAX_EVENTS = 60;
|
|
1897
1937
|
function isDebugEnabled() {
|
|
@@ -1918,7 +1958,7 @@ function WidgetDebugOverlay() {
|
|
|
1918
1958
|
const typingUsers = useWidgetStore((s) => s.typingUsers);
|
|
1919
1959
|
const aiProcessingMap = useWidgetStore((s) => s.aiProcessing);
|
|
1920
1960
|
const { store } = useWidgetContext();
|
|
1921
|
-
|
|
1961
|
+
useEffect6(() => {
|
|
1922
1962
|
setEnabled(isDebugEnabled());
|
|
1923
1963
|
}, []);
|
|
1924
1964
|
const pushEvent = useMemo(
|
|
@@ -1933,7 +1973,7 @@ function WidgetDebugOverlay() {
|
|
|
1933
1973
|
},
|
|
1934
1974
|
[]
|
|
1935
1975
|
);
|
|
1936
|
-
|
|
1976
|
+
useEffect6(() => {
|
|
1937
1977
|
if (!enabled) return;
|
|
1938
1978
|
if (typeof window === "undefined" || typeof window.fetch !== "function") return;
|
|
1939
1979
|
const originalFetch = window.fetch.bind(window);
|
|
@@ -1965,7 +2005,7 @@ function WidgetDebugOverlay() {
|
|
|
1965
2005
|
window.fetch = originalFetch;
|
|
1966
2006
|
};
|
|
1967
2007
|
}, [enabled, pushEvent]);
|
|
1968
|
-
|
|
2008
|
+
useEffect6(() => {
|
|
1969
2009
|
if (!enabled) return;
|
|
1970
2010
|
const original = store.getState().handleRealtimeEvent;
|
|
1971
2011
|
store.setState({
|
|
@@ -1984,7 +2024,7 @@ function WidgetDebugOverlay() {
|
|
|
1984
2024
|
[activeMessages]
|
|
1985
2025
|
);
|
|
1986
2026
|
const prevSigRef = useRef8(lastMsgSignature);
|
|
1987
|
-
|
|
2027
|
+
useEffect6(() => {
|
|
1988
2028
|
if (!enabled) return;
|
|
1989
2029
|
if (prevSigRef.current !== lastMsgSignature) {
|
|
1990
2030
|
prevSigRef.current = lastMsgSignature;
|
|
@@ -2137,10 +2177,10 @@ var styles = {
|
|
|
2137
2177
|
};
|
|
2138
2178
|
|
|
2139
2179
|
// src/themed/content/content-tab-view.tsx
|
|
2140
|
-
import { useCallback as useCallback11, useEffect as
|
|
2180
|
+
import { useCallback as useCallback11, useEffect as useEffect9 } from "react";
|
|
2141
2181
|
|
|
2142
2182
|
// src/hooks/use-content-tab.ts
|
|
2143
|
-
import { useCallback as useCallback8, useEffect as
|
|
2183
|
+
import { useCallback as useCallback8, useEffect as useEffect7, useState as useState9 } from "react";
|
|
2144
2184
|
var EMPTY_TABS = [];
|
|
2145
2185
|
function listKey(tabId, lang) {
|
|
2146
2186
|
return `flat:${tabId}:${lang}:list`;
|
|
@@ -2255,7 +2295,7 @@ function useContentTab(tabId) {
|
|
|
2255
2295
|
const clearDetail = useCallback8(() => {
|
|
2256
2296
|
setDetail(null);
|
|
2257
2297
|
}, []);
|
|
2258
|
-
|
|
2298
|
+
useEffect7(() => {
|
|
2259
2299
|
if (tab && entries.length === 0) {
|
|
2260
2300
|
fetchEntries({ page: 1, reset: true });
|
|
2261
2301
|
}
|
|
@@ -2401,7 +2441,7 @@ function ContentEntryCard({
|
|
|
2401
2441
|
}
|
|
2402
2442
|
|
|
2403
2443
|
// src/themed/content/grouped-content-tab-view.tsx
|
|
2404
|
-
import { useEffect as
|
|
2444
|
+
import { useEffect as useEffect8, useRef as useRef11 } from "react";
|
|
2405
2445
|
|
|
2406
2446
|
// src/hooks/use-grouped-content-tab.ts
|
|
2407
2447
|
import { useCallback as useCallback10, useRef as useRef10, useState as useState11 } from "react";
|
|
@@ -2645,16 +2685,16 @@ function GroupedContentTabView({
|
|
|
2645
2685
|
fetchDetail,
|
|
2646
2686
|
clearCategory
|
|
2647
2687
|
} = useGroupedContentTab(tab.id);
|
|
2648
|
-
|
|
2688
|
+
useEffect8(() => {
|
|
2649
2689
|
initFetch();
|
|
2650
2690
|
}, [initFetch]);
|
|
2651
|
-
|
|
2691
|
+
useEffect8(() => {
|
|
2652
2692
|
if (detailSlug && subView === "content-detail") {
|
|
2653
2693
|
fetchDetail(detailSlug);
|
|
2654
2694
|
}
|
|
2655
2695
|
}, [detailSlug, subView, fetchDetail]);
|
|
2656
2696
|
const prevSubView = useRef11(subView);
|
|
2657
|
-
|
|
2697
|
+
useEffect8(() => {
|
|
2658
2698
|
if (prevSubView.current === "content-category" && subView === null) {
|
|
2659
2699
|
clearCategory();
|
|
2660
2700
|
}
|
|
@@ -2748,7 +2788,7 @@ function FlatContentTabView({
|
|
|
2748
2788
|
loadMore,
|
|
2749
2789
|
fetchDetail
|
|
2750
2790
|
} = useContentTab(tab.id);
|
|
2751
|
-
|
|
2791
|
+
useEffect9(() => {
|
|
2752
2792
|
if (detailSlug) fetchDetail(detailSlug);
|
|
2753
2793
|
}, [detailSlug, fetchDetail]);
|
|
2754
2794
|
const handleSearch = useCallback11(
|
|
@@ -2791,7 +2831,7 @@ function ContentTabIconComponent({ icon }) {
|
|
|
2791
2831
|
}
|
|
2792
2832
|
|
|
2793
2833
|
// src/themed/message-list.tsx
|
|
2794
|
-
import React, { useEffect as
|
|
2834
|
+
import React, { useEffect as useEffect10, useRef as useRef12 } from "react";
|
|
2795
2835
|
import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2796
2836
|
function parseParts(raw) {
|
|
2797
2837
|
if (!raw) return null;
|
|
@@ -2818,8 +2858,8 @@ function MessageList({
|
|
|
2818
2858
|
const containerRef = useRef12(null);
|
|
2819
2859
|
const prevItemCountRef = useRef12(items.length);
|
|
2820
2860
|
const isInitialLoadRef = useRef12(true);
|
|
2821
|
-
const agentName = useWidgetStore((s) => s.agentConfig?.name) ?? t("widget.
|
|
2822
|
-
|
|
2861
|
+
const agentName = useWidgetStore((s) => s.agentConfig?.name) ?? t("widget.helpway_ai");
|
|
2862
|
+
useEffect10(() => {
|
|
2823
2863
|
const prevCount = prevItemCountRef.current;
|
|
2824
2864
|
const newCount = items.length;
|
|
2825
2865
|
prevItemCountRef.current = newCount;
|
|
@@ -2834,12 +2874,12 @@ function MessageList({
|
|
|
2834
2874
|
isInitialLoadRef.current = false;
|
|
2835
2875
|
}
|
|
2836
2876
|
}, [items]);
|
|
2837
|
-
|
|
2877
|
+
useEffect10(() => {
|
|
2838
2878
|
if (isTyping || isAiProcessing) {
|
|
2839
2879
|
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2840
2880
|
}
|
|
2841
2881
|
}, [isTyping, isAiProcessing]);
|
|
2842
|
-
|
|
2882
|
+
useEffect10(() => {
|
|
2843
2883
|
if (!hasMore || !onLoadMore || !topRef.current) return;
|
|
2844
2884
|
const observer = new IntersectionObserver(
|
|
2845
2885
|
(entries) => {
|
|
@@ -3275,7 +3315,7 @@ function DefaultWidget({ initialOpen = false } = {}) {
|
|
|
3275
3315
|
handleClose();
|
|
3276
3316
|
}
|
|
3277
3317
|
}, [handleClose]);
|
|
3278
|
-
|
|
3318
|
+
useEffect11(() => {
|
|
3279
3319
|
if (!isOpen || !windowRef.current) return;
|
|
3280
3320
|
const vv = window.visualViewport;
|
|
3281
3321
|
if (!vv) return;
|
|
@@ -3292,7 +3332,7 @@ function DefaultWidget({ initialOpen = false } = {}) {
|
|
|
3292
3332
|
win.style.removeProperty("--hw-visible-height");
|
|
3293
3333
|
};
|
|
3294
3334
|
}, [isOpen]);
|
|
3295
|
-
|
|
3335
|
+
useEffect11(() => {
|
|
3296
3336
|
if (!isOpen || !windowRef.current) return;
|
|
3297
3337
|
const win = windowRef.current;
|
|
3298
3338
|
const handleKeyDown = (e) => {
|
|
@@ -3308,7 +3348,7 @@ function DefaultWidget({ initialOpen = false } = {}) {
|
|
|
3308
3348
|
win.addEventListener("keydown", handleKeyDown);
|
|
3309
3349
|
return () => win.removeEventListener("keydown", handleKeyDown);
|
|
3310
3350
|
}, [isOpen, subView, handleClose, goBack]);
|
|
3311
|
-
|
|
3351
|
+
useEffect11(() => {
|
|
3312
3352
|
if (!isOpen || !windowRef.current) return;
|
|
3313
3353
|
const win = windowRef.current;
|
|
3314
3354
|
const getFocusable = () => win.querySelectorAll(
|
|
@@ -3340,6 +3380,12 @@ function DefaultWidget({ initialOpen = false } = {}) {
|
|
|
3340
3380
|
return () => win.removeEventListener("keydown", handleTab);
|
|
3341
3381
|
}, [isOpen]);
|
|
3342
3382
|
const showTabBar = subView === null;
|
|
3383
|
+
const activeConvSummary = useWidgetStore((s) => {
|
|
3384
|
+
const id = s.activeConversationId;
|
|
3385
|
+
return id ? s.conversations.find((c) => c.id === id) : null;
|
|
3386
|
+
});
|
|
3387
|
+
const hasTeamAgent = activeConvSummary?.lastMessageSenderType === "team" && activeConvSummary?.lastMessageSenderName;
|
|
3388
|
+
const headerName = hasTeamAgent ? activeConvSummary.lastMessageSenderName : agentConfig?.name ?? website?.name ?? "Support";
|
|
3343
3389
|
const companyName = agentConfig?.name ?? website?.name ?? "Support";
|
|
3344
3390
|
const subtitleMsg = agentConfig?.subtitleText;
|
|
3345
3391
|
const subtitleIsFactoryDefault = !subtitleMsg || subtitleMsg === DEFAULT_EN_SUBTITLE;
|
|
@@ -3448,9 +3494,9 @@ function DefaultWidget({ initialOpen = false } = {}) {
|
|
|
3448
3494
|
}
|
|
3449
3495
|
),
|
|
3450
3496
|
/* @__PURE__ */ jsxs7("div", { className: "hw-header-identity", children: [
|
|
3451
|
-
/* @__PURE__ */ jsx12("div", { className: "hw-header-bot-icon", children: /* @__PURE__ */ jsx12(WidgetLogo, {}) }),
|
|
3497
|
+
/* @__PURE__ */ jsx12("div", { className: `hw-header-bot-icon${hasTeamAgent ? " hw-header-bot-icon--team" : ""}`, children: hasTeamAgent && activeConvSummary?.lastMessageSenderImage ? /* @__PURE__ */ jsx12("img", { src: activeConvSummary.lastMessageSenderImage, alt: headerName, className: "hw-header-agent-img" }) : hasTeamAgent ? /* @__PURE__ */ jsx12("span", { className: "hw-header-agent-initials", children: headerName.split(" ").map((w) => w[0]).join("").slice(0, 2).toUpperCase() }) : /* @__PURE__ */ jsx12(WidgetLogo, {}) }),
|
|
3452
3498
|
/* @__PURE__ */ jsxs7("div", { className: "hw-header-info", children: [
|
|
3453
|
-
/* @__PURE__ */ jsx12("div", { className: "hw-header-name", children:
|
|
3499
|
+
/* @__PURE__ */ jsx12("div", { className: "hw-header-name", children: headerName }),
|
|
3454
3500
|
/* @__PURE__ */ jsx12("div", { className: "hw-header-status", children: subtitleText })
|
|
3455
3501
|
] })
|
|
3456
3502
|
] }),
|
|
@@ -3741,12 +3787,14 @@ function MessagesView({
|
|
|
3741
3787
|
}
|
|
3742
3788
|
function ConvCardBody({ conv }) {
|
|
3743
3789
|
const agentName = useWidgetStore((s) => s.agentConfig?.name) ?? "Support";
|
|
3790
|
+
const isTeam = conv.lastMessageSenderType === "team" && conv.lastMessageSenderName;
|
|
3791
|
+
const displayName = isTeam ? conv.lastMessageSenderName : agentName;
|
|
3744
3792
|
const preview = conv.lastMessageText ?? t("widget.no_preview");
|
|
3745
3793
|
return /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
3746
|
-
/* @__PURE__ */ jsx12("div", { className: "hw-conv-card-avatar", children: /* @__PURE__ */ jsx12(WidgetLogo, {}) }),
|
|
3794
|
+
/* @__PURE__ */ jsx12("div", { className: `hw-conv-card-avatar${isTeam ? " hw-conv-card-avatar--team" : ""}`, children: isTeam ? conv.lastMessageSenderImage ? /* @__PURE__ */ jsx12("img", { src: conv.lastMessageSenderImage, alt: displayName, className: "hw-conv-card-avatar-img" }) : /* @__PURE__ */ jsx12("span", { className: "hw-conv-card-avatar-initials", children: displayName.split(" ").map((w) => w[0]).join("").slice(0, 2).toUpperCase() }) : /* @__PURE__ */ jsx12(WidgetLogo, {}) }),
|
|
3747
3795
|
/* @__PURE__ */ jsxs7("div", { className: "hw-conv-card-content", children: [
|
|
3748
3796
|
/* @__PURE__ */ jsxs7("div", { className: "hw-conv-card-top", children: [
|
|
3749
|
-
/* @__PURE__ */ jsx12("span", { className: "hw-conv-card-name", children:
|
|
3797
|
+
/* @__PURE__ */ jsx12("span", { className: "hw-conv-card-name", children: displayName }),
|
|
3750
3798
|
conv.lastMessageAt && /* @__PURE__ */ jsx12("span", { className: "hw-conv-card-time", children: formatRelativeTime(conv.lastMessageAt) })
|
|
3751
3799
|
] }),
|
|
3752
3800
|
/* @__PURE__ */ jsx12("div", { className: "hw-conv-card-preview", children: preview })
|
|
@@ -4053,7 +4101,7 @@ function MessagePreview({ onOpen }) {
|
|
|
4053
4101
|
const dismissPreview = useWidgetStore((s) => s.dismissPreview);
|
|
4054
4102
|
const agentName = useWidgetStore((s) => s.agentConfig?.name) ?? "Support";
|
|
4055
4103
|
const [closing, setClosing] = useState12(false);
|
|
4056
|
-
|
|
4104
|
+
useEffect11(() => {
|
|
4057
4105
|
if (!preview) return;
|
|
4058
4106
|
const timer = setTimeout(() => {
|
|
4059
4107
|
setClosing(true);
|
|
@@ -4102,6 +4150,31 @@ function MessagePreview({ onOpen }) {
|
|
|
4102
4150
|
);
|
|
4103
4151
|
}
|
|
4104
4152
|
|
|
4153
|
+
// #style-inject:#style-inject
|
|
4154
|
+
function styleInject(css, { insertAt } = {}) {
|
|
4155
|
+
if (!css || typeof document === "undefined") return;
|
|
4156
|
+
const head = document.head || document.getElementsByTagName("head")[0];
|
|
4157
|
+
const style = document.createElement("style");
|
|
4158
|
+
style.type = "text/css";
|
|
4159
|
+
if (insertAt === "top") {
|
|
4160
|
+
if (head.firstChild) {
|
|
4161
|
+
head.insertBefore(style, head.firstChild);
|
|
4162
|
+
} else {
|
|
4163
|
+
head.appendChild(style);
|
|
4164
|
+
}
|
|
4165
|
+
} else {
|
|
4166
|
+
head.appendChild(style);
|
|
4167
|
+
}
|
|
4168
|
+
if (style.styleSheet) {
|
|
4169
|
+
style.styleSheet.cssText = css;
|
|
4170
|
+
} else {
|
|
4171
|
+
style.appendChild(document.createTextNode(css));
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4174
|
+
|
|
4175
|
+
// src/themed/styles.css
|
|
4176
|
+
styleInject(':host {\n all: initial;\n font-family:\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n Roboto,\n "Helvetica Neue",\n Arial,\n sans-serif;\n font-size: 14px;\n line-height: 1.5;\n color: #1a1a1a;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.hw-widget {\n font-family:\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n Roboto,\n "Helvetica Neue",\n Arial,\n sans-serif;\n font-size: 14px;\n line-height: 1.5;\n color: #1a1a1a;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.hw-widget *,\n.hw-widget *::before,\n.hw-widget *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n.hw-widget {\n --hw-primary: #171717;\n --hw-primary-hover: #2a2a2a;\n --hw-focus-border: #9ca3af;\n --hw-focus-ring: rgba(0, 0, 0, 0.06);\n --hw-accent: #6366f1;\n --hw-bg: #ffffff;\n --hw-bg-subtle: #fafafa;\n --hw-bg-hover: #f5f5f5;\n --hw-border: #f0f0f0;\n --hw-border-md: #e5e5e5;\n --hw-text: #111;\n --hw-text-1: #111;\n --hw-text-2: #666;\n --hw-text-3: #999;\n --hw-text-4: #bbb;\n --hw-radius: 16px;\n --hw-visitor-bubble-bg: #f0f0f0;\n --hw-visitor-bubble-text: #1a1a1a;\n --hw-font:\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n Roboto,\n "Helvetica Neue",\n Arial,\n sans-serif;\n}\n.hw-agent-img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.hw-agent-icon {\n width: 100%;\n height: 100%;\n border-radius: inherit;\n}\n.hw-widget :focus-visible {\n outline: 2px solid var(--hw-primary);\n outline-offset: 2px;\n}\n.hw-widget :focus:not(:focus-visible) {\n outline: none;\n}\n.hw-widget {\n position: fixed;\n bottom: 20px;\n right: var(--hw-position-right, 20px);\n left: var(--hw-position-left, auto);\n z-index: 999999;\n font-family: var(--hw-font);\n}\n.hw-bubble {\n width: 48px;\n height: 48px;\n border-radius: 14px;\n background: var(--hw-primary);\n color: white;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease;\n position: relative;\n overflow: visible;\n}\n.hw-bubble--rounded {\n border-radius: 14px;\n}\n.hw-bubble--square {\n border-radius: 8px;\n}\n.hw-bubble--pill {\n border-radius: 24px;\n}\n.hw-bubble--launcher-bubble,\n.hw-bubble--launcher-help {\n width: auto;\n padding: 0 16px 0 12px;\n gap: 8px;\n border-radius: 24px;\n}\n.hw-bubble--launcher-bubble.hw-bubble--square,\n.hw-bubble--launcher-help.hw-bubble--square {\n border-radius: 8px;\n}\n.hw-bubble--launcher-bubble.hw-bubble--rounded,\n.hw-bubble--launcher-help.hw-bubble--rounded {\n border-radius: 14px;\n}\n.hw-bubble-label {\n font-size: 14px;\n font-weight: 600;\n white-space: nowrap;\n line-height: 1;\n position: static;\n opacity: 1;\n transform: none;\n}\n.hw-bubble--launcher-bubble .hw-bubble-icon,\n.hw-bubble--launcher-help .hw-bubble-icon {\n position: static;\n}\n.hw-bubble:hover {\n transform: scale(1.05);\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);\n}\n.hw-bubble:active {\n transform: scale(0.95);\n}\n.hw-bubble--open {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\n}\n.hw-bubble:focus-visible {\n outline: 2px solid white;\n outline-offset: 2px;\n}\n.hw-bubble-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.2s ease;\n}\n.hw-bubble-icon svg {\n width: 22px;\n height: 22px;\n}\n.hw-bubble-icon--hidden {\n transform: scale(0.3) rotate(90deg);\n opacity: 0;\n}\n.hw-bubble-icon--bot {\n}\n.hw-bubble--avatar .hw-bubble-icon--bot {\n width: 100%;\n height: 100%;\n}\n.hw-bubble--avatar .hw-bubble-icon--bot .hw-agent-img {\n width: 100%;\n height: 100%;\n border-radius: 0;\n}\n.hw-bubble-icon--close svg {\n width: 22px;\n height: 22px;\n}\n.hw-bubble-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 20px;\n height: 20px;\n border-radius: 10px;\n background: var(--hw-primary);\n color: white;\n font-size: 11px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 5px;\n border: 2px solid white;\n animation: hw-badge-pop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n@keyframes hw-badge-pop {\n from {\n transform: scale(0);\n }\n to {\n transform: scale(1);\n }\n}\n.hw-bubble-badge::after {\n content: "";\n position: absolute;\n inset: -2px;\n border-radius: inherit;\n background: var(--hw-primary);\n opacity: 0;\n animation: hw-badge-pulse 2s ease-out infinite;\n}\n@keyframes hw-badge-pulse {\n 0% {\n opacity: 0.5;\n transform: scale(1);\n }\n 100% {\n opacity: 0;\n transform: scale(1.8);\n }\n}\n.hw-window {\n position: absolute;\n bottom: 72px;\n right: var(--hw-window-right, 0);\n left: var(--hw-window-left, auto);\n width: 440px;\n height: 640px;\n background: var(--hw-bg-subtle);\n color: var(--hw-text);\n border-radius: var(--hw-radius);\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.04);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: hw-window-open 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n@keyframes hw-window-open {\n from {\n opacity: 0;\n transform: translateY(12px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n.hw-window--closing {\n animation: hw-window-close 0.2s ease forwards;\n}\n@keyframes hw-window-close {\n from {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n to {\n opacity: 0;\n transform: translateY(8px) scale(0.98);\n }\n}\n.hw-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-height: 0;\n}\n@media (prefers-reduced-motion: reduce) {\n .hw-window,\n .hw-window--closing,\n .hw-content,\n .hw-msg,\n .hw-bubble-icon,\n .hw-bubble-badge,\n .hw-bubble-badge::after,\n .hw-typing-dot,\n .hw-loading-dot {\n animation-duration: 0.01ms !important;\n transition-duration: 0.01ms !important;\n }\n}\n.hw-hero {\n flex-shrink: 0;\n background:\n linear-gradient(\n 160deg,\n color-mix(in srgb, var(--hw-primary) 60%, black) 0%,\n var(--hw-primary) 50%,\n color-mix(in srgb, var(--hw-primary) 40%, black) 100%);\n color: white;\n padding: 20px 22px 40px;\n}\n.hw-hero-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n}\n.hw-hero-close {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n border: none;\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.6);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.15s, color 0.15s;\n}\n.hw-hero-close:hover {\n background: rgba(255, 255, 255, 0.2);\n color: white;\n}\n.hw-hero-close:active {\n transform: scale(0.92);\n transition:\n transform 0.14s cubic-bezier(0.23, 1, 0.32, 1),\n background 0.15s,\n color 0.15s;\n}\n.hw-hero-close svg {\n width: 20px;\n height: 20px;\n}\n.hw-hero-bot-icon {\n width: 36px;\n height: 36px;\n flex-shrink: 0;\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n overflow: hidden;\n}\n.hw-hero-bot-icon svg {\n width: 32px;\n height: 32px;\n}\n.hw-hero-greeting {\n font-size: 26px;\n font-weight: 700;\n line-height: 1.15;\n margin-bottom: 6px;\n}\n.hw-hero-greeting-name {\n font-weight: 300;\n}\n.hw-hero-greeting-question {\n font-weight: 700;\n}\n.hw-hero-subtitle {\n font-size: 15px;\n color: rgba(255, 255, 255, 0.5);\n line-height: 1.35;\n}\n.hw-sheet {\n flex: 1;\n overflow-y: auto;\n min-height: 0;\n background: #ffffff;\n border-radius: 20px 20px 0 0;\n margin-top: -24px;\n box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.08);\n position: relative;\n z-index: 1;\n}\n.hw-sheet-inner {\n padding: 20px 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.hw-header {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n background: var(--hw-primary);\n color: white;\n flex-shrink: 0;\n gap: 10px;\n}\n.hw-header--sub {\n justify-content: space-between;\n background: transparent;\n color: var(--hw-text);\n border-bottom: 1px solid var(--hw-border);\n}\n.hw-header-back {\n width: 28px;\n height: 28px;\n border-radius: 8px;\n border: none;\n background: transparent;\n color: var(--hw-text-3);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.15s, background 0.15s;\n flex-shrink: 0;\n}\n.hw-header-back svg {\n width: 18px;\n height: 18px;\n}\n.hw-header-back:hover {\n color: var(--hw-text);\n background: var(--hw-bg-subtle);\n}\n.hw-header-identity {\n display: flex;\n align-items: center;\n gap: 10px;\n flex: 1;\n min-width: 0;\n}\n.hw-header-bot-icon {\n width: 28px;\n height: 28px;\n flex-shrink: 0;\n color: var(--hw-text);\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n overflow: hidden;\n}\n.hw-header-bot-icon svg {\n width: 24px;\n height: 24px;\n}\n.hw-header-bot-icon--team {\n background: var(--hw-brand, #0a0a0a);\n color: #fff;\n}\n.hw-header-agent-img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.hw-header-agent-initials {\n font-size: 11px;\n font-weight: 600;\n line-height: 1;\n}\n.hw-header-info {\n flex: 1;\n min-width: 0;\n}\n.hw-header-name {\n font-size: 14px;\n font-weight: 600;\n line-height: 1.3;\n}\n.hw-header-status {\n font-size: 12px;\n color: var(--hw-text-3);\n line-height: 1.3;\n}\n.hw-header-close {\n width: 28px;\n height: 28px;\n border-radius: 8px;\n border: none;\n background: transparent;\n color: var(--hw-text-3);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition:\n background-color 140ms cubic-bezier(0.23, 1, 0.32, 1),\n color 140ms cubic-bezier(0.23, 1, 0.32, 1),\n transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\n flex-shrink: 0;\n}\n.hw-header-close svg {\n width: 20px;\n height: 20px;\n}\n.hw-header-close:hover {\n background: var(--hw-bg-subtle);\n color: var(--hw-text);\n}\n.hw-header-close:active {\n transform: scale(0.92);\n}\n.hw-header--centered {\n justify-content: space-between;\n background: transparent;\n color: var(--hw-text);\n border-bottom: 1px solid var(--hw-border);\n}\n.hw-header--centered .hw-header-title {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n max-width: calc(100% - 88px);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n text-align: center;\n}\n.hw-header-spacer {\n width: 28px;\n flex-shrink: 0;\n}\n.hw-header--messages {\n justify-content: space-between;\n background: transparent;\n color: var(--hw-text);\n border-bottom: 1px solid var(--hw-border);\n}\n.hw-header-title {\n font-size: 16px;\n font-weight: 600;\n}\n.hw-header-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.hw-header-action {\n width: 28px;\n height: 28px;\n border-radius: 8px;\n border: none;\n background: transparent;\n color: var(--hw-text-3);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition:\n background-color 140ms cubic-bezier(0.23, 1, 0.32, 1),\n color 140ms cubic-bezier(0.23, 1, 0.32, 1),\n transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\n}\n.hw-header-action svg {\n width: 16px;\n height: 16px;\n}\n.hw-header-action:hover {\n background: var(--hw-bg-subtle);\n color: var(--hw-text);\n}\n.hw-header-action:active {\n transform: scale(0.94);\n}\n.hw-card {\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n padding: 14px 16px;\n border-radius: 14px;\n background: var(--hw-bg);\n border: 1px solid rgba(0, 0, 0, 0.06);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.03);\n cursor: pointer;\n transition: box-shadow 180ms cubic-bezier(0.23, 1, 0.32, 1), transform 180ms cubic-bezier(0.23, 1, 0.32, 1);\n text-align: left;\n color: var(--hw-text);\n font-family: inherit;\n}\n.hw-card:hover {\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08), 0 0 0 1px rgba(0, 0, 0, 0.05);\n transform: translateY(-1px);\n}\n.hw-card:active {\n transform: translateY(0) scale(0.99);\n transition-duration: 120ms;\n}\n.hw-card-body {\n flex: 1;\n min-width: 0;\n}\n.hw-card-title {\n font-size: 14px;\n font-weight: 600;\n line-height: 1.3;\n color: var(--hw-text);\n}\n.hw-card-meta {\n font-size: 12px;\n color: var(--hw-text-3);\n line-height: 1.3;\n margin-top: 1px;\n}\n.hw-card-arrow {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--hw-primary);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n.hw-card-arrow svg {\n width: 14px;\n height: 14px;\n}\n.hw-msgs-tab {\n flex: 1;\n overflow-y: auto;\n padding: 12px 16px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.hw-recent-card {\n border-radius: 14px;\n background: var(--hw-bg);\n border: 1px solid rgba(0, 0, 0, 0.06);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.03);\n overflow: hidden;\n}\n.hw-recent-header {\n font-size: 12px;\n font-weight: 600;\n color: var(--hw-text-2);\n padding: 12px 14px 0;\n}\n.hw-recent-row {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 14px;\n border: none;\n border-bottom: 1px solid var(--hw-border);\n background: none;\n cursor: pointer;\n text-align: left;\n font-family: inherit;\n color: var(--hw-text);\n transition: background-color 140ms cubic-bezier(0.23, 1, 0.32, 1), transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\n position: relative;\n}\n.hw-recent-row:hover {\n background: rgba(0, 0, 0, 0.03);\n}\n.hw-recent-row:active {\n transform: scale(0.995);\n}\n.hw-recent-row--last {\n border-bottom: none;\n}\n.hw-recent-row .hw-conv-card-avatar {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n}\n.hw-recent-row .hw-conv-card-avatar svg {\n width: 18px;\n height: 18px;\n}\n.hw-recent-row .hw-conv-card-name {\n font-size: 13px;\n}\n.hw-recent-row .hw-conv-card-preview {\n font-size: 12px;\n}\n.hw-recent-row--unread .hw-conv-card-name {\n color: var(--hw-text);\n}\n.hw-recent-row--unread .hw-conv-card-time {\n color: var(--hw-accent);\n font-weight: 500;\n}\n.hw-recent-row-badge {\n min-width: 18px;\n height: 18px;\n border-radius: 9px;\n background: var(--hw-primary);\n color: white;\n font-size: 11px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 5px;\n flex-shrink: 0;\n font-variant-numeric: tabular-nums;\n}\n.hw-recent-see-all {\n display: block;\n width: 100%;\n padding: 10px 14px;\n text-align: center;\n font-size: 13px;\n font-weight: 500;\n color: var(--hw-text);\n background: none;\n border: none;\n border-top: 1px solid var(--hw-border);\n cursor: pointer;\n font-family: inherit;\n transition: background 0.1s;\n}\n.hw-recent-see-all:hover {\n background: rgba(0, 0, 0, 0.02);\n}\n.hw-conv-card {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n padding: 14px 16px;\n border-radius: 14px;\n background: var(--hw-bg);\n border: 1px solid rgba(0, 0, 0, 0.06);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.03);\n cursor: pointer;\n transition: box-shadow 0.15s, transform 0.1s;\n text-align: left;\n font-family: inherit;\n color: var(--hw-text);\n}\n.hw-conv-card:hover {\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.04);\n}\n.hw-conv-card:active {\n transform: scale(0.99);\n}\n.hw-conv-card-row {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n.hw-conv-card-avatar {\n width: 36px;\n height: 36px;\n border-radius: 10px;\n background: var(--hw-bg-subtle);\n color: var(--hw-text-3);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n overflow: hidden;\n}\n.hw-conv-card-avatar svg {\n width: 20px;\n height: 20px;\n}\n.hw-conv-card-avatar-img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.hw-conv-card-avatar--team {\n background: var(--hw-brand, #0a0a0a);\n color: #fff;\n}\n.hw-conv-card-avatar-initials {\n font-size: 12px;\n font-weight: 600;\n line-height: 1;\n letter-spacing: 0.02em;\n}\n.hw-conv-card-content {\n flex: 1;\n min-width: 0;\n}\n.hw-conv-card-top {\n display: flex;\n align-items: baseline;\n gap: 8px;\n}\n.hw-conv-card-name {\n flex: 1;\n font-size: 14px;\n font-weight: 600;\n color: var(--hw-text);\n}\n.hw-conv-card-time {\n font-size: 11px;\n color: var(--hw-text-3);\n flex-shrink: 0;\n font-variant-numeric: tabular-nums;\n}\n.hw-conv-card-preview {\n font-size: 13px;\n color: var(--hw-text-2);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n line-height: 1.4;\n margin-top: 1px;\n}\n.hw-conv-card--unread .hw-conv-card-name {\n color: var(--hw-text);\n}\n.hw-conv-card--unread .hw-conv-card-time {\n color: var(--hw-accent);\n font-weight: 500;\n}\n.hw-conv-card-badge {\n position: absolute;\n top: 12px;\n right: 12px;\n min-width: 18px;\n height: 18px;\n border-radius: 9px;\n background: var(--hw-primary);\n color: white;\n font-size: 11px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 5px;\n font-variant-numeric: tabular-nums;\n}\n.hw-empty-state {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px;\n text-align: center;\n}\n.hw-empty-icon-wrap {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: var(--hw-bg-subtle);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 16px;\n color: var(--hw-text-3);\n}\n.hw-empty-icon-wrap svg {\n width: 24px;\n height: 24px;\n}\n.hw-empty-title {\n font-size: 15px;\n font-weight: 600;\n color: var(--hw-text);\n margin-bottom: 4px;\n}\n.hw-empty-desc {\n font-size: 13px;\n color: var(--hw-text-3);\n margin-bottom: 20px;\n}\n.hw-empty-btn {\n padding: 8px 20px;\n border-radius: 10px;\n background: var(--hw-primary);\n color: white;\n border: none;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n font-family: inherit;\n transition: background 0.15s;\n}\n.hw-empty-btn:hover {\n background: var(--hw-primary-hover);\n}\n.hw-tabs {\n display: flex;\n border-top: 1px solid var(--hw-border);\n flex-shrink: 0;\n background: var(--hw-bg-subtle);\n}\n.hw-tabs-item {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n padding: 8px 0;\n border: none;\n background: none;\n cursor: pointer;\n font-family: inherit;\n font-size: 11px;\n font-weight: 500;\n color: var(--hw-text-3);\n transition: color 0.15s;\n}\n.hw-tabs-item svg {\n width: 22px;\n height: 22px;\n}\n.hw-tabs-item--active {\n color: var(--hw-text);\n}\n.hw-tabs-item:hover {\n color: var(--hw-text-2);\n}\n.hw-tabs-item:active {\n transform: scale(0.94);\n transition: transform 0.14s cubic-bezier(0.23, 1, 0.32, 1), color 0.15s;\n}\n.hw-tabs-icon-wrap {\n position: relative;\n display: inline-flex;\n}\n.hw-tabs-badge {\n position: absolute;\n top: -6px;\n right: -10px;\n min-width: 16px;\n height: 16px;\n border-radius: 8px;\n background: var(--hw-primary);\n color: white;\n font-size: 10px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 4px;\n font-variant-numeric: tabular-nums;\n}\n.hw-messages {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 16px 20px;\n background: var(--hw-bg-subtle);\n display: flex;\n flex-direction: column;\n gap: 2px;\n overscroll-behavior: contain;\n min-width: 0;\n scrollbar-color: rgba(0, 0, 0, 0.2) transparent;\n scrollbar-width: thin;\n}\n.hw-messages::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\n.hw-messages::-webkit-scrollbar-track {\n background: transparent;\n}\n.hw-messages::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.16);\n background-clip: content-box;\n border: 3px solid transparent;\n border-radius: 999px;\n}\n.hw-messages::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.28);\n background-clip: content-box;\n}\n.hw-widget[data-theme=dark] .hw-messages {\n scrollbar-color: rgba(255, 255, 255, 0.26) transparent;\n}\n.hw-widget[data-theme=dark] .hw-messages::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.2);\n background-clip: content-box;\n}\n.hw-widget[data-theme=dark] .hw-messages::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.32);\n background-clip: content-box;\n}\n.hw-empty {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px;\n color: var(--hw-text-3);\n text-align: center;\n}\n.hw-empty-icon {\n width: 40px;\n height: 40px;\n margin-bottom: 12px;\n opacity: 0.3;\n}\n.hw-date-sep {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 0;\n}\n.hw-date-sep-line {\n flex: 1;\n height: 1px;\n background: var(--hw-border-md);\n}\n.hw-date-sep-text {\n font-size: 11px;\n color: var(--hw-text-3);\n font-weight: 500;\n white-space: nowrap;\n}\n.hw-msg {\n display: flex;\n padding: 4px 0;\n max-width: 75%;\n min-width: 0;\n animation: hw-msg-appear 0.25s ease-out;\n}\n@keyframes hw-msg-appear {\n from {\n opacity: 0;\n transform: translateY(6px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.hw-msg--visitor {\n align-self: flex-end;\n}\n.hw-msg--team,\n.hw-msg--ai {\n align-self: flex-start;\n}\n.hw-msg--ai {\n width: 100%;\n max-width: 100%;\n}\n.hw-msg-body {\n display: flex;\n flex-direction: column;\n min-width: 0;\n max-width: 100%;\n}\n.hw-msg-bubble {\n padding: 10px 14px;\n border-radius: 18px;\n font-size: 14px;\n line-height: 1.45;\n white-space: pre-wrap;\n word-break: break-word;\n overflow-wrap: anywhere;\n max-width: 100%;\n}\n.hw-msg--visitor .hw-msg-bubble {\n background: var(--hw-primary);\n color: white;\n border-bottom-right-radius: 4px;\n}\n.hw-msg--team .hw-msg-bubble {\n background: var(--hw-visitor-bubble-bg);\n color: var(--hw-visitor-bubble-text);\n border-bottom-left-radius: 4px;\n}\n.hw-msg--ai .hw-msg-bubble {\n background: var(--hw-visitor-bubble-bg);\n color: var(--hw-text);\n border-bottom-left-radius: 4px;\n white-space: normal;\n max-width: min(100%, 640px);\n}\n.hw-msg--ai .hw-msg-body {\n width: 100%;\n}\n.hw-msg--ai .hw-msg-bubble:has(.hw-code),\n.hw-msg--ai .hw-msg-bubble:has(pre) {\n width: 100%;\n}\n.hw-msg--ai .hw-code {\n width: 100%;\n box-sizing: border-box;\n}\n.hw-msg-meta {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: var(--hw-text-3);\n margin-top: 3px;\n padding: 0 4px;\n opacity: 1;\n font-variant-numeric: tabular-nums;\n min-height: 20px;\n}\n.hw-msg-time {\n opacity: 0.72;\n}\n.hw-msg-hover-meta {\n max-width: 0;\n opacity: 0;\n overflow: hidden;\n white-space: nowrap;\n transition: max-width 180ms ease, opacity 140ms ease;\n}\n.hw-msg:hover .hw-msg-hover-meta,\n.hw-msg:focus-within .hw-msg-hover-meta {\n max-width: 180px;\n opacity: 1;\n}\n.hw-msg--visitor .hw-msg-meta {\n text-align: right;\n}\n.hw-msg--team .hw-msg-body,\n.hw-msg--ai .hw-msg-body {\n align-items: flex-start;\n}\n.hw-msg--visitor .hw-msg-body {\n align-items: flex-end;\n}\n.hw-msg-sender {\n font-size: 11px;\n font-weight: 500;\n color: var(--hw-text-3);\n margin-bottom: 3px;\n padding: 0 4px;\n}\n.hw-typing {\n display: flex;\n flex-direction: column;\n gap: 3px;\n padding: 8px 0;\n width: fit-content;\n animation: hw-msg-appear 0.25s ease-out;\n}\n.hw-typing-label {\n font-size: 11px;\n font-weight: 500;\n color: var(--hw-text-3);\n padding: 0 4px;\n}\n.hw-typing-dots {\n display: flex;\n gap: 3px;\n padding: 10px 14px;\n width: fit-content;\n background: var(--hw-visitor-bubble-bg);\n border-radius: var(--hw-radius);\n border-bottom-left-radius: 4px;\n}\n.hw-typing-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--hw-text-3);\n animation: hw-typing-bounce 1.4s infinite;\n}\n.hw-typing-dot:nth-child(2) {\n animation-delay: 0.2s;\n}\n.hw-typing-dot:nth-child(3) {\n animation-delay: 0.4s;\n}\n@keyframes hw-typing-bounce {\n 0%, 60%, 100% {\n transform: translateY(0);\n }\n 30% {\n transform: translateY(-4px);\n }\n}\n.hw-loading {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.hw-loading-dots {\n display: flex;\n gap: 4px;\n}\n.hw-loading-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--hw-text-4);\n animation: hw-loading-pulse 1.4s infinite;\n}\n.hw-loading-dot:nth-child(2) {\n animation-delay: 0.2s;\n}\n.hw-loading-dot:nth-child(3) {\n animation-delay: 0.4s;\n}\n@keyframes hw-loading-pulse {\n 0%, 60%, 100% {\n opacity: 0.3;\n transform: scale(0.8);\n }\n 30% {\n opacity: 1;\n transform: scale(1);\n }\n}\n@keyframes hw-skeleton-shimmer {\n 0% {\n background-position: -200px 0;\n }\n 100% {\n background-position: calc(200px + 100%) 0;\n }\n}\n.hw-skeleton {\n background:\n linear-gradient(\n 90deg,\n var(--hw-bg-subtle) 25%,\n rgba(0, 0, 0, 0.04) 50%,\n var(--hw-bg-subtle) 75%);\n background-size: 200px 100%;\n animation: hw-skeleton-shimmer 1.5s ease-in-out infinite;\n border-radius: 6px;\n}\n.hw-skeleton-messages {\n flex: 1;\n display: flex;\n flex-direction: column;\n padding: 16px;\n gap: 16px;\n}\n.hw-skeleton-msg {\n display: flex;\n gap: 10px;\n align-items: flex-start;\n}\n.hw-skeleton-msg--right {\n flex-direction: row-reverse;\n}\n.hw-skeleton-avatar {\n width: 28px;\n height: 28px;\n border-radius: 8px;\n flex-shrink: 0;\n}\n.hw-skeleton-bubble {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.hw-skeleton-line {\n height: 12px;\n border-radius: 6px;\n}\n.hw-skeleton-convs {\n display: flex;\n flex-direction: column;\n padding: 8px 0;\n}\n.hw-skeleton-conv {\n display: flex;\n gap: 10px;\n align-items: center;\n padding: 10px 16px;\n}\n.hw-skeleton-conv-avatar {\n width: 36px;\n height: 36px;\n border-radius: 8px;\n flex-shrink: 0;\n}\n.hw-skeleton-conv-lines {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.hw-skeleton-content {\n display: flex;\n flex-direction: column;\n padding: 12px 16px;\n gap: 12px;\n}\n.hw-skeleton-content-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px;\n border-radius: 10px;\n background: var(--hw-bg);\n}\n.hw-email-card {\n margin: 0 12px;\n padding: 14px 16px 10px;\n border: 1px solid var(--hw-border, rgba(0,0,0,0.08));\n border-radius: 14px;\n background: var(--hw-surface, #fff);\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06), 0 4px 12px rgba(0, 0, 0, 0.03);\n animation: hw-email-slide-in 0.25s ease-out;\n}\n@keyframes hw-email-slide-in {\n from {\n opacity: 0;\n transform: translateY(8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.hw-email-card-header {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n margin-bottom: 12px;\n}\n.hw-email-card-icon {\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n border-radius: 8px;\n background: var(--hw-brand, #0a0a0a);\n display: flex;\n align-items: center;\n justify-content: center;\n color: #fff;\n}\n.hw-email-card-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--hw-text, #1a1a1a);\n line-height: 1.3;\n margin: 0 0 2px;\n}\n.hw-email-card-subtitle {\n font-size: 12px;\n color: var(--hw-text-muted, #888);\n line-height: 1.4;\n margin: 0;\n}\n.hw-email-card-input {\n width: 100%;\n padding: 9px 12px;\n border-radius: 10px;\n border: 1px solid var(--hw-border, rgba(0,0,0,0.1));\n background: var(--hw-bg, #fafafa);\n color: var(--hw-text, #1a1a1a);\n font-size: 13px;\n outline: none;\n margin-bottom: 8px;\n box-sizing: border-box;\n transition: border-color 0.15s;\n}\n.hw-email-card-input:focus {\n border-color: var(--hw-brand, #0a0a0a);\n box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.06);\n}\n.hw-email-card-input--error {\n border-color: #ef4444;\n}\n.hw-email-card-submit {\n width: 100%;\n padding: 9px;\n border-radius: 10px;\n border: none;\n background: var(--hw-brand, #0a0a0a);\n color: #fff;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity 0.15s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n}\n.hw-email-card-submit:hover:not(:disabled) {\n opacity: 0.88;\n}\n.hw-email-card-submit:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.hw-email-card--success {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 10px 16px;\n font-size: 13px;\n color: var(--hw-text-muted, #888);\n animation: hw-email-slide-in 0.2s ease-out;\n}\n.hw-email-card--success svg {\n flex-shrink: 0;\n}\n.hw-composer {\n display: flex;\n flex-direction: column;\n padding: 12px 16px;\n background: transparent;\n flex-shrink: 0;\n}\n.hw-composer--compact {\n padding: 8px 12px;\n}\n.hw-composer-box {\n display: flex;\n flex-direction: column;\n border: 2px solid var(--hw-border-md);\n border-radius: 16px;\n overflow: hidden;\n transition: border-color 0.2s;\n background: var(--hw-bg);\n}\n.hw-composer-box:focus-within {\n border-color: var(--hw-focus-border);\n box-shadow: 0 0 0 3px var(--hw-focus-ring);\n}\n.hw-composer-input {\n flex: 1;\n resize: none;\n border: none;\n padding: 12px 16px 4px;\n font-size: 14px;\n font-family: inherit;\n line-height: 1.4;\n outline: none;\n min-height: 40px;\n max-height: 120px;\n background: transparent;\n color: var(--hw-text);\n}\n.hw-composer-input:focus {\n outline: none;\n}\n.hw-composer-input:focus-visible {\n outline: none;\n}\n.hw-composer-input::placeholder {\n color: var(--hw-text-4);\n}\n.hw-composer-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 10px 10px;\n}\n.hw-composer-toolbar-left {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.hw-composer-send {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition:\n background-color 140ms cubic-bezier(0.23, 1, 0.32, 1),\n color 140ms cubic-bezier(0.23, 1, 0.32, 1),\n transform 140ms cubic-bezier(0.23, 1, 0.32, 1);\n}\n.hw-composer-send:active:not(:disabled) {\n transform: scale(0.9);\n}\n.hw-composer-send--active {\n background: var(--hw-primary);\n color: white;\n}\n.hw-composer-send--inactive {\n background: var(--hw-border);\n color: var(--hw-text-4);\n cursor: default;\n}\n.hw-composer-send svg {\n width: 14px;\n height: 14px;\n}\n.hw-composer-charcount {\n font-size: 11px;\n color: var(--hw-text-3);\n font-variant-numeric: tabular-nums;\n opacity: 1;\n transform: translateY(0);\n transition:\n color 180ms cubic-bezier(0.23, 1, 0.32, 1),\n opacity 180ms cubic-bezier(0.23, 1, 0.32, 1),\n transform 180ms cubic-bezier(0.23, 1, 0.32, 1);\n}\n@starting-style {\n .hw-composer-charcount {\n opacity: 0;\n transform: translateY(3px);\n }\n}\n.hw-composer-charcount--over {\n color: #ef4444;\n font-weight: 600;\n}\n@media (prefers-reduced-motion: reduce) {\n .hw-composer-charcount {\n transform: none;\n transition: color 160ms ease, opacity 160ms ease;\n }\n @starting-style {\n .hw-composer-charcount {\n transform: none;\n }\n }\n}\n.hw-composer-previews {\n display: flex;\n gap: 6px;\n padding: 8px 10px 0;\n overflow-x: auto;\n scrollbar-width: none;\n}\n.hw-composer-previews::-webkit-scrollbar {\n display: none;\n}\n.hw-composer-preview {\n position: relative;\n width: 48px;\n height: 48px;\n border-radius: 8px;\n overflow: hidden;\n flex-shrink: 0;\n background: var(--hw-border);\n cursor: pointer;\n}\n.hw-composer-preview--error {\n outline: 2px solid #ef4444;\n outline-offset: -2px;\n}\n.hw-composer-preview-img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.hw-composer-preview-file {\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--hw-bg-subtle);\n}\n.hw-composer-preview-ext {\n font-size: 10px;\n font-weight: 700;\n color: var(--hw-text-3);\n text-transform: uppercase;\n}\n.hw-composer-preview-loader {\n position: absolute;\n inset: 0;\n background: rgba(0, 0, 0, 0.35);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.hw-composer-preview-loader::after {\n content: "";\n width: 16px;\n height: 16px;\n border: 2px solid rgba(255, 255, 255, 0.3);\n border-top-color: white;\n border-radius: 50%;\n animation: hw-spin 0.6s linear infinite;\n}\n@keyframes hw-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.hw-composer-preview-badge {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: #ef4444;\n color: white;\n font-size: 10px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.hw-composer-preview-remove {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: none;\n background: rgba(0, 0, 0, 0.55);\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n transition: opacity 0.15s;\n}\n.hw-composer-preview-remove svg {\n width: 10px;\n height: 10px;\n}\n.hw-composer-preview:hover .hw-composer-preview-remove {\n opacity: 1;\n}\n.hw-composer-attach {\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n color: var(--hw-text-3);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n opacity: 0.7;\n transition: opacity 0.15s;\n}\n.hw-composer-attach:hover {\n opacity: 1;\n}\n.hw-composer-attach svg {\n width: 16px;\n height: 16px;\n}\n.hw-msg-images {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin-bottom: 4px;\n}\n.hw-msg-image-link {\n display: block;\n border-radius: 14px;\n overflow: hidden;\n line-height: 0;\n}\n.hw-msg-image {\n max-width: 140px;\n max-height: 80px;\n object-fit: cover;\n border-radius: 8px;\n outline: 1px solid rgba(0, 0, 0, 0.08);\n outline-offset: -1px;\n}\n.hw-msg-files {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin-top: 4px;\n}\n.hw-msg-file {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 10px;\n background: var(--hw-bg-subtle);\n text-decoration: none;\n color: var(--hw-text);\n transition: background 0.15s;\n}\n.hw-msg-file:hover {\n background: var(--hw-border);\n}\n.hw-msg-file-icon {\n flex-shrink: 0;\n width: 20px;\n height: 20px;\n color: var(--hw-text-3);\n}\n.hw-msg-file-icon svg {\n width: 100%;\n height: 100%;\n}\n.hw-msg-file-info {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.hw-msg-file-name {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.hw-msg-file-size {\n font-size: 11px;\n color: var(--hw-text-3);\n}\n.hw-msg-image-link {\n cursor: pointer;\n border: none;\n padding: 0;\n background: none;\n display: block;\n line-height: 0;\n}\n.hw-hover-preview {\n position: fixed;\n z-index: 99998;\n padding: 6px;\n border-radius: 14px;\n background: white;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.06);\n cursor: pointer;\n animation: hw-hover-in 0.15s ease-out;\n}\n@media (prefers-color-scheme: dark) {\n .hw-hover-preview {\n background: #1c1c1e;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.08);\n }\n}\n@keyframes hw-hover-in {\n from {\n opacity: 0;\n transform: scale(0.96) translateY(4px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n.hw-hover-preview-img {\n width: 100%;\n max-height: 200px;\n object-fit: contain;\n border-radius: 10px;\n display: block;\n outline: 1px solid rgba(0, 0, 0, 0.08);\n outline-offset: -1px;\n}\n.hw-hover-preview--doc {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n}\n.hw-hover-preview-doc-icon {\n width: 28px;\n height: 28px;\n flex-shrink: 0;\n}\n.hw-hover-preview-doc-icon svg {\n width: 100%;\n height: 100%;\n}\n.hw-hover-preview-doc-info {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.hw-hover-preview-doc-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--hw-text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.hw-hover-preview-doc-hint {\n font-size: 11px;\n color: var(--hw-text-3);\n}\n.hw-event {\n display: flex;\n justify-content: center;\n padding: 8px 16px;\n}\n.hw-event-text {\n font-size: 12px;\n color: var(--hw-text-3);\n text-align: center;\n}\n.hw-event--card {\n justify-content: flex-start;\n align-items: center;\n gap: 10px;\n background: var(--hw-bg-subtle);\n padding: 10px 14px;\n border-radius: 12px;\n margin: 4px 16px;\n}\n.hw-event-avatar {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: #e0e0e0;\n color: #555;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 600;\n flex-shrink: 0;\n overflow: hidden;\n}\n.hw-event-avatar-img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.hw-event-body {\n font-size: 13px;\n line-height: 1.3;\n}\n.hw-event-name {\n font-weight: 600;\n color: var(--hw-text);\n}\n.hw-event-action {\n color: var(--hw-text-2);\n}\n.hw-resolved-banner {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 12px 16px;\n border-top: 1px solid var(--hw-border);\n background: var(--hw-bg-subtle);\n color: var(--hw-text-2);\n font-size: 13px;\n flex-shrink: 0;\n}\n.hw-new {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: var(--hw-bg-subtle);\n}\n.hw-new-body {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px 24px;\n text-align: center;\n}\n.hw-new-welcome {\n flex: 1;\n padding: 16px 20px;\n overflow-y: auto;\n}\n.hw-new-heading {\n font-size: 17px;\n font-weight: 600;\n color: var(--hw-text);\n margin-bottom: 6px;\n}\n.hw-new-desc {\n font-size: 13px;\n color: var(--hw-text-2);\n margin-bottom: 24px;\n}\n.hw-powered {\n text-align: center;\n padding: 8px;\n font-size: 11px;\n color: var(--hw-text-4);\n flex-shrink: 0;\n}\n.hw-powered a {\n color: var(--hw-text-2);\n text-decoration: none;\n font-weight: 500;\n}\n.hw-powered a:hover {\n color: var(--hw-text);\n}\n@media (max-width: 479px) {\n .hw-widget {\n bottom: 16px;\n right: 16px;\n left: auto;\n }\n .hw-window {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: var(--hw-visible-height, 100%);\n border-radius: 0;\n animation: hw-mob-up 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n }\n .hw-window--closing {\n animation: hw-mob-down 0.2s ease forwards;\n }\n @keyframes hw-mob-up {\n from {\n opacity: 0;\n transform: translateY(100%);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n @keyframes hw-mob-down {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(100%);\n }\n }\n .hw-hero {\n padding-top: calc(20px + env(safe-area-inset-top, 0px));\n }\n .hw-header {\n padding-top: env(safe-area-inset-top, 0px);\n }\n .hw-tabs {\n padding-bottom: env(safe-area-inset-bottom, 0px);\n }\n .hw-composer {\n padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));\n }\n .hw-powered {\n padding-bottom: calc(5px + env(safe-area-inset-bottom, 0px));\n }\n .hw-header-close,\n .hw-header-back,\n .hw-header-action {\n width: 34px;\n height: 34px;\n }\n .hw-composer-send {\n width: 40px;\n height: 40px;\n }\n .hw-window ~ .hw-bubble {\n display: none;\n }\n .hw-messages {\n padding: 12px 14px;\n }\n .hw-msg {\n max-width: 82%;\n }\n .hw-msg--ai {\n max-width: 100%;\n }\n}\n.hw-preview {\n position: absolute;\n bottom: calc(100% + 12px);\n right: 0;\n width: 300px;\n max-width: calc(100vw - 40px);\n background: var(--hw-bg);\n border: 1px solid var(--hw-border);\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);\n animation: hw-preview-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n overflow: hidden;\n cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n}\n.hw-preview:hover {\n transform: translateY(-2px);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.08);\n}\n.hw-preview--closing {\n animation: hw-preview-out 0.2s ease forwards;\n}\n@keyframes hw-preview-in {\n from {\n opacity: 0;\n transform: translateY(8px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n@keyframes hw-preview-out {\n from {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n to {\n opacity: 0;\n transform: translateY(8px) scale(0.95);\n }\n}\n.hw-preview-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 14px 0;\n}\n.hw-preview-avatar {\n width: 28px;\n height: 28px;\n border-radius: 50%;\n background:\n linear-gradient(\n 135deg,\n var(--hw-primary),\n color-mix(in srgb, var(--hw-primary) 50%, black));\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n flex-shrink: 0;\n overflow: hidden;\n}\n.hw-preview-avatar svg {\n width: 16px;\n height: 16px;\n}\n.hw-preview-name {\n font-size: 13px;\n font-weight: 600;\n color: var(--hw-text);\n flex: 1;\n}\n.hw-preview-close {\n width: 24px;\n height: 24px;\n border: none;\n background: transparent;\n color: var(--hw-text-3);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n transition: background 0.15s, color 0.15s;\n flex-shrink: 0;\n}\n.hw-preview-close:hover {\n background: var(--hw-bg-subtle);\n color: var(--hw-text-2);\n}\n.hw-preview-close:active {\n transform: scale(0.90);\n transition:\n transform 0.14s cubic-bezier(0.23, 1, 0.32, 1),\n background 0.15s,\n color 0.15s;\n}\n.hw-preview-close svg {\n width: 12px;\n height: 12px;\n}\n.hw-preview-body {\n padding: 8px 14px 14px;\n font-size: 14px;\n line-height: 1.45;\n color: var(--hw-text-2);\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.hw-content-search {\n padding: 10px 16px;\n}\n.hw-content-search-box {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--hw-bg);\n border: 1px solid var(--hw-border-md);\n border-radius: 10px;\n transition: border-color 0.15s, box-shadow 0.15s;\n}\n.hw-content-search-box:focus-within {\n border-color: var(--hw-focus-border);\n box-shadow: 0 0 0 3px var(--hw-focus-ring);\n}\n.hw-content-search-input {\n flex: 1;\n border: none !important;\n outline: none !important;\n box-shadow: none !important;\n background: none;\n font-size: 13px;\n color: var(--hw-text-1);\n font-family: inherit;\n line-height: 1;\n -webkit-appearance: none;\n}\n.hw-content-search-input:focus,\n.hw-content-search-input:focus-visible {\n outline: none !important;\n box-shadow: none !important;\n border: none !important;\n}\n.hw-content-search-input::placeholder {\n color: var(--hw-text-3);\n}\n.hw-content-search-icon {\n width: 15px;\n height: 15px;\n color: var(--hw-text-3);\n flex-shrink: 0;\n}\n.hw-content-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n.hw-content-entries {\n flex: 1;\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n.hw-content-entry {\n display: block;\n width: 100%;\n padding: 14px 16px;\n border: none;\n border-bottom: 1px solid var(--hw-border);\n background: none;\n cursor: pointer;\n text-align: left;\n transition: background-color 0.15s ease;\n -webkit-tap-highlight-color: transparent;\n}\n.hw-content-entry:hover {\n background: var(--hw-bg-hover);\n}\n.hw-content-entry:active {\n background: var(--hw-border);\n}\n.hw-content-entry:last-child {\n border-bottom: none;\n}\n.hw-content-entry-main {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n.hw-content-entry-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n.hw-content-entry-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--hw-text-1);\n line-height: 1.3;\n}\n.hw-content-entry-desc {\n font-size: 13px;\n color: var(--hw-text-2);\n line-height: 1.4;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.hw-content-entry-meta {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 2px;\n}\n.hw-content-entry-badge {\n font-size: 11px;\n font-weight: 500;\n color: var(--hw-text-3);\n background: var(--hw-bg-hover);\n padding: 1px 6px;\n border-radius: 4px;\n}\n.hw-content-entry-date {\n font-size: 11px;\n color: var(--hw-text-3);\n}\n.hw-content-entry-chevron {\n width: 16px;\n height: 16px;\n color: var(--hw-text-3);\n flex-shrink: 0;\n opacity: 0.5;\n}\n.hw-content-detail {\n padding: 16px;\n overflow-y: auto;\n overscroll-behavior: contain;\n height: 100%;\n}\n.hw-content-detail-header {\n margin-bottom: 16px;\n}\n.hw-content-detail-title {\n font-size: 17px;\n font-weight: 700;\n color: var(--hw-text-1);\n margin: 0 0 6px;\n line-height: 1.3;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.hw-content-detail-meta {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n.hw-content-detail-date {\n font-size: 12px;\n color: var(--hw-text-3);\n}\n.hw-content-detail-body {\n font-size: 14px;\n line-height: 1.6;\n color: var(--hw-text-1);\n}\n.hw-markdown h1 {\n font-size: 17px;\n font-weight: 700;\n margin: 20px 0 8px;\n}\n.hw-markdown h2 {\n font-size: 15px;\n font-weight: 600;\n margin: 16px 0 6px;\n}\n.hw-markdown h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 12px 0 4px;\n}\n.hw-markdown p {\n margin: 0 0 12px;\n}\n.hw-markdown ul {\n margin: 0 0 12px;\n padding-left: 20px;\n}\n.hw-markdown li {\n margin: 4px 0;\n}\n.hw-markdown code {\n font-family:\n ui-monospace,\n "SF Mono",\n monospace;\n font-size: 12px;\n background: var(--hw-bg-hover);\n padding: 1px 5px;\n border-radius: 4px;\n}\n.hw-code {\n margin: 10px 0;\n border-radius: 10px;\n overflow: hidden;\n border: 1px solid var(--hw-border, rgba(0, 0, 0, 0.08));\n background: var(--hw-bg-hover, #f5f5f4);\n font-family:\n ui-monospace,\n "SF Mono",\n "Menlo",\n monospace;\n}\n.hw-code-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n padding: 7px 8px 7px 12px;\n font-size: 11px;\n color: var(--hw-text-2, #6b7280);\n background: rgba(0, 0, 0, 0.03);\n border-bottom: 1px solid var(--hw-border, rgba(0, 0, 0, 0.06));\n}\n.hw-code-lang {\n text-transform: lowercase;\n letter-spacing: 0.02em;\n font-weight: 500;\n}\n.hw-code-actions {\n display: inline-flex;\n align-items: center;\n gap: 1px;\n}\n.hw-code-action {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n padding: 0;\n font-family: inherit;\n color: var(--hw-text-2, #6b7280);\n background: transparent;\n border: 1px solid transparent;\n border-radius: 6px;\n cursor: pointer;\n opacity: 0.62;\n transition:\n background 120ms ease,\n color 120ms ease,\n opacity 120ms ease,\n scale 120ms ease;\n}\n.hw-code-action:hover {\n color: var(--hw-text, #111);\n background: rgba(0, 0, 0, 0.06);\n opacity: 1;\n}\n.hw-code-action:active {\n scale: 0.96;\n}\n.hw-code-action svg {\n width: 13px;\n height: 13px;\n}\n.hw-code-copy-icon,\n.hw-code-check-icon {\n position: absolute;\n inset: 50% auto auto 50%;\n transition:\n opacity 180ms cubic-bezier(0.2, 0, 0, 1),\n scale 180ms cubic-bezier(0.2, 0, 0, 1),\n filter 180ms cubic-bezier(0.2, 0, 0, 1);\n translate: -50% -50%;\n}\n.hw-code-check-icon {\n filter: blur(4px);\n opacity: 0;\n scale: 0.25;\n}\n.hw-code-copy--copied .hw-code-copy-icon {\n filter: blur(4px);\n opacity: 0;\n scale: 0.25;\n}\n.hw-code-copy--copied .hw-code-check-icon {\n filter: blur(0);\n opacity: 1;\n scale: 1;\n}\n.hw-code-copy-label {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n}\n.hw-code-copy--copied {\n color: #16a34a;\n}\n.hw-code-copy--failed {\n color: #dc2626;\n}\n.hw-code pre {\n margin: 0;\n padding: 10px 12px;\n background: transparent;\n border-radius: 0;\n overflow-x: auto;\n max-width: 100%;\n max-height: 320px;\n scrollbar-color: rgba(0, 0, 0, 0.22) transparent;\n scrollbar-width: thin;\n}\n.hw-code pre::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\n.hw-code pre::-webkit-scrollbar-track {\n background: transparent;\n}\n.hw-code pre::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.18);\n background-clip: content-box;\n border: 3px solid transparent;\n border-radius: 999px;\n}\n.hw-code pre::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.28);\n background-clip: content-box;\n}\n.hw-code pre code {\n display: block;\n background: transparent;\n padding: 0;\n font-size: 12px;\n line-height: 1.55;\n white-space: pre;\n color: var(--hw-text, #111);\n}\n@media (prefers-color-scheme: dark) {\n .hw-code {\n background: rgba(255, 255, 255, 0.04);\n border-color: rgba(255, 255, 255, 0.08);\n }\n .hw-code-header {\n background: rgba(255, 255, 255, 0.03);\n border-bottom-color: rgba(255, 255, 255, 0.06);\n }\n .hw-code-action:hover,\n .hw-code-action:focus-visible {\n background: rgba(255, 255, 255, 0.08);\n }\n .hw-code pre {\n scrollbar-color: rgba(255, 255, 255, 0.26) transparent;\n }\n .hw-code pre::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.22);\n background-clip: content-box;\n }\n .hw-code pre::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.32);\n background-clip: content-box;\n }\n}\n.hw-markdown pre {\n margin: 8px 0;\n padding: 10px 12px;\n background: var(--hw-bg-hover);\n border-radius: 8px;\n overflow-x: auto;\n max-width: 100%;\n}\n.hw-markdown pre code {\n display: block;\n background: transparent;\n padding: 0;\n border-radius: 0;\n font-size: 12px;\n line-height: 1.5;\n white-space: pre;\n word-break: normal;\n color: inherit;\n}\n.hw-msg-bubble pre {\n margin: 6px 0;\n padding: 8px 10px;\n background: rgba(0, 0, 0, 0.06);\n border-radius: 6px;\n overflow-x: auto;\n max-width: 100%;\n}\n.hw-msg-bubble pre code {\n background: transparent;\n padding: 0;\n font-size: 12px;\n line-height: 1.5;\n white-space: pre;\n}\n.hw-msg-bubble .hw-code pre {\n margin: 0;\n padding: 10px 12px;\n background: transparent;\n border-radius: 0;\n}\n.hw-msg-bubble .hw-code pre code {\n background: transparent;\n padding: 0;\n font-size: 12px;\n line-height: 1.55;\n}\n.hw-msg--team .hw-msg-bubble pre,\n.hw-msg--visitor .hw-msg-bubble pre {\n background: rgba(255, 255, 255, 0.12);\n}\n.hw-markdown blockquote {\n margin: 0 0 12px;\n padding: 8px 12px;\n border-left: 3px solid var(--hw-border);\n color: var(--hw-text-2);\n font-style: italic;\n}\n.hw-markdown a {\n color: var(--hw-primary);\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.hw-markdown img {\n max-width: 100%;\n border-radius: 8px;\n margin: 8px 0;\n outline: 1px solid rgba(0, 0, 0, 0.08);\n outline-offset: -1px;\n}\n.hw-markdown hr {\n border: none;\n border-top: 1px solid var(--hw-border);\n margin: 16px 0;\n}\n.hw-content-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n text-align: center;\n}\n.hw-content-empty-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--hw-text-1);\n margin-bottom: 4px;\n}\n.hw-content-empty-desc {\n font-size: 12px;\n color: var(--hw-text-3);\n}\n.hw-content-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n}\n.hw-content-load-more {\n display: block;\n width: 100%;\n padding: 10px;\n border: none;\n background: none;\n color: var(--hw-primary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n text-align: center;\n}\n.hw-content-load-more:hover {\n background: var(--hw-bg-hover);\n}\n.hw-content-load-more:disabled {\n opacity: 0.5;\n cursor: default;\n}\n@media (hover: none) {\n .hw-composer-preview-remove {\n opacity: 0.7;\n }\n .hw-msg-meta {\n opacity: 1;\n }\n .hw-msg-copy {\n opacity: 1;\n }\n}\n.hw-composer--dragging .hw-composer-box {\n border-color: var(--hw-primary);\n background: color-mix(in srgb, var(--hw-primary) 4%, transparent);\n}\n.hw-composer-drop-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--hw-bg) 90%, transparent);\n border: 2px dashed var(--hw-primary);\n border-radius: 12px;\n z-index: 10;\n pointer-events: none;\n animation: hw-drop-pulse 1.5s ease-in-out infinite;\n}\n.hw-composer-drop-text {\n font-size: 13px;\n font-weight: 500;\n color: var(--hw-primary);\n}\n@keyframes hw-drop-pulse {\n 0%, 100% {\n opacity: 0.8;\n }\n 50% {\n opacity: 1;\n }\n}\n.hw-msg-copy {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n margin-left: 4px;\n border: none;\n border-radius: 4px;\n background: none;\n color: var(--hw-text-4);\n cursor: pointer;\n vertical-align: middle;\n opacity: 0;\n transition:\n color 0.15s,\n background 0.15s,\n opacity 0.15s;\n padding: 0;\n flex-shrink: 0;\n}\n.hw-msg:hover .hw-msg-copy,\n.hw-msg:focus-within .hw-msg-copy {\n opacity: 1;\n}\n.hw-msg-copy:hover {\n background: var(--hw-bg-hover);\n color: var(--hw-text-2);\n}\n.hw-msg-copy svg {\n width: 12px;\n height: 12px;\n}\n.hw-msg-copy--done {\n color: #22c55e;\n}\n.hw-disconnect {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 6px 12px;\n background: #fef3c7;\n color: #92400e;\n font-size: 12px;\n font-weight: 500;\n flex-shrink: 0;\n animation: hw-msg-appear 0.25s ease-out;\n}\n.hw-disconnect-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: #f59e0b;\n animation: hw-loading-pulse 1.4s infinite;\n}\n.hw-error-state {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px 24px;\n text-align: center;\n gap: 12px;\n}\n.hw-error-icon {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: #fef2f2;\n color: #ef4444;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.hw-error-icon svg {\n width: 24px;\n height: 24px;\n}\n.hw-error-title {\n font-size: 15px;\n font-weight: 600;\n color: var(--hw-text);\n}\n.hw-error-desc {\n font-size: 13px;\n color: var(--hw-text-2);\n}\n.hw-error-btn {\n padding: 8px 20px;\n border: 1px solid var(--hw-border-md);\n border-radius: 8px;\n background: var(--hw-bg);\n color: var(--hw-text);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s;\n}\n.hw-error-btn:hover {\n background: var(--hw-bg-hover);\n}\n.hw-send-error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: #fef2f2;\n color: #dc2626;\n font-size: 12px;\n font-weight: 500;\n flex-shrink: 0;\n animation: hw-msg-appear 0.25s ease-out;\n}\n.hw-send-error-retry {\n margin-left: auto;\n padding: 2px 8px;\n border: 1px solid #fca5a5;\n border-radius: 4px;\n background: none;\n color: #dc2626;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n}\n.hw-send-error-retry:hover {\n background: #fee2e2;\n}\n.hw-resolved {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid var(--hw-border);\n flex-shrink: 0;\n}\n.hw-resolved-text {\n font-size: 13px;\n color: var(--hw-text-3);\n font-weight: 500;\n}\n.hw-resolved-actions {\n display: flex;\n gap: 8px;\n}\n.hw-resolved-reopen {\n padding: 6px 16px;\n border: 1px solid var(--hw-border-md);\n border-radius: 8px;\n background: var(--hw-bg);\n color: var(--hw-text);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s;\n}\n.hw-resolved-reopen:hover {\n background: var(--hw-bg-hover);\n}\n.hw-csat {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n}\n.hw-csat-label {\n font-size: 12px;\n color: var(--hw-text-3);\n}\n.hw-csat-buttons {\n display: flex;\n gap: 8px;\n}\n.hw-csat-btn {\n width: 36px;\n height: 36px;\n border: 1px solid var(--hw-border-md);\n border-radius: 8px;\n background: var(--hw-bg);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n transition:\n transform 0.15s,\n border-color 0.15s,\n background 0.15s;\n}\n.hw-csat-btn:hover {\n transform: scale(1.1);\n border-color: var(--hw-text-3);\n}\n.hw-csat-btn--selected {\n border-color: var(--hw-primary);\n background: var(--hw-bg-hover);\n transform: scale(1.15);\n}\n.hw-csat-thanks {\n font-size: 12px;\n color: #22c55e;\n font-weight: 500;\n animation: hw-msg-appear 0.25s ease-out;\n}\n.hw-load-more-trigger {\n display: flex;\n justify-content: center;\n min-height: 1px;\n}\n.hw-load-more-trigger:has(.hw-load-more-spinner) {\n padding: 8px 0;\n}\n.hw-load-more-spinner {\n display: flex;\n gap: 3px;\n}\n.hw-load-more-spinner > div {\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: var(--hw-text-4);\n animation: hw-loading-pulse 1.4s infinite;\n}\n.hw-load-more-spinner > div:nth-child(2) {\n animation-delay: 0.2s;\n}\n.hw-load-more-spinner > div:nth-child(3) {\n animation-delay: 0.4s;\n}\n.hw-drag-handle {\n display: none;\n}\n@media (max-width: 479px) {\n .hw-drag-handle {\n display: flex;\n justify-content: center;\n padding: 8px 0 4px;\n flex-shrink: 0;\n }\n .hw-drag-handle-pill {\n width: 32px;\n height: 4px;\n border-radius: 2px;\n background: var(--hw-text-4);\n }\n}\n.hw-msg-bubble p {\n margin: 0 0 8px;\n}\n.hw-msg-bubble p:last-child {\n margin-bottom: 0;\n}\n.hw-msg-bubble strong {\n font-weight: 600;\n}\n.hw-msg-bubble em {\n font-style: italic;\n}\n.hw-msg-bubble a {\n color: var(--hw-primary);\n text-decoration: underline;\n text-underline-offset: 2px;\n word-break: break-all;\n}\n.hw-msg-bubble a:hover {\n opacity: 0.8;\n}\n.hw-msg--visitor .hw-msg-bubble a {\n color: rgba(255, 255, 255, 0.9);\n}\n.hw-msg--visitor .hw-msg-bubble a:hover {\n color: white;\n}\n.hw-msg-bubble ul,\n.hw-msg-bubble ol {\n margin: 4px 0 8px;\n padding-left: 20px;\n}\n.hw-msg-bubble li {\n margin: 2px 0;\n}\n.hw-msg-bubble code {\n padding: 1px 4px;\n border-radius: 3px;\n background: rgba(0, 0, 0, 0.06);\n font-size: 0.9em;\n font-family:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n monospace;\n}\n.hw-msg-bubble pre {\n margin: 4px 0 8px;\n padding: 8px 10px;\n border-radius: 6px;\n background: rgba(0, 0, 0, 0.06);\n overflow-x: auto;\n font-size: 0.85em;\n}\n.hw-msg-bubble pre code {\n padding: 0;\n background: none;\n}\n.hw-msg-bubble blockquote {\n margin: 4px 0 8px;\n padding: 4px 0 4px 12px;\n border-left: 3px solid var(--hw-border-md);\n color: var(--hw-text-2);\n}\n.hw-widget[data-theme=dark] {\n --hw-bg: #1c1c1e;\n --hw-bg-subtle: #161618;\n --hw-bg-hover: #2c2c2e;\n --hw-border: rgba(255, 255, 255, 0.08);\n --hw-border-md: rgba(255, 255, 255, 0.14);\n --hw-text: #f5f5f5;\n --hw-text-1: #f5f5f5;\n --hw-text-2: #a1a1aa;\n --hw-text-3: #71717a;\n --hw-text-4: #52525b;\n --hw-visitor-bubble-bg: #2c2c2e;\n --hw-visitor-bubble-text: #f5f5f5;\n --hw-focus-border: rgba(255, 255, 255, 0.28);\n --hw-focus-ring: rgba(255, 255, 255, 0.08);\n}\n@media (prefers-color-scheme: dark) {\n .hw-widget:not([data-theme=light]) .hw-messages {\n scrollbar-color: rgba(255, 255, 255, 0.26) transparent;\n }\n .hw-widget:not([data-theme=light]) .hw-messages::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.2);\n background-clip: content-box;\n }\n .hw-widget:not([data-theme=light]) .hw-messages::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.32);\n background-clip: content-box;\n }\n .hw-widget:not([data-theme=light]) {\n --hw-bg: #1c1c1e;\n --hw-bg-subtle: #161618;\n --hw-bg-hover: #2c2c2e;\n --hw-border: rgba(255, 255, 255, 0.08);\n --hw-border-md: rgba(255, 255, 255, 0.14);\n --hw-text: #f5f5f5;\n --hw-text-1: #f5f5f5;\n --hw-text-2: #a1a1aa;\n --hw-text-3: #71717a;\n --hw-text-4: #52525b;\n --hw-visitor-bubble-bg: #2c2c2e;\n --hw-visitor-bubble-text: #f5f5f5;\n --hw-focus-border: rgba(255, 255, 255, 0.28);\n --hw-focus-ring: rgba(255, 255, 255, 0.08);\n }\n}\n@media (prefers-color-scheme: dark) {\n .hw-widget:not([data-theme=light]) .hw-header {\n background: var(--hw-bg);\n border-color: var(--hw-border);\n }\n .hw-header-bot-icon {\n background: var(--hw-bg-hover);\n }\n .hw-header-name,\n .hw-header-title {\n color: var(--hw-text);\n }\n .hw-header-status {\n color: var(--hw-text-2);\n }\n .hw-header-close,\n .hw-header-back {\n color: var(--hw-text-2);\n }\n .hw-header-close:hover,\n .hw-header-back:hover {\n background: var(--hw-bg-hover);\n color: var(--hw-text);\n }\n .hw-content-entry {\n background: var(--hw-bg);\n border-color: var(--hw-border);\n }\n .hw-content-entry:hover {\n background: var(--hw-bg-hover);\n border-color: var(--hw-border-md);\n }\n .hw-content-empty,\n .hw-empty {\n color: var(--hw-text-3);\n }\n .hw-conv-card {\n border-color: var(--hw-border);\n }\n .hw-recent-row {\n border-color: var(--hw-border);\n }\n .hw-composer-drop-overlay {\n background: rgba(0, 0, 0, 0.6);\n color: var(--hw-text);\n }\n .hw-composer--dragging .hw-composer-box {\n border-color: var(--hw-focus-border);\n box-shadow: 0 0 0 3px var(--hw-focus-ring);\n }\n .hw-hero {\n background:\n linear-gradient(\n 160deg,\n color-mix(in srgb, var(--hw-primary) 40%, black) 0%,\n var(--hw-primary) 50%,\n color-mix(in srgb, var(--hw-primary) 25%, black) 100%);\n }\n .hw-sheet {\n background: var(--hw-bg);\n }\n .hw-card {\n background: var(--hw-bg-hover);\n border-color: var(--hw-border);\n }\n .hw-card:hover {\n background: #333;\n }\n .hw-window {\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.06);\n }\n .hw-bubble:focus-visible {\n outline-color: var(--hw-text-3);\n }\n .hw-msg--visitor .hw-msg-bubble {\n background: var(--hw-primary);\n color: white;\n }\n .hw-msg-bubble code {\n background: rgba(255, 255, 255, 0.08);\n }\n .hw-msg-bubble pre {\n background: rgba(255, 255, 255, 0.08);\n }\n .hw-composer-box {\n background: var(--hw-bg);\n border-color: var(--hw-border);\n }\n .hw-composer-input {\n color: var(--hw-text);\n }\n .hw-tabs {\n background: var(--hw-bg);\n border-color: var(--hw-border);\n }\n .hw-conv-card:hover,\n .hw-recent-row:hover {\n background: var(--hw-bg-hover);\n }\n .hw-disconnect {\n background: #422006;\n color: #fcd34d;\n }\n .hw-send-error {\n background: #450a0a;\n color: #fca5a5;\n }\n .hw-error-icon {\n background: #450a0a;\n color: #f87171;\n }\n .hw-msg-copy:hover {\n background: var(--hw-bg-hover);\n color: var(--hw-text-2);\n }\n .hw-resolved {\n border-color: var(--hw-border);\n }\n .hw-resolved-reopen,\n .hw-csat-btn {\n background: var(--hw-bg-hover);\n border-color: var(--hw-border-md);\n color: var(--hw-text);\n }\n .hw-hover-preview {\n background: #1c1c1e;\n border-color: var(--hw-border);\n }\n .hw-content-search-box {\n background: var(--hw-bg-hover);\n border-color: var(--hw-border-md);\n }\n .hw-preview {\n background: var(--hw-bg);\n border-color: var(--hw-border);\n }\n}\n');
|
|
4177
|
+
|
|
4105
4178
|
// src/helpway-widget.tsx
|
|
4106
4179
|
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
4107
4180
|
function HelpwayWidget({
|
|
@@ -4128,10 +4201,10 @@ function HelpwayWidget({
|
|
|
4128
4201
|
}
|
|
4129
4202
|
|
|
4130
4203
|
// src/hooks/use-realtime.ts
|
|
4131
|
-
import { useEffect as
|
|
4204
|
+
import { useEffect as useEffect12 } from "react";
|
|
4132
4205
|
function useRealtime(handler) {
|
|
4133
4206
|
const { ws } = useWidgetContext();
|
|
4134
|
-
|
|
4207
|
+
useEffect12(() => {
|
|
4135
4208
|
return ws.onEvent(handler);
|
|
4136
4209
|
}, [ws, handler]);
|
|
4137
4210
|
}
|
|
@@ -4139,6 +4212,7 @@ export {
|
|
|
4139
4212
|
Composer,
|
|
4140
4213
|
DefaultWidget,
|
|
4141
4214
|
HelpwayWidget,
|
|
4215
|
+
MarkdownContent,
|
|
4142
4216
|
MessageBubble,
|
|
4143
4217
|
MessageList,
|
|
4144
4218
|
SupportProvider,
|
|
@@ -4147,6 +4221,8 @@ export {
|
|
|
4147
4221
|
formatTime,
|
|
4148
4222
|
getInitials,
|
|
4149
4223
|
getOrCreateVisitorId,
|
|
4224
|
+
linkifyText,
|
|
4225
|
+
renderMarkdown,
|
|
4150
4226
|
useComposer,
|
|
4151
4227
|
useConversations,
|
|
4152
4228
|
useIdentify,
|