open-chat-studio-widget 0.4.8 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +23 -20
  2. package/dist/cjs/{index-AhSI5tER.js → index-CC3Krx2K.js} +4 -2
  3. package/dist/cjs/index-CC3Krx2K.js.map +1 -0
  4. package/dist/cjs/loader.cjs.js +2 -2
  5. package/dist/cjs/open-chat-studio-widget.cjs.entry.js +1116 -301
  6. package/dist/cjs/open-chat-studio-widget.cjs.entry.js.map +1 -1
  7. package/dist/cjs/open-chat-studio-widget.cjs.js +2 -2
  8. package/dist/cjs/open-chat-studio-widget.entry.cjs.js.map +1 -1
  9. package/dist/collection/components/ocs-chat/{heroicons.js → icons.js} +23 -1
  10. package/dist/collection/components/ocs-chat/icons.js.map +1 -0
  11. package/dist/collection/components/ocs-chat/ocs-chat.css +596 -1983
  12. package/dist/collection/components/ocs-chat/ocs-chat.js +480 -273
  13. package/dist/collection/components/ocs-chat/ocs-chat.js.map +1 -1
  14. package/dist/collection/services/chat-session-service.js +145 -0
  15. package/dist/collection/services/chat-session-service.js.map +1 -0
  16. package/dist/collection/services/file-attachment-manager.js +125 -0
  17. package/dist/collection/services/file-attachment-manager.js.map +1 -0
  18. package/dist/collection/utils/cookies.js +5 -12
  19. package/dist/collection/utils/cookies.js.map +1 -1
  20. package/dist/collection/utils/markdown.js +1 -1
  21. package/dist/collection/utils/markdown.js.map +1 -1
  22. package/dist/collection/utils/translations.js +99 -0
  23. package/dist/collection/utils/translations.js.map +1 -0
  24. package/dist/components/open-chat-studio-widget.js +1122 -302
  25. package/dist/components/open-chat-studio-widget.js.map +1 -1
  26. package/dist/esm/{index-DkJ7OJTS.js → index-BF7CYZiN.js} +4 -3
  27. package/dist/esm/index-BF7CYZiN.js.map +1 -0
  28. package/dist/esm/loader.js +3 -3
  29. package/dist/esm/open-chat-studio-widget.entry.js +1116 -301
  30. package/dist/esm/open-chat-studio-widget.entry.js.map +1 -1
  31. package/dist/esm/open-chat-studio-widget.js +3 -3
  32. package/dist/open-chat-studio-widget/open-chat-studio-widget.entry.esm.js.map +1 -1
  33. package/dist/open-chat-studio-widget/open-chat-studio-widget.esm.js +1 -1
  34. package/dist/open-chat-studio-widget/p-400b1f47.entry.js +4 -0
  35. package/dist/open-chat-studio-widget/p-400b1f47.entry.js.map +1 -0
  36. package/dist/open-chat-studio-widget/p-BF7CYZiN.js +3 -0
  37. package/dist/open-chat-studio-widget/p-BF7CYZiN.js.map +1 -0
  38. package/dist/types/components/ocs-chat/{heroicons.d.ts → icons.d.ts} +19 -0
  39. package/dist/types/components/ocs-chat/ocs-chat.d.ts +52 -36
  40. package/dist/types/components.d.ts +22 -8
  41. package/dist/types/services/chat-session-service.d.ts +78 -0
  42. package/dist/types/services/file-attachment-manager.d.ts +40 -0
  43. package/dist/types/utils/translations.d.ts +23 -0
  44. package/package.json +8 -3
  45. package/dist/cjs/index-AhSI5tER.js.map +0 -1
  46. package/dist/collection/components/ocs-chat/heroicons.js.map +0 -1
  47. package/dist/esm/index-DkJ7OJTS.js.map +0 -1
  48. package/dist/open-chat-studio-widget/p-DkJ7OJTS.js +0 -3
  49. package/dist/open-chat-studio-widget/p-DkJ7OJTS.js.map +0 -1
  50. package/dist/open-chat-studio-widget/p-bde68fbd.entry.js +0 -4
  51. package/dist/open-chat-studio-widget/p-bde68fbd.entry.js.map +0 -1
@@ -1,5 +1,17 @@
1
- import { h, r as registerInstance, H as Host, g as getElement } from './index-DkJ7OJTS.js';
2
-
1
+ import { h, r as registerInstance, E as Env, H as Host, g as getElement } from './index-BF7CYZiN.js';
2
+
3
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4
+ const OcsWidgetAvatar = () => {
5
+ return h("svg", { width: "24", height: "24", viewBox: "0 0 500 500", fill: "currentColor", xmlns: "http://www.w3.org/2000/svg" },
6
+ h("path", { d: "M80.1777 149.487C73.7354 160.531 68.6208 172.445 65.0576 185.012C43.6097 196.458 29.0128 219.057 29.0127 245.065C29.0127 270.995 43.5207 293.535 64.8613 305.014C68.3612 317.586 73.409 329.512 79.7881 340.575C34.4248 332.436 2.20245e-05 292.771 0 245.065C0.000198788 197.223 34.6221 157.469 80.1777 149.487ZM419.821 149.487C465.377 157.469 500 197.223 500 245.065C500 292.771 465.575 332.436 420.211 340.575C426.59 329.512 431.638 317.586 435.138 305.014C456.479 293.535 470.987 270.995 470.987 245.065C470.987 219.056 456.39 196.458 434.941 185.012C431.378 172.445 426.264 160.532 419.821 149.487ZM259.868 16.4473C304.099 16.4473 341.297 46.5498 352.097 87.3848C340.566 81.9422 328.254 77.8819 315.375 75.4209C303.51 57.3742 283.08 45.46 259.868 45.46H253.289C230.975 45.4601 211.232 56.4698 199.197 73.3535C186.6 74.535 174.442 77.2268 162.906 81.248C175.656 43.5694 211.305 16.4474 253.289 16.4473H259.868Z" }),
7
+ h("path", { d: "M286.185 72.6685C371.571 72.6686 440.789 141.888 440.789 227.274V263.458C440.789 348.844 371.57 418.064 286.185 418.064H213.815C128.43 418.064 59.2111 348.844 59.2109 263.458V227.274C59.211 141.888 128.43 72.6686 213.815 72.6685H286.185ZM213.815 105.263C142.963 105.263 85.5265 162.7 85.5264 233.552V256.579C85.5264 327.431 142.963 384.868 213.815 384.869H286.185C357.037 384.868 414.474 327.431 414.474 256.579V233.552C414.473 162.7 357.037 105.263 286.185 105.263H213.815Z" }),
8
+ h("rect", { x: "289.475", y: "184.808", width: "61.9019", height: "115.73", rx: "30.951" }),
9
+ h("rect", { x: "161.184", y: "184.808", width: "61.9019", height: "115.73", rx: "30.951" }),
10
+ h("path", { d: "M325.658 483.553V414.58V401.316H148.027L325.658 483.553Z" }));
11
+ };
12
+ /**
13
+ * Heroicon: x-mark
14
+ */
3
15
  const XMarkIcon = () => {
4
16
  return h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
5
17
  h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M6 18 18 6M6 6l12 12" }));
@@ -13,22 +25,37 @@ const GripDotsVerticalIcon = () => {
13
25
  h("circle", { cx: "16", cy: "12", r: "1.5" }),
14
26
  h("circle", { cx: "16", cy: "18", r: "1.5" })));
15
27
  };
28
+ /**
29
+ * Heroicon: plus-circle
30
+ */
16
31
  const PlusWithCircleIcon = () => {
17
32
  return (h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
18
33
  h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M12 9v6m3-3H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" })));
19
34
  };
35
+ /**
36
+ * Heroicon: arrows-pointing-out
37
+ */
20
38
  const ArrowsPointingOutIcon = () => {
21
39
  return (h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
22
40
  h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" })));
23
41
  };
42
+ /**
43
+ * Heroicon: arrows-pointing-in
44
+ */
24
45
  const ArrowsPointingInIcon = () => {
25
46
  return (h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
26
47
  h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M9 9V4.5M9 9H4.5M9 9 3.75 3.75M15 9h4.5M15 9V4.5M15 9l5.25-5.25M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 15h4.5M15 15v4.5m0-4.5 5.25 5.25" })));
27
48
  };
49
+ /**
50
+ * Heroicon: paper-clip
51
+ */
28
52
  const PaperClipIcon = () => {
29
53
  return (h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
30
54
  h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "m18.375 12.739-7.693 7.693a4.5 4.5 0 0 1-6.364-6.364l10.94-10.94A3 3 0 1 1 19.5 7.372L8.552 18.32m.009-.01-.01.01m5.699-9.941-7.81 7.81a1.5 1.5 0 0 0 2.112 2.13" })));
31
55
  };
56
+ /**
57
+ * Heroicon: document-check
58
+ */
32
59
  const CheckDocumentIcon = () => {
33
60
  return (h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
34
61
  h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M10.125 2.25h-4.5c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125v-9M10.125 2.25h.375a9 9 0 0 1 9 9v.375M10.125 2.25A3.375 3.375 0 0 1 13.5 5.625v1.5c0 .621.504 1.125 1.125 1.125h1.5a3.375 3.375 0 0 1 3.375 3.375M9 15l2.25 2.25L15 12" })));
@@ -4299,7 +4326,7 @@ function renderMarkdownSync(content) {
4299
4326
  'href', 'target', 'rel', 'class', 'src', 'alt', 'title',
4300
4327
  'width', 'height', 'align', 'colspan', 'rowspan'
4301
4328
  ],
4302
- ALLOWED_URI_REGEXP: /^(?:(?:https?):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,
4329
+ ALLOWED_URI_REGEXP: /^(?:(?:https?):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i,
4303
4330
  ADD_ATTR: ['target'],
4304
4331
  FORBID_TAGS: ['script', 'style', 'form', 'input', 'button'],
4305
4332
  FORBID_ATTR: ['onclick', 'onload', 'onerror', 'onmouseover'],
@@ -4312,6 +4339,414 @@ function renderMarkdownSync(content) {
4312
4339
  }
4313
4340
  }
4314
4341
 
4342
+ /**
4343
+ * Convert a CSS percentage (60%) or pixel (10px) value to pixels.
4344
+ * @param value The CSS string value
4345
+ * @param maxValue The max value to use when converting from a percentage
4346
+ * @param defaultValue The default value if the CSS value is neither a percentage nor a pixel value.
4347
+ */
4348
+ const varToPixels = (value, maxValue, defaultValue) => {
4349
+ value = value.trim();
4350
+ if (value.includes("%")) {
4351
+ const percent = percentToFloat(value);
4352
+ if (!isNaN(percent)) {
4353
+ return maxValue * percent;
4354
+ }
4355
+ }
4356
+ else if (value.includes("px")) {
4357
+ const pixels = parseFloat(value);
4358
+ if (!isNaN(pixels)) {
4359
+ return pixels;
4360
+ }
4361
+ }
4362
+ return defaultValue;
4363
+ };
4364
+ const percentToFloat = (percentageString) => {
4365
+ const numericValue = parseFloat(percentageString);
4366
+ if (isNaN(numericValue)) {
4367
+ return NaN;
4368
+ }
4369
+ return numericValue / 100;
4370
+ };
4371
+
4372
+ var ar = {
4373
+ "launcher.open": "فتح المحادثة",
4374
+ "window.close": "إغلاق",
4375
+ "window.newChat": "بدء محادثة جديدة",
4376
+ "window.fullscreen": "دخول وضع ملء الشاشة",
4377
+ "window.exitFullscreen": "الخروج من وضع ملء الشاشة",
4378
+ "attach.add": "إرفاق ملفات",
4379
+ "attach.remove": "إزالة الملف",
4380
+ "attach.success": "تم إرفاق الملف",
4381
+ "status.starting": "جارٍ بدء المحادثة...",
4382
+ "status.typing": "جارٍ تحضير الرد",
4383
+ "status.uploading": "جارٍ التحميل",
4384
+ "modal.newChatTitle": "بدء محادثة جديدة",
4385
+ "modal.newChatBody": "بدء محادثة جديدة سيؤدي إلى مسح المحادثة الحالية. هل ترغب بالمتابعة؟",
4386
+ "modal.cancel": "إلغاء",
4387
+ "modal.confirm": "تأكيد",
4388
+ "composer.placeholder": "اكتب رسالة...",
4389
+ "composer.send": "إرسال الرسالة",
4390
+ "error.fileTooLarge": "الملف كبير جدًا",
4391
+ "error.totalTooLarge": "إجمالي حجم الملفات كبير جدًا",
4392
+ "error.unsupportedType": "نوع الملف غير مدعوم",
4393
+ "error.connection": "خطأ في الاتصال. يرجى المحاولة مرة أخرى.",
4394
+ "error.sessionExpired": "انتهت صلاحية الجلسة. يرجى بدء محادثة جديدة.",
4395
+ "branding.poweredBy": "مدعوم من",
4396
+ "branding.buttonText": "",
4397
+ "branding.headerText": "",
4398
+ "content.welcomeMessages": [
4399
+ ],
4400
+ "content.starterQuestions": [
4401
+ ]
4402
+ };
4403
+
4404
+ var en = {
4405
+ "launcher.open": "Open chat",
4406
+ "window.close": "Close",
4407
+ "window.newChat": "Start new chat",
4408
+ "window.fullscreen": "Enter fullscreen",
4409
+ "window.exitFullscreen": "Exit fullscreen",
4410
+ "attach.add": "Attach files",
4411
+ "attach.remove": "Remove file",
4412
+ "attach.success": "File attached",
4413
+ "status.starting": "Starting chat...",
4414
+ "status.typing": "Preparing response",
4415
+ "status.uploading": "Uploading",
4416
+ "modal.newChatTitle": "Start New Chat",
4417
+ "modal.newChatBody": "Starting a new chat will clear your current conversation. Continue?",
4418
+ "modal.cancel": "Cancel",
4419
+ "modal.confirm": "Confirm",
4420
+ "composer.placeholder": "Type a message...",
4421
+ "composer.send": "Send message",
4422
+ "error.fileTooLarge": "File too large",
4423
+ "error.totalTooLarge": "Total file size too large",
4424
+ "error.unsupportedType": "Unsupported file type",
4425
+ "error.connection": "Connection error. Please try again.",
4426
+ "error.sessionExpired": "Session expired. Please start a new chat.",
4427
+ "branding.poweredBy": "Powered by",
4428
+ "branding.buttonText": "",
4429
+ "branding.headerText": "",
4430
+ "content.welcomeMessages": [
4431
+ ],
4432
+ "content.starterQuestions": [
4433
+ ]
4434
+ };
4435
+
4436
+ var es = {
4437
+ "launcher.open": "Abrir chat",
4438
+ "window.close": "Cerrar",
4439
+ "window.newChat": "Iniciar nuevo chat",
4440
+ "window.fullscreen": "Pantalla completa",
4441
+ "window.exitFullscreen": "Salir de pantalla completa",
4442
+ "attach.add": "Adjuntar archivos",
4443
+ "attach.remove": "Eliminar archivo",
4444
+ "attach.success": "Archivo adjunto",
4445
+ "status.starting": "Iniciando chat...",
4446
+ "status.typing": "Preparando respuesta",
4447
+ "status.uploading": "Subiendo",
4448
+ "modal.newChatTitle": "Iniciar Nuevo Chat",
4449
+ "modal.newChatBody": "Iniciar un nuevo chat borrará tu conversación actual. ¿Continuar?",
4450
+ "modal.cancel": "Cancelar",
4451
+ "modal.confirm": "Confirmar",
4452
+ "composer.placeholder": "Escribe un mensaje...",
4453
+ "composer.send": "Enviar mensaje",
4454
+ "error.fileTooLarge": "Archivo demasiado grande",
4455
+ "error.totalTooLarge": "Tamaño total de archivos demasiado grande",
4456
+ "error.unsupportedType": "Tipo de archivo no soportado",
4457
+ "error.connection": "Error de conexión. Por favor, inténtalo de nuevo.",
4458
+ "error.sessionExpired": "Sesión expirada. Por favor, inicia un nuevo chat.",
4459
+ "branding.poweredBy": "Desarrollado por",
4460
+ "branding.buttonText": "",
4461
+ "branding.headerText": "",
4462
+ "content.welcomeMessages": [
4463
+ ],
4464
+ "content.starterQuestions": [
4465
+ ]
4466
+ };
4467
+
4468
+ var fr = {
4469
+ "launcher.open": "Ouvrir le chat",
4470
+ "window.close": "Fermer",
4471
+ "window.newChat": "Nouveau chat",
4472
+ "window.fullscreen": "Plein écran",
4473
+ "window.exitFullscreen": "Quitter le plein écran",
4474
+ "attach.add": "Joindre des fichiers",
4475
+ "attach.remove": "Supprimer le fichier",
4476
+ "attach.success": "Fichier joint",
4477
+ "status.starting": "Démarrage du chat...",
4478
+ "status.typing": "Préparation de la réponse",
4479
+ "status.uploading": "Téléversement",
4480
+ "modal.newChatTitle": "Nouveau Chat",
4481
+ "modal.newChatBody": "Démarrer un nouveau chat effacera votre conversation actuelle. Continuer?",
4482
+ "modal.cancel": "Annuler",
4483
+ "modal.confirm": "Confirmer",
4484
+ "composer.placeholder": "Tapez un message...",
4485
+ "composer.send": "Envoyer le message",
4486
+ "error.fileTooLarge": "Fichier trop volumineux",
4487
+ "error.totalTooLarge": "Taille totale des fichiers trop importante",
4488
+ "error.unsupportedType": "Type de fichier non pris en charge",
4489
+ "error.connection": "Erreur de connexion. Veuillez réessayer.",
4490
+ "error.sessionExpired": "Session expirée. Veuillez démarrer un nouveau chat.",
4491
+ "branding.poweredBy": "Propulsé par",
4492
+ "branding.buttonText": "",
4493
+ "branding.headerText": "",
4494
+ "content.welcomeMessages": [
4495
+ ],
4496
+ "content.starterQuestions": [
4497
+ ]
4498
+ };
4499
+
4500
+ var hi = {
4501
+ "launcher.open": "चैट खोलें",
4502
+ "window.close": "बंद करें",
4503
+ "window.newChat": "नई चैट शुरू करें",
4504
+ "window.fullscreen": "पूर्ण स्क्रीन पर जाएं",
4505
+ "window.exitFullscreen": "पूर्ण स्क्रीन से बाहर आएं",
4506
+ "attach.add": "फ़ाइलें संलग्न करें",
4507
+ "attach.remove": "फ़ाइल हटाएँ",
4508
+ "attach.success": "फ़ाइल संलग्न की गई",
4509
+ "status.starting": "चैट शुरू हो रही है...",
4510
+ "status.typing": "जवाब तैयार किया जा रहा है",
4511
+ "status.uploading": "अपलोड हो रहा है",
4512
+ "modal.newChatTitle": "नई चैट शुरू करें",
4513
+ "modal.newChatBody": "नई चैट शुरू करने से आपकी मौजूदा बातचीत हट जाएगी। क्या आप जारी रखना चाहते हैं?",
4514
+ "modal.cancel": "रद्द करें",
4515
+ "modal.confirm": "पुष्टि करें",
4516
+ "composer.placeholder": "संदेश लिखें...",
4517
+ "composer.send": "संदेश भेजें",
4518
+ "error.fileTooLarge": "फ़ाइल बहुत बड़ी है",
4519
+ "error.totalTooLarge": "कुल फ़ाइल आकार बहुत बड़ा है",
4520
+ "error.unsupportedType": "फ़ाइल प्रकार समर्थित नहीं है",
4521
+ "error.connection": "कनेक्शन त्रुटि। कृपया पुनः प्रयास करें।",
4522
+ "error.sessionExpired": "सत्र समाप्त हो गया है। कृपया नई चैट शुरू करें।",
4523
+ "branding.poweredBy": "द्वारा संचालित",
4524
+ "branding.buttonText": "",
4525
+ "branding.headerText": "",
4526
+ "content.welcomeMessages": [
4527
+ ],
4528
+ "content.starterQuestions": [
4529
+ ]
4530
+ };
4531
+
4532
+ var it = {
4533
+ "launcher.open": "Apri chat",
4534
+ "window.close": "Chiudi",
4535
+ "window.newChat": "Avvia nuova chat",
4536
+ "window.fullscreen": "Schermo intero",
4537
+ "window.exitFullscreen": "Esci da schermo intero",
4538
+ "attach.add": "Allega file",
4539
+ "attach.remove": "Rimuovi file",
4540
+ "attach.success": "File allegato",
4541
+ "status.starting": "Avvio della chat...",
4542
+ "status.typing": "Preparazione della risposta",
4543
+ "status.uploading": "Caricamento",
4544
+ "modal.newChatTitle": "Avvia nuova chat",
4545
+ "modal.newChatBody": "Avviare una nuova chat cancellerà la conversazione attuale. Continuare?",
4546
+ "modal.cancel": "Annulla",
4547
+ "modal.confirm": "Conferma",
4548
+ "composer.placeholder": "Scrivi un messaggio...",
4549
+ "composer.send": "Invia messaggio",
4550
+ "error.fileTooLarge": "File troppo grande",
4551
+ "error.totalTooLarge": "Dimensione totale del file troppo grande",
4552
+ "error.unsupportedType": "Tipo di file non supportato",
4553
+ "error.connection": "Errore di connessione. Riprova.",
4554
+ "error.sessionExpired": "Sessione scaduta. Avvia una nuova chat.",
4555
+ "branding.poweredBy": "Offerto da",
4556
+ "branding.buttonText": "",
4557
+ "branding.headerText": "",
4558
+ "content.welcomeMessages": [
4559
+ ],
4560
+ "content.starterQuestions": [
4561
+ ]
4562
+ };
4563
+
4564
+ var pt = {
4565
+ "launcher.open": "Abrir chat",
4566
+ "window.close": "Fechar",
4567
+ "window.newChat": "Iniciar novo chat",
4568
+ "window.fullscreen": "Entrar em tela cheia",
4569
+ "window.exitFullscreen": "Sair da tela cheia",
4570
+ "attach.add": "Anexar arquivos",
4571
+ "attach.remove": "Remover arquivo",
4572
+ "attach.success": "Arquivo anexado",
4573
+ "status.starting": "Iniciando chat...",
4574
+ "status.typing": "Preparando resposta",
4575
+ "status.uploading": "Carregando",
4576
+ "modal.newChatTitle": "Iniciar novo chat",
4577
+ "modal.newChatBody": "Iniciar um novo chat apagará sua conversa atual. Deseja continuar?",
4578
+ "modal.cancel": "Cancelar",
4579
+ "modal.confirm": "Confirmar",
4580
+ "composer.placeholder": "Digite uma mensagem...",
4581
+ "composer.send": "Enviar mensagem",
4582
+ "error.fileTooLarge": "Arquivo muito grande",
4583
+ "error.totalTooLarge": "Tamanho total do arquivo muito grande",
4584
+ "error.unsupportedType": "Tipo de arquivo não suportado",
4585
+ "error.connection": "Erro de conexão. Por favor, tente novamente.",
4586
+ "error.sessionExpired": "Sessão expirada. Por favor, inicie um novo chat.",
4587
+ "branding.poweredBy": "Desenvolvido por",
4588
+ "branding.buttonText": "",
4589
+ "branding.headerText": "",
4590
+ "content.welcomeMessages": [
4591
+ ],
4592
+ "content.starterQuestions": [
4593
+ ]
4594
+ };
4595
+
4596
+ var sw = {
4597
+ "launcher.open": "Fungua gumzo",
4598
+ "window.close": "Funga",
4599
+ "window.newChat": "Anza gumzo jipya",
4600
+ "window.fullscreen": "Ingiza skrini nzima",
4601
+ "window.exitFullscreen": "Toka kwenye skrini nzima",
4602
+ "attach.add": "Ambatanisha faili",
4603
+ "attach.remove": "Ondoa faili",
4604
+ "attach.success": "Faili limeambatanishwa",
4605
+ "status.starting": "Inaanzisha gumzo...",
4606
+ "status.typing": "Inatayarisha jibu",
4607
+ "status.uploading": "Inapakia",
4608
+ "modal.newChatTitle": "Anza gumzo jipya",
4609
+ "modal.newChatBody": "Kuanza gumzo jipya kutafuta gumzo lako la sasa. Je, ungependa kuendelea?",
4610
+ "modal.cancel": "Ghairi",
4611
+ "modal.confirm": "Thibitisha",
4612
+ "composer.placeholder": "Andika ujumbe...",
4613
+ "composer.send": "Tuma ujumbe",
4614
+ "error.fileTooLarge": "Faili ni kubwa sana",
4615
+ "error.totalTooLarge": "Jumla ya ukubwa wa faili ni kubwa sana",
4616
+ "error.unsupportedType": "Aina ya faili haitumiki",
4617
+ "error.connection": "Hitilafu ya muunganisho. Tafadhali jaribu tena.",
4618
+ "error.sessionExpired": "Kipindi kimeisha muda wake. Tafadhali anza gumzo jipya.",
4619
+ "branding.poweredBy": "Inaendeshwa na",
4620
+ "branding.buttonText": "",
4621
+ "branding.headerText": "",
4622
+ "content.welcomeMessages": [
4623
+ ],
4624
+ "content.starterQuestions": [
4625
+ ]
4626
+ };
4627
+
4628
+ var uk = {
4629
+ "launcher.open": "Відкрити чат",
4630
+ "window.close": "Закрити",
4631
+ "window.newChat": "Почати новий чат",
4632
+ "window.fullscreen": "На весь екран",
4633
+ "window.exitFullscreen": "Вийти з повного екрану",
4634
+ "attach.add": "Прикріпити файли",
4635
+ "attach.remove": "Видалити файл",
4636
+ "attach.success": "Файл прикріплено",
4637
+ "status.starting": "Запуск чату...",
4638
+ "status.typing": "Готується відповідь",
4639
+ "status.uploading": "Завантаження",
4640
+ "modal.newChatTitle": "Почати новий чат",
4641
+ "modal.newChatBody": "Початок нового чату видалить вашу поточну розмову. Продовжити?",
4642
+ "modal.cancel": "Скасувати",
4643
+ "modal.confirm": "Підтвердити",
4644
+ "composer.placeholder": "Введіть повідомлення...",
4645
+ "composer.send": "Надіслати повідомлення",
4646
+ "error.fileTooLarge": "Файл занадто великий",
4647
+ "error.totalTooLarge": "Загальний розмір файлів занадто великий",
4648
+ "error.unsupportedType": "Непідтримуваний тип файлу",
4649
+ "error.connection": "Помилка з'єднання. Будь ласка, спробуйте ще раз.",
4650
+ "error.sessionExpired": "Сесія завершилася. Будь ласка, почніть новий чат.",
4651
+ "branding.poweredBy": "Працює на",
4652
+ "branding.buttonText": "",
4653
+ "branding.headerText": "",
4654
+ "content.welcomeMessages": [
4655
+ ],
4656
+ "content.starterQuestions": [
4657
+ ]
4658
+ };
4659
+
4660
+ /**
4661
+ * Translation utilities for the chat widget
4662
+ */
4663
+ // Default (English) translations
4664
+ const defaultTranslations = en;
4665
+ // Available translations map
4666
+ const translationFiles = {
4667
+ ar: ar,
4668
+ en: en,
4669
+ es: es,
4670
+ fr: fr,
4671
+ hi: hi,
4672
+ it: it,
4673
+ pt: pt,
4674
+ sw: sw,
4675
+ uk: uk,
4676
+ };
4677
+ function getBrowserLanguage() {
4678
+ if (typeof navigator !== 'undefined') {
4679
+ const lang = navigator.language || navigator.userLanguage;
4680
+ if (lang) {
4681
+ return lang.split('-')[0].toLowerCase();
4682
+ }
4683
+ }
4684
+ return 'en';
4685
+ }
4686
+ function resolveLanguage(langProp) {
4687
+ if (langProp) {
4688
+ return langProp.toLowerCase();
4689
+ }
4690
+ return getBrowserLanguage();
4691
+ }
4692
+ async function loadTranslations(language) {
4693
+ return translationFiles[language] || defaultTranslations;
4694
+ }
4695
+ /**
4696
+ * Overrides matching keys
4697
+ */
4698
+ function mergeTranslations(baseTranslations, customTranslations) {
4699
+ return Object.assign(Object.assign({}, baseTranslations), customTranslations);
4700
+ }
4701
+ class TranslationManager {
4702
+ constructor(language, customTranslations) {
4703
+ this.translations = defaultTranslations;
4704
+ this.language = 'en';
4705
+ this.language = resolveLanguage(language);
4706
+ this.loadTranslations(customTranslations);
4707
+ }
4708
+ async loadTranslations(customTranslations) {
4709
+ let baseTranslations;
4710
+ try {
4711
+ baseTranslations = await loadTranslations(this.language);
4712
+ }
4713
+ catch (error) {
4714
+ console.error('Failed to load translations:', error);
4715
+ baseTranslations = defaultTranslations;
4716
+ }
4717
+ this.translations = customTranslations
4718
+ ? mergeTranslations(baseTranslations, customTranslations)
4719
+ : baseTranslations;
4720
+ }
4721
+ get(key, override) {
4722
+ var _a;
4723
+ if (override !== undefined && override !== null) {
4724
+ return override;
4725
+ }
4726
+ const value = (_a = this.translations[key]) !== null && _a !== void 0 ? _a : defaultTranslations[key];
4727
+ if (Array.isArray(value)) {
4728
+ return value.length > 0 ? value[0] : undefined;
4729
+ }
4730
+ return value !== null && value !== void 0 ? value : undefined;
4731
+ }
4732
+ getAll() {
4733
+ return this.translations;
4734
+ }
4735
+ getArray(key) {
4736
+ const value = this.translations[key] || defaultTranslations[key];
4737
+ if (Array.isArray(value)) {
4738
+ return value;
4739
+ }
4740
+ if (typeof value === 'string') {
4741
+ return [value];
4742
+ }
4743
+ return [];
4744
+ }
4745
+ getLanguage() {
4746
+ return this.language;
4747
+ }
4748
+ }
4749
+
4315
4750
  /*! js-cookie v3.0.5 | MIT */
4316
4751
  /* eslint-disable no-var */
4317
4752
  function assign (target) {
@@ -4454,70 +4889,298 @@ function getCSRFToken(apiBaseUrl) {
4454
4889
  return api.get('csrftoken');
4455
4890
  }
4456
4891
  function currentDomainMatchesApiBaseUrl(apiBaseUrl) {
4457
- const currentDomain = window.location.hostname;
4458
- const apiDomain = getDomainFromUrl(apiBaseUrl);
4459
- if (!apiDomain) {
4892
+ let apiBase;
4893
+ try {
4894
+ apiBase = new URL(apiBaseUrl);
4895
+ }
4896
+ catch (_a) {
4460
4897
  return false;
4461
4898
  }
4462
- return currentDomain === apiDomain;
4899
+ return window.location.origin === apiBase.origin;
4463
4900
  }
4464
- function getDomainFromUrl(url) {
4465
- try {
4466
- const urlObj = new URL(url);
4467
- return urlObj.hostname;
4901
+
4902
+ class ChatSessionService {
4903
+ constructor(options) {
4904
+ var _a, _b, _c, _d;
4905
+ this.apiBaseUrl = options.apiBaseUrl;
4906
+ this.embedKey = options.embedKey;
4907
+ this.widgetVersion = options.widgetVersion;
4908
+ this.csrfTokenProvider = (_a = options.csrfTokenProvider) !== null && _a !== void 0 ? _a : getCSRFToken;
4909
+ this.taskPollingIntervalMs = (_b = options.taskPollingIntervalMs) !== null && _b !== void 0 ? _b : 1000;
4910
+ this.taskPollingMaxAttempts = (_c = options.taskPollingMaxAttempts) !== null && _c !== void 0 ? _c : 120;
4911
+ this.messagePollingIntervalMs = (_d = options.messagePollingIntervalMs) !== null && _d !== void 0 ? _d : 30000;
4912
+ }
4913
+ async startSession(requestBody) {
4914
+ const response = await fetch(`${this.apiBaseUrl}/api/chat/start/`, {
4915
+ method: 'POST',
4916
+ headers: this.getJsonHeaders(),
4917
+ body: JSON.stringify(requestBody),
4918
+ });
4919
+ if (!response.ok) {
4920
+ throw new Error(`Failed to start session: ${response.statusText}`);
4921
+ }
4922
+ return response.json();
4468
4923
  }
4469
- catch (error) {
4470
- return null;
4924
+ async sendMessage(sessionId, payload) {
4925
+ const response = await fetch(`${this.apiBaseUrl}/api/chat/${sessionId}/message/`, {
4926
+ method: 'POST',
4927
+ headers: this.getJsonHeaders(),
4928
+ body: JSON.stringify(payload),
4929
+ });
4930
+ if (!response.ok) {
4931
+ throw new Error(`Failed to send message: ${response.statusText}`);
4932
+ }
4933
+ return response.json();
4934
+ }
4935
+ async pollTaskOnce(sessionId, taskId) {
4936
+ const response = await fetch(`${this.apiBaseUrl}/api/chat/${sessionId}/${taskId}/poll/`);
4937
+ if (!response.ok) {
4938
+ throw new Error(`Failed to poll task: ${response.statusText}`);
4939
+ }
4940
+ return response.json();
4941
+ }
4942
+ pollTask(sessionId, taskId, callbacks) {
4943
+ let attempts = 0;
4944
+ let cancelled = false;
4945
+ let timeoutId;
4946
+ const scheduleNextPoll = () => {
4947
+ timeoutId = setTimeout(() => {
4948
+ void poll();
4949
+ }, this.taskPollingIntervalMs);
4950
+ };
4951
+ const poll = async () => {
4952
+ if (cancelled) {
4953
+ return;
4954
+ }
4955
+ try {
4956
+ const data = await this.pollTaskOnce(sessionId, taskId);
4957
+ if (data.error) {
4958
+ throw new Error(data.error);
4959
+ }
4960
+ if (data.status === 'complete' && data.message) {
4961
+ callbacks.onMessage(data.message);
4962
+ return;
4963
+ }
4964
+ attempts += 1;
4965
+ if (attempts >= this.taskPollingMaxAttempts) {
4966
+ if (callbacks.onTimeout) {
4967
+ callbacks.onTimeout();
4968
+ }
4969
+ return;
4970
+ }
4971
+ scheduleNextPoll();
4972
+ }
4973
+ catch (error) {
4974
+ if (callbacks.onError) {
4975
+ callbacks.onError(error instanceof Error ? error : new Error('Failed to get response'));
4976
+ }
4977
+ }
4978
+ };
4979
+ void poll();
4980
+ return {
4981
+ cancel: () => {
4982
+ cancelled = true;
4983
+ if (timeoutId) {
4984
+ clearTimeout(timeoutId);
4985
+ }
4986
+ },
4987
+ };
4988
+ }
4989
+ async fetchMessages(sessionId, since) {
4990
+ const url = new URL(`${this.apiBaseUrl}/api/chat/${sessionId}/poll/`);
4991
+ if (since) {
4992
+ url.searchParams.set('since', since);
4993
+ }
4994
+ const response = await fetch(url.toString());
4995
+ if (!response.ok) {
4996
+ throw new Error(`Failed to poll messages: ${response.statusText}`);
4997
+ }
4998
+ return response.json();
4999
+ }
5000
+ startMessagePolling(sessionId, callbacks) {
5001
+ const poll = async () => {
5002
+ try {
5003
+ const since = callbacks.getSince();
5004
+ const data = await this.fetchMessages(sessionId, since);
5005
+ if (data.messages.length > 0) {
5006
+ callbacks.onMessages(data.messages);
5007
+ }
5008
+ }
5009
+ catch (error) {
5010
+ if (callbacks.onError) {
5011
+ callbacks.onError(error instanceof Error ? error : new Error('Failed to poll messages'));
5012
+ }
5013
+ }
5014
+ };
5015
+ // perform an initial poll immediately
5016
+ void poll();
5017
+ this.messagePollingTimer = setInterval(() => {
5018
+ void poll();
5019
+ }, this.messagePollingIntervalMs);
5020
+ return {
5021
+ stop: () => this.stopMessagePolling(),
5022
+ };
5023
+ }
5024
+ stopMessagePolling() {
5025
+ if (this.messagePollingTimer) {
5026
+ clearInterval(this.messagePollingTimer);
5027
+ this.messagePollingTimer = undefined;
5028
+ }
5029
+ }
5030
+ getJsonHeaders() {
5031
+ const headers = {
5032
+ 'Content-Type': 'application/json',
5033
+ 'x-ocs-widget-version': this.widgetVersion,
5034
+ };
5035
+ const csrfToken = this.csrfTokenProvider(this.apiBaseUrl);
5036
+ if (csrfToken) {
5037
+ headers['X-CSRFToken'] = csrfToken;
5038
+ }
5039
+ if (this.embedKey) {
5040
+ headers['X-Embed-Key'] = this.embedKey;
5041
+ }
5042
+ return headers;
4471
5043
  }
4472
5044
  }
4473
5045
 
4474
- /**
4475
- * Convert a CSS percentage (60%) or pixel (10px) value to pixels.
4476
- * @param value The CSS string value
4477
- * @param maxValue The max value to use when converting from a percentage
4478
- * @param defaultValue The default value if the CSS value is neither a percentage nor a pixel value.
4479
- */
4480
- const varToPixels = (value, maxValue, defaultValue) => {
4481
- value = value.trim();
4482
- if (value.includes("%")) {
4483
- const percent = percentToFloat(value);
4484
- if (!isNaN(percent)) {
4485
- return maxValue * percent;
5046
+ class FileAttachmentManager {
5047
+ constructor(config) {
5048
+ this.supportedExtensions = config.supportedExtensions;
5049
+ this.maxFileSizeMb = config.maxFileSizeMb;
5050
+ this.maxTotalSizeMb = config.maxTotalSizeMb;
5051
+ }
5052
+ addFiles(existingFiles, files) {
5053
+ const newSelected = [];
5054
+ const fileArray = Array.from(files instanceof FileList ? Array.from(files) : files);
5055
+ let totalSize = existingFiles.reduce((sum, f) => sum + f.file.size, 0);
5056
+ for (const file of fileArray) {
5057
+ const extension = this.getFileExtension(file.name);
5058
+ if (!this.supportedExtensions.includes(extension)) {
5059
+ newSelected.push({ file, error: `File type ${extension} not supported` });
5060
+ continue;
5061
+ }
5062
+ const fileSizeMb = this.bytesToMb(file.size);
5063
+ if (fileSizeMb > this.maxFileSizeMb) {
5064
+ newSelected.push({ file, error: `File exceeds ${this.maxFileSizeMb}MB limit` });
5065
+ continue;
5066
+ }
5067
+ totalSize += file.size;
5068
+ const totalSizeMb = this.bytesToMb(totalSize);
5069
+ if (totalSizeMb > this.maxTotalSizeMb) {
5070
+ newSelected.push({ file, error: `Total size exceeds ${this.maxTotalSizeMb}MB limit` });
5071
+ continue;
5072
+ }
5073
+ newSelected.push({ file });
4486
5074
  }
5075
+ return [...existingFiles, ...newSelected];
4487
5076
  }
4488
- else if (value.includes("px")) {
4489
- const pixels = parseFloat(value);
4490
- if (!isNaN(pixels)) {
4491
- return pixels;
5077
+ removeFile(existingFiles, index) {
5078
+ return existingFiles.filter((_, i) => i !== index);
5079
+ }
5080
+ markPendingFilesWithError(existingFiles, errorMessage) {
5081
+ return existingFiles.map(file => {
5082
+ if (!file.error && !file.uploaded) {
5083
+ return Object.assign(Object.assign({}, file), { error: errorMessage });
5084
+ }
5085
+ return file;
5086
+ });
5087
+ }
5088
+ async uploadPendingFiles(existingFiles, context) {
5089
+ if (existingFiles.length === 0) {
5090
+ return { selectedFiles: existingFiles, uploadedIds: [] };
5091
+ }
5092
+ const uploadCandidates = existingFiles.filter(file => !file.error && !file.uploaded);
5093
+ const uploadedIds = existingFiles
5094
+ .filter(file => file.uploaded)
5095
+ .map(file => file.uploaded.id);
5096
+ if (uploadCandidates.length === 0) {
5097
+ return { selectedFiles: existingFiles, uploadedIds };
5098
+ }
5099
+ const formData = new FormData();
5100
+ for (const file of uploadCandidates) {
5101
+ formData.append('files', file.file);
5102
+ }
5103
+ formData.append('participant_remote_id', context.participantId);
5104
+ if (context.participantName) {
5105
+ formData.append('participant_name', context.participantName);
5106
+ }
5107
+ try {
5108
+ const response = await fetch(`${context.apiBaseUrl}/api/chat/${context.sessionId}/upload/`, {
5109
+ method: 'POST',
5110
+ body: formData,
5111
+ });
5112
+ if (!response.ok) {
5113
+ const errorData = await this.safeJson(response);
5114
+ const errorMessage = (errorData && typeof errorData === 'object' && 'error' in errorData && errorData.error) ||
5115
+ 'Failed to upload files';
5116
+ return {
5117
+ selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),
5118
+ uploadedIds,
5119
+ errorMessage,
5120
+ };
5121
+ }
5122
+ const data = await this.safeJson(response);
5123
+ if (!data || typeof data !== 'object' || !Array.isArray(data.files)) {
5124
+ const errorMessage = 'Unexpected upload response shape';
5125
+ return {
5126
+ selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),
5127
+ uploadedIds,
5128
+ errorMessage,
5129
+ };
5130
+ }
5131
+ const uploadedFiles = data.files;
5132
+ let index = 0;
5133
+ const updatedSelected = existingFiles.map(file => {
5134
+ if (!file.error && !file.uploaded) {
5135
+ const uploaded = uploadedFiles[index];
5136
+ index += 1;
5137
+ return Object.assign(Object.assign({}, file), { uploaded });
5138
+ }
5139
+ return file;
5140
+ });
5141
+ uploadedIds.push(...uploadedFiles.map(file => file.id));
5142
+ return { selectedFiles: updatedSelected, uploadedIds };
5143
+ }
5144
+ catch (error) {
5145
+ const errorMessage = error instanceof Error ? error.message : 'Failed to upload files';
5146
+ return {
5147
+ selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),
5148
+ uploadedIds,
5149
+ errorMessage,
5150
+ };
4492
5151
  }
4493
5152
  }
4494
- return defaultValue;
4495
- };
4496
- const percentToFloat = (percentageString) => {
4497
- const numericValue = parseFloat(percentageString);
4498
- if (isNaN(numericValue)) {
4499
- return NaN;
5153
+ bytesToMb(bytes) {
5154
+ return bytes / (1024 * 1024);
4500
5155
  }
4501
- return numericValue / 100;
4502
- };
5156
+ getFileExtension(filename) {
5157
+ const parts = filename.split('.');
5158
+ const ext = parts.pop();
5159
+ return ext ? `.${ext.toLowerCase()}` : '';
5160
+ }
5161
+ async safeJson(response) {
5162
+ try {
5163
+ return await response.json();
5164
+ }
5165
+ catch (_a) {
5166
+ return undefined;
5167
+ }
5168
+ }
5169
+ }
4503
5170
 
4504
- const ocsChatCss = "*, ::before, ::after {\n --tw-border-spacing-x: 0;\n --tw-border-spacing-y: 0;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-pan-x: ;\n --tw-pan-y: ;\n --tw-pinch-zoom: ;\n --tw-scroll-snap-strictness: proximity;\n --tw-gradient-from-position: ;\n --tw-gradient-via-position: ;\n --tw-gradient-to-position: ;\n --tw-ordinal: ;\n --tw-slashed-zero: ;\n --tw-numeric-figure: ;\n --tw-numeric-spacing: ;\n --tw-numeric-fraction: ;\n --tw-ring-inset: ;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-color: rgb(59 130 246 / 0.5);\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n --tw-blur: ;\n --tw-brightness: ;\n --tw-contrast: ;\n --tw-grayscale: ;\n --tw-hue-rotate: ;\n --tw-invert: ;\n --tw-saturate: ;\n --tw-sepia: ;\n --tw-drop-shadow: ;\n --tw-backdrop-blur: ;\n --tw-backdrop-brightness: ;\n --tw-backdrop-contrast: ;\n --tw-backdrop-grayscale: ;\n --tw-backdrop-hue-rotate: ;\n --tw-backdrop-invert: ;\n --tw-backdrop-opacity: ;\n --tw-backdrop-saturate: ;\n --tw-backdrop-sepia: ;\n --tw-contain-size: ;\n --tw-contain-layout: ;\n --tw-contain-paint: ;\n --tw-contain-style: ;\n}\n\n::backdrop {\n --tw-border-spacing-x: 0;\n --tw-border-spacing-y: 0;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-pan-x: ;\n --tw-pan-y: ;\n --tw-pinch-zoom: ;\n --tw-scroll-snap-strictness: proximity;\n --tw-gradient-from-position: ;\n --tw-gradient-via-position: ;\n --tw-gradient-to-position: ;\n --tw-ordinal: ;\n --tw-slashed-zero: ;\n --tw-numeric-figure: ;\n --tw-numeric-spacing: ;\n --tw-numeric-fraction: ;\n --tw-ring-inset: ;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-color: rgb(59 130 246 / 0.5);\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n --tw-blur: ;\n --tw-brightness: ;\n --tw-contrast: ;\n --tw-grayscale: ;\n --tw-hue-rotate: ;\n --tw-invert: ;\n --tw-saturate: ;\n --tw-sepia: ;\n --tw-drop-shadow: ;\n --tw-backdrop-blur: ;\n --tw-backdrop-brightness: ;\n --tw-backdrop-contrast: ;\n --tw-backdrop-grayscale: ;\n --tw-backdrop-hue-rotate: ;\n --tw-backdrop-invert: ;\n --tw-backdrop-opacity: ;\n --tw-backdrop-saturate: ;\n --tw-backdrop-sepia: ;\n --tw-contain-size: ;\n --tw-contain-layout: ;\n --tw-contain-paint: ;\n --tw-contain-style: ;\n}/*\n! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com\n*//*\n1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)\n2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)\n*/\n\n*,\n::before,\n::after {\n box-sizing: border-box; /* 1 */\n border-width: 0; /* 2 */\n border-style: solid; /* 2 */\n border-color: #e5e7eb; /* 2 */\n}\n\n::before,\n::after {\n --tw-content: '';\n}\n\n/*\n1. Use a consistent sensible line-height in all browsers.\n2. Prevent adjustments of font size after orientation changes in iOS.\n3. Use a more readable tab size.\n4. Use the user's configured `sans` font-family by default.\n5. Use the user's configured `sans` font-feature-settings by default.\n6. Use the user's configured `sans` font-variation-settings by default.\n7. Disable tap highlights on iOS\n*/\n\nhtml,\n:host {\n line-height: 1.5; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n -moz-tab-size: 4; /* 3 */\n -o-tab-size: 4;\n tab-size: 4; /* 3 */\n font-family: ui-sans-serif, system-ui, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"; /* 4 */\n font-feature-settings: normal; /* 5 */\n font-variation-settings: normal; /* 6 */\n -webkit-tap-highlight-color: transparent; /* 7 */\n}\n\n/*\n1. Remove the margin in all browsers.\n2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.\n*/\n\nbody {\n margin: 0; /* 1 */\n line-height: inherit; /* 2 */\n}\n\n/*\n1. Add the correct height in Firefox.\n2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)\n3. Ensure horizontal rules are visible by default.\n*/\n\nhr {\n height: 0; /* 1 */\n color: inherit; /* 2 */\n border-top-width: 1px; /* 3 */\n}\n\n/*\nAdd the correct text decoration in Chrome, Edge, and Safari.\n*/\n\nabbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n}\n\n/*\nRemove the default font size and weight for headings.\n*/\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-size: inherit;\n font-weight: inherit;\n}\n\n/*\nReset links to optimize for opt-in styling instead of opt-out.\n*/\n\na {\n color: inherit;\n text-decoration: inherit;\n}\n\n/*\nAdd the correct font weight in Edge and Safari.\n*/\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/*\n1. Use the user's configured `mono` font-family by default.\n2. Use the user's configured `mono` font-feature-settings by default.\n3. Use the user's configured `mono` font-variation-settings by default.\n4. Correct the odd `em` font sizing in all browsers.\n*/\n\ncode,\nkbd,\nsamp,\npre {\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace; /* 1 */\n font-feature-settings: normal; /* 2 */\n font-variation-settings: normal; /* 3 */\n font-size: 1em; /* 4 */\n}\n\n/*\nAdd the correct font size in all browsers.\n*/\n\nsmall {\n font-size: 80%;\n}\n\n/*\nPrevent `sub` and `sup` elements from affecting the line height in all browsers.\n*/\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/*\n1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)\n2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)\n3. Remove gaps between table borders by default.\n*/\n\ntable {\n text-indent: 0; /* 1 */\n border-color: inherit; /* 2 */\n border-collapse: collapse; /* 3 */\n}\n\n/*\n1. Change the font styles in all browsers.\n2. Remove the margin in Firefox and Safari.\n3. Remove default padding in all browsers.\n*/\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-feature-settings: inherit; /* 1 */\n font-variation-settings: inherit; /* 1 */\n font-size: 100%; /* 1 */\n font-weight: inherit; /* 1 */\n line-height: inherit; /* 1 */\n letter-spacing: inherit; /* 1 */\n color: inherit; /* 1 */\n margin: 0; /* 2 */\n padding: 0; /* 3 */\n}\n\n/*\nRemove the inheritance of text transform in Edge and Firefox.\n*/\n\nbutton,\nselect {\n text-transform: none;\n}\n\n/*\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Remove default button styles.\n*/\n\nbutton,\ninput:where([type='button']),\ninput:where([type='reset']),\ninput:where([type='submit']) {\n -webkit-appearance: button; /* 1 */\n background-color: transparent; /* 2 */\n background-image: none; /* 2 */\n}\n\n/*\nUse the modern Firefox focus style for all focusable elements.\n*/\n\n:-moz-focusring {\n outline: auto;\n}\n\n/*\nRemove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)\n*/\n\n:-moz-ui-invalid {\n box-shadow: none;\n}\n\n/*\nAdd the correct vertical alignment in Chrome and Firefox.\n*/\n\nprogress {\n vertical-align: baseline;\n}\n\n/*\nCorrect the cursor style of increment and decrement buttons in Safari.\n*/\n\n::-webkit-inner-spin-button,\n::-webkit-outer-spin-button {\n height: auto;\n}\n\n/*\n1. Correct the odd appearance in Chrome and Safari.\n2. Correct the outline style in Safari.\n*/\n\n[type='search'] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/*\nRemove the inner padding in Chrome and Safari on macOS.\n*/\n\n::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/*\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Change font properties to `inherit` in Safari.\n*/\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/*\nAdd the correct display in Chrome and Safari.\n*/\n\nsummary {\n display: list-item;\n}\n\n/*\nRemoves the default spacing and border for appropriate elements.\n*/\n\nblockquote,\ndl,\ndd,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\nhr,\nfigure,\np,\npre {\n margin: 0;\n}\n\nfieldset {\n margin: 0;\n padding: 0;\n}\n\nlegend {\n padding: 0;\n}\n\nol,\nul,\nmenu {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n/*\nReset default styling for dialogs.\n*/\ndialog {\n padding: 0;\n}\n\n/*\nPrevent resizing textareas horizontally by default.\n*/\n\ntextarea {\n resize: vertical;\n}\n\n/*\n1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)\n2. Set the default placeholder color to the user's configured gray 400 color.\n*/\n\ninput::-moz-placeholder, textarea::-moz-placeholder {\n opacity: 1; /* 1 */\n color: #9ca3af; /* 2 */\n}\n\ninput::placeholder,\ntextarea::placeholder {\n opacity: 1; /* 1 */\n color: #9ca3af; /* 2 */\n}\n\n/*\nSet the default cursor for buttons.\n*/\n\nbutton,\n[role=\"button\"] {\n cursor: pointer;\n}\n\n/*\nMake sure disabled buttons don't get the pointer cursor.\n*/\n:disabled {\n cursor: default;\n}\n\n/*\n1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)\n2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)\n This can trigger a poorly considered lint error in some tools but is included by design.\n*/\n\nimg,\nsvg,\nvideo,\ncanvas,\naudio,\niframe,\nembed,\nobject {\n display: block; /* 1 */\n vertical-align: middle; /* 2 */\n}\n\n/*\nConstrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)\n*/\n\nimg,\nvideo {\n max-width: 100%;\n height: auto;\n}\n\n/* Make elements with the HTML hidden attribute stay hidden by default */\n[hidden]:where(:not([hidden=\"until-found\"])) {\n display: none;\n}\n.container {\n width: 100%;\n}\n@media (min-width: 640px) {\n\n .container {\n max-width: 640px;\n }\n}\n@media (min-width: 768px) {\n\n .container {\n max-width: 768px;\n }\n}\n@media (min-width: 1024px) {\n\n .container {\n max-width: 1024px;\n }\n}\n@media (min-width: 1280px) {\n\n .container {\n max-width: 1280px;\n }\n}\n@media (min-width: 1536px) {\n\n .container {\n max-width: 1536px;\n }\n}\n#ocs-chat-window {\n z-index: var(--chat-z-index);\n font-size: var(--chat-window-font-size);\n }\n.starter-question {\n border-radius: 0.5rem;\n text-align: left;\n transition-duration: 200ms;\n padding: 0.75em;\n background-color: var(--starter-question-bg-color);\n border: 1px solid var(--starter-question-border-color);\n color: var(--starter-question-text-color);\n}\n.starter-question:hover {\n background-color: var(--starter-question-bg-hover-color);\n border-color: var(--starter-question-border-hover-color);\n }\n.chat-btn-text,\n .chat-btn-icon {\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n border-radius: 0.5rem;\n border-width: 0px;\n --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n transition-property: all;\n transition-duration: 200ms;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n}\n.chat-btn-text:hover,\n .chat-btn-icon:hover {\n --tw-scale-x: 1.05;\n --tw-scale-y: 1.05;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.chat-btn-text,\n .chat-btn-icon {\n background-color: var(--button-background-color, white);\n border: 1px solid var(--button-border-color);\n z-index: var(--chat-z-index, 50);\n font-size: var(--button-font-size);\n padding: 0.5em;\n }\n.chat-btn-text:hover, .chat-btn-icon:hover {\n color: var(--button-text-color-hover, #1d4ed8);\n border: 1px solid var(--button-border-color-hover);\n }\n/* Button with text and icon */\n.chat-btn-text {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--button-text-color, #111827);\n}\n.chat-btn-text span {\n white-space: nowrap;\n font-weight: 500;\n}\n.chat-btn-text img {\n flex-shrink: 0;\n -o-object-fit: contain;\n object-fit: contain;\n width: var(--button-icon-size);\n height: var(--button-icon-size);\n}\n/* Icon-only button */\n.chat-btn-icon {\n }\n.chat-btn-icon img {\n -o-object-fit: contain;\n object-fit: contain;\n width: var(--button-icon-size);\n height: var(--button-icon-size);\n}\n.chat-btn-text.round,\n .chat-btn-icon.round {\n border-radius: 9999px;\n}\n/* Error message styling */\n.error-message {\n padding: 0.5em;\n color: var(--error-text-color);\n }\n/* Chat window positioning classes */\n.chat-window-fullscreen {\n position: fixed;\n inset: 0px;\n z-index: 9999;\n display: flex;\n height: 100%;\n max-height: 100%;\n width: 100%;\n flex-direction: column;\n overflow: hidden;\n border-radius: 0px;\n border-width: 0px;\n --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n transition-property: box-shadow;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n background-color: var(--chat-window-bg-color);\n max-width: var(--chat-window-fullscreen-width);\n}\n.chat-window-normal {\n position: fixed;\n display: flex;\n height: 100vh;\n min-height: 300px;\n width: 100vw;\n min-width: 300px;\n max-width: 1024px;\n flex-direction: column;\n overflow: hidden;\n border-radius: 0.5rem;\n}\n@media (min-width: 640px) {\n\n .chat-window-normal {\n height: var(--chat-window-height);\n width: var(--chat-window-width);\n }\n}\n.chat-window-normal {\n background-color: var(--chat-window-bg-color);\n border: 1px solid var(--chat-window-border-color);\n }\n.chat-window-dragging {\n cursor: grabbing;\n --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);\n --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.chat-window-normal:not(.chat-window-dragging) {\n --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n transition-property: box-shadow;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n}\n/* Header/drag bar classes */\n.chat-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n padding: 0.5em;\n background-color: var(--header-bg-color);\n border-bottom: 1px solid var(--header-border-color);\n font-size: var(--header-font-size);\n}\n.header-text {\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--header-text-font-size);\n color: var(--header-text-color);\n}\n.chat-header:hover,\n .chat-header:active {\n background-color: var(--header-bg-hover-color);\n }\n.chat-header-draggable {\n cursor: grab;\n}\n.chat-header-dragging {\n cursor: grabbing;\n}\n.drag-indicator {\n display: none;\n}\n@media (min-width: 640px) {\n\n .drag-indicator {\n display: flex;\n }\n}\n.drag-dots {\n pointer-events: none;\n margin-left: 2px;\n display: flex;\n gap: 2px;\n}\n.header-buttons {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n/* Header button classes */\n.header-button {\n border-radius: 0.375rem;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n padding: 0.375em;\n color: var(--header-button-text-color);\n}\n.header-button svg {\n width: var(--header-button-icon-size);\n height: var(--header-button-icon-size);\n }\n.header-button:hover {\n background-color: var(--header-button-bg-hover-color);\n }\n.fullscreen-button {\n display: none;\n}\n@media (min-width: 640px) {\n\n .fullscreen-button {\n display: block;\n }\n}\n/* Chat content area */\n.chat-content {\n display: flex;\n flex-grow: 1;\n flex-direction: column;\n overflow: hidden;\n}\n/* Loading state */\n.loading-container {\n display: flex;\n flex-grow: 1;\n align-items: center;\n justify-content: center;\n}\n.loading-text {\n margin-left: 2px;\n color: var(--loading-text-color);\n }\n/* Messages container */\n.messages-container {\n flex-grow: 1;\n}\n.messages-container > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));\n}\n.messages-container {\n overflow-y: auto;\n}\n.messages-container::-webkit-scrollbar {\n height: 0.375rem;\n width: 0.375rem;\n}\n.messages-container::-webkit-scrollbar-track {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-track-color);\n}\n.messages-container::-webkit-scrollbar-thumb {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-thumb-color);\n}\n.messages-container::-webkit-scrollbar-thumb:hover {\n background-color: var(--scrollbar-thumb-hover-color);\n}\n.messages-container {\n padding: 1em;\n }\n/* Message bubbles */\n.message-row {\n display: flex;\n}\n.message-row-user {\n justify-content: flex-end;\n}\n.message-row-assistant {\n justify-content: flex-start;\n}\n.message-bubble {\n border-radius: 0.5rem;\n padding: 0.5em 1em;\n}\n.message-bubble-user {\n background-color: var(--message-user-bg-color);\n color: var(--message-user-text-color);\n }\n.message-bubble-assistant {\n background-color: var(--message-assistant-bg-color);\n color: var(--message-assistant-text-color);\n }\n.message-bubble-system {\n background-color: var(--message-system-bg-color);\n color: var(--message-system-text-color);\n }\n.message-timestamp {\n margin-top: 4px;\n opacity: 0.7;\n font-size: var(--chat-window-font-size-sm);\n}\n.message-attachments {\n margin-top: 8px;\n}\n.message-attachments > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));\n}\n/* Welcome messages */\n.welcome-messages > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));\n}\n/* Typing indicator */\n.typing-indicator {\n height: 0.375rem;\n width: 100%;\n overflow: hidden;\n}\n.typing-progress {\n height: 100%;\n width: 100%;\n transform-origin: 0% 50%;\n}\n@keyframes progress {\n\n 0% {\n transform: translateX(0) scaleX(0);\n }\n\n 10% {\n transform: translateX(0) scaleX(0.3);\n }\n\n 50% {\n transform: translateX(100%) scaleX(0.3);\n }\n\n 90% {\n transform: translateX(0) scaleX(0.3);\n }\n\n 100% {\n transform: translateX(0) scaleX(0);\n }\n}\n.typing-progress {\n animation: progress 3s infinite linear;\n border-radius: 0.5rem;\n background-color: var(--typing-progress-bg-color);\n}\n.typing-text {\n width: 100%;\n justify-content: center;\n opacity: 0.7;\n font-size: var(--chat-window-font-size-sm);\n}\n@keyframes dots {\n\n 0%, 20% {\n color: rgba(0,0,0,0);\n text-shadow: .25em 0 0 rgba(0,0,0,0), .5em 0 0 rgba(0,0,0,0);\n }\n\n 40% {\n color: black;\n text-shadow: .25em 0 0 rgba(0,0,0,0), .5em 0 0 rgba(0,0,0,0);\n }\n\n 60% {\n text-shadow: .25em 0 0 black, .5em 0 0 rgba(0,0,0,0);\n }\n\n 80%, 100% {\n text-shadow: .25em 0 0 black, .5em 0 0 black;\n }\n}\n.typing-dots {\n animation: dots 1s steps(5, end) infinite;\n}\n.typing-dots:after {\n content: ' .';\n}\n/* Starter questions */\n.starter-questions > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));\n}\n.starter-questions {\n padding: 1em;\n }\n.starter-question-row {\n display: flex;\n justify-content: flex-end;\n}\n/* Input area */\n.input-area {\n padding: 1em 1em 0 1em;\n background-color: var(--input-bg-color);\n border-top: 1px solid var(--input-border-color);\n }\n.input-container {\n display: flex;\n gap: 8px;\n}\n.message-textarea {\n flex-grow: 1;\n resize: none;\n border-radius: 0.375rem;\n border-width: 1px;\n --tw-border-opacity: 1;\n border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));\n}\n.message-textarea:focus {\n outline-color: #93c5fd;\n}\n.message-textarea {\n background-color: var(--input-bg-color);\n padding: 0.5em 0.75em;\n color: var(--input-text-color);\n border: 1px solid var(--input-border-color);\n }\n.message-textarea:focus {\n outline-color: var(--input-outline-focus-color);\n }\n.send-button {\n border-radius: 0.375rem;\n font-weight: 500;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n padding: 0.5em 1em;\n}\n.send-button-enabled {\n background-color: var(--send-button-bg-color);\n color: var(--send-button-text-color);\n }\n.send-button-enabled:hover {\n background-color: var(--send-button-bg-hover-color);\n }\n.send-button-disabled {\n cursor: not-allowed;\n background-color: var(--send-button-bg-disabled-color);\n color: var(--send-button-text-disabled-color);\n}\n/* Confirmation dialog */\n.confirmation-overlay {\n position: fixed;\n inset: 0px;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--confirmation-overlay-bg-color);\n z-index: 9999;\n}\n.confirmation-dialog {\n margin-left: 1rem;\n margin-right: 1rem;\n width: 100%;\n max-width: 24rem;\n background-color: var(--confirmation-dialog-bg-color);\n border: 1px solid var(--confirmation-dialog-border-color);\n border-radius: 0.75em;\n box-shadow: 0 0.625em 1.5625em var(--confirmation-dialog-shadow-color);\n}\n.confirmation-content {\n padding: 1.5em;\n }\n.confirmation-title {\n margin-bottom: 0.5rem;\n font-weight: 600;\n color: var(--confirmation-title-color);\n font-size: var(--confirmation-title-font-size);\n}\n.confirmation-message {\n margin-bottom: 1rem;\n color: var(--confirmation-message-color);\n font-size: var(--confirmation-message-font-size);\n}\n.confirmation-buttons {\n display: flex;\n justify-content: flex-end;\n gap: 0.75em;\n}\n.confirmation-button {\n border-radius: 0.375rem;\n font-weight: 500;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n padding: 0.5em 1em;\n}\n.confirmation-button-cancel {\n background-color: var(--confirmation-button-cancel-bg-color);\n color: var(--confirmation-button-cancel-text-color);\n }\n.confirmation-button-cancel:hover {\n background-color: var(--confirmation-button-cancel-bg-hover-color);\n }\n.confirmation-button-confirm {\n background-color: var(--confirmation-button-confirm-bg-color);\n color: var(--confirmation-button-confirm-text-color);\n }\n.confirmation-button-confirm:hover {\n background-color: var(--confirmation-button-confirm-bg-hover-color);\n }\n.\\!visible {\n visibility: visible !important;\n}\n.visible {\n visibility: visible;\n}\n.static {\n position: static;\n}\n.relative {\n position: relative;\n}\n.flex {\n display: flex;\n}\n.table {\n display: table;\n}\n.hidden {\n display: none;\n}\n.w-full {\n width: 100%;\n}\n.transform {\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.resize {\n resize: both;\n}\n.items-center {\n align-items: center;\n}\n.justify-center {\n justify-content: center;\n}\n.gap-\\[0\\.5em\\] {\n gap: 0.5em;\n}\n.space-y-\\[0\\.25em\\] > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.25em * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.25em * var(--tw-space-y-reverse));\n}\n.border {\n border-width: 1px;\n}\n.py-\\[2px\\] {\n padding-top: 2px;\n padding-bottom: 2px;\n}\n.text-\\[0\\.8em\\] {\n font-size: 0.8em;\n}\n.font-light {\n font-weight: 300;\n}\n.text-slate-500 {\n --tw-text-opacity: 1;\n color: rgb(100 116 139 / var(--tw-text-opacity, 1));\n}\n.underline {\n text-decoration-line: underline;\n}\n.shadow {\n --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.filter {\n filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);\n}\n:host {\n /**\n * @prop --chat-z-index: Z-index for chat widget (50)\n *\n * @prop --button-background-color: Button background color (#ffffff)\n * @prop --button-background-color-hover: Button background color on hover (#f3f4f6)\n * @prop --button-text-color: Button text color (#111827)\n * @prop --button-text-color-hover: Button text color on hover (#1d4ed8)\n * @prop --button-border-color: Button border color (#6b7280)\n * @prop --button-border-color-hover: Button border color on hover (#374151)\n * @prop --button-font-size: Button text font size (0.875em)\n * @prop --button-icon-size: Button icon size (1.5em)\n *\n * @prop --chat-window-height: Chat window height in pixels or percent (60%)\n * @prop --chat-window-width: Chat window width in pixels or percent (25%)\n * @prop --chat-window-fullscreen-width: Chat window fullscreen width in pixels or percent (80%)\n * @prop --chat-window-bg-color: Chat window background color (#ffffff)\n * @prop --chat-window-border-color: Chat window border color (#d1d5db)\n * @prop --chat-window-shadow-color: Chat window shadow color (rgba(0, 0, 0, 0.1))\n * @prop --chat-window-font-size: Default font size for text in the chat window (0.875em)\n * @prop --chat-window-font-size-sm: Font size for small text in the chat window (0.75em)\n *\n * @prop --header-bg-color: Header background color (transparent)\n * @prop --header-bg-hover-color: Header background color on hover (#f9fafb)\n * @prop --header-border-color: Header border color (#f3f4f6)\n * @prop --header-button-text-color: Header button text color (#6b7280)\n * @prop --header-button-bg-hover-color: Header button background on hover (#f3f4f6)\n * @prop --header-font-size: Header font size (1em)\n * @prop --header-button-icon-size: Icon size for buttons in the header (1.5em)\n * @prop --header-text-font-size: Font size for the text in the header (1em)\n * @prop --header-text-color: Color for the text in the header (#525762)\n *\n * @prop --starter-question-bg-color: Starter question background color (transparent)\n * @prop --starter-question-bg-hover-color: Starter question background on hover (#eff6ff)\n * @prop --starter-question-text-color: Starter question text color (#3b82f6)\n * @prop --starter-question-border-color: Starter question border color (#3b82f6)\n * @prop --starter-question-border-hover-color: Starter question border on hover (#2563eb)\n *\n * @prop --message-user-bg-color: User message background color (#e4edfb)\n * @prop --message-user-text-color: User message text color (#1f2937)\n * @prop --message-user-link-color: User message link color (#155dfc)\n\n * @prop --message-assistant-bg-color: Assistant message background color (#eae7e8)\n * @prop --message-assistant-text-color: Assistant message text color (--message-user-text-color)\n * @prop --message-assistant-link-color: Assistant message link color (--message-user-link-color)\n\n * @prop --message-system-bg-color: System message background color (#fbe4f8)\n * @prop --message-system-text-color: System message text color (--message-user-text-color)\n * @prop --message-system-link-color: System message link color (--message-user-link-color)\n\n * @prop --message-timestamp-color: User message timestamp color (rgba(255, 255, 255, 0.7))\n * @prop --message-timestamp-assistant-color: Assistant message timestamp color (rgba(75, 85, 99, 0.7))\n *\n * @prop --input-bg-color: Input area background color (transparent)\n * @prop --input-border-color: Input field border color (#d1d5db)\n * @prop --input-text-color: Input text color (#111827)\n * @prop --input-placeholder-color: Input placeholder text color (#6b7280)\n * @prop --input-outline-focus-color: Input field focus ring color (#3b82f6)\n *\n * @prop --send-button-bg-color: Send button background color (#3b82f6)\n * @prop --send-button-bg-hover-color: Send button background on hover (#2563eb)\n * @prop --send-button-text-color: Send button text color (#ffffff)\n * @prop --send-button-bg-disabled-color: Send button background when disabled (#d1d5db)\n * @prop --send-button-text-disabled-color: Send button text when disabled (#6b7280)\n *\n * @prop --loading-text-color: Loading text color (#6b7280)\n * @prop --loading-spinner-track-color: Loading spinner track color (#e5e7eb)\n * @prop --loading-spinner-fill-color: Loading spinner fill color (#3b82f6)\n * @prop --loading-spinner-size: Loading spinner size (1.25em)\n *\n * @prop --typing-progress-bg-color: Typing progress bar background color (#ade3ff)\n *\n * @prop --scrollbar-track-color: Scrollbar track color (#f3f4f6)\n * @prop --scrollbar-thumb-color: Scrollbar thumb color (#d1d5db)\n * @prop --scrollbar-thumb-hover-color: Scrollbar thumb hover color (#9ca3af)\n *\n * @prop --error-text-color: Error text color (#ef4444)\n * @prop --success-text-color: Success text color (#10b981)\n *\n * @prop --code-bg-user-color: Code background in user messages (--message-user-bg-color + 20% white)\n * @prop --code-text-user-color: Code text color in user messages (--message-user-text-color)\n * @prop --code-border-user-color: Code border in user messages (--message-user-bg-color + 20% black)\n * @prop --code-bg-assistant-color: Code background in assistant messages (--message-assistant-bg-color + 50% white)\n * @prop --code-text-assistant-color: Code text color in assistant messages (--message-assistant-text-color)\n * @prop --code-border-assistant-color: Code border in assistant messages (--message-assistant-bg-color + 10% black)\n *\n * @prop --confirmation-overlay-bg-color: Confirmation dialog overlay background color (rgba(0, 0, 0, 0.5))\n * @prop --confirmation-dialog-bg-color: Confirmation dialog background color (uses --chat-window-bg-color)\n * @prop --confirmation-dialog-border-color: Confirmation dialog border color (uses --chat-window-border-color)\n * @prop --confirmation-dialog-shadow-color: Confirmation dialog shadow color (uses --chat-window-shadow-color)\n * @prop --confirmation-title-color: Confirmation dialog title text color (uses #111827)\n * @prop --confirmation-title-font-size: Confirmation dialog title font size (1.125em)\n * @prop --confirmation-message-color: Confirmation dialog message text color (uses --loading-text-color)\n * @prop --confirmation-message-font-size: Confirmation dialog message font size (uses 1em)\n * @prop --confirmation-button-cancel-bg-color: Cancel button background color (uses --button-background-color-hover)\n * @prop --confirmation-button-cancel-bg-hover-color: Cancel button background on hover (uses #e5e7eb)\n * @prop --confirmation-button-cancel-text-color: Cancel button text color (uses --header-button-text-color)\n * @prop --confirmation-button-confirm-bg-color: Confirm button background color (uses --error-text-color)\n * @prop --confirmation-button-confirm-bg-hover-color: Confirm button background on hover (uses --error-text-color)\n * @prop --confirmation-button-confirm-text-color: Confirm button text color (uses --send-button-text-color)\n * @prop --file-attachment-button-bg-color: Attach file button background color (transparent)\n * @prop --file-attachment-button-bg-hover-color: Attach file button background hover color (--header-button-bg-hover-color)\n * @prop --file-attachment-button-text-color: Attach file button text color (--header-button-text-color)\n * @prop --file-attachment-button-text-disabled-color: Attach file button disabled text color (--send-button-text-disabled-color)\n *\n * @prop --selected-files-bg-color: Selected files container background color (--chat-window-bg-color)\n * @prop --selected-files-border-color: Selected files container border color (--header-border-color)\n *\n * @prop --selected-file-bg-color: Selected file item background color (--message-system-bg-color)\n * @prop --selected-file-font-size: Selected file item font size (--chat-window-font-size-sm)\n * @prop --selected-file-name-color: Selected file name color (--message-assistant-text-color)\n * @prop --selected-file-size-color: Selected file size display color (--input-placeholder-color)\n * @prop --selected-file-icon-size: Selected file item icon size (1.25em)\n * @prop --selected-file-remove-icon-color: Selected file remove icon color (--error-text-color)\n * @prop --selected-file-remove-icon-hover-color: Selected file remove icon hover (#dc2626)\n *\n * @prop --message-attachment-icon-size: Message attachment icon size (1em)\n */\n /* Global variables */\n --chat-z-index: 50;\n\n /* Button variables */\n --button-background-color: #ffffff;\n --button-background-color-hover: #f3f4f6;\n --button-text-color: #111827;\n --button-text-color-hover: #1d4ed8;\n --button-border-color: #d1d5db;\n --button-border-color-hover: #6b7280;\n --button-font-size: 1em; /* text-sm */\n --button-icon-size: 1.5em;\n\n /* Chat window variables */\n --chat-window-height: 60%;\n --chat-window-width: 25%;\n --chat-window-fullscreen-width: 80%;\n --chat-window-bg-color: #ffffff;\n --chat-window-border-color: #d1d5db;\n --chat-window-shadow-color: rgba(0, 0, 0, 0.1);\n --chat-window-font-size: 0.875em; /* text-sm */\n --chat-window-font-size-sm: 0.75em; /* text-xs */\n\n /* Header variables */\n --header-bg-color: transparent;\n --header-bg-hover-color: #f9fafb;\n --header-border-color: #f3f4f6;\n --header-button-text-color: #6b7280;\n --header-button-bg-hover-color: #f3f4f6;\n --header-font-size: 1em;\n --header-text-font-size: 1em;\n --header-text-color: #525762;\n --header-button-icon-size: 1.5em;\n\n /* Starter question variables */\n --starter-question-bg-color: transparent;\n --starter-question-bg-hover-color: #eff6ff;\n --starter-question-text-color: #3b82f6;\n --starter-question-border-color: #3b82f6;\n --starter-question-border-hover-color: #2563eb;\n\n /* Message bubble variables */\n --message-user-bg-color: #e4edfb;\n --message-user-text-color: #1f2937;\n --message-user-link-color: #155dfc;\n\n --message-assistant-bg-color: #eae7e8;\n --message-assistant-text-color: var(--message-user-text-color);\n --message-assistant-link-color: var(--message-user-link-color);\n\n --message-system-bg-color: #fbe4f8;\n --message-system-text-color: var(--message-user-text-color);\n --message-system-link-color: var(--message-user-link-color);\n\n --message-timestamp-color: rgba(255, 255, 255, 0.7);\n --message-timestamp-assistant-color: rgba(75, 85, 99, 0.7);\n\n /* Input area variables */\n --input-bg-color: transparent;\n --input-border-color: #d1d5db;\n --input-text-color: #111827;\n --input-placeholder-color: #6b7280;\n --input-outline-focus-color: #3b82f6;\n\n /* Send button variables */\n --send-button-bg-color: #3b82f6;\n --send-button-bg-hover-color: #2563eb;\n --send-button-text-color: #ffffff;\n --send-button-bg-disabled-color: #d1d5db;\n --send-button-text-disabled-color: #6b7280;\n\n /* Loading variables */\n --loading-text-color: #6b7280;\n --loading-spinner-track-color: #e5e7eb;\n --loading-spinner-fill-color: #3b82f6;\n --loading-spinner-size: 1.25em;\n\n /* Typing indicator variables */\n --typing-progress-bg-color: #ade3ff;\n\n /* Scrollbar variables */\n --scrollbar-track-color: #f3f4f6;\n --scrollbar-thumb-color: #d1d5db;\n --scrollbar-thumb-hover-color: #9ca3af;\n\n /* Error variables */\n --error-text-color: #ef4444;\n --success-text-color: #10b981; /* Complementary green to existing blue palette */;\n\n /* Markdown code variables */\n --code-bg-user-color: color-mix(in srgb, var(--message-user-bg-color) 80%, white 20%);\n --code-text-user-color: var(--message-user-text-color);\n --code-border-user-color: color-mix(in srgb, var(--message-user-bg-color) 90%, black 10%);\n --code-bg-assistant-color: color-mix(in srgb, var(--message-assistant-bg-color) 50%, white 50%);\n --code-text-assistant-color: var(--message-assistant-text-color);\n --code-border-assistant-color: color-mix(in srgb, var(--message-assistant-bg-color) 90%, black 10%);;\n\n --confirmation-overlay-bg-color: rgba(0, 0, 0, 0.5);\n --confirmation-dialog-bg-color: var(--chat-window-bg-color);\n --confirmation-dialog-border-color: var(--chat-window-border-color);\n --confirmation-dialog-shadow-color: var(--chat-window-shadow-color);\n --confirmation-title-color: #111827;\n --confirmation-title-font-size: 1.125em;\n --confirmation-message-color: var(--loading-text-color);\n --confirmation-message-font-size: 1em;\n --confirmation-button-cancel-bg-color: var(--button-background-color-hover);\n --confirmation-button-cancel-bg-hover-color: #e5e7eb;\n --confirmation-button-cancel-text-color: var(--header-button-text-color);\n --confirmation-button-confirm-bg-color: var(--error-text-color);\n --confirmation-button-confirm-bg-hover-color: var(--error-text-color);\n --confirmation-button-confirm-text-color: var(--send-button-text-color);\n\n /* File upload variables */\n --file-attachment-button-bg-color: transparent;\n --file-attachment-button-bg-hover-color: var(--header-button-bg-hover-color); /* #f3f4f6 */\n --file-attachment-button-text-color: var(--header-button-text-color); /* #6b7280 */\n --file-attachment-button-text-disabled-color: var(--send-button-text-disabled-color); /* #6b7280 */\n\n /* Selected files variables */\n --selected-files-bg-color: var(--chat-window-bg-color); /* transparent */\n --selected-files-border-color: var(--header-border-color); /* #f3f4f6 */\n\n /* Selected file item variables */\n --selected-file-bg-color: var(--message-system-bg-color); /* #f3f4f6 */\n\n /* Selected file text variables */\n --selected-file-font-size: var(--chat-window-font-size-sm);\n --selected-file-name-color: var(--message-assistant-text-color); /* #1f2937 */\n --selected-file-size-color: var(--input-placeholder-color); /* #6b7280 */\n\n /* Selected file icon variables */\n --selected-file-icon-size: 1.25em;\n --selected-file-remove-icon-color: var(--error-text-color); /* #ef4444 */\n --selected-file-remove-icon-hover-color: #dc2626; /* Darker red for hover */\n\n /* Message attachment variables */\n --message-attachment-icon-size: 1em;\n\n display: block;\n position: fixed;\n right: 30px;\n bottom: 30px;\n}\ntextarea {\n max-height: 8rem;\n min-height: 2.5rem;\n resize: none;\n overflow-y: auto;\n}\ntextarea::-webkit-scrollbar {\n height: 0.375rem;\n width: 0.375rem;\n}\ntextarea::-webkit-scrollbar-track {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-track-color);\n}\ntextarea::-webkit-scrollbar-thumb {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-thumb-color);\n}\ntextarea::-webkit-scrollbar-thumb:hover {\n background-color: var(--scrollbar-thumb-hover-color);\n}\n@keyframes spin {\n\n to {\n transform: rotate(360deg);\n }\n}\n.loading-spinner {\n animation: spin 1s linear infinite;\n border-radius: 9999px;\n border-width: 2px;\n border-color: var(--loading-spinner-track-color);\n border-top-color: var(--loading-spinner-fill-color);\n width: var(--loading-spinner-size);\n height: var(--loading-spinner-size);\n}\n.overflow-y-auto::-webkit-scrollbar {\n height: 0.375rem;\n width: 0.375rem;\n}\n.overflow-y-auto::-webkit-scrollbar-track {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-track-color);\n}\n.overflow-y-auto::-webkit-scrollbar-thumb {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-thumb-color);\n}\n.overflow-y-auto::-webkit-scrollbar-thumb:hover {\n background-color: var(--scrollbar-thumb-hover-color);\n}\n/* Markdown content styling for chat messages */\n.chat-markdown {\n color: var(--tw-prose-body);\n max-width: 65ch;\n}\n.chat-markdown :where(p):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.25em;\n margin-bottom: 1.25em;\n}\n.chat-markdown :where([class~=\"lead\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-lead);\n font-size: 1.25em;\n line-height: 1.6;\n margin-top: 1.2em;\n margin-bottom: 1.2em;\n}\n.chat-markdown :where(a):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-links);\n text-decoration: underline;\n font-weight: 500;\n}\n.chat-markdown :where(strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-bold);\n font-weight: 600;\n}\n.chat-markdown :where(a strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(blockquote strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(thead th strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(ol):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: decimal;\n margin-top: 1.25em;\n margin-bottom: 1.25em;\n padding-inline-start: 1.625em;\n}\n.chat-markdown :where(ol[type=\"A\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: upper-alpha;\n}\n.chat-markdown :where(ol[type=\"a\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: lower-alpha;\n}\n.chat-markdown :where(ol[type=\"A\" s]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: upper-alpha;\n}\n.chat-markdown :where(ol[type=\"a\" s]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: lower-alpha;\n}\n.chat-markdown :where(ol[type=\"I\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: upper-roman;\n}\n.chat-markdown :where(ol[type=\"i\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: lower-roman;\n}\n.chat-markdown :where(ol[type=\"I\" s]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: upper-roman;\n}\n.chat-markdown :where(ol[type=\"i\" s]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: lower-roman;\n}\n.chat-markdown :where(ol[type=\"1\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: decimal;\n}\n.chat-markdown :where(ul):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: disc;\n margin-top: 1.25em;\n margin-bottom: 1.25em;\n padding-inline-start: 1.625em;\n}\n.chat-markdown :where(ol > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::marker {\n font-weight: 400;\n color: var(--tw-prose-counters);\n}\n.chat-markdown :where(ul > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::marker {\n color: var(--tw-prose-bullets);\n}\n.chat-markdown :where(dt):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 600;\n margin-top: 1.25em;\n}\n.chat-markdown :where(hr):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n border-color: var(--tw-prose-hr);\n border-top-width: 1px;\n margin-top: 3em;\n margin-bottom: 3em;\n}\n.chat-markdown :where(blockquote):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 500;\n font-style: italic;\n color: var(--tw-prose-quotes);\n border-inline-start-width: 0.25rem;\n border-inline-start-color: var(--tw-prose-quote-borders);\n quotes: \"\\201C\"\"\\201D\"\"\\2018\"\"\\2019\";\n margin-top: 1.6em;\n margin-bottom: 1.6em;\n padding-inline-start: 1em;\n}\n.chat-markdown :where(blockquote p:first-of-type):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::before {\n content: open-quote;\n}\n.chat-markdown :where(blockquote p:last-of-type):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::after {\n content: close-quote;\n}\n.chat-markdown :where(h1):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 800;\n font-size: 2.25em;\n margin-top: 0;\n margin-bottom: 0.8888889em;\n line-height: 1.1111111;\n}\n.chat-markdown :where(h1 strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 900;\n color: inherit;\n}\n.chat-markdown :where(h2):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 700;\n font-size: 1.5em;\n margin-top: 2em;\n margin-bottom: 1em;\n line-height: 1.3333333;\n}\n.chat-markdown :where(h2 strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 800;\n color: inherit;\n}\n.chat-markdown :where(h3):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 600;\n font-size: 1.25em;\n margin-top: 1.6em;\n margin-bottom: 0.6em;\n line-height: 1.6;\n}\n.chat-markdown :where(h3 strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 700;\n color: inherit;\n}\n.chat-markdown :where(h4):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 600;\n margin-top: 1.5em;\n margin-bottom: 0.5em;\n line-height: 1.5;\n}\n.chat-markdown :where(h4 strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 700;\n color: inherit;\n}\n.chat-markdown :where(img):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 2em;\n margin-bottom: 2em;\n}\n.chat-markdown :where(picture):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n display: block;\n margin-top: 2em;\n margin-bottom: 2em;\n}\n.chat-markdown :where(video):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 2em;\n margin-bottom: 2em;\n}\n.chat-markdown :where(kbd):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 500;\n font-family: inherit;\n color: var(--tw-prose-kbd);\n box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%);\n font-size: 0.875em;\n border-radius: 0.3125rem;\n padding-top: 0.1875em;\n padding-inline-end: 0.375em;\n padding-bottom: 0.1875em;\n padding-inline-start: 0.375em;\n}\n.chat-markdown :where(code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-code);\n font-weight: 600;\n font-size: 0.875em;\n}\n.chat-markdown :where(code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::before {\n content: \"`\";\n}\n.chat-markdown :where(code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::after {\n content: \"`\";\n}\n.chat-markdown :where(a code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(h1 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(h2 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n font-size: 0.875em;\n}\n.chat-markdown :where(h3 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n font-size: 0.9em;\n}\n.chat-markdown :where(h4 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(blockquote code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(thead th code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(pre):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-pre-code);\n background-color: var(--tw-prose-pre-bg);\n overflow-x: auto;\n font-weight: 400;\n font-size: 0.875em;\n line-height: 1.7142857;\n margin-top: 1.7142857em;\n margin-bottom: 1.7142857em;\n border-radius: 0.375rem;\n padding-top: 0.8571429em;\n padding-inline-end: 1.1428571em;\n padding-bottom: 0.8571429em;\n padding-inline-start: 1.1428571em;\n}\n.chat-markdown :where(pre code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n background-color: transparent;\n border-width: 0;\n border-radius: 0;\n padding: 0;\n font-weight: inherit;\n color: inherit;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\n.chat-markdown :where(pre code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::before {\n content: none;\n}\n.chat-markdown :where(pre code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::after {\n content: none;\n}\n.chat-markdown :where(table):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n width: 100%;\n table-layout: auto;\n margin-top: 2em;\n margin-bottom: 2em;\n font-size: 0.875em;\n line-height: 1.7142857;\n}\n.chat-markdown :where(thead):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n border-bottom-width: 1px;\n border-bottom-color: var(--tw-prose-th-borders);\n}\n.chat-markdown :where(thead th):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 600;\n vertical-align: bottom;\n padding-inline-end: 0.5714286em;\n padding-bottom: 0.5714286em;\n padding-inline-start: 0.5714286em;\n}\n.chat-markdown :where(tbody tr):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n border-bottom-width: 1px;\n border-bottom-color: var(--tw-prose-td-borders);\n}\n.chat-markdown :where(tbody tr:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n border-bottom-width: 0;\n}\n.chat-markdown :where(tbody td):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n vertical-align: baseline;\n}\n.chat-markdown :where(tfoot):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n border-top-width: 1px;\n border-top-color: var(--tw-prose-th-borders);\n}\n.chat-markdown :where(tfoot td):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n vertical-align: top;\n}\n.chat-markdown :where(th, td):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n text-align: start;\n}\n.chat-markdown :where(figure > *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n margin-bottom: 0;\n}\n.chat-markdown :where(figcaption):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-captions);\n font-size: 0.875em;\n line-height: 1.4285714;\n margin-top: 0.8571429em;\n}\n.chat-markdown {\n --tw-prose-body: #374151;\n --tw-prose-headings: #111827;\n --tw-prose-lead: #4b5563;\n --tw-prose-links: #111827;\n --tw-prose-bold: #111827;\n --tw-prose-counters: #6b7280;\n --tw-prose-bullets: #d1d5db;\n --tw-prose-hr: #e5e7eb;\n --tw-prose-quotes: #111827;\n --tw-prose-quote-borders: #e5e7eb;\n --tw-prose-captions: #6b7280;\n --tw-prose-kbd: #111827;\n --tw-prose-kbd-shadows: 17 24 39;\n --tw-prose-code: #111827;\n --tw-prose-pre-code: #e5e7eb;\n --tw-prose-pre-bg: #1f2937;\n --tw-prose-th-borders: #d1d5db;\n --tw-prose-td-borders: #e5e7eb;\n --tw-prose-invert-body: #d1d5db;\n --tw-prose-invert-headings: #fff;\n --tw-prose-invert-lead: #9ca3af;\n --tw-prose-invert-links: #fff;\n --tw-prose-invert-bold: #fff;\n --tw-prose-invert-counters: #9ca3af;\n --tw-prose-invert-bullets: #4b5563;\n --tw-prose-invert-hr: #374151;\n --tw-prose-invert-quotes: #f3f4f6;\n --tw-prose-invert-quote-borders: #374151;\n --tw-prose-invert-captions: #9ca3af;\n --tw-prose-invert-kbd: #fff;\n --tw-prose-invert-kbd-shadows: 255 255 255;\n --tw-prose-invert-code: #fff;\n --tw-prose-invert-pre-code: #d1d5db;\n --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);\n --tw-prose-invert-th-borders: #4b5563;\n --tw-prose-invert-td-borders: #374151;\n font-size: 1rem;\n line-height: 1.75;\n}\n.chat-markdown :where(picture > img):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n margin-bottom: 0;\n}\n.chat-markdown :where(li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.5em;\n margin-bottom: 0.5em;\n}\n.chat-markdown :where(ol > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0.375em;\n}\n.chat-markdown :where(ul > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0.375em;\n}\n.chat-markdown :where(.prose > ul > li p):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.75em;\n margin-bottom: 0.75em;\n}\n.chat-markdown :where(.prose > ul > li > p:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.25em;\n}\n.chat-markdown :where(.prose > ul > li > p:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 1.25em;\n}\n.chat-markdown :where(.prose > ol > li > p:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.25em;\n}\n.chat-markdown :where(.prose > ol > li > p:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 1.25em;\n}\n.chat-markdown :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.75em;\n margin-bottom: 0.75em;\n}\n.chat-markdown :where(dl):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.25em;\n margin-bottom: 1.25em;\n}\n.chat-markdown :where(dd):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.5em;\n padding-inline-start: 1.625em;\n}\n.chat-markdown :where(hr + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h2 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h3 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h4 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(thead th:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0;\n}\n.chat-markdown :where(thead th:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-end: 0;\n}\n.chat-markdown :where(tbody td, tfoot td):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-top: 0.5714286em;\n padding-inline-end: 0.5714286em;\n padding-bottom: 0.5714286em;\n padding-inline-start: 0.5714286em;\n}\n.chat-markdown :where(tbody td:first-child, tfoot td:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0;\n}\n.chat-markdown :where(tbody td:last-child, tfoot td:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-end: 0;\n}\n.chat-markdown :where(figure):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 2em;\n margin-bottom: 2em;\n}\n.chat-markdown :where(.prose > :first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(.prose > :last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 0;\n}\n.chat-markdown {\n font-size: 0.875rem;\n line-height: 1.7142857;\n}\n.chat-markdown :where(p):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n margin-bottom: 1.1428571em;\n}\n.chat-markdown :where([class~=\"lead\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 1.2857143em;\n line-height: 1.5555556;\n margin-top: 0.8888889em;\n margin-bottom: 0.8888889em;\n}\n.chat-markdown :where(blockquote):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.3333333em;\n margin-bottom: 1.3333333em;\n padding-inline-start: 1.1111111em;\n}\n.chat-markdown :where(h1):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 2.1428571em;\n margin-top: 0;\n margin-bottom: 0.8em;\n line-height: 1.2;\n}\n.chat-markdown :where(h2):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 1.4285714em;\n margin-top: 1.6em;\n margin-bottom: 0.8em;\n line-height: 1.4;\n}\n.chat-markdown :where(h3):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 1.2857143em;\n margin-top: 1.5555556em;\n margin-bottom: 0.4444444em;\n line-height: 1.5555556;\n}\n.chat-markdown :where(h4):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.4285714em;\n margin-bottom: 0.5714286em;\n line-height: 1.4285714;\n}\n.chat-markdown :where(img):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.7142857em;\n margin-bottom: 1.7142857em;\n}\n.chat-markdown :where(picture):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.7142857em;\n margin-bottom: 1.7142857em;\n}\n.chat-markdown :where(picture > img):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n margin-bottom: 0;\n}\n.chat-markdown :where(video):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.7142857em;\n margin-bottom: 1.7142857em;\n}\n.chat-markdown :where(kbd):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8571429em;\n border-radius: 0.3125rem;\n padding-top: 0.1428571em;\n padding-inline-end: 0.3571429em;\n padding-bottom: 0.1428571em;\n padding-inline-start: 0.3571429em;\n}\n.chat-markdown :where(code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8571429em;\n}\n.chat-markdown :where(h2 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.9em;\n}\n.chat-markdown :where(h3 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8888889em;\n}\n.chat-markdown :where(pre):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8571429em;\n line-height: 1.6666667;\n margin-top: 1.6666667em;\n margin-bottom: 1.6666667em;\n border-radius: 0.25rem;\n padding-top: 0.6666667em;\n padding-inline-end: 1em;\n padding-bottom: 0.6666667em;\n padding-inline-start: 1em;\n}\n.chat-markdown :where(ol):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n margin-bottom: 1.1428571em;\n padding-inline-start: 1.5714286em;\n}\n.chat-markdown :where(ul):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n margin-bottom: 1.1428571em;\n padding-inline-start: 1.5714286em;\n}\n.chat-markdown :where(li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.2857143em;\n margin-bottom: 0.2857143em;\n}\n.chat-markdown :where(ol > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0.4285714em;\n}\n.chat-markdown :where(ul > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0.4285714em;\n}\n.chat-markdown :where(.prose-sm > ul > li p):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.5714286em;\n margin-bottom: 0.5714286em;\n}\n.chat-markdown :where(.prose-sm > ul > li > p:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n}\n.chat-markdown :where(.prose-sm > ul > li > p:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 1.1428571em;\n}\n.chat-markdown :where(.prose-sm > ol > li > p:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n}\n.chat-markdown :where(.prose-sm > ol > li > p:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 1.1428571em;\n}\n.chat-markdown :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.5714286em;\n margin-bottom: 0.5714286em;\n}\n.chat-markdown :where(dl):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n margin-bottom: 1.1428571em;\n}\n.chat-markdown :where(dt):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n}\n.chat-markdown :where(dd):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.2857143em;\n padding-inline-start: 1.5714286em;\n}\n.chat-markdown :where(hr):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 2.8571429em;\n margin-bottom: 2.8571429em;\n}\n.chat-markdown :where(hr + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h2 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h3 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h4 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(table):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8571429em;\n line-height: 1.5;\n}\n.chat-markdown :where(thead th):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-end: 1em;\n padding-bottom: 0.6666667em;\n padding-inline-start: 1em;\n}\n.chat-markdown :where(thead th:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0;\n}\n.chat-markdown :where(thead th:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-end: 0;\n}\n.chat-markdown :where(tbody td, tfoot td):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-top: 0.6666667em;\n padding-inline-end: 1em;\n padding-bottom: 0.6666667em;\n padding-inline-start: 1em;\n}\n.chat-markdown :where(tbody td:first-child, tfoot td:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0;\n}\n.chat-markdown :where(tbody td:last-child, tfoot td:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-end: 0;\n}\n.chat-markdown :where(figure):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.7142857em;\n margin-bottom: 1.7142857em;\n}\n.chat-markdown :where(figure > *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n margin-bottom: 0;\n}\n.chat-markdown :where(figcaption):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8571429em;\n line-height: 1.3333333;\n margin-top: 0.6666667em;\n}\n.chat-markdown :where(.prose-sm > :first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(.prose-sm > :last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 0;\n}\n.chat-markdown {\n --tw-prose-body: #374151;\n --tw-prose-headings: #111827;\n --tw-prose-lead: #4b5563;\n --tw-prose-links: #111827;\n --tw-prose-bold: #111827;\n --tw-prose-counters: #6b7280;\n --tw-prose-bullets: #d1d5db;\n --tw-prose-hr: #e5e7eb;\n --tw-prose-quotes: #111827;\n --tw-prose-quote-borders: #e5e7eb;\n --tw-prose-captions: #6b7280;\n --tw-prose-kbd: #111827;\n --tw-prose-kbd-shadows: 17 24 39;\n --tw-prose-code: #111827;\n --tw-prose-pre-code: #e5e7eb;\n --tw-prose-pre-bg: #1f2937;\n --tw-prose-th-borders: #d1d5db;\n --tw-prose-td-borders: #e5e7eb;\n --tw-prose-invert-body: #d1d5db;\n --tw-prose-invert-headings: #fff;\n --tw-prose-invert-lead: #9ca3af;\n --tw-prose-invert-links: #fff;\n --tw-prose-invert-bold: #fff;\n --tw-prose-invert-counters: #9ca3af;\n --tw-prose-invert-bullets: #4b5563;\n --tw-prose-invert-hr: #374151;\n --tw-prose-invert-quotes: #f3f4f6;\n --tw-prose-invert-quote-borders: #374151;\n --tw-prose-invert-captions: #9ca3af;\n --tw-prose-invert-kbd: #fff;\n --tw-prose-invert-kbd-shadows: 255 255 255;\n --tw-prose-invert-code: #fff;\n --tw-prose-invert-pre-code: #d1d5db;\n --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);\n --tw-prose-invert-th-borders: #4b5563;\n --tw-prose-invert-td-borders: #374151;\n max-width: none;\n}\n.chat-markdown :is(:where(a):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))) {\n text-decoration-line: none;\n}\n.chat-markdown :is(:where(a):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))):hover {\n text-decoration-line: underline;\n}\n.chat-markdown {\n font-size: 1em;\n}\n/* override spacing */\n.chat-markdown > * {\n margin-top: 0.1em;\n margin-bottom: 0.1em;\n}\n.message-bubble-assistant .chat-markdown {\n --tw-prose-body: var(--message-assistant-text-color);\n --tw-prose-headings: var(--message-assistant-text-color);\n --tw-prose-lead: var(--message-assistant-text-color);\n --tw-prose-links: var(--message-assistant-link-color);\n --tw-prose-bold: var(--message-assistant-text-color);\n --tw-prose-counters: var(--message-assistant-text-color);\n --tw-prose-bullets: var(--message-assistant-text-color);\n --tw-prose-hr: var(--message-assistant-text-color);\n --tw-prose-quotes: var(--message-assistant-text-color);\n --tw-prose-quote-borders: var(--message-assistant-text-color);\n --tw-prose-captions: var(--message-assistant-text-color);\n --tw-prose-kbd: var(--message-assistant-text-color);\n --tw-prose-kbd-shadows: var(--message-assistant-text-color);\n --tw-prose-code: var(--code-text-assistant-color);\n --tw-prose-pre-code: var(--code-text-assistant-color);\n --tw-prose-pre-bg: var(--code-bg-assistant-color);\n --tw-prose-th-borders: var(--message-assistant-text-color);\n --tw-prose-td-borders: var(--message-assistant-text-color);\n}\n.message-bubble-user .chat-markdown {\n --tw-prose-body: var(--message-user-text-color);\n --tw-prose-headings: var(--message-user-text-color);\n --tw-prose-lead: var(--message-user-text-color);\n --tw-prose-links: var(--message-user-link-color);\n --tw-prose-bold: var(--message-user-text-color);\n --tw-prose-counters: var(--message-user-text-color);\n --tw-prose-bullets: var(--message-user-text-color);\n --tw-prose-hr: var(--message-user-text-color);\n --tw-prose-quotes: var(--message-user-text-color);\n --tw-prose-quote-borders: var(--message-user-text-color);\n --tw-prose-captions: var(--message-user-text-color);\n --tw-prose-kbd: var(--message-user-text-color);\n --tw-prose-kbd-shadows: var(--message-user-text-color);\n --tw-prose-code: var(--code-text-user-color);\n --tw-prose-pre-code: var(--code-text-user-color);\n --tw-prose-pre-bg: var(--code-bg-user-color);\n --tw-prose-th-borders: var(--message-user-text-color);\n --tw-prose-td-borders: var(--message-user-text-color);\n}\n.message-bubble-system .chat-markdown {\n --tw-prose-body: var(--message-system-text-color);\n --tw-prose-headings: var(--message-system-text-color);\n --tw-prose-lead: var(--message-system-text-color);\n --tw-prose-links: var(--message-system-link-color);\n --tw-prose-bold: var(--message-system-text-color);\n --tw-prose-counters: var(--message-system-text-color);\n --tw-prose-bullets: var(--message-system-text-color);\n --tw-prose-hr: var(--message-system-text-color);\n --tw-prose-quotes: var(--message-system-text-color);\n --tw-prose-quote-borders: var(--message-system-text-color);\n --tw-prose-captions: var(--message-system-text-color);\n --tw-prose-kbd: var(--message-system-text-color);\n --tw-prose-kbd-shadows: var(--message-system-text-color);\n --tw-prose-code: var(--message-system-text-color);\n --tw-prose-pre-code: var(--message-system-text-color);\n --tw-prose-pre-bg: var(--message-system-text-color);\n --tw-prose-th-borders: var(--message-system-text-color);\n --tw-prose-td-borders: var(--message-system-text-color);\n}\n.message-bubble-user .chat-markdown pre {\n border: 1px solid var(--code-border-user-color);\n}\n.message-bubble-assistant .chat-markdown pre {\n border: 1px solid var(--code-border-assistant-color);\n}\n.loading:after {\n content: ' .';\n}\n/* File Upload Button */\n.file-attachment-button {\n border-radius: 0.375rem;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n}\n.file-attachment-button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n.file-attachment-button {\n padding: 0.375em;\n background-color: var(--file-attachment-button-bg-color);\n color: var(--file-attachment-button-text-color);\n}\n.file-attachment-button svg {\n width: 1.5em;\n height: 1.5em;\n}\n.file-attachment-button:hover:not(:disabled) {\n background-color: var(--file-attachment-button-bg-hover-color);\n}\n.file-attachment-button:disabled {\n color: var(--file-attachment-button-text-disabled-color);\n}\n/* Selected Files Container */\n.selected-files-container {\n padding: 1em 1em 0.5em 1em;\n background-color: var(--selected-files-bg-color);\n border-top: 1px solid var(--selected-files-border-color);\n}\n/* Selected File Item */\n.selected-file-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n background-color: var(--selected-file-bg-color);\n border-radius: 0.375em;\n padding: 0.25em 0.5em;\n font-size: var(--selected-file-font-size);\n color: var(--selected-file-name-color);\n}\n.selected-file-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.selected-file-icon svg {\n width: var(--selected-file-icon-size);\n height: var(--selected-file-icon-size);\n}\n.selected-file-size {\n color: var(--selected-file-size-color);\n}\n.selected-file-error {\n color: var(--error-text-color);\n}\n.selected-file-success-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--success-text-color);\n width: var(--selected-file-icon-size);\n height: var(--selected-file-icon-size);\n}\n.selected-file-remove-button {\n font-weight: 700;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n color: var(--selected-file-remove-icon-color);\n padding: 0.375em;\n}\n.selected-file-remove-button svg {\n width: var(--selected-file-icon-size);\n height: var(--selected-file-icon-size);\n}\n.selected-file-remove-button:hover {\n color: var(--selected-file-remove-icon-hover-color);\n}\n/* Message Attachments */\n.message-attachments {\n margin-top: 0.5em;\n}\n.message-attachments > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.25em * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.25em * var(--tw-space-y-reverse));\n}\n.message-attachments {\n font-size: var(--chat-window-font-size-sm);\n}\n.message-attachment-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--message-attachment-icon-size);\n height: var(--message-attachment-icon-size);\n}\n/* Update Send Button for Upload State */\n.send-button-disabled {\n cursor: not-allowed;\n background-color: var(--send-button-bg-disabled-color);\n color: var(--send-button-text-disabled-color);\n}\n";
5171
+ const ocsChatCss = "/*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */@layer properties{@supports ((-webkit-hyphens:none) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,::backdrop,:after,:before{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-ease:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:host,:root{--font-sans:ui-sans-serif,system-ui,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;--color-blue-300:oklch(80.9% .105 251.813);--color-slate-500:oklch(55.4% .046 257.417);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--spacing:.25rem;--breakpoint-lg:64rem;--container-sm:24rem;--font-weight-light:300;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--animate-progress:progress 3s infinite linear;--animate-dots:dots 1s steps(5,end)infinite;--transform-origin-left-right:0% 50%}}@layer base{*,::backdrop,:after,:before{border:0 solid;border-color:var(--color-gray-200,currentcolor);box-sizing:border-box;margin:0;padding:0}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button;background-color:#0000;border:0 solid;border-color:var(--color-gray-200,currentcolor);border-radius:0;box-sizing:border-box;color:inherit;font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;margin:0;margin-inline-end:4px;opacity:1;padding:0}:host,html{-webkit-text-size-adjust:100%;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-size:1em;font-variation-settings:var(--default-mono-font-variation-settings,normal)}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}menu,ol,ul{list-style:none}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}button,input,optgroup,select,textarea{background-color:#0000;border-radius:0;color:inherit;font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::-moz-placeholder{opacity:1}::placeholder{opacity:1}@supports (not (-webkit-appearance:-apple-pay-button)) or (contain-intrinsic-size:1px){::-moz-placeholder{color:currentColor}::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::-moz-placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex;padding-block:0}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.fixed{position:fixed}.relative{position:relative}.static{position:static}.container{width:100%}.flex{display:flex}.hidden{display:none}.w-full{width:100%}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.resize{resize:both}.items-center{align-items:center}.justify-center{justify-content:center}.gap-\\[0\\.5em\\]{gap:.5em}:where(.space-y-\\[0\\.25em\\]>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(.25em*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(.25em*var(--tw-space-y-reverse))}.border{border-style:var(--tw-border-style);border-width:1px}.py-\\[2px\\]{padding-block:2px}.text-\\[0\\.8em\\]{font-size:.8em}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.text-slate-500{color:var(--color-slate-500)}.underline{text-decoration-line:underline}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a)}.ring,.shadow{box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor)}} /*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */@layer properties{}@layer base{}@layer components; /*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */@layer properties{}@layer base{}@layer components{#ocs-chat-window{font-size:var(--chat-window-font-size);z-index:var(--chat-z-index)}.starter-question{border-radius:var(--radius-lg);text-align:left;--tw-duration:.2s;background-color:var(--starter-question-bg-color);border:1px solid var(--starter-question-border-color);color:var(--starter-question-text-color);padding:.75em;transition-duration:.2s}.starter-question:hover{background-color:var(--starter-question-bg-hover-color);border-color:var(--starter-question-border-hover-color)}.chat-btn-text{border-radius:var(--radius-lg);border-style:var(--tw-border-style);transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,);--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;--tw-ease:var(--ease-in-out);align-items:center;background-color:var(--button-background-color,#fff);border-width:0;border:1px solid var(--button-border-color);color:var(--button-text-color,#111827);display:flex;font-size:var(--button-font-size);gap:8px;padding:.5em;transition-duration:.2s;transition-timing-function:var(--ease-in-out);z-index:var(--chat-z-index,50)}.chat-btn-text:hover{border:1px solid var(--button-border-color-hover);color:var(--button-text-color-hover,#1d4ed8)}.chat-btn-text span{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap}.chat-btn-text img{flex-shrink:0;height:var(--button-icon-size);-o-object-fit:contain;object-fit:contain;width:var(--button-icon-size)}.chat-btn-text.round{border-radius:3.40282e+38px}.chat-btn-icon{border-radius:var(--radius-lg);border-style:var(--tw-border-style);transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,);--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;--tw-ease:var(--ease-in-out);background-color:var(--button-background-color,#fff);border-width:0;border:1px solid var(--button-border-color);font-size:var(--button-font-size);padding:.5em;transition-duration:.2s;transition-timing-function:var(--ease-in-out);z-index:var(--chat-z-index,50)}.chat-btn-icon:hover{border:1px solid var(--button-border-color-hover);color:var(--button-text-color-hover,#1d4ed8)}.chat-btn-icon img{height:var(--button-icon-size);-o-object-fit:contain;object-fit:contain;width:var(--button-icon-size)}.chat-btn-icon.round,.round .chat-btn-icon,.round.chat-btn-text{border-radius:3.40282e+38px}.error-message{color:var(--error-text-color);padding:.5em}.chat-window-fullscreen{border-style:var(--tw-border-style);inset:calc(var(--spacing)*0);z-index:9999;--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);height:100%;max-height:100%;transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));width:100%;--tw-duration:.2s;border-radius:0;border-width:0;max-width:var(--chat-window-fullscreen-width);transition-duration:.2s}.chat-window-fullscreen,.chat-window-normal{background-color:var(--chat-window-bg-color);display:flex;flex-direction:column;overflow:hidden;position:fixed}.chat-window-normal{border:1px solid var(--chat-window-border-color);border-radius:var(--radius-lg);height:100vh;max-width:var(--breakpoint-lg);min-height:300px;min-width:300px;width:100vw}.chat-window-normal:not(.chat-window-dragging){--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;transition-duration:.2s}.chat-window-dragging,.chat-window-normal:not(.chat-window-dragging){box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.chat-window-dragging{cursor:grabbing;--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040)}.chat-header{transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.15s;align-items:center;background-color:var(--header-bg-color);border-bottom:1px solid var(--header-border-color);display:flex;font-size:var(--header-font-size);justify-content:space-between;padding:.5em;transition-duration:.15s}.chat-header:active,.chat-header:hover{background-color:var(--header-bg-hover-color)}.header-text{align-items:center;color:var(--header-text-color);display:flex;font-size:var(--header-text-font-size);justify-content:center}.chat-header-draggable{cursor:grab}.chat-header-dragging{cursor:grabbing}.drag-indicator{display:none}.drag-dots{display:flex;gap:2px;margin-left:2px;pointer-events:none}.header-buttons{align-items:center;display:flex;gap:4px}.header-button{border-radius:var(--radius-md);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;color:var(--header-button-text-color);padding:.375em;transition-duration:.2s}.header-button svg{height:var(--header-button-icon-size);width:var(--header-button-icon-size)}.header-button:hover{background-color:var(--header-button-bg-hover-color)}.fullscreen-button{display:none}.chat-content{display:flex;flex-direction:column;flex-grow:1;overflow:hidden}.loading-container{align-items:center;display:flex;flex-grow:1;justify-content:center}.loading-text{color:var(--loading-text-color);margin-left:2px}.messages-container{flex-grow:1;overflow-y:auto;padding:1em}:where(.messages-container>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(var(--spacing)*2*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(var(--spacing)*2*var(--tw-space-y-reverse))}.message-row{display:flex}.message-row-user{justify-content:flex-end}.message-row-assistant{justify-content:flex-start}.message-bubble{border-radius:var(--radius-lg);padding:.5em 1em}.message-bubble-user{background-color:var(--message-user-bg-color);color:var(--message-user-text-color)}.message-bubble-assistant{background-color:var(--message-assistant-bg-color);color:var(--message-assistant-text-color)}.message-bubble-system{background-color:var(--message-system-bg-color);color:var(--message-system-text-color)}.message-timestamp{font-size:var(--chat-window-font-size-sm);margin-top:4px;opacity:.7}.message-attachments{margin-top:8px}:where(.message-attachments>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(var(--spacing)*1*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(var(--spacing)*1*var(--tw-space-y-reverse))}.attachment-link{display:block;text-decoration-line:underline}:where(.welcome-messages>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(var(--spacing)*2*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(var(--spacing)*2*var(--tw-space-y-reverse))}.typing-indicator{height:calc(var(--spacing)*1.5);overflow:hidden;width:100%}.typing-progress{animation:var(--animate-progress);background-color:var(--typing-progress-bg-color);border-radius:var(--radius-lg);height:100%;transform-origin:var(--transform-origin-left-right);width:100%}.typing-text{font-size:var(--chat-window-font-size-sm);justify-content:center;opacity:.7;width:100%}.typing-dots{animation:var(--animate-dots)}:where(.starter-questions>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(var(--spacing)*2*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(var(--spacing)*2*var(--tw-space-y-reverse))}.starter-questions{padding:1em}.starter-question-row{display:flex;justify-content:flex-end}.input-area{background-color:var(--input-bg-color);border-top:1px solid var(--input-border-color);padding:1em 1em 0}.input-container{display:flex;gap:8px}.message-textarea{background-color:var(--input-bg-color);border-color:var(--color-gray-300);border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;border:1px solid var(--input-border-color);color:var(--input-text-color);flex-grow:1;padding:.5em .75em;resize:none}.message-textarea:focus{outline-color:var(--input-outline-focus-color)}.send-button{border-radius:var(--radius-md);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;padding:.5em 1em;transition-duration:.2s}.send-button-enabled{background-color:var(--send-button-bg-color);color:var(--send-button-text-color)}.send-button-enabled:hover{background-color:var(--send-button-bg-hover-color)}.send-button-disabled{background-color:var(--send-button-bg-disabled-color);color:var(--send-button-text-disabled-color);cursor:not-allowed}.confirmation-overlay{align-items:center;background-color:var(--confirmation-overlay-bg-color);display:flex;inset:calc(var(--spacing)*0);justify-content:center;position:fixed;z-index:9999}.confirmation-dialog{background-color:var(--confirmation-dialog-bg-color);border:1px solid var(--confirmation-dialog-border-color);border-radius:.75em;box-shadow:0 .625em 1.5625em var(--confirmation-dialog-shadow-color);margin-inline:calc(var(--spacing)*4);max-width:var(--container-sm);width:100%}.confirmation-content{padding:1.5em}.confirmation-title{margin-bottom:calc(var(--spacing)*2);--tw-font-weight:var(--font-weight-semibold);color:var(--confirmation-title-color);font-size:var(--confirmation-title-font-size);font-weight:var(--font-weight-semibold)}.confirmation-message{color:var(--confirmation-message-color);font-size:var(--confirmation-message-font-size);margin-bottom:calc(var(--spacing)*4)}.confirmation-buttons{display:flex;gap:.75em;justify-content:flex-end}.confirmation-button{border-radius:var(--radius-md);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;padding:.5em 1em;transition-duration:.2s}.confirmation-button-cancel{background-color:var(--confirmation-button-cancel-bg-color);color:var(--confirmation-button-cancel-text-color)}.confirmation-button-cancel:hover{background-color:var(--confirmation-button-cancel-bg-hover-color)}.confirmation-button-confirm{background-color:var(--confirmation-button-confirm-bg-color);color:var(--confirmation-button-confirm-text-color)}.confirmation-button-confirm:hover{background-color:var(--confirmation-button-confirm-bg-hover-color)}}@layer utilities{:host{--chat-z-index:50;--button-background-color:#fff;--button-background-color-hover:#f3f4f6;--button-text-color:#111827;--button-text-color-hover:#1d4ed8;--button-border-color:#d1d5db;--button-border-color-hover:#6b7280;--button-font-size:1em;--button-icon-size:1.5em;--chat-window-height:60%;--chat-window-width:25%;--chat-window-fullscreen-width:80%;--chat-window-bg-color:#fff;--chat-window-border-color:#d1d5db;--chat-window-shadow-color:#0000001a;--chat-window-font-size:.875em;--chat-window-font-size-sm:.75em;--header-bg-color:transparent;--header-bg-hover-color:#f9fafb;--header-border-color:#f3f4f6;--header-button-text-color:#6b7280;--header-button-bg-hover-color:#f3f4f6;--header-font-size:1em;--header-text-font-size:1em;--header-text-color:#525762;--header-button-icon-size:1.5em;--starter-question-bg-color:transparent;--starter-question-bg-hover-color:#eff6ff;--starter-question-text-color:#3b82f6;--starter-question-border-color:#3b82f6;--starter-question-border-hover-color:#2563eb;--message-user-bg-color:#e4edfb;--message-user-text-color:#1f2937;--message-user-link-color:#155dfc;--message-assistant-bg-color:#eae7e8;--message-assistant-text-color:var(--message-user-text-color);--message-assistant-link-color:var(--message-user-link-color);--message-system-bg-color:#fbe4f8;--message-system-text-color:var(--message-user-text-color);--message-system-link-color:var(--message-user-link-color);--message-timestamp-color:#ffffffb3;--message-timestamp-assistant-color:#4b5563b3;--input-bg-color:transparent;--input-border-color:#d1d5db;--input-text-color:#111827;--input-placeholder-color:#6b7280;--input-outline-focus-color:#3b82f6;--send-button-bg-color:#3b82f6;--send-button-bg-hover-color:#2563eb;--send-button-text-color:#fff;--send-button-bg-disabled-color:#d1d5db;--send-button-text-disabled-color:#6b7280;--loading-text-color:#6b7280;--loading-spinner-track-color:#e5e7eb;--loading-spinner-fill-color:#3b82f6;--loading-spinner-size:1.25em;--typing-progress-bg-color:#ade3ff;--scrollbar-track-color:#f3f4f6;--scrollbar-thumb-color:#d1d5db;--scrollbar-thumb-hover-color:#9ca3af;--error-text-color:#ef4444;--success-text-color:#10b981;--code-bg-user-color:var(--message-user-bg-color);--code-text-user-color:var(--message-user-text-color);--code-border-user-color:var(--message-user-bg-color);--code-bg-assistant-color:var(--message-assistant-bg-color);--code-text-assistant-color:var(--message-assistant-text-color);--code-border-assistant-color:var(--message-assistant-bg-color);--confirmation-overlay-bg-color:#00000080;--confirmation-dialog-bg-color:var(--chat-window-bg-color);--confirmation-dialog-border-color:var(--chat-window-border-color);--confirmation-dialog-shadow-color:var(--chat-window-shadow-color);--confirmation-title-color:#111827;--confirmation-title-font-size:1.125em;--confirmation-message-color:var(--loading-text-color);--confirmation-message-font-size:1em;--confirmation-button-cancel-bg-color:var(--button-background-color-hover);--confirmation-button-cancel-bg-hover-color:#e5e7eb;--confirmation-button-cancel-text-color:var(--header-button-text-color);--confirmation-button-confirm-bg-color:var(--error-text-color);--confirmation-button-confirm-bg-hover-color:var(--error-text-color);--confirmation-button-confirm-text-color:var(--send-button-text-color);--file-attachment-button-bg-color:transparent;--file-attachment-button-bg-hover-color:var(--header-button-bg-hover-color);--file-attachment-button-text-color:var(--header-button-text-color);--file-attachment-button-text-disabled-color:var(--send-button-text-disabled-color);--selected-files-bg-color:var(--chat-window-bg-color);--selected-files-border-color:var(--header-border-color);--selected-file-bg-color:var(--message-system-bg-color);--selected-file-font-size:var(--chat-window-font-size-sm);--selected-file-name-color:var(--message-assistant-text-color);--selected-file-size-color:var(--input-placeholder-color);--selected-file-icon-size:1.25em;--selected-file-remove-icon-color:var(--error-text-color);--selected-file-remove-icon-hover-color:#dc2626;--message-attachment-icon-size:1em;bottom:30px;display:block;position:fixed;right:30px}@supports (color:color-mix(in lab,red,red)){:host{--code-bg-user-color:color-mix(in srgb,var(--message-user-bg-color)80%,#fff 20%);--code-border-user-color:color-mix(in srgb,var(--message-user-bg-color)90%,#000 10%);--code-bg-assistant-color:color-mix(in srgb,var(--message-assistant-bg-color)50%,#fff 50%);--code-border-assistant-color:color-mix(in srgb,var(--message-assistant-bg-color)90%,#000 10%)}}}textarea{max-height:calc(var(--spacing)*32);min-height:calc(var(--spacing)*10);overflow-y:auto;resize:none}.loading-spinner{animation:var(--animate-spin);border-color:var(--loading-spinner-track-color);border-radius:3.40282e+38px;border-style:var(--tw-border-style);border-top-color:var(--loading-spinner-fill-color);border-width:2px;height:var(--loading-spinner-size);width:var(--loading-spinner-size)}.overflow-y-auto::-webkit-scrollbar{height:calc(var(--spacing)*1.5);width:calc(var(--spacing)*1.5)}.overflow-y-auto::-webkit-scrollbar-track{background-color:var(--scrollbar-track-color);border-radius:var(--radius-sm)}.overflow-y-auto::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-color);border-radius:var(--radius-sm)}.overflow-y-auto::-webkit-scrollbar-thumb:hover{background-color:var(--scrollbar-thumb-hover-color)}.chat-markdown{color:var(--tw-prose-body);font-size:1rem;font-size:.875rem;line-height:1.75;line-height:1.71429;max-width:65ch;--tw-prose-body:oklch(37.3% .034 259.733);--tw-prose-headings:oklch(21% .034 264.665);--tw-prose-lead:oklch(44.6% .03 256.802);--tw-prose-links:oklch(21% .034 264.665);--tw-prose-bold:oklch(21% .034 264.665);--tw-prose-counters:oklch(55.1% .027 264.364);--tw-prose-bullets:oklch(87.2% .01 258.338);--tw-prose-hr:oklch(92.8% .006 264.531);--tw-prose-quotes:oklch(21% .034 264.665);--tw-prose-quote-borders:oklch(92.8% .006 264.531);--tw-prose-captions:oklch(55.1% .027 264.364);--tw-prose-kbd:oklch(21% .034 264.665);--tw-prose-kbd-shadows:NaN NaN NaN;--tw-prose-code:oklch(21% .034 264.665);--tw-prose-pre-code:oklch(92.8% .006 264.531);--tw-prose-pre-bg:oklch(27.8% .033 256.848);--tw-prose-th-borders:oklch(87.2% .01 258.338);--tw-prose-td-borders:oklch(92.8% .006 264.531);--tw-prose-invert-body:oklch(87.2% .01 258.338);--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:oklch(70.7% .022 261.325);--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:oklch(70.7% .022 261.325);--tw-prose-invert-bullets:oklch(44.6% .03 256.802);--tw-prose-invert-hr:oklch(37.3% .034 259.733);--tw-prose-invert-quotes:oklch(96.7% .003 264.542);--tw-prose-invert-quote-borders:oklch(37.3% .034 259.733);--tw-prose-invert-captions:oklch(70.7% .022 261.325);--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:oklch(87.2% .01 258.338);--tw-prose-invert-pre-bg:#00000080;--tw-prose-invert-th-borders:oklch(44.6% .03 256.802);--tw-prose-invert-td-borders:oklch(37.3% .034 259.733);font-size:1em;max-width:none}.chat-markdown :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;font-size:1.28571em;line-height:1.6;line-height:1.55556;margin-bottom:.888889em;margin-top:.888889em}.chat-markdown :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline;text-decoration-line:none}.chat-markdown :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.chat-markdown :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.chat-markdown :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.chat-markdown :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.chat-markdown :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.chat-markdown :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.chat-markdown :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.chat-markdown :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.chat-markdown :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.chat-markdown :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.chat-markdown :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.chat-markdown :where(ol[type=\"1\"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.chat-markdown :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.chat-markdown :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.chat-markdown :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.chat-markdown :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.14286em}.chat-markdown :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:2.85714em;margin-top:2.85714em}.chat-markdown :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){border-inline-start-color:var(--tw-prose-quote-borders);border-inline-start-width:.25rem;color:var(--tw-prose-quotes);font-style:italic;font-weight:500;margin-bottom:1.33333em;margin-top:1.33333em;padding-inline-start:1em;padding-inline-start:1.11111em;quotes:\"\u201C\"\"\u201D\"\"\u2018\"\"\u2019\"}.chat-markdown :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.chat-markdown :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.chat-markdown :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-size:2.14286em;font-weight:800;line-height:1.11111;line-height:1.2;margin-bottom:.8em;margin-top:0}.chat-markdown :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:900}.chat-markdown :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-size:1.42857em;font-weight:700;line-height:1.33333;line-height:1.4;margin-bottom:.8em;margin-top:1.6em}.chat-markdown :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:800}.chat-markdown :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-size:1.28571em;font-weight:600;line-height:1.6;line-height:1.55556;margin-bottom:.444444em;margin-top:1.55556em}.chat-markdown :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.chat-markdown :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;line-height:1.42857;margin-bottom:.571429em;margin-top:1.42857em}.chat-markdown :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.chat-markdown :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-bottom:2em;margin-top:2em}.chat-markdown :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows)/10%);color:var(--tw-prose-kbd);font-family:inherit;font-size:.875em;font-size:.857143em;font-weight:500;padding-inline-end:.375em;padding-inline-end:.357143em;padding-bottom:.142857em;padding-inline-start:.375em;padding-top:.142857em;padding-inline-start:.357143em}.chat-markdown :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-size:.857143em;font-weight:600}.chat-markdown :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after,.chat-markdown :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:\"\\`\"}.chat-markdown :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.chat-markdown :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em;font-size:.9em}.chat-markdown :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em;font-size:.888889em}.chat-markdown :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.chat-markdown :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;border-radius:.25rem;color:var(--tw-prose-pre-code);font-size:.875em;font-size:.857143em;font-weight:400;line-height:1.71429;line-height:1.66667;margin-bottom:1.66667em;margin-top:1.66667em;overflow-x:auto;padding-inline-end:1.14286em;padding-inline-end:1em;padding-bottom:.666667em;padding-inline-start:1.14286em;padding-top:.666667em;padding-inline-start:1em}.chat-markdown :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:#0000;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.chat-markdown :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after,.chat-markdown :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.chat-markdown :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;font-size:.857143em;line-height:1.71429;line-height:1.5;margin-bottom:2em;margin-top:2em;table-layout:auto;width:100%}.chat-markdown :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.chat-markdown :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-inline-end:.571429em;padding-inline-end:1em;padding-bottom:.666667em;padding-inline-start:.571429em;padding-inline-start:1em;vertical-align:bottom}.chat-markdown :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.chat-markdown :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.chat-markdown :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.chat-markdown :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.chat-markdown :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.chat-markdown :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.chat-markdown :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;font-size:.857143em;line-height:1.42857;line-height:1.33333;margin-top:.666667em}.chat-markdown :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.chat-markdown :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.chat-markdown :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.chat-markdown :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.chat-markdown :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.chat-markdown :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.chat-markdown :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.chat-markdown :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em;margin-top:1.14286em}.chat-markdown :where(img):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.71429em;margin-top:1.71429em}.chat-markdown :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.chat-markdown :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.71429em;margin-top:1.71429em}.chat-markdown :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em;margin-top:1.14286em;padding-inline-start:1.57143em}.chat-markdown :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.285714em;margin-top:.285714em}.chat-markdown :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.428571em}.chat-markdown :where(.prose-sm>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.571429em;margin-top:.571429em}.chat-markdown :where(.prose-sm>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em}.chat-markdown :where(.prose-sm>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em}.chat-markdown :where(.prose-sm>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em}.chat-markdown :where(.prose-sm>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em}.chat-markdown :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.571429em;margin-top:.571429em}.chat-markdown :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em;margin-top:1.14286em}.chat-markdown :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.285714em;padding-inline-start:1.57143em}.chat-markdown :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.chat-markdown :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.chat-markdown :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.chat-markdown :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.666667em;padding-top:.666667em;padding-inline-start:1em}.chat-markdown :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.chat-markdown :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.chat-markdown :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.71429em;margin-top:1.71429em}.chat-markdown :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.chat-markdown :where(.prose-sm>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.chat-markdown :where(.prose-sm>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.chat-markdown>*{margin-bottom:.1em;margin-top:.1em}.message-bubble-assistant .chat-markdown{--tw-prose-body:var(--message-assistant-text-color);--tw-prose-headings:var(--message-assistant-text-color);--tw-prose-lead:var(--message-assistant-text-color);--tw-prose-links:var(--message-assistant-link-color);--tw-prose-bold:var(--message-assistant-text-color);--tw-prose-counters:var(--message-assistant-text-color);--tw-prose-bullets:var(--message-assistant-text-color);--tw-prose-hr:var(--message-assistant-text-color);--tw-prose-quotes:var(--message-assistant-text-color);--tw-prose-quote-borders:var(--message-assistant-text-color);--tw-prose-captions:var(--message-assistant-text-color);--tw-prose-kbd:var(--message-assistant-text-color);--tw-prose-kbd-shadows:var(--message-assistant-text-color);--tw-prose-code:var(--code-text-assistant-color);--tw-prose-pre-code:var(--code-text-assistant-color);--tw-prose-pre-bg:var(--code-bg-assistant-color);--tw-prose-th-borders:var(--message-assistant-text-color);--tw-prose-td-borders:var(--message-assistant-text-color)}.message-bubble-user .chat-markdown{--tw-prose-body:var(--message-user-text-color);--tw-prose-headings:var(--message-user-text-color);--tw-prose-lead:var(--message-user-text-color);--tw-prose-links:var(--message-user-link-color);--tw-prose-bold:var(--message-user-text-color);--tw-prose-counters:var(--message-user-text-color);--tw-prose-bullets:var(--message-user-text-color);--tw-prose-hr:var(--message-user-text-color);--tw-prose-quotes:var(--message-user-text-color);--tw-prose-quote-borders:var(--message-user-text-color);--tw-prose-captions:var(--message-user-text-color);--tw-prose-kbd:var(--message-user-text-color);--tw-prose-kbd-shadows:var(--message-user-text-color);--tw-prose-code:var(--code-text-user-color);--tw-prose-pre-code:var(--code-text-user-color);--tw-prose-pre-bg:var(--code-bg-user-color);--tw-prose-th-borders:var(--message-user-text-color);--tw-prose-td-borders:var(--message-user-text-color)}.message-bubble-system .chat-markdown{--tw-prose-body:var(--message-system-text-color);--tw-prose-headings:var(--message-system-text-color);--tw-prose-lead:var(--message-system-text-color);--tw-prose-links:var(--message-system-link-color);--tw-prose-bold:var(--message-system-text-color);--tw-prose-counters:var(--message-system-text-color);--tw-prose-bullets:var(--message-system-text-color);--tw-prose-hr:var(--message-system-text-color);--tw-prose-quotes:var(--message-system-text-color);--tw-prose-quote-borders:var(--message-system-text-color);--tw-prose-captions:var(--message-system-text-color);--tw-prose-kbd:var(--message-system-text-color);--tw-prose-kbd-shadows:var(--message-system-text-color);--tw-prose-code:var(--message-system-text-color);--tw-prose-pre-code:var(--message-system-text-color);--tw-prose-pre-bg:var(--message-system-text-color);--tw-prose-th-borders:var(--message-system-text-color);--tw-prose-td-borders:var(--message-system-text-color)}.message-bubble-user .chat-markdown pre{border:1px solid var(--code-border-user-color)}.message-bubble-assistant .chat-markdown pre{border:1px solid var(--code-border-assistant-color)}.loading:after{content:\" .\"}.file-attachment-button{border-radius:var(--radius-md);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;background-color:var(--file-attachment-button-bg-color);color:var(--file-attachment-button-text-color);padding:.375em;transition-duration:.2s}.file-attachment-button:disabled{color:var(--file-attachment-button-text-disabled-color);cursor:not-allowed;opacity:.5}.file-attachment-button svg{height:1.5em;width:1.5em}.file-attachment-button:hover:not(:disabled){background-color:var(--file-attachment-button-bg-hover-color)}.selected-files-container{background-color:var(--selected-files-bg-color);border-top:1px solid var(--selected-files-border-color);padding:1em 1em .5em}.selected-file-item{align-items:center;background-color:var(--selected-file-bg-color);border-radius:.375em;color:var(--selected-file-name-color);display:flex;font-size:var(--selected-file-font-size);justify-content:space-between;padding:.25em .5em}.selected-file-icon{align-items:center;display:flex;justify-content:center}.selected-file-icon svg{height:var(--selected-file-icon-size);width:var(--selected-file-icon-size)}.selected-file-size{color:var(--selected-file-size-color)}.selected-file-error{color:var(--error-text-color)}.selected-file-success-icon{align-items:center;color:var(--success-text-color);display:flex;height:var(--selected-file-icon-size);justify-content:center;width:var(--selected-file-icon-size)}.selected-file-remove-button{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;color:var(--selected-file-remove-icon-color);padding:.375em;transition-duration:.2s}.selected-file-remove-button svg{height:var(--selected-file-icon-size);width:var(--selected-file-icon-size)}.selected-file-remove-button:hover{color:var(--selected-file-remove-icon-hover-color)}.message-attachments{font-size:var(--chat-window-font-size-sm);margin-top:.5em}:where(.message-attachments>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(.25em*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(.25em*var(--tw-space-y-reverse))}.message-attachment-icon{align-items:center;display:flex;height:var(--message-attachment-icon-size);justify-content:center;width:var(--message-attachment-icon-size)}.send-button-disabled{background-color:var(--send-button-bg-disabled-color);color:var(--send-button-text-disabled-color);cursor:not-allowed}@property --tw-rotate-x{syntax:\"*\";inherits:false}@property --tw-rotate-y{syntax:\"*\";inherits:false}@property --tw-rotate-z{syntax:\"*\";inherits:false}@property --tw-skew-x{syntax:\"*\";inherits:false}@property --tw-skew-y{syntax:\"*\";inherits:false}@property --tw-space-y-reverse{syntax:\"*\";inherits:false;initial-value:0}@property --tw-border-style{syntax:\"*\";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:\"*\";inherits:false}@property --tw-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:\"*\";inherits:false}@property --tw-shadow-alpha{syntax:\"<percentage>\";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:\"*\";inherits:false}@property --tw-inset-shadow-alpha{syntax:\"<percentage>\";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:\"*\";inherits:false}@property --tw-ring-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:\"*\";inherits:false}@property --tw-inset-ring-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:\"*\";inherits:false}@property --tw-ring-offset-width{syntax:\"<length>\";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:\"*\";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:\"*\";inherits:false}@property --tw-ease{syntax:\"*\";inherits:false}@property --tw-scale-x{syntax:\"*\";inherits:false;initial-value:1}@property --tw-scale-y{syntax:\"*\";inherits:false;initial-value:1}@property --tw-scale-z{syntax:\"*\";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(1turn)}}@keyframes progress{0%{transform:translate(0)scaleX(0)}10%{transform:translate(0)scaleX(.3)}50%{transform:translate(100%)scaleX(.3)}90%{transform:translate(0)scaleX(.3)}to{transform:translate(0)scaleX(0)}}@keyframes dots{0%,20%{color:#0000;text-shadow:.25em 0 #0000,.5em 0 #0000}40%{color:#000;text-shadow:.25em 0 #0000,.5em 0 #0000}60%{text-shadow:.25em 0 #000,.5em 0 #0000}80%,to{text-shadow:.25em 0 #000,.5em 0 #000}}@media (min-width:40rem){.container{max-width:40rem}.chat-window-normal{height:var(--chat-window-height);width:var(--chat-window-width)}.drag-indicator{display:flex}.fullscreen-button{display:block}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}@media (hover:hover){.chat-btn-icon:hover,.chat-btn-text:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x)var(--tw-scale-y)}.attachment-link:hover{text-decoration-line:none}.chat-markdown :where(a):not(:where([class~=not-prose],[class~=not-prose] *)):hover{text-decoration-line:underline}}";
4505
5172
 
4506
5173
  const OcsChat = class {
4507
5174
  constructor(hostRef) {
4508
5175
  registerInstance(this, hostRef);
4509
5176
  /**
4510
- * The base URL for the API (defaults to current origin).
5177
+ * The base URL for the API.
4511
5178
  */
4512
- this.apiBaseUrl = "https://chatbots.dimagi.com";
5179
+ this.apiBaseUrl = "https://www.openchatstudio.com";
4513
5180
  /**
4514
5181
  * The shape of the chat button. 'round' makes it circular, 'square' keeps it rectangular.
4515
5182
  */
4516
5183
  this.buttonShape = 'square';
4517
- /**
4518
- * The message to display in the new chat confirmation dialog.
4519
- */
4520
- this.newChatConfirmationMessage = "Starting a new chat will clear your current conversation. Continue?";
4521
5184
  /**
4522
5185
  * Whether the chat widget is visible on load.
4523
5186
  */
@@ -4543,10 +5206,6 @@ const OcsChat = class {
4543
5206
  * Allow the user to attach files to their messages.
4544
5207
  */
4545
5208
  this.allowAttachments = false;
4546
- /**
4547
- * The text to display while the assistant is typing/preparing a response.
4548
- */
4549
- this.typingIndicatorText = "Preparing response";
4550
5209
  this.error = "";
4551
5210
  this.messages = [];
4552
5211
  this.isLoading = false;
@@ -4563,6 +5222,20 @@ const OcsChat = class {
4563
5222
  this.showNewChatConfirmation = false;
4564
5223
  this.selectedFiles = [];
4565
5224
  this.isUploadingFiles = false;
5225
+ this.buttonPosition = { x: 30, y: 30 };
5226
+ this.buttonHorizontalSide = 'right';
5227
+ this.buttonVerticalSide = 'bottom';
5228
+ this.isButtonDragging = false;
5229
+ this.buttonWasDragged = false;
5230
+ this.translationManager = new TranslationManager();
5231
+ this.attachmentManager = new FileAttachmentManager({
5232
+ supportedExtensions: OcsChat.SUPPORTED_FILE_EXTENSIONS,
5233
+ maxFileSizeMb: OcsChat.MAX_FILE_SIZE_MB,
5234
+ maxTotalSizeMb: OcsChat.MAX_TOTAL_SIZE_MB,
5235
+ });
5236
+ this.buttonDragOffset = { x: 0, y: 0 };
5237
+ this.rafId = null;
5238
+ this.buttonListenersAttached = false;
4566
5239
  this.chatWindowHeight = 600;
4567
5240
  this.chatWindowWidth = 450;
4568
5241
  this.chatWindowFullscreenWidth = 1024;
@@ -4611,15 +5284,101 @@ const OcsChat = class {
4611
5284
  this.endDrag();
4612
5285
  };
4613
5286
  this.handleWindowResize = () => {
5287
+ var _a, _b;
4614
5288
  this.positionInitialized = false;
4615
5289
  this.initializePosition();
5290
+ // Revalidate button position after resize to keep it within viewport bounds
5291
+ if (this.isButtonDraggable()) {
5292
+ const windowWidth = window.innerWidth;
5293
+ const windowHeight = window.innerHeight;
5294
+ const buttonWidth = ((_a = this.buttonRef) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 60;
5295
+ const buttonHeight = ((_b = this.buttonRef) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
5296
+ const minPadding = 10;
5297
+ this.buttonPosition = {
5298
+ x: Math.max(minPadding, Math.min(this.buttonPosition.x, windowWidth - buttonWidth - minPadding)),
5299
+ y: Math.max(minPadding, Math.min(this.buttonPosition.y, windowHeight - buttonHeight - minPadding))
5300
+ };
5301
+ this.updateHostPosition();
5302
+ }
5303
+ };
5304
+ this.handleButtonMouseDown = (event) => {
5305
+ if (!this.buttonRef || !this.isButtonDraggable())
5306
+ return;
5307
+ event.preventDefault();
5308
+ event.stopPropagation();
5309
+ const pointer = this.getPointerCoordinates(event);
5310
+ if (!pointer)
5311
+ return;
5312
+ this.isButtonDragging = true;
5313
+ this.buttonWasDragged = false; // Reset the drag flag
5314
+ const rect = this.host.getBoundingClientRect();
5315
+ this.buttonDragOffset = {
5316
+ x: pointer.clientX - rect.left,
5317
+ y: pointer.clientY - rect.top
5318
+ };
5319
+ this.addButtonEventListeners();
5320
+ };
5321
+ this.handleButtonTouchStart = (event) => {
5322
+ if (!this.buttonRef || !this.isButtonDraggable())
5323
+ return;
5324
+ event.preventDefault();
5325
+ event.stopPropagation();
5326
+ const pointer = this.getPointerCoordinates(event);
5327
+ if (!pointer)
5328
+ return;
5329
+ this.isButtonDragging = true;
5330
+ this.buttonWasDragged = false; // Reset the drag flag
5331
+ const rect = this.host.getBoundingClientRect();
5332
+ this.buttonDragOffset = {
5333
+ x: pointer.clientX - rect.left,
5334
+ y: pointer.clientY - rect.top
5335
+ };
5336
+ this.addButtonEventListeners();
5337
+ };
5338
+ this.handleButtonMouseMove = (event) => {
5339
+ if (!this.isButtonDragging)
5340
+ return;
5341
+ const pointer = this.getPointerCoordinates(event);
5342
+ if (!pointer)
5343
+ return;
5344
+ this.updateButtonPosition(pointer);
5345
+ };
5346
+ this.handleButtonTouchMove = (event) => {
5347
+ if (!this.isButtonDragging)
5348
+ return;
5349
+ event.preventDefault();
5350
+ const pointer = this.getPointerCoordinates(event);
5351
+ if (!pointer)
5352
+ return;
5353
+ this.updateButtonPosition(pointer);
5354
+ };
5355
+ this.handleButtonMouseUp = () => {
5356
+ if (this.isButtonDragging) {
5357
+ this.isButtonDragging = false;
5358
+ this.removeButtonEventListeners();
5359
+ }
5360
+ };
5361
+ this.handleButtonTouchEnd = () => {
5362
+ if (this.isButtonDragging) {
5363
+ this.isButtonDragging = false;
5364
+ this.removeButtonEventListeners();
5365
+ }
5366
+ };
5367
+ this.handleButtonClick = () => {
5368
+ // Only toggle visibility if the button wasn't dragged
5369
+ if (!this.buttonWasDragged) {
5370
+ this.toggleWindowVisibility();
5371
+ }
5372
+ // Reset the flag after handling the click
5373
+ this.buttonWasDragged = false;
4616
5374
  };
4617
5375
  }
4618
- componentWillLoad() {
5376
+ async componentWillLoad() {
4619
5377
  if (!this.chatbotId) {
4620
5378
  this.error = 'Chatbot ID is required';
4621
5379
  return;
4622
5380
  }
5381
+ await this.initializeTranslations();
4623
5382
  // Always try to load existing session if localStorage is available
4624
5383
  if (this.persistentSession && this.isLocalStorageAvailable()) {
4625
5384
  const { sessionId, messages } = this.loadSessionFromStorage();
@@ -4639,6 +5398,8 @@ const OcsChat = class {
4639
5398
  this.chatWindowHeight = varToPixels(windowHeightVar, window.innerHeight, this.chatWindowHeight);
4640
5399
  this.chatWindowWidth = varToPixels(windowWidthVar, window.innerWidth, this.chatWindowWidth);
4641
5400
  this.chatWindowFullscreenWidth = varToPixels(fullscreenWidthVar, window.innerWidth, this.chatWindowFullscreenWidth);
5401
+ // Initialize button position from computed styles
5402
+ this.initializeButtonPosition();
4642
5403
  if (this.visible) {
4643
5404
  this.initializePosition();
4644
5405
  }
@@ -4648,15 +5409,29 @@ const OcsChat = class {
4648
5409
  }
4649
5410
  else if (this.visible && this.sessionId) {
4650
5411
  // Resume polling for existing session
4651
- this.startPolling();
5412
+ this.startMessagePolling();
4652
5413
  }
4653
5414
  window.addEventListener('resize', this.handleWindowResize);
4654
5415
  }
4655
5416
  disconnectedCallback() {
4656
5417
  this.cleanup();
4657
5418
  this.removeEventListeners();
5419
+ this.removeButtonEventListeners();
4658
5420
  window.removeEventListener('resize', this.handleWindowResize);
4659
5421
  }
5422
+ getChatService() {
5423
+ if (!this.chatService) {
5424
+ this.chatService = new ChatSessionService({
5425
+ apiBaseUrl: this.apiBaseUrl || 'https://www.openchatstudio.com',
5426
+ embedKey: this.embedKey,
5427
+ widgetVersion: Env.version,
5428
+ taskPollingIntervalMs: OcsChat.TASK_POLLING_INTERVAL_MS,
5429
+ taskPollingMaxAttempts: OcsChat.TASK_POLLING_MAX_ATTEMPTS,
5430
+ messagePollingIntervalMs: OcsChat.MESSAGE_POLLING_INTERVAL_MS,
5431
+ });
5432
+ }
5433
+ return this.chatService;
5434
+ }
4660
5435
  addErrorMessage(errorText) {
4661
5436
  const errorMessage = {
4662
5437
  created_at: new Date().toISOString(),
@@ -4700,25 +5475,34 @@ const OcsChat = class {
4700
5475
  parseStarterQuestions() {
4701
5476
  this.parsedStarterQuestions = this.parseJSONProp(this.starterQuestions, 'starter questions');
4702
5477
  }
4703
- cleanup() {
4704
- if (this.pollingIntervalRef) {
4705
- clearInterval(this.pollingIntervalRef);
4706
- this.pollingIntervalRef = undefined;
5478
+ async initializeTranslations() {
5479
+ let customTranslationsObj;
5480
+ if (this.translationsUrl) {
5481
+ customTranslationsObj = await this.loadTranslationsFromUrl(this.translationsUrl);
4707
5482
  }
4708
- this.currentPollTaskId = '';
5483
+ this.translationManager = new TranslationManager(this.language, customTranslationsObj);
4709
5484
  }
4710
- getApiBaseUrl() {
4711
- return this.apiBaseUrl || window.location.origin;
5485
+ async loadTranslationsFromUrl(url) {
5486
+ try {
5487
+ const response = await fetch(url);
5488
+ if (!response.ok) {
5489
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5490
+ }
5491
+ const translations = await response.json();
5492
+ return translations;
5493
+ }
5494
+ catch (error) {
5495
+ console.error('Error loading translations from URL:', error);
5496
+ return defaultTranslations;
5497
+ }
4712
5498
  }
4713
- getApiHeaders() {
4714
- const headers = {
4715
- 'Content-Type': 'application/json',
4716
- };
4717
- const csrfToken = getCSRFToken(this.getApiBaseUrl());
4718
- if (csrfToken) {
4719
- headers['X-CSRFToken'] = csrfToken;
5499
+ cleanup() {
5500
+ this.stopMessagePolling();
5501
+ if (this.taskPollingHandle) {
5502
+ this.taskPollingHandle.cancel();
5503
+ this.taskPollingHandle = undefined;
4720
5504
  }
4721
- return headers;
5505
+ this.currentPollTaskId = '';
4722
5506
  }
4723
5507
  async startSession() {
4724
5508
  try {
@@ -4735,94 +5519,38 @@ const OcsChat = class {
4735
5519
  if (this.userName) {
4736
5520
  requestBody.participant_name = this.userName;
4737
5521
  }
4738
- const response = await fetch(`${this.getApiBaseUrl()}/api/chat/start/`, {
4739
- method: 'POST',
4740
- headers: this.getApiHeaders(),
4741
- body: JSON.stringify(requestBody)
4742
- });
4743
- if (!response.ok) {
4744
- this.handleError(`Failed to start session: ${response.statusText}`);
4745
- return;
4746
- }
4747
- const data = await response.json();
5522
+ const data = await this.getChatService().startSession(requestBody);
4748
5523
  this.sessionId = data.session_id;
4749
5524
  this.saveSessionToStorage();
4750
5525
  // Handle seed message if present
4751
5526
  if (data.seed_message_task_id) {
4752
- this.isTyping = true; // Show typing indicator for seed message
4753
- this.currentPollTaskId = data.seed_message_task_id;
4754
- await this.pollTaskResponse();
5527
+ this.startTaskPolling(data.seed_message_task_id);
5528
+ }
5529
+ else {
5530
+ this.startMessagePolling();
4755
5531
  }
4756
- // Start polling for messages
4757
- this.startPolling();
4758
5532
  }
4759
- catch (error) {
5533
+ catch (_error) {
4760
5534
  this.handleError('Failed to start chat session');
4761
5535
  }
4762
5536
  finally {
4763
5537
  this.isLoading = false;
4764
5538
  }
4765
5539
  }
4766
- markPendingFilesWithError(errorMessage) {
4767
- this.selectedFiles = this.selectedFiles.map(sf => {
4768
- if (!sf.error && !sf.uploaded) {
4769
- return Object.assign(Object.assign({}, sf), { error: errorMessage });
4770
- }
4771
- return sf;
4772
- });
4773
- }
4774
5540
  async uploadFiles() {
4775
5541
  if (this.selectedFiles.length === 0 || !this.sessionId || !this.allowAttachments) {
4776
5542
  return [];
4777
5543
  }
4778
5544
  this.isUploadingFiles = true;
4779
- const uploadedIds = [];
4780
5545
  try {
4781
- const formData = new FormData();
4782
- // Add all files to form data
4783
- for (const selectedFile of this.selectedFiles) {
4784
- if (!selectedFile.error && !selectedFile.uploaded) {
4785
- formData.append('files', selectedFile.file);
4786
- }
4787
- else if (selectedFile.uploaded) {
4788
- uploadedIds.push(selectedFile.uploaded.id);
4789
- }
4790
- }
4791
- // Add user ID and name to the form data
4792
- const userId = this.getOrGenerateUserId();
4793
- formData.append('participant_remote_id', userId);
4794
- if (this.userName) {
4795
- formData.append('participant_name', this.userName);
4796
- }
4797
- // Only upload if there are new files
4798
- if (formData.has('files')) {
4799
- const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/upload/`, {
4800
- method: 'POST',
4801
- body: formData,
4802
- });
4803
- if (!response.ok) {
4804
- const errorData = await response.json();
4805
- const errorMessage = errorData.error || 'Failed to upload files';
4806
- this.markPendingFilesWithError(errorMessage);
4807
- return uploadedIds;
4808
- }
4809
- const data = await response.json();
4810
- // Update selected files with upload results
4811
- let fileIndex = 0;
4812
- this.selectedFiles = this.selectedFiles.map(sf => {
4813
- if (!sf.error && !sf.uploaded) {
4814
- return Object.assign(Object.assign({}, sf), { uploaded: data.files[fileIndex++] });
4815
- }
4816
- return sf;
4817
- });
4818
- uploadedIds.push(...data.files.map((f) => f.id));
4819
- }
4820
- return uploadedIds;
4821
- }
4822
- catch (error) {
4823
- const errorMessage = error instanceof Error ? error.message : 'Failed to upload files';
4824
- this.markPendingFilesWithError(errorMessage);
4825
- return uploadedIds;
5546
+ const uploadResult = await this.attachmentManager.uploadPendingFiles(this.selectedFiles, {
5547
+ apiBaseUrl: this.apiBaseUrl || 'https://www.openchatstudio.com',
5548
+ sessionId: this.sessionId,
5549
+ participantId: this.getOrGenerateUserId(),
5550
+ participantName: this.userName,
5551
+ });
5552
+ this.selectedFiles = uploadResult.selectedFiles;
5553
+ return uploadResult.uploadedIds;
4826
5554
  }
4827
5555
  finally {
4828
5556
  this.isUploadingFiles = false;
@@ -4875,27 +5603,15 @@ const OcsChat = class {
4875
5603
  this.selectedFiles = []; // Clear selected files after sending
4876
5604
  }
4877
5605
  this.scrollToBottom();
4878
- // Start typing indicator - it will stay on during task polling
4879
- this.isTyping = true;
4880
5606
  const requestBody = { message: message.trim() };
4881
5607
  if (this.allowAttachments && attachmentIds.length > 0) {
4882
5608
  requestBody.attachment_ids = attachmentIds;
4883
5609
  }
4884
- const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/message/`, {
4885
- method: 'POST',
4886
- headers: this.getApiHeaders(),
4887
- body: JSON.stringify(requestBody)
4888
- });
4889
- if (!response.ok) {
4890
- throw new Error(`Failed to send message: ${response.statusText}`);
4891
- }
4892
- const data = await response.json();
5610
+ const data = await this.getChatService().sendMessage(this.sessionId, requestBody);
4893
5611
  if (data.status === 'error') {
4894
5612
  throw new Error(data.error || 'Failed to send message');
4895
5613
  }
4896
- // Poll for the response - typing indicator will be managed in pollTaskResponse
4897
- this.currentPollTaskId = data.task_id;
4898
- await this.pollTaskResponse();
5614
+ this.startTaskPolling(data.task_id);
4899
5615
  }
4900
5616
  catch (error) {
4901
5617
  const errorText = error instanceof Error ? error.message : 'Failed to send message';
@@ -4905,110 +5621,6 @@ const OcsChat = class {
4905
5621
  handleStarterQuestionClick(question) {
4906
5622
  this.sendMessage(question);
4907
5623
  }
4908
- async pollTaskResponse() {
4909
- if (!this.sessionId || !this.currentPollTaskId)
4910
- return;
4911
- // Stop message polling while task polling is active
4912
- this.pauseMessagePolling();
4913
- let attempts = 0;
4914
- const poll = async () => {
4915
- if (!this.sessionId || !this.currentPollTaskId)
4916
- return;
4917
- try {
4918
- const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/${this.currentPollTaskId}/poll/`);
4919
- if (!response.ok) {
4920
- throw new Error(`Failed to poll task: ${response.statusText}`);
4921
- }
4922
- const data = await response.json();
4923
- if (data.error) {
4924
- throw new Error(data.error);
4925
- }
4926
- if (data.status === 'complete' && data.message) {
4927
- this.messages = [...this.messages, data.message];
4928
- this.saveSessionToStorage();
4929
- this.scrollToBottom();
4930
- // Task polling complete, clear typing indicator and resume message polling
4931
- this.isTyping = false;
4932
- this.currentPollTaskId = '';
4933
- this.resumeMessagePolling();
4934
- this.focusInput();
4935
- return;
4936
- }
4937
- if (data.status === 'processing' && attempts < OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
4938
- attempts++;
4939
- setTimeout(poll, OcsChat.TASK_POLLING_INTERVAL_MS);
4940
- }
4941
- else if (attempts >= OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
4942
- // Task polling timed out - add timeout message and resume polling
4943
- const timeoutMessage = {
4944
- created_at: new Date().toISOString(),
4945
- role: 'system',
4946
- content: 'The response is taking longer than expected. The system may be experiencing delays. Please try sending your message again.',
4947
- attachments: []
4948
- };
4949
- this.messages = [...this.messages, timeoutMessage];
4950
- this.saveSessionToStorage();
4951
- this.scrollToBottom();
4952
- // Clear typing indicator and resume message polling
4953
- this.isTyping = false;
4954
- this.currentPollTaskId = '';
4955
- this.resumeMessagePolling();
4956
- this.focusInput();
4957
- }
4958
- }
4959
- catch (error) {
4960
- const errorText = error instanceof Error ? error.message : 'Failed to get response';
4961
- this.handleError(errorText);
4962
- // Clear states and resume polling
4963
- this.currentPollTaskId = '';
4964
- this.resumeMessagePolling();
4965
- }
4966
- };
4967
- await poll();
4968
- }
4969
- startPolling() {
4970
- if (this.pollingIntervalRef)
4971
- return;
4972
- this.pollingIntervalRef = setInterval(async () => {
4973
- // Only poll for messages if not currently polling for a task
4974
- if (!this.currentPollTaskId) {
4975
- await this.pollForMessages();
4976
- }
4977
- }, OcsChat.MESSAGE_POLLING_INTERVAL_MS);
4978
- }
4979
- pauseMessagePolling() {
4980
- if (this.pollingIntervalRef) {
4981
- clearInterval(this.pollingIntervalRef);
4982
- this.pollingIntervalRef = undefined;
4983
- }
4984
- }
4985
- resumeMessagePolling() {
4986
- // Resume message polling after task polling is complete
4987
- this.startPolling();
4988
- }
4989
- async pollForMessages() {
4990
- if (!this.sessionId)
4991
- return;
4992
- try {
4993
- const url = new URL(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/poll/`);
4994
- if (this.messages && this.messages.length > 0) {
4995
- url.searchParams.set('since', this.messages.at(-1).created_at);
4996
- }
4997
- const response = await fetch(url.toString());
4998
- if (!response.ok)
4999
- return; // Silently fail for polling
5000
- const data = await response.json();
5001
- if (data.messages.length > 0) {
5002
- this.messages = [...this.messages, ...data.messages];
5003
- this.saveSessionToStorage();
5004
- this.scrollToBottom();
5005
- this.focusInput();
5006
- }
5007
- }
5008
- catch (_a) {
5009
- // Silently fail for polling
5010
- }
5011
- }
5012
5624
  /**
5013
5625
  * Scroll the message container to the bottom.
5014
5626
  * @param forceEnd When `false`, scroll the top of the last message into view.
@@ -5053,50 +5665,18 @@ const OcsChat = class {
5053
5665
  this.messageInput = event.target.value;
5054
5666
  }
5055
5667
  handleFileSelect(event) {
5056
- var _a;
5057
5668
  if (!this.allowAttachments)
5058
5669
  return;
5059
5670
  const input = event.target;
5060
5671
  if (!input.files || input.files.length === 0)
5061
5672
  return;
5062
- const newFiles = [];
5063
- let totalSize = this.selectedFiles.reduce((sum, f) => sum + f.file.size, 0);
5064
- for (let i = 0; i < input.files.length; i++) {
5065
- const file = input.files[i];
5066
- const ext = '.' + ((_a = file.name.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase());
5067
- if (!OcsChat.SUPPORTED_FILE_EXTENSIONS.includes(ext)) {
5068
- newFiles.push({
5069
- file,
5070
- error: `File type ${ext} not supported`
5071
- });
5072
- continue;
5073
- }
5074
- const fileSizeMB = file.size / (1024 * 1024);
5075
- if (fileSizeMB > OcsChat.MAX_FILE_SIZE_MB) {
5076
- newFiles.push({
5077
- file,
5078
- error: `File exceeds ${OcsChat.MAX_FILE_SIZE_MB}MB limit`
5079
- });
5080
- continue;
5081
- }
5082
- totalSize += file.size;
5083
- const totalSizeMB = totalSize / (1024 * 1024);
5084
- if (totalSizeMB > OcsChat.MAX_TOTAL_SIZE_MB) {
5085
- newFiles.push({
5086
- file,
5087
- error: `Total size exceeds ${OcsChat.MAX_TOTAL_SIZE_MB}MB limit`
5088
- });
5089
- continue;
5090
- }
5091
- newFiles.push({ file });
5092
- }
5093
- this.selectedFiles = [...this.selectedFiles, ...newFiles];
5673
+ this.selectedFiles = this.attachmentManager.addFiles(this.selectedFiles, input.files);
5094
5674
  input.value = '';
5095
5675
  }
5096
5676
  removeSelectedFile(index) {
5097
5677
  if (!this.allowAttachments)
5098
5678
  return;
5099
- this.selectedFiles = this.selectedFiles.filter((_, i) => i !== index);
5679
+ this.selectedFiles = this.attachmentManager.removeFile(this.selectedFiles, index);
5100
5680
  }
5101
5681
  formatFileSize(bytes) {
5102
5682
  if (bytes === 0)
@@ -5123,6 +5703,11 @@ const OcsChat = class {
5123
5703
  * @param visible - The new value for the field.
5124
5704
  */
5125
5705
  async visibilityHandler(visible) {
5706
+ if (this.isButtonDragging) {
5707
+ this.isButtonDragging = false;
5708
+ this.buttonWasDragged = false;
5709
+ this.removeButtonEventListeners();
5710
+ }
5126
5711
  if (visible) {
5127
5712
  this.initializePosition();
5128
5713
  }
@@ -5130,11 +5715,86 @@ const OcsChat = class {
5130
5715
  await this.startSession();
5131
5716
  }
5132
5717
  else if (!visible) {
5133
- this.pauseMessagePolling();
5718
+ this.stopMessagePolling();
5134
5719
  }
5135
5720
  else {
5136
5721
  this.scrollToBottom(true);
5137
- this.resumeMessagePolling();
5722
+ this.startMessagePolling();
5723
+ }
5724
+ }
5725
+ startTaskPolling(taskId) {
5726
+ if (!this.sessionId)
5727
+ return;
5728
+ this.currentPollTaskId = taskId;
5729
+ this.isTyping = true;
5730
+ this.stopMessagePolling();
5731
+ if (this.taskPollingHandle) {
5732
+ this.taskPollingHandle.cancel();
5733
+ }
5734
+ this.taskPollingHandle = this.getChatService().pollTask(this.sessionId, taskId, {
5735
+ onMessage: (message) => {
5736
+ this.messages = [...this.messages, message];
5737
+ this.saveSessionToStorage();
5738
+ this.scrollToBottom();
5739
+ this.isTyping = false;
5740
+ this.currentPollTaskId = '';
5741
+ this.taskPollingHandle = undefined;
5742
+ this.startMessagePolling();
5743
+ this.focusInput();
5744
+ },
5745
+ onTimeout: () => {
5746
+ const timeoutMessage = {
5747
+ created_at: new Date().toISOString(),
5748
+ role: 'system',
5749
+ content: 'The response is taking longer than expected. The system may be experiencing delays. Please try sending your message again.',
5750
+ attachments: []
5751
+ };
5752
+ this.messages = [...this.messages, timeoutMessage];
5753
+ this.saveSessionToStorage();
5754
+ this.scrollToBottom();
5755
+ this.isTyping = false;
5756
+ this.currentPollTaskId = '';
5757
+ this.taskPollingHandle = undefined;
5758
+ this.startMessagePolling();
5759
+ this.focusInput();
5760
+ },
5761
+ onError: (error) => {
5762
+ this.handleError(error.message);
5763
+ this.taskPollingHandle = undefined;
5764
+ this.startMessagePolling();
5765
+ }
5766
+ });
5767
+ }
5768
+ startMessagePolling() {
5769
+ if (!this.sessionId || this.currentPollTaskId || !this.visible) {
5770
+ return;
5771
+ }
5772
+ if (this.messagePollingHandle) {
5773
+ return;
5774
+ }
5775
+ this.messagePollingHandle = this.getChatService().startMessagePolling(this.sessionId, {
5776
+ getSince: () => { var _a; return this.messages.length > 0 ? (_a = this.messages.at(-1)) === null || _a === void 0 ? void 0 : _a.created_at : undefined; },
5777
+ onMessages: (messages) => {
5778
+ if (messages.length === 0)
5779
+ return;
5780
+ this.messages = [...this.messages, ...messages];
5781
+ this.saveSessionToStorage();
5782
+ this.scrollToBottom();
5783
+ this.focusInput();
5784
+ },
5785
+ onError: () => {
5786
+ // Silently ignore polling errors to match previous behaviour
5787
+ }
5788
+ });
5789
+ }
5790
+ stopMessagePolling() {
5791
+ var _a;
5792
+ if (this.messagePollingHandle) {
5793
+ this.messagePollingHandle.stop();
5794
+ this.messagePollingHandle = undefined;
5795
+ }
5796
+ else {
5797
+ (_a = this.chatService) === null || _a === void 0 ? void 0 : _a.stopMessagePolling();
5138
5798
  }
5139
5799
  }
5140
5800
  setPosition(position) {
@@ -5155,7 +5815,6 @@ const OcsChat = class {
5155
5815
  const actualChatWidth = Math.min(windowWidth, this.chatWindowFullscreenWidth);
5156
5816
  const centeredX = (windowWidth - actualChatWidth) / 2;
5157
5817
  const maxOffset = (windowWidth - actualChatWidth) / 2;
5158
- console.log(windowWidth, actualChatWidth, centeredX, maxOffset);
5159
5818
  return { windowWidth, actualChatWidth, centeredX, maxOffset };
5160
5819
  }
5161
5820
  getPositionStyles() {
@@ -5277,25 +5936,181 @@ const OcsChat = class {
5277
5936
  document.removeEventListener('touchmove', this.handleTouchMove);
5278
5937
  document.removeEventListener('touchend', this.handleTouchEnd);
5279
5938
  }
5280
- getDefaultIconUrl() {
5281
- return `${this.getApiBaseUrl()}/static/images/favicons/favicon.svg`;
5939
+ // Button positioning and drag handlers
5940
+ initializeButtonPosition() {
5941
+ const computedStyle = getComputedStyle(this.host);
5942
+ const position = computedStyle.getPropertyValue('position');
5943
+ // Only enable dragging if the host element is positioned fixed
5944
+ if (position !== 'fixed') {
5945
+ return;
5946
+ }
5947
+ const rect = this.host.getBoundingClientRect();
5948
+ const windowWidth = window.innerWidth;
5949
+ const windowHeight = window.innerHeight;
5950
+ const left = computedStyle.getPropertyValue('left');
5951
+ const right = computedStyle.getPropertyValue('right');
5952
+ const top = computedStyle.getPropertyValue('top');
5953
+ const bottom = computedStyle.getPropertyValue('bottom');
5954
+ const hasLeft = !this.isAutoPosition(left);
5955
+ const hasTop = !this.isAutoPosition(top);
5956
+ this.buttonHorizontalSide = hasLeft ? 'left' : 'right';
5957
+ this.buttonVerticalSide = hasTop ? 'top' : 'bottom';
5958
+ const resolvedRight = this.getNumericPositionValue(right, Math.max(0, windowWidth - rect.right));
5959
+ const resolvedLeft = this.getNumericPositionValue(left, Math.max(0, rect.left));
5960
+ const resolvedBottom = this.getNumericPositionValue(bottom, Math.max(0, windowHeight - rect.bottom));
5961
+ const resolvedTop = this.getNumericPositionValue(top, Math.max(0, rect.top));
5962
+ const horizontalValue = this.buttonHorizontalSide === 'left' ? resolvedLeft : resolvedRight;
5963
+ const verticalValue = this.buttonVerticalSide === 'top' ? resolvedTop : resolvedBottom;
5964
+ this.buttonPosition = {
5965
+ x: horizontalValue,
5966
+ y: verticalValue
5967
+ };
5968
+ // Apply the position to the host
5969
+ this.updateHostPosition();
5970
+ }
5971
+ updateHostPosition() {
5972
+ this.host.style.position = 'fixed';
5973
+ if (this.buttonHorizontalSide === 'left') {
5974
+ this.host.style.left = `${this.buttonPosition.x}px`;
5975
+ this.host.style.right = 'auto';
5976
+ }
5977
+ else {
5978
+ this.host.style.right = `${this.buttonPosition.x}px`;
5979
+ this.host.style.left = 'auto';
5980
+ }
5981
+ if (this.buttonVerticalSide === 'top') {
5982
+ this.host.style.top = `${this.buttonPosition.y}px`;
5983
+ this.host.style.bottom = 'auto';
5984
+ }
5985
+ else {
5986
+ this.host.style.bottom = `${this.buttonPosition.y}px`;
5987
+ this.host.style.top = 'auto';
5988
+ }
5989
+ }
5990
+ isButtonDraggable() {
5991
+ const computedStyle = getComputedStyle(this.host);
5992
+ return computedStyle.getPropertyValue('position') === 'fixed';
5993
+ }
5994
+ updateButtonPosition(pointer) {
5995
+ var _a, _b;
5996
+ const windowWidth = window.innerWidth;
5997
+ const windowHeight = window.innerHeight;
5998
+ const buttonWidth = ((_a = this.buttonRef) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 60;
5999
+ const buttonHeight = ((_b = this.buttonRef) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
6000
+ const minPadding = 10;
6001
+ const candidateLeft = pointer.clientX - this.buttonDragOffset.x;
6002
+ const candidateTop = pointer.clientY - this.buttonDragOffset.y;
6003
+ const minLeft = minPadding;
6004
+ const maxLeft = windowWidth - buttonWidth - minPadding;
6005
+ const minTop = minPadding;
6006
+ const maxTop = windowHeight - buttonHeight - minPadding;
6007
+ const constrainedLeft = Math.max(minLeft, Math.min(candidateLeft, maxLeft));
6008
+ const constrainedTop = Math.max(minTop, Math.min(candidateTop, maxTop));
6009
+ const newHorizontalValue = this.buttonHorizontalSide === 'left'
6010
+ ? constrainedLeft
6011
+ : Math.max(minPadding, windowWidth - (constrainedLeft + buttonWidth));
6012
+ const newVerticalValue = this.buttonVerticalSide === 'top'
6013
+ ? constrainedTop
6014
+ : Math.max(minPadding, windowHeight - (constrainedTop + buttonHeight));
6015
+ if (newHorizontalValue !== this.buttonPosition.x || newVerticalValue !== this.buttonPosition.y) {
6016
+ this.buttonWasDragged = true;
6017
+ this.buttonPosition = { x: newHorizontalValue, y: newVerticalValue };
6018
+ if (this.rafId === null) {
6019
+ this.rafId = requestAnimationFrame(() => {
6020
+ this.updateHostPosition();
6021
+ this.rafId = null;
6022
+ });
6023
+ }
6024
+ }
6025
+ }
6026
+ addButtonEventListeners() {
6027
+ if (this.buttonListenersAttached) {
6028
+ return;
6029
+ }
6030
+ document.addEventListener('mousemove', this.handleButtonMouseMove);
6031
+ document.addEventListener('mouseup', this.handleButtonMouseUp);
6032
+ document.addEventListener('touchmove', this.handleButtonTouchMove, { passive: false });
6033
+ document.addEventListener('touchend', this.handleButtonTouchEnd);
6034
+ this.buttonListenersAttached = true;
6035
+ }
6036
+ removeButtonEventListeners() {
6037
+ if (!this.buttonListenersAttached) {
6038
+ return;
6039
+ }
6040
+ if (this.rafId !== null) {
6041
+ cancelAnimationFrame(this.rafId);
6042
+ this.rafId = null;
6043
+ }
6044
+ document.removeEventListener('mousemove', this.handleButtonMouseMove);
6045
+ document.removeEventListener('mouseup', this.handleButtonMouseUp);
6046
+ document.removeEventListener('touchmove', this.handleButtonTouchMove);
6047
+ document.removeEventListener('touchend', this.handleButtonTouchEnd);
6048
+ this.buttonListenersAttached = false;
6049
+ }
6050
+ isAutoPosition(value) {
6051
+ const trimmed = value.trim();
6052
+ return trimmed === '' || trimmed === 'auto';
6053
+ }
6054
+ parsePixelValue(value) {
6055
+ const trimmed = value.trim();
6056
+ if (trimmed === '' || trimmed === 'auto') {
6057
+ return null;
6058
+ }
6059
+ if (trimmed.endsWith('px')) {
6060
+ const parsed = parseFloat(trimmed);
6061
+ return Number.isFinite(parsed) ? parsed : null;
6062
+ }
6063
+ const numeric = Number(trimmed);
6064
+ if (Number.isFinite(numeric)) {
6065
+ return numeric;
6066
+ }
6067
+ return null;
6068
+ }
6069
+ getNumericPositionValue(value, fallback) {
6070
+ const parsed = this.parsePixelValue(value);
6071
+ if (parsed !== null) {
6072
+ return parsed;
6073
+ }
6074
+ return fallback;
6075
+ }
6076
+ getWelcomeMessages() {
6077
+ const translated = this.translationManager.getArray("content.welcomeMessages");
6078
+ return translated && translated.length > 0
6079
+ ? translated
6080
+ : this.parsedWelcomeMessages;
6081
+ }
6082
+ getStarterQuestions() {
6083
+ const translated = this.translationManager.getArray("content.starterQuestions");
6084
+ return translated && translated.length > 0
6085
+ ? translated
6086
+ : this.parsedStarterQuestions;
5282
6087
  }
5283
6088
  getButtonClasses() {
5284
- const hasText = this.buttonText && this.buttonText.trim();
6089
+ const buttonText = this.translationManager.get('branding.buttonText', this.buttonText);
6090
+ const hasText = !!(buttonText && buttonText.trim());
5285
6091
  const baseClass = hasText ? 'chat-btn-text' : 'chat-btn-icon';
5286
6092
  const shapeClass = this.buttonShape === 'round' ? 'round' : '';
5287
6093
  return `${baseClass} ${shapeClass}`.trim();
5288
6094
  }
5289
6095
  renderButton() {
5290
- const hasText = this.buttonText && this.buttonText.trim();
6096
+ var _a;
6097
+ const buttonText = this.translationManager.get('branding.buttonText', this.buttonText);
6098
+ const hasText = !!(buttonText && buttonText.trim());
5291
6099
  const hasCustomIcon = this.iconUrl && this.iconUrl.trim();
5292
- const iconSrc = hasCustomIcon ? this.iconUrl : this.getDefaultIconUrl();
5293
6100
  const buttonClasses = this.getButtonClasses();
6101
+ const finalButtonText = buttonText !== null && buttonText !== void 0 ? buttonText : '';
6102
+ const openLabel = (_a = this.translationManager.get('launcher.open')) !== null && _a !== void 0 ? _a : '';
6103
+ const buttonAriaLabel = finalButtonText ? `${openLabel} - ${finalButtonText}` : openLabel;
6104
+ // Only show drag cursor if button is draggable
6105
+ const isDraggable = this.isButtonDraggable();
6106
+ const buttonStyle = isDraggable ? {
6107
+ cursor: this.isButtonDragging ? 'grabbing' : 'grab',
6108
+ } : {};
5294
6109
  if (hasText) {
5295
- return (h("button", { class: buttonClasses, onClick: () => this.toggleWindowVisibility(), "aria-label": `Open chat - ${this.buttonText}`, title: this.buttonText }, h("img", { src: iconSrc, alt: "" }), h("span", null, this.buttonText)));
6110
+ return (h("button", { ref: (el) => this.buttonRef = el, class: buttonClasses, "aria-label": buttonAriaLabel, title: finalButtonText || openLabel, style: buttonStyle, onClick: () => this.handleButtonClick(), onMouseDown: (e) => this.handleButtonMouseDown(e), onTouchStart: (e) => this.handleButtonTouchStart(e), "aria-grabbed": this.isButtonDragging, "aria-describedby": isDraggable ? "chat-button-drag-hint" : undefined }, hasCustomIcon ? h("img", { src: this.iconUrl, alt: "" }) : h(OcsWidgetAvatar, null), h("span", null, finalButtonText), isDraggable && (h("span", { id: "chat-button-drag-hint", style: { display: 'none' } }, "Draggable. Use mouse or touch to reposition."))));
5296
6111
  }
5297
6112
  else {
5298
- return (h("button", { class: buttonClasses, onClick: () => this.toggleWindowVisibility(), "aria-label": "Open chat", title: "Open chat" }, h("img", { src: iconSrc, alt: "Chat" })));
6113
+ return (h("button", { ref: (el) => this.buttonRef = el, class: buttonClasses, "aria-label": openLabel, title: openLabel, style: buttonStyle, onClick: () => this.handleButtonClick(), onMouseDown: (e) => this.handleButtonMouseDown(e), onTouchStart: (e) => this.handleButtonTouchStart(e), "aria-grabbed": this.isButtonDragging, "aria-describedby": isDraggable ? "chat-button-drag-hint" : undefined }, hasCustomIcon ? h("img", { src: this.iconUrl, alt: "" }) : h(OcsWidgetAvatar, null), isDraggable && (h("span", { id: "chat-button-drag-hint", style: { display: 'none' } }, "Draggable. Use mouse or touch to reposition."))));
5299
6114
  }
5300
6115
  }
5301
6116
  getStorageKeys() {
@@ -5431,18 +6246,18 @@ const OcsChat = class {
5431
6246
  if (this.error && !this.sessionId) {
5432
6247
  return (h(Host, null, h("p", { class: "error-message" }, this.error)));
5433
6248
  }
5434
- return (h(Host, null, this.renderButton(), this.visible && (h("div", { ref: (el) => this.chatWindowRef = el, id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, h("div", { class: "drag-indicator" }, h("div", { class: "drag-dots header-button" }, h(GripDotsVerticalIcon, null))), h("div", { class: "header-text" }, this.headerText), h("div", { class: "header-buttons" }, this.messages.length > 0 && (h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title: "Start new chat", "aria-label": "Start new chat" }, h(PlusWithCircleIcon, null))), this.allowFullScreen && h("button", { class: "header-button fullscreen-button", onClick: () => this.toggleFullscreen(), title: this.isFullscreen ? "Exit fullscreen" : "Enter fullscreen", "aria-label": this.isFullscreen ? "Exit fullscreen" : "Enter fullscreen" }, this.isFullscreen ? h(ArrowsPointingInIcon, null) : h(ArrowsPointingOutIcon, null)), h("button", { class: "header-button", onClick: () => this.visible = false, "aria-label": "Close" }, h(XMarkIcon, null)))), this.showNewChatConfirmation && (h("div", { class: "confirmation-overlay" }, h("div", { class: "confirmation-dialog" }, h("div", { class: "confirmation-content" }, h("h3", { class: "confirmation-title" }, "Start New Chat"), h("p", { class: "confirmation-message" }, this.newChatConfirmationMessage), h("div", { class: "confirmation-buttons" }, h("button", { class: "confirmation-button confirmation-button-cancel", onClick: () => this.hideConfirmationDialog() }, "Cancel"), h("button", { class: "confirmation-button confirmation-button-confirm", onClick: () => this.confirmNewChat() }, "Continue")))))), h("div", { class: "chat-content" }, this.isLoading && !this.sessionId && (h("div", { class: "loading-container" }, h("div", { class: "loading-spinner" }), h("span", { class: "loading-text" }, "Starting chat..."))), (h("div", { ref: (el) => this.messageListRef = el, class: "messages-container" }, this.messages.length === 0 && this.parsedWelcomeMessages.length > 0 && (h("div", { class: "welcome-messages" }, this.parsedWelcomeMessages.map((message, index) => (h("div", { key: `welcome-${index}`, class: "message-row message-row-assistant" }, h("div", { class: "message-bubble message-bubble-assistant" }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(message) }))))))), this.messages.map((message, index) => (h("div", { key: index, class: `message-row ${message.role === 'user' ? 'message-row-user' : 'message-row-assistant'}` }, h("div", { class: `message-bubble ${message.role === 'user'
6249
+ return (h(Host, null, this.renderButton(), this.visible && (h("div", { ref: (el) => this.chatWindowRef = el, id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, h("div", { class: "drag-indicator" }, h("div", { class: "drag-dots header-button" }, h(GripDotsVerticalIcon, null))), h("div", { class: "header-text" }, this.translationManager.get('branding.headerText', this.headerText)), h("div", { class: "header-buttons" }, this.messages.length > 0 && (h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title: this.translationManager.get('window.newChat'), "aria-label": this.translationManager.get('window.newChat') }, h(PlusWithCircleIcon, null))), this.allowFullScreen && h("button", { class: "header-button fullscreen-button", onClick: () => this.toggleFullscreen(), title: this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen'), "aria-label": this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen') }, this.isFullscreen ? h(ArrowsPointingInIcon, null) : h(ArrowsPointingOutIcon, null)), h("button", { class: "header-button", onClick: () => this.visible = false, "aria-label": this.translationManager.get('window.close') }, h(XMarkIcon, null)))), this.showNewChatConfirmation && (h("div", { class: "confirmation-overlay" }, h("div", { class: "confirmation-dialog" }, h("div", { class: "confirmation-content" }, h("h3", { class: "confirmation-title" }, this.translationManager.get('modal.newChatTitle')), h("p", { class: "confirmation-message" }, this.translationManager.get('modal.newChatBody', this.newChatConfirmationMessage)), h("div", { class: "confirmation-buttons" }, h("button", { class: "confirmation-button confirmation-button-cancel", onClick: () => this.hideConfirmationDialog() }, this.translationManager.get('modal.cancel')), h("button", { class: "confirmation-button confirmation-button-confirm", onClick: () => this.confirmNewChat() }, this.translationManager.get('modal.confirm'))))))), h("div", { class: "chat-content" }, this.isLoading && !this.sessionId && (h("div", { class: "loading-container" }, h("div", { class: "loading-spinner" }), h("span", { class: "loading-text" }, this.translationManager.get('status.starting')))), (h("div", { ref: (el) => this.messageListRef = el, class: "messages-container" }, this.messages.length === 0 && this.parsedWelcomeMessages.length > 0 && (h("div", { class: "welcome-messages" }, this.getWelcomeMessages().map((message, index) => (h("div", { key: `welcome-${index}`, class: "message-row message-row-assistant" }, h("div", { class: "message-bubble message-bubble-assistant" }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(message) }))))))), this.messages.map((message, index) => (h("div", { key: index, class: `message-row ${message.role === 'user' ? 'message-row-user' : 'message-row-assistant'}` }, h("div", { class: `message-bubble ${message.role === 'user'
5435
6250
  ? 'message-bubble-user'
5436
6251
  : message.role === 'assistant'
5437
6252
  ? 'message-bubble-assistant'
5438
- : 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(message.content) }), message.attachments && message.attachments.length > 0 && (h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (h("div", { key: attachmentIndex, class: "flex items-center gap-[0.5em]" }, h("span", { class: "message-attachment-icon" }, h(PaperClipIcon, null)), h("span", { class: "message-attachment-name" }, attachment.name)))))), h("div", { class: "message-timestamp" }, this.formatTime(message.created_at)))))), this.isTyping && (h("div", null, h("div", { class: "typing-indicator" }, h("div", { class: "typing-progress" })), h("div", { class: "typing-text" }, h("span", null, this.typingIndicatorText), h("span", { class: "typing-dots" })))))), this.messages.length === 0 && this.parsedStarterQuestions.length > 0 && (h("div", { class: "starter-questions" }, this.parsedStarterQuestions.map((question, index) => (h("div", { key: `starter-${index}`, class: "starter-question-row" }, h("button", { class: "starter-question", onClick: () => this.handleStarterQuestionClick(question) }, question)))))), this.allowAttachments && this.selectedFiles.length > 0 && (h("div", { class: "selected-files-container" }, h("div", { class: "space-y-[0.25em]" }, this.selectedFiles.map((selectedFile, index) => (h("div", { key: index, class: "selected-file-item" }, h("div", { class: "flex items-center gap-[0.5em]" }, h("span", { class: "selected-file-icon" }, h(PaperClipIcon, null)), h("span", null, selectedFile.file.name), h("span", { class: "selected-file-size" }, "(", this.formatFileSize(selectedFile.file.size), ")"), selectedFile.error && (h("span", { class: "selected-file-error" }, selectedFile.error)), selectedFile.uploaded && (h("span", { class: "selected-file-success-icon" }, h(CheckDocumentIcon, null)))), h("button", { onClick: () => this.removeSelectedFile(index), class: "selected-file-remove-button", "aria-label": "Remove file" }, h(XIcon, null)))))))), this.sessionId && (h("div", { class: "input-area" }, h("div", { class: "input-container" }, h("textarea", { ref: (el) => this.textareaRef = el, class: "message-textarea", rows: 1, placeholder: "Type your message...", value: this.messageInput, onInput: (e) => this.handleInputChange(e), onKeyPress: (e) => this.handleKeyPress(e), disabled: this.isTyping || this.isUploadingFiles }), this.allowAttachments && (h("input", { ref: (el) => {
6253
+ : 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(message.content) }), message.attachments && message.attachments.length > 0 && (h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (h("div", { key: attachmentIndex, class: "flex items-center gap-[0.5em]" }, h("span", { class: "message-attachment-icon" }, h(PaperClipIcon, null)), h("span", { class: "message-attachment-name" }, attachment.name)))))), h("div", { class: "message-timestamp" }, this.formatTime(message.created_at)))))), this.isTyping && (h("div", null, h("div", { class: "typing-indicator" }, h("div", { class: "typing-progress" })), h("div", { class: "typing-text" }, h("span", null, this.translationManager.get('status.typing', this.typingIndicatorText)), h("span", { class: "typing-dots loading" })))))), this.messages.length === 0 && this.parsedStarterQuestions.length > 0 && (h("div", { class: "starter-questions" }, this.getStarterQuestions().map((question, index) => (h("div", { key: `starter-${index}`, class: "starter-question-row" }, h("button", { class: "starter-question", onClick: () => this.handleStarterQuestionClick(question) }, question)))))), this.allowAttachments && this.selectedFiles.length > 0 && (h("div", { class: "selected-files-container" }, h("div", { class: "space-y-[0.25em]" }, this.selectedFiles.map((selectedFile, index) => (h("div", { key: index, class: "selected-file-item" }, h("div", { class: "flex items-center gap-[0.5em]" }, h("span", { class: "selected-file-icon" }, h(PaperClipIcon, null)), h("span", null, selectedFile.file.name), h("span", { class: "selected-file-size" }, "(", this.formatFileSize(selectedFile.file.size), ")"), selectedFile.error && (h("span", { class: "selected-file-error" }, selectedFile.error)), selectedFile.uploaded && (h("span", { class: "selected-file-success-icon" }, h(CheckDocumentIcon, null)))), h("button", { onClick: () => this.removeSelectedFile(index), class: "selected-file-remove-button", "aria-label": this.translationManager.get('attach.remove') }, h(XIcon, null)))))))), this.sessionId && (h("div", { class: "input-area" }, h("div", { class: "input-container" }, h("textarea", { ref: (el) => this.textareaRef = el, class: "message-textarea", rows: 1, placeholder: this.translationManager.get('composer.placeholder'), value: this.messageInput, onInput: (e) => this.handleInputChange(e), onKeyPress: (e) => this.handleKeyPress(e), disabled: this.isTyping || this.isUploadingFiles }), this.allowAttachments && (h("input", { ref: (el) => {
5439
6254
  // Unclear why but after removing all attachments this is being set to `null`.
5440
6255
  if (el) {
5441
6256
  this.fileInputRef = el;
5442
6257
  }
5443
- }, id: "ocs-file-input", type: "file", multiple: true, accept: OcsChat.SUPPORTED_FILE_EXTENSIONS.join(','), onChange: (e) => this.handleFileSelect(e), class: "hidden" })), this.allowAttachments && (h("button", { class: "file-attachment-button", onClick: () => { var _a; return (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click(); }, disabled: this.isTyping || this.isUploadingFiles, title: "Attach files", "aria-label": "Attach files" }, h(PaperClipIcon, null))), h("button", { class: `send-button ${!this.isTyping && !!this.messageInput.trim()
6258
+ }, id: "ocs-file-input", type: "file", multiple: true, accept: OcsChat.SUPPORTED_FILE_EXTENSIONS.join(','), onChange: (e) => this.handleFileSelect(e), class: "hidden" })), this.allowAttachments && (h("button", { class: "file-attachment-button", onClick: () => { var _a; return (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click(); }, disabled: this.isTyping || this.isUploadingFiles, title: this.translationManager.get('attach.add'), "aria-label": this.translationManager.get('attach.add') }, h(PaperClipIcon, null))), h("button", { class: `send-button ${!this.isTyping && !!this.messageInput.trim()
5444
6259
  ? 'send-button-enabled'
5445
- : 'send-button-disabled'}`, onClick: () => this.sendMessage(this.messageInput), disabled: this.isTyping || this.isUploadingFiles || !this.messageInput.trim() }, this.isUploadingFiles ? 'Uploading...' : 'Send')))), h("div", { class: "flex items-center justify-center text-[0.8em] font-light w-full text-slate-500 py-[2px]" }, h("p", null, "Powered by ", h("a", { class: "underline", href: "https://www.dimagi.com", target: "_blank" }, "Dimagi"))))))));
6260
+ : 'send-button-disabled'}`, onClick: () => this.sendMessage(this.messageInput), disabled: this.isTyping || this.isUploadingFiles || !this.messageInput.trim() }, this.isUploadingFiles ? `${this.translationManager.get('status.uploading')}...` : this.translationManager.get('composer.send'))))), h("div", { class: "flex items-center justify-center text-[0.8em] font-light w-full text-slate-500 py-[2px]" }, h("p", null, this.translationManager.get('branding.poweredBy'), ' ', " ", h("a", { class: "underline", href: "https://www.dimagi.com", target: "_blank" }, "Dimagi"))))))));
5446
6261
  }
5447
6262
  get host() { return getElement(this); }
5448
6263
  static get watchers() { return {