@gengage/assistant-fe 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +100 -0
  2. package/dist/assistant-fe.css +1 -1
  3. package/dist/chat/components/ChatDrawer.d.ts +8 -4
  4. package/dist/chat/components/ChatDrawer.d.ts.map +1 -1
  5. package/dist/chat/index.d.ts +5 -0
  6. package/dist/chat/index.d.ts.map +1 -1
  7. package/dist/chat/types.d.ts +1 -1
  8. package/dist/chat.cjs +1 -1
  9. package/dist/chat.iife.js +16 -16
  10. package/dist/chat.iife.js.map +1 -1
  11. package/dist/chat.js +2 -2
  12. package/dist/common/events.d.ts.map +1 -1
  13. package/dist/common/index.d.ts +2 -0
  14. package/dist/common/index.d.ts.map +1 -1
  15. package/dist/common/native-webview.d.ts +61 -0
  16. package/dist/common/native-webview.d.ts.map +1 -0
  17. package/dist/common/overlay.d.ts +5 -0
  18. package/dist/common/overlay.d.ts.map +1 -1
  19. package/dist/common.cjs +1 -1
  20. package/dist/common.cjs.map +1 -1
  21. package/dist/common.js +197 -426
  22. package/dist/common.js.map +1 -1
  23. package/dist/index-1yPxOqAw.cjs +13 -0
  24. package/dist/index-1yPxOqAw.cjs.map +1 -0
  25. package/dist/index-BH-V2lWn.js +510 -0
  26. package/dist/index-BH-V2lWn.js.map +1 -0
  27. package/dist/index-BelS6Vnv.cjs +2 -0
  28. package/dist/index-BelS6Vnv.cjs.map +1 -0
  29. package/dist/index-CERWfDdF.js +4571 -0
  30. package/dist/index-CERWfDdF.js.map +1 -0
  31. package/dist/index.cjs +1 -1
  32. package/dist/index.d.ts +2 -2
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +55 -50
  35. package/dist/index.js.map +1 -1
  36. package/dist/native/index.d.ts +3 -0
  37. package/dist/native/index.d.ts.map +1 -0
  38. package/dist/native.cjs +2 -0
  39. package/dist/native.cjs.map +1 -0
  40. package/dist/native.iife.js +97 -0
  41. package/dist/native.iife.js.map +1 -0
  42. package/dist/native.js +9 -0
  43. package/dist/native.js.map +1 -0
  44. package/dist/qna/components/TextInput.d.ts.map +1 -1
  45. package/dist/qna/components/renderUISpec.d.ts.map +1 -1
  46. package/dist/qna/index.d.ts +1 -0
  47. package/dist/qna/index.d.ts.map +1 -1
  48. package/dist/qna/types.d.ts +1 -1
  49. package/dist/qna/types.d.ts.map +1 -1
  50. package/dist/qna.cjs +1 -1
  51. package/dist/qna.cjs.map +1 -1
  52. package/dist/qna.css +1 -1
  53. package/dist/qna.iife.js +14 -14
  54. package/dist/qna.iife.js.map +1 -1
  55. package/dist/qna.js +92 -80
  56. package/dist/qna.js.map +1 -1
  57. package/dist/{schemas-DhaO7I0-.cjs → schemas-DHzfUzwA.cjs} +22 -22
  58. package/dist/schemas-DHzfUzwA.cjs.map +1 -0
  59. package/dist/{schemas-BlkBmaA5.js → schemas-yF4IOEUi.js} +807 -755
  60. package/dist/schemas-yF4IOEUi.js.map +1 -0
  61. package/dist/simrel/components/ProductCard.d.ts.map +1 -1
  62. package/dist/simrel.cjs +1 -1
  63. package/dist/simrel.cjs.map +1 -1
  64. package/dist/simrel.css +1 -1
  65. package/dist/simrel.iife.js +8 -8
  66. package/dist/simrel.iife.js.map +1 -1
  67. package/dist/simrel.js +218 -214
  68. package/dist/simrel.js.map +1 -1
  69. package/package.json +9 -2
  70. package/dist/index-B8EeSm-F.cjs +0 -13
  71. package/dist/index-B8EeSm-F.cjs.map +0 -1
  72. package/dist/index-BSpLCzAK.js +0 -4523
  73. package/dist/index-BSpLCzAK.js.map +0 -1
  74. package/dist/schemas-BlkBmaA5.js.map +0 -1
  75. package/dist/schemas-DhaO7I0-.cjs.map +0 -1
@@ -1,4523 +0,0 @@
1
- import { b as ve, c as ze, a as De, A as Re, r as Ue, o as A, s as x, f as z, C as ae, d as oe, u as re, v as Q, e as K, _ as _e, B as He, D as Fe, j, t as qe, i as Oe, E as je, F as Ve, g as $e, G as Ge, H as Ke, I as ge, m as We, J as Ye, y as Qe, x as Xe, n as Je, K as Ze, L as de, h as et, M as tt, N as at, l as nt, O as it, P as ot, Q as rt, R as st, S as ct, T as lt } from "./schemas-BlkBmaA5.js";
2
- import { s as $, i as W, f as H, c as se, d as R, a as X, e as G, r as we, g as ye, b as ke } from "./quantity-stepper-B8kX8GbN.js";
3
- function gt() {
4
- const i = Date.now(), e = new Uint8Array(16);
5
- crypto.getRandomValues(e), e[0] = i / 2 ** 40 & 255, e[1] = i / 2 ** 32 & 255, e[2] = i / 2 ** 24 & 255, e[3] = i / 2 ** 16 & 255, e[4] = i / 2 ** 8 & 255, e[5] = i & 255, e[6] = e[6] & 15 | 112, e[8] = e[8] & 63 | 128;
6
- const t = Array.from(e, (a) => a.toString(16).padStart(2, "0")).join("");
7
- return `${t.slice(0, 8)}-${t.slice(8, 12)}-${t.slice(12, 16)}-${t.slice(16, 20)}-${t.slice(20)}`;
8
- }
9
- class dt {
10
- constructor(e) {
11
- this._handlers = /* @__PURE__ */ new Map(), this._destroyed = !1, this._namespace = e.namespace, this._allowedOrigins = e.allowedOrigins ?? ["*"], this._onMessage = e.onMessage, this._allowedOrigins.includes("*"), this._messageListener = (t) => this._handlePostMessage(t), window.addEventListener("message", this._messageListener);
12
- }
13
- /** Send a message to the host page via CustomEvent on window. */
14
- send(e, t) {
15
- if (this._destroyed) return;
16
- const a = {
17
- namespace: this._namespace,
18
- type: e
19
- };
20
- t !== void 0 && (a.payload = t), window.dispatchEvent(
21
- new CustomEvent("gengage:bridge:message", {
22
- detail: a,
23
- bubbles: !1
24
- })
25
- );
26
- }
27
- /**
28
- * Register a handler for a specific message type.
29
- * Returns an unsubscribe function.
30
- */
31
- on(e, t) {
32
- this._handlers.has(e) || this._handlers.set(e, /* @__PURE__ */ new Set());
33
- const a = this._handlers.get(e);
34
- return a.add(t), () => {
35
- a.delete(t), a.size === 0 && this._handlers.delete(e);
36
- };
37
- }
38
- /** Clean up all event listeners and handlers. */
39
- destroy() {
40
- this._destroyed || (this._destroyed = !0, window.removeEventListener("message", this._messageListener), this._handlers.clear());
41
- }
42
- // ---------------------------------------------------------------------------
43
- // Private
44
- // ---------------------------------------------------------------------------
45
- _handlePostMessage(e) {
46
- if (this._destroyed || !this._isOriginAllowed(e.origin)) return;
47
- const t = e.data;
48
- if (!pt(t) || t.gengage !== this._namespace) return;
49
- const a = { type: t.type };
50
- t.payload !== void 0 && (a.payload = t.payload), this._onMessage?.(a);
51
- const n = this._handlers.get(a.type);
52
- if (n)
53
- for (const o of n)
54
- o(a.payload);
55
- }
56
- _isOriginAllowed(e) {
57
- return this._allowedOrigins.includes("*") ? !0 : this._allowedOrigins.includes(e);
58
- }
59
- }
60
- function pt(i) {
61
- if (typeof i != "object" || i === null) return !1;
62
- const e = i;
63
- return typeof e.gengage == "string" && typeof e.type == "string";
64
- }
65
- const ht = console;
66
- function ut(i, e, t = {}) {
67
- const a = i.action, n = t.logger ?? ht;
68
- switch (a.kind) {
69
- case "open_chat": {
70
- e.openChat?.(a.payload);
71
- return;
72
- }
73
- case "navigate": {
74
- if (typeof a.url != "string") {
75
- J(a, e, t, n);
76
- return;
77
- }
78
- const o = typeof a.newTab == "boolean" ? a.newTab : void 0;
79
- if (e.navigate) {
80
- o !== void 0 ? e.navigate({ url: a.url, newTab: o }) : e.navigate({ url: a.url });
81
- return;
82
- }
83
- mt(a.url, o);
84
- return;
85
- }
86
- case "save_session": {
87
- if (typeof a.sessionId != "string" || typeof a.sku != "string") {
88
- J(a, e, t, n);
89
- return;
90
- }
91
- e.saveSession?.({ sessionId: a.sessionId, sku: a.sku });
92
- return;
93
- }
94
- case "add_to_cart": {
95
- if (typeof a.sku != "string" || typeof a.quantity != "number" || typeof a.cartCode != "string") {
96
- J(a, e, t, n);
97
- return;
98
- }
99
- e.addToCart?.({
100
- sku: a.sku,
101
- quantity: a.quantity,
102
- cartCode: a.cartCode
103
- });
104
- return;
105
- }
106
- case "script_call": {
107
- if (t.allowScriptCall === !1) {
108
- J(a, e, t, n);
109
- return;
110
- }
111
- if (typeof a.name != "string") {
112
- J(a, e, t, n);
113
- return;
114
- }
115
- const o = ft(a.payload) ? a.payload : void 0;
116
- o !== void 0 ? e.scriptCall?.({ name: a.name, payload: o }) : e.scriptCall?.({ name: a.name });
117
- return;
118
- }
119
- default:
120
- J(a, e, t, n);
121
- }
122
- }
123
- function J(i, e, t, a) {
124
- const n = t.unknownActionPolicy ?? "log-and-ignore";
125
- if (n === "delegate") {
126
- e.unknown?.(i), e.unknown || a.warn("[gengage] Unknown action received without delegate handler", i);
127
- return;
128
- }
129
- if (n === "throw")
130
- throw new Error(`[gengage] Unknown action kind: ${i.kind}`);
131
- a.warn("[gengage] Unknown action ignored", i);
132
- }
133
- function mt(i, e) {
134
- if (!(typeof window > "u")) {
135
- if (e) {
136
- window.open(i, "_blank", "noopener,noreferrer");
137
- return;
138
- }
139
- window.location.href = i;
140
- }
141
- }
142
- function ft(i) {
143
- return typeof i == "object" && i !== null && !Array.isArray(i);
144
- }
145
- const bt = ["image/jpeg", "image/png", "image/webp"], xt = 5 * 1024 * 1024;
146
- function vt(i) {
147
- return bt.includes(i.type) ? i.size > xt ? { ok: !1, reason: "too_large" } : { ok: !0 } : { ok: !1, reason: "invalid_type" };
148
- }
149
- function _t(i, e) {
150
- const t = i.type, a = i.payload != null && typeof i.payload == "object" && !Array.isArray(i.payload) ? i.payload : {}, n = (o) => {
151
- const s = { ...a };
152
- for (const [l, r] of Object.entries(o))
153
- l in s || (s[l] = r);
154
- return s;
155
- };
156
- switch (t) {
157
- case "inputText": {
158
- const o = {
159
- is_launcher: 0
160
- };
161
- return e.pageContext?.extra && (o.page_details = e.pageContext.extra), "is_suggested_text" in a || (o.is_suggested_text = 0), { ...i, payload: n(o) };
162
- }
163
- case "findSimilar": {
164
- const o = {
165
- is_launcher: 0
166
- };
167
- return i.title && (o.text = i.title), i.title && (o.input = i.title), { ...i, payload: n(o) };
168
- }
169
- case "getComparisonTable":
170
- return i;
171
- case "addToCart": {
172
- const o = {};
173
- return "error_message" in a || (o.error_message = ""), { ...i, payload: n(o) };
174
- }
175
- case "reviewSummary": {
176
- const o = {};
177
- return e.pageContext?.sku && !("sku" in a) && (o.sku = e.pageContext.sku), Object.keys(o).length === 0 ? i : { ...i, payload: n(o) };
178
- }
179
- default:
180
- return i;
181
- }
182
- }
183
- const wt = {
184
- user_message: "inputText"
185
- };
186
- function yt(i) {
187
- const { action: e, type: t, payload: a, ...n } = i, o = t ?? e?.type ?? "inputText", s = a ?? e?.payload, l = wt[o] ?? o, r = {
188
- ...n,
189
- type: l
190
- };
191
- return s !== void 0 && (r.payload = typeof s == "string" ? { text: s } : s), JSON.stringify(r);
192
- }
193
- function kt(i) {
194
- const e = i.type ?? i.action?.type ?? "inputText", t = i.payload ?? i.action?.payload;
195
- let a = i.action?.title ?? "";
196
- (e === "inputText" || e === "user_message") && (typeof t == "string" ? a = t : t && typeof t == "object" && "text" in t && (a = String(t.text)));
197
- const n = {
198
- message: a,
199
- session_id: i.session_id
200
- };
201
- if (i.user_id && (n.user_id = i.user_id), i.locale && (n.output_language = i.locale), i.meta?.outputLanguage && (n.output_language = i.meta.outputLanguage), i.sku || i.page_type) {
202
- const o = {};
203
- i.page_type && (o.screen_type = i.page_type), i.sku && (o.sku_list = [i.sku]), n.screen_context = o;
204
- }
205
- return e !== "inputText" && e !== "user_message" && (n.action_type = e, t !== void 0 && (n.action_payload = typeof t == "string" ? { text: t } : t)), JSON.stringify(n);
206
- }
207
- function Ct(i, e, t) {
208
- const a = ve("process_action", t), n = new AbortController();
209
- return (async () => {
210
- try {
211
- const s = t.backendType === "acap" ? kt(i) : yt(i), l = t.attachment !== void 0;
212
- let r;
213
- if (l) {
214
- const u = new FormData();
215
- u.append("request", s), t.attachment !== void 0 && u.append("attachment", t.attachment), r = {
216
- method: "POST",
217
- body: u,
218
- signal: n.signal
219
- };
220
- } else
221
- r = {
222
- method: "POST",
223
- headers: { "Content-Type": "application/json" },
224
- body: s,
225
- signal: n.signal
226
- };
227
- const c = await fetch(a, r);
228
- if (!c.ok) {
229
- let u = c.statusText;
230
- try {
231
- const p = await c.json(), b = p.detail ?? p.message ?? p.error;
232
- typeof b == "string" && (u = b);
233
- } catch {
234
- }
235
- e.onError(new Error(`HTTP ${c.status}: ${u}`));
236
- return;
237
- }
238
- let d = !1;
239
- const g = () => {
240
- d || (d = !0, e.onDone());
241
- };
242
- await ze(c, {
243
- onEvent: (u) => {
244
- const p = De(u);
245
- if (p)
246
- switch (p.type) {
247
- case "text_chunk":
248
- e.onTextChunk(p.content, p.final === !0, {
249
- productMentions: p.productMentions,
250
- skuToProductItem: p.skuToProductItem,
251
- conversationMode: p.conversationMode
252
- });
253
- break;
254
- case "ui_spec":
255
- e.onUISpec(p.spec, p.widget, p.panelHint);
256
- break;
257
- case "action":
258
- e.onAction(p);
259
- break;
260
- case "metadata":
261
- e.onMetadata(p);
262
- break;
263
- case "error":
264
- e.onError(new Error(p.message));
265
- break;
266
- case "done":
267
- g();
268
- break;
269
- }
270
- },
271
- onError: e.onError,
272
- signal: n.signal
273
- }), g();
274
- } catch (s) {
275
- if (s instanceof DOMException && s.name === "AbortError") return;
276
- e.onError(s instanceof Error ? s : new Error(String(s)));
277
- }
278
- })(), n;
279
- }
280
- async function Et(i, e) {
281
- const t = ve("proactive_action", e);
282
- try {
283
- const a = await fetch(t, {
284
- method: "POST",
285
- headers: { "Content-Type": "application/json" },
286
- body: JSON.stringify(i)
287
- });
288
- return a.ok ? await a.json() : null;
289
- } catch {
290
- return null;
291
- }
292
- }
293
- const ce = {
294
- headerTitle: "Ürün Uzmanı",
295
- inputPlaceholder: "Ürün ara, soru sor",
296
- sendButton: "Gönder",
297
- closeButton: "Kapat",
298
- openButton: "Sohbeti aç",
299
- newChatButton: "Yeni sohbet",
300
- poweredBy: "Powered by Gengage",
301
- errorMessage: "Bir hata oluştu. Lütfen tekrar deneyin.",
302
- retryButton: "Tekrar Dene",
303
- loadingMessage: "Düşünüyorum...",
304
- productCtaLabel: "İncele",
305
- attachImageButton: "Resim ekle",
306
- removeAttachmentButton: "Resmi kaldır",
307
- invalidFileType: "Sadece JPEG, PNG ve WebP dosyaları destekleniyor.",
308
- fileTooLarge: "Dosya boyutu 5 MB'dan küçük olmalıdır.",
309
- aiTopPicksTitle: "Sizin İçin En İyiler",
310
- roleWinner: "En Beğendiğim",
311
- roleBestValue: "En Uygun Fiyatlı",
312
- roleBestAlternative: "En İyi Alternatif",
313
- viewDetails: "Detayları Gör",
314
- groundingReviewCta: "Yorumları Oku",
315
- groundingReviewSubtitle: "{count} yorum mevcut",
316
- variantsLabel: "Varyantlar",
317
- sortRelated: "Önerilen",
318
- sortPriceAsc: "Fiyat ↑",
319
- sortPriceDesc: "Fiyat ↓",
320
- compareSelected: "Karşılaştır",
321
- panelTitleProductDetails: "Ürün Detayı",
322
- panelTitleSimilarProducts: "Benzer Ürünler",
323
- panelTitleComparisonResults: "Karşılaştırma Sonuçları",
324
- panelTitleCategories: "Kategoriler",
325
- panelTitleSearchResults: "Arama Sonuçları",
326
- inStockLabel: "Stokta",
327
- outOfStockLabel: "Tükendi",
328
- findSimilarLabel: "Benzerlerini Bul",
329
- choicePrompterHeading: "Kararsız mı kaldın?",
330
- choicePrompterSuggestion: "Ürünleri seçip karşılaştırabilirsin",
331
- choicePrompterCta: "Seç ve Karşılaştır",
332
- viewMoreLabel: "Daha Fazla Göster",
333
- similarProductsLabel: "Benzer Ürünler",
334
- addToCartButton: "Sepete Ekle",
335
- shareButton: "Paylaş",
336
- productInfoTab: "Ürün Bilgileri",
337
- specificationsTab: "Teknik Özellikler",
338
- recommendedChoiceLabel: "Önerilen Seçim",
339
- highlightsLabel: "Öne Çıkan Özellikler",
340
- keyDifferencesLabel: "Temel Farklar",
341
- specialCasesLabel: "Özel Durumlar İçin",
342
- emptyReviewsMessage: "Yorum özeti bulunamadı.",
343
- closeAriaLabel: "Kapat",
344
- startChatLabel: "Sohbete Başla",
345
- voiceButton: "Sesli giriş",
346
- voiceListening: "Dinleniyor...",
347
- voiceNotSupported: "Sesli giriş bu tarayıcıda desteklenmiyor.",
348
- voicePermissionDenied: "Mikrofon erişimi reddedildi.",
349
- voiceError: "Sesli giriş hatası.",
350
- handoffHeading: "Destek temsilcisine aktarılıyor",
351
- productNotFoundMessage: "Bu ürün bilgisi şu an kullanılamıyor. Başka bir konuda yardımcı olabilirim."
352
- }, St = {
353
- headerTitle: "Product Expert",
354
- inputPlaceholder: "Search products, ask questions",
355
- sendButton: "Send",
356
- closeButton: "Close",
357
- openButton: "Open chat",
358
- newChatButton: "New chat",
359
- poweredBy: "Powered by Gengage",
360
- errorMessage: "Something went wrong. Please try again.",
361
- retryButton: "Retry",
362
- loadingMessage: "Thinking...",
363
- productCtaLabel: "View",
364
- attachImageButton: "Attach image",
365
- removeAttachmentButton: "Remove image",
366
- invalidFileType: "Only JPEG, PNG and WebP files are supported.",
367
- fileTooLarge: "File must be smaller than 5 MB.",
368
- aiTopPicksTitle: "Top Picks for You",
369
- roleWinner: "Top Pick",
370
- roleBestValue: "Best Value",
371
- roleBestAlternative: "Best Alternative",
372
- viewDetails: "View Details",
373
- groundingReviewCta: "Read Reviews",
374
- groundingReviewSubtitle: "{count} reviews available",
375
- variantsLabel: "Variants",
376
- sortRelated: "Related",
377
- sortPriceAsc: "Price ↑",
378
- sortPriceDesc: "Price ↓",
379
- compareSelected: "Compare",
380
- panelTitleProductDetails: "Product Details",
381
- panelTitleSimilarProducts: "Similar Products",
382
- panelTitleComparisonResults: "Comparison Results",
383
- panelTitleCategories: "Categories",
384
- panelTitleSearchResults: "Search Results",
385
- inStockLabel: "In Stock",
386
- outOfStockLabel: "Out of Stock",
387
- findSimilarLabel: "Find Similar",
388
- choicePrompterHeading: "Can't decide?",
389
- choicePrompterSuggestion: "Select products to compare them",
390
- choicePrompterCta: "Select & Compare",
391
- viewMoreLabel: "Show More",
392
- similarProductsLabel: "Similar Products",
393
- addToCartButton: "Add to Cart",
394
- shareButton: "Share",
395
- productInfoTab: "Product Info",
396
- specificationsTab: "Specifications",
397
- recommendedChoiceLabel: "Recommended Choice",
398
- highlightsLabel: "Key Highlights",
399
- keyDifferencesLabel: "Key Differences",
400
- specialCasesLabel: "For Special Cases",
401
- emptyReviewsMessage: "No review summary found.",
402
- closeAriaLabel: "Close",
403
- startChatLabel: "Start Chat",
404
- voiceButton: "Voice input",
405
- voiceListening: "Listening...",
406
- voiceNotSupported: "Voice input is not supported in this browser.",
407
- voicePermissionDenied: "Microphone access denied.",
408
- voiceError: "Voice input error.",
409
- handoffHeading: "Transferring to a support agent",
410
- productNotFoundMessage: "Product information is currently unavailable. I can help with something else."
411
- };
412
- function Tt(i) {
413
- return i ? i.toLowerCase().split("-")[0] ?? "tr" : "tr";
414
- }
415
- function It(i) {
416
- return Tt(i) === "en" ? St : ce;
417
- }
418
- function Lt() {
419
- return Ce() !== null;
420
- }
421
- function Ce() {
422
- const i = globalThis;
423
- return i.SpeechRecognition ?? i.webkitSpeechRecognition ?? null;
424
- }
425
- class Nt {
426
- constructor(e, t) {
427
- this.recognition = null, this._state = "idle", this.silenceTimer = null, this.accumulatedTranscript = "", this.intentionalStop = !1, this.callbacks = e, this.lang = t?.lang ?? "tr-TR", this.silenceTimeoutMs = t?.silenceTimeoutMs ?? 1500, this.autoSubmit = t?.autoSubmit ?? !0;
428
- }
429
- get state() {
430
- return this._state;
431
- }
432
- /**
433
- * Start listening. Requests microphone permission on first call.
434
- */
435
- start() {
436
- if (this._state === "listening") return;
437
- const e = Ce();
438
- if (!e) {
439
- this.setState("error"), this.callbacks.onError?.("not-supported", "Web Speech API is not supported in this browser.");
440
- return;
441
- }
442
- if (typeof globalThis.isSecureContext < "u" && !globalThis.isSecureContext) {
443
- this.setState("error"), this.callbacks.onError?.("not-allowed", "Voice input requires HTTPS.");
444
- return;
445
- }
446
- this.accumulatedTranscript = "", this.intentionalStop = !1;
447
- const t = new e();
448
- t.continuous = !0, t.interimResults = !0, t.lang = this.lang, t.maxAlternatives = 1, t.onstart = () => {
449
- this.setState("listening");
450
- }, t.onresult = (a) => {
451
- this.clearSilenceTimer();
452
- let n = "", o = "";
453
- for (let s = a.resultIndex; s < a.results.length; s++) {
454
- const l = a.results[s];
455
- if (!l) continue;
456
- const r = l[0];
457
- r && (l.isFinal ? o += r.transcript : n += r.transcript);
458
- }
459
- o && (this.accumulatedTranscript += o, this.callbacks.onFinal?.(this.accumulatedTranscript)), n && this.callbacks.onInterim?.(this.accumulatedTranscript + n), this.autoSubmit && this.accumulatedTranscript && this.startSilenceTimer();
460
- }, t.onerror = (a) => {
461
- const n = At(a.error);
462
- this.intentionalStop && (a.error === "no-speech" || a.error === "aborted") || (this.setState("error"), this.callbacks.onError?.(n, a.message || a.error));
463
- }, t.onend = () => {
464
- if (this.clearSilenceTimer(), this._state === "listening" && !this.intentionalStop) {
465
- try {
466
- t.start();
467
- } catch {
468
- this.setState("idle");
469
- }
470
- return;
471
- }
472
- this.setState("idle");
473
- }, this.recognition = t;
474
- try {
475
- t.start();
476
- } catch {
477
- this.setState("error"), this.callbacks.onError?.("unknown", "Failed to start speech recognition.");
478
- }
479
- }
480
- /**
481
- * Stop listening. Returns the accumulated transcript.
482
- */
483
- stop() {
484
- if (this.intentionalStop = !0, this.clearSilenceTimer(), this.recognition) {
485
- try {
486
- this.recognition.stop();
487
- } catch {
488
- }
489
- this.recognition = null;
490
- }
491
- return this.setState("idle"), this.accumulatedTranscript;
492
- }
493
- /**
494
- * Abort listening. Discards any accumulated transcript.
495
- */
496
- abort() {
497
- if (this.intentionalStop = !0, this.clearSilenceTimer(), this.accumulatedTranscript = "", this.recognition) {
498
- try {
499
- this.recognition.abort();
500
- } catch {
501
- }
502
- this.recognition = null;
503
- }
504
- this.setState("idle");
505
- }
506
- /** Destroy the instance and release resources. */
507
- destroy() {
508
- this.abort();
509
- }
510
- setState(e) {
511
- this._state !== e && (this._state = e, this.callbacks.onStateChange?.(e));
512
- }
513
- startSilenceTimer() {
514
- this.clearSilenceTimer(), this.silenceTimer = setTimeout(() => {
515
- const e = this.stop();
516
- e.trim() && this.callbacks.onAutoSubmit?.(e.trim());
517
- }, this.silenceTimeoutMs);
518
- }
519
- clearSilenceTimer() {
520
- this.silenceTimer !== null && (clearTimeout(this.silenceTimer), this.silenceTimer = null);
521
- }
522
- }
523
- function At(i) {
524
- switch (i) {
525
- case "not-allowed":
526
- return "not-allowed";
527
- case "no-speech":
528
- return "no-speech";
529
- case "audio-capture":
530
- return "no-microphone";
531
- case "network":
532
- return "network";
533
- case "aborted":
534
- return "aborted";
535
- default:
536
- return "unknown";
537
- }
538
- }
539
- function Pt(i) {
540
- const e = document.createElement("div");
541
- e.className = "gengage-chat-kvkk-banner", e.setAttribute("role", "alert");
542
- const t = document.createElement("div");
543
- t.className = "gengage-chat-kvkk-content", t.innerHTML = $(i.htmlContent), e.appendChild(t);
544
- const a = document.createElement("button");
545
- return a.className = "gengage-chat-kvkk-dismiss", a.type = "button", a.setAttribute("aria-label", i.closeAriaLabel ?? "Kapat"), a.textContent = "×", a.addEventListener("click", i.onDismiss), e.appendChild(a), e;
546
- }
547
- class Mt {
548
- constructor(e) {
549
- this._el = document.createElement("div"), this._el.className = "gengage-chat-panel-topbar", this._backBtn = document.createElement("button"), this._backBtn.className = "gengage-chat-panel-topbar-back", this._backBtn.type = "button", this._backBtn.disabled = !0, this._backBtn.setAttribute("aria-label", "Back"), this._backBtn.textContent = "←", this._backBtn.addEventListener("click", () => e.onBack()), this._titleEl = document.createElement("span"), this._titleEl.className = "gengage-chat-panel-topbar-title", this._forwardBtn = document.createElement("button"), this._forwardBtn.className = "gengage-chat-panel-topbar-forward", this._forwardBtn.type = "button", this._forwardBtn.disabled = !0, this._forwardBtn.setAttribute("aria-label", "Forward"), this._forwardBtn.textContent = "→", this._forwardBtn.addEventListener("click", () => e.onForward()), this._el.appendChild(this._backBtn), this._el.appendChild(this._titleEl), this._el.appendChild(this._forwardBtn);
550
- }
551
- update(e, t, a) {
552
- this._backBtn.disabled = !e, this._forwardBtn.disabled = !t, this._titleEl.textContent = a;
553
- }
554
- getElement() {
555
- return this._el;
556
- }
557
- }
558
- class Bt {
559
- constructor(e) {
560
- this._onThumbnailClick = e.onThumbnailClick, this._el = document.createElement("div"), this._el.className = "gengage-chat-thumbnails-column", this._el.style.display = "none";
561
- }
562
- getElement() {
563
- return this._el;
564
- }
565
- setEntries(e) {
566
- const t = /* @__PURE__ */ new Set(), a = [];
567
- for (const n of e)
568
- t.has(n.sku) || (t.add(n.sku), a.push(n));
569
- this._el.innerHTML = "";
570
- for (const n of a) {
571
- const o = document.createElement("button");
572
- if (o.type = "button", o.className = "gengage-chat-thumbnail-btn", o.title = n.sku, W(n.imageUrl)) {
573
- const s = document.createElement("img");
574
- s.className = "gengage-chat-thumbnail-img", s.src = n.imageUrl, s.alt = n.sku, s.width = 40, s.height = 40, o.appendChild(s);
575
- }
576
- o.addEventListener("click", () => {
577
- this._onThumbnailClick(n.threadId);
578
- }), this._el.appendChild(o);
579
- }
580
- }
581
- show() {
582
- this._el.style.display = "";
583
- }
584
- hide() {
585
- this._el.style.display = "none";
586
- }
587
- }
588
- const pe = {
589
- search: '<svg viewBox="0 0 16 16" class="gengage-chat-icon"><circle cx="6.5" cy="6.5" r="5" fill="none" stroke="currentColor" stroke-width="1.5"/><line x1="10" y1="10" x2="15" y2="15" stroke="currentColor" stroke-width="1.5"/></svg>',
590
- review: '<svg viewBox="0 0 16 16" class="gengage-chat-icon"><polygon points="8,1 10,6 15,6 11,9 12.5,14 8,11 3.5,14 5,9 1,6 6,6" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>',
591
- info: '<svg viewBox="0 0 16 16" class="gengage-chat-icon"><circle cx="8" cy="8" r="7" fill="none" stroke="currentColor" stroke-width="1.5"/><line x1="8" y1="7" x2="8" y2="12" stroke="currentColor" stroke-width="1.5"/><circle cx="8" cy="4.5" r="0.8" fill="currentColor"/></svg>',
592
- similar: '<svg viewBox="0 0 16 16" class="gengage-chat-icon"><rect x="1" y="3" width="6" height="6" rx="1" fill="none" stroke="currentColor" stroke-width="1.5"/><rect x="9" y="3" width="6" height="6" rx="1" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>'
593
- }, zt = ce;
594
- class Dt {
595
- constructor(e, t) {
596
- this._panelVisible = !1, this._panelCollapsed = !1, this._panelForceExpanded = !1, this._onPanelToggle = void 0, this._pendingAttachment = null, this._onAttachment = void 0, this._onRollback = void 0, this._onLinkClick = void 0, this._userScrolledUp = !1, this._scrollLockedUntil = 0, this._thinkingSteps = [], this._firstBotMessageIds = /* @__PURE__ */ new Set(), this._voiceInput = null, this._micBtn = null, this._voiceEnabled = !1, this._voiceLang = "tr-TR", this.i18n = { ...zt, ...t.i18n }, this.onSend = t.onSend, t.onPanelToggle !== void 0 && (this._onPanelToggle = t.onPanelToggle), t.onAttachment !== void 0 && (this._onAttachment = t.onAttachment), t.onRollback !== void 0 && (this._onRollback = t.onRollback), t.onLinkClick !== void 0 && (this._onLinkClick = t.onLinkClick), t.voiceEnabled && (this._voiceEnabled = !0), t.voiceLang !== void 0 && (this._voiceLang = t.voiceLang), this.root = document.createElement("div"), this.root.className = "gengage-chat-drawer", this.root.setAttribute("role", "dialog"), this.root.setAttribute("aria-label", this.i18n.headerTitle ?? "Chat"), this.root.setAttribute("aria-modal", "true");
597
- const a = document.createElement("div");
598
- a.className = "gengage-chat-header";
599
- const n = document.createElement("div");
600
- if (n.className = "gengage-chat-header-left", t.headerAvatarUrl) {
601
- const h = document.createElement("img");
602
- h.className = "gengage-chat-header-avatar", h.src = t.headerAvatarUrl, h.alt = t.headerTitle ?? "Assistant", n.appendChild(h);
603
- }
604
- const o = document.createElement("div");
605
- o.className = "gengage-chat-header-info";
606
- const s = document.createElement("div");
607
- s.className = "gengage-chat-header-title-row";
608
- const l = document.createElement("span");
609
- if (l.className = "gengage-chat-header-title", l.textContent = t.headerTitle ?? this.i18n.headerTitle ?? "Gengage Asistanı", s.appendChild(l), t.headerBadge) {
610
- const h = document.createElement("span");
611
- h.className = "gengage-chat-header-badge", h.textContent = t.headerBadge, s.appendChild(h);
612
- }
613
- o.appendChild(s);
614
- const r = document.createElement("a");
615
- r.className = "gengage-chat-header-powered", r.href = "https://gengage.ai/", r.target = "_blank", r.rel = "noopener noreferrer", r.innerHTML = '<svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 1a7 7 0 110 14A7 7 0 018 1zm0 1.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM7 4.5h2v4H7v-4zm0 5h2v2H7v-2z"/></svg>Powered by Gengage', o.appendChild(r), n.appendChild(o), a.appendChild(n);
616
- const c = document.createElement("div");
617
- if (c.className = "gengage-chat-header-right", t.headerCartUrl) {
618
- const h = document.createElement("a");
619
- h.className = "gengage-chat-header-btn", h.href = t.headerCartUrl, h.target = "_blank", h.rel = "noopener noreferrer", h.setAttribute("aria-label", "Sepetim"), h.innerHTML = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>', c.appendChild(h);
620
- }
621
- if (t.headerFavoritesToggle) {
622
- const h = document.createElement("button");
623
- h.className = "gengage-chat-header-btn", h.type = "button", h.setAttribute("aria-label", "Favorilerim"), h.innerHTML = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>', h.addEventListener("click", () => t.onFavoritesClick?.()), c.appendChild(h);
624
- }
625
- const d = document.createElement("button");
626
- d.className = "gengage-chat-close", d.type = "button", d.setAttribute("aria-label", this.i18n.closeButton), d.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>', d.addEventListener("click", t.onClose), c.appendChild(d), a.appendChild(c);
627
- const g = document.createElement("div");
628
- g.className = "gengage-chat-body", this._panelEl = document.createElement("div"), this._panelEl.className = "gengage-chat-panel", this._panelTopBar = new Mt({
629
- onBack: () => t.onPanelBack?.(),
630
- onForward: () => t.onPanelForward?.()
631
- }), this._panelEl.appendChild(this._panelTopBar.getElement()), g.appendChild(this._panelEl), this._dividerEl = document.createElement("div"), this._dividerEl.className = "gengage-chat-panel-divider gengage-chat-panel-divider--hidden", this._dividerEl.setAttribute("role", "separator"), this._dividerEl.setAttribute("aria-label", "Toggle panel");
632
- const u = document.createElement("button");
633
- u.className = "gengage-chat-panel-divider-toggle", u.type = "button", u.setAttribute("aria-label", "Toggle panel"), u.textContent = "»", u.addEventListener("click", () => {
634
- this.togglePanel(), this._onPanelToggle?.();
635
- }), this._dividerEl.appendChild(u), g.appendChild(this._dividerEl);
636
- const p = document.createElement("div");
637
- p.className = "gengage-chat-conversation", p.appendChild(a), this._kvkkSlot = document.createElement("div"), this._kvkkSlot.className = "gengage-chat-kvkk-slot", p.appendChild(this._kvkkSlot), this.messagesEl = document.createElement("div"), this.messagesEl.className = "gengage-chat-messages", this.messagesEl.setAttribute("role", "log"), this.messagesEl.setAttribute("aria-live", "polite"), this.messagesEl.setAttribute("aria-label", "Chat messages");
638
- let b = !1;
639
- this.messagesEl.addEventListener(
640
- "scroll",
641
- () => {
642
- b || (b = !0, requestAnimationFrame(() => {
643
- b = !1;
644
- const { scrollTop: h, scrollHeight: f, clientHeight: w } = this.messagesEl;
645
- this._userScrolledUp = f - h - w > 10;
646
- }));
647
- },
648
- { passive: !0 }
649
- ), p.appendChild(this.messagesEl), this._thumbnailsColumn = new Bt({
650
- onThumbnailClick: (h) => t.onThumbnailClick?.(h)
651
- }), this._panelEl.appendChild(this._thumbnailsColumn.getElement()), this._pillsEl = document.createElement("div"), this._pillsEl.className = "gengage-chat-pills", this._pillsEl.setAttribute("role", "toolbar"), this._pillsEl.setAttribute("aria-label", "Suggestions"), this._pillsEl.style.display = "none";
652
- const y = document.createElement("div");
653
- y.className = "gengage-chat-pills-scroll", this._pillsEl.appendChild(y);
654
- const _ = document.createElement("button");
655
- _.className = "gengage-chat-pills-arrow", _.type = "button", _.setAttribute("aria-label", "More suggestions"), _.textContent = "›", _.addEventListener("click", () => {
656
- y.scrollBy({ left: 150, behavior: "smooth" });
657
- }), this._pillsEl.appendChild(_);
658
- let I = !1;
659
- y.addEventListener(
660
- "scroll",
661
- () => {
662
- I || (I = !0, requestAnimationFrame(() => {
663
- I = !1;
664
- const h = y.scrollLeft + y.clientWidth >= y.scrollWidth - 4;
665
- _.style.display = h ? "none" : "";
666
- }));
667
- },
668
- { passive: !0 }
669
- ), p.appendChild(this._pillsEl), this._inputChipsEl = document.createElement("div"), this._inputChipsEl.className = "gengage-chat-input-chips", this._inputChipsEl.style.display = "none", p.appendChild(this._inputChipsEl);
670
- const C = document.createElement("div");
671
- C.className = "gengage-chat-input-area", this.inputEl = document.createElement("textarea"), this.inputEl.className = "gengage-chat-input", this.inputEl.rows = 1, this.inputEl.placeholder = this.i18n.inputPlaceholder, this.inputEl.addEventListener("input", () => {
672
- requestAnimationFrame(() => {
673
- this.inputEl.style.height = "auto", this.inputEl.style.height = `${Math.min(this.inputEl.scrollHeight, 120)}px`;
674
- });
675
- }), this.inputEl.addEventListener("keydown", (h) => {
676
- h.key === "Enter" && (window.innerWidth < 768 || !h.shiftKey) && (h.preventDefault(), this._submit());
677
- }), this.inputEl.addEventListener("paste", (h) => {
678
- const f = h.clipboardData?.files[0];
679
- f && f.type.startsWith("image/") && (h.preventDefault(), this._onAttachment ? this._onAttachment(f) : this.stageAttachment(f));
680
- }), this._fileInput = document.createElement("input"), this._fileInput.type = "file", this._fileInput.accept = "image/jpeg,image/png,image/webp", this._fileInput.style.display = "none", this._fileInput.addEventListener("change", () => {
681
- const h = this._fileInput.files?.[0];
682
- h && (this._onAttachment ? this._onAttachment(h) : this.stageAttachment(h)), this._fileInput.value = "";
683
- });
684
- const T = document.createElement("button");
685
- T.className = "gengage-chat-attach-btn", T.type = "button", T.setAttribute("aria-label", this.i18n.attachImageButton), T.innerHTML = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg>', T.addEventListener("click", () => this._fileInput.click()), this._previewStrip = document.createElement("div"), this._previewStrip.className = "gengage-chat-attachment-preview gengage-chat-attachment-preview--hidden";
686
- const v = document.createElement("img");
687
- v.className = "gengage-chat-attachment-preview-thumb", v.alt = "", this._previewName = document.createElement("span"), this._previewName.className = "gengage-chat-attachment-name";
688
- const m = document.createElement("button");
689
- m.className = "gengage-chat-attachment-remove", m.type = "button", m.setAttribute("aria-label", this.i18n.removeAttachmentButton), m.textContent = "×", m.addEventListener("click", () => this.clearAttachment()), this._previewStrip.appendChild(v), this._previewStrip.appendChild(this._previewName), this._previewStrip.appendChild(m), this.sendBtn = document.createElement("button"), this.sendBtn.className = "gengage-chat-send", this.sendBtn.type = "button", this.sendBtn.setAttribute("aria-label", this.i18n.sendButton), this.sendBtn.innerHTML = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>', this.sendBtn.addEventListener("click", () => this._submit()), C.addEventListener("dragover", (h) => {
690
- h.preventDefault(), C.classList.add("gengage-chat-input-area--dragover");
691
- }), C.addEventListener("dragleave", () => {
692
- C.classList.remove("gengage-chat-input-area--dragover");
693
- }), C.addEventListener("drop", (h) => {
694
- h.preventDefault(), C.classList.remove("gengage-chat-input-area--dragover");
695
- const f = h.dataTransfer?.files[0];
696
- f && (this._onAttachment ? this._onAttachment(f) : this.stageAttachment(f));
697
- });
698
- const k = document.createElement("div");
699
- k.className = "gengage-chat-input-pill", k.appendChild(T), k.appendChild(this.inputEl), this._voiceEnabled && Lt() && (this._micBtn = document.createElement("button"), this._micBtn.className = "gengage-chat-mic-btn", this._micBtn.type = "button", this._micBtn.setAttribute("aria-label", this.i18n.voiceButton), this._micBtn.innerHTML = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg>', this._micBtn.addEventListener("click", () => this._toggleVoice()), k.appendChild(this._micBtn), this._voiceInput = new Nt(
700
- {
701
- onInterim: (h) => {
702
- this.inputEl.value = h, this.inputEl.style.height = "auto", this.inputEl.style.height = `${Math.min(this.inputEl.scrollHeight, 120)}px`;
703
- },
704
- onFinal: (h) => {
705
- this.inputEl.value = h;
706
- },
707
- onAutoSubmit: (h) => {
708
- this.inputEl.value = h, this._micBtn?.classList.remove("gengage-chat-mic-btn--active"), this._submit();
709
- },
710
- onStateChange: (h) => {
711
- h === "listening" ? this._micBtn?.classList.add("gengage-chat-mic-btn--active") : this._micBtn?.classList.remove("gengage-chat-mic-btn--active");
712
- },
713
- onError: (h, f) => {
714
- this._micBtn?.classList.remove("gengage-chat-mic-btn--active");
715
- }
716
- },
717
- { lang: this._voiceLang }
718
- )), k.appendChild(this.sendBtn), C.appendChild(this._previewStrip), C.appendChild(this._fileInput), C.appendChild(k), p.appendChild(C), g.appendChild(p), this.root.appendChild(g);
719
- const S = document.createElement("div");
720
- S.className = "gengage-chat-footer", S.textContent = this.i18n.poweredBy, this.root.appendChild(S), this.root.addEventListener("keydown", (h) => {
721
- h.key === "Escape" && t.onClose();
722
- }), this._trapFocus(), e.appendChild(this.root);
723
- }
724
- addMessage(e) {
725
- const t = document.createElement("div");
726
- if (t.className = `gengage-chat-bubble gengage-chat-bubble--${e.role}`, t.dataset.messageId = e.id, e.threadId && (t.dataset.threadId = e.threadId), this._firstBotMessageIds.has(e.id) && t.classList.add("gengage-chat-bubble--first"), e.attachment) {
727
- const a = document.createElement("img");
728
- a.className = "gengage-chat-attachment-thumb";
729
- const n = URL.createObjectURL(e.attachment);
730
- a.src = n, a.alt = e.attachment.name, a.addEventListener("load", () => URL.revokeObjectURL(n), { once: !0 }), a.addEventListener("error", () => URL.revokeObjectURL(n), { once: !0 }), t.insertBefore(a, t.firstChild);
731
- }
732
- if (e.content) {
733
- const a = document.createElement("div");
734
- if (a.className = "gengage-chat-bubble-text", e.role === "assistant") {
735
- if (a.innerHTML = $(e.content), this._onLinkClick) {
736
- const n = a.querySelectorAll("a[href]");
737
- for (const o of n)
738
- o.addEventListener("click", (s) => {
739
- s.preventDefault();
740
- const l = o.getAttribute("href");
741
- l && this._onLinkClick?.(l);
742
- });
743
- }
744
- } else
745
- a.textContent = e.content;
746
- t.appendChild(a);
747
- }
748
- if (e.role === "user" && this._onRollback) {
749
- const a = document.createElement("button");
750
- a.className = "gengage-chat-rollback-btn", a.type = "button", a.setAttribute("aria-label", "Rollback to this message"), a.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/></svg>', a.addEventListener("click", (n) => {
751
- n.stopPropagation(), this._onRollback?.(e.id);
752
- }), t.appendChild(a);
753
- }
754
- this.messagesEl.appendChild(t), this._scrollToBottom(e.role === "user");
755
- }
756
- showTypingIndicator(e) {
757
- this.removeTypingIndicator();
758
- const t = document.createElement("div");
759
- if (t.className = "gengage-chat-typing", t.dataset.typing = "true", this._thinkingSteps.length > 0)
760
- this._renderThinkingStepsInto(t);
761
- else {
762
- const a = document.createElement("div");
763
- a.className = "gengage-chat-typing-dots";
764
- for (let n = 0; n < 3; n++) a.appendChild(document.createElement("span"));
765
- if (t.appendChild(a), e) {
766
- const n = document.createElement("span");
767
- n.className = "gengage-chat-typing-sparkle", n.textContent = "✨", t.appendChild(n);
768
- const o = document.createElement("span");
769
- o.className = "gengage-chat-typing-text", o.textContent = e, t.appendChild(o);
770
- }
771
- }
772
- this.messagesEl.appendChild(t), this._scrollToBottom(!0);
773
- }
774
- /** Accumulate a new thinking step (shown as a checklist in the typing indicator). */
775
- addThinkingStep(e) {
776
- this._thinkingSteps.push(e), this._renderThinkingSteps();
777
- }
778
- removeTypingIndicator() {
779
- this.messagesEl.querySelector(".gengage-chat-typing")?.remove(), this._thinkingSteps = [];
780
- }
781
- showError(e, t) {
782
- const a = document.createElement("div");
783
- a.className = "gengage-chat-error";
784
- const n = document.createElement("span");
785
- if (n.textContent = e ?? this.i18n.errorMessage, a.appendChild(n), t) {
786
- const o = document.createElement("button");
787
- o.className = "gengage-chat-error-retry", o.textContent = this.i18n.retryButton ?? "Retry", o.addEventListener("click", () => {
788
- a.remove(), t();
789
- }), a.appendChild(o);
790
- }
791
- this.messagesEl.appendChild(a), this._scrollToBottom(!0);
792
- }
793
- clearMessages() {
794
- this.messagesEl.innerHTML = "";
795
- }
796
- /** Replace suggestion pills. Pass empty array to hide. */
797
- setPills(e) {
798
- const t = this._pillsEl.querySelector(".gengage-chat-pills-scroll");
799
- if (!t) return;
800
- for (; t.firstChild; ) t.removeChild(t.firstChild);
801
- if (e.length === 0) {
802
- this._pillsEl.style.display = "none";
803
- return;
804
- }
805
- this._pillsEl.style.display = "";
806
- for (const n of e) {
807
- const o = document.createElement("button");
808
- if (o.className = n.image ? "gengage-chat-pill gengage-chat-pill--rich" : "gengage-chat-pill", o.type = "button", n.icon) {
809
- const l = pe[n.icon];
810
- if (l) {
811
- const r = document.createElement("span");
812
- r.className = "gengage-chat-pill-icon", r.innerHTML = l, o.appendChild(r);
813
- }
814
- }
815
- if (n.image && W(n.image)) {
816
- const l = document.createElement("img");
817
- l.className = "gengage-chat-pill-img", l.src = n.image, l.alt = "", o.appendChild(l);
818
- }
819
- const s = document.createElement("span");
820
- if (s.className = "gengage-chat-pill-text", s.textContent = n.label, o.appendChild(s), n.description) {
821
- const l = document.createElement("span");
822
- l.className = "gengage-chat-pill-desc", l.textContent = n.description, o.appendChild(l);
823
- }
824
- o.addEventListener("click", () => n.onAction()), t.appendChild(o);
825
- }
826
- const a = this._pillsEl.querySelector(".gengage-chat-pills-arrow");
827
- a && requestAnimationFrame(() => {
828
- a.style.display = t.scrollWidth > t.clientWidth ? "" : "none";
829
- });
830
- }
831
- focusInput() {
832
- this.inputEl.focus();
833
- }
834
- showKvkkBanner(e, t) {
835
- this._kvkkSlot.innerHTML = "";
836
- const a = Pt({ htmlContent: e, onDismiss: t });
837
- this._kvkkSlot.appendChild(a);
838
- }
839
- hideKvkkBanner() {
840
- this._kvkkSlot.innerHTML = "";
841
- }
842
- getElement() {
843
- return this.root;
844
- }
845
- /** Stage a file attachment for sending. Shows preview. */
846
- stageAttachment(e) {
847
- this._pendingAttachment = e, this._previewName.textContent = e.name;
848
- const t = this._previewStrip.querySelector(".gengage-chat-attachment-preview-thumb");
849
- t && (t.src && t.src.startsWith("blob:") && URL.revokeObjectURL(t.src), t.src = URL.createObjectURL(e)), this._previewStrip.classList.remove("gengage-chat-attachment-preview--hidden");
850
- }
851
- /** Remove the staged attachment and hide preview. */
852
- clearAttachment() {
853
- const e = this._previewStrip.querySelector(".gengage-chat-attachment-preview-thumb");
854
- e?.src && (URL.revokeObjectURL(e.src), e.src = ""), this._pendingAttachment = null, this._previewStrip.classList.add("gengage-chat-attachment-preview--hidden");
855
- }
856
- /** Get the currently staged attachment file, or null. */
857
- getPendingAttachment() {
858
- return this._pendingAttachment;
859
- }
860
- /** Replace panel content and show the panel. */
861
- setPanelContent(e) {
862
- this._panelEl.innerHTML = "", this._panelEl.appendChild(this._panelTopBar.getElement()), this._panelEl.appendChild(e), this._panelForceExpanded || this._dividerEl.classList.remove("gengage-chat-panel-divider--hidden"), this._panelVisible || (this._panelVisible = !0, this._panelEl.classList.add("gengage-chat-panel--visible"), this.root.classList.add("gengage-chat-drawer--with-panel")), this._panelCollapsed && this._panelEl.classList.add("gengage-chat-panel--collapsed");
863
- }
864
- /** Append content to the panel without replacing existing content. */
865
- appendPanelContent(e) {
866
- this._panelEl.appendChild(e), this._panelForceExpanded || this._dividerEl.classList.remove("gengage-chat-panel-divider--hidden"), this._panelVisible || (this._panelVisible = !0, this._panelEl.classList.add("gengage-chat-panel--visible"), this.root.classList.add("gengage-chat-drawer--with-panel"));
867
- }
868
- /** Return the panel element's content child (after topbar), or null. */
869
- getPanelContentElement() {
870
- const e = this._panelEl.children;
871
- for (let t = 0; t < e.length; t++) {
872
- const a = e[t];
873
- if (!(a.classList.contains("gengage-chat-panel-topbar") || a.classList.contains("gengage-chat-thumbnails-column")))
874
- return a;
875
- }
876
- return null;
877
- }
878
- /** Whether the panel is currently visible and has rendered content (beyond topbar + thumbnails column). */
879
- hasPanelContent() {
880
- return this._panelVisible && this.getPanelContentElement() !== null;
881
- }
882
- /** Whether panel currently shows loading skeleton blocks. */
883
- isPanelLoading() {
884
- return this._panelEl.querySelector(".gengage-chat-panel-skeleton") !== null;
885
- }
886
- /** Show loading skeleton in the panel. Variant depends on contentType hint. */
887
- showPanelLoading(e) {
888
- this._panelForceExpanded || this._dividerEl.classList.remove("gengage-chat-panel-divider--hidden"), this._panelEl.innerHTML = "", this._panelEl.appendChild(this._panelTopBar.getElement());
889
- const t = document.createElement("div");
890
- switch (t.className = "gengage-chat-panel-skeleton", e) {
891
- case "productDetails": {
892
- const a = document.createElement("div");
893
- a.className = "gengage-chat-panel-skeleton-block gengage-chat-panel-skeleton-block--image", t.appendChild(a);
894
- for (let n = 0; n < 3; n++) {
895
- const o = document.createElement("div");
896
- o.className = "gengage-chat-panel-skeleton-block gengage-chat-panel-skeleton-block--text", t.appendChild(o);
897
- }
898
- break;
899
- }
900
- case "productList":
901
- case "groupList": {
902
- const a = document.createElement("div");
903
- a.className = "gengage-chat-panel-skeleton-grid";
904
- for (let n = 0; n < 6; n++) {
905
- const o = document.createElement("div");
906
- o.className = "gengage-chat-panel-skeleton-block gengage-chat-panel-skeleton-block--card", a.appendChild(o);
907
- }
908
- t.appendChild(a);
909
- break;
910
- }
911
- case "comparisonTable": {
912
- for (let a = 0; a < 4; a++) {
913
- const n = document.createElement("div");
914
- n.className = "gengage-chat-panel-skeleton-block gengage-chat-panel-skeleton-block--row", t.appendChild(n);
915
- }
916
- break;
917
- }
918
- default: {
919
- for (let a = 0; a < 3; a++) {
920
- const n = document.createElement("div");
921
- n.className = "gengage-chat-panel-skeleton-block", t.appendChild(n);
922
- }
923
- break;
924
- }
925
- }
926
- this._panelEl.appendChild(t), this._panelVisible || (this._panelVisible = !0, this._panelEl.classList.add("gengage-chat-panel--visible"), this.root.classList.add("gengage-chat-drawer--with-panel"));
927
- }
928
- /** Update the panel top bar navigation state. */
929
- updatePanelTopBar(e, t, a) {
930
- this._panelTopBar.update(e, t, a);
931
- }
932
- /**
933
- * Hide the panel and clear its content. Always hides — even in force-expanded mode.
934
- * Callers: _hideDrawer (stale panel cleanup), stream onDone (loading skeleton cleanup),
935
- * thread navigation (no snapshot to restore). All require full hide.
936
- */
937
- clearPanel() {
938
- this._panelEl.innerHTML = "", this._panelEl.appendChild(this._panelTopBar.getElement()), this._panelVisible = !1, this._panelCollapsed = !1, this._panelEl.classList.remove("gengage-chat-panel--visible", "gengage-chat-panel--collapsed"), this.root.classList.remove("gengage-chat-drawer--with-panel"), this._dividerEl.classList.add("gengage-chat-panel-divider--hidden");
939
- }
940
- /** Expand panel without locking — user can still toggle via divider. */
941
- expandPanel() {
942
- this._panelCollapsed = !1, this._panelEl.classList.remove("gengage-chat-panel--collapsed"), this._panelVisible || (this._panelVisible = !0, this._panelEl.classList.add("gengage-chat-panel--visible"), this.root.classList.add("gengage-chat-drawer--with-panel"));
943
- }
944
- /** Force the panel to stay expanded (panelMode: 'expanded'). Hides the divider toggle. */
945
- setForceExpanded() {
946
- this._panelForceExpanded = !0, this._panelCollapsed = !1, this._panelEl.classList.remove("gengage-chat-panel--collapsed"), this._panelVisible || (this._panelVisible = !0, this._panelEl.classList.add("gengage-chat-panel--visible"), this.root.classList.add("gengage-chat-drawer--with-panel")), this._dividerEl.classList.add("gengage-chat-panel-divider--hidden");
947
- }
948
- /** Toggle panel between collapsed and expanded. */
949
- togglePanel() {
950
- this._panelForceExpanded || this.setPanelCollapsed(!this._panelCollapsed);
951
- }
952
- /** Whether the panel is currently collapsed by the user. */
953
- isPanelCollapsed() {
954
- return this._panelCollapsed;
955
- }
956
- /** Programmatically set panel collapsed state. */
957
- setPanelCollapsed(e) {
958
- if (this._panelForceExpanded) return;
959
- this._panelCollapsed = e, e ? this._panelEl.classList.add("gengage-chat-panel--collapsed") : this._panelEl.classList.remove("gengage-chat-panel--collapsed");
960
- const t = this._dividerEl.querySelector(".gengage-chat-panel-divider-toggle");
961
- t && (t.textContent = e ? "«" : "»");
962
- }
963
- /** Save panel collapsed state to sessionStorage. */
964
- persistPanelState(e) {
965
- try {
966
- const t = `gengage:panel:${e}`;
967
- this._panelCollapsed ? sessionStorage.setItem(t, "collapsed") : sessionStorage.removeItem(t);
968
- } catch {
969
- }
970
- }
971
- /** Restore panel collapsed state from sessionStorage. */
972
- restorePanelState(e) {
973
- try {
974
- const t = `gengage:panel:${e}`;
975
- sessionStorage.getItem(t) === "collapsed" && (this._panelCollapsed = !0);
976
- } catch {
977
- }
978
- }
979
- /** Re-render thinking steps inside the existing typing indicator container. */
980
- _renderThinkingSteps() {
981
- const e = this.messagesEl.querySelector('[data-typing="true"]');
982
- if (!e) {
983
- this.showTypingIndicator();
984
- return;
985
- }
986
- e.innerHTML = "", this._renderThinkingStepsInto(e), this._scrollToBottom(!1);
987
- }
988
- /** Render the accumulated thinking-step checklist into a container element. */
989
- _renderThinkingStepsInto(e) {
990
- const t = document.createElement("div");
991
- t.className = "gengage-chat-thinking-steps";
992
- for (let a = 0; a < this._thinkingSteps.length; a++) {
993
- const n = document.createElement("div");
994
- n.className = "gengage-chat-thinking-step";
995
- const o = document.createElement("span");
996
- o.className = "gengage-chat-thinking-step-marker", a < this._thinkingSteps.length - 1 ? (o.textContent = "✓", o.classList.add("gengage-chat-thinking-step-marker--done")) : (o.textContent = "●", o.classList.add("gengage-chat-thinking-step-marker--active")), n.appendChild(o);
997
- const s = document.createElement("span");
998
- s.className = "gengage-chat-thinking-step-text", s.textContent = this._thinkingSteps[a], n.appendChild(s), t.appendChild(n);
999
- }
1000
- e.appendChild(t);
1001
- }
1002
- _trapFocus() {
1003
- this.root.addEventListener("keydown", (e) => {
1004
- if (e.key !== "Tab") return;
1005
- const t = this.root.querySelectorAll(
1006
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
1007
- );
1008
- if (t.length === 0) return;
1009
- const a = t[0], n = t[t.length - 1];
1010
- if (!a || !n) return;
1011
- const s = this.root.getRootNode().activeElement ?? document.activeElement;
1012
- e.shiftKey ? s === a && (e.preventDefault(), n.focus()) : s === n && (e.preventDefault(), a.focus());
1013
- });
1014
- }
1015
- _submit() {
1016
- const e = this.inputEl.value.trim(), t = this._pendingAttachment;
1017
- !e && !t || (this.onSend(e, t ?? void 0), this.inputEl.value = "", this.inputEl.style.height = "auto", this.clearAttachment());
1018
- }
1019
- _toggleVoice() {
1020
- if (this._voiceInput)
1021
- if (this._voiceInput.state === "listening") {
1022
- const e = this._voiceInput.stop();
1023
- e.trim() && (this.inputEl.value = e, this._submit());
1024
- } else
1025
- this.inputEl.value = "", this._voiceInput.start();
1026
- }
1027
- /** Lock auto-scroll for 500ms after session history restore to prevent visual jump. */
1028
- lockScrollForRestore() {
1029
- this._scrollLockedUntil = Date.now() + 500;
1030
- }
1031
- /** Scroll to bottom only if user hasn't scrolled up. Force=true always scrolls. */
1032
- _scrollToBottom(e = !1) {
1033
- !e && this._userScrolledUp || !e && Date.now() < this._scrollLockedUntil || requestAnimationFrame(() => {
1034
- this.messagesEl.scrollTop = this.messagesEl.scrollHeight, this._userScrolledUp = !1;
1035
- });
1036
- }
1037
- /** Public method for typewriter ticks — scrolls only if user is near bottom. */
1038
- scrollToBottomIfNeeded() {
1039
- this._scrollToBottom(!1);
1040
- }
1041
- /** Update a bot message's text content in the DOM (e.g. for fallback messages). */
1042
- updateBotMessage(e, t) {
1043
- const a = this.messagesEl.querySelector(`[data-message-id="${CSS.escape(e)}"]`);
1044
- if (!a) return;
1045
- let n = a.querySelector(".gengage-chat-bubble-text");
1046
- n || (n = document.createElement("div"), n.className = "gengage-chat-bubble-text", a.appendChild(n)), n.innerHTML = $(t), this._scrollToBottom(!1);
1047
- }
1048
- /** Mark a message as the first bot message in its thread (for special styling). */
1049
- markFirstBotMessage(e) {
1050
- this._firstBotMessageIds.add(e);
1051
- const t = this.messagesEl.querySelector(`[data-message-id="${CSS.escape(e)}"]`);
1052
- t && t.classList.add("gengage-chat-bubble--first");
1053
- }
1054
- /** Scroll to the first message of the last thread (for restore targeting). */
1055
- scrollToLastThread() {
1056
- const e = this.messagesEl.querySelectorAll("[data-thread-id]");
1057
- if (e.length === 0) {
1058
- this._scrollToBottom(!0);
1059
- return;
1060
- }
1061
- const t = e[e.length - 1].getAttribute("data-thread-id");
1062
- if (!t) {
1063
- this._scrollToBottom(!0);
1064
- return;
1065
- }
1066
- const a = this.messagesEl.querySelector(`[data-thread-id="${CSS.escape(t)}"]`);
1067
- a ? requestAnimationFrame(() => {
1068
- a.scrollIntoView({ block: "start", behavior: "auto" }), this._userScrolledUp = !1;
1069
- }) : this._scrollToBottom(!0);
1070
- }
1071
- /** Set compact input-area chips (search/info/review shortcuts above input). */
1072
- setInputAreaChips(e) {
1073
- if (this._inputChipsEl.innerHTML = "", e.length === 0) {
1074
- this._inputChipsEl.style.display = "none";
1075
- return;
1076
- }
1077
- this._inputChipsEl.style.display = "";
1078
- for (const t of e) {
1079
- const a = document.createElement("button");
1080
- if (a.className = "gengage-chat-input-chip", a.type = "button", t.icon) {
1081
- const o = pe[t.icon];
1082
- if (o) {
1083
- const s = document.createElement("span");
1084
- s.className = "gengage-chat-input-chip-icon", s.innerHTML = o, a.appendChild(s);
1085
- }
1086
- }
1087
- const n = document.createElement("span");
1088
- n.textContent = t.label, a.appendChild(n), a.addEventListener("click", () => t.onAction()), this._inputChipsEl.appendChild(a);
1089
- }
1090
- }
1091
- /** Clear input-area chips. */
1092
- clearInputAreaChips() {
1093
- this._inputChipsEl.innerHTML = "", this._inputChipsEl.style.display = "none";
1094
- }
1095
- setThumbnails(e) {
1096
- this._thumbnailsColumn.setEntries(e), e.length > 0 ? this._thumbnailsColumn.show() : this._thumbnailsColumn.hide();
1097
- }
1098
- hideThumbnails() {
1099
- this._thumbnailsColumn.hide();
1100
- }
1101
- }
1102
- const Rt = `<svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1103
- <rect x="3" y="7" width="18" height="13" rx="3" fill="currentColor" opacity="0.15"/>
1104
- <rect x="3" y="7" width="18" height="13" rx="3" stroke="currentColor" stroke-width="1.5"/>
1105
- <circle cx="9" cy="13" r="1.5" fill="currentColor"/>
1106
- <circle cx="15" cy="13" r="1.5" fill="currentColor"/>
1107
- <path d="M9.5 17C10.3 17.6 11.1 18 12 18C12.9 18 13.7 17.6 14.5 17" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
1108
- <path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
1109
- <circle cx="12" cy="3" r="1" fill="currentColor"/>
1110
- <path d="M1 12V14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
1111
- <path d="M23 12V14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
1112
- </svg>`;
1113
- function Ut(i) {
1114
- const e = document.createElement("div");
1115
- e.className = "gengage-chat-launcher-container";
1116
- const t = document.createElement("div");
1117
- t.className = "gengage-chat-launcher-content-area", e.appendChild(t);
1118
- const a = document.createElement("button");
1119
- if (a.className = "gengage-chat-launcher", a.type = "button", a.setAttribute("aria-label", i.ariaLabel ?? "Open chat"), a.innerHTML = i.svgMarkup ?? Rt, i.tooltip !== void 0) {
1120
- const o = document.createElement("span");
1121
- o.className = "gengage-chat-launcher-tooltip", o.textContent = i.tooltip, a.appendChild(o);
1122
- }
1123
- i.hideMobile && (e.dataset.hideMobile = "1"), i.mobileBreakpoint !== void 0 && (e.dataset.mobileBreakpoint = String(i.mobileBreakpoint)), a.addEventListener("click", i.onClick), e.appendChild(a);
1124
- const n = document.createElement("div");
1125
- return n.className = "gengage-chat-launcher-content-area-bottom", e.appendChild(n), { container: e, button: a, contentArea: t, contentAreaBottom: n };
1126
- }
1127
- function Ht(i) {
1128
- const e = document.createElement("div");
1129
- e.className = "gengage-chat-proactive";
1130
- const t = document.createElement("p");
1131
- t.className = "gengage-chat-proactive-message", t.textContent = i.message, e.appendChild(t);
1132
- const a = document.createElement("div");
1133
- a.className = "gengage-chat-proactive-actions";
1134
- let n = null;
1135
- function o() {
1136
- n !== null && clearTimeout(n), e.remove();
1137
- }
1138
- if (i.actionButtons && i.actionButtons.length > 0)
1139
- for (const r of i.actionButtons) {
1140
- const c = document.createElement("button");
1141
- c.className = "gengage-chat-proactive-accept", c.type = "button", c.textContent = r.title, c.addEventListener("click", () => {
1142
- o(), r.onSelect();
1143
- }), a.appendChild(c);
1144
- }
1145
- else {
1146
- const r = document.createElement("button");
1147
- r.className = "gengage-chat-proactive-accept", r.type = "button", r.textContent = i.acceptLabel ?? "Sohbete Başla", r.addEventListener("click", () => {
1148
- o(), i.onAccept();
1149
- }), a.appendChild(r);
1150
- }
1151
- const s = document.createElement("button");
1152
- s.className = "gengage-chat-proactive-dismiss", s.type = "button", s.textContent = "×", s.setAttribute("aria-label", i.closeAriaLabel ?? "Kapat"), s.addEventListener("click", () => {
1153
- o(), i.onDismiss();
1154
- }), e.appendChild(s), e.appendChild(a);
1155
- const l = i.autoDismissMs ?? 15e3;
1156
- return l > 0 && (n = setTimeout(() => {
1157
- e.parentElement && (e.remove(), i.onDismiss());
1158
- }, l)), requestAnimationFrame(() => e.classList.add("gengage-chat-proactive--visible")), e;
1159
- }
1160
- class Ft {
1161
- constructor(e = {}) {
1162
- this._idleTimer = null, this._maxScrollDepth = 0, this._lastReportedDepth = 0, this._listeners = [], this._destroyed = !1, this._idleThreshold = e.idleThresholdMs ?? 3e4, this._scrollGranularity = e.scrollGranularity ?? 25, this._onActivity = e.onActivity ?? null, this._setup();
1163
- }
1164
- _setup() {
1165
- this._emit({ type: "pageview", timestamp: Date.now() }), this._resetIdleTimer(), this._listen(window, "scroll", () => this._onScroll(), { passive: !0 }), this._listen(window, "mousemove", () => this._resetIdleTimer(), { passive: !0 }), this._listen(window, "keydown", () => this._resetIdleTimer(), { passive: !0 }), this._listen(window, "touchstart", () => this._resetIdleTimer(), { passive: !0 }), this._listen(document, "visibilitychange", () => this._onVisibility());
1166
- }
1167
- _listen(e, t, a, n) {
1168
- e.addEventListener(t, a, n), this._listeners.push([e, t, a]);
1169
- }
1170
- _resetIdleTimer() {
1171
- this._idleTimer && clearTimeout(this._idleTimer), this._idleTimer = setTimeout(() => {
1172
- this._emit({ type: "idle", timestamp: Date.now() });
1173
- }, this._idleThreshold);
1174
- }
1175
- _onScroll() {
1176
- const e = window.scrollY || document.documentElement.scrollTop, t = Math.max(document.documentElement.scrollHeight - window.innerHeight, 1), a = Math.min(100, Math.round(e / t * 100));
1177
- a > this._maxScrollDepth && (this._maxScrollDepth = a);
1178
- const n = Math.floor(a / this._scrollGranularity) * this._scrollGranularity;
1179
- n > this._lastReportedDepth && (this._lastReportedDepth = n, this._emit({
1180
- type: "scroll",
1181
- timestamp: Date.now(),
1182
- data: { depth: n }
1183
- })), this._resetIdleTimer();
1184
- }
1185
- _onVisibility() {
1186
- document.hidden ? (this._emit({ type: "blur", timestamp: Date.now() }), this._idleTimer && clearTimeout(this._idleTimer)) : (this._emit({ type: "focus", timestamp: Date.now() }), this._resetIdleTimer());
1187
- }
1188
- _emit(e) {
1189
- this._destroyed || this._onActivity?.(e);
1190
- }
1191
- /** Current max scroll depth reached (0-100). */
1192
- get maxScrollDepth() {
1193
- return this._maxScrollDepth;
1194
- }
1195
- destroy() {
1196
- this._destroyed = !0, this._idleTimer && clearTimeout(this._idleTimer);
1197
- for (const [e, t, a] of this._listeners)
1198
- e.removeEventListener(t, a);
1199
- this._listeners = [];
1200
- }
1201
- }
1202
- const qt = /* @__PURE__ */ new Set([
1203
- "audio/ogg",
1204
- "audio/mpeg",
1205
- "audio/mp3",
1206
- "audio/wav",
1207
- "audio/webm",
1208
- "audio/aac",
1209
- "audio/mp4"
1210
- ]);
1211
- function Ot(i, e = "audio/ogg") {
1212
- const t = e.split(";")[0].trim();
1213
- if (!qt.has(t)) return null;
1214
- try {
1215
- const a = new Audio(`data:${e};base64,${i}`);
1216
- return a.play().catch(() => {
1217
- }), {
1218
- stop: () => {
1219
- a.pause(), a.currentTime = 0;
1220
- }
1221
- };
1222
- } catch {
1223
- return null;
1224
- }
1225
- }
1226
- class jt {
1227
- constructor(e) {
1228
- this._timer = null, this._destroyed = !1, this._abortController = null, this._sessionStart = Date.now(), this._lastActivity = Date.now(), this._searchesCount = 0, this._actionsCount = 0, this._triggerFireCounts = {}, this._options = e;
1229
- const t = Re(e.middlewareUrl);
1230
- this._endpoint = `${t}/v2/heartbeat`;
1231
- }
1232
- start() {
1233
- this._timer || this._destroyed || this._scheduleNext();
1234
- }
1235
- /** Schedule the next poll after the current one finishes (prevents overlapping polls). */
1236
- _scheduleNext() {
1237
- this._destroyed || (this._timer = setTimeout(() => {
1238
- this._poll().finally(() => this._scheduleNext());
1239
- }, this._options.intervalMs));
1240
- }
1241
- stop() {
1242
- this._timer && (clearTimeout(this._timer), this._timer = null);
1243
- }
1244
- /** Call when the user performs an action (search, click, etc.). */
1245
- recordAction() {
1246
- this._actionsCount++, this._lastActivity = Date.now();
1247
- }
1248
- /** Call when the user performs a search. */
1249
- recordSearch() {
1250
- this._searchesCount++, this._lastActivity = Date.now();
1251
- }
1252
- /** Call on any user interaction to reset idle timer. */
1253
- recordActivity() {
1254
- this._lastActivity = Date.now();
1255
- }
1256
- destroy() {
1257
- this._destroyed = !0, this._abortController?.abort(), this._abortController = null, this.stop();
1258
- }
1259
- async _poll() {
1260
- if (this._destroyed) return;
1261
- const e = Date.now(), t = {
1262
- account_id: this._options.accountId,
1263
- thread_id: this._options.sessionId,
1264
- output_language: this._options.locale.toUpperCase(),
1265
- idle_seconds: (e - this._lastActivity) / 1e3,
1266
- page_type: this._options.getPageType(),
1267
- current_sku: this._options.getCurrentSku(),
1268
- cart_item_count: 0,
1269
- searches_count: this._searchesCount,
1270
- actions_count: this._actionsCount,
1271
- session_duration_seconds: (e - this._sessionStart) / 1e3,
1272
- trigger_fire_counts: { ...this._triggerFireCounts }
1273
- };
1274
- this._abortController = new AbortController();
1275
- try {
1276
- const a = await fetch(this._endpoint, {
1277
- method: "POST",
1278
- headers: { "Content-Type": "application/json" },
1279
- body: JSON.stringify(t),
1280
- signal: this._abortController.signal
1281
- });
1282
- if (this._destroyed || !a.ok) return;
1283
- const n = await a.json();
1284
- if (this._destroyed) return;
1285
- n.action === "message" && n.message && (n.trigger_type && (this._triggerFireCounts[n.trigger_type] = (this._triggerFireCounts[n.trigger_type] ?? 0) + 1), this._options.onMessage(n));
1286
- } catch {
1287
- }
1288
- }
1289
- }
1290
- const Vt = {
1291
- screen_size: "Ekran Boyutu",
1292
- weight: "Ağırlık",
1293
- battery_capacity: "Batarya Kapasitesi",
1294
- battery_life: "Batarya Ömrü",
1295
- storage: "Depolama",
1296
- memory: "Bellek",
1297
- ram: "RAM",
1298
- processor: "İşlemci",
1299
- camera: "Kamera",
1300
- resolution: "Çözünürlük",
1301
- display_type: "Ekran Tipi",
1302
- refresh_rate: "Yenileme Hızı",
1303
- color: "Renk",
1304
- material: "Malzeme",
1305
- dimensions: "Boyutlar",
1306
- warranty: "Garanti",
1307
- connectivity: "Bağlantı",
1308
- water_resistance: "Su Dayanıklılığı",
1309
- operating_system: "İşletim Sistemi",
1310
- brand: "Marka",
1311
- model: "Model",
1312
- price: "Fiyat",
1313
- energy_class: "Enerji Sınıfı",
1314
- noise_level: "Gürültü Seviyesi",
1315
- capacity: "Kapasite",
1316
- power: "Güç",
1317
- voltage: "Voltaj",
1318
- width: "Genişlik",
1319
- height: "Yükseklik",
1320
- depth: "Derinlik"
1321
- };
1322
- function $t(i) {
1323
- return Vt[i] ?? i.replace(/_/g, " ").replace(/^\w/, (e) => e.toUpperCase());
1324
- }
1325
- function Gt(i) {
1326
- const { recommended: e, products: t, attributes: a, highlights: n, specialCases: o, onProductClick: s, i18n: l } = i, r = document.createElement("div");
1327
- r.className = "gengage-chat-comparison";
1328
- const c = document.createElement("h3");
1329
- if (c.className = "gengage-chat-comparison-heading", c.textContent = l?.comparisonHeading ?? "KARŞILAŞTIRMA SONUÇLARI", r.appendChild(c), e) {
1330
- const d = document.createElement("div");
1331
- d.className = "gengage-chat-comparison-recommended";
1332
- const g = document.createElement("div");
1333
- g.className = "gengage-chat-comparison-recommended-label", g.textContent = l?.recommendedChoiceLabel ?? "Önerilen Seçim", d.appendChild(g);
1334
- const u = document.createElement("div");
1335
- if (u.className = "gengage-chat-comparison-recommended-body", e.imageUrl && W(e.imageUrl)) {
1336
- const _ = document.createElement("img");
1337
- _.src = e.imageUrl, _.alt = e.name, _.loading = "lazy", _.addEventListener(
1338
- "error",
1339
- () => {
1340
- _.style.display = "none";
1341
- },
1342
- { once: !0 }
1343
- ), u.appendChild(_);
1344
- }
1345
- const p = document.createElement("div");
1346
- p.className = "gengage-chat-comparison-recommended-info";
1347
- const b = document.createElement("div");
1348
- b.className = "gengage-chat-comparison-recommended-title", b.textContent = e.name, p.appendChild(b);
1349
- const y = document.createElement("div");
1350
- if (y.className = "gengage-chat-comparison-recommended-price", y.textContent = H(e.price, i.pricing), p.appendChild(y), u.appendChild(p), u.addEventListener("click", () => {
1351
- s(e.sku);
1352
- }), u.style.cursor = "pointer", d.appendChild(u), n.length > 0) {
1353
- const _ = document.createElement("div");
1354
- _.className = "gengage-chat-comparison-highlights";
1355
- const I = document.createElement("div");
1356
- I.className = "gengage-chat-comparison-highlights-label", I.textContent = l?.highlightsLabel ?? "Öne Çıkan Özellikler", _.appendChild(I);
1357
- const C = document.createElement("ul");
1358
- for (const T of n) {
1359
- const v = document.createElement("li");
1360
- v.textContent = T, C.appendChild(v);
1361
- }
1362
- _.appendChild(C), d.appendChild(_);
1363
- }
1364
- if (i.recommendedText) {
1365
- const _ = document.createElement("div");
1366
- _.className = "gengage-chat-comparison-recommended-text", _.innerHTML = $(i.recommendedText), d.appendChild(_);
1367
- }
1368
- r.appendChild(d);
1369
- }
1370
- if (i.keyDifferencesHtml) {
1371
- const d = document.createElement("div");
1372
- d.className = "gengage-chat-comparison-key-differences";
1373
- const g = document.createElement("h4");
1374
- g.textContent = l?.keyDifferencesLabel ?? "Temel Farklar", d.appendChild(g);
1375
- const u = document.createElement("div");
1376
- u.className = "gengage-chat-comparison-key-differences-content", u.innerHTML = $(Kt(i.keyDifferencesHtml)), d.appendChild(u), r.appendChild(d);
1377
- }
1378
- if (o && o.length > 0) {
1379
- const d = document.createElement("details");
1380
- d.className = "gengage-chat-comparison-special";
1381
- const g = document.createElement("summary");
1382
- g.textContent = l?.specialCasesLabel ?? "Özel Durumlar İçin", d.appendChild(g);
1383
- const u = document.createElement("ul");
1384
- for (const p of o)
1385
- Wt(u, p);
1386
- u.childElementCount > 0 && d.appendChild(u), r.appendChild(d);
1387
- }
1388
- if (t.length > 0 && a.length > 0) {
1389
- const d = document.createElement("table");
1390
- d.className = "gengage-chat-comparison-table";
1391
- const g = document.createElement("thead"), u = document.createElement("tr"), p = document.createElement("th");
1392
- u.appendChild(p);
1393
- for (const y of t) {
1394
- const _ = document.createElement("th");
1395
- if (y.sku === e?.sku && (_.className = "gengage-chat-comparison-selected"), y.imageUrl && W(y.imageUrl)) {
1396
- const T = document.createElement("img");
1397
- T.src = y.imageUrl, T.alt = y.name, T.loading = "lazy", T.addEventListener(
1398
- "error",
1399
- () => {
1400
- T.style.display = "none";
1401
- },
1402
- { once: !0 }
1403
- ), _.appendChild(T);
1404
- }
1405
- const I = document.createElement("div");
1406
- I.textContent = y.name, _.appendChild(I);
1407
- const C = document.createElement("div");
1408
- C.className = "gengage-chat-comparison-table-price", C.textContent = H(y.price, i.pricing), _.appendChild(C), u.appendChild(_);
1409
- }
1410
- g.appendChild(u), d.appendChild(g);
1411
- const b = document.createElement("tbody");
1412
- for (const y of a) {
1413
- const _ = document.createElement("tr"), I = document.createElement("td");
1414
- I.className = "gengage-chat-comparison-label", I.textContent = $t(y.label), _.appendChild(I);
1415
- for (let C = 0; C < y.values.length; C++) {
1416
- const T = document.createElement("td");
1417
- t[C]?.sku === e?.sku && (T.className = "gengage-chat-comparison-selected"), T.textContent = y.values[C] ?? "", _.appendChild(T);
1418
- }
1419
- b.appendChild(_);
1420
- }
1421
- d.appendChild(b), r.appendChild(d);
1422
- }
1423
- if (i.productActions) {
1424
- const d = document.createElement("div");
1425
- d.className = "gengage-chat-comparison-product-actions";
1426
- for (const g of t)
1427
- if (i.productActions[g.sku]) {
1428
- const p = document.createElement("button");
1429
- p.className = "gengage-chat-comparison-view-btn", p.type = "button", p.textContent = g.name, p.addEventListener("click", () => s(g.sku)), d.appendChild(p);
1430
- }
1431
- d.childElementCount > 0 && r.appendChild(d);
1432
- }
1433
- return r;
1434
- }
1435
- function Kt(i) {
1436
- const e = i.split(`
1437
- `).filter((t) => t.trim());
1438
- return e.length <= 1 ? i : "<ul>" + e.map((t) => `<li>${t.trim()}</li>`).join("") + "</ul>";
1439
- }
1440
- function Wt(i, e) {
1441
- const t = $(e);
1442
- if (!t) return;
1443
- const a = document.createElement("template");
1444
- a.innerHTML = t;
1445
- const n = Array.from(a.content.querySelectorAll("li"));
1446
- if (n.length > 0) {
1447
- for (const s of n) {
1448
- const l = document.createElement("li");
1449
- l.innerHTML = $(s.innerHTML), i.appendChild(l);
1450
- }
1451
- return;
1452
- }
1453
- const o = document.createElement("li");
1454
- Yt(e) ? o.innerHTML = t : o.textContent = e, i.appendChild(o);
1455
- }
1456
- function Yt(i) {
1457
- return /<\/?[a-z][\s\S]*>/i.test(i);
1458
- }
1459
- function Qt(i, e) {
1460
- const t = document.createElement("div");
1461
- t.className = "gengage-chat-review-highlights";
1462
- const a = i.props?.reviews;
1463
- if (!Array.isArray(a) || a.length === 0) {
1464
- const u = document.createElement("div");
1465
- return u.className = "gengage-chat-review-empty", u.textContent = e?.emptyReviewsMessage ?? "Yorum özeti bulunamadı.", t.appendChild(u), t;
1466
- }
1467
- const n = a.filter(
1468
- (u) => u !== null && typeof u == "object"
1469
- ), o = { all: n.length, positive: 0, negative: 0, neutral: 0 };
1470
- for (const u of n)
1471
- u.review_class === "positive" ? o.positive++ : u.review_class === "negative" ? o.negative++ : o.neutral++;
1472
- const s = document.createElement("div");
1473
- s.className = "gengage-chat-review-tabs";
1474
- const l = [{ label: `Tümü (${o.all})`, filter: "all" }];
1475
- o.positive > 0 && l.push({ label: `Olumlu (${o.positive})`, filter: "positive" }), o.negative > 0 && l.push({ label: `Olumsuz (${o.negative})`, filter: "negative" });
1476
- let r = "all";
1477
- const c = document.createElement("div");
1478
- c.className = "gengage-chat-review-items";
1479
- function d() {
1480
- for (; c.firstChild; ) c.removeChild(c.firstChild);
1481
- const u = r === "all" ? n : n.filter((p) => p.review_class === r);
1482
- for (const p of u) {
1483
- const b = document.createElement("article");
1484
- b.className = "gengage-chat-review-item";
1485
- const y = p.review_class;
1486
- if ((y === "positive" || y === "negative" || y === "neutral") && (b.dataset.tone = y), typeof p.review_tag == "string" && p.review_tag.length > 0) {
1487
- const _ = document.createElement("div");
1488
- _.className = "gengage-chat-review-tag", _.textContent = p.review_tag, b.appendChild(_);
1489
- }
1490
- if (typeof p.review_text == "string" && p.review_text.length > 0) {
1491
- const _ = document.createElement("div");
1492
- _.className = "gengage-chat-review-text", _.textContent = p.review_text, b.appendChild(_);
1493
- }
1494
- if (p.review_rating !== void 0 && String(p.review_rating).length > 0) {
1495
- const _ = document.createElement("div");
1496
- _.className = "gengage-chat-review-rating", _.textContent = String(p.review_rating), b.appendChild(_);
1497
- }
1498
- c.appendChild(b);
1499
- }
1500
- }
1501
- for (const u of l) {
1502
- const p = document.createElement("button");
1503
- p.className = "gengage-chat-review-tab", p.type = "button", p.textContent = u.label, u.filter === r && p.classList.add("gengage-chat-review-tab--active"), p.addEventListener("click", () => {
1504
- r = u.filter;
1505
- for (const b of s.querySelectorAll(".gengage-chat-review-tab"))
1506
- b.classList.toggle("gengage-chat-review-tab--active", b === p);
1507
- d();
1508
- }), s.appendChild(p);
1509
- }
1510
- t.appendChild(s);
1511
- const g = /* @__PURE__ */ new Map();
1512
- for (const u of n)
1513
- if (typeof u.review_tag == "string" && u.review_tag.length > 0) {
1514
- const p = g.get(u.review_tag);
1515
- p ? p.count++ : g.set(u.review_tag, { count: 1, sentiment: u.review_class ?? "neutral" });
1516
- }
1517
- if (g.size > 0) {
1518
- const u = document.createElement("div");
1519
- u.className = "gengage-chat-review-pills";
1520
- for (const [p, b] of g) {
1521
- const y = document.createElement("span");
1522
- y.className = "gengage-chat-review-pill", y.dataset.tone = b.sentiment;
1523
- const _ = document.createElement("span");
1524
- _.className = "gengage-chat-review-pill-icon", _.textContent = b.sentiment === "positive" ? "✓" : b.sentiment === "negative" ? "✕" : "●", y.appendChild(_);
1525
- const I = document.createElement("span");
1526
- if (I.textContent = p, y.appendChild(I), b.count > 1) {
1527
- const C = document.createElement("span");
1528
- C.className = "gengage-chat-review-pill-count", C.textContent = String(b.count), y.appendChild(C);
1529
- }
1530
- u.appendChild(y);
1531
- }
1532
- t.appendChild(u);
1533
- }
1534
- return d(), t.appendChild(c), t;
1535
- }
1536
- function Ee(i) {
1537
- const e = i.product.sku;
1538
- if (typeof e == "string" && e.length > 0) return e;
1539
- const t = i.action?.payload;
1540
- return t && typeof t == "object" && "sku" in t && typeof t.sku == "string" ? t.sku : null;
1541
- }
1542
- const Xt = {
1543
- winner: "roleWinner",
1544
- best_value: "roleBestValue",
1545
- best_alternative: "roleBestAlternative"
1546
- };
1547
- function Se(i, e) {
1548
- if (!i || !e) return null;
1549
- const t = Xt[i];
1550
- return t ? e[t] ?? i : i;
1551
- }
1552
- function Jt(i, e) {
1553
- const t = document.createElement("div");
1554
- t.className = "gengage-chat-ai-top-picks";
1555
- const a = i.props?.suggestions ?? [];
1556
- if (a.length === 0) return t;
1557
- const n = document.createElement("h3");
1558
- n.className = "gengage-chat-ai-top-picks-title", n.textContent = e.i18n?.aiTopPicksTitle ?? "Top Picks", t.appendChild(n);
1559
- const o = document.createElement("div");
1560
- o.className = "gengage-chat-ai-top-picks-cards";
1561
- for (let s = 0; s < a.length; s++) {
1562
- const l = a[s], c = l.role === "winner" || s === 0 ? Zt(l, e) : ea(l, e);
1563
- o.appendChild(c);
1564
- }
1565
- return t.appendChild(o), t;
1566
- }
1567
- function Zt(i, e) {
1568
- const t = document.createElement("div");
1569
- t.className = "gengage-chat-ai-toppick-card gengage-chat-ai-toppick-card--winner";
1570
- const a = document.createElement("span");
1571
- a.className = "gengage-chat-ai-toppick-badge", a.textContent = Se(i.role, e.i18n) ?? e.i18n?.roleWinner ?? "TOP MATCH", t.appendChild(a);
1572
- const n = i.product, o = n.discountPercent;
1573
- if (typeof o == "number" && o > 0) {
1574
- const g = document.createElement("span");
1575
- g.className = "gengage-chat-ai-toppick-discount-badge", g.textContent = `%${se(o)}`, t.appendChild(g);
1576
- }
1577
- const s = n.imageUrl;
1578
- if (s && W(s)) {
1579
- const g = document.createElement("img");
1580
- g.className = "gengage-chat-ai-toppick-img", R(g, "src", s), g.alt = n.name ?? "", X(g), t.appendChild(g);
1581
- }
1582
- const l = document.createElement("div");
1583
- l.className = "gengage-chat-ai-toppick-body";
1584
- const r = n.name;
1585
- if (r) {
1586
- const g = document.createElement("div");
1587
- g.className = "gengage-chat-ai-toppick-name", g.textContent = r, l.appendChild(g);
1588
- }
1589
- if (i.reason) {
1590
- const g = document.createElement("div");
1591
- g.className = "gengage-chat-ai-toppick-reason", g.textContent = i.reason, l.appendChild(g);
1592
- }
1593
- if (i.labels && i.labels.length > 0 && l.appendChild(Te(i.labels)), typeof i.expertQualityScore == "number") {
1594
- const g = document.createElement("div");
1595
- g.className = "gengage-chat-ai-toppick-score";
1596
- const u = i.expertQualityScore <= 5 ? 5 : 10;
1597
- g.textContent = `${i.expertQualityScore}/${u}`, l.appendChild(g);
1598
- }
1599
- if (i.reviewHighlight) {
1600
- const g = document.createElement("blockquote");
1601
- g.className = "gengage-chat-ai-toppick-review", g.textContent = i.reviewHighlight, l.appendChild(g);
1602
- }
1603
- const c = n.price, d = n.originalPrice;
1604
- if (c) {
1605
- const g = document.createElement("div");
1606
- if (g.className = "gengage-chat-ai-toppick-price", d && d !== c) {
1607
- const p = document.createElement("span");
1608
- p.className = "gengage-chat-ai-toppick-original-price", p.textContent = H(d, e.pricing), g.appendChild(p), g.appendChild(document.createTextNode(" "));
1609
- }
1610
- const u = document.createElement("span");
1611
- u.textContent = H(c, e.pricing), g.appendChild(u), l.appendChild(g);
1612
- }
1613
- if (t.appendChild(l), i.action) {
1614
- const g = Ee(i), u = n.url ?? "", p = document.createElement("div");
1615
- p.className = "gengage-chat-ai-toppick-spinner", p.style.display = g && e.topPicksLoadingSku === g ? "" : "none", t.appendChild(p);
1616
- const b = document.createElement("button");
1617
- b.className = "gengage-chat-ai-toppick-cta", b.type = "button", b.textContent = e.i18n?.viewDetails ?? "View Details", b.addEventListener("click", () => {
1618
- if (i.action?.type === "findSimilar" && g && e.onProductClick) {
1619
- e.onProductClick({ sku: g, url: u });
1620
- return;
1621
- }
1622
- e.onAction(i.action);
1623
- }), t.appendChild(b);
1624
- }
1625
- return t;
1626
- }
1627
- function ea(i, e) {
1628
- const t = document.createElement("div");
1629
- t.className = "gengage-chat-ai-toppick-card gengage-chat-ai-toppick-card--compact";
1630
- const a = i.product, n = a.discountPercent;
1631
- if (typeof n == "number" && n > 0) {
1632
- const d = document.createElement("span");
1633
- d.className = "gengage-chat-ai-toppick-discount-badge", d.textContent = `%${se(n)}`, t.appendChild(d);
1634
- }
1635
- const o = a.imageUrl;
1636
- if (o && W(o)) {
1637
- const d = document.createElement("img");
1638
- d.className = "gengage-chat-ai-toppick-img", R(d, "src", o), d.alt = a.name ?? "", X(d), t.appendChild(d);
1639
- }
1640
- const s = document.createElement("div");
1641
- s.className = "gengage-chat-ai-toppick-body";
1642
- const l = Se(i.role, e.i18n);
1643
- if (l) {
1644
- const d = document.createElement("div");
1645
- d.className = "gengage-chat-ai-toppick-role", d.textContent = l, s.appendChild(d);
1646
- }
1647
- const r = a.name;
1648
- if (r) {
1649
- const d = document.createElement("div");
1650
- d.className = "gengage-chat-ai-toppick-name", d.textContent = r, s.appendChild(d);
1651
- }
1652
- if (i.reason) {
1653
- const d = document.createElement("div");
1654
- d.className = "gengage-chat-ai-toppick-reason", d.textContent = i.reason, s.appendChild(d);
1655
- }
1656
- i.labels && i.labels.length > 0 && s.appendChild(Te(i.labels));
1657
- const c = a.price;
1658
- if (c) {
1659
- const d = document.createElement("div");
1660
- d.className = "gengage-chat-ai-toppick-price", d.textContent = H(c, e.pricing), s.appendChild(d);
1661
- }
1662
- if (t.appendChild(s), i.action) {
1663
- const d = Ee(i), g = a.url ?? "", u = document.createElement("div");
1664
- u.className = "gengage-chat-ai-toppick-spinner", u.style.display = d && e.topPicksLoadingSku === d ? "" : "none", t.appendChild(u);
1665
- const p = document.createElement("button");
1666
- p.className = "gengage-chat-ai-toppick-cta", p.type = "button", p.textContent = e.i18n?.viewDetails ?? "View Details", p.addEventListener("click", () => {
1667
- if (i.action?.type === "findSimilar" && d && e.onProductClick) {
1668
- e.onProductClick({ sku: d, url: g });
1669
- return;
1670
- }
1671
- e.onAction(i.action);
1672
- }), t.appendChild(p);
1673
- }
1674
- return t;
1675
- }
1676
- function Te(i) {
1677
- const e = document.createElement("div");
1678
- e.className = "gengage-chat-ai-toppick-labels";
1679
- for (const t of i) {
1680
- const a = document.createElement("span");
1681
- a.className = "gengage-chat-ai-toppick-label", a.dataset.sentiment = t.sentiment ?? "neutral", a.textContent = t.label, e.appendChild(a);
1682
- }
1683
- return e;
1684
- }
1685
- function ta(i, e) {
1686
- const t = document.createElement("div");
1687
- t.className = "gengage-chat-grounding-review";
1688
- const a = i.props ?? {}, n = a.title, o = a.reviewCount, s = a.action, l = e.i18n?.groundingReviewCta ?? "Yorumları Oku", r = document.createElement("span");
1689
- r.className = "gengage-chat-grounding-review-icon", r.textContent = "📋", t.appendChild(r);
1690
- const c = document.createElement("div");
1691
- c.className = "gengage-chat-grounding-review-body";
1692
- const d = document.createElement("div");
1693
- if (d.className = "gengage-chat-grounding-review-title", d.textContent = n ?? "Müşteri Yorumları", c.appendChild(d), o) {
1694
- const u = document.createElement("div");
1695
- u.className = "gengage-chat-grounding-review-subtitle";
1696
- const p = e.i18n?.groundingReviewSubtitle ?? "{count} yorum mevcut";
1697
- u.textContent = p.replace("{count}", o), c.appendChild(u);
1698
- }
1699
- t.appendChild(c);
1700
- const g = document.createElement("span");
1701
- return g.className = "gengage-chat-grounding-review-cta", g.textContent = `${l} →`, t.appendChild(g), s && (t.style.cursor = "pointer", t.addEventListener("click", () => e.onAction(s))), t;
1702
- }
1703
- function aa(i) {
1704
- if (i.action.type !== "findSimilar") return i.action;
1705
- const e = i.action.payload && typeof i.action.payload == "object" ? i.action.payload : null, t = typeof e?.input == "string" && e.input.trim() || typeof e?.text == "string" && e.text.trim() || i.name.trim();
1706
- if (!t) return i.action;
1707
- const a = {
1708
- text: t,
1709
- is_suggested_text: 1
1710
- };
1711
- if (typeof e?.sku == "string" && e.sku.trim() && (a.sku = e.sku), Array.isArray(e?.group_skus)) {
1712
- const n = e.group_skus.filter((o) => typeof o == "string" && o.length > 0);
1713
- n.length > 0 && (a.group_skus = n);
1714
- }
1715
- return {
1716
- title: i.action.title,
1717
- type: "inputText",
1718
- payload: a
1719
- };
1720
- }
1721
- function na(i, e) {
1722
- const t = document.createElement("div");
1723
- t.className = "gengage-chat-grouping-cards";
1724
- const a = i.props?.entries ?? [];
1725
- if (a.length === 0) return t;
1726
- for (const n of a) {
1727
- const o = document.createElement("div");
1728
- if (o.className = "gengage-chat-grouping-card", o.style.cursor = "pointer", o.addEventListener("click", () => e.onAction(aa(n))), n.image && W(n.image)) {
1729
- const c = document.createElement("img");
1730
- c.className = "gengage-chat-grouping-card-img", c.src = n.image, c.alt = n.name, c.width = 20, c.height = 20, o.appendChild(c);
1731
- }
1732
- const s = document.createElement("div");
1733
- s.className = "gengage-chat-grouping-card-body";
1734
- const l = document.createElement("span");
1735
- if (l.className = "gengage-chat-grouping-card-name", l.textContent = n.name, s.appendChild(l), n.description) {
1736
- const c = document.createElement("span");
1737
- c.className = "gengage-chat-grouping-card-desc", c.textContent = n.description, s.appendChild(c);
1738
- }
1739
- if (n.labels && n.labels.length > 0) {
1740
- const c = document.createElement("span");
1741
- c.className = "gengage-chat-grouping-card-labels", c.textContent = n.labels.slice(0, 3).join(" · "), s.appendChild(c);
1742
- }
1743
- o.appendChild(s);
1744
- const r = document.createElement("span");
1745
- r.className = "gengage-chat-grouping-card-arrow", r.textContent = "↳", o.insertBefore(r, o.firstChild), t.appendChild(o);
1746
- }
1747
- return t;
1748
- }
1749
- function ia(i, e) {
1750
- const t = document.createElement("div");
1751
- t.className = "gengage-chat-suggested-search-cards";
1752
- const a = i.props?.entries ?? [];
1753
- if (a.length === 0) return t;
1754
- for (const n of a) {
1755
- const o = document.createElement("div");
1756
- if (o.className = "gengage-chat-suggested-search-card", o.style.cursor = "pointer", o.addEventListener("click", () => e.onAction(n.action)), n.image && W(n.image)) {
1757
- const r = document.createElement("img");
1758
- r.className = "gengage-chat-suggested-search-card-img", r.src = n.image, r.alt = n.shortName, r.width = 40, r.height = 40, o.appendChild(r);
1759
- }
1760
- const s = document.createElement("div");
1761
- s.className = "gengage-chat-suggested-search-card-body";
1762
- const l = document.createElement("div");
1763
- if (l.className = "gengage-chat-suggested-search-card-name", l.textContent = n.shortName, s.appendChild(l), n.detailedMessage) {
1764
- const r = document.createElement("div");
1765
- r.className = "gengage-chat-suggested-search-card-desc", r.textContent = n.detailedMessage, s.appendChild(r);
1766
- }
1767
- if (n.whyDifferent) {
1768
- const r = document.createElement("div");
1769
- r.className = "gengage-chat-suggested-search-card-diff", r.textContent = n.whyDifferent, s.appendChild(r);
1770
- }
1771
- o.appendChild(s), t.appendChild(o);
1772
- }
1773
- return t;
1774
- }
1775
- function oa(i, e) {
1776
- const t = document.createElement("button");
1777
- t.className = "gengage-chat-comparison-floating-btn", t.type = "button";
1778
- const a = e.i18n?.compareSelected ?? "Karşılaştır";
1779
- return t.textContent = `${a} (${i.length})`, t.addEventListener("click", () => {
1780
- e.onAction({
1781
- title: a,
1782
- type: "getComparisonTable",
1783
- payload: { sku_list: [...i] }
1784
- });
1785
- }), t;
1786
- }
1787
- function ra(i) {
1788
- const e = document.createElement("div");
1789
- e.className = "gengage-chat-pros-cons";
1790
- const t = i.props?.productName;
1791
- if (t) {
1792
- const o = document.createElement("h4");
1793
- o.className = "gengage-chat-pros-cons-heading", o.textContent = t, e.appendChild(o);
1794
- }
1795
- const a = i.props?.pros, n = i.props?.cons;
1796
- if (a && a.length > 0) {
1797
- const o = document.createElement("ul");
1798
- o.className = "gengage-chat-pros-cons-list";
1799
- for (const s of a) {
1800
- const l = document.createElement("li");
1801
- l.className = "gengage-chat-pros-cons-item";
1802
- const r = document.createElement("span");
1803
- r.className = "gengage-chat-pros-cons-icon gengage-chat-pros-cons-icon--pro", r.textContent = "✓", l.appendChild(r);
1804
- const c = document.createElement("span");
1805
- c.textContent = s, l.appendChild(c), o.appendChild(l);
1806
- }
1807
- e.appendChild(o);
1808
- }
1809
- if (n && n.length > 0) {
1810
- const o = document.createElement("ul");
1811
- o.className = "gengage-chat-pros-cons-list";
1812
- for (const s of n) {
1813
- const l = document.createElement("li");
1814
- l.className = "gengage-chat-pros-cons-item";
1815
- const r = document.createElement("span");
1816
- r.className = "gengage-chat-pros-cons-icon gengage-chat-pros-cons-icon--con", r.textContent = "✗", l.appendChild(r);
1817
- const c = document.createElement("span");
1818
- c.textContent = s, l.appendChild(c), o.appendChild(l);
1819
- }
1820
- e.appendChild(o);
1821
- }
1822
- return e;
1823
- }
1824
- function sa(i, e) {
1825
- const t = i.props?.groups ?? [], a = i.props?.filterTags ?? [], n = document.createElement("div");
1826
- if (n.className = "gengage-chat-categories", t.length === 0) return n;
1827
- const o = document.createElement("div");
1828
- o.className = "gengage-chat-categories-tabs", o.setAttribute("role", "tablist");
1829
- const s = [], l = [], r = (c) => {
1830
- for (let d = 0; d < s.length; d++) {
1831
- const g = d === c;
1832
- s[d].classList.toggle("gengage-chat-categories-tab--active", g), s[d].setAttribute("aria-selected", String(g)), s[d].tabIndex = g ? 0 : -1, l[d].style.display = g ? "" : "none";
1833
- }
1834
- };
1835
- for (let c = 0; c < t.length; c++) {
1836
- const d = t[c], g = `gengage-cat-tab-${c}`, u = `gengage-cat-panel-${c}`, p = document.createElement("button");
1837
- p.className = "gengage-chat-categories-tab", p.type = "button", p.id = g, p.setAttribute("role", "tab"), p.setAttribute("aria-controls", u), p.setAttribute("aria-selected", String(c === 0)), p.tabIndex = c === 0 ? 0 : -1, c === 0 && p.classList.add("gengage-chat-categories-tab--active"), p.textContent = d.groupName, p.addEventListener("click", () => r(c)), p.addEventListener("keydown", (y) => {
1838
- let _ = -1;
1839
- y.key === "ArrowRight" || y.key === "ArrowDown" ? _ = (c + 1) % t.length : y.key === "ArrowLeft" || y.key === "ArrowUp" ? _ = (c - 1 + t.length) % t.length : y.key === "Home" ? _ = 0 : y.key === "End" && (_ = t.length - 1), _ >= 0 && (y.preventDefault(), r(_), s[_].focus());
1840
- }), s.push(p), o.appendChild(p);
1841
- const b = document.createElement("div");
1842
- b.className = "gengage-chat-categories-grid", b.id = u, b.setAttribute("role", "tabpanel"), b.setAttribute("aria-labelledby", g), c !== 0 && (b.style.display = "none");
1843
- for (const y of d.products) {
1844
- const _ = ca(y, e);
1845
- b.appendChild(_);
1846
- }
1847
- l.push(b);
1848
- }
1849
- n.appendChild(o);
1850
- for (const c of l) n.appendChild(c);
1851
- if (a.length > 0) {
1852
- const c = document.createElement("div");
1853
- c.className = "gengage-chat-categories-filter-tags";
1854
- for (const d of a) {
1855
- const g = document.createElement("button");
1856
- g.className = "gengage-chat-categories-filter-tag", g.type = "button", g.textContent = d.title, d.action && g.addEventListener("click", () => {
1857
- e.onAction(d.action);
1858
- }), c.appendChild(g);
1859
- }
1860
- n.appendChild(c);
1861
- }
1862
- return n;
1863
- }
1864
- function ca(i, e) {
1865
- const t = document.createElement("div");
1866
- if (t.className = "gengage-chat-product-card", i.imageUrl && W(i.imageUrl)) {
1867
- const o = document.createElement("img");
1868
- o.className = "gengage-chat-product-card-img", o.src = i.imageUrl, o.alt = i.name, t.appendChild(o);
1869
- }
1870
- const a = document.createElement("div");
1871
- a.className = "gengage-chat-product-card-body";
1872
- const n = document.createElement("div");
1873
- if (n.className = "gengage-chat-product-card-name", n.textContent = i.name, a.appendChild(n), i.price) {
1874
- const o = document.createElement("div");
1875
- o.className = "gengage-chat-product-card-price", o.textContent = i.price, a.appendChild(o);
1876
- }
1877
- return t.appendChild(a), e.onProductSelect && (t.style.cursor = "pointer", t.addEventListener("click", () => {
1878
- e.onProductSelect?.(i);
1879
- })), t;
1880
- }
1881
- function la(i, e) {
1882
- const t = document.createElement("div");
1883
- t.className = "gengage-chat-handoff-notice", t.setAttribute("role", "alert");
1884
- const a = document.createElement("span");
1885
- a.className = "gengage-chat-handoff-notice-icon", a.textContent = "👤", a.setAttribute("aria-hidden", "true"), t.appendChild(a);
1886
- const n = document.createElement("h4");
1887
- n.className = "gengage-chat-handoff-notice-heading", n.textContent = e.i18n?.handoffHeading ?? "Transferring to a support agent", t.appendChild(n);
1888
- const o = i.props?.summary;
1889
- if (o) {
1890
- const s = document.createElement("p");
1891
- s.className = "gengage-chat-handoff-notice-summary", s.textContent = o, t.appendChild(s);
1892
- }
1893
- return t;
1894
- }
1895
- function ga(i, e) {
1896
- const t = i.props?.product ?? i.props, a = document.createElement("div");
1897
- if (a.className = "gengage-chat-product-summary", !t) return a;
1898
- a.style.cursor = "pointer", a.addEventListener("click", (p) => {
1899
- p.target.closest("a") || e.onProductSelect?.(t);
1900
- });
1901
- const n = t.imageUrl;
1902
- if (n && G(n)) {
1903
- const p = document.createElement("div");
1904
- p.className = "gengage-chat-product-summary__image";
1905
- const b = document.createElement("img");
1906
- R(b, "src", n);
1907
- const y = t.name;
1908
- y && (b.alt = y), X(b), p.appendChild(b), a.appendChild(p);
1909
- }
1910
- const o = document.createElement("div");
1911
- o.className = "gengage-chat-product-summary__content";
1912
- const s = t.brand, l = t.name;
1913
- if (l) {
1914
- const p = document.createElement("div");
1915
- p.className = "gengage-chat-product-summary__name";
1916
- const b = s && !l.toLowerCase().startsWith(s.toLowerCase());
1917
- p.textContent = b ? `${s} ${l}` : l, o.appendChild(p);
1918
- }
1919
- const r = t.rating, c = t.reviewCount;
1920
- if (typeof r == "number" && Number.isFinite(r) && r > 0) {
1921
- const p = document.createElement("div");
1922
- if (p.className = "gengage-chat-product-summary__rating", p.textContent = we(ye(r)), typeof c == "number" && Number.isFinite(c)) {
1923
- const b = document.createElement("span");
1924
- b.className = "gengage-chat-product-summary__review-count", b.textContent = ` (${c})`, p.appendChild(b);
1925
- }
1926
- o.appendChild(p);
1927
- }
1928
- const d = t.price, g = t.originalPrice;
1929
- if (d) {
1930
- const p = document.createElement("div");
1931
- if (p.className = "gengage-chat-product-summary__price", g && g !== d) {
1932
- const y = document.createElement("span");
1933
- y.className = "gengage-chat-product-summary__price-original", y.textContent = H(g, e.pricing), p.appendChild(y), p.appendChild(document.createTextNode(" "));
1934
- }
1935
- const b = document.createElement("span");
1936
- b.className = "gengage-chat-product-summary__price-current", b.textContent = H(d, e.pricing), p.appendChild(b), o.appendChild(p);
1937
- }
1938
- a.appendChild(o);
1939
- const u = t.url;
1940
- if (u && G(u)) {
1941
- const p = document.createElement("a");
1942
- p.className = "gengage-chat-product-summary__cta", R(p, "href", u), R(p, "target", "_blank"), R(p, "rel", "noopener noreferrer"), p.textContent = e.i18n?.productCtaLabel ?? "İncele", a.appendChild(p);
1943
- }
1944
- return a;
1945
- }
1946
- function Ie() {
1947
- return window.innerWidth < 768;
1948
- }
1949
- const Le = {
1950
- ActionButtons: ({ element: i, context: e }) => ha(i, e),
1951
- ActionButton: ({ element: i, context: e }) => ua(i, e),
1952
- ProductCard: ({ element: i, context: e }) => ma(i, e),
1953
- ProductDetailsPanel: ({ element: i, context: e }) => fa(i, e),
1954
- ProductGrid: ({ element: i, spec: e, renderElement: t, context: a }) => va(i, e, t, a),
1955
- ReviewHighlights: ({ element: i, context: e }) => Qt(i, { emptyReviewsMessage: e.i18n?.emptyReviewsMessage }),
1956
- ComparisonTable: ({ element: i, context: e }) => _a(i, e),
1957
- AITopPicks: ({ element: i, context: e }) => Jt(i, e),
1958
- GroundingReviewCard: ({ element: i, context: e }) => ta(i, e),
1959
- AIGroupingCards: ({ element: i, context: e }) => na(i, e),
1960
- AISuggestedSearchCards: ({ element: i, context: e }) => ia(i, e),
1961
- ProsAndCons: ({ element: i }) => ra(i),
1962
- CategoriesContainer: ({ element: i, context: e }) => sa(i, e),
1963
- HandoffNotice: ({ element: i, context: e }) => la(i, e),
1964
- ProductSummaryCard: ({ element: i, context: e }) => ga(i, e),
1965
- Divider: ({ element: i }) => wa(i)
1966
- }, Ne = ({
1967
- element: i,
1968
- renderElement: e
1969
- }) => {
1970
- if (!i.children || i.children.length === 0)
1971
- return null;
1972
- const t = document.createElement("div");
1973
- for (const a of i.children) {
1974
- const n = e(a);
1975
- n && t.appendChild(n);
1976
- }
1977
- return t;
1978
- };
1979
- function da() {
1980
- return { ...Le };
1981
- }
1982
- function pa(i, e, t = Le, a = Ne) {
1983
- return Ue({
1984
- spec: i,
1985
- context: e,
1986
- registry: t,
1987
- containerClassName: "gengage-chat-uispec",
1988
- unknownRenderer: a
1989
- });
1990
- }
1991
- function ha(i, e) {
1992
- const t = document.createElement("div");
1993
- t.className = "gengage-chat-action-buttons";
1994
- const a = i.props?.buttons;
1995
- if (a)
1996
- for (const n of a) {
1997
- const o = document.createElement("button");
1998
- o.className = "gengage-chat-action-btn", o.textContent = n.label, o.addEventListener("click", () => e.onAction(n.action)), t.appendChild(o);
1999
- }
2000
- return t;
2001
- }
2002
- function ua(i, e) {
2003
- const t = document.createElement("button");
2004
- t.className = "gengage-chat-action-btn";
2005
- const a = i.props?.label;
2006
- typeof a == "string" && (t.textContent = a);
2007
- const n = i.props?.action;
2008
- return n && t.addEventListener("click", () => e.onAction(n)), t;
2009
- }
2010
- function ma(i, e) {
2011
- const t = document.createElement("div");
2012
- t.className = "gengage-chat-product-card";
2013
- const a = i.props?.product ?? i.props;
2014
- if (!a) return t;
2015
- const n = a.sku;
2016
- n && (t.dataset.sku = n), e.onProductSelect && (t.style.cursor = "pointer", t.addEventListener("click", (v) => {
2017
- v.target.closest(".gengage-chat-product-card-atc") || v.target.closest(".gengage-chat-product-card-cta") || e.onProductSelect?.(a);
2018
- }));
2019
- const o = a.imageUrl;
2020
- if (o && G(o)) {
2021
- const v = document.createElement("div");
2022
- v.className = "gengage-chat-product-card-img-wrapper";
2023
- const m = document.createElement("img");
2024
- m.className = "gengage-chat-product-card-img", m.loading = "lazy", R(m, "src", o);
2025
- const k = a.name;
2026
- k && (m.alt = k), X(m), v.appendChild(m);
2027
- const S = a.discountPercent;
2028
- if (typeof S == "number" && S > 0) {
2029
- const w = document.createElement("span");
2030
- w.className = "gengage-chat-product-card-discount-badge", w.textContent = `%${se(S)}`, v.appendChild(w);
2031
- }
2032
- const h = a.sku;
2033
- if (h) {
2034
- const w = document.createElement("button");
2035
- w.className = "gengage-chat-find-similar-pill", w.type = "button", w.textContent = e.i18n?.findSimilarLabel ?? "Benzerlerini Bul", w.addEventListener("click", (P) => {
2036
- P.stopPropagation(), e.onAction({
2037
- title: e.i18n?.findSimilarLabel ?? "Benzerlerini Bul",
2038
- type: "findSimilar",
2039
- payload: { sku: h, ...o ? { image_url: o } : {} }
2040
- });
2041
- }), v.appendChild(w);
2042
- }
2043
- const f = a.sku;
2044
- if (f && e.onFavoriteToggle) {
2045
- const w = document.createElement("button");
2046
- w.className = "gengage-chat-favorite-btn", w.type = "button", w.setAttribute("aria-label", "Favorilere ekle");
2047
- const P = e.favoritedSkus?.has(f) ?? !1;
2048
- P && w.classList.add("gengage-chat-favorite-btn--active");
2049
- const D = P ? "currentColor" : "none";
2050
- w.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24" fill="${D}" stroke="currentColor" stroke-width="2"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>`, w.addEventListener("click", (E) => {
2051
- E.stopPropagation(), w.classList.toggle("gengage-chat-favorite-btn--active");
2052
- const N = w.querySelector("svg");
2053
- N && N.setAttribute(
2054
- "fill",
2055
- w.classList.contains("gengage-chat-favorite-btn--active") ? "currentColor" : "none"
2056
- ), e.onFavoriteToggle(f, a);
2057
- }), v.appendChild(w);
2058
- }
2059
- t.appendChild(v);
2060
- }
2061
- const s = document.createElement("div");
2062
- s.className = "gengage-chat-product-card-body";
2063
- const l = a.brand;
2064
- if (l) {
2065
- const v = document.createElement("div");
2066
- v.className = "gengage-chat-product-card-brand", v.textContent = l, s.appendChild(v);
2067
- }
2068
- const r = a.name;
2069
- if (r) {
2070
- const v = document.createElement("div");
2071
- v.className = "gengage-chat-product-card-name", v.textContent = r, s.appendChild(v);
2072
- }
2073
- const c = a.rating, d = a.reviewCount;
2074
- if (typeof c == "number" && Number.isFinite(c)) {
2075
- const v = document.createElement("div");
2076
- if (v.className = "gengage-chat-product-card-rating", v.textContent = we(c), typeof d == "number" && Number.isFinite(d)) {
2077
- const m = document.createElement("span");
2078
- m.className = "gengage-chat-product-card-review-count", m.textContent = ` (${d})`, v.appendChild(m);
2079
- }
2080
- s.appendChild(v);
2081
- }
2082
- const g = a.price, u = a.originalPrice;
2083
- if (a.price_async === !0) {
2084
- const v = document.createElement("div");
2085
- v.className = "gengage-chat-product-card-price";
2086
- const m = document.createElement("span");
2087
- m.className = "gengage-chat-price-skeleton", v.appendChild(m), s.appendChild(v), setTimeout(() => {
2088
- m.parentElement && (g ? m.replaceWith(document.createTextNode(H(g, e.pricing))) : m.remove());
2089
- }, 300);
2090
- } else if (g) {
2091
- const v = document.createElement("div");
2092
- if (v.className = "gengage-chat-product-card-price", u && u !== g) {
2093
- const k = document.createElement("span");
2094
- k.className = "gengage-chat-product-card-original-price", k.textContent = H(u, e.pricing), v.appendChild(k), v.appendChild(document.createTextNode(" "));
2095
- }
2096
- const m = document.createElement("span");
2097
- m.textContent = H(g, e.pricing), v.appendChild(m), s.appendChild(v);
2098
- }
2099
- const b = a.inStock;
2100
- if (typeof b == "boolean") {
2101
- const v = document.createElement("div");
2102
- v.className = `gengage-chat-product-card-stock ${b ? "is-in-stock" : "is-out-of-stock"}`, v.textContent = b ? e.i18n?.inStockLabel ?? "Stokta" : e.i18n?.outOfStockLabel ?? "Tükendi", s.appendChild(v);
2103
- }
2104
- const y = a.promotions;
2105
- if (y && y.length > 0) {
2106
- const v = document.createElement("div");
2107
- v.className = "gengage-chat-product-card-promos";
2108
- for (const m of y) {
2109
- const k = document.createElement("span");
2110
- k.className = "gengage-chat-product-card-promo-badge", k.textContent = m, v.appendChild(k);
2111
- }
2112
- s.appendChild(v);
2113
- }
2114
- t.appendChild(s);
2115
- const _ = a.url, I = a.sku, C = i.props?.action;
2116
- if (C) {
2117
- const v = document.createElement("button");
2118
- v.className = "gengage-chat-product-card-cta", v.type = "button", v.textContent = C.title || e.i18n?.productCtaLabel || "Incele", v.addEventListener("click", () => e.onAction(C)), t.appendChild(v);
2119
- } else if (_ && G(_)) {
2120
- const v = document.createElement("a");
2121
- v.className = "gengage-chat-product-card-cta", R(v, "href", _), R(v, "target", "_blank"), R(v, "rel", "noopener noreferrer"), v.textContent = e.i18n?.productCtaLabel ?? "İncele", v.addEventListener("click", (m) => {
2122
- e.onProductClick && I && (m.preventDefault(), e.onProductClick({ sku: I, url: _ }));
2123
- }), t.appendChild(v);
2124
- }
2125
- const T = a.cartCode;
2126
- if (T && I && b !== !1) {
2127
- const v = ke({
2128
- compact: !0,
2129
- label: e.i18n?.addToCartButton ?? "Sepete Ekle",
2130
- onSubmit: (m) => {
2131
- e.onAction({
2132
- title: e.i18n?.addToCartButton ?? "Sepete Ekle",
2133
- type: "addToCart",
2134
- payload: { sku: I, cartCode: T, quantity: m }
2135
- });
2136
- }
2137
- });
2138
- v.classList.add("gengage-chat-product-card-atc"), t.appendChild(v);
2139
- }
2140
- if (e.comparisonSelectMode && I && e.onToggleComparisonSku) {
2141
- const v = document.createElement("div");
2142
- v.className = "gengage-chat-comparison-select-wrapper";
2143
- const m = document.createElement("input");
2144
- return m.type = "checkbox", m.className = "gengage-chat-comparison-checkbox", m.checked = e.comparisonSelectedSkus?.includes(I) ?? !1, m.addEventListener("change", () => {
2145
- e.onToggleComparisonSku?.(I);
2146
- }), v.appendChild(m), v.appendChild(t), v;
2147
- }
2148
- return t;
2149
- }
2150
- function fa(i, e) {
2151
- const t = document.createElement("article");
2152
- t.className = "gengage-chat-product-details-panel";
2153
- const a = i.props?.product ?? i.props;
2154
- if (!a) return t;
2155
- const n = a.images, o = a.imageUrl, s = a.sku;
2156
- if (n && n.length > 1) {
2157
- const h = document.createElement("div");
2158
- h.className = "gengage-chat-product-details-media gengage-chat-product-details-gallery gengage-chat-product-details-img-wrap";
2159
- const f = document.createElement("img");
2160
- f.className = "gengage-chat-product-details-img";
2161
- const w = n.find((M) => G(M));
2162
- w && R(f, "src", w);
2163
- const P = a.name;
2164
- P && (f.alt = P), X(f), h.appendChild(f);
2165
- const D = document.createElement("div");
2166
- D.className = "gengage-chat-product-gallery-thumbs";
2167
- let E = null, N = 0;
2168
- for (let M = 0; M < n.length; M++) {
2169
- const F = n[M];
2170
- if (!F || !G(F)) continue;
2171
- const U = document.createElement("img");
2172
- U.className = "gengage-chat-product-gallery-thumb", M === 0 && (U.classList.add("gengage-chat-product-gallery-thumb--active"), E = U), R(U, "src", F), U.alt = `${P ?? "Product"} ${M + 1}`, U.width = 48, U.height = 48, X(U), U.addEventListener("click", () => {
2173
- R(f, "src", F), E && E.classList.remove("gengage-chat-product-gallery-thumb--active"), U.classList.add("gengage-chat-product-gallery-thumb--active"), E = U, N = M;
2174
- }), D.appendChild(U);
2175
- }
2176
- let B = 0;
2177
- const L = 50;
2178
- if (f.addEventListener(
2179
- "touchstart",
2180
- (M) => {
2181
- B = M.changedTouches[0].clientX;
2182
- },
2183
- { passive: !0 }
2184
- ), f.addEventListener("touchend", (M) => {
2185
- const F = M.changedTouches[0].clientX, U = B - F;
2186
- if (Math.abs(U) < L) return;
2187
- const ne = D.querySelectorAll(".gengage-chat-product-gallery-thumb"), ie = U > 0 ? Math.min(N + 1, ne.length - 1) : Math.max(N - 1, 0);
2188
- ie !== N && ne[ie] && ne[ie].click();
2189
- }), h.appendChild(D), s) {
2190
- const M = document.createElement("button");
2191
- M.className = "gengage-chat-find-similar-pill", M.type = "button", M.textContent = e.i18n?.findSimilarLabel ?? "Benzerlerini Bul", M.addEventListener("click", () => {
2192
- e.onAction({
2193
- title: e.i18n?.findSimilarLabel ?? "Benzerlerini Bul",
2194
- type: "findSimilar",
2195
- payload: { sku: s, ...w ? { image_url: w } : {} }
2196
- });
2197
- }), h.appendChild(M);
2198
- }
2199
- t.appendChild(h);
2200
- } else if (o && G(o)) {
2201
- const h = document.createElement("div");
2202
- h.className = "gengage-chat-product-details-media gengage-chat-product-details-img-wrap";
2203
- const f = document.createElement("img");
2204
- f.className = "gengage-chat-product-details-img", f.loading = "lazy", R(f, "src", o), X(f);
2205
- const w = a.name;
2206
- if (w && (f.alt = w), h.appendChild(f), s) {
2207
- const P = document.createElement("button");
2208
- P.className = "gengage-chat-find-similar-pill", P.type = "button", P.textContent = e.i18n?.findSimilarLabel ?? "Benzerlerini Bul", P.addEventListener("click", () => {
2209
- e.onAction({
2210
- title: e.i18n?.findSimilarLabel ?? "Benzerlerini Bul",
2211
- type: "findSimilar",
2212
- payload: { sku: s, ...o ? { image_url: o } : {} }
2213
- });
2214
- }), h.appendChild(P);
2215
- }
2216
- t.appendChild(h);
2217
- }
2218
- const l = document.createElement("div");
2219
- l.className = "gengage-chat-product-details-content";
2220
- const r = a.name;
2221
- if (r) {
2222
- const h = document.createElement("h3");
2223
- h.className = "gengage-chat-product-details-title", h.textContent = r, l.appendChild(h);
2224
- }
2225
- const c = a.rating, d = a.reviewCount;
2226
- if (typeof c == "number" && Number.isFinite(c)) {
2227
- const h = document.createElement("div");
2228
- if (h.className = "gengage-chat-product-details-rating", h.textContent = `★ ${ye(c).toFixed(1)}`, typeof d == "number" && Number.isFinite(d)) {
2229
- const f = document.createElement("span");
2230
- f.className = "gengage-chat-product-details-review-count", f.textContent = ` (${d})`, h.appendChild(f);
2231
- }
2232
- l.appendChild(h);
2233
- }
2234
- const g = a.price, u = a.originalPrice;
2235
- if (a.price_async === !0) {
2236
- const h = document.createElement("div");
2237
- h.className = "gengage-chat-product-details-price";
2238
- const f = document.createElement("span");
2239
- f.className = "gengage-chat-price-skeleton", h.appendChild(f), l.appendChild(h), setTimeout(() => {
2240
- if (f.parentElement)
2241
- if (g) {
2242
- const w = document.createElement("span");
2243
- w.className = "gengage-chat-product-details-current-price", w.textContent = H(g, e.pricing), f.replaceWith(w);
2244
- } else
2245
- f.remove();
2246
- }, 300);
2247
- } else if (g) {
2248
- const h = document.createElement("div");
2249
- if (h.className = "gengage-chat-product-details-price", u && u !== g) {
2250
- const w = document.createElement("span");
2251
- w.className = "gengage-chat-product-details-original-price", w.textContent = H(u, e.pricing), h.appendChild(w), h.appendChild(document.createTextNode(" "));
2252
- }
2253
- const f = document.createElement("span");
2254
- f.className = "gengage-chat-product-details-current-price", f.textContent = H(g, e.pricing), h.appendChild(f), l.appendChild(h);
2255
- }
2256
- const b = a.inStock;
2257
- if (typeof b == "boolean") {
2258
- const h = document.createElement("div");
2259
- h.className = `gengage-chat-product-details-stock ${b ? "is-in-stock" : "is-out-of-stock"}`, h.textContent = b ? "Stokta var" : "Stokta yok", l.appendChild(h);
2260
- }
2261
- const y = a.promotions;
2262
- if (y && y.length > 0) {
2263
- const h = document.createElement("div");
2264
- h.className = "gengage-chat-product-details-promos";
2265
- for (const f of y) {
2266
- const w = document.createElement("span");
2267
- w.className = "gengage-chat-product-details-promo-badge", w.textContent = f, h.appendChild(w);
2268
- }
2269
- l.appendChild(h);
2270
- }
2271
- const _ = a.variants;
2272
- if (_ && _.length > 0) {
2273
- const h = document.createElement("div");
2274
- h.className = "gengage-chat-product-variants";
2275
- const f = document.createElement("div");
2276
- f.className = "gengage-chat-product-variants-label", f.textContent = e.i18n?.variantsLabel ?? "Varyantlar", h.appendChild(f);
2277
- const w = document.createElement("div");
2278
- w.className = "gengage-chat-product-variants-list";
2279
- for (const P of _) {
2280
- const D = P.name ?? P.variant_name, E = P.sku;
2281
- if (!D && !E) continue;
2282
- const N = document.createElement("button");
2283
- N.className = "gengage-chat-product-variant-btn", N.type = "button";
2284
- const B = D ?? E ?? "", L = P.price;
2285
- L && String(L) !== String(g) ? N.textContent = `${B} - ${H(String(L), e.pricing)}` : N.textContent = B, E && N.addEventListener("click", () => {
2286
- e.onAction({
2287
- title: B,
2288
- type: "launchVariant",
2289
- payload: { sku: E }
2290
- });
2291
- }), w.appendChild(N);
2292
- }
2293
- h.appendChild(w), l.appendChild(h);
2294
- }
2295
- const I = a.sku, C = a.cartCode, T = document.createElement("div");
2296
- T.className = "gengage-chat-product-details-actions";
2297
- const v = i.props?.action;
2298
- if (v) {
2299
- const h = document.createElement("button");
2300
- h.className = "gengage-chat-product-details-cta", h.type = "button", h.textContent = v.title || e.i18n?.productCtaLabel || "Incele", h.addEventListener("click", () => e.onAction(v)), T.appendChild(h);
2301
- } else {
2302
- const h = a.url;
2303
- if (h && G(h)) {
2304
- const f = document.createElement("a");
2305
- f.className = "gengage-chat-product-details-cta", R(f, "href", h), R(f, "target", "_blank"), R(f, "rel", "noopener noreferrer"), f.textContent = e.i18n?.productCtaLabel ?? "Incele", f.addEventListener("click", (w) => {
2306
- e.onProductClick && I && (w.preventDefault(), e.onProductClick({ sku: I, url: h }));
2307
- }), T.appendChild(f);
2308
- }
2309
- }
2310
- if (C && I && b !== !1) {
2311
- const h = ke({
2312
- compact: !1,
2313
- label: e.i18n?.addToCartButton ?? "Sepete Ekle",
2314
- onSubmit: (f) => {
2315
- e.onAction({
2316
- title: e.i18n?.addToCartButton ?? "Sepete Ekle",
2317
- type: "addToCart",
2318
- payload: { sku: I, cartCode: C, quantity: f }
2319
- });
2320
- }
2321
- });
2322
- h.classList.add("gengage-chat-product-details-atc-stepper"), T.appendChild(h);
2323
- }
2324
- const m = a.url;
2325
- if (m && G(m)) {
2326
- let h = function(N, B) {
2327
- const L = document.createElementNS(D, "circle");
2328
- L.setAttribute("cx", N), L.setAttribute("cy", B), L.setAttribute("r", "3"), E.appendChild(L);
2329
- }, f = function(N, B, L, M) {
2330
- const F = document.createElementNS(D, "line");
2331
- F.setAttribute("x1", N), F.setAttribute("y1", B), F.setAttribute("x2", L), F.setAttribute("y2", M), E.appendChild(F);
2332
- };
2333
- const w = document.createElement("button");
2334
- w.className = "gengage-chat-product-details-share", w.type = "button";
2335
- const P = e.i18n?.shareButton ?? "Paylaş";
2336
- w.title = P, w.setAttribute("aria-label", P);
2337
- const D = "http://www.w3.org/2000/svg", E = document.createElementNS(D, "svg");
2338
- E.setAttribute("width", "18"), E.setAttribute("height", "18"), E.setAttribute("viewBox", "0 0 24 24"), E.setAttribute("fill", "none"), E.setAttribute("stroke", "currentColor"), E.setAttribute("stroke-width", "2"), E.setAttribute("stroke-linecap", "round"), E.setAttribute("stroke-linejoin", "round"), h("18", "5"), h("6", "12"), h("18", "19"), f("8.59", "13.51", "15.42", "17.49"), f("15.41", "6.51", "8.59", "10.49"), w.appendChild(E), w.addEventListener("click", async () => {
2339
- const N = a.name;
2340
- try {
2341
- navigator.share ? await navigator.share({ title: N ?? "", url: m }) : navigator.clipboard && (await navigator.clipboard.writeText(m), w.classList.add("gengage-chat-product-details-share--copied"), setTimeout(() => w.classList.remove("gengage-chat-product-details-share--copied"), 1500));
2342
- } catch {
2343
- }
2344
- }), T.appendChild(w);
2345
- }
2346
- T.childElementCount > 0 && l.appendChild(T), t.appendChild(l);
2347
- const k = a.description, S = a.specifications;
2348
- return (k || S) && t.appendChild(ba(k, S, e)), t;
2349
- }
2350
- function ba(i, e, t) {
2351
- const a = document.createElement("div");
2352
- a.className = "gengage-chat-product-detail-tabs";
2353
- const n = document.createElement("div");
2354
- n.className = "gengage-chat-product-detail-tab-bar";
2355
- const o = [];
2356
- if (i) {
2357
- const l = document.createElement("button");
2358
- l.className = "gengage-chat-product-detail-tab gengage-chat-product-detail-tab--active", l.type = "button", l.textContent = t.i18n?.productInfoTab ?? "Ürün Bilgileri", n.appendChild(l);
2359
- const r = document.createElement("div");
2360
- r.className = "gengage-chat-product-detail-tab-panel", r.textContent = i, o.push(r);
2361
- }
2362
- if (e) {
2363
- const l = document.createElement("button");
2364
- l.className = `gengage-chat-product-detail-tab${i ? "" : " gengage-chat-product-detail-tab--active"}`, l.type = "button", l.textContent = t.i18n?.specificationsTab ?? "Teknik Özellikler", n.appendChild(l);
2365
- const r = document.createElement("div");
2366
- r.className = "gengage-chat-product-detail-tab-panel", i && (r.style.display = "none");
2367
- const c = document.createElement("table");
2368
- c.className = "gengage-chat-product-specs-table";
2369
- const d = Array.isArray(e) ? e : Object.entries(e).map(([g, u]) => ({ key: g, value: u }));
2370
- for (const g of d) {
2371
- const u = document.createElement("tr"), p = document.createElement("td");
2372
- p.className = "gengage-chat-product-specs-key", p.textContent = g.key;
2373
- const b = document.createElement("td");
2374
- b.className = "gengage-chat-product-specs-value", b.textContent = g.value, u.appendChild(p), u.appendChild(b), c.appendChild(u);
2375
- }
2376
- r.appendChild(c), o.push(r);
2377
- }
2378
- const s = n.querySelectorAll(".gengage-chat-product-detail-tab");
2379
- s.forEach((l, r) => {
2380
- l.addEventListener("click", () => {
2381
- s.forEach((c) => c.classList.remove("gengage-chat-product-detail-tab--active")), l.classList.add("gengage-chat-product-detail-tab--active"), o.forEach((c, d) => {
2382
- c.style.display = d === r ? "" : "none";
2383
- });
2384
- });
2385
- }), a.appendChild(n);
2386
- for (const l of o) a.appendChild(l);
2387
- return a;
2388
- }
2389
- function Ae(i, e, t) {
2390
- if (!t || t.type === "related") return i;
2391
- const a = i.map((n) => {
2392
- const s = e.elements[n]?.props?.product, l = s ? Number(s.price) : NaN;
2393
- return { id: n, price: Number.isFinite(l) ? l : 1 / 0 };
2394
- });
2395
- return a.sort((n, o) => n.price === 1 / 0 && o.price === 1 / 0 ? 0 : n.price === 1 / 0 ? 1 : o.price === 1 / 0 ? -1 : t.direction === "desc" ? o.price - n.price : n.price - o.price), a.map((n) => n.id);
2396
- }
2397
- function xa(i, e, t, a) {
2398
- const n = Ae(e, t, a), o = /* @__PURE__ */ new Map();
2399
- for (const s of Array.from(i.children)) {
2400
- const l = s.dataset.elementId;
2401
- l && o.set(l, s);
2402
- }
2403
- for (const s of n) {
2404
- const l = o.get(s);
2405
- l && i.appendChild(l);
2406
- }
2407
- }
2408
- function va(i, e, t, a) {
2409
- const n = document.createElement("div");
2410
- n.className = "gengage-chat-product-grid-wrapper";
2411
- const o = i.children ?? [];
2412
- if (o.length > 1 && a?.onSortChange) {
2413
- const c = document.createElement("div");
2414
- c.className = "gengage-chat-product-sort-toolbar";
2415
- const d = a.productSort ?? { type: "related" }, g = [
2416
- { label: a.i18n?.sortRelated ?? "Önerilen", sortState: { type: "related" } },
2417
- { label: a.i18n?.sortPriceAsc ?? "Fiyat ↑", sortState: { type: "price", direction: "asc" } },
2418
- { label: a.i18n?.sortPriceDesc ?? "Fiyat ↓", sortState: { type: "price", direction: "desc" } }
2419
- ];
2420
- for (const u of g) {
2421
- const p = document.createElement("button");
2422
- p.className = "gengage-chat-product-sort-btn", p.type = "button", d.type === u.sortState.type && d.direction === u.sortState.direction && p.classList.add("gengage-chat-product-sort-btn--active"), p.textContent = u.label, p.addEventListener("click", () => {
2423
- a.onSortChange?.(u.sortState), xa(s, o, e, u.sortState), c.querySelectorAll(".gengage-chat-product-sort-btn").forEach((y) => y.classList.remove("gengage-chat-product-sort-btn--active")), p.classList.add("gengage-chat-product-sort-btn--active");
2424
- }), c.appendChild(p);
2425
- }
2426
- if (a.onToggleComparisonSku) {
2427
- const u = document.createElement("div");
2428
- u.className = "gengage-chat-product-sort-separator", c.appendChild(u);
2429
- const p = document.createElement("button");
2430
- p.className = "gengage-chat-comparison-toggle-btn", p.type = "button", a.comparisonSelectMode && p.classList.add("gengage-chat-comparison-toggle-btn--active"), p.textContent = a.i18n?.compareSelected ?? "Karşılaştır", p.addEventListener("click", () => {
2431
- a.onToggleComparisonSku?.("");
2432
- }), c.appendChild(p);
2433
- }
2434
- n.appendChild(c);
2435
- }
2436
- const s = document.createElement("div");
2437
- s.className = "gengage-chat-product-grid";
2438
- const l = Ae(o, e, a?.productSort);
2439
- for (const c of l) {
2440
- if (!e.elements[c]) continue;
2441
- const d = t(c);
2442
- d && (d.dataset.elementId = c, s.appendChild(d));
2443
- }
2444
- if (Ie() && s.classList.add("gengage-chat-product-grid--mobile"), n.appendChild(s), i.props?.endOfList !== !0 && o.length > 0) {
2445
- const c = document.createElement("button");
2446
- c.className = "gengage-chat-product-grid-view-more", c.type = "button", c.textContent = a?.i18n?.viewMoreLabel ?? "Daha Fazla Göster", c.addEventListener("click", () => {
2447
- a?.onAction({ title: "More", type: "moreProductList", payload: {} });
2448
- }), n.appendChild(c);
2449
- }
2450
- if (a?.comparisonSelectMode && a.comparisonSelectedSkus && a.comparisonSelectedSkus.length >= 2) {
2451
- const c = oa(a.comparisonSelectedSkus, a);
2452
- n.appendChild(c);
2453
- }
2454
- return n;
2455
- }
2456
- function _a(i, e) {
2457
- const t = i.props ?? {}, a = t.keyDifferencesHtml, n = t.recommended, o = t.products ?? [], s = t.attributes ?? [], l = t.highlights ?? [], r = t.specialCases, c = t.recommendedText, d = t.winnerHits, g = t.productActions;
2458
- if (!n)
2459
- return document.createElement("div");
2460
- const u = {
2461
- recommended: n,
2462
- products: o,
2463
- attributes: s,
2464
- highlights: l,
2465
- specialCases: r,
2466
- onProductClick: (b) => {
2467
- e.onProductClick?.({ sku: b, url: "" });
2468
- },
2469
- pricing: e.pricing
2470
- };
2471
- c !== void 0 && (u.recommendedText = c), d !== void 0 && (u.winnerHits = d), g !== void 0 && (u.productActions = g), a !== void 0 && (u.keyDifferencesHtml = a), e.i18n && (u.i18n = {
2472
- comparisonHeading: e.i18n.panelTitleComparisonResults,
2473
- recommendedChoiceLabel: e.i18n.recommendedChoiceLabel,
2474
- highlightsLabel: e.i18n.highlightsLabel,
2475
- keyDifferencesLabel: e.i18n.keyDifferencesLabel,
2476
- specialCasesLabel: e.i18n.specialCasesLabel,
2477
- addToCartButton: e.i18n.addToCartButton
2478
- });
2479
- const p = Gt(u);
2480
- return Ie() && p.classList.add("gengage-chat-comparison--mobile"), p;
2481
- }
2482
- function wa(i) {
2483
- const e = document.createElement("hr");
2484
- e.className = "gengage-chat-divider";
2485
- const t = i.props?.label;
2486
- if (t) {
2487
- const a = document.createElement("div");
2488
- a.className = "gengage-chat-divider-wrapper";
2489
- const n = document.createElement("span");
2490
- return n.className = "gengage-chat-divider-label", n.textContent = t, a.appendChild(e), a.appendChild(n), a;
2491
- }
2492
- return e;
2493
- }
2494
- const ya = /* @__PURE__ */ new Set([
2495
- "P",
2496
- "DIV",
2497
- "H1",
2498
- "H2",
2499
- "H3",
2500
- "H4",
2501
- "H5",
2502
- "H6",
2503
- "LI",
2504
- "UL",
2505
- "OL",
2506
- "BLOCKQUOTE",
2507
- "PRE",
2508
- "TABLE",
2509
- "SECTION",
2510
- "HR",
2511
- "FIGURE",
2512
- "FIGCAPTION",
2513
- "DL",
2514
- "DT",
2515
- "DD"
2516
- ]);
2517
- function ka(i) {
2518
- const e = [];
2519
- let t = [];
2520
- for (const a of i)
2521
- a.nodeType === Node.ELEMENT_NODE && ya.has(a.tagName) ? (t.length > 0 && (e.push(t), t = []), e.push([a])) : t.push(a);
2522
- return t.length > 0 && e.push(t), e;
2523
- }
2524
- function Ca(i) {
2525
- for (const e of i)
2526
- for (const t of e)
2527
- if (t.nodeType === Node.ELEMENT_NODE && (t.tagName === "TABLE" || t.querySelector?.("table")))
2528
- return !0;
2529
- return !1;
2530
- }
2531
- function Ea() {
2532
- return typeof window > "u" || typeof window.matchMedia != "function" ? !1 : window.matchMedia("(prefers-reduced-motion: reduce)").matches;
2533
- }
2534
- function Sa(i) {
2535
- const { container: e, html: t, delayMs: a = 30, onTick: n, onComplete: o } = i, s = document.createElement("template");
2536
- s.innerHTML = t;
2537
- const l = ka(s.content.childNodes);
2538
- if (Ea() || l.length <= 1 || Ca(l))
2539
- return e.innerHTML = t, o?.(), { complete() {
2540
- }, cancel() {
2541
- }, isRunning: !1 };
2542
- e.innerHTML = "";
2543
- let r = 0, c = null, d = !0;
2544
- function g() {
2545
- if (!d || r >= l.length) {
2546
- d = !1, o?.();
2547
- return;
2548
- }
2549
- const u = l[r], p = document.createElement("span");
2550
- p.className = "gengage-chat-typewriter-block";
2551
- for (const b of u)
2552
- p.appendChild(b.cloneNode(!0));
2553
- e.appendChild(p), r++, n?.(), r < l.length ? c = setTimeout(g, a) : (d = !1, o?.());
2554
- }
2555
- return g(), {
2556
- complete() {
2557
- d && (c !== null && clearTimeout(c), d = !1, e.innerHTML = t, o?.());
2558
- },
2559
- cancel() {
2560
- c !== null && clearTimeout(c), d = !1;
2561
- },
2562
- get isRunning() {
2563
- return d;
2564
- }
2565
- };
2566
- }
2567
- function he(i) {
2568
- return i !== void 0 && /[\p{L}\p{N}_]/u.test(i);
2569
- }
2570
- function Ta(i) {
2571
- const { container: e, mentions: t, onProductClick: a } = i;
2572
- if (t.length === 0) return;
2573
- const n = /* @__PURE__ */ new Map();
2574
- for (const o of t)
2575
- o.short_name.length !== 0 && n.set(o.short_name.toLowerCase(), o);
2576
- if (n.size !== 0)
2577
- for (const [o, s] of n) {
2578
- const l = document.createTreeWalker(e, NodeFilter.SHOW_TEXT);
2579
- let r = l.nextNode(), c = !1;
2580
- for (; r && !c; ) {
2581
- const d = r.textContent ?? "", g = d.toLowerCase().indexOf(o);
2582
- if (g === -1) {
2583
- r = l.nextNode();
2584
- continue;
2585
- }
2586
- const u = g > 0 ? d[g - 1] : void 0, p = d[g + s.short_name.length];
2587
- if (he(u) || he(p)) {
2588
- r = l.nextNode();
2589
- continue;
2590
- }
2591
- const b = d.slice(0, g), y = d.slice(g, g + s.short_name.length), _ = d.slice(g + s.short_name.length), I = r.parentNode;
2592
- if (!I) {
2593
- r = l.nextNode();
2594
- continue;
2595
- }
2596
- const C = document.createElement("a");
2597
- C.className = "gengage-product-mention", C.textContent = y, C.href = "#", C.addEventListener("click", (T) => {
2598
- T.preventDefault(), a(s.sku);
2599
- }), b && I.insertBefore(document.createTextNode(b), r), I.insertBefore(C, r), _ && I.insertBefore(document.createTextNode(_), r), I.removeChild(r), c = !0;
2600
- }
2601
- }
2602
- }
2603
- const Ia = /* @__PURE__ */ new Set(["search", "info", "review", "similar"]), La = /* @__PURE__ */ new Set([
2604
- "quickAnswer",
2605
- "reviewSummary",
2606
- "searchDiscovery",
2607
- "launchDiscovery",
2608
- "exploreTogetherV2"
2609
- ]);
2610
- function Na(i) {
2611
- return !!(i.icon && Ia.has(i.icon) || i.action?.type && La.has(i.action.type));
2612
- }
2613
- const Pe = "gengage_choice_prompter_dismissed";
2614
- function Aa(i) {
2615
- const e = document.createElement("div");
2616
- e.className = "gengage-chat-choice-prompter";
2617
- const t = document.createElement("div");
2618
- t.className = "gengage-chat-choice-prompter-heading", t.textContent = i.heading, e.appendChild(t);
2619
- const a = document.createElement("div");
2620
- a.className = "gengage-chat-choice-prompter-suggestion", a.textContent = i.suggestion, e.appendChild(a);
2621
- const n = document.createElement("button");
2622
- n.type = "button", n.className = "gengage-chat-choice-prompter-cta", n.textContent = i.ctaLabel, n.addEventListener("click", () => {
2623
- ue(), e.remove(), i.onCtaClick();
2624
- }), e.appendChild(n);
2625
- const o = document.createElement("button");
2626
- return o.type = "button", o.className = "gengage-chat-choice-prompter-dismiss", o.textContent = "×", o.setAttribute("aria-label", "Dismiss"), o.addEventListener("click", () => {
2627
- ue(), e.remove(), i.onDismiss?.();
2628
- }), e.appendChild(o), e;
2629
- }
2630
- function Pa() {
2631
- try {
2632
- return sessionStorage.getItem(Pe) === "1";
2633
- } catch {
2634
- return !1;
2635
- }
2636
- }
2637
- function ue() {
2638
- try {
2639
- sessionStorage.setItem(Pe, "1");
2640
- } catch {
2641
- }
2642
- }
2643
- const Ma = "gengage_assistant", Ba = 3, Y = "sessions", q = "context", V = "payload", O = "favorites";
2644
- function ee(i) {
2645
- return new Promise((e, t) => {
2646
- i.onsuccess = () => e(i.result), i.onerror = () => t(i.error);
2647
- });
2648
- }
2649
- function Z(i) {
2650
- return new Promise((e, t) => {
2651
- i.oncomplete = () => e(), i.onerror = () => t(i.error), i.onabort = () => t(i.error ?? new DOMException("Transaction aborted"));
2652
- });
2653
- }
2654
- class za {
2655
- constructor(e = Ma, t = Ba) {
2656
- this._db = null, this._dbName = e, this._version = t;
2657
- }
2658
- // -------------------------------------------------------------------------
2659
- // Lifecycle
2660
- // -------------------------------------------------------------------------
2661
- async open() {
2662
- return this._db ? this._db : new Promise((e, t) => {
2663
- const a = indexedDB.open(this._dbName, this._version);
2664
- a.onupgradeneeded = (n) => {
2665
- const o = a.result, s = n.oldVersion;
2666
- s < 1 && (o.createObjectStore(Y, { keyPath: ["userId", "appId", "sessionId"] }), o.createObjectStore(q, { keyPath: ["sessionId", "threadId"] }), o.createObjectStore(V, {
2667
- keyPath: ["threadId", "messageId"]
2668
- }).createIndex("threadId", "threadId", { unique: !1 }), o.createObjectStore(O, { keyPath: ["userId", "appId", "sku"] })), s >= 1 && s < 2 && (o.objectStoreNames.contains(Y) && o.deleteObjectStore(Y), o.objectStoreNames.contains(V) && o.deleteObjectStore(V), o.createObjectStore(Y, { keyPath: ["userId", "appId", "sessionId"] }), o.createObjectStore(V, {
2669
- keyPath: ["threadId", "messageId"]
2670
- }).createIndex("threadId", "threadId", { unique: !1 }), o.objectStoreNames.contains(q) || o.createObjectStore(q, { keyPath: ["sessionId", "threadId"] })), s < 3 && (o.objectStoreNames.contains(O) || o.createObjectStore(O, { keyPath: ["userId", "appId", "sku"] }));
2671
- }, a.onsuccess = () => {
2672
- this._db = a.result, e(this._db);
2673
- }, a.onerror = () => t(a.error);
2674
- });
2675
- }
2676
- close() {
2677
- this._db?.close(), this._db = null;
2678
- }
2679
- // -------------------------------------------------------------------------
2680
- // Sessions
2681
- // -------------------------------------------------------------------------
2682
- async saveSession(e) {
2683
- const a = this._requireDb().transaction(Y, "readwrite");
2684
- a.objectStore(Y).put(e), await Z(a);
2685
- }
2686
- async loadSession(e, t, a) {
2687
- const o = this._requireDb().transaction(Y, "readonly");
2688
- return await ee(o.objectStore(Y).get([e, t, a])) ?? null;
2689
- }
2690
- // -------------------------------------------------------------------------
2691
- // Context (compound key: [sessionId, threadId])
2692
- // -------------------------------------------------------------------------
2693
- async saveContext(e) {
2694
- const a = this._requireDb().transaction(q, "readwrite");
2695
- a.objectStore(q).put(e), await Z(a);
2696
- }
2697
- async loadContext(e, t) {
2698
- const n = this._requireDb().transaction(q, "readonly");
2699
- return await ee(n.objectStore(q).get([e, t])) ?? null;
2700
- }
2701
- /**
2702
- * Delete all context entries for a session whose threadId is lexicographically
2703
- * greater than the given threadId. Used during rollback to prune future branches.
2704
- *
2705
- * Thread IDs are UUIDv7 (lexicographically sortable by time), so string
2706
- * comparison is sufficient.
2707
- */
2708
- async deleteContextsAfterThread(e, t) {
2709
- const n = this._requireDb().transaction(q, "readwrite"), s = n.objectStore(q).openCursor();
2710
- await new Promise((l, r) => {
2711
- s.onsuccess = () => {
2712
- const c = s.result;
2713
- if (!c) {
2714
- l();
2715
- return;
2716
- }
2717
- const d = c.value;
2718
- if (d.sessionId === e && d.threadId > t)
2719
- try {
2720
- c.delete();
2721
- } catch {
2722
- }
2723
- c.continue();
2724
- }, s.onerror = () => r(s.error);
2725
- }), await Z(n);
2726
- }
2727
- /**
2728
- * Load the most recent context for a session (latest threadId).
2729
- * Uses lexicographic ordering of UUIDv7 threadIds for chronological sort.
2730
- */
2731
- async loadLatestContext(e) {
2732
- const n = this._requireDb().transaction(q, "readonly").objectStore(q), o = IDBKeyRange.bound([e, ""], [e, "￿"]);
2733
- return new Promise((s, l) => {
2734
- const r = n.openCursor(o, "prev");
2735
- r.onsuccess = () => {
2736
- const c = r.result;
2737
- s(c ? c.value : null);
2738
- }, r.onerror = () => l(r.error);
2739
- });
2740
- }
2741
- // -------------------------------------------------------------------------
2742
- // Payload
2743
- // -------------------------------------------------------------------------
2744
- async savePayload(e) {
2745
- const a = this._requireDb().transaction(V, "readwrite");
2746
- a.objectStore(V).put(e), await Z(a);
2747
- }
2748
- async loadPayload(e, t) {
2749
- const n = this._requireDb().transaction(V, "readonly");
2750
- return await ee(n.objectStore(V).get([e, t])) ?? null;
2751
- }
2752
- async loadPayloadsByThread(e) {
2753
- const n = this._requireDb().transaction(V, "readonly").objectStore(V).index("threadId"), o = [];
2754
- return new Promise((s, l) => {
2755
- const r = n.openCursor(IDBKeyRange.only(e));
2756
- r.onsuccess = () => {
2757
- const c = r.result;
2758
- if (!c) {
2759
- s(o);
2760
- return;
2761
- }
2762
- o.push(c.value), c.continue();
2763
- }, r.onerror = () => l(r.error);
2764
- });
2765
- }
2766
- // -------------------------------------------------------------------------
2767
- // Favorites
2768
- // -------------------------------------------------------------------------
2769
- async saveFavorite(e) {
2770
- const a = this._requireDb().transaction(O, "readwrite");
2771
- a.objectStore(O).put(e), await Z(a);
2772
- }
2773
- async removeFavorite(e, t, a) {
2774
- const o = this._requireDb().transaction(O, "readwrite");
2775
- o.objectStore(O).delete([e, t, a]), await Z(o);
2776
- }
2777
- async loadFavorites(e, t) {
2778
- const n = this._requireDb().transaction(O, "readonly");
2779
- return (await ee(n.objectStore(O).getAll())).filter((s) => s.userId === e && s.appId === t);
2780
- }
2781
- async isFavorite(e, t, a) {
2782
- const o = this._requireDb().transaction(O, "readonly");
2783
- return await ee(o.objectStore(O).get([e, t, a])) !== void 0;
2784
- }
2785
- // -------------------------------------------------------------------------
2786
- // Internal
2787
- // -------------------------------------------------------------------------
2788
- _requireDb() {
2789
- if (!this._db)
2790
- throw new Error("GengageIndexedDB: database not open. Call open() first.");
2791
- return this._db;
2792
- }
2793
- }
2794
- const Da = [
2795
- "comparisonTable",
2796
- "groupList",
2797
- "productDetailsSimilars",
2798
- "productList"
2799
- ];
2800
- class Ra {
2801
- constructor(e) {
2802
- this._lockCount = 1, this._hiddenByUser = !1, this._lastPanelContentType = null, this._chatShown = !1, this._isFavoritesMode = !1, this._lastExtended = !1, this._onChange = e.onChange;
2803
- const t = new Set(Da);
2804
- e.productDetailsInPanel && t.add("productDetails"), this._panelContentTypes = t;
2805
- }
2806
- get isExtended() {
2807
- return this._lockCount === 0 && !this._hiddenByUser && !this._isFavoritesMode && this._lastPanelContentType !== null && this._panelContentTypes.has(this._lastPanelContentType) && this._chatShown;
2808
- }
2809
- unlock() {
2810
- this._lockCount > 0 && this._lockCount--, this._checkStateChange();
2811
- }
2812
- lock() {
2813
- this._lockCount++, this._checkStateChange();
2814
- }
2815
- setHiddenByUser(e) {
2816
- this._hiddenByUser = e, this._checkStateChange();
2817
- }
2818
- setChatShown(e) {
2819
- this._chatShown = e, this._checkStateChange();
2820
- }
2821
- setFavoritesMode(e) {
2822
- this._isFavoritesMode = e, this._checkStateChange();
2823
- }
2824
- setPanelContentType(e) {
2825
- this._lastPanelContentType = e, this._checkStateChange();
2826
- }
2827
- _checkStateChange() {
2828
- const e = this.isExtended;
2829
- e !== this._lastExtended && (this._lastExtended = e, this._onChange(e));
2830
- }
2831
- }
2832
- class Ua {
2833
- constructor(e) {
2834
- this.deps = e, this.snapshots = /* @__PURE__ */ new Map(), this.snapshotTypes = /* @__PURE__ */ new Map(), this.activePanelMessageId = null, this.currentType = null, this.threads = [], this.lastActionType = null;
2835
- }
2836
- /**
2837
- * Deep-clone the current panel content (excluding topbar/thumbnails) and store
2838
- * it keyed by message ID. Called when a stream completes so panel content can
2839
- * be restored later without duplicating the topbar.
2840
- */
2841
- snapshotForMessage(e) {
2842
- const t = this.deps.drawer();
2843
- if (!t?.hasPanelContent() || t.isPanelLoading()) return;
2844
- const a = t.getPanelContentElement();
2845
- if (!a) return;
2846
- const n = a.cloneNode(!0);
2847
- this.snapshots.set(e, n), this.currentType && this.snapshotTypes.set(e, this.currentType);
2848
- }
2849
- /**
2850
- * Attach a click handler to a bot message bubble so clicking it restores
2851
- * the panel content that was active when that message was received.
2852
- */
2853
- attachClickHandler(e) {
2854
- const a = this.deps.shadow()?.querySelector(`[data-message-id="${CSS.escape(e)}"]`);
2855
- a && (a.style.cursor = "pointer", a.addEventListener("click", () => this.restoreForMessage(e)));
2856
- }
2857
- /**
2858
- * Restore the panel content snapshot associated with a given message ID.
2859
- * Highlights the active message and de-highlights the previous one.
2860
- * Also restores the panel topbar title for the snapshot's component type.
2861
- * Returns true if the snapshot was found and restored.
2862
- */
2863
- restoreForMessage(e) {
2864
- const t = this.snapshots.get(e);
2865
- if (!t) return !1;
2866
- const a = this.deps.shadow(), n = this.deps.drawer();
2867
- this.activePanelMessageId && a?.querySelector(`[data-message-id="${CSS.escape(this.activePanelMessageId)}"]`)?.classList.remove("gengage-chat-bubble--active"), a?.querySelector(`[data-message-id="${CSS.escape(e)}"]`)?.classList.add("gengage-chat-bubble--active"), this.activePanelMessageId = e, n?.setPanelContent(t.cloneNode(!0));
2868
- const s = this.snapshotTypes.get(e);
2869
- return s && (this.currentType = s, this.updateTopBar(s)), !0;
2870
- }
2871
- /**
2872
- * Send maximize-pdp / minify-pdp bridge messages with production-matching delays.
2873
- * Called by the extended mode manager when panel extension state changes.
2874
- */
2875
- notifyExtension(e) {
2876
- const t = this.deps.bridge();
2877
- e ? setTimeout(() => t?.send("maximize-pdp", {}), 350) : setTimeout(() => t?.send("minify-pdp", {}), 200);
2878
- }
2879
- /**
2880
- * Derive panel title from UISpec root element type using i18n strings.
2881
- * When the backend provides a `panelTitle` prop, it takes precedence.
2882
- */
2883
- titleForComponent(e, t) {
2884
- if (t) return t;
2885
- const a = this.deps.i18n();
2886
- switch (e) {
2887
- case "ProductDetailsPanel":
2888
- return a.panelTitleProductDetails;
2889
- case "ProductGrid":
2890
- return me(this.lastActionType) ? a.panelTitleSearchResults : a.panelTitleSimilarProducts;
2891
- case "ComparisonTable":
2892
- return a.panelTitleComparisonResults;
2893
- case "AIGroupingCards":
2894
- return a.panelTitleCategories;
2895
- default:
2896
- return "";
2897
- }
2898
- }
2899
- /**
2900
- * Update the panel top bar navigation state and title.
2901
- * When the backend provides a `panelTitle`, it takes precedence over i18n defaults.
2902
- */
2903
- updateTopBar(e, t) {
2904
- const a = this.deps.currentThreadId();
2905
- if (!a) return;
2906
- const n = this.threads.indexOf(a), o = n > 0, s = n >= 0 && n < this.threads.length - 1, l = this.titleForComponent(e, t);
2907
- this.deps.drawer()?.updatePanelTopBar(o, s, l);
2908
- }
2909
- /**
2910
- * Set panel topbar title during loading (before actual panel content arrives).
2911
- * Maps backend pending types to the same i18n titles used for final content.
2912
- */
2913
- updateTopBarForLoading(e) {
2914
- const t = this.deps.i18n(), n = {
2915
- productDetails: t.panelTitleProductDetails,
2916
- productList: me(this.lastActionType) ? t.panelTitleSearchResults : t.panelTitleSimilarProducts,
2917
- comparisonTable: t.panelTitleComparisonResults,
2918
- groupList: t.panelTitleCategories
2919
- }[e] ?? "";
2920
- if (n) {
2921
- const o = this.deps.currentThreadId(), s = o ? this.threads.indexOf(o) : -1, l = s > 0, r = s >= 0 && s < this.threads.length - 1;
2922
- this.deps.drawer()?.updatePanelTopBar(l, r, n);
2923
- }
2924
- }
2925
- /**
2926
- * Map UISpec component types to PanelContentType for the extended mode manager.
2927
- */
2928
- updateExtendedMode(e) {
2929
- const a = {
2930
- ComparisonTable: "comparisonTable",
2931
- AIGroupingCards: "groupList",
2932
- ProductDetailsPanel: "productDetails",
2933
- ProductGrid: "productList"
2934
- }[e] ?? null;
2935
- this.deps.extendedModeManager()?.setPanelContentType(a);
2936
- }
2937
- /** Navigate to the previous panel thread. */
2938
- navigateBack() {
2939
- const e = this.deps.currentThreadId();
2940
- if (!e) return;
2941
- const t = this.threads.indexOf(e);
2942
- if (t > 0) {
2943
- const a = this.threads[t - 1];
2944
- a && this.deps.rollbackToThread(a);
2945
- }
2946
- }
2947
- /** Navigate to the next panel thread. */
2948
- navigateForward() {
2949
- const e = this.deps.currentThreadId();
2950
- if (!e) return;
2951
- const t = this.threads.indexOf(e);
2952
- if (t >= 0 && t < this.threads.length - 1) {
2953
- const a = this.threads[t + 1];
2954
- a && this.deps.rollbackToThread(a);
2955
- }
2956
- }
2957
- /**
2958
- * Panel route shaping:
2959
- * - product details => expanded LHS panel (`ProductDetailsPanel`)
2960
- * - all other panel-routed specs keep their original component types
2961
- */
2962
- toPanelSpec(e) {
2963
- const t = e.elements[e.root];
2964
- if (!t || t.type !== "ProductCard") return e;
2965
- const a = {
2966
- ...t,
2967
- type: "ProductDetailsPanel"
2968
- };
2969
- return {
2970
- root: e.root,
2971
- elements: {
2972
- ...e.elements,
2973
- [e.root]: a
2974
- }
2975
- };
2976
- }
2977
- destroy() {
2978
- this.snapshots.clear(), this.snapshotTypes.clear(), this.activePanelMessageId = null, this.currentType = null, this.threads = [];
2979
- }
2980
- }
2981
- function me(i) {
2982
- return i === "user_message" || i === "inputText";
2983
- }
2984
- class fe {
2985
- constructor(e) {
2986
- this.favoritedSkus = /* @__PURE__ */ new Set(), this._db = e;
2987
- }
2988
- get db() {
2989
- return this._db;
2990
- }
2991
- set db(e) {
2992
- this._db = e;
2993
- }
2994
- /**
2995
- * Persist current session state to IndexedDB.
2996
- * Called after each stream completion (onDone). Non-fatal on failure.
2997
- */
2998
- async persist(e) {
2999
- if (!this._db) return;
3000
- const t = e.messages.map((n) => {
3001
- const o = {
3002
- id: n.id,
3003
- role: n.role,
3004
- timestamp: n.timestamp,
3005
- status: n.status === "streaming" ? "done" : n.status
3006
- };
3007
- return n.threadId !== void 0 && (o.threadId = n.threadId), n.content !== void 0 && (o.content = n.content), n.silent && (o.silent = !0), o;
3008
- }), a = {};
3009
- for (const [n, o] of e.panelSnapshots)
3010
- o.querySelector(".gengage-chat-panel-skeleton") || (a[n] = o.innerHTML);
3011
- await this._db.saveSession({
3012
- userId: e.userId,
3013
- appId: e.appId,
3014
- sessionId: e.sessionId,
3015
- messages: t,
3016
- currentThreadId: e.currentThreadId,
3017
- lastThreadId: e.lastThreadId,
3018
- createdAt: e.chatCreatedAt,
3019
- panelThreads: e.panelThreads.length > 0 ? e.panelThreads : void 0,
3020
- thumbnailEntries: e.thumbnailEntries.length > 0 ? e.thumbnailEntries : void 0,
3021
- panelSnapshotHtml: Object.keys(a).length > 0 ? a : void 0,
3022
- sku: e.sku
3023
- }), e.lastBackendContext && e.currentThreadId && await this._db.saveContext({
3024
- sessionId: e.sessionId,
3025
- threadId: e.currentThreadId,
3026
- context: e.lastBackendContext
3027
- });
3028
- for (const n of e.messages)
3029
- n.uiSpec && n.threadId && await this._db.savePayload({
3030
- threadId: n.threadId,
3031
- messageId: n.id,
3032
- uiSpec: n.uiSpec
3033
- });
3034
- }
3035
- /**
3036
- * Persist session to IndexedDB, then navigate to the URL.
3037
- * Sends an 'openURLInNewTab' bridge message so the host page can intercept
3038
- * (e.g. for SPA routing), then navigates directly as fallback.
3039
- *
3040
- * Legacy compatibility: the prior engine navigated via window.location.href
3041
- * after posting saveSessionAndOpenURL to the iframe. The clean-room runs in
3042
- * the same window (Shadow DOM, not iframe), so it navigates directly.
3043
- */
3044
- async saveAndOpenURL(e, t, a) {
3045
- try {
3046
- await t();
3047
- } catch {
3048
- }
3049
- a?.send("openURLInNewTab", { url: e }), window.location.href = e;
3050
- }
3051
- /**
3052
- * Load a UISpec payload from IndexedDB with retry logic.
3053
- * Returns null if not found or all retries fail.
3054
- */
3055
- async loadPayload(e, t) {
3056
- if (!this._db) return null;
3057
- for (let a = 0; a < 3; a++) {
3058
- try {
3059
- const n = await this._db.loadPayload(e, t);
3060
- if (n) return n.uiSpec;
3061
- } catch {
3062
- }
3063
- a < 2 && await new Promise((n) => setTimeout(n, 100));
3064
- }
3065
- return null;
3066
- }
3067
- /**
3068
- * Load favorited SKUs from IDB into the in-memory set.
3069
- */
3070
- async loadFavorites(e, t) {
3071
- if (this._db)
3072
- try {
3073
- const a = await this._db.loadFavorites(e, t);
3074
- for (const n of a) this.favoritedSkus.add(n.sku);
3075
- } catch {
3076
- }
3077
- }
3078
- /**
3079
- * Toggle a product's favorited state in IDB and in-memory set.
3080
- */
3081
- async toggleFavorite(e, t, a, n) {
3082
- this._db && (this.favoritedSkus.has(a) ? (this.favoritedSkus.delete(a), await this._db.removeFavorite(e, t, a)) : (this.favoritedSkus.add(a), await this._db.saveFavorite({
3083
- userId: e,
3084
- appId: t,
3085
- sku: a,
3086
- name: n.name,
3087
- imageUrl: n.imageUrl,
3088
- price: n.price,
3089
- savedAt: (/* @__PURE__ */ new Date()).toISOString()
3090
- })));
3091
- }
3092
- close() {
3093
- this._db?.close(), this._db = null;
3094
- }
3095
- }
3096
- const Me = "gengage_kvkk_shown", Ha = ["kvkk", "kişisel veri", "kisisel veri"], Fa = /\b6698\b/;
3097
- function le(i) {
3098
- const e = i.toLowerCase();
3099
- return Ha.some((t) => e.includes(t)) || Fa.test(e);
3100
- }
3101
- function be(i) {
3102
- try {
3103
- return localStorage.getItem(`${Me}_${i}`) === "1";
3104
- } catch {
3105
- return !1;
3106
- }
3107
- }
3108
- function qa(i) {
3109
- try {
3110
- localStorage.setItem(`${Me}_${i}`, "1");
3111
- } catch {
3112
- }
3113
- }
3114
- function Oa(i) {
3115
- const t = new DOMParser().parseFromString(i, "text/html").body, a = Array.from(t.children);
3116
- for (const n of a)
3117
- if (le(n.textContent ?? "")) {
3118
- n.remove();
3119
- break;
3120
- }
3121
- return t.innerHTML.trim();
3122
- }
3123
- function ja(i) {
3124
- const e = new DOMParser().parseFromString(i, "text/html");
3125
- for (const t of Array.from(e.body.children))
3126
- if (le(t.textContent ?? ""))
3127
- return t.outerHTML;
3128
- return null;
3129
- }
3130
- const Va = {
3131
- tr: "TURKISH",
3132
- en: "ENGLISH",
3133
- de: "GERMAN",
3134
- fr: "FRENCH"
3135
- };
3136
- function $a(i) {
3137
- return i ? Va[i.toLowerCase().slice(0, 2)] ?? "TURKISH" : "TURKISH";
3138
- }
3139
- const Ga = ':host{all:initial;font-family:var(--gengage-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);font-size:var(--gengage-font-size, 14px)}.gengage-chat-root{position:fixed;z-index:var(--gengage-z-index, 2147483647);--_gengage-chat-offset: var(--gengage-chat-offset, 20px);--_gengage-chat-launcher-bottom: var(--gengage-chat-launcher-bottom, 20px);--_gengage-chat-launcher-right: var(--gengage-chat-launcher-right, 20px);--_gengage-chat-launcher-size: var(--gengage-chat-launcher-size, 56px);--_gengage-chat-drawer-width: var(--gengage-chat-width, 400px);--_gengage-chat-radius: var(--gengage-chat-shell-radius, 12px);--_gengage-chat-header-height: var(--gengage-chat-header-height, 60px);--_gengage-chat-conversation-width: var(--gengage-chat-conversation-width, 396px);--_gengage-chat-panel-min-width: var(--gengage-chat-panel-min-width, 320px);--_gengage-chat-panel-max-width: var(--gengage-chat-panel-max-width, 860px);--_gengage-chat-input-height: var(--gengage-chat-input-height, 48px);--_gengage-chat-shadow: var(--gengage-chat-shadow, 0 12px 40px rgba(15, 23, 42, .18));--_gengage-border-color: var(--gengage-border-color, #e5e7eb);--_gengage-discount-color: var(--gengage-discount-color, #ef4444);--_gengage-success-color: var(--gengage-success-color, #16a34a);--_gengage-text-secondary: var(--gengage-text-secondary, #64748b);--_gengage-qty-btn-size: var(--gengage-qty-btn-size, 28px);--_gengage-qty-btn-size-compact: var(--gengage-qty-btn-size-compact, 24px)}.gengage-chat-launcher-container{position:fixed;bottom:var(--_gengage-chat-launcher-bottom);right:var(--_gengage-chat-launcher-right);display:flex;flex-direction:column;align-items:flex-end;gap:10px;z-index:var(--gengage-z-index, 2147483647)}.gengage-chat-launcher-content-area,.gengage-chat-launcher-content-area-bottom{display:flex;flex-direction:column;align-items:flex-end;gap:8px}.gengage-chat-launcher-content-area:empty,.gengage-chat-launcher-content-area-bottom:empty{display:none}.gengage-chat-root--open .gengage-chat-launcher-content-area,.gengage-chat-root--open .gengage-chat-launcher-content-area-bottom{display:none}.gengage-chat-root--open .gengage-chat-launcher-container{pointer-events:none;opacity:0;transition:opacity .2s ease}.gengage-chat-launcher{width:var(--_gengage-chat-launcher-size);height:var(--_gengage-chat-launcher-size);border-radius:50%;border:none;background:var(--gengage-primary-color, #3b82f6);color:var(--gengage-primary-foreground, #fff);cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 8px 22px #0f172a47;transition:transform .18s cubic-bezier(.2,.8,.2,1),box-shadow .18s ease;position:relative;flex-shrink:0}.gengage-chat-launcher:hover{transform:scale(1.05);box-shadow:0 14px 28px #0f172a47}.gengage-chat-launcher svg{width:24px;height:24px}.gengage-chat-launcher--hidden-mobile{display:none!important}.gengage-chat-launcher-tooltip{position:absolute;right:calc(100% + 12px);top:50%;transform:translateY(-50%);padding:6px 12px;border-radius:8px;background:#1e293b;color:#fff;font-size:13px;font-weight:500;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .2s ease;box-shadow:0 2px 8px #00000026}.gengage-chat-launcher-tooltip:after{content:"";position:absolute;left:100%;top:50%;transform:translateY(-50%);border:5px solid transparent;border-left-color:#1e293b}.gengage-chat-launcher:hover .gengage-chat-launcher-tooltip{opacity:1}.gengage-chat-root--open .gengage-chat-launcher-tooltip{display:none}.gengage-chat-proactive{position:fixed;bottom:calc(var(--_gengage-chat-launcher-bottom) + var(--_gengage-chat-launcher-size) + 14px);right:var(--_gengage-chat-launcher-right);width:280px;padding:16px 18px;border-radius:16px;background:#fff;box-shadow:0 8px 30px #0000001f,0 2px 8px #0000000f;opacity:0;transform:translateY(8px) scale(.96);transition:opacity .25s ease,transform .25s ease;z-index:2147483645}.gengage-chat-proactive--visible{opacity:1;transform:translateY(0) scale(1)}.gengage-chat-proactive-message{margin:0 0 12px;font-size:14px;line-height:1.5;color:#1f2937}.gengage-chat-proactive-actions{display:flex;gap:8px}.gengage-chat-proactive-accept{flex:1;padding:8px 16px;border:none;border-radius:10px;background:var(--gengage-primary-color, #3b82f6);color:#fff;font-size:13px;font-weight:700;font-family:inherit;cursor:pointer;transition:filter .15s ease}.gengage-chat-proactive-accept:hover{filter:brightness(1.08)}.gengage-chat-proactive-dismiss{position:absolute;top:8px;right:8px;width:24px;height:24px;border:none;border-radius:50%;background:transparent;color:#64748b;font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center}.gengage-chat-proactive-dismiss:hover{color:#475569;background:#f1f5f9}.gengage-chat-drawer{position:fixed;top:0;bottom:0;right:0;width:var(--_gengage-chat-drawer-width);max-height:-webkit-fill-available;max-height:100dvh;border-radius:0;background:var(--gengage-background-color, #fff);box-shadow:var(--_gengage-chat-shadow);display:flex;flex-direction:column;overflow:hidden;z-index:var(--gengage-z-index, 2147483647);transform-origin:right center;clip-path:inset(0);transition:clip-path .42s cubic-bezier(.25,.46,.45,.94),opacity .32s ease}.gengage-chat-root--mobile .gengage-chat-launcher-container{right:16px;bottom:calc(16px + env(safe-area-inset-bottom))}.gengage-chat-root--mobile .gengage-chat-drawer{left:0;right:0;bottom:0;width:100%;max-width:none;max-height:-webkit-fill-available;max-height:100dvh;border-radius:16px 16px 0 0;border-top:1px solid rgba(0,0,0,.06);box-shadow:0 -4px 16px #0000001a,0 12px 40px #0f172a2e;padding-bottom:env(safe-area-inset-bottom,0px);clip-path:inset(0);transition:clip-path .42s cubic-bezier(.25,.46,.45,.94),opacity .32s ease}.gengage-chat-root--mobile.gengage-chat-root--open:before{content:"";position:fixed;inset:0;background:#0000001f;z-index:-1;pointer-events:none}.gengage-chat-root--mobile.gengage-chat-root--mobile-half .gengage-chat-drawer{top:auto;height:min(72dvh,620px);max-height:min(72dvh,620px)}.gengage-chat-root--mobile.gengage-chat-root--mobile-full .gengage-chat-drawer{top:0;height:100dvh;max-height:100dvh;border-radius:0;border-top:none}.gengage-chat-root--mobile .gengage-chat-input-area{padding-bottom:calc(10px + env(safe-area-inset-bottom,0px));border-top:1px solid var(--_gengage-border-color, #e5e7eb);transform:translateY(calc(-1 * var(--gengage-keyboard-offset, 0px)))}.gengage-chat-header{display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;min-height:var(--_gengage-chat-header-height);padding:4px 12px;background:var(--gengage-chat-header-bg, #1d2939);color:var(--gengage-chat-header-foreground, #fff);box-shadow:0 4px 20px #00000014,0 0 2px #0000001f;border:none;position:relative;z-index:2}.gengage-chat-header-left{display:flex;align-items:center;gap:10px;min-width:0}.gengage-chat-header-avatar{width:40px;height:40px;border-radius:50%;object-fit:cover;flex-shrink:0;border:2px solid rgba(255,255,255,.15)}.gengage-chat-header-info{display:flex;flex-direction:column;gap:2px;min-width:0}.gengage-chat-header-title-row{display:flex;align-items:center;gap:6px}.gengage-chat-header-title{font-weight:700;font-size:15px;line-height:1.25;letter-spacing:.01em;color:inherit}.gengage-chat-header-badge{display:inline-flex;align-items:center;padding:1px 6px;border-radius:4px;background:var(--gengage-primary-color, #3b82f6);color:#fff;font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;line-height:1.5}.gengage-chat-header-powered{display:flex;align-items:center;gap:4px;font-size:11px;color:#ffffffbf;text-decoration:none;transition:color .15s}.gengage-chat-header-powered:hover{color:#fffc}.gengage-chat-header-powered svg{width:12px;height:12px;opacity:.6}.gengage-chat-header-right{display:flex;align-items:center;gap:4px;flex-shrink:0}.gengage-chat-header-btn{width:32px;height:32px;border-radius:8px;background:transparent;border:1px solid rgba(255,255,255,.12);color:#ffffffb3;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;text-decoration:none;line-height:1;transition:background-color .15s ease,color .15s ease,border-color .15s ease}.gengage-chat-header-btn:hover{background:#ffffff1a;color:#fff;border-color:#ffffff40}.gengage-chat-close{width:32px;height:32px;border-radius:8px;background:transparent;border:1px solid rgba(255,255,255,.12);color:#ffffffb3;font-size:18px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;line-height:1;transition:background-color .15s ease,color .15s ease,border-color .15s ease}.gengage-chat-close:hover{background:#ffffff1a;color:#fff;border-color:#ffffff40}.gengage-chat-body{display:flex;flex:1;overflow:hidden;min-height:0}.gengage-chat-panel{display:none;width:0;overflow:hidden;transition:width .22s cubic-bezier(.2,.72,.2,1)}.gengage-chat-panel--visible{display:flex;flex-direction:column;position:relative;box-sizing:border-box;width:440px;min-width:440px;border-right:1px solid var(--_gengage-border-color);overflow-y:auto;padding:16px;background:#f8fafc}.gengage-chat-panel-divider{display:flex;align-items:center;width:4px;cursor:pointer;background:#e5e7eb;position:relative;flex-shrink:0;transition:background .15s;z-index:2}.gengage-chat-panel-divider:hover{background:#cbd5e1}.gengage-chat-panel-divider--hidden{display:none}.gengage-chat-panel-divider-toggle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:24px;height:48px;border:1px solid var(--_gengage-border-color);border-radius:6px;background:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px;color:var(--_gengage-text-secondary);box-shadow:0 1px 3px #00000014;transition:background .15s,color .15s;padding:0;line-height:1}.gengage-chat-panel-divider-toggle:hover{background:#f1f5f9;color:#334155}.gengage-chat-panel--collapsed{flex:0 0 0px!important;width:0!important;min-width:0!important;max-width:0!important;padding:0!important;border-right:none!important;overflow:hidden}.gengage-chat-panel--collapsed~.gengage-chat-panel-divider{width:0;background:transparent}.gengage-chat-panel--collapsed~.gengage-chat-panel-divider .gengage-chat-panel-divider-toggle{left:0;transform:translateY(-50%)}.gengage-chat-conversation{display:flex;flex-direction:column;flex:1;min-width:0;overflow:hidden;background:var(--gengage-background-color, #fff);position:relative;z-index:1}.gengage-chat-drawer--with-panel{width:auto;background:transparent;box-shadow:none}.gengage-chat-drawer--with-panel .gengage-chat-header{border-radius:0;flex-shrink:0}.gengage-chat-drawer--with-panel .gengage-chat-body{flex:1 1 0;min-height:0;gap:0;padding:0;align-items:stretch}.gengage-chat-drawer--with-panel .gengage-chat-panel--visible{flex:0 0 auto;width:clamp(var(--_gengage-chat-panel-min-width),50vw,var(--_gengage-chat-panel-max-width));min-width:var(--_gengage-chat-panel-min-width);max-width:var(--_gengage-chat-panel-max-width);border-right:none;background:#fff;padding:0 16px 16px;overflow-y:auto;margin:0;border-radius:0;box-shadow:0 8px 32px #0f172a1f,0 2px 8px #0f172a0f;max-height:100dvh}.gengage-chat-drawer--with-panel .gengage-chat-panel-divider{width:0;background:transparent}.gengage-chat-drawer--with-panel .gengage-chat-panel-divider-toggle{width:20px;height:48px;border-radius:10px;background:var(--gengage-primary-color, #3b82f6);color:#fff;border:2px solid #fff;box-shadow:0 2px 8px #0f172a2e;font-size:12px;z-index:10}.gengage-chat-drawer--with-panel .gengage-chat-panel-divider-toggle:hover{background:var(--gengage-primary-hover, #2563eb);color:#fff}.gengage-chat-drawer--with-panel .gengage-chat-conversation{flex:0 0 var(--_gengage-chat-conversation-width);width:var(--_gengage-chat-conversation-width);border-left:none;background:var(--gengage-background-color, #fff);box-shadow:-4px 0 24px #0f172a1f,-1px 0 4px #0f172a0f}.gengage-chat-drawer--with-panel .gengage-chat-messages{padding-right:6px;scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.12) transparent}.gengage-chat-drawer--with-panel .gengage-chat-messages::-webkit-scrollbar{width:0}.gengage-chat-drawer--with-panel:has(.gengage-chat-panel--collapsed){width:var(--_gengage-chat-conversation-width);background:var(--gengage-background-color, #fff);box-shadow:var(--_gengage-chat-shadow)}.gengage-chat-drawer--with-panel .gengage-chat-footer{display:none}.gengage-chat-messages{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:16px;min-height:0;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;touch-action:pan-y}.gengage-chat-messages::-webkit-scrollbar{width:6px}.gengage-chat-messages::-webkit-scrollbar-track{background:transparent}.gengage-chat-messages::-webkit-scrollbar-thumb{background:#0000001f;border-radius:3px}.gengage-chat-messages::-webkit-scrollbar-thumb:hover{background:#0003}.gengage-chat-bubble{max-width:85%;padding:12px 16px;border-radius:12px;line-height:1.5;font-size:14px;font-weight:500;word-wrap:break-word;overflow-wrap:break-word;animation:gengage-chat-msg-in .3s cubic-bezier(.2,.7,.2,1)}@keyframes gengage-chat-msg-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.gengage-chat-bubble--user{align-self:flex-end;background:var(--gengage-primary-color, #3b82f6);color:var(--gengage-primary-foreground, #fff);border-bottom-right-radius:4px}.gengage-chat-bubble--assistant{align-self:flex-start;background:#f3f4f6;color:#1f2937;border-bottom-left-radius:4px;min-width:120px}.gengage-chat-bubble--active{outline:2px solid var(--gengage-primary-color, #3b82f6);outline-offset:-2px}.gengage-chat-bubble--assistant:empty{display:none}.gengage-chat-bubble--assistant .gengage-chat-bubble-text a{color:var(--gengage-primary-color, #2563eb);text-decoration:underline}.gengage-chat-bubble--assistant .gengage-chat-bubble-text a:hover{text-decoration:none}.gengage-chat-bubble--assistant .gengage-chat-bubble-text p{margin:0 0 8px}.gengage-chat-bubble--assistant .gengage-chat-bubble-text p:last-child{margin-bottom:0}.gengage-chat-bubble--assistant .gengage-chat-bubble-text ul,.gengage-chat-bubble--assistant .gengage-chat-bubble-text ol{margin:6px 0;padding-left:20px}.gengage-chat-bubble--assistant .gengage-chat-bubble-text li{margin-bottom:6px;line-height:1.5}.gengage-chat-bubble--assistant .gengage-chat-bubble-text code{background:#0000000f;padding:1px 4px;border-radius:3px;font-size:.9em}.gengage-chat-bubble--assistant .gengage-chat-bubble-text pre{background:#0000000a;padding:8px;border-radius:6px;overflow-x:auto;margin:4px 0}.gengage-chat-bubble--assistant .gengage-chat-bubble-text table{border-collapse:collapse;margin:4px 0;font-size:.9em}.gengage-chat-bubble--assistant .gengage-chat-bubble-text th,.gengage-chat-bubble--assistant .gengage-chat-bubble-text td{border:1px solid var(--_gengage-border-color);padding:4px 8px}.gengage-chat-bubble--assistant .gengage-chat-bubble-text img{max-width:100%;height:auto;border-radius:4px;margin:4px 0}.gengage-chat-bubble--assistant .gengage-chat-bubble-text h1,.gengage-chat-bubble--assistant .gengage-chat-bubble-text h2,.gengage-chat-bubble--assistant .gengage-chat-bubble-text h3,.gengage-chat-bubble--assistant .gengage-chat-bubble-text h4,.gengage-chat-bubble--assistant .gengage-chat-bubble-text h5,.gengage-chat-bubble--assistant .gengage-chat-bubble-text h6{margin:8px 0 4px;line-height:1.3;color:#0f172a}.gengage-chat-bubble--assistant .gengage-chat-bubble-text blockquote{border-left:3px solid var(--_gengage-border-color);padding-left:12px;margin:4px 0;color:var(--_gengage-text-secondary)}.gengage-chat-bubble--first{border-left:3px solid var(--gengage-accent-primary, #3b82f6);padding-left:12px}.gengage-chat-bubble--first .gengage-chat-bubble-text{font-size:15px}.gengage-chat-typing{display:flex;align-items:center;gap:5px;padding:8px 4px;align-self:flex-start;max-width:85%}.gengage-chat-typing:has(.gengage-chat-typing-text),.gengage-chat-typing:has(.gengage-chat-thinking-steps){background:#f3f4f6;padding:10px 14px;border-radius:12px 12px 12px 4px;gap:8px}.gengage-chat-typing-dots{display:flex;align-items:center;gap:5px}.gengage-chat-typing-dots span{width:6px;height:6px;border-radius:50%;background:#94a3b8;display:inline-block;animation:gengage-chat-typing-fade 1.4s ease-in-out infinite}.gengage-chat-typing-dots span:nth-child(2){animation-delay:.2s}.gengage-chat-typing-dots span:nth-child(3){animation-delay:.4s}@keyframes gengage-chat-typing-fade{0%,to{opacity:.25}50%{opacity:1}}.gengage-chat-typing-sparkle{animation:gengage-sparkle-pulse 1.2s infinite}@keyframes gengage-sparkle-pulse{0%,to{opacity:1}50%{opacity:.4}}.gengage-chat-typing-text{font-size:13px;color:var(--_gengage-text-secondary);font-style:italic;flex:1;min-width:0;word-wrap:break-word;overflow-wrap:break-word}.gengage-chat-thinking-steps{display:flex;flex-direction:column;gap:4px;padding:4px 0}.gengage-chat-thinking-step{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--gengage-chat-text-secondary, #666)}.gengage-chat-thinking-step-marker{font-size:12px;width:16px;text-align:center;flex-shrink:0}.gengage-chat-thinking-step-marker--done{color:var(--gengage-chat-success, #4caf50)}.gengage-chat-thinking-step-marker--active{color:var(--gengage-chat-primary, #1976d2);animation:gengage-thinking-pulse 1.5s ease-in-out infinite}@keyframes gengage-thinking-pulse{0%,to{opacity:1}50%{opacity:.4}}.gengage-chat-thinking-step-text{line-height:1.4}.gengage-chat-error{display:flex;align-items:center;justify-content:center;gap:10px;padding:10px 14px;border-radius:10px;background:#fef2f2;color:#991b1b;font-size:13px;text-align:center;border:1px solid #fecaca}.gengage-chat-error-retry{flex-shrink:0;padding:4px 12px;border:1px solid #fca5a5;border-radius:6px;background:#fff;color:#991b1b;font-size:12px;font-weight:500;cursor:pointer;transition:background .15s}.gengage-chat-error-retry:hover{background:#fee2e2}.gengage-chat-input-area{display:flex;flex-wrap:wrap;align-items:center;gap:0;padding:8px 12px;border-top:1px solid var(--_gengage-border-color);background:var(--gengage-background-color, #fff)}.gengage-chat-input-pill{display:flex;align-items:center;gap:4px;flex:1;min-width:0;height:44px;background:#f3f4f6;border:1px solid var(--_gengage-border-color);border-radius:30px;padding:2px 8px;overflow:hidden;transition:border-color .2s ease,box-shadow .2s ease}.gengage-chat-input-pill:focus-within{border-color:var(--gengage-primary-color, #3b82f6);box-shadow:0 0 0 2px #3b82f626}.gengage-chat-input{flex:1;min-width:0;min-height:40px;max-height:120px;padding:0 6px 0 14px;border:none;border-radius:0;font-size:14px;font-family:inherit;line-height:1.4;align-content:center;outline:none;background:transparent;color:#1f2937;resize:none;overflow-y:hidden}@media(max-width:767px){.gengage-chat-input{max-height:40px;white-space:nowrap;overflow:hidden}.gengage-chat-send{width:44px;height:44px;min-width:44px}}.gengage-chat-input::placeholder{font-size:14px;color:#6b7280}.gengage-chat-send{width:36px;height:36px;min-width:36px;padding:0;border:none;border-radius:50%;background:var(--gengage-primary-color, #3b82f6);color:var(--gengage-primary-foreground, #fff);font-weight:700;font-size:0;font-family:inherit;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background-color .2s cubic-bezier(.4,0,.2,1),box-shadow .2s ease,transform .15s ease;box-shadow:0 2px 4px #0000001f}.gengage-chat-send:hover{filter:brightness(.92);transform:translateY(-1px);box-shadow:0 4px 8px #0000002e}.gengage-chat-send:active{transform:translateY(0);box-shadow:0 1px 2px #0000001f}.gengage-chat-send svg{width:18px;height:18px}.gengage-chat-send:disabled{background:#d1d5db;box-shadow:none;cursor:not-allowed}.gengage-chat-footer{padding:4px 10px;text-align:center;font-size:10px;color:#6b7280;border-top:1px solid #f1f5f9;background:var(--gengage-background-color, #fff)}.gengage-chat-uispec{width:100%}.gengage-chat-uispec:empty{display:none}.gengage-chat-uispec>*{animation:gengage-chat-widget-enter .16s cubic-bezier(.2,.7,.2,1) both}@keyframes gengage-chat-widget-enter{0%{opacity:0;transform:translateY(5px) scale(.99)}to{opacity:1;transform:translateY(0) scale(1)}}.gengage-chat-action-buttons{display:flex;gap:8px;padding:6px 0 4px;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}.gengage-chat-action-buttons::-webkit-scrollbar{display:none}.gengage-chat-action-btn{flex:0 0 auto;padding:8px 16px;border:none;border-radius:999px;background:var(--gengage-primary-color, #3b82f6);color:var(--gengage-primary-foreground, #fff);font-size:13px;font-weight:600;line-height:1.25;font-family:inherit;cursor:pointer;white-space:nowrap;transition:filter .15s ease,transform .1s ease}.gengage-chat-action-btn:hover{filter:brightness(.92)}.gengage-chat-action-btn:active{transform:scale(.97)}.gengage-chat-product-card{position:relative;border:1px solid #eee;border-radius:16px;overflow:hidden;background:#fff;width:160px;min-width:160px;max-width:160px;box-shadow:0 2px 8px #0000000f;transition:transform .1s ease,box-shadow .2s ease}.gengage-chat-product-card:hover{transform:translateY(-2px);box-shadow:0 4px 16px #0000001f}.gengage-chat-product-card-img{width:100%;height:120px;object-fit:contain;display:block;background:#fff;padding:8px;box-sizing:border-box}.gengage-chat-product-card-body{display:flex;flex-direction:column;gap:4px;padding:8px 10px 10px;text-align:center}.gengage-chat-product-card-name{font-size:13px;font-weight:600;color:#1f2937;line-height:1.35;margin-bottom:0;min-height:0;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.gengage-chat-product-card-brand{font-size:10px;color:#666}.gengage-chat-product-card-rating{font-size:11px;color:#f59e0b;line-height:1}.gengage-chat-product-card-review-count{color:#64748b;font-size:10px}.gengage-chat-product-card-price{display:flex;align-items:baseline;justify-content:center;gap:4px;font-size:16px;font-weight:800;color:#0f172a}.gengage-chat-product-card-original-price{text-decoration:line-through;color:#64748b;font-weight:400;font-size:12px}.gengage-chat-price-skeleton{display:inline-block;width:80px;height:16px;background:linear-gradient(90deg,#e2e8f0 25%,#f1f5f9,#e2e8f0 75%);background-size:200% 100%;animation:gengage-skeleton-price-pulse 1.5s ease-in-out infinite;border-radius:4px;vertical-align:middle}@keyframes gengage-skeleton-price-pulse{0%{background-position:200% 0}to{background-position:-200% 0}}.gengage-chat-product-card-cta{display:block;padding:8px 10px;text-align:center;background:transparent;color:var(--gengage-primary-color, #3b82f6);text-decoration:none;font-size:12px;font-weight:700;letter-spacing:.01em;border-top:1px solid #f1f5f9;transition:color .15s ease,background .15s ease}.gengage-chat-product-card-cta:hover{color:var(--gengage-primary-color, #0b24d6);background:#f8fafc}.gengage-chat-product-card-cta:active{background:#f1f5f9}.gengage-chat-product-summary{display:flex;align-items:center;gap:12px;padding:10px 12px;border:1px solid #e5e7eb;border-radius:12px;background:#fff;cursor:pointer;transition:background .15s,box-shadow .15s;margin:4px 0}.gengage-chat-product-summary:hover{background:#f9fafb;box-shadow:0 1px 4px #0000000f}.gengage-chat-product-summary__image{flex-shrink:0;width:64px;height:64px;border-radius:8px;overflow:hidden;border:1px solid #f3f4f6;background:#f9fafb}.gengage-chat-product-summary__image img{width:100%;height:100%;object-fit:cover;display:block}.gengage-chat-product-summary__content{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.gengage-chat-product-summary__name{font-size:13px;font-weight:500;line-height:1.3;color:#111827;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.gengage-chat-product-summary__rating{font-size:11px;color:#f59e0b;line-height:1}.gengage-chat-product-summary__review-count{color:#6b7280;font-size:11px}.gengage-chat-product-summary__price{font-size:13px;font-weight:600;color:#111827;line-height:1;margin-top:2px}.gengage-chat-product-summary__price-original{text-decoration:line-through;color:#6b7280;font-weight:400;font-size:11px}.gengage-chat-product-summary__price-current{color:var(--gengage-primary-color, #111827)}.gengage-chat-product-summary__cta{flex-shrink:0;font-size:12px;font-weight:500;color:var(--gengage-primary-color, #2563eb);text-decoration:none;padding:4px 10px;border-radius:8px;transition:background .15s;white-space:nowrap}.gengage-chat-product-summary__cta:hover{background:#0000000a}.gengage-chat-product-summary__cta:focus-visible{outline:2px solid var(--gengage-primary-color, #2563eb);outline-offset:2px}.gengage-chat-product-grid{display:flex;gap:12px;overflow-x:auto;padding:8px 0;-webkit-overflow-scrolling:touch;scrollbar-width:none;scroll-snap-type:x proximity;min-height:180px}.gengage-chat-product-grid>*{scroll-snap-align:start;flex:0 0 auto}.gengage-chat-product-grid::-webkit-scrollbar{display:none}.gengage-chat-review-highlights{padding:2px 0 6px}.gengage-chat-review-item{border:1px solid var(--_gengage-border-color);border-radius:12px;padding:10px 12px;background:#fff}.gengage-chat-review-item[data-tone=positive]{border-color:#bbf7d0;background:#f0fdf4}.gengage-chat-review-item[data-tone=negative]{border-color:#fecaca;background:#fef2f2}.gengage-chat-review-tag{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--_gengage-text-secondary);margin-bottom:4px}.gengage-chat-review-text{font-size:13px;line-height:1.45;color:#1f2937}.gengage-chat-review-rating{margin-top:6px;font-size:12px;font-weight:700;color:#0f172a}.gengage-chat-review-empty{font-size:12px;color:var(--_gengage-text-secondary)}.gengage-chat-review-tabs{display:flex;gap:6px;margin-bottom:10px}.gengage-chat-review-tab{padding:6px 14px;border:1px solid var(--_gengage-border-color);border-radius:999px;background:#fff;color:var(--_gengage-text-secondary);font-size:12px;font-weight:600;font-family:inherit;cursor:pointer;transition:background .15s,border-color .15s}.gengage-chat-review-tab:hover{background:#f8fafc}.gengage-chat-review-tab--active{background:#f1f5f9;border-color:#94a3b8;color:#0f172a}.gengage-chat-review-pills{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px}.gengage-chat-review-pill{display:flex;align-items:center;gap:6px;padding:6px 10px;border:1px solid var(--_gengage-border-color);border-radius:8px;background:#fff;font-size:12px;color:#334155;box-shadow:0 1px 2px #0000000a}.gengage-chat-review-pill[data-tone=positive]{border-color:#bbf7d0}.gengage-chat-review-pill[data-tone=negative]{border-color:#fecaca}.gengage-chat-review-pill-icon{font-size:11px;font-weight:700}.gengage-chat-review-pill[data-tone=positive] .gengage-chat-review-pill-icon{color:#16a34a}.gengage-chat-review-pill[data-tone=negative] .gengage-chat-review-pill-icon{color:#dc2626}.gengage-chat-review-pill-count{font-size:10px;font-weight:700;background:#f1f5f9;color:var(--_gengage-text-secondary);border-radius:4px;padding:1px 5px}.gengage-chat-review-items{display:grid;gap:10px}.gengage-chat-divider{border:none;border-top:1px solid var(--_gengage-border-color);margin:8px 0}.gengage-chat-divider-wrapper{display:flex;align-items:center;gap:8px;margin:8px 0}.gengage-chat-divider-wrapper hr{flex:1;border:none;border-top:1px solid var(--_gengage-border-color);margin:0}.gengage-chat-divider-label{font-size:11px;color:#6b7280;white-space:nowrap}.gengage-chat--overlay .gengage-chat-drawer{position:fixed;inset:0;width:100%;max-width:480px;max-height:100%;margin:0 auto;border-radius:0;animation:gengage-chat-overlay-in .24s cubic-bezier(.2,.72,.2,1)}.gengage-chat--overlay:before{content:"";position:fixed;inset:0;background:#00000073;z-index:-1}@keyframes gengage-chat-overlay-in{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}.gengage-chat-panel-skeleton{display:flex;flex-direction:column;gap:14px;padding:6px 0}.gengage-chat-panel-skeleton-block{height:110px;border-radius:10px;background:linear-gradient(90deg,#e5e7eb 25%,#f3f4f6,#e5e7eb 75%);background-size:200% 100%;animation:gengage-panel-shimmer 1.4s infinite}@keyframes gengage-panel-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.gengage-chat-panel-skeleton-block--image{height:200px;border-radius:8px;margin-bottom:12px}.gengage-chat-panel-skeleton-block--text{height:16px;border-radius:4px;margin-bottom:8px}.gengage-chat-panel-skeleton-block--text:nth-child(3){width:80%}.gengage-chat-panel-skeleton-block--text:nth-child(4){width:60%}.gengage-chat-panel-skeleton-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}.gengage-chat-panel-skeleton-block--card{height:120px;border-radius:8px}.gengage-chat-panel-skeleton-block--row{height:32px;border-radius:4px;margin-bottom:4px}.gengage-chat-panel .gengage-chat-product-card{width:100%;max-width:100%;min-width:0;display:flex;flex-direction:column;border-radius:12px;border:1px solid var(--_gengage-border-color);box-shadow:0 1px 4px #0000000f;overflow:hidden;padding:0}.gengage-chat-panel .gengage-chat-product-card:hover{transform:translateY(-2px);box-shadow:0 4px 12px #0000001a;border-color:#d1d5db}.gengage-chat-panel .gengage-chat-product-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));overflow-x:visible;gap:12px;min-height:auto;padding:4px 0}.gengage-chat-panel .gengage-chat-product-card-img{width:100%;height:160px;border-radius:0;object-fit:contain;background:#fafafa;padding:12px;box-sizing:border-box}.gengage-chat-panel .gengage-chat-product-card-body{padding:10px 12px 12px;text-align:left;gap:4px}.gengage-chat-panel .gengage-chat-product-card-name{min-height:0;margin-bottom:2px;font-size:13px;-webkit-line-clamp:2;line-clamp:2}.gengage-chat-panel .gengage-chat-product-card-price{justify-content:flex-start;font-size:15px}.gengage-chat-panel .gengage-chat-product-card-cta{display:block;padding:10px 12px;text-align:center;border-top:1px solid #f1f5f9;border-radius:0;background:transparent;color:var(--gengage-primary-color, #3b82f6);font-weight:700;font-size:13px}.gengage-chat-product-details-panel{display:flex;flex-direction:column;gap:12px;width:100%;background:#fff;border:1px solid var(--_gengage-border-color);border-radius:16px;padding:14px;box-sizing:border-box}.gengage-chat-product-details-media{border:1px solid #f1f5f9;border-radius:12px;background:#fafafa;padding:12px;display:flex;flex-direction:column;align-items:center}.gengage-chat-product-details-img{width:100%;height:auto;max-height:300px;object-fit:contain;border-radius:8px}.gengage-chat-product-details-content{display:flex;flex-direction:column;gap:8px;min-width:0}.gengage-chat-product-details-title{margin:0;font-size:17px;font-weight:700;line-height:1.3;color:#0f172a}.gengage-chat-product-details-rating{display:inline-flex;align-items:center;gap:4px;width:fit-content;padding:3px 8px;border-radius:999px;background:#fff7ed;color:#9a3412;font-size:13px;font-weight:700}.gengage-chat-product-details-review-count{color:#7c2d12;font-weight:600}.gengage-chat-product-details-price{display:flex;align-items:baseline;gap:6px}.gengage-chat-product-details-original-price{font-size:14px;color:#64748b;text-decoration:line-through}.gengage-chat-product-details-current-price{font-size:22px;font-weight:800;line-height:1.1;color:#0f172a}.gengage-chat-product-details-stock{width:fit-content;padding:4px 10px;border-radius:999px;font-size:12px;font-weight:700}.gengage-chat-product-details-stock.is-in-stock{background:#dcfce7;color:#166534}.gengage-chat-product-details-stock.is-out-of-stock{background:#fee2e2;color:#991b1b}.gengage-chat-product-details-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:4px}.gengage-chat-product-details-cta{display:inline-flex;align-items:center;justify-content:center;min-height:40px;padding:0 20px;border-radius:999px;border:none;text-decoration:none;background:var(--gengage-primary-color, #3b82f6);color:var(--gengage-primary-foreground, #fff);font-size:14px;font-weight:700;cursor:pointer;transition:filter .14s ease,transform .12s ease}.gengage-chat-product-details-cta:hover{filter:brightness(1.05);transform:translateY(-1px)}.gengage-chat-product-details-cta:active{transform:translateY(1px)}.gengage-chat-product-details-atc{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:10px 20px;border:none;border-radius:10px;background:var(--_gengage-success-color);color:#fff;font-size:14px;font-weight:700;font-family:inherit;cursor:pointer;transition:filter .12s ease,transform .12s ease}.gengage-chat-product-details-atc:hover{filter:brightness(1.08);transform:translateY(-1px)}.gengage-chat-product-details-atc:active{transform:translateY(1px)}.gengage-chat-product-detail-tabs{margin-top:4px;border-top:1px solid var(--_gengage-border-color);padding-top:12px}.gengage-chat-product-detail-tab-bar{display:flex;gap:0;border-bottom:2px solid var(--_gengage-border-color);margin-bottom:12px}.gengage-chat-product-detail-tab{flex:1;padding:8px 12px;border:none;background:transparent;color:var(--_gengage-text-secondary);font-size:13px;font-weight:600;font-family:inherit;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-2px;transition:color .15s,border-color .15s}.gengage-chat-product-detail-tab:hover{color:#334155}.gengage-chat-product-detail-tab--active{color:var(--gengage-primary-color, #3b82f6);border-bottom-color:var(--gengage-primary-color, #3b82f6)}.gengage-chat-product-detail-tab-panel{font-size:13px;line-height:1.6;color:#374151}.gengage-chat-product-specs-table{width:100%;border-collapse:collapse;font-size:13px}.gengage-chat-product-specs-table tr:nth-child(2n){background:#f8fafc}.gengage-chat-product-specs-key{padding:6px 10px;font-weight:600;color:#475569;white-space:nowrap;border-bottom:1px solid #f1f5f9;width:40%}.gengage-chat-product-specs-value{padding:6px 10px;color:#1f2937;border-bottom:1px solid #f1f5f9}.gengage-chat-product-card-atc{position:absolute;bottom:42px;right:6px;opacity:0;transition:opacity .15s ease;z-index:1}.gengage-chat-product-card:hover .gengage-chat-product-card-atc{opacity:1}.gengage-chat-drawer.gengage-chat-drawer--hidden{clip-path:inset(0 0 0 100%);opacity:0;pointer-events:none;box-shadow:none}.gengage-chat-root--mobile .gengage-chat-drawer.gengage-chat-drawer--hidden{clip-path:inset(100% 0 0 0);opacity:0;pointer-events:none;box-shadow:none}@media(max-width:900px){.gengage-chat-drawer--with-panel .gengage-chat-panel--visible{width:clamp(280px,calc(100vw - var(--_gengage-chat-conversation-width)),560px);max-width:560px}}.gengage-chat-attachment-preview{display:flex;align-items:center;gap:8px;padding:6px 10px;background:#f3f4f6;border:1px solid var(--_gengage-border-color);border-radius:8px;width:100%;box-sizing:border-box}.gengage-chat-attachment-preview--hidden{display:none}.gengage-chat-attachment-preview-thumb{width:40px;height:40px;border-radius:4px;object-fit:cover;flex-shrink:0}.gengage-chat-attachment-name{flex:1;font-size:12px;color:#4b5563;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gengage-chat-attachment-remove{background:none;border:none;cursor:pointer;font-size:18px;color:#6b7280;padding:0 4px;line-height:1;flex-shrink:0}.gengage-chat-attachment-remove:hover{color:#ef4444}.gengage-chat-attach-btn{background:none;border:none;cursor:pointer;padding:6px;line-height:1;flex-shrink:0;display:flex;align-items:center;justify-content:center;border-radius:50%;color:#6b7280;transition:color .15s,background .15s}.gengage-chat-attach-btn:hover{color:#4b5563;background:#0000000d}.gengage-chat-attach-btn svg{width:20px;height:20px}.gengage-chat-mic-btn{background:none;border:none;cursor:pointer;padding:6px;line-height:1;flex-shrink:0;display:flex;align-items:center;justify-content:center;border-radius:50%;color:#6b7280;transition:color .15s,background .15s}.gengage-chat-mic-btn:hover{color:#4b5563;background:#0000000d}.gengage-chat-mic-btn svg{width:20px;height:20px}.gengage-chat-mic-btn--active{color:#ef4444;animation:gengage-mic-pulse 1.2s ease-in-out infinite}.gengage-chat-mic-btn--active:hover{color:#dc2626}@keyframes gengage-mic-pulse{0%,to{transform:scale(1);opacity:1}50%{transform:scale(1.15);opacity:.8}}.gengage-chat-input-area--dragover{outline:2px dashed var(--gengage-primary-color, #3b82f6);outline-offset:-2px;background:#eff6ff}.gengage-chat-attachment-thumb{width:120px;max-width:100%;height:auto;border-radius:8px;margin-bottom:6px;display:block}@media(max-width:768px){.gengage-chat-panel-divider{display:none}.gengage-chat-drawer--with-panel{left:0;right:0;width:100%;border-radius:0}.gengage-chat-drawer--with-panel .gengage-chat-body{flex-direction:column}.gengage-chat-drawer--with-panel .gengage-chat-panel--visible{width:100%;min-width:0;max-width:none;max-height:30dvh;border-right:none;border-bottom:1px solid var(--_gengage-border-color);padding:0 12px 12px;margin:0;border-radius:0;box-shadow:none}.gengage-chat-drawer--with-panel .gengage-chat-conversation{width:100%;flex:1;border-left:none}.gengage-chat-panel .gengage-chat-product-card{grid-template-columns:84px 1fr}.gengage-chat-panel .gengage-chat-product-card-cta{grid-column:1 / -1;width:100%}.gengage-chat-product-details-panel{padding:12px;gap:12px}.gengage-chat-product-details-media{min-height:140px}.gengage-chat-product-details-title{font-size:15px}.gengage-chat-product-details-current-price{font-size:20px}.gengage-chat-product-grid{scroll-snap-type:x mandatory}.gengage-chat-product-card{width:280px;min-width:280px;scroll-snap-align:center}.gengage-chat-product-card-img{height:180px}}@media(max-width:480px){.gengage-chat-drawer{position:fixed;inset:0;width:100%;max-height:100%;border-radius:0}.gengage-chat-bubble{max-width:100%}}.gengage-chat-kvkk-banner{display:flex;align-items:flex-start;gap:8px;padding:10px 14px;background:#fffbeb;border-bottom:1px solid #fde68a;font-size:12px;line-height:1.5;color:#92400e}.gengage-chat-kvkk-content{flex:1;min-width:0}.gengage-chat-kvkk-content a{color:#b45309;text-decoration:underline}.gengage-chat-kvkk-dismiss{flex-shrink:0;width:20px;height:20px;border:none;background:transparent;color:#92400e;font-size:16px;cursor:pointer;padding:0;line-height:1}.gengage-chat-comparison{padding:16px}.gengage-chat-comparison-heading{font-size:14px;font-weight:700;letter-spacing:.05em;color:#0f172a;margin:0 0 16px}.gengage-chat-comparison-recommended{border:1px solid var(--_gengage-border-color);border-radius:12px;padding:16px;background:#fff;box-shadow:0 1px 3px #0000000f;margin-bottom:12px}.gengage-chat-comparison-recommended-label{font-size:12px;font-weight:700;color:#16a34a;text-transform:uppercase;letter-spacing:.04em;margin-bottom:12px}.gengage-chat-comparison-recommended-body{display:flex;gap:12px;align-items:flex-start}.gengage-chat-comparison-recommended-body img{width:80px;height:80px;object-fit:contain;border-radius:8px;background:#f8fafc}.gengage-chat-comparison-recommended-info{flex:1;min-width:0}.gengage-chat-comparison-recommended-title{font-size:14px;font-weight:600;color:#0f172a;margin-bottom:4px}.gengage-chat-comparison-recommended-price{font-size:16px;font-weight:700;color:#0f172a}.gengage-chat-comparison-highlights{margin-top:12px;padding-top:12px;border-top:1px solid #f1f5f9}.gengage-chat-comparison-highlights-label{font-size:12px;font-weight:600;color:var(--_gengage-text-secondary);margin-bottom:6px}.gengage-chat-comparison-highlights ul{margin:0;padding-left:18px;font-size:13px;color:#334155;line-height:1.6}.gengage-chat-comparison-special{background:#fffbeb;border:1px solid #fde68a;border-radius:12px;padding:12px 16px;margin-bottom:12px;font-size:13px;color:#92400e}.gengage-chat-comparison-special summary{cursor:pointer;font-weight:600}.gengage-chat-comparison-special ul{margin:8px 0 0;padding-left:18px;line-height:1.6}.gengage-chat-comparison-table{width:100%;border-collapse:collapse;font-size:13px;margin-top:12px}.gengage-chat-comparison-table th,.gengage-chat-comparison-table td{padding:10px 12px;text-align:center;border-bottom:1px solid #f1f5f9;vertical-align:top}.gengage-chat-comparison-table th{font-weight:600;font-size:12px;color:#334155}.gengage-chat-comparison-table th img{width:60px;height:60px;object-fit:contain;border-radius:6px;background:#f8fafc;margin-bottom:6px}.gengage-chat-comparison-table-price{font-weight:700;color:#0f172a}.gengage-chat-comparison-label{text-align:left;font-weight:600;color:var(--_gengage-text-secondary);white-space:nowrap}.gengage-chat-comparison-selected{background:#f0fdf4}.gengage-chat-comparison-recommended-text{padding:8px 12px;font-size:12px;color:var(--gengage-text-secondary, #475569);font-style:italic;border-top:1px solid var(--gengage-border-color, #e2e8f0);margin-top:8px}.gengage-chat-comparison-product-actions{display:flex;gap:8px;margin-top:12px;flex-wrap:wrap}.gengage-chat-comparison-view-btn{flex:1;min-width:0;padding:8px 12px;border:1px solid var(--gengage-primary-color, #3b82f6);border-radius:6px;background:transparent;color:var(--gengage-primary-color, #3b82f6);font-size:12px;font-weight:500;font-family:inherit;cursor:pointer;transition:background .15s ease,color .15s ease;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.gengage-chat-comparison-view-btn:hover{background:var(--gengage-primary-color, #3b82f6);color:#fff}.gengage-chat-pills{position:relative;padding:8px 12px;border-top:1px solid #f1f5f9;background:var(--gengage-background-color, #fff)}.gengage-chat-pills-scroll{display:flex;gap:8px;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding-right:28px}.gengage-chat-pills-scroll::-webkit-scrollbar{display:none}.gengage-chat-pill{flex:0 0 auto;padding:8px 16px;border:none;border-radius:999px;background:var(--gengage-primary-color, #3b82f6);color:var(--gengage-primary-foreground, #fff);font-size:13px;font-weight:600;font-family:inherit;white-space:nowrap;cursor:pointer;transition:filter .15s,transform .1s}.gengage-chat-pill:hover{filter:brightness(.92)}.gengage-chat-pill:active{transform:scale(.97)}.gengage-chat-pill--rich{display:flex;align-items:center;gap:8px;padding:6px 14px 6px 6px;border-radius:20px}.gengage-chat-pill-img{width:32px;height:32px;border-radius:50%;object-fit:cover;flex-shrink:0;background:#ffffff26}.gengage-chat-pill-text{font-size:13px;font-weight:600;line-height:1.2}.gengage-chat-pill-desc{display:none}.gengage-chat-pill--rich .gengage-chat-pill-desc{display:block;font-size:10px;font-weight:400;opacity:.8;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:160px}.gengage-chat-pills-arrow{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:28px;height:28px;border-radius:50%;border:1px solid var(--_gengage-border-color);background:#fff;color:var(--_gengage-text-secondary);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:-4px 0 8px #ffffffe6;z-index:1}.gengage-chat-pills-arrow:hover{background:#f8fafc;color:#334155}@media(prefers-reduced-motion:reduce){.gengage-chat-uispec>*,.gengage-chat-action-btn,.gengage-chat-product-card,.gengage-chat-product-card-cta,.gengage-chat-send,.gengage-chat-launcher,.gengage-chat-pill,.gengage-chat-drawer,.gengage-chat-proactive,.gengage-chat-typing-dots span,.gengage-chat-typing-sparkle,.gengage-chat-thinking-step-marker--active,.gengage-chat-bubble,.gengage-chat-panel-skeleton-block,.gengage-chat-ai-toppick-card,.gengage-chat-mic-btn--active,.gengage-chat-ai-toppick-spinner:after,.gengage-chat-panel-shimmer,.gengage-chat-overlay,.gengage-chat-product-details-skeleton-price{animation:none!important;transition:none!important;transform:none!important}}.gengage-chat-bubble--user{position:relative}.gengage-chat-rollback-btn{position:absolute;left:-28px;top:50%;transform:translateY(-50%);width:24px;height:24px;border:none;border-radius:50%;background:var(--gengage-surface-color, #f1f5f9);color:var(--gengage-text-secondary, #64748b);cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s ease;padding:0}.gengage-chat-bubble--user:hover .gengage-chat-rollback-btn{opacity:1}.gengage-chat-rollback-btn:hover{background:var(--gengage-primary-color, #3b82f6);color:#fff}.gengage-chat-bubble--hidden{display:none}.gengage-chat-ai-top-picks{display:flex;flex-direction:column;gap:12px;padding:8px 0}.gengage-chat-ai-top-picks-title{font-size:15px;font-weight:600;color:var(--gengage-text-primary, #1e293b);margin:0 0 4px}.gengage-chat-ai-top-picks-cards{display:flex;flex-direction:column;gap:10px}.gengage-chat-ai-toppick-discount-badge{position:absolute;top:8px;left:8px;background:var(--gengage-discount-bg, #ef4444);color:#fff;font-size:11px;font-weight:700;padding:2px 6px;border-radius:4px;z-index:1}.gengage-chat-ai-toppick-card--winner{position:relative;display:flex;flex-direction:column;border:2px solid var(--gengage-primary-color, #3b82f6);border-radius:12px;background:#fff;overflow:hidden;transition:box-shadow .2s ease}.gengage-chat-ai-toppick-card--winner:hover{box-shadow:0 4px 16px #3b82f626}.gengage-chat-ai-toppick-card--winner .gengage-chat-ai-toppick-img{width:100%;height:140px;object-fit:contain;background:#f8fafc}.gengage-chat-ai-toppick-card--compact{position:relative;display:flex;flex-direction:row;align-items:center;gap:12px;border:1px solid var(--gengage-border-color, #e2e8f0);border-radius:10px;background:#fff;padding:10px;transition:box-shadow .2s ease,transform .15s ease}.gengage-chat-ai-toppick-card--compact:hover{box-shadow:0 2px 8px #00000014;transform:translateY(-1px)}.gengage-chat-ai-toppick-card--compact .gengage-chat-ai-toppick-img{width:64px;height:64px;object-fit:contain;border-radius:8px;background:#f8fafc;flex-shrink:0}.gengage-chat-ai-toppick-badge{position:absolute;top:8px;left:8px;background:var(--gengage-primary-color, #3b82f6);color:#fff;font-size:10px;font-weight:700;text-transform:uppercase;padding:2px 8px;border-radius:4px;z-index:1;letter-spacing:.5px}.gengage-chat-ai-toppick-body{display:flex;flex-direction:column;gap:4px;padding:10px;flex:1;min-width:0}.gengage-chat-ai-toppick-card--compact .gengage-chat-ai-toppick-body{padding:0}.gengage-chat-ai-toppick-name{font-size:13px;font-weight:600;color:var(--gengage-text-primary, #1e293b);overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical}.gengage-chat-ai-toppick-role{font-size:11px;font-weight:600;color:var(--gengage-primary-color, #3b82f6);text-transform:uppercase;letter-spacing:.3px}.gengage-chat-ai-toppick-labels{display:flex;flex-wrap:wrap;gap:4px}.gengage-chat-ai-toppick-label{font-size:11px;padding:1px 6px;border-radius:4px;font-weight:500}.gengage-chat-ai-toppick-label[data-sentiment=positive]{background:#dcfce7;color:#166534}.gengage-chat-ai-toppick-label[data-sentiment=negative]{background:#fee2e2;color:#991b1b}.gengage-chat-ai-toppick-label[data-sentiment=neutral]{background:#f1f5f9;color:#475569}.gengage-chat-ai-toppick-score{font-size:12px;font-weight:700;color:var(--gengage-primary-color, #3b82f6)}.gengage-chat-ai-toppick-reason{font-size:12px;color:var(--gengage-chat-text-secondary, #666);line-height:1.4;margin-top:4px}.gengage-chat-ai-toppick-review{font-size:12px;font-style:italic;color:var(--gengage-text-secondary, #64748b);margin:2px 0;padding-left:8px;border-left:2px solid var(--gengage-border-color, #e2e8f0)}.gengage-chat-ai-toppick-price{font-size:14px;font-weight:700;color:var(--gengage-text-primary, #1e293b)}.gengage-chat-ai-toppick-original-price{text-decoration:line-through;color:var(--gengage-text-secondary, #64748b);font-weight:400;font-size:12px}.gengage-chat-ai-toppick-cta{display:block;width:calc(100% - 20px);margin:6px 10px 10px;padding:8px 0;border:none;border-radius:8px;background:var(--gengage-primary-color, #3b82f6);color:#fff;font-size:13px;font-weight:600;cursor:pointer;text-align:center;transition:background .15s ease}.gengage-chat-ai-toppick-cta:hover{filter:brightness(.92)}.gengage-chat-ai-toppick-card--compact .gengage-chat-ai-toppick-cta{width:auto;margin:0;padding:6px 14px;flex-shrink:0;align-self:center}.gengage-chat-ai-toppick-spinner{position:absolute;inset:0;background:#ffffffb3;display:flex;align-items:center;justify-content:center;border-radius:12px;z-index:3}.gengage-chat-ai-toppick-spinner:after{content:"";width:24px;height:24px;border:3px solid var(--gengage-border, #e2e8f0);border-top-color:var(--gengage-accent-primary, #3b82f6);border-radius:50%;animation:gengage-spin .7s linear infinite}@keyframes gengage-spin{to{transform:rotate(360deg)}}@media(max-width:768px){.gengage-chat-ai-top-picks-cards{flex-direction:row;overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;gap:10px;padding-bottom:4px}.gengage-chat-ai-toppick-card--winner,.gengage-chat-ai-toppick-card--compact{min-width:280px;max-width:280px;flex-shrink:0;scroll-snap-align:start}.gengage-chat-ai-toppick-card--compact{flex-direction:column;align-items:stretch}.gengage-chat-ai-toppick-card--compact .gengage-chat-ai-toppick-img{width:100%;height:100px;border-radius:8px 8px 0 0}.gengage-chat-ai-toppick-card--compact .gengage-chat-ai-toppick-cta{width:calc(100% - 20px);margin:6px 10px 10px;align-self:stretch}.gengage-chat-rollback-btn{left:-24px}}.gengage-chat-grounding-review{display:flex;align-items:center;gap:12px;padding:12px 16px;background:var(--gengage-surface-color, #f8fafc);border:1px solid var(--gengage-border-color, #e2e8f0);border-radius:10px;transition:background .15s ease,border-color .15s ease}.gengage-chat-grounding-review:hover{background:var(--gengage-hover-color, #f1f5f9);border-color:var(--gengage-primary-color, #3b82f6)}.gengage-chat-grounding-review-icon{font-size:20px;flex-shrink:0}.gengage-chat-grounding-review-body{flex:1;min-width:0}.gengage-chat-grounding-review-title{font-weight:600;font-size:13px;color:var(--gengage-text-color, #1e293b)}.gengage-chat-grounding-review-subtitle{font-size:12px;color:var(--gengage-text-muted, #64748b);margin-top:2px}.gengage-chat-grounding-review-cta{font-size:13px;font-weight:500;color:var(--gengage-primary-color, #3b82f6);white-space:nowrap;flex-shrink:0}.gengage-chat-grouping-cards{display:flex;flex-direction:column;gap:6px}.gengage-chat-grouping-card{display:flex;align-items:center;gap:10px;padding:8px 12px;background:var(--gengage-surface-color, #f8fafc);border:1px solid var(--gengage-border-color, #e2e8f0);border-radius:8px;transition:background .15s ease,border-color .15s ease}.gengage-chat-grouping-card:hover{background:var(--gengage-hover-color, #f1f5f9);border-color:var(--gengage-primary-color, #3b82f6)}.gengage-chat-grouping-card-arrow{display:none;font-size:14px;color:var(--gengage-primary-color, #3b82f6);flex-shrink:0}.gengage-chat-grouping-card-img{width:20px;height:20px;border-radius:4px;object-fit:cover;flex-shrink:0}.gengage-chat-grouping-card-body{flex:1;min-width:0;display:flex;align-items:baseline;gap:6px;flex-wrap:wrap}.gengage-chat-grouping-card-name{font-weight:600;font-size:13px;color:var(--gengage-text-color, #1e293b)}.gengage-chat-grouping-card-desc{font-size:12px;color:var(--gengage-text-muted, #64748b)}.gengage-chat-grouping-card-labels{display:block;font-size:11px;color:var(--gengage-chat-text-secondary, #888);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gengage-chat-root--mobile .gengage-chat-grouping-card-img{display:none}.gengage-chat-root--mobile .gengage-chat-grouping-card-arrow{display:inline}.gengage-chat-suggested-search-cards{display:flex;flex-direction:column;gap:8px}.gengage-chat-suggested-search-card{display:flex;align-items:flex-start;gap:12px;padding:10px 14px;background:var(--gengage-surface-color, #f8fafc);border:1px solid var(--gengage-border-color, #e2e8f0);border-radius:10px;transition:background .15s ease,border-color .15s ease}.gengage-chat-suggested-search-card:hover{background:var(--gengage-hover-color, #f1f5f9);border-color:var(--gengage-primary-color, #3b82f6)}.gengage-chat-suggested-search-card-img{width:40px;height:40px;border-radius:6px;object-fit:cover;flex-shrink:0}.gengage-chat-suggested-search-card-body{flex:1;min-width:0}.gengage-chat-suggested-search-card-name{font-weight:600;font-size:13px;color:var(--gengage-text-color, #1e293b)}.gengage-chat-suggested-search-card-desc{font-size:12px;color:var(--gengage-text-secondary, #475569);margin-top:2px}.gengage-chat-suggested-search-card-diff{font-size:11px;color:var(--gengage-text-muted, #64748b);margin-top:2px;font-style:italic}.gengage-chat-product-details-gallery{position:relative}.gengage-chat-product-details-gallery .gengage-chat-product-details-img{touch-action:pan-y}.gengage-chat-product-gallery-thumbs{display:flex;gap:8px;padding:10px 0 4px;overflow-x:auto;scrollbar-width:thin;justify-content:center;width:100%}.gengage-chat-product-gallery-thumb{width:56px;height:56px;object-fit:cover;border-radius:8px;border:2px solid transparent;cursor:pointer;flex-shrink:0;transition:border-color .15s ease;background:#fff}.gengage-chat-product-gallery-thumb:hover{border-color:var(--gengage-border-color, #cbd5e1)}.gengage-chat-product-gallery-thumb--active{border-color:var(--gengage-primary-color, #3b82f6)}.gengage-chat-product-variants{margin-top:12px}.gengage-chat-product-variants-label{font-size:12px;font-weight:600;color:var(--gengage-text-muted, #64748b);margin-bottom:6px;text-transform:uppercase;letter-spacing:.5px}.gengage-chat-product-variants-list{display:flex;flex-wrap:wrap;gap:6px}.gengage-chat-product-variant-btn{padding:6px 12px;border:1px solid var(--gengage-border-color, #e2e8f0);border-radius:6px;background:var(--gengage-surface-color, #f8fafc);color:var(--gengage-text-color, #1e293b);font-size:12px;cursor:pointer;transition:background .15s ease,border-color .15s ease}.gengage-chat-product-variant-btn:hover{background:var(--gengage-hover-color, #f1f5f9);border-color:var(--gengage-primary-color, #3b82f6)}.gengage-chat-product-grid-wrapper{display:flex;flex-direction:column;gap:8px}.gengage-chat-product-sort-toolbar{display:flex;gap:4px;padding:4px;background:var(--gengage-surface-color, #f8fafc);border-radius:8px;border:1px solid var(--gengage-border-color, #e2e8f0)}.gengage-chat-product-sort-btn{flex:1;padding:6px 10px;border:none;border-radius:6px;background:transparent;color:var(--gengage-text-muted, #64748b);font-size:12px;font-weight:500;cursor:pointer;transition:background .15s ease,color .15s ease}.gengage-chat-product-sort-btn:hover{background:var(--gengage-hover-color, #f1f5f9);color:var(--gengage-text-color, #1e293b)}.gengage-chat-product-sort-btn--active,.gengage-chat-product-sort-btn--active:hover{background:var(--gengage-primary-color, #3b82f6);color:#fff}.gengage-chat-product-sort-separator{width:1px;background:var(--gengage-border-color, #e2e8f0);margin:2px}.gengage-chat-comparison-toggle-btn{flex:none;padding:6px 10px;border:none;border-radius:6px;background:transparent;color:var(--gengage-text-muted, #64748b);font-size:12px;font-weight:500;cursor:pointer;transition:background .15s ease,color .15s ease;white-space:nowrap}.gengage-chat-comparison-toggle-btn:hover{background:var(--gengage-hover-color, #f1f5f9);color:var(--gengage-text-color, #1e293b)}.gengage-chat-comparison-toggle-btn--active,.gengage-chat-comparison-toggle-btn--active:hover{background:var(--gengage-primary-color, #3b82f6);color:#fff}.gengage-chat-comparison-select-wrapper{position:relative}.gengage-chat-comparison-checkbox{position:absolute;top:8px;left:8px;z-index:2;width:18px;height:18px;cursor:pointer;accent-color:var(--gengage-primary-color, #3b82f6)}.gengage-chat-comparison-floating-btn{display:block;width:100%;margin-top:8px;padding:10px 16px;border:none;border-radius:8px;background:var(--gengage-primary-color, #3b82f6);color:#fff;font-size:14px;font-weight:600;cursor:pointer;transition:background .15s ease;text-align:center}.gengage-chat-comparison-floating-btn:hover{background:var(--gengage-primary-hover, #2563eb)}.gengage-chat-panel-topbar{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid var(--_gengage-border-color);background:#f8fafc;min-height:44px;flex-shrink:0;position:sticky;top:0;z-index:3}.gengage-chat-panel-topbar-back,.gengage-chat-panel-topbar-forward{width:28px;height:28px;min-width:28px;padding:0;border:1px solid #d1d5db;border-radius:6px;background:transparent;color:#374151;font-size:14px;font-family:inherit;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s ease,border-color .15s ease,opacity .15s ease}.gengage-chat-panel-topbar-back:hover:not(:disabled),.gengage-chat-panel-topbar-forward:hover:not(:disabled){background:#f3f4f6;border-color:#9ca3af}.gengage-chat-panel-topbar-back:disabled,.gengage-chat-panel-topbar-forward:disabled{opacity:.3;cursor:default}.gengage-chat-panel-topbar-title{flex:1;font-size:14px;font-weight:600;color:#1f2937;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center}@keyframes gengage-typewriter-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.gengage-chat-typewriter-block{display:block;animation:gengage-typewriter-fade-in .15s ease both}@media(prefers-reduced-motion:reduce){.gengage-chat-typewriter-block{animation:none}}.gengage-product-mention{color:var(--gengage-primary-color, #3b82f6);text-decoration:none;cursor:pointer;font-weight:500;border-bottom:1px dashed var(--gengage-primary-color, #3b82f6);transition:border-color .15s}.gengage-product-mention:hover{border-bottom-style:solid}@keyframes gengage-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.8}}.gengage-chat-panel-skeleton-block{animation:gengage-skeleton-pulse 1.5s ease-in-out infinite}@media(prefers-reduced-motion:reduce){.gengage-chat-panel-skeleton-block{animation:none}}.gengage-chat-input-chips{display:flex;gap:6px;padding:4px 12px 2px;flex-wrap:wrap}.gengage-chat-input-chip{display:inline-flex;align-items:center;padding:4px 10px;border-radius:12px;border:1px solid var(--_gengage-border-color);background:#f9fafb;color:#374151;font-size:12px;font-weight:500;font-family:inherit;cursor:pointer;transition:background .12s,border-color .12s;white-space:nowrap}.gengage-chat-input-chip:hover{background:#f3f4f6;border-color:#d1d5db}.gengage-chat-icon{width:14px;height:14px;flex-shrink:0}.gengage-chat-input-chip-icon,.gengage-chat-pill-icon{display:inline-flex;align-items:center;margin-right:4px}.gengage-chat-product-card-img-wrapper,.gengage-chat-product-details-img-wrap{position:relative;overflow:hidden}.gengage-chat-product-card-discount-badge{position:absolute;top:6px;left:6px;padding:2px 6px;border-radius:4px;background:var(--_gengage-discount-color);color:#fff;font-size:11px;font-weight:700;line-height:1.3;z-index:1}.gengage-chat-product-card-stock{font-size:11px;font-weight:600;margin-top:2px}.gengage-chat-product-card-stock.is-in-stock{color:var(--_gengage-success-color)}.gengage-chat-product-card-stock.is-out-of-stock{color:#dc2626}.gengage-chat-find-similar-pill{position:absolute;top:8px;right:8px;opacity:0;pointer-events:none;transition:opacity .2s ease;padding:4px 10px;font-size:11px;font-weight:500;font-family:inherit;border:none;border-radius:12px;background:var(--gengage-chat-pill-bg, rgba(0, 0, 0, .7));color:var(--gengage-chat-pill-text, #fff);cursor:pointer;white-space:nowrap;z-index:2}.gengage-chat-product-card-img-wrapper:hover .gengage-chat-find-similar-pill,.gengage-chat-product-details-img-wrap:hover .gengage-chat-find-similar-pill{opacity:1;pointer-events:auto}.gengage-chat-favorite-btn{position:absolute;top:8px;right:8px;background:#ffffffe6;border:none;border-radius:50%;width:28px;height:28px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--gengage-text-secondary, #64748b);z-index:3;transition:color .2s;padding:0}.gengage-chat-favorite-btn:hover,.gengage-chat-favorite-btn--active{color:var(--gengage-accent-primary, #ef4444)}.gengage-chat-product-card-promos,.gengage-chat-product-details-promos{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.gengage-chat-product-card-promo-badge,.gengage-chat-product-details-promo-badge{display:inline-block;padding:2px 6px;font-size:10px;font-weight:500;border-radius:4px;background:var(--gengage-chat-promo-bg, #e8f5e9);color:var(--gengage-chat-promo-text, #2e7d32);white-space:nowrap}.gengage-chat-thumbnails-column{position:absolute;right:4px;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:4px;z-index:2;pointer-events:auto}.gengage-chat-thumbnail-btn{display:flex;align-items:center;justify-content:center;width:40px;height:40px;padding:0;border:2px solid #e5e7eb;border-radius:6px;background:#fff;cursor:pointer;overflow:hidden;transition:border-color .15s ease}.gengage-chat-thumbnail-btn:hover{border-color:var(--gengage-primary-color, #3b82f6)}.gengage-chat-thumbnail-img{width:100%;height:100%;object-fit:cover}.gengage-chat-choice-prompter{position:absolute;bottom:12px;right:12px;width:200px;padding:12px 14px;background:#fff;border:1px solid var(--_gengage-border-color);border-radius:10px;box-shadow:0 4px 12px #0000001a;z-index:10;animation:gengage-choice-prompter-in .2s ease}@keyframes gengage-choice-prompter-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.gengage-chat-choice-prompter-heading{font-size:13px;font-weight:600;color:#1f2937;margin-bottom:4px}.gengage-chat-choice-prompter-suggestion{font-size:12px;color:#6b7280;margin-bottom:10px;line-height:1.4}.gengage-chat-choice-prompter-cta{display:block;width:100%;padding:6px 12px;border:none;border-radius:6px;background:var(--gengage-primary-color, #3b82f6);color:#fff;font-size:12px;font-weight:600;font-family:inherit;cursor:pointer;text-align:center;transition:opacity .15s ease}.gengage-chat-choice-prompter-cta:hover{opacity:.9}.gengage-chat-choice-prompter-dismiss{position:absolute;top:4px;right:6px;padding:2px 6px;border:none;background:none;color:#6b7280;font-size:16px;cursor:pointer;line-height:1}.gengage-chat-choice-prompter-dismiss:hover{color:#6b7280}@media(prefers-reduced-motion:reduce){.gengage-chat-choice-prompter{animation:none}}.gengage-chat-pros-cons{padding:12px 14px;background:#f8fafc;border-radius:8px;margin:8px 0}.gengage-chat-pros-cons-heading{margin:0 0 10px;font-size:14px;font-weight:600;color:#0f172a}.gengage-chat-pros-cons-list{list-style:none;margin:0 0 8px;padding:0}.gengage-chat-pros-cons-list:last-child{margin-bottom:0}.gengage-chat-pros-cons-item{display:flex;align-items:flex-start;gap:8px;padding:4px 0;font-size:13px;line-height:1.5;color:#334155}.gengage-chat-pros-cons-icon{flex-shrink:0;width:18px;height:18px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;border-radius:50%}.gengage-chat-pros-cons-icon--pro{color:#16a34a;background:#dcfce7}.gengage-chat-pros-cons-icon--con{color:#dc2626;background:#fee2e2}.gengage-chat-categories{display:flex;flex-direction:column;gap:8px}.gengage-chat-categories-tabs{display:flex;gap:4px;overflow-x:auto;padding:4px 0;-webkit-overflow-scrolling:touch}.gengage-chat-categories-tab{padding:6px 14px;border:1px solid var(--gengage-border-color, #e5e7eb);border-radius:20px;background:var(--gengage-bg, #fff);color:var(--gengage-text, #374151);cursor:pointer;white-space:nowrap;font-size:13px;transition:background .15s,color .15s}.gengage-chat-categories-tab:hover{background:var(--gengage-bg-hover, #f3f4f6)}.gengage-chat-categories-tab--active{background:var(--gengage-primary, #2563eb);color:#fff;border-color:var(--gengage-primary, #2563eb)}.gengage-chat-categories-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}.gengage-chat-categories-filter-tags{display:flex;gap:6px;flex-wrap:wrap;margin-top:4px}.gengage-chat-categories-filter-tag{padding:4px 10px;border:1px solid var(--gengage-border-color, #e5e7eb);border-radius:14px;background:var(--gengage-bg, #fff);color:var(--gengage-text-secondary, #6b7280);font-size:12px;cursor:pointer;transition:background .15s}.gengage-chat-categories-filter-tag:hover{background:var(--gengage-bg-hover, #f3f4f6)}.gengage-chat-product-grid-view-more{display:block;width:100%;padding:10px;margin-top:8px;border:1px solid var(--gengage-border-color, #e5e7eb);border-radius:8px;background:var(--gengage-bg, #fff);color:var(--gengage-primary, #2563eb);font-size:14px;font-weight:500;cursor:pointer;text-align:center;transition:background .15s;grid-column:1 / -1}.gengage-chat-product-grid-view-more:hover{background:var(--gengage-bg-hover, #f3f4f6)}.gengage-chat-product-grid--mobile{display:flex;overflow-x:auto;gap:8px;padding:8px 0;-webkit-overflow-scrolling:touch}.gengage-chat-product-grid--mobile .gengage-chat-product-card{min-width:160px;max-width:180px;flex-shrink:0}.gengage-chat-comparison--mobile{overflow-x:auto;-webkit-overflow-scrolling:touch}.gengage-chat-comparison--mobile .gengage-chat-comparison-table{min-width:480px}.gengage-chat-comparison-key-differences{margin-top:12px;padding:12px;background:var(--gengage-bg-secondary, #f9fafb);border-radius:8px}.gengage-chat-comparison-key-differences h4{margin:0 0 8px;font-size:14px;font-weight:600;color:var(--gengage-text, #374151)}.gengage-chat-comparison-key-differences-content{font-size:13px;color:var(--gengage-text-secondary, #6b7280);line-height:1.5}.gengage-chat-comparison-key-differences-content ul{margin:0;padding-left:18px}.gengage-chat-comparison-key-differences-content li{margin-bottom:4px}.gengage-chat-product-details-similars-heading{margin:16px 0 8px;font-size:15px;font-weight:600;color:var(--gengage-text, #374151)}.gengage-chat-product-details-similars{margin-top:8px}.gengage-chat-handoff-notice{display:flex;flex-direction:column;align-items:center;gap:6px;padding:16px;margin:8px 0;background:#fef3c7;border:1px solid #fcd34d;border-radius:8px;text-align:center}.gengage-chat-handoff-notice-icon{font-size:24px}.gengage-chat-handoff-notice-heading{margin:0;font-size:14px;font-weight:600;color:#92400e}.gengage-chat-handoff-notice-summary{margin:0;font-size:13px;line-height:1.5;color:#78350f}.gengage-qty-stepper{display:inline-flex;align-items:center;gap:0;border:1px solid #d1d5db;border-radius:8px;overflow:hidden;background:#fff}.gengage-qty-btn{width:var(--_gengage-qty-btn-size);height:var(--_gengage-qty-btn-size);border:none;background:transparent;color:#374151;font-size:14px;font-weight:600;font-family:inherit;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background-color .12s}.gengage-qty-btn:hover:not(:disabled){background:#f3f4f6}.gengage-qty-btn:disabled{opacity:.35;cursor:default}.gengage-qty-value{min-width:24px;text-align:center;font-size:13px;font-weight:600;color:#1f2937;-webkit-user-select:none;user-select:none}.gengage-qty-submit{border:none;border-left:1px solid #d1d5db;background:var(--_gengage-success-color);color:#fff;font-size:13px;font-weight:700;font-family:inherit;cursor:pointer;padding:6px 12px;transition:filter .12s ease,transform .12s ease}.gengage-qty-submit:hover{filter:brightness(1.08)}.gengage-qty-submit:active{transform:translateY(1px)}.gengage-qty-stepper--compact{border-radius:14px;box-shadow:0 2px 6px #0000001f}.gengage-qty-stepper--compact .gengage-qty-btn{width:var(--_gengage-qty-btn-size-compact);height:var(--_gengage-qty-btn-size-compact);font-size:12px}.gengage-qty-stepper--compact .gengage-qty-value{min-width:18px;font-size:12px}.gengage-qty-stepper--compact .gengage-qty-submit{padding:4px 8px;font-size:13px;border-radius:0 14px 14px 0}.gengage-chat-product-details-atc-stepper{border-radius:10px}.gengage-chat-product-details-atc-stepper .gengage-qty-btn{width:32px;height:32px}.gengage-chat-product-details-atc-stepper .gengage-qty-value{min-width:28px;font-size:14px}.gengage-chat-product-details-atc-stepper .gengage-qty-submit{padding:8px 18px;font-size:14px;border-radius:0 10px 10px 0}.gengage-chat-product-details-share{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border:1px solid #d1d5db;border-radius:10px;background:transparent;color:#6b7280;cursor:pointer;transition:color .12s,border-color .12s,background-color .12s;position:relative;flex-shrink:0}.gengage-chat-product-details-share:hover{color:var(--gengage-primary-color, #3b82f6);border-color:var(--gengage-primary-color, #3b82f6);background:#f0f7ff}.gengage-chat-product-details-share:before{content:attr(aria-label);position:absolute;bottom:calc(100% + 6px);left:50%;transform:translate(-50%);padding:4px 8px;border-radius:4px;background:#1e293b;color:#fff;font-size:11px;font-weight:500;white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .15s ease;z-index:2}.gengage-chat-product-details-share:hover:before{opacity:1}.gengage-chat-product-details-share--copied:after{content:"✓";position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:var(--_gengage-success-color);color:#fff;border-radius:10px;font-size:16px;font-weight:700}.gengage-chat-launcher:focus-visible,.gengage-chat-close:focus-visible,.gengage-chat-header-btn:focus-visible,.gengage-chat-header-powered:focus-visible,.gengage-chat-proactive-accept:focus-visible,.gengage-chat-proactive-dismiss:focus-visible,.gengage-chat-send:focus-visible,.gengage-chat-action-btn:focus-visible,.gengage-chat-pill:focus-visible,.gengage-chat-input-chip:focus-visible,.gengage-chat-pills-arrow:focus-visible,.gengage-chat-error-retry:focus-visible,.gengage-chat-product-card-cta:focus-visible,.gengage-chat-product-details-cta:focus-visible,.gengage-chat-product-details-atc:focus-visible,.gengage-chat-product-detail-tab:focus-visible,.gengage-chat-panel-divider-toggle:focus-visible,.gengage-chat-panel-topbar-back:focus-visible,.gengage-chat-panel-topbar-forward:focus-visible,.gengage-chat-rollback-btn:focus-visible,.gengage-chat-ai-toppick-cta:focus-visible,.gengage-chat-comparison-view-btn:focus-visible,.gengage-chat-comparison-toggle-btn:focus-visible,.gengage-chat-comparison-floating-btn:focus-visible,.gengage-chat-comparison-checkbox:focus-visible,.gengage-chat-product-sort-btn:focus-visible,.gengage-chat-product-variant-btn:focus-visible,.gengage-chat-product-gallery-thumb:focus-visible,.gengage-chat-thumbnail-btn:focus-visible,.gengage-chat-find-similar-pill:focus-visible,.gengage-chat-favorite-btn:focus-visible,.gengage-chat-attach-btn:focus-visible,.gengage-chat-mic-btn:focus-visible,.gengage-chat-attachment-remove:focus-visible,.gengage-chat-kvkk-dismiss:focus-visible,.gengage-chat-choice-prompter-cta:focus-visible,.gengage-chat-choice-prompter-dismiss:focus-visible,.gengage-chat-categories-tab:focus-visible,.gengage-chat-categories-filter-tag:focus-visible,.gengage-chat-product-grid-view-more:focus-visible,.gengage-chat-product-details-share:focus-visible,.gengage-qty-btn:focus-visible,.gengage-qty-submit:focus-visible{outline:2px solid var(--gengage-primary-color, #3b82f6);outline-offset:2px}', Ka = A({
3140
- role: _e(["user", "assistant"]),
3141
- content: x(),
3142
- timestamp: Q().optional()
3143
- }), Wa = A({
3144
- sku: x(),
3145
- name: x(),
3146
- imageUrl: x().url().optional(),
3147
- price: x().optional(),
3148
- originalPrice: x().optional(),
3149
- url: x().url(),
3150
- /** Override CTA label (default: "View product") */
3151
- ctaLabel: x().optional()
3152
- }), Ya = A({
3153
- buttons: z(
3154
- A({
3155
- label: x(),
3156
- /** Opaque action payload forwarded to the backend when clicked. */
3157
- action: A({
3158
- title: x(),
3159
- type: x(),
3160
- payload: K().optional()
3161
- })
3162
- })
3163
- )
3164
- }), Qa = A({}), Xa = A({
3165
- label: x().optional()
3166
- }), xe = A({
3167
- sku: x(),
3168
- name: x(),
3169
- price: x(),
3170
- imageUrl: x().optional(),
3171
- rating: Q().optional(),
3172
- reviewCount: Q().optional()
3173
- }), Ja = A({
3174
- recommended: xe,
3175
- products: z(xe),
3176
- attributes: z(
3177
- A({
3178
- label: x(),
3179
- values: z(x())
3180
- })
3181
- ),
3182
- highlights: z(x()),
3183
- specialCases: z(x()).optional(),
3184
- recommendedText: x().optional(),
3185
- winnerHits: ae(
3186
- x(),
3187
- A({
3188
- positive: z(x()).optional(),
3189
- negative: z(x()).optional()
3190
- })
3191
- ).optional(),
3192
- productActions: ae(
3193
- x(),
3194
- A({
3195
- title: x(),
3196
- type: x(),
3197
- payload: K().optional()
3198
- })
3199
- ).optional()
3200
- }), Za = A({
3201
- label: x(),
3202
- sentiment: _e(["positive", "negative", "neutral"]).optional()
3203
- }), en = A({
3204
- product: ae(x(), K()),
3205
- role: x().optional(),
3206
- reason: x().optional(),
3207
- labels: z(Za).optional(),
3208
- expertQualityScore: Q().optional(),
3209
- reviewHighlight: x().optional(),
3210
- action: A({
3211
- title: x(),
3212
- type: x(),
3213
- payload: K().optional()
3214
- }).optional()
3215
- }), tn = A({
3216
- suggestions: z(en)
3217
- }), an = A({
3218
- title: x().optional(),
3219
- text: x().optional(),
3220
- reviewCount: x().optional(),
3221
- action: A({ title: x(), type: x(), payload: K().optional() })
3222
- }), nn = A({
3223
- entries: z(
3224
- A({
3225
- name: x(),
3226
- image: x().optional(),
3227
- description: x().optional(),
3228
- action: A({ title: x(), type: x(), payload: K().optional() })
3229
- })
3230
- )
3231
- }), on = A({
3232
- entries: z(
3233
- A({
3234
- shortName: x(),
3235
- detailedMessage: x().optional(),
3236
- whyDifferent: x().optional(),
3237
- image: x().optional(),
3238
- action: A({ title: x(), type: x(), payload: K().optional() })
3239
- })
3240
- )
3241
- }), Be = A({
3242
- title: x(),
3243
- type: x(),
3244
- payload: K().optional()
3245
- }), rn = A({
3246
- name: x().optional(),
3247
- variant_name: x().optional(),
3248
- sku: x().optional(),
3249
- price: re([Q(), x()]).optional()
3250
- }), sn = A({
3251
- product: A({
3252
- sku: x().optional(),
3253
- name: x().optional(),
3254
- images: z(x()).optional(),
3255
- imageUrl: x().optional(),
3256
- rating: Q().optional(),
3257
- reviewCount: Q().optional(),
3258
- price: x().optional(),
3259
- originalPrice: x().optional(),
3260
- price_async: oe().optional(),
3261
- inStock: oe().optional(),
3262
- promotions: z(x()).optional(),
3263
- variants: z(rn).optional(),
3264
- url: x().optional(),
3265
- cartCode: x().optional(),
3266
- description: x().optional(),
3267
- specifications: re([ae(x(), x()), z(A({ key: x(), value: x() }))]).optional()
3268
- }).optional(),
3269
- action: Be.optional()
3270
- }), cn = A({
3271
- endOfList: oe().optional()
3272
- }), ln = A({
3273
- review_class: x().optional(),
3274
- review_text: x().optional(),
3275
- review_rating: re([x(), Q()]).optional(),
3276
- review_tag: x().optional()
3277
- }), gn = A({
3278
- reviews: z(ln).optional()
3279
- }), dn = A({
3280
- productName: x().optional(),
3281
- pros: z(x()).optional(),
3282
- cons: z(x()).optional()
3283
- }), pn = A({
3284
- groups: z(
3285
- A({
3286
- groupName: x(),
3287
- products: z(ae(x(), K())).optional()
3288
- })
3289
- ).optional(),
3290
- filterTags: z(
3291
- A({
3292
- title: x(),
3293
- action: Be.optional()
3294
- })
3295
- ).optional()
3296
- }), hn = A({
3297
- summary: x().optional(),
3298
- products_discussed: z(x()).optional(),
3299
- user_sentiment: x().optional()
3300
- }), xn = {
3301
- components: {
3302
- MessageBubble: {
3303
- schema: Ka,
3304
- description: "A single chat message bubble for user or assistant turns."
3305
- },
3306
- ProductCard: {
3307
- schema: Wa,
3308
- description: "A product card rendered inline in the chat stream."
3309
- },
3310
- ActionButtons: {
3311
- schema: Ya,
3312
- description: "A horizontal row of quick-reply action buttons."
3313
- },
3314
- TypingIndicator: {
3315
- schema: Qa,
3316
- description: "An animated indicator shown while the assistant is typing."
3317
- },
3318
- Divider: {
3319
- schema: Xa,
3320
- description: "A horizontal rule with an optional label."
3321
- },
3322
- ComparisonTable: {
3323
- schema: Ja,
3324
- description: "A product comparison table with recommended pick, attribute rows, and highlights."
3325
- },
3326
- AITopPicks: {
3327
- schema: tn,
3328
- description: "Rich AI-curated product suggestion cards with roles, sentiment labels, scores, and review quotes."
3329
- },
3330
- GroundingReviewCard: {
3331
- schema: an,
3332
- description: "A card showing review grounding data with review count and CTA."
3333
- },
3334
- AIGroupingCards: {
3335
- schema: nn,
3336
- description: "Category grouping cards with images and labels for product discovery."
3337
- },
3338
- AISuggestedSearchCards: {
3339
- schema: on,
3340
- description: "Suggested search cards with images, descriptions, and differentiation."
3341
- },
3342
- ProductDetailsPanel: {
3343
- schema: sn,
3344
- description: "Full product detail view with images, specs, variants, and purchase actions."
3345
- },
3346
- ProductGrid: {
3347
- schema: cn,
3348
- description: 'A scrollable grid of ProductCard children with optional "more" pagination.'
3349
- },
3350
- ReviewHighlights: {
3351
- schema: gn,
3352
- description: "A list of highlighted customer reviews with sentiment and ratings."
3353
- },
3354
- ProsAndCons: {
3355
- schema: dn,
3356
- description: "A pros and cons list for a product."
3357
- },
3358
- CategoriesContainer: {
3359
- schema: pn,
3360
- description: "Tabbed product groups with optional filter tag buttons."
3361
- },
3362
- HandoffNotice: {
3363
- schema: hn,
3364
- description: "A notice shown when the conversation is escalated to a human agent."
3365
- }
3366
- }
3367
- };
3368
- function un(i) {
3369
- return i.length > 120 ? !1 : /^[a-zA-Z0-9#(),.\s%/\-]+$/.test(i);
3370
- }
3371
- function te(i) {
3372
- return typeof i == "object" && i !== null && typeof i.type == "string";
3373
- }
3374
- class mn extends He {
3375
- constructor() {
3376
- super(...arguments), this._shadow = null, this._rootEl = null, this._launcher = null, this._drawer = null, this._bridge = null, this._activityTracker = null, this._heartbeat = null, this._proactiveShown = !1, this._drawerVisible = !1, this._messages = [], this._currentMessageId = 0, this._abortControllers = /* @__PURE__ */ new Set(), this._currentThreadId = null, this._lastThreadId = null, this._chatCreatedAt = "", this._lastBackendContext = null, this._productSort = { type: "related" }, this._comparisonSelectMode = !1, this._comparisonSelectedSkus = [], this._thumbnailEntries = [], this._choicePrompterEl = null, this._openState = "full", this._mobileBreakpoint = 768, this._isMobileViewport = !1, this._pdpLaunched = !1, this._productContextUnavailableSku = null, this._i18n = ce, this._extendedModeManager = null, this._activeTypewriter = null, this._activeTtsHandle = null, this._activeRequestThreadId = null, this._skuToProductItem = {}, this._conversationMode = null, this._initComplete = !1, this._pendingActions = [], this._bridgeContext = null, this._cartQuantity = null, this._threadsWithFirstBot = /* @__PURE__ */ new Set(), this._panel = null, this._session = null, this._eventCallbacks = /* @__PURE__ */ new Map();
3377
- }
3378
- async onInit(e) {
3379
- this._i18n = this._resolveI18n(e), this._chatCreatedAt = (/* @__PURE__ */ new Date()).toISOString(), this._shadow = this.root.attachShadow({ mode: "open" });
3380
- const t = document.createElement("style");
3381
- t.textContent = Ga, this._shadow.appendChild(t);
3382
- const a = document.createElement("div");
3383
- a.className = "gengage-chat-root", this._rootEl = a, this._shadow.appendChild(a);
3384
- const n = e.variant ?? "floating";
3385
- if (n === "floating") {
3386
- const g = {
3387
- onClick: () => this.open(),
3388
- ariaLabel: this._i18n.openButton
3389
- };
3390
- e.launcherSvg !== void 0 && (g.svgMarkup = e.launcherSvg), e.hideMobileLauncher !== void 0 && (g.hideMobile = e.hideMobileLauncher), e.mobileBreakpoint !== void 0 && (g.mobileBreakpoint = e.mobileBreakpoint), e.launcherTooltip !== void 0 && (g.tooltip = e.launcherTooltip), this._launcher = Ut(g), a.appendChild(this._launcher.container);
3391
- }
3392
- n === "overlay" && a.classList.add("gengage-chat--overlay");
3393
- const o = document.createElement("div");
3394
- a.appendChild(o), this._drawer = new Dt(o, {
3395
- i18n: this._i18n,
3396
- onSend: (g, u) => this._sendMessage(g, u),
3397
- onClose: () => this.close(),
3398
- onAttachment: (g) => this._handleAttachment(g),
3399
- onPanelToggle: () => {
3400
- this._drawer?.persistPanelState(e.accountId);
3401
- },
3402
- onRollback: (g) => this._handleRollback(g),
3403
- onPanelBack: () => this._panel?.navigateBack(),
3404
- onPanelForward: () => this._panel?.navigateForward(),
3405
- headerTitle: e.headerTitle,
3406
- headerAvatarUrl: e.headerAvatarUrl,
3407
- headerBadge: e.headerBadge,
3408
- headerCartUrl: e.headerCartUrl,
3409
- headerFavoritesToggle: e.headerFavoritesToggle,
3410
- onFavoritesClick: () => {
3411
- Fe(), e.onFavoritesClick?.();
3412
- },
3413
- onThumbnailClick: (g) => this._rollbackToThread(g),
3414
- onLinkClick: (g) => {
3415
- this._saveSessionAndOpenURL(g);
3416
- },
3417
- voiceEnabled: e.voiceEnabled,
3418
- voiceLang: e.locale ? `${e.locale.split("-")[0] ?? "tr"}-${(e.locale.split("-")[1] ?? e.locale.split("-")[0] ?? "TR").toUpperCase()}` : void 0
3419
- }), this._extendedModeManager = new Ra({
3420
- onChange: (g) => this._panel?.notifyExtension(g),
3421
- productDetailsInPanel: e.isDemoWebsite ?? !1
3422
- }), this._panel = new Ua({
3423
- drawer: () => this._drawer,
3424
- shadow: () => this._shadow,
3425
- currentThreadId: () => this._currentThreadId,
3426
- bridge: () => this._bridge,
3427
- extendedModeManager: () => this._extendedModeManager,
3428
- i18n: () => this._i18n,
3429
- rollbackToThread: (g) => this._rollbackToThread(g)
3430
- }), n !== "inline" && this._drawer.getElement().classList.add("gengage-chat-drawer--hidden"), this._drawer.restorePanelState(e.accountId);
3431
- const s = e.panelMode ?? "auto";
3432
- s === "collapsed" ? this._drawer.setPanelCollapsed(!0) : s === "expanded" ? this._drawer.setForceExpanded() : this._drawer.expandPanel();
3433
- const l = sessionStorage.getItem("gengage_restore_session_id"), r = sessionStorage.getItem("gengage_restore_sku"), c = !!(l && r);
3434
- c && (sessionStorage.removeItem("gengage_restore_session_id"), sessionStorage.removeItem("gengage_restore_sku"));
3435
- try {
3436
- const g = new za();
3437
- await g.open(), this._session = new fe(g), await this._restoreFromIndexedDB(c);
3438
- } catch {
3439
- this._session = new fe(null);
3440
- }
3441
- this._registerPublicAPI(), e.mobileInitialState !== void 0 && (this._openState = e.mobileInitialState), this._mobileBreakpoint = e.mobileBreakpoint ?? 768, this._syncViewportState();
3442
- const d = () => this._syncViewportState();
3443
- if (window.addEventListener("resize", d, { passive: !0 }), this.addCleanup(() => window.removeEventListener("resize", d)), window.visualViewport) {
3444
- const g = () => {
3445
- if (!this._drawerVisible || !this._isMobileViewport) return;
3446
- const u = this._drawer?.getElement();
3447
- if (!u) return;
3448
- const p = window.innerHeight - (window.visualViewport?.height ?? window.innerHeight);
3449
- u.style.setProperty("--gengage-keyboard-offset", `${Math.max(0, p)}px`);
3450
- };
3451
- window.visualViewport.addEventListener("resize", g), this.addCleanup(() => window.visualViewport?.removeEventListener("resize", g));
3452
- }
3453
- n === "inline" && (this._drawerVisible = !0, this.isVisible = !0, this._applyOpenStateClasses()), this._bridge = new dt({
3454
- namespace: "chat",
3455
- onMessage: (g) => this._handleBridgeMessage(g)
3456
- }), this._activityTracker = new Ft({
3457
- idleThresholdMs: e.proactiveDelayMs ?? 3e4,
3458
- onActivity: (g) => {
3459
- if (g.type === "idle" && !this._proactiveShown && !this._drawerVisible) {
3460
- const u = e.proactiveMinScrollDepth ?? 0;
3461
- if (u > 0 && (this._activityTracker?.maxScrollDepth ?? 0) < u * 100)
3462
- return;
3463
- try {
3464
- if (sessionStorage.getItem("gengage_proactive_shown")) return;
3465
- } catch {
3466
- }
3467
- if (this._isProactiveCooldownActive()) return;
3468
- e.proactiveFetchActions ? this._fetchAndShowProactive() : e.proactiveMessage && this._showProactivePopup(e.proactiveMessage);
3469
- }
3470
- }
3471
- }), this.addCleanup(() => this._activityTracker?.destroy()), e.enableHeartbeat && (this._heartbeat = new jt({
3472
- middlewareUrl: e.middlewareUrl,
3473
- accountId: e.accountId,
3474
- sessionId: e.session?.sessionId ?? "",
3475
- locale: e.locale ?? "tr",
3476
- intervalMs: e.heartbeatIntervalMs ?? 3e4,
3477
- getPageType: () => this.config.pageContext?.pageType ?? "other",
3478
- getCurrentSku: () => this.config.pageContext?.sku ?? "",
3479
- onMessage: (g) => {
3480
- if (!this._proactiveShown && !this._drawerVisible && g.message) {
3481
- const u = [];
3482
- if (g.suggested_actions && Array.isArray(g.suggested_actions))
3483
- for (const p of g.suggested_actions)
3484
- p.title && te(p.requestDetails) && u.push({
3485
- title: p.title,
3486
- onSelect: () => {
3487
- this.openWithAction(p.requestDetails);
3488
- }
3489
- });
3490
- this._showProactivePopup(g.message, u.length > 0 ? u : void 0);
3491
- }
3492
- }
3493
- }), this._heartbeat.start(), this.addCleanup(() => this._heartbeat?.destroy())), this._lastSku = this.config.pageContext?.sku, this._initComplete = !0;
3494
- for (const g of this._pendingActions)
3495
- this._sendAction(g.action, g.options);
3496
- this._pendingActions = [], j("gengage:chat:ready", {}), qe("chat"), e.onReady?.();
3497
- }
3498
- onUpdate(e) {
3499
- e.sku !== void 0 && e.sku !== this._lastSku && (this._lastSku = e.sku, this._resetForNewPage());
3500
- }
3501
- onShow() {
3502
- this._showDrawer(), this.emit("open"), j("gengage:chat:open", { state: this._openState }), Oe("chat"), this.config.onOpen?.(), !this._pdpLaunched && this.config.pageContext?.sku && (this._pdpLaunched = !0, this._sendAction(
3503
- {
3504
- title: "",
3505
- type: "launchSingleProduct",
3506
- payload: { sku: this.config.pageContext.sku }
3507
- },
3508
- { silent: !0 }
3509
- ));
3510
- }
3511
- onHide() {
3512
- (this.config.variant ?? "floating") === "floating" && (this.root.style.display = ""), this._hideDrawer(), this.emit("close"), j("gengage:chat:close", {}), this.config.onClose?.();
3513
- }
3514
- onDestroy() {
3515
- this._abortControllers.forEach((e) => e.abort()), this._abortControllers.clear(), this._activeTypewriter?.cancel(), this._activeTypewriter = null, this._activeTtsHandle?.stop(), this._activeTtsHandle = null, this._bridge?.destroy(), this._bridge = null, this._extendedModeManager = null, this._panel?.destroy(), this._panel = null, this._session?.close(), this._session = null, window.gengage && delete window.gengage.chat, this._shadow && (this._shadow.innerHTML = "", this._shadow = null), this._rootEl = null;
3516
- }
3517
- // ---------------------------------------------------------------------------
3518
- // Public API
3519
- // ---------------------------------------------------------------------------
3520
- open(e) {
3521
- e?.state !== void 0 && (this._openState = e.state, this._drawerVisible && this._applyOpenStateClasses()), this.show(), e?.initialMessage !== void 0 && this._sendMessage(e.initialMessage);
3522
- }
3523
- openWithAction(e, t) {
3524
- t?.sku !== void 0 && this.update({ sku: t.sku }), this._pdpLaunched = !0, t?.state !== void 0 ? this._openState = t.state : this._isMobileViewport && (this._openState = "half"), this.show(), this._drawerVisible && this._applyOpenStateClasses(), this._sendAction(e);
3525
- }
3526
- /** Send a user message programmatically (same flow as typing + submit). */
3527
- sendMessage(e) {
3528
- this._sendMessage(e);
3529
- }
3530
- /** Send a backend action programmatically. */
3531
- sendAction(e, t) {
3532
- this._sendAction(e, t);
3533
- }
3534
- close() {
3535
- this.hide();
3536
- }
3537
- saveSession(e, t) {
3538
- sessionStorage.setItem("gengage_restore_session_id", e), sessionStorage.setItem("gengage_restore_sku", t);
3539
- }
3540
- get isOpen() {
3541
- return this._drawerVisible;
3542
- }
3543
- /**
3544
- * Register a callback for a GA4 event name (e.g. 'gengage-cart-add').
3545
- * The callback receives the event detail and should return true (success) or false (failure).
3546
- * For add-to-cart, failure triggers an error message in the chat.
3547
- * @returns unsubscribe function
3548
- */
3549
- addCallback(e, t) {
3550
- let a = this._eventCallbacks.get(e);
3551
- return a || (a = /* @__PURE__ */ new Set(), this._eventCallbacks.set(e, a)), a.add(t), () => {
3552
- a.delete(t), a.size === 0 && this._eventCallbacks.delete(e);
3553
- };
3554
- }
3555
- // ---------------------------------------------------------------------------
3556
- // Private
3557
- // ---------------------------------------------------------------------------
3558
- /** Reset all chat state when navigating to a different SKU/page. */
3559
- _resetForNewPage() {
3560
- this._abortControllers.forEach((e) => e.abort()), this._abortControllers.clear(), this._activeTypewriter?.cancel(), this._activeTypewriter = null, this._activeTtsHandle?.stop(), this._activeTtsHandle = null, this._messages.length = 0, this._drawer?.clearMessages(), this._drawer?.clearPanel(), this._panel.snapshots.clear(), this._panel.threads = [], this._thumbnailEntries = [], this._drawer?.setThumbnails([]), this._comparisonSelectMode = !1, this._comparisonSelectedSkus = [], this._currentThreadId = null, this._lastThreadId = null, this._lastBackendContext = null, this._chatCreatedAt = (/* @__PURE__ */ new Date()).toISOString(), this._pdpLaunched = !1, this._productContextUnavailableSku = null;
3561
- }
3562
- _handleBridgeMessage(e) {
3563
- switch (e.type) {
3564
- case "openChat":
3565
- this.open();
3566
- break;
3567
- case "closeChat":
3568
- this.close();
3569
- break;
3570
- case "startNewChatWithLauncherAction": {
3571
- const t = e.payload, a = t?.action, n = te(a) ? a : te(t) ? t : null;
3572
- n && this._sendAction(n, { silent: !0 }), this.open();
3573
- break;
3574
- }
3575
- case "startNewChatWithDetailContext": {
3576
- const t = e.payload;
3577
- if (t && typeof t == "object") {
3578
- this._bridgeContext = t;
3579
- const a = t.sku;
3580
- if (a && this.update({ sku: a }), te(t.action)) {
3581
- this._pdpLaunched = !0, this.open(), this._sendAction(t.action);
3582
- break;
3583
- }
3584
- }
3585
- this.open();
3586
- break;
3587
- }
3588
- case "launcherAction": {
3589
- const a = e.payload?.action;
3590
- a && typeof a == "object" && "type" in a && this._sendAction(a);
3591
- break;
3592
- }
3593
- case "scrollToBottom":
3594
- this._drawer?.scrollToBottomIfNeeded();
3595
- break;
3596
- case "addToCardHandler": {
3597
- this._bridge?.send("addToCardResult", e.payload);
3598
- break;
3599
- }
3600
- case "cartQuantityHandler": {
3601
- const t = e.payload;
3602
- t && "quantity" in t && typeof t.quantity == "number" && (this._cartQuantity = t.quantity);
3603
- break;
3604
- }
3605
- case "minimizeRequestedByUser":
3606
- this._extendedModeManager?.setHiddenByUser(!0);
3607
- break;
3608
- case "bgColorChange": {
3609
- const a = e.payload?.color;
3610
- typeof a == "string" && un(a) && this._shadow && this._shadow.host.style.setProperty("--gengage-chat-bg", a);
3611
- break;
3612
- }
3613
- }
3614
- }
3615
- _registerPublicAPI() {
3616
- window.gengage || (window.gengage = {}), window.gengage.chat = {
3617
- open: (e) => this.open(e),
3618
- openWithAction: (e, t) => this.openWithAction(e, t),
3619
- sendMessage: (e) => this.sendMessage(e),
3620
- sendAction: (e, t) => this.sendAction(e, t),
3621
- close: () => this.close(),
3622
- saveSession: (e, t) => this.saveSession(e, t),
3623
- get isOpen() {
3624
- return !1;
3625
- },
3626
- // Placeholder, overridden below
3627
- on: (e, t) => this.on(e, t),
3628
- trackCheckout: (e, t) => this.trackCheckout(e, t),
3629
- flushMeteringSummary: (e) => this.flushMeteringSummary(e),
3630
- addCallback: (e, t) => this.addCallback(e, t)
3631
- }, Object.defineProperty(window.gengage.chat, "isOpen", {
3632
- get: () => this._drawerVisible
3633
- });
3634
- }
3635
- _showDrawer() {
3636
- if (this._drawerVisible) return;
3637
- this._drawerVisible = !0;
3638
- const e = this._drawer?.getElement();
3639
- e && e.classList.remove("gengage-chat-drawer--hidden"), this._applyOpenStateClasses(), this._isMobileViewport && this._openState === "half" || this._drawer?.focusInput(), this._extendedModeManager?.setChatShown(!0);
3640
- }
3641
- _showProactivePopup(e, t) {
3642
- if (this._proactiveShown || !this._rootEl) return;
3643
- this._proactiveShown = !0;
3644
- try {
3645
- sessionStorage.setItem("gengage_proactive_shown", "1");
3646
- } catch {
3647
- }
3648
- this._setProactiveCooldown();
3649
- const a = {
3650
- message: e,
3651
- onAccept: () => this.open(),
3652
- onDismiss: () => {
3653
- },
3654
- ...t && t.length > 0 && { actionButtons: t }
3655
- };
3656
- this.config.proactiveAcceptLabel !== void 0 && (a.acceptLabel = this.config.proactiveAcceptLabel);
3657
- const n = Ht(a);
3658
- this._rootEl.appendChild(n);
3659
- }
3660
- /** Fetch proactive actions from backend and show popup with per-action buttons. */
3661
- async _fetchAndShowProactive() {
3662
- if (!this._proactiveShown)
3663
- try {
3664
- const e = {
3665
- middlewareUrl: this.config.middlewareUrl,
3666
- accountId: this.config.accountId,
3667
- backendType: this.config.backendType ?? "v1"
3668
- }, t = this.config.pageContext?.sku, a = this.config.pageContext?.pageType, n = this.config.locale, o = await Et(
3669
- {
3670
- account_id: this.config.accountId,
3671
- ...t && { sku: t },
3672
- ...a && { page_type: a },
3673
- ...n && { output_language: n }
3674
- },
3675
- e
3676
- );
3677
- if (!o) return;
3678
- const s = o.question ?? o.title ?? "";
3679
- if (!s) return;
3680
- const l = [];
3681
- if (o.actions && Array.isArray(o.actions))
3682
- for (const r of o.actions) {
3683
- const c = r, d = c.title;
3684
- if (d && te(c.requestDetails)) {
3685
- const g = c.requestDetails;
3686
- l.push({
3687
- title: d,
3688
- onSelect: () => {
3689
- this.openWithAction(g);
3690
- }
3691
- });
3692
- }
3693
- }
3694
- this._showProactivePopup(s, l);
3695
- } catch {
3696
- }
3697
- }
3698
- _proactiveCooldownKey() {
3699
- return `gengage_proactive_time_${this.config.accountId}`;
3700
- }
3701
- _isProactiveCooldownActive() {
3702
- try {
3703
- const e = localStorage.getItem(this._proactiveCooldownKey());
3704
- if (e) {
3705
- const t = Date.now() - parseInt(e, 10), a = this.config.proactiveCooldownMs ?? 36e5;
3706
- return t < a;
3707
- }
3708
- } catch {
3709
- }
3710
- return !1;
3711
- }
3712
- _setProactiveCooldown() {
3713
- try {
3714
- localStorage.setItem(this._proactiveCooldownKey(), String(Date.now()));
3715
- } catch {
3716
- }
3717
- }
3718
- _hideDrawer() {
3719
- if (!this._drawerVisible) return;
3720
- this._activeTypewriter?.cancel(), this._activeTypewriter = null, this._activeTtsHandle?.stop(), this._activeTtsHandle = null, this._drawerVisible = !1, this._openState = "full";
3721
- const e = this._drawer?.getElement();
3722
- e && e.classList.add("gengage-chat-drawer--hidden"), this._applyOpenStateClasses(), this._extendedModeManager?.setChatShown(!1);
3723
- }
3724
- _syncViewportState() {
3725
- if (this._rootEl) {
3726
- if (this._isMobileViewport = window.innerWidth <= this._mobileBreakpoint, this._rootEl.classList.toggle("gengage-chat-root--mobile", this._isMobileViewport), this._launcher) {
3727
- const e = this._isMobileViewport && this.config.hideMobileLauncher === !0;
3728
- this._launcher.container.classList.toggle("gengage-chat-launcher--hidden-mobile", e);
3729
- }
3730
- this._applyOpenStateClasses();
3731
- }
3732
- }
3733
- _applyOpenStateClasses() {
3734
- if (!this._rootEl) return;
3735
- const e = this._drawerVisible && this._isMobileViewport && this._openState === "half", t = this._drawerVisible && this._isMobileViewport && this._openState === "full";
3736
- this._rootEl.classList.toggle("gengage-chat-root--open", this._drawerVisible), this._rootEl.classList.toggle("gengage-chat-root--mobile-half", e), this._rootEl.classList.toggle("gengage-chat-root--mobile-full", t);
3737
- }
3738
- _handleAttachment(e) {
3739
- const t = vt(e);
3740
- if (!t.ok) {
3741
- const a = t.reason === "invalid_type" ? this._i18n.invalidFileType : this._i18n.fileTooLarge;
3742
- j("gengage:global:error", {
3743
- message: a,
3744
- source: "chat"
3745
- });
3746
- return;
3747
- }
3748
- this._drawer?.stageAttachment(e);
3749
- }
3750
- _sendMessage(e, t) {
3751
- je(), this._messages.some((o) => o.role === "user") || Ve();
3752
- const n = {
3753
- title: e,
3754
- type: "user_message",
3755
- payload: e
3756
- };
3757
- t !== void 0 ? this._sendAction(n, { attachment: t }) : this._sendAction(n);
3758
- }
3759
- _sendAction(e, t) {
3760
- if (this._activeTypewriter?.cancel(), this._activeTypewriter = null, this._activeTtsHandle?.stop(), this._activeTtsHandle = null, !this._initComplete) {
3761
- this._pendingActions.length < 10 && this._pendingActions.push({ action: e, options: t });
3762
- return;
3763
- }
3764
- if (this._choicePrompterEl?.remove(), this._choicePrompterEl = null, this._currentThreadId && this._lastThreadId && this._lastThreadId > this._currentThreadId) {
3765
- const m = this._currentThreadId, k = this._messages.filter((h) => h.threadId !== void 0 && h.threadId > m);
3766
- this._messages = this._messages.filter((h) => !h.threadId || h.threadId <= m);
3767
- for (const h of k)
3768
- this._shadow?.querySelector(`[data-message-id="${CSS.escape(h.id)}"]`)?.remove(), this._panel.snapshots.delete(h.id), this._panel.snapshotTypes.delete(h.id);
3769
- this._shadow?.querySelectorAll("[data-thread-id]")?.forEach((h) => {
3770
- h instanceof HTMLElement && h.dataset.threadId && h.dataset.threadId > m && h.remove();
3771
- });
3772
- }
3773
- this._drawer?.setPills([]), this._drawer?.clearInputAreaChips(), this._bridge?.send("isResponding", !0);
3774
- const a = gt();
3775
- this._currentThreadId = a, this._lastThreadId = a, this._panel && e.type !== "launchSingleProduct" && (this._panel.lastActionType = e.type);
3776
- const n = t?.preservePanel === !0, o = e.type === "launchSingleProduct" && t?.silent === !0;
3777
- if (n || (this._activeRequestThreadId = a), !t?.silent) {
3778
- const m = this._createMessage("user", typeof e.payload == "string" ? e.payload : e.title);
3779
- m.threadId = a, t?.attachment !== void 0 && (m.attachment = t.attachment), this._drawer?.addMessage(m), this._messages.push(m);
3780
- }
3781
- if (!t?.silent && this._hasUnavailableProductContext() && (e.type === "user_message" || e.type === "inputText")) {
3782
- const m = this._i18n.productNotFoundMessage, k = this._createMessage("assistant", m);
3783
- k.threadId = a, k.status = "done", this._messages.push(k), this._ensureAssistantMessageRendered(k), this._drawer?.updateBotMessage(k.id, m), this._bridge?.send("isResponding", !1), this.emit("message", k), this._persistToIndexedDB().catch(() => {
3784
- });
3785
- return;
3786
- }
3787
- t?.preservePanel || (this._drawer?.hasPanelContent() ? this._drawer.showPanelLoading() : this._drawer?.clearPanel()), this._drawer?.showTypingIndicator();
3788
- let l = "";
3789
- const r = this._createMessage("assistant", "");
3790
- r.threadId = a, r.status = "streaming", t?.silent && (r.silent = !0), this._messages.push(r), t?.preservePanel || (this._abortControllers.forEach((m) => m.abort()), this._abortControllers.clear());
3791
- const c = {
3792
- middlewareUrl: this.config.middlewareUrl,
3793
- ...this.config.backendType ? { backendType: this.config.backendType } : {},
3794
- ...this.config.accountId ? { accountId: this.config.accountId } : {}
3795
- };
3796
- t?.attachment !== void 0 && (c.attachment = t.attachment);
3797
- const g = this._getVisibleMessages().filter((m) => m.content).slice(-50).map((m) => ({
3798
- role: m.role === "user" ? "user" : "model",
3799
- content: m.content ?? ""
3800
- })), u = {
3801
- outputLanguage: $a(this.config.locale),
3802
- parentUrl: window.location.href,
3803
- windowWidth: String(window.innerWidth),
3804
- windowHeight: String(window.innerHeight),
3805
- selfUrl: "",
3806
- id: this.config.session?.sessionId ?? "",
3807
- userId: this.config.session?.userId ?? "",
3808
- appId: this.config.accountId,
3809
- threads: [],
3810
- createdAt: this._chatCreatedAt,
3811
- kvkkApproved: be(this.config.accountId),
3812
- voiceEnabled: this.config.voiceEnabled ?? !1,
3813
- threadId: a,
3814
- isControlGroup: this.config.session?.abTestVariant === "control",
3815
- isMobile: this._isMobileViewport
3816
- };
3817
- this.config.session?.viewId !== void 0 && (u.viewId = this.config.session.viewId);
3818
- const p = _t(e, {
3819
- pageContext: this.config.pageContext,
3820
- backendContext: this._lastBackendContext,
3821
- isMobile: this._isMobileViewport
3822
- }), b = {
3823
- account_id: this.config.accountId,
3824
- session_id: this.config.session?.sessionId ?? "",
3825
- correlation_id: this.config.session?.sessionId ?? "",
3826
- type: p.type,
3827
- locale: this.config.locale ?? "tr",
3828
- meta: u,
3829
- context: {
3830
- // Spread backend context (panel, message_id, etc.) but preserve FE's
3831
- // authoritative chatHistory — the backend's stale `messages` must not
3832
- // overwrite the up-to-date conversation history built by the widget.
3833
- ...this._lastBackendContext ?? {},
3834
- messages: g,
3835
- // V1 backend reads session_id from context (not top-level).
3836
- // Include here for V1 compatibility; V2 uses thread_id from meta.
3837
- session_id: this.config.session?.sessionId ?? ""
3838
- }
3839
- };
3840
- this.config.session?.userId !== void 0 && (b.user_id = this.config.session.userId), this.config.session?.viewId !== void 0 && (b.view_id = this.config.session.viewId), p.payload !== void 0 && (b.payload = p.payload), this.config.pageContext?.sku !== void 0 && (b.sku = this.config.pageContext.sku), this.config.pageContext?.pageType !== void 0 && (b.page_type = this.config.pageContext.pageType);
3841
- const y = crypto.randomUUID(), _ = Date.now();
3842
- let I = 0, C = !1, T = !1;
3843
- this.track(
3844
- $e(this.analyticsContext(), {
3845
- endpoint: "process_action",
3846
- request_id: y,
3847
- widget: "chat"
3848
- })
3849
- );
3850
- let v = null;
3851
- v = Ct(
3852
- b,
3853
- {
3854
- onTextChunk: (m, k, S) => {
3855
- if (!n && a !== this._activeRequestThreadId || (l += m, this._drawer?.removeTypingIndicator(), S?.skuToProductItem && (this._skuToProductItem = { ...this._skuToProductItem, ...S.skuToProductItem }), S?.conversationMode && (this._conversationMode = S.conversationMode), this.track(
3856
- lt(this.analyticsContext(), {
3857
- request_id: y,
3858
- chunk_index: I++,
3859
- widget: "chat"
3860
- })
3861
- ), !this._drawer)) return;
3862
- let h = l;
3863
- if (k && le(h)) {
3864
- const w = this.config.accountId;
3865
- if (!be(w)) {
3866
- const P = ja(h);
3867
- P && this._drawer?.showKvkkBanner(P, () => {
3868
- this._drawer?.hideKvkkBanner();
3869
- }), qa(w);
3870
- }
3871
- h = Oa(h);
3872
- }
3873
- const f = this._shadow?.querySelector(
3874
- `[data-message-id="${r.id}"] .gengage-chat-bubble-text`
3875
- );
3876
- if (f ? f.innerHTML = $(h) : (r.content = h, r.role === "assistant" && r.threadId && !this._threadsWithFirstBot.has(r.threadId) && (this._threadsWithFirstBot.add(r.threadId), this._drawer.markFirstBotMessage(r.id)), this._drawer.addMessage(r)), k) {
3877
- r.content = h, r.status = "done", de();
3878
- const w = this._shadow?.querySelector(
3879
- `[data-message-id="${r.id}"] .gengage-chat-bubble-text`
3880
- );
3881
- if (w) {
3882
- this._activeTypewriter?.cancel();
3883
- const P = S?.productMentions;
3884
- this._activeTypewriter = Sa({
3885
- container: w,
3886
- html: $(h),
3887
- onTick: () => this._drawer?.scrollToBottomIfNeeded(),
3888
- onComplete: () => {
3889
- this._activeTypewriter = null, P && P.length > 0 && w && Ta({
3890
- container: w,
3891
- mentions: P,
3892
- onProductClick: (D) => {
3893
- this._sendAction({
3894
- title: P.find((E) => E.sku === D)?.short_name ?? D,
3895
- type: "launchSingleProduct",
3896
- payload: { sku: D }
3897
- });
3898
- }
3899
- });
3900
- }
3901
- });
3902
- }
3903
- }
3904
- },
3905
- onUISpec: (m, k, S) => {
3906
- if (!n && a !== this._activeRequestThreadId || k !== "chat") return;
3907
- const h = m.elements[m.root], f = h?.type ?? "unknown";
3908
- this.track(
3909
- rt(this.analyticsContext(), {
3910
- request_id: y,
3911
- chunk_index: I,
3912
- component_type: f,
3913
- widget: "chat"
3914
- })
3915
- );
3916
- const w = this._buildRenderContext();
3917
- if (f === "ComparisonTable") {
3918
- const E = h?.props?.products;
3919
- st(Array.isArray(E) ? E.length : 0);
3920
- }
3921
- if (f === "ProductGrid") {
3922
- const E = h?.children?.length ?? 0;
3923
- ct(void 0, E);
3924
- }
3925
- const P = S === "panel" && this._panel ? this._panel.toPanelSpec(m) : m, D = !r.silent && (S !== "panel" || f === "ProductCard") && f !== "ActionButtons";
3926
- if (S === "panel" && this._panel) {
3927
- T = !0, h?.props?.similarsAppend === !0 && this._panel.currentType === "ProductDetailsPanel" && this._drawer?.hasPanelContent() && !this._drawer.isPanelLoading() ? this._appendSimilarsToPanel(P, w) : f === "ProductGrid" && this._drawer?.hasPanelContent() && !this._drawer.isPanelLoading() ? this._drawer.appendPanelContent(this._renderUISpec(P, w)) : (this._comparisonSelectMode = !1, this._comparisonSelectedSkus = [], this._drawer?.setPanelContent(this._renderUISpec(P, w)), this._panel.currentType = f), f === "ProductDetailsPanel" && e.type === "launchSingleProduct" && this._clearUnavailableProductContext(), r.threadId && !this._panel.threads.includes(r.threadId) && this._panel.threads.push(r.threadId);
3928
- const E = this._panel.currentType ?? f, N = h?.props?.panelTitle;
3929
- this._panel.updateTopBar(E, N), this._panel.updateExtendedMode(f);
3930
- }
3931
- if (f === "ProductDetailsPanel" && !r.silent && S === "panel") {
3932
- const E = h?.props?.product;
3933
- if (E) {
3934
- const N = {
3935
- root: "root",
3936
- elements: {
3937
- root: {
3938
- type: "ProductSummaryCard",
3939
- props: { product: E }
3940
- }
3941
- }
3942
- }, B = this._shadow?.querySelector(".gengage-chat-messages");
3943
- if (B) {
3944
- const L = this._renderUISpec(N, w);
3945
- r.threadId && (L.dataset.threadId = r.threadId), B.appendChild(L), L.scrollIntoView({ behavior: "auto", block: "end" });
3946
- }
3947
- }
3948
- }
3949
- if (D) {
3950
- const E = this._shadow?.querySelector(".gengage-chat-messages");
3951
- if (E) {
3952
- const N = this._renderUISpec(m, w);
3953
- r.threadId && (N.dataset.threadId = r.threadId), E.appendChild(N), N.scrollIntoView({ behavior: "auto", block: "end" });
3954
- }
3955
- }
3956
- if ((f === "ProductGrid" || f === "ProductCard") && r.threadId) {
3957
- const E = h?.children ?? [], N = f === "ProductGrid" ? E.map((B) => m.elements[B]?.props?.product).filter(Boolean) : [h?.props?.product].filter(Boolean);
3958
- for (const B of N) {
3959
- const L = B.sku, M = B.imageUrl;
3960
- L && M && this._thumbnailEntries.push({ sku: L, imageUrl: M, threadId: r.threadId });
3961
- }
3962
- this._drawer?.setThumbnails(this._thumbnailEntries);
3963
- }
3964
- if (f === "ProductGrid" || f === "ProductDetailsPanel") {
3965
- const N = (f === "ProductGrid" ? (h?.children ?? []).map((B) => m.elements[B]?.props?.product).filter(Boolean) : [
3966
- h?.props?.product ?? h?.props
3967
- ].filter(Boolean)).map((B) => B.imageUrl).filter((B) => typeof B == "string").slice(0, 5);
3968
- N.length > 0 && this._bridge?.send("previewImages", { images: N });
3969
- }
3970
- if (f === "ProductGrid" && S === "panel" && !this._comparisonSelectMode && !Pa() && (this._choicePrompterEl?.remove(), this._choicePrompterEl = Aa({
3971
- heading: this._i18n.choicePrompterHeading,
3972
- suggestion: this._i18n.choicePrompterSuggestion,
3973
- ctaLabel: this._i18n.choicePrompterCta,
3974
- onCtaClick: () => {
3975
- this._comparisonSelectMode = !0, this._choicePrompterEl = null, this._refreshComparisonUI();
3976
- },
3977
- onDismiss: () => {
3978
- this._choicePrompterEl = null;
3979
- }
3980
- }), this._shadow?.querySelector(".gengage-chat-panel")?.appendChild(this._choicePrompterEl)), f === "ActionButtons") {
3981
- const E = h?.props?.buttons;
3982
- if (E && E.length > 0) {
3983
- const N = [], B = [];
3984
- for (const L of E)
3985
- if (Na(L)) {
3986
- const M = {
3987
- label: L.label,
3988
- action: L.action
3989
- };
3990
- L.icon && (M.icon = L.icon), N.push(M);
3991
- } else
3992
- B.push(L);
3993
- N.length > 0 && this._drawer?.setInputAreaChips(
3994
- N.map((L) => ({
3995
- label: L.label,
3996
- onAction: () => this._sendAction(L.action),
3997
- ...L.icon ? { icon: L.icon } : {}
3998
- }))
3999
- ), B.length > 0 && this._drawer?.setPills(
4000
- B.map((L) => {
4001
- const M = {
4002
- label: L.label,
4003
- onAction: () => this._sendAction(L.action)
4004
- };
4005
- return L.icon && (M.icon = L.icon), L.image && (M.image = L.image), L.description && (M.description = L.description), M;
4006
- })
4007
- );
4008
- }
4009
- }
4010
- r.uiSpec = m;
4011
- },
4012
- onAction: (m) => {
4013
- if (!(!n && a !== this._activeRequestThreadId) && m.type === "action") {
4014
- const k = {};
4015
- this.config.actionHandling?.unknownActionPolicy !== void 0 && (k.unknownActionPolicy = this.config.actionHandling.unknownActionPolicy), this.config.actionHandling?.allowScriptCall !== void 0 && (k.allowScriptCall = this.config.actionHandling.allowScriptCall), ut(
4016
- m,
4017
- {
4018
- openChat: () => this.open(),
4019
- navigate: (S) => {
4020
- this._bridge?.send("navigate", S), S.newTab ? window.open(S.url, "_blank", "noopener,noreferrer") : window.location.href = S.url;
4021
- },
4022
- saveSession: (S) => this.saveSession(S.sessionId, S.sku),
4023
- addToCart: (S) => {
4024
- j("gengage:similar:add-to-cart", S);
4025
- },
4026
- scriptCall: (S) => {
4027
- j("gengage:chat:script-call", S), this.config.onScriptCall?.(S);
4028
- }
4029
- },
4030
- k
4031
- );
4032
- }
4033
- },
4034
- onMetadata: (m) => {
4035
- if (!(!n && a !== this._activeRequestThreadId) && m.type === "metadata" && m.meta) {
4036
- if ((m.meta.panel !== void 0 || m.meta.messages !== void 0 || m.meta.message_id !== void 0) && (this._lastBackendContext = m.meta), m.meta.panelLoading) {
4037
- C = !0, T = !1;
4038
- const S = typeof m.meta.panelPendingType == "string" ? m.meta.panelPendingType : void 0;
4039
- this._panel && (this._panel.currentType = null), this._drawer?.showPanelLoading(S), S && this._panel?.updateTopBarForLoading(S);
4040
- }
4041
- if (m.meta.voice) {
4042
- const S = new CustomEvent("gengage:chat:voice", {
4043
- detail: { payload: m.meta.voice },
4044
- bubbles: !1,
4045
- cancelable: !0
4046
- }), h = window.dispatchEvent(S);
4047
- if (it(), h) {
4048
- const f = m.meta.voice;
4049
- f.audio_base64 && (this._activeTtsHandle?.stop(), this._activeTtsHandle = Ot(
4050
- f.audio_base64,
4051
- f.content_type ?? "audio/ogg"
4052
- ));
4053
- }
4054
- }
4055
- (m.meta.redirectTarget || m.meta.redirect) && j("gengage:chat:redirect", {
4056
- target: m.meta.redirectTarget ?? null,
4057
- payload: m.meta.redirect ?? null
4058
- }), m.meta.analyzeAnimation && (C = !0, T = !1, this._panel && (this._panel.currentType = null), this._drawer?.showPanelLoading(), this._panel?.updateTopBarForLoading("productDetails")), m.meta.loading && typeof m.meta.loadingText == "string" && (this._drawer?.addThinkingStep(m.meta.loadingText), this._bridge?.send("loadingMessage", { text: m.meta.loadingText })), m.meta.visitorDataResponse && this._bridge?.send("engagingMessage", m.meta.visitorDataResponse), m.meta.formType && this._bridge?.send("glovOtokoc", {
4059
- type: m.meta.formType,
4060
- data: m.meta.formPayload
4061
- }), m.meta.launcherContent && this._bridge?.send("launcherContent", m.meta.launcherContent), j("gengage:chat:metadata", { payload: m.meta });
4062
- const k = m.meta;
4063
- typeof k.prompt_tokens == "number" && typeof k.completion_tokens == "number" && this.track(
4064
- ot(this.analyticsContext(), {
4065
- model: m.model ?? "unknown",
4066
- prompt_tokens: k.prompt_tokens,
4067
- completion_tokens: k.completion_tokens,
4068
- total_tokens: k.total_tokens ?? k.prompt_tokens + k.completion_tokens
4069
- })
4070
- );
4071
- }
4072
- },
4073
- onError: (m) => {
4074
- if (v && this._abortControllers.delete(v), !n && a !== this._activeRequestThreadId) return;
4075
- this._bridge?.send("isResponding", !1), this._bridge?.send("loadingMessage", { text: null }), this._drawer?.removeTypingIndicator();
4076
- const k = T;
4077
- if (C && !T && this._drawer?.isPanelLoading() && this._drawer.clearPanel(), C = !1, T = !1, !(r.silent || r.content != null && r.content.length > 0 || l.length > 0 || k))
4078
- if (o || this._hasUnavailableProductContext()) {
4079
- const h = this._i18n.productNotFoundMessage;
4080
- r.content = h, r.status = "done", this._ensureAssistantMessageRendered(r), this._drawer?.updateBotMessage(r.id, h), this._markUnavailableProductContext();
4081
- } else
4082
- this.emit("error", m), this._drawer?.showError(this._i18n.errorMessage);
4083
- r.status === "streaming" && (r.status = "error"), this.track(
4084
- nt(this.analyticsContext(), {
4085
- request_id: y,
4086
- error_code: "STREAM_ERROR",
4087
- error_message: m.message,
4088
- widget: "chat"
4089
- })
4090
- );
4091
- },
4092
- onDone: () => {
4093
- if (v && this._abortControllers.delete(v), !(!n && a !== this._activeRequestThreadId)) {
4094
- if (this._activeRequestThreadId = null, this._bridge?.send("isResponding", !1), this._bridge?.send("loadingMessage", { text: null }), this._drawer?.removeTypingIndicator(), C && !T && this._drawer?.isPanelLoading() && this._drawer.clearPanel(), C = !1, T = !1, o && !l && !T) {
4095
- const m = this._i18n.productNotFoundMessage;
4096
- r.content = m, this._ensureAssistantMessageRendered(r), this._drawer?.updateBotMessage(r.id, m), this._markUnavailableProductContext();
4097
- }
4098
- r.status === "streaming" && (r.status = "done", de()), this.emit("message", r), this._panel?.snapshotForMessage(r.id), this._panel?.attachClickHandler(r.id), this.track(
4099
- et(this.analyticsContext(), {
4100
- request_id: y,
4101
- latency_ms: Date.now() - _,
4102
- chunk_count: I,
4103
- widget: "chat"
4104
- })
4105
- ), this.track(
4106
- tt(this.analyticsContext(), {
4107
- meter_key: "chat_request",
4108
- quantity: 1,
4109
- unit: "request"
4110
- })
4111
- ), this.track(
4112
- at(this.analyticsContext(), {
4113
- message_count: this._messages.length,
4114
- history_ref: this.config.session?.sessionId ?? "",
4115
- redaction_level: "none"
4116
- })
4117
- ), this._persistToIndexedDB().catch(() => {
4118
- });
4119
- }
4120
- }
4121
- },
4122
- c
4123
- ), this._abortControllers.add(v);
4124
- }
4125
- /** Return messages visible at the current thread cursor. */
4126
- _getVisibleMessages() {
4127
- const e = this._messages.filter((a) => !a.silent);
4128
- if (!this._currentThreadId) return e;
4129
- const t = this._currentThreadId;
4130
- return e.filter((a) => !a.threadId || a.threadId <= t);
4131
- }
4132
- /** Handle rollback-on-click from a user message bubble. */
4133
- _appendSimilarsToPanel(e, t) {
4134
- if (!this._drawer) return;
4135
- const a = this._drawer.getPanelContentElement();
4136
- if (!a) return;
4137
- const n = document.createElement("h3");
4138
- n.className = "gengage-chat-product-details-similars-heading", n.textContent = this._i18n.similarProductsLabel ?? "Benzer Ürünler", a.appendChild(n);
4139
- const o = this._renderUISpec(e, t);
4140
- o.classList.add("gengage-chat-product-details-similars"), a.appendChild(o);
4141
- }
4142
- _handleRollback(e) {
4143
- const t = this._messages.find((a) => a.id === e);
4144
- t?.threadId && this._rollbackToThread(t.threadId);
4145
- }
4146
- /** Rewind the conversation to the given thread. */
4147
- _rollbackToThread(e) {
4148
- this._currentThreadId = e, this._extendedModeManager?.setHiddenByUser(!1);
4149
- for (const o of this._messages) {
4150
- const s = this._shadow?.querySelector(`[data-message-id="${CSS.escape(o.id)}"]`);
4151
- s && (o.threadId && o.threadId > e ? s.classList.add("gengage-chat-bubble--hidden") : s.classList.remove("gengage-chat-bubble--hidden"));
4152
- }
4153
- this._shadow?.querySelectorAll("[data-thread-id]").forEach((o) => {
4154
- o instanceof HTMLElement && o.dataset.threadId && o.dataset.threadId > e ? o.classList.add("gengage-chat-bubble--hidden") : o instanceof HTMLElement && o.classList.remove("gengage-chat-bubble--hidden");
4155
- });
4156
- const t = this._messages.find((o) => o.role === "assistant" && o.threadId === e);
4157
- t && this._panel?.restoreForMessage(t.id) || this._drawer?.clearPanel();
4158
- const n = this._panel.currentType ?? "";
4159
- this._panel?.updateTopBar(n), this._drawer?.setPills([]), this._session?.db && this.config.session?.sessionId && this._session?.db.loadContext(this.config.session.sessionId, e).then((o) => {
4160
- o && (this._lastBackendContext = o.context);
4161
- }).catch(() => {
4162
- }), this._session?.db && this.config.session?.sessionId && this._session?.db.deleteContextsAfterThread(this.config.session.sessionId, e).catch(() => {
4163
- });
4164
- }
4165
- // ---------------------------------------------------------------------------
4166
- // IndexedDB persistence (delegates to SessionPersistence)
4167
- // ---------------------------------------------------------------------------
4168
- async _persistToIndexedDB() {
4169
- !this._session || !this.config.session?.sessionId || await this._session.persist({
4170
- userId: this.config.session.userId ?? "",
4171
- appId: this.config.accountId,
4172
- sessionId: this.config.session.sessionId,
4173
- messages: this._messages,
4174
- currentThreadId: this._currentThreadId,
4175
- lastThreadId: this._lastThreadId,
4176
- chatCreatedAt: this._chatCreatedAt,
4177
- panelSnapshots: this._panel?.snapshots ?? /* @__PURE__ */ new Map(),
4178
- panelThreads: this._panel?.threads ?? [],
4179
- thumbnailEntries: this._thumbnailEntries,
4180
- lastBackendContext: this._lastBackendContext,
4181
- sku: this.config.pageContext?.sku
4182
- });
4183
- }
4184
- _isSameOriginUrl(e) {
4185
- try {
4186
- return e.trim() ? new URL(e, window.location.href).origin === window.location.origin : !1;
4187
- } catch {
4188
- return !1;
4189
- }
4190
- }
4191
- _markUnavailableProductContext() {
4192
- this._productContextUnavailableSku = this.config.pageContext?.sku ?? null;
4193
- }
4194
- _clearUnavailableProductContext() {
4195
- this._productContextUnavailableSku = null;
4196
- }
4197
- _hasUnavailableProductContext() {
4198
- const e = this.config.pageContext?.sku;
4199
- return e !== void 0 && e.length > 0 && this._productContextUnavailableSku === e;
4200
- }
4201
- _ensureAssistantMessageRendered(e) {
4202
- if (!(this._shadow?.querySelector(`[data-message-id="${CSS.escape(e.id)}"]`) || !this._drawer)) {
4203
- if (e.role === "assistant" && e.threadId && !this._threadsWithFirstBot.has(e.threadId)) {
4204
- this._threadsWithFirstBot.add(e.threadId), this._drawer.addMessage(e), this._drawer.markFirstBotMessage(e.id);
4205
- return;
4206
- }
4207
- this._drawer.addMessage(e);
4208
- }
4209
- }
4210
- async _saveSessionAndOpenURL(e) {
4211
- this._session && await this._session.saveAndOpenURL(e, () => this._persistToIndexedDB(), this._bridge);
4212
- }
4213
- async _loadPayload(e, t) {
4214
- return this._session ? this._session.loadPayload(e, t) : null;
4215
- }
4216
- /**
4217
- * Attempt to restore chat session from IndexedDB.
4218
- * Always restores when IDB has session data for the current sessionId.
4219
- * Best-effort — failures are silently ignored.
4220
- */
4221
- async _restoreFromIndexedDB(e) {
4222
- if (!this._session?.db) return;
4223
- const t = this.config.session?.sessionId;
4224
- if (!t) return;
4225
- const a = this.config.session?.userId ?? "", n = this.config.accountId;
4226
- if (await this._session.loadFavorites(a, n), !e) return;
4227
- const o = await this._session.db?.loadSession(a, n, t);
4228
- if (!o || o.messages.length === 0) return;
4229
- const s = this.config.pageContext?.sku;
4230
- if (s && o.sku && o.sku !== s) return;
4231
- if (this._pdpLaunched = !0, this._drawer?.lockScrollForRestore(), this._currentThreadId = o.currentThreadId, this._lastThreadId = o.lastThreadId, this._chatCreatedAt = o.createdAt, o.panelThreads && (this._panel.threads = o.panelThreads), o.thumbnailEntries && (this._thumbnailEntries = o.thumbnailEntries, this._drawer?.setThumbnails(this._thumbnailEntries)), o.panelSnapshotHtml)
4232
- for (const [r, c] of Object.entries(o.panelSnapshotHtml)) {
4233
- const d = document.createElement("div");
4234
- d.innerHTML = $(c), this._panel.snapshots.set(r, d);
4235
- }
4236
- let l = 0;
4237
- for (const r of o.messages) {
4238
- const c = {
4239
- id: r.id,
4240
- role: r.role,
4241
- timestamp: r.timestamp,
4242
- status: r.status
4243
- };
4244
- if (r.threadId !== void 0 && (c.threadId = r.threadId), r.content !== void 0 && (c.content = r.content), r.silent && (c.silent = !0), this._messages.push(c), c.silent) continue;
4245
- c.role === "assistant" && c.threadId && !this._threadsWithFirstBot.has(c.threadId) && (this._threadsWithFirstBot.add(c.threadId), this._drawer?.markFirstBotMessage(c.id)), this._drawer?.addMessage(c);
4246
- const d = parseInt(r.id.replace("msg-", ""), 10);
4247
- if (!isNaN(d) && d > l && (l = d), c.role === "assistant" && c.threadId) {
4248
- const g = await this._loadPayload(c.threadId, c.id);
4249
- g && (c.uiSpec = g, this._restoreInlineUISpec(c), this._panel?.attachClickHandler(c.id), delete c.uiSpec);
4250
- }
4251
- }
4252
- if (l > this._currentMessageId && (this._currentMessageId = l), this._currentThreadId) {
4253
- let r = await this._session.db?.loadContext(t, this._currentThreadId);
4254
- r || (r = await this._session.db?.loadLatestContext(t)), r && (this._lastBackendContext = r.context);
4255
- }
4256
- if (this._currentThreadId) {
4257
- const r = [...this._messages].reverse().find((c) => c.role === "assistant" && c.threadId === this._currentThreadId && !c.silent);
4258
- r && this._panel.snapshots.has(r.id) && this._panel?.restoreForMessage(r.id);
4259
- }
4260
- if (this._currentThreadId) {
4261
- const r = this._currentThreadId;
4262
- for (const c of this._messages)
4263
- c.threadId && c.threadId > r && this._shadow?.querySelector(`[data-message-id="${CSS.escape(c.id)}"]`)?.classList.add("gengage-chat-bubble--hidden");
4264
- this._shadow?.querySelectorAll("[data-thread-id]").forEach((c) => {
4265
- c instanceof HTMLElement && c.dataset.threadId && c.dataset.threadId > r && c.classList.add("gengage-chat-bubble--hidden");
4266
- });
4267
- }
4268
- if (this._panel.threads.length > 0 && this._currentThreadId) {
4269
- const r = this._panel.threads[this._panel.threads.length - 1];
4270
- if (r) {
4271
- const c = [...this._messages].reverse().find((d) => d.role === "assistant" && d.threadId === r);
4272
- if (c?.threadId) {
4273
- const d = await this._loadPayload(c.threadId, c.id);
4274
- if (d) {
4275
- const g = d.elements[d.root];
4276
- g && this._panel?.updateTopBar(g.type);
4277
- }
4278
- }
4279
- }
4280
- }
4281
- setTimeout(() => {
4282
- this._drawer?.scrollToLastThread();
4283
- }, 550);
4284
- }
4285
- /**
4286
- * Toggle comparison mode or individual SKU selection, then refresh the DOM.
4287
- * Extracted so both the render-context callback and DOM-created checkboxes
4288
- * share the same state-mutation + refresh path.
4289
- */
4290
- _toggleComparisonSku(e) {
4291
- e === "" ? (this._comparisonSelectMode = !this._comparisonSelectMode, this._comparisonSelectMode || (this._comparisonSelectedSkus = [], Ge())) : this._comparisonSelectedSkus.indexOf(e) >= 0 ? this._comparisonSelectedSkus = this._comparisonSelectedSkus.filter((a) => a !== e) : (this._comparisonSelectedSkus = [...this._comparisonSelectedSkus, e], Ke(e)), this._refreshComparisonUI();
4292
- }
4293
- /**
4294
- * Refresh the panel DOM to reflect the current comparison state without
4295
- * full re-render. Updates: toggle button active class, checkbox overlays
4296
- * on product cards, and the floating comparison button.
4297
- */
4298
- _refreshComparisonUI() {
4299
- const e = this._shadow?.querySelector(".gengage-chat-panel");
4300
- if (!e) return;
4301
- const t = e.querySelector(".gengage-chat-product-grid-wrapper");
4302
- if (!t) return;
4303
- const a = t.querySelector(".gengage-chat-product-grid");
4304
- if (!a) return;
4305
- const n = t.querySelector(".gengage-chat-comparison-toggle-btn");
4306
- if (n && n.classList.toggle("gengage-chat-comparison-toggle-btn--active", this._comparisonSelectMode), this._comparisonSelectMode) {
4307
- const s = a.querySelectorAll(".gengage-chat-product-card[data-sku]");
4308
- for (const l of s) {
4309
- if (l.parentElement?.classList.contains("gengage-chat-comparison-select-wrapper")) {
4310
- const g = l.parentElement.querySelector(".gengage-chat-comparison-checkbox");
4311
- g && (g.checked = this._comparisonSelectedSkus.includes(l.dataset.sku));
4312
- continue;
4313
- }
4314
- const r = l.dataset.sku, c = document.createElement("div");
4315
- c.className = "gengage-chat-comparison-select-wrapper";
4316
- const d = document.createElement("input");
4317
- d.type = "checkbox", d.className = "gengage-chat-comparison-checkbox", d.checked = this._comparisonSelectedSkus.includes(r), d.addEventListener("change", () => {
4318
- this._toggleComparisonSku(r);
4319
- }), l.parentNode.insertBefore(c, l), c.appendChild(d), c.appendChild(l);
4320
- }
4321
- } else {
4322
- const s = a.querySelectorAll(".gengage-chat-comparison-select-wrapper");
4323
- for (const l of s) {
4324
- const r = l.querySelector(".gengage-chat-product-card");
4325
- r && l.parentNode && (l.parentNode.insertBefore(r, l), l.remove());
4326
- }
4327
- }
4328
- const o = t.querySelector(".gengage-chat-comparison-floating-btn");
4329
- if (this._comparisonSelectMode && this._comparisonSelectedSkus.length >= 2) {
4330
- const s = this._i18n.compareSelected ?? "Karşılaştır", l = `${s} (${this._comparisonSelectedSkus.length})`;
4331
- if (o)
4332
- o.textContent = l;
4333
- else {
4334
- const r = document.createElement("button");
4335
- r.className = "gengage-chat-comparison-floating-btn", r.type = "button", r.textContent = l, r.addEventListener("click", () => {
4336
- ge(this._comparisonSelectedSkus), this._sendAction({
4337
- title: s,
4338
- type: "getComparisonTable",
4339
- payload: { sku_list: [...this._comparisonSelectedSkus] }
4340
- });
4341
- }), t.appendChild(r);
4342
- }
4343
- } else
4344
- o?.remove();
4345
- }
4346
- /**
4347
- * Build a ChatUISpecRenderContext with all callbacks wired up.
4348
- * Used both during streaming and during session restore.
4349
- */
4350
- _buildRenderContext() {
4351
- const e = {
4352
- onAction: (t) => {
4353
- if (Je(t.title, t.type), t.type === "findSimilar") {
4354
- const n = typeof t.payload == "object" && t.payload !== null && "sku" in t.payload ? String(t.payload.sku) : "";
4355
- Ze(n);
4356
- }
4357
- t.type === "getComparisonTable" && ge(this._comparisonSelectedSkus);
4358
- const a = t.type === "addToCart" || t.type === "like";
4359
- this._sendAction(t, a ? { preservePanel: !0 } : void 0);
4360
- },
4361
- onProductClick: (t) => {
4362
- Xe(t.sku), this.config.isDemoWebsite !== !0 && this._isSameOriginUrl(t.url) ? (j("gengage:similar:product-click", {
4363
- sku: t.sku,
4364
- url: t.url,
4365
- sessionId: this.config.session?.sessionId ?? null
4366
- }), this._saveSessionAndOpenURL(t.url)) : this._sendAction({
4367
- title: t.sku,
4368
- type: "launchSingleProduct",
4369
- payload: { sku: t.sku }
4370
- });
4371
- },
4372
- onAddToCart: (t) => {
4373
- Qe(t.sku, t.quantity);
4374
- const a = {
4375
- ...t,
4376
- sessionId: this.config.session?.sessionId ?? null
4377
- };
4378
- j("gengage:chat:add-to-cart", a), this._bridge?.send("addToCart", t), this._runEventCallbacks("gengage-cart-add", a), this._sendAction(
4379
- {
4380
- title: "Sepete Ekle",
4381
- type: "addToCart",
4382
- payload: { sku: t.sku, cart_code: t.cartCode, quantity: t.quantity }
4383
- },
4384
- { preservePanel: !0 }
4385
- );
4386
- },
4387
- onProductSelect: (t) => {
4388
- const a = {
4389
- root: "root",
4390
- elements: {
4391
- root: {
4392
- type: "ProductDetailsPanel",
4393
- props: { product: t }
4394
- }
4395
- }
4396
- };
4397
- this._drawer?.setPanelContent(this._renderUISpec(a, e));
4398
- },
4399
- i18n: this._i18n,
4400
- pricing: this.config.pricing,
4401
- productSort: this._productSort,
4402
- onSortChange: (t) => {
4403
- this._productSort = t;
4404
- },
4405
- comparisonSelectMode: this._comparisonSelectMode,
4406
- comparisonSelectedSkus: this._comparisonSelectedSkus,
4407
- onToggleComparisonSku: (t) => {
4408
- this._toggleComparisonSku(t);
4409
- },
4410
- favoritedSkus: this._session?.favoritedSkus ?? /* @__PURE__ */ new Set(),
4411
- onFavoriteToggle: (t, a) => {
4412
- Ye(t), this._toggleFavorite(t, a);
4413
- const n = a.name ?? t;
4414
- this._sendAction(
4415
- {
4416
- title: n,
4417
- type: "like",
4418
- payload: { sku: t }
4419
- },
4420
- { preservePanel: !0 }
4421
- );
4422
- }
4423
- };
4424
- return e;
4425
- }
4426
- async _toggleFavorite(e, t) {
4427
- if (!this._session) return;
4428
- const a = this.config.session?.userId ?? "", n = this.config.accountId;
4429
- await this._session.toggleFavorite(a, n, e, t);
4430
- }
4431
- /**
4432
- * Run registered callbacks for a GA4 event.
4433
- * If any callback returns false or throws, handle the failure (e.g. show error for cart-add).
4434
- */
4435
- async _runEventCallbacks(e, t) {
4436
- const a = this._eventCallbacks.get(e);
4437
- if (!(!a || a.size === 0))
4438
- for (const n of a)
4439
- try {
4440
- const o = n(t);
4441
- if ((o instanceof Promise ? await o : o) === !1) {
4442
- this._handleCallbackFailure(e, t);
4443
- return;
4444
- }
4445
- } catch {
4446
- this._handleCallbackFailure(e, t);
4447
- return;
4448
- }
4449
- }
4450
- /**
4451
- * Handle a callback failure — for add-to-cart, show an error message in chat.
4452
- */
4453
- _handleCallbackFailure(e, t) {
4454
- if (e === "gengage-cart-add") {
4455
- const n = this._createMessage("assistant", "Üzgünüm sepete ekleyemedim, bir sorunla karşılaştım.");
4456
- this._currentThreadId && (n.threadId = this._currentThreadId), this._messages.push(n), this._drawer?.addMessage(n);
4457
- }
4458
- }
4459
- /**
4460
- * Re-render inline UISpec elements for a restored bot message.
4461
- * Inserts them into the messages container after the message bubble.
4462
- */
4463
- _restoreInlineUISpec(e) {
4464
- if (!e.uiSpec || !this._drawer) return;
4465
- const t = e.uiSpec, a = t.elements[t.root];
4466
- if (!a) return;
4467
- const n = a.type;
4468
- if (n === "ActionButtons" || n === "ComparisonTable" || n === "ProductGrid" && a.props?.similarsAppend === !0) return;
4469
- const o = this._buildRenderContext(), s = this._shadow?.querySelector(".gengage-chat-messages");
4470
- if (!s) return;
4471
- if (n === "ProductDetailsPanel") {
4472
- const r = a.props?.product;
4473
- if (!r) return;
4474
- const c = {
4475
- root: "root",
4476
- elements: { root: { type: "ProductSummaryCard", props: { product: r } } }
4477
- }, d = this._renderUISpec(c, o);
4478
- e.threadId && (d.dataset.threadId = e.threadId), s.appendChild(d);
4479
- return;
4480
- }
4481
- const l = this._renderUISpec(t, o);
4482
- e.threadId && (l.dataset.threadId = e.threadId), s.appendChild(l);
4483
- }
4484
- _createMessage(e, t) {
4485
- return this._currentMessageId++, {
4486
- id: `msg-${this._currentMessageId}`,
4487
- role: e,
4488
- content: t,
4489
- timestamp: Date.now(),
4490
- status: "done"
4491
- };
4492
- }
4493
- _resolveI18n(e) {
4494
- return { ...It(e.locale), ...e.i18n };
4495
- }
4496
- _resolveUISpecRegistry() {
4497
- const e = da();
4498
- return We(e, this.config.renderer?.registry);
4499
- }
4500
- _renderUISpec(e, t) {
4501
- const a = this._resolveUISpecRegistry(), n = this.config.renderer?.unknownRenderer ?? Ne, o = (r, c) => pa(r, c, a, n), s = this.config.renderer?.renderUISpec;
4502
- return s ? s(e, t, {
4503
- registry: a,
4504
- unknownRenderer: n,
4505
- defaultRender: o
4506
- }) : o(e, t);
4507
- }
4508
- }
4509
- function vn() {
4510
- return new mn();
4511
- }
4512
- export {
4513
- mn as G,
4514
- Nt as V,
4515
- da as a,
4516
- pa as b,
4517
- vn as c,
4518
- Ne as d,
4519
- xn as e,
4520
- Lt as i,
4521
- ut as r
4522
- };
4523
- //# sourceMappingURL=index-BSpLCzAK.js.map