open-chat-studio-widget 0.4.8 → 0.5.1

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-Du0PBL6n.js} +4 -2
  3. package/dist/cjs/index-Du0PBL6n.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-CX3v6rTy.js} +4 -3
  27. package/dist/esm/index-CX3v6rTy.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-90719a8b.entry.js +4 -0
  35. package/dist/open-chat-studio-widget/p-90719a8b.entry.js.map +1 -0
  36. package/dist/open-chat-studio-widget/p-CX3v6rTy.js +3 -0
  37. package/dist/open-chat-studio-widget/p-CX3v6rTy.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, proxyCustomElement, HTMLElement, Host } from '@stencil/core/internal/client';
2
-
1
+ import { h, proxyCustomElement, HTMLElement, Env, Host } from '@stencil/core/internal/client';
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,54 +4889,286 @@ 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 = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLElement {
4507
5174
  constructor() {
@@ -4509,17 +5176,13 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
4509
5176
  this.__registerHost();
4510
5177
  this.__attachShadow();
4511
5178
  /**
4512
- * The base URL for the API (defaults to current origin).
5179
+ * The base URL for the API.
4513
5180
  */
4514
- this.apiBaseUrl = "https://chatbots.dimagi.com";
5181
+ this.apiBaseUrl = "https://www.openchatstudio.com";
4515
5182
  /**
4516
5183
  * The shape of the chat button. 'round' makes it circular, 'square' keeps it rectangular.
4517
5184
  */
4518
5185
  this.buttonShape = 'square';
4519
- /**
4520
- * The message to display in the new chat confirmation dialog.
4521
- */
4522
- this.newChatConfirmationMessage = "Starting a new chat will clear your current conversation. Continue?";
4523
5186
  /**
4524
5187
  * Whether the chat widget is visible on load.
4525
5188
  */
@@ -4545,10 +5208,6 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
4545
5208
  * Allow the user to attach files to their messages.
4546
5209
  */
4547
5210
  this.allowAttachments = false;
4548
- /**
4549
- * The text to display while the assistant is typing/preparing a response.
4550
- */
4551
- this.typingIndicatorText = "Preparing response";
4552
5211
  this.error = "";
4553
5212
  this.messages = [];
4554
5213
  this.isLoading = false;
@@ -4565,6 +5224,20 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
4565
5224
  this.showNewChatConfirmation = false;
4566
5225
  this.selectedFiles = [];
4567
5226
  this.isUploadingFiles = false;
5227
+ this.buttonPosition = { x: 30, y: 30 };
5228
+ this.buttonHorizontalSide = 'right';
5229
+ this.buttonVerticalSide = 'bottom';
5230
+ this.isButtonDragging = false;
5231
+ this.buttonWasDragged = false;
5232
+ this.translationManager = new TranslationManager();
5233
+ this.attachmentManager = new FileAttachmentManager({
5234
+ supportedExtensions: OcsChat.SUPPORTED_FILE_EXTENSIONS,
5235
+ maxFileSizeMb: OcsChat.MAX_FILE_SIZE_MB,
5236
+ maxTotalSizeMb: OcsChat.MAX_TOTAL_SIZE_MB,
5237
+ });
5238
+ this.buttonDragOffset = { x: 0, y: 0 };
5239
+ this.rafId = null;
5240
+ this.buttonListenersAttached = false;
4568
5241
  this.chatWindowHeight = 600;
4569
5242
  this.chatWindowWidth = 450;
4570
5243
  this.chatWindowFullscreenWidth = 1024;
@@ -4613,15 +5286,101 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
4613
5286
  this.endDrag();
4614
5287
  };
4615
5288
  this.handleWindowResize = () => {
5289
+ var _a, _b;
4616
5290
  this.positionInitialized = false;
4617
5291
  this.initializePosition();
5292
+ // Revalidate button position after resize to keep it within viewport bounds
5293
+ if (this.isButtonDraggable()) {
5294
+ const windowWidth = window.innerWidth;
5295
+ const windowHeight = window.innerHeight;
5296
+ const buttonWidth = ((_a = this.buttonRef) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 60;
5297
+ const buttonHeight = ((_b = this.buttonRef) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
5298
+ const minPadding = 10;
5299
+ this.buttonPosition = {
5300
+ x: Math.max(minPadding, Math.min(this.buttonPosition.x, windowWidth - buttonWidth - minPadding)),
5301
+ y: Math.max(minPadding, Math.min(this.buttonPosition.y, windowHeight - buttonHeight - minPadding))
5302
+ };
5303
+ this.updateHostPosition();
5304
+ }
5305
+ };
5306
+ this.handleButtonMouseDown = (event) => {
5307
+ if (!this.buttonRef || !this.isButtonDraggable())
5308
+ return;
5309
+ event.preventDefault();
5310
+ event.stopPropagation();
5311
+ const pointer = this.getPointerCoordinates(event);
5312
+ if (!pointer)
5313
+ return;
5314
+ this.isButtonDragging = true;
5315
+ this.buttonWasDragged = false; // Reset the drag flag
5316
+ const rect = this.host.getBoundingClientRect();
5317
+ this.buttonDragOffset = {
5318
+ x: pointer.clientX - rect.left,
5319
+ y: pointer.clientY - rect.top
5320
+ };
5321
+ this.addButtonEventListeners();
5322
+ };
5323
+ this.handleButtonTouchStart = (event) => {
5324
+ if (!this.buttonRef || !this.isButtonDraggable())
5325
+ return;
5326
+ event.preventDefault();
5327
+ event.stopPropagation();
5328
+ const pointer = this.getPointerCoordinates(event);
5329
+ if (!pointer)
5330
+ return;
5331
+ this.isButtonDragging = true;
5332
+ this.buttonWasDragged = false; // Reset the drag flag
5333
+ const rect = this.host.getBoundingClientRect();
5334
+ this.buttonDragOffset = {
5335
+ x: pointer.clientX - rect.left,
5336
+ y: pointer.clientY - rect.top
5337
+ };
5338
+ this.addButtonEventListeners();
5339
+ };
5340
+ this.handleButtonMouseMove = (event) => {
5341
+ if (!this.isButtonDragging)
5342
+ return;
5343
+ const pointer = this.getPointerCoordinates(event);
5344
+ if (!pointer)
5345
+ return;
5346
+ this.updateButtonPosition(pointer);
5347
+ };
5348
+ this.handleButtonTouchMove = (event) => {
5349
+ if (!this.isButtonDragging)
5350
+ return;
5351
+ event.preventDefault();
5352
+ const pointer = this.getPointerCoordinates(event);
5353
+ if (!pointer)
5354
+ return;
5355
+ this.updateButtonPosition(pointer);
5356
+ };
5357
+ this.handleButtonMouseUp = () => {
5358
+ if (this.isButtonDragging) {
5359
+ this.isButtonDragging = false;
5360
+ this.removeButtonEventListeners();
5361
+ }
5362
+ };
5363
+ this.handleButtonTouchEnd = () => {
5364
+ if (this.isButtonDragging) {
5365
+ this.isButtonDragging = false;
5366
+ this.removeButtonEventListeners();
5367
+ }
5368
+ };
5369
+ this.handleButtonClick = () => {
5370
+ // Only toggle visibility if the button wasn't dragged
5371
+ if (!this.buttonWasDragged) {
5372
+ this.toggleWindowVisibility();
5373
+ }
5374
+ // Reset the flag after handling the click
5375
+ this.buttonWasDragged = false;
4618
5376
  };
4619
5377
  }
4620
- componentWillLoad() {
5378
+ async componentWillLoad() {
4621
5379
  if (!this.chatbotId) {
4622
5380
  this.error = 'Chatbot ID is required';
4623
5381
  return;
4624
5382
  }
5383
+ await this.initializeTranslations();
4625
5384
  // Always try to load existing session if localStorage is available
4626
5385
  if (this.persistentSession && this.isLocalStorageAvailable()) {
4627
5386
  const { sessionId, messages } = this.loadSessionFromStorage();
@@ -4641,6 +5400,8 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
4641
5400
  this.chatWindowHeight = varToPixels(windowHeightVar, window.innerHeight, this.chatWindowHeight);
4642
5401
  this.chatWindowWidth = varToPixels(windowWidthVar, window.innerWidth, this.chatWindowWidth);
4643
5402
  this.chatWindowFullscreenWidth = varToPixels(fullscreenWidthVar, window.innerWidth, this.chatWindowFullscreenWidth);
5403
+ // Initialize button position from computed styles
5404
+ this.initializeButtonPosition();
4644
5405
  if (this.visible) {
4645
5406
  this.initializePosition();
4646
5407
  }
@@ -4650,15 +5411,29 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
4650
5411
  }
4651
5412
  else if (this.visible && this.sessionId) {
4652
5413
  // Resume polling for existing session
4653
- this.startPolling();
5414
+ this.startMessagePolling();
4654
5415
  }
4655
5416
  window.addEventListener('resize', this.handleWindowResize);
4656
5417
  }
4657
5418
  disconnectedCallback() {
4658
5419
  this.cleanup();
4659
5420
  this.removeEventListeners();
5421
+ this.removeButtonEventListeners();
4660
5422
  window.removeEventListener('resize', this.handleWindowResize);
4661
5423
  }
5424
+ getChatService() {
5425
+ if (!this.chatService) {
5426
+ this.chatService = new ChatSessionService({
5427
+ apiBaseUrl: this.apiBaseUrl || 'https://www.openchatstudio.com',
5428
+ embedKey: this.embedKey,
5429
+ widgetVersion: Env.version,
5430
+ taskPollingIntervalMs: OcsChat.TASK_POLLING_INTERVAL_MS,
5431
+ taskPollingMaxAttempts: OcsChat.TASK_POLLING_MAX_ATTEMPTS,
5432
+ messagePollingIntervalMs: OcsChat.MESSAGE_POLLING_INTERVAL_MS,
5433
+ });
5434
+ }
5435
+ return this.chatService;
5436
+ }
4662
5437
  addErrorMessage(errorText) {
4663
5438
  const errorMessage = {
4664
5439
  created_at: new Date().toISOString(),
@@ -4702,25 +5477,34 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
4702
5477
  parseStarterQuestions() {
4703
5478
  this.parsedStarterQuestions = this.parseJSONProp(this.starterQuestions, 'starter questions');
4704
5479
  }
4705
- cleanup() {
4706
- if (this.pollingIntervalRef) {
4707
- clearInterval(this.pollingIntervalRef);
4708
- this.pollingIntervalRef = undefined;
5480
+ async initializeTranslations() {
5481
+ let customTranslationsObj;
5482
+ if (this.translationsUrl) {
5483
+ customTranslationsObj = await this.loadTranslationsFromUrl(this.translationsUrl);
4709
5484
  }
4710
- this.currentPollTaskId = '';
5485
+ this.translationManager = new TranslationManager(this.language, customTranslationsObj);
4711
5486
  }
4712
- getApiBaseUrl() {
4713
- return this.apiBaseUrl || window.location.origin;
5487
+ async loadTranslationsFromUrl(url) {
5488
+ try {
5489
+ const response = await fetch(url);
5490
+ if (!response.ok) {
5491
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5492
+ }
5493
+ const translations = await response.json();
5494
+ return translations;
5495
+ }
5496
+ catch (error) {
5497
+ console.error('Error loading translations from URL:', error);
5498
+ return defaultTranslations;
5499
+ }
4714
5500
  }
4715
- getApiHeaders() {
4716
- const headers = {
4717
- 'Content-Type': 'application/json',
4718
- };
4719
- const csrfToken = getCSRFToken(this.getApiBaseUrl());
4720
- if (csrfToken) {
4721
- headers['X-CSRFToken'] = csrfToken;
5501
+ cleanup() {
5502
+ this.stopMessagePolling();
5503
+ if (this.taskPollingHandle) {
5504
+ this.taskPollingHandle.cancel();
5505
+ this.taskPollingHandle = undefined;
4722
5506
  }
4723
- return headers;
5507
+ this.currentPollTaskId = '';
4724
5508
  }
4725
5509
  async startSession() {
4726
5510
  try {
@@ -4737,94 +5521,38 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
4737
5521
  if (this.userName) {
4738
5522
  requestBody.participant_name = this.userName;
4739
5523
  }
4740
- const response = await fetch(`${this.getApiBaseUrl()}/api/chat/start/`, {
4741
- method: 'POST',
4742
- headers: this.getApiHeaders(),
4743
- body: JSON.stringify(requestBody)
4744
- });
4745
- if (!response.ok) {
4746
- this.handleError(`Failed to start session: ${response.statusText}`);
4747
- return;
4748
- }
4749
- const data = await response.json();
5524
+ const data = await this.getChatService().startSession(requestBody);
4750
5525
  this.sessionId = data.session_id;
4751
5526
  this.saveSessionToStorage();
4752
5527
  // Handle seed message if present
4753
5528
  if (data.seed_message_task_id) {
4754
- this.isTyping = true; // Show typing indicator for seed message
4755
- this.currentPollTaskId = data.seed_message_task_id;
4756
- await this.pollTaskResponse();
5529
+ this.startTaskPolling(data.seed_message_task_id);
5530
+ }
5531
+ else {
5532
+ this.startMessagePolling();
4757
5533
  }
4758
- // Start polling for messages
4759
- this.startPolling();
4760
5534
  }
4761
- catch (error) {
5535
+ catch (_error) {
4762
5536
  this.handleError('Failed to start chat session');
4763
5537
  }
4764
5538
  finally {
4765
5539
  this.isLoading = false;
4766
5540
  }
4767
5541
  }
4768
- markPendingFilesWithError(errorMessage) {
4769
- this.selectedFiles = this.selectedFiles.map(sf => {
4770
- if (!sf.error && !sf.uploaded) {
4771
- return Object.assign(Object.assign({}, sf), { error: errorMessage });
4772
- }
4773
- return sf;
4774
- });
4775
- }
4776
5542
  async uploadFiles() {
4777
5543
  if (this.selectedFiles.length === 0 || !this.sessionId || !this.allowAttachments) {
4778
5544
  return [];
4779
5545
  }
4780
5546
  this.isUploadingFiles = true;
4781
- const uploadedIds = [];
4782
5547
  try {
4783
- const formData = new FormData();
4784
- // Add all files to form data
4785
- for (const selectedFile of this.selectedFiles) {
4786
- if (!selectedFile.error && !selectedFile.uploaded) {
4787
- formData.append('files', selectedFile.file);
4788
- }
4789
- else if (selectedFile.uploaded) {
4790
- uploadedIds.push(selectedFile.uploaded.id);
4791
- }
4792
- }
4793
- // Add user ID and name to the form data
4794
- const userId = this.getOrGenerateUserId();
4795
- formData.append('participant_remote_id', userId);
4796
- if (this.userName) {
4797
- formData.append('participant_name', this.userName);
4798
- }
4799
- // Only upload if there are new files
4800
- if (formData.has('files')) {
4801
- const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/upload/`, {
4802
- method: 'POST',
4803
- body: formData,
4804
- });
4805
- if (!response.ok) {
4806
- const errorData = await response.json();
4807
- const errorMessage = errorData.error || 'Failed to upload files';
4808
- this.markPendingFilesWithError(errorMessage);
4809
- return uploadedIds;
4810
- }
4811
- const data = await response.json();
4812
- // Update selected files with upload results
4813
- let fileIndex = 0;
4814
- this.selectedFiles = this.selectedFiles.map(sf => {
4815
- if (!sf.error && !sf.uploaded) {
4816
- return Object.assign(Object.assign({}, sf), { uploaded: data.files[fileIndex++] });
4817
- }
4818
- return sf;
4819
- });
4820
- uploadedIds.push(...data.files.map((f) => f.id));
4821
- }
4822
- return uploadedIds;
4823
- }
4824
- catch (error) {
4825
- const errorMessage = error instanceof Error ? error.message : 'Failed to upload files';
4826
- this.markPendingFilesWithError(errorMessage);
4827
- return uploadedIds;
5548
+ const uploadResult = await this.attachmentManager.uploadPendingFiles(this.selectedFiles, {
5549
+ apiBaseUrl: this.apiBaseUrl || 'https://www.openchatstudio.com',
5550
+ sessionId: this.sessionId,
5551
+ participantId: this.getOrGenerateUserId(),
5552
+ participantName: this.userName,
5553
+ });
5554
+ this.selectedFiles = uploadResult.selectedFiles;
5555
+ return uploadResult.uploadedIds;
4828
5556
  }
4829
5557
  finally {
4830
5558
  this.isUploadingFiles = false;
@@ -4877,27 +5605,15 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
4877
5605
  this.selectedFiles = []; // Clear selected files after sending
4878
5606
  }
4879
5607
  this.scrollToBottom();
4880
- // Start typing indicator - it will stay on during task polling
4881
- this.isTyping = true;
4882
5608
  const requestBody = { message: message.trim() };
4883
5609
  if (this.allowAttachments && attachmentIds.length > 0) {
4884
5610
  requestBody.attachment_ids = attachmentIds;
4885
5611
  }
4886
- const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/message/`, {
4887
- method: 'POST',
4888
- headers: this.getApiHeaders(),
4889
- body: JSON.stringify(requestBody)
4890
- });
4891
- if (!response.ok) {
4892
- throw new Error(`Failed to send message: ${response.statusText}`);
4893
- }
4894
- const data = await response.json();
5612
+ const data = await this.getChatService().sendMessage(this.sessionId, requestBody);
4895
5613
  if (data.status === 'error') {
4896
5614
  throw new Error(data.error || 'Failed to send message');
4897
5615
  }
4898
- // Poll for the response - typing indicator will be managed in pollTaskResponse
4899
- this.currentPollTaskId = data.task_id;
4900
- await this.pollTaskResponse();
5616
+ this.startTaskPolling(data.task_id);
4901
5617
  }
4902
5618
  catch (error) {
4903
5619
  const errorText = error instanceof Error ? error.message : 'Failed to send message';
@@ -4907,110 +5623,6 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
4907
5623
  handleStarterQuestionClick(question) {
4908
5624
  this.sendMessage(question);
4909
5625
  }
4910
- async pollTaskResponse() {
4911
- if (!this.sessionId || !this.currentPollTaskId)
4912
- return;
4913
- // Stop message polling while task polling is active
4914
- this.pauseMessagePolling();
4915
- let attempts = 0;
4916
- const poll = async () => {
4917
- if (!this.sessionId || !this.currentPollTaskId)
4918
- return;
4919
- try {
4920
- const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/${this.currentPollTaskId}/poll/`);
4921
- if (!response.ok) {
4922
- throw new Error(`Failed to poll task: ${response.statusText}`);
4923
- }
4924
- const data = await response.json();
4925
- if (data.error) {
4926
- throw new Error(data.error);
4927
- }
4928
- if (data.status === 'complete' && data.message) {
4929
- this.messages = [...this.messages, data.message];
4930
- this.saveSessionToStorage();
4931
- this.scrollToBottom();
4932
- // Task polling complete, clear typing indicator and resume message polling
4933
- this.isTyping = false;
4934
- this.currentPollTaskId = '';
4935
- this.resumeMessagePolling();
4936
- this.focusInput();
4937
- return;
4938
- }
4939
- if (data.status === 'processing' && attempts < OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
4940
- attempts++;
4941
- setTimeout(poll, OcsChat.TASK_POLLING_INTERVAL_MS);
4942
- }
4943
- else if (attempts >= OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
4944
- // Task polling timed out - add timeout message and resume polling
4945
- const timeoutMessage = {
4946
- created_at: new Date().toISOString(),
4947
- role: 'system',
4948
- content: 'The response is taking longer than expected. The system may be experiencing delays. Please try sending your message again.',
4949
- attachments: []
4950
- };
4951
- this.messages = [...this.messages, timeoutMessage];
4952
- this.saveSessionToStorage();
4953
- this.scrollToBottom();
4954
- // Clear typing indicator and resume message polling
4955
- this.isTyping = false;
4956
- this.currentPollTaskId = '';
4957
- this.resumeMessagePolling();
4958
- this.focusInput();
4959
- }
4960
- }
4961
- catch (error) {
4962
- const errorText = error instanceof Error ? error.message : 'Failed to get response';
4963
- this.handleError(errorText);
4964
- // Clear states and resume polling
4965
- this.currentPollTaskId = '';
4966
- this.resumeMessagePolling();
4967
- }
4968
- };
4969
- await poll();
4970
- }
4971
- startPolling() {
4972
- if (this.pollingIntervalRef)
4973
- return;
4974
- this.pollingIntervalRef = setInterval(async () => {
4975
- // Only poll for messages if not currently polling for a task
4976
- if (!this.currentPollTaskId) {
4977
- await this.pollForMessages();
4978
- }
4979
- }, OcsChat.MESSAGE_POLLING_INTERVAL_MS);
4980
- }
4981
- pauseMessagePolling() {
4982
- if (this.pollingIntervalRef) {
4983
- clearInterval(this.pollingIntervalRef);
4984
- this.pollingIntervalRef = undefined;
4985
- }
4986
- }
4987
- resumeMessagePolling() {
4988
- // Resume message polling after task polling is complete
4989
- this.startPolling();
4990
- }
4991
- async pollForMessages() {
4992
- if (!this.sessionId)
4993
- return;
4994
- try {
4995
- const url = new URL(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/poll/`);
4996
- if (this.messages && this.messages.length > 0) {
4997
- url.searchParams.set('since', this.messages.at(-1).created_at);
4998
- }
4999
- const response = await fetch(url.toString());
5000
- if (!response.ok)
5001
- return; // Silently fail for polling
5002
- const data = await response.json();
5003
- if (data.messages.length > 0) {
5004
- this.messages = [...this.messages, ...data.messages];
5005
- this.saveSessionToStorage();
5006
- this.scrollToBottom();
5007
- this.focusInput();
5008
- }
5009
- }
5010
- catch (_a) {
5011
- // Silently fail for polling
5012
- }
5013
- }
5014
5626
  /**
5015
5627
  * Scroll the message container to the bottom.
5016
5628
  * @param forceEnd When `false`, scroll the top of the last message into view.
@@ -5055,50 +5667,18 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
5055
5667
  this.messageInput = event.target.value;
5056
5668
  }
5057
5669
  handleFileSelect(event) {
5058
- var _a;
5059
5670
  if (!this.allowAttachments)
5060
5671
  return;
5061
5672
  const input = event.target;
5062
5673
  if (!input.files || input.files.length === 0)
5063
5674
  return;
5064
- const newFiles = [];
5065
- let totalSize = this.selectedFiles.reduce((sum, f) => sum + f.file.size, 0);
5066
- for (let i = 0; i < input.files.length; i++) {
5067
- const file = input.files[i];
5068
- const ext = '.' + ((_a = file.name.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase());
5069
- if (!OcsChat.SUPPORTED_FILE_EXTENSIONS.includes(ext)) {
5070
- newFiles.push({
5071
- file,
5072
- error: `File type ${ext} not supported`
5073
- });
5074
- continue;
5075
- }
5076
- const fileSizeMB = file.size / (1024 * 1024);
5077
- if (fileSizeMB > OcsChat.MAX_FILE_SIZE_MB) {
5078
- newFiles.push({
5079
- file,
5080
- error: `File exceeds ${OcsChat.MAX_FILE_SIZE_MB}MB limit`
5081
- });
5082
- continue;
5083
- }
5084
- totalSize += file.size;
5085
- const totalSizeMB = totalSize / (1024 * 1024);
5086
- if (totalSizeMB > OcsChat.MAX_TOTAL_SIZE_MB) {
5087
- newFiles.push({
5088
- file,
5089
- error: `Total size exceeds ${OcsChat.MAX_TOTAL_SIZE_MB}MB limit`
5090
- });
5091
- continue;
5092
- }
5093
- newFiles.push({ file });
5094
- }
5095
- this.selectedFiles = [...this.selectedFiles, ...newFiles];
5675
+ this.selectedFiles = this.attachmentManager.addFiles(this.selectedFiles, input.files);
5096
5676
  input.value = '';
5097
5677
  }
5098
5678
  removeSelectedFile(index) {
5099
5679
  if (!this.allowAttachments)
5100
5680
  return;
5101
- this.selectedFiles = this.selectedFiles.filter((_, i) => i !== index);
5681
+ this.selectedFiles = this.attachmentManager.removeFile(this.selectedFiles, index);
5102
5682
  }
5103
5683
  formatFileSize(bytes) {
5104
5684
  if (bytes === 0)
@@ -5125,6 +5705,11 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
5125
5705
  * @param visible - The new value for the field.
5126
5706
  */
5127
5707
  async visibilityHandler(visible) {
5708
+ if (this.isButtonDragging) {
5709
+ this.isButtonDragging = false;
5710
+ this.buttonWasDragged = false;
5711
+ this.removeButtonEventListeners();
5712
+ }
5128
5713
  if (visible) {
5129
5714
  this.initializePosition();
5130
5715
  }
@@ -5132,11 +5717,86 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
5132
5717
  await this.startSession();
5133
5718
  }
5134
5719
  else if (!visible) {
5135
- this.pauseMessagePolling();
5720
+ this.stopMessagePolling();
5136
5721
  }
5137
5722
  else {
5138
5723
  this.scrollToBottom(true);
5139
- this.resumeMessagePolling();
5724
+ this.startMessagePolling();
5725
+ }
5726
+ }
5727
+ startTaskPolling(taskId) {
5728
+ if (!this.sessionId)
5729
+ return;
5730
+ this.currentPollTaskId = taskId;
5731
+ this.isTyping = true;
5732
+ this.stopMessagePolling();
5733
+ if (this.taskPollingHandle) {
5734
+ this.taskPollingHandle.cancel();
5735
+ }
5736
+ this.taskPollingHandle = this.getChatService().pollTask(this.sessionId, taskId, {
5737
+ onMessage: (message) => {
5738
+ this.messages = [...this.messages, message];
5739
+ this.saveSessionToStorage();
5740
+ this.scrollToBottom();
5741
+ this.isTyping = false;
5742
+ this.currentPollTaskId = '';
5743
+ this.taskPollingHandle = undefined;
5744
+ this.startMessagePolling();
5745
+ this.focusInput();
5746
+ },
5747
+ onTimeout: () => {
5748
+ const timeoutMessage = {
5749
+ created_at: new Date().toISOString(),
5750
+ role: 'system',
5751
+ content: 'The response is taking longer than expected. The system may be experiencing delays. Please try sending your message again.',
5752
+ attachments: []
5753
+ };
5754
+ this.messages = [...this.messages, timeoutMessage];
5755
+ this.saveSessionToStorage();
5756
+ this.scrollToBottom();
5757
+ this.isTyping = false;
5758
+ this.currentPollTaskId = '';
5759
+ this.taskPollingHandle = undefined;
5760
+ this.startMessagePolling();
5761
+ this.focusInput();
5762
+ },
5763
+ onError: (error) => {
5764
+ this.handleError(error.message);
5765
+ this.taskPollingHandle = undefined;
5766
+ this.startMessagePolling();
5767
+ }
5768
+ });
5769
+ }
5770
+ startMessagePolling() {
5771
+ if (!this.sessionId || this.currentPollTaskId || !this.visible) {
5772
+ return;
5773
+ }
5774
+ if (this.messagePollingHandle) {
5775
+ return;
5776
+ }
5777
+ this.messagePollingHandle = this.getChatService().startMessagePolling(this.sessionId, {
5778
+ getSince: () => { var _a; return this.messages.length > 0 ? (_a = this.messages.at(-1)) === null || _a === void 0 ? void 0 : _a.created_at : undefined; },
5779
+ onMessages: (messages) => {
5780
+ if (messages.length === 0)
5781
+ return;
5782
+ this.messages = [...this.messages, ...messages];
5783
+ this.saveSessionToStorage();
5784
+ this.scrollToBottom();
5785
+ this.focusInput();
5786
+ },
5787
+ onError: () => {
5788
+ // Silently ignore polling errors to match previous behaviour
5789
+ }
5790
+ });
5791
+ }
5792
+ stopMessagePolling() {
5793
+ var _a;
5794
+ if (this.messagePollingHandle) {
5795
+ this.messagePollingHandle.stop();
5796
+ this.messagePollingHandle = undefined;
5797
+ }
5798
+ else {
5799
+ (_a = this.chatService) === null || _a === void 0 ? void 0 : _a.stopMessagePolling();
5140
5800
  }
5141
5801
  }
5142
5802
  setPosition(position) {
@@ -5157,7 +5817,6 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
5157
5817
  const actualChatWidth = Math.min(windowWidth, this.chatWindowFullscreenWidth);
5158
5818
  const centeredX = (windowWidth - actualChatWidth) / 2;
5159
5819
  const maxOffset = (windowWidth - actualChatWidth) / 2;
5160
- console.log(windowWidth, actualChatWidth, centeredX, maxOffset);
5161
5820
  return { windowWidth, actualChatWidth, centeredX, maxOffset };
5162
5821
  }
5163
5822
  getPositionStyles() {
@@ -5279,25 +5938,181 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
5279
5938
  document.removeEventListener('touchmove', this.handleTouchMove);
5280
5939
  document.removeEventListener('touchend', this.handleTouchEnd);
5281
5940
  }
5282
- getDefaultIconUrl() {
5283
- return `${this.getApiBaseUrl()}/static/images/favicons/favicon.svg`;
5941
+ // Button positioning and drag handlers
5942
+ initializeButtonPosition() {
5943
+ const computedStyle = getComputedStyle(this.host);
5944
+ const position = computedStyle.getPropertyValue('position');
5945
+ // Only enable dragging if the host element is positioned fixed
5946
+ if (position !== 'fixed') {
5947
+ return;
5948
+ }
5949
+ const rect = this.host.getBoundingClientRect();
5950
+ const windowWidth = window.innerWidth;
5951
+ const windowHeight = window.innerHeight;
5952
+ const left = computedStyle.getPropertyValue('left');
5953
+ const right = computedStyle.getPropertyValue('right');
5954
+ const top = computedStyle.getPropertyValue('top');
5955
+ const bottom = computedStyle.getPropertyValue('bottom');
5956
+ const hasLeft = !this.isAutoPosition(left);
5957
+ const hasTop = !this.isAutoPosition(top);
5958
+ this.buttonHorizontalSide = hasLeft ? 'left' : 'right';
5959
+ this.buttonVerticalSide = hasTop ? 'top' : 'bottom';
5960
+ const resolvedRight = this.getNumericPositionValue(right, Math.max(0, windowWidth - rect.right));
5961
+ const resolvedLeft = this.getNumericPositionValue(left, Math.max(0, rect.left));
5962
+ const resolvedBottom = this.getNumericPositionValue(bottom, Math.max(0, windowHeight - rect.bottom));
5963
+ const resolvedTop = this.getNumericPositionValue(top, Math.max(0, rect.top));
5964
+ const horizontalValue = this.buttonHorizontalSide === 'left' ? resolvedLeft : resolvedRight;
5965
+ const verticalValue = this.buttonVerticalSide === 'top' ? resolvedTop : resolvedBottom;
5966
+ this.buttonPosition = {
5967
+ x: horizontalValue,
5968
+ y: verticalValue
5969
+ };
5970
+ // Apply the position to the host
5971
+ this.updateHostPosition();
5972
+ }
5973
+ updateHostPosition() {
5974
+ this.host.style.position = 'fixed';
5975
+ if (this.buttonHorizontalSide === 'left') {
5976
+ this.host.style.left = `${this.buttonPosition.x}px`;
5977
+ this.host.style.right = 'auto';
5978
+ }
5979
+ else {
5980
+ this.host.style.right = `${this.buttonPosition.x}px`;
5981
+ this.host.style.left = 'auto';
5982
+ }
5983
+ if (this.buttonVerticalSide === 'top') {
5984
+ this.host.style.top = `${this.buttonPosition.y}px`;
5985
+ this.host.style.bottom = 'auto';
5986
+ }
5987
+ else {
5988
+ this.host.style.bottom = `${this.buttonPosition.y}px`;
5989
+ this.host.style.top = 'auto';
5990
+ }
5991
+ }
5992
+ isButtonDraggable() {
5993
+ const computedStyle = getComputedStyle(this.host);
5994
+ return computedStyle.getPropertyValue('position') === 'fixed';
5995
+ }
5996
+ updateButtonPosition(pointer) {
5997
+ var _a, _b;
5998
+ const windowWidth = window.innerWidth;
5999
+ const windowHeight = window.innerHeight;
6000
+ const buttonWidth = ((_a = this.buttonRef) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 60;
6001
+ const buttonHeight = ((_b = this.buttonRef) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
6002
+ const minPadding = 10;
6003
+ const candidateLeft = pointer.clientX - this.buttonDragOffset.x;
6004
+ const candidateTop = pointer.clientY - this.buttonDragOffset.y;
6005
+ const minLeft = minPadding;
6006
+ const maxLeft = windowWidth - buttonWidth - minPadding;
6007
+ const minTop = minPadding;
6008
+ const maxTop = windowHeight - buttonHeight - minPadding;
6009
+ const constrainedLeft = Math.max(minLeft, Math.min(candidateLeft, maxLeft));
6010
+ const constrainedTop = Math.max(minTop, Math.min(candidateTop, maxTop));
6011
+ const newHorizontalValue = this.buttonHorizontalSide === 'left'
6012
+ ? constrainedLeft
6013
+ : Math.max(minPadding, windowWidth - (constrainedLeft + buttonWidth));
6014
+ const newVerticalValue = this.buttonVerticalSide === 'top'
6015
+ ? constrainedTop
6016
+ : Math.max(minPadding, windowHeight - (constrainedTop + buttonHeight));
6017
+ if (newHorizontalValue !== this.buttonPosition.x || newVerticalValue !== this.buttonPosition.y) {
6018
+ this.buttonWasDragged = true;
6019
+ this.buttonPosition = { x: newHorizontalValue, y: newVerticalValue };
6020
+ if (this.rafId === null) {
6021
+ this.rafId = requestAnimationFrame(() => {
6022
+ this.updateHostPosition();
6023
+ this.rafId = null;
6024
+ });
6025
+ }
6026
+ }
6027
+ }
6028
+ addButtonEventListeners() {
6029
+ if (this.buttonListenersAttached) {
6030
+ return;
6031
+ }
6032
+ document.addEventListener('mousemove', this.handleButtonMouseMove);
6033
+ document.addEventListener('mouseup', this.handleButtonMouseUp);
6034
+ document.addEventListener('touchmove', this.handleButtonTouchMove, { passive: false });
6035
+ document.addEventListener('touchend', this.handleButtonTouchEnd);
6036
+ this.buttonListenersAttached = true;
6037
+ }
6038
+ removeButtonEventListeners() {
6039
+ if (!this.buttonListenersAttached) {
6040
+ return;
6041
+ }
6042
+ if (this.rafId !== null) {
6043
+ cancelAnimationFrame(this.rafId);
6044
+ this.rafId = null;
6045
+ }
6046
+ document.removeEventListener('mousemove', this.handleButtonMouseMove);
6047
+ document.removeEventListener('mouseup', this.handleButtonMouseUp);
6048
+ document.removeEventListener('touchmove', this.handleButtonTouchMove);
6049
+ document.removeEventListener('touchend', this.handleButtonTouchEnd);
6050
+ this.buttonListenersAttached = false;
6051
+ }
6052
+ isAutoPosition(value) {
6053
+ const trimmed = value.trim();
6054
+ return trimmed === '' || trimmed === 'auto';
6055
+ }
6056
+ parsePixelValue(value) {
6057
+ const trimmed = value.trim();
6058
+ if (trimmed === '' || trimmed === 'auto') {
6059
+ return null;
6060
+ }
6061
+ if (trimmed.endsWith('px')) {
6062
+ const parsed = parseFloat(trimmed);
6063
+ return Number.isFinite(parsed) ? parsed : null;
6064
+ }
6065
+ const numeric = Number(trimmed);
6066
+ if (Number.isFinite(numeric)) {
6067
+ return numeric;
6068
+ }
6069
+ return null;
6070
+ }
6071
+ getNumericPositionValue(value, fallback) {
6072
+ const parsed = this.parsePixelValue(value);
6073
+ if (parsed !== null) {
6074
+ return parsed;
6075
+ }
6076
+ return fallback;
6077
+ }
6078
+ getWelcomeMessages() {
6079
+ const translated = this.translationManager.getArray("content.welcomeMessages");
6080
+ return translated && translated.length > 0
6081
+ ? translated
6082
+ : this.parsedWelcomeMessages;
6083
+ }
6084
+ getStarterQuestions() {
6085
+ const translated = this.translationManager.getArray("content.starterQuestions");
6086
+ return translated && translated.length > 0
6087
+ ? translated
6088
+ : this.parsedStarterQuestions;
5284
6089
  }
5285
6090
  getButtonClasses() {
5286
- const hasText = this.buttonText && this.buttonText.trim();
6091
+ const buttonText = this.translationManager.get('branding.buttonText', this.buttonText);
6092
+ const hasText = !!(buttonText && buttonText.trim());
5287
6093
  const baseClass = hasText ? 'chat-btn-text' : 'chat-btn-icon';
5288
6094
  const shapeClass = this.buttonShape === 'round' ? 'round' : '';
5289
6095
  return `${baseClass} ${shapeClass}`.trim();
5290
6096
  }
5291
6097
  renderButton() {
5292
- const hasText = this.buttonText && this.buttonText.trim();
6098
+ var _a;
6099
+ const buttonText = this.translationManager.get('branding.buttonText', this.buttonText);
6100
+ const hasText = !!(buttonText && buttonText.trim());
5293
6101
  const hasCustomIcon = this.iconUrl && this.iconUrl.trim();
5294
- const iconSrc = hasCustomIcon ? this.iconUrl : this.getDefaultIconUrl();
5295
6102
  const buttonClasses = this.getButtonClasses();
6103
+ const finalButtonText = buttonText !== null && buttonText !== void 0 ? buttonText : '';
6104
+ const openLabel = (_a = this.translationManager.get('launcher.open')) !== null && _a !== void 0 ? _a : '';
6105
+ const buttonAriaLabel = finalButtonText ? `${openLabel} - ${finalButtonText}` : openLabel;
6106
+ // Only show drag cursor if button is draggable
6107
+ const isDraggable = this.isButtonDraggable();
6108
+ const buttonStyle = isDraggable ? {
6109
+ cursor: this.isButtonDragging ? 'grabbing' : 'grab',
6110
+ } : {};
5296
6111
  if (hasText) {
5297
- 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)));
6112
+ 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."))));
5298
6113
  }
5299
6114
  else {
5300
- return (h("button", { class: buttonClasses, onClick: () => this.toggleWindowVisibility(), "aria-label": "Open chat", title: "Open chat" }, h("img", { src: iconSrc, alt: "Chat" })));
6115
+ 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."))));
5301
6116
  }
5302
6117
  }
5303
6118
  getStorageKeys() {
@@ -5433,18 +6248,18 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
5433
6248
  if (this.error && !this.sessionId) {
5434
6249
  return (h(Host, null, h("p", { class: "error-message" }, this.error)));
5435
6250
  }
5436
- 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'
6251
+ 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'
5437
6252
  ? 'message-bubble-user'
5438
6253
  : message.role === 'assistant'
5439
6254
  ? 'message-bubble-assistant'
5440
- : '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) => {
6255
+ : '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) => {
5441
6256
  // Unclear why but after removing all attachments this is being set to `null`.
5442
6257
  if (el) {
5443
6258
  this.fileInputRef = el;
5444
6259
  }
5445
- }, 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()
6260
+ }, 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()
5446
6261
  ? 'send-button-enabled'
5447
- : '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"))))))));
6262
+ : '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"))))))));
5448
6263
  }
5449
6264
  get host() { return this; }
5450
6265
  static get watchers() { return {
@@ -5456,6 +6271,7 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
5456
6271
  "apiBaseUrl": [1, "api-base-url"],
5457
6272
  "buttonText": [1, "button-text"],
5458
6273
  "iconUrl": [1, "icon-url"],
6274
+ "embedKey": [1, "embed-key"],
5459
6275
  "buttonShape": [1, "button-shape"],
5460
6276
  "headerText": [1, "header-text"],
5461
6277
  "newChatConfirmationMessage": [1, "new-chat-confirmation-message"],
@@ -5470,6 +6286,8 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
5470
6286
  "allowFullScreen": [4, "allow-full-screen"],
5471
6287
  "allowAttachments": [4, "allow-attachments"],
5472
6288
  "typingIndicatorText": [1, "typing-indicator-text"],
6289
+ "language": [1],
6290
+ "translationsUrl": [1, "translations-url"],
5473
6291
  "error": [32],
5474
6292
  "messages": [32],
5475
6293
  "sessionId": [32],
@@ -5487,7 +6305,9 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
5487
6305
  "isFullscreen": [32],
5488
6306
  "showNewChatConfirmation": [32],
5489
6307
  "selectedFiles": [32],
5490
- "isUploadingFiles": [32]
6308
+ "isUploadingFiles": [32],
6309
+ "isButtonDragging": [32],
6310
+ "buttonWasDragged": [32]
5491
6311
  }, undefined, {
5492
6312
  "visible": ["visibilityHandler"]
5493
6313
  }]);