@heedb/web-sdk 0.1.7 → 1.0.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.
package/README.md CHANGED
@@ -22,7 +22,7 @@ The fastest way — no build step, no dependencies. Add one line before `</body>
22
22
 
23
23
  > **Important:** `data-host` is required when loading from a CDN. It tells the widget where to send API requests. Omit it only when the script is served from the same domain as your Heedb instance.
24
24
 
25
- A floating chat button appears in the bottom-right corner. That's it.
25
+ A floating chat button appears in the bottom-right corner. That's it. Customize the look, trigger mode, and behavior from your [dashboard](https://heedb.com/app/customization).
26
26
 
27
27
  ### npm
28
28
 
@@ -399,16 +399,18 @@ Use the CDN script tag — no build tools needed:
399
399
 
400
400
  For verified identity on static sites, you'll need a small server endpoint that returns the `userHash` — see the React + API route example above.
401
401
 
402
+ > **Tip:** To pin a specific major version on the CDN, use `https://cdn.jsdelivr.net/npm/@heedb/web-sdk@1/widget.js`. Without the version pin, you always get the latest release.
403
+
402
404
  ---
403
405
 
404
406
  ## What the widget does
405
407
 
406
- The widget adds a floating button to your page with three tabs:
408
+ The widget adds a trigger button to your page with up to three tabs:
407
409
 
408
410
  | Tab | Description | Requires |
409
411
  |-----|-------------|----------|
410
412
  | **Message** | Contact form — name, email, and a message. Creates a new support thread. Fields are hidden when the user is identified. | Nothing |
411
- | **Privacy** | GDPR/privacy request form — data export, deletion, or opt-out. | Nothing |
413
+ | **Privacy** | GDPR/privacy request form — data export, deletion, or opt-out. Can be hidden via dashboard settings. | Nothing |
412
414
  | **Messages** | Conversation history — shows open threads. | Verified identity (`userHash`) |
413
415
 
414
416
  **The full conversation loop:**
@@ -422,6 +424,46 @@ The widget adds a floating button to your page with three tabs:
422
424
 
423
425
  ---
424
426
 
427
+ ## Trigger modes
428
+
429
+ The widget supports three trigger modes, configured in your dashboard under **Customization**:
430
+
431
+ | Mode | Description |
432
+ |------|-------------|
433
+ | **Floating** (default) | A round button fixed in the bottom-right or bottom-left corner |
434
+ | **Tag** | A vertical tab on the left or right edge of the page (e.g. "Talk to us!") |
435
+ | **Embedded** | No visible button — you provide a CSS selector for an existing element on your page that opens the widget when clicked |
436
+
437
+ All trigger modes support a custom SVG icon or emoji, plus optional button text.
438
+
439
+ ---
440
+
441
+ ## Customization
442
+
443
+ All visual customization is done through the [dashboard](https://heedb.com/app/customization) — no code changes needed. Available options:
444
+
445
+ | Option | Description |
446
+ |--------|-------------|
447
+ | **Theme mode** | Light, dark, or system (follows OS preference) |
448
+ | **Colors** | Primary, text, and background colors — separate sets for light and dark mode |
449
+ | **Border radius** | Panel corner rounding (0–24px) |
450
+ | **Button radius** | Trigger button rounding (0–50px / full circle) |
451
+ | **Font family** | Custom font stack |
452
+ | **Header title** | Custom panel title (e.g. "Talk to us!") |
453
+ | **Trigger icon** | Custom SVG icon for the trigger button |
454
+ | **Trigger emoji** | Emoji for the trigger (default: 💬) |
455
+ | **Trigger text** | Label next to the icon (tag mode and floating with label) |
456
+ | **Position** | Bottom-right or bottom-left (floating), right or left edge (tag) |
457
+ | **Privacy tab** | Show or hide the privacy/GDPR tab |
458
+ | **Custom CSS** | Inject custom CSS to override any widget style |
459
+ | **Custom labels** | Localized overrides for tab labels, placeholders, and empty state text (en/es/pt) |
460
+
461
+ ### Language
462
+
463
+ The widget auto-detects the page language from the `<html lang>` attribute and supports English, Spanish, and Portuguese. You can override individual labels with localized strings in the dashboard.
464
+
465
+ ---
466
+
425
467
  ## Configuration reference
426
468
 
427
469
  ### Script tag attributes
@@ -447,7 +489,7 @@ The widget adds a floating button to your page with three tabs:
447
489
  |---|---|---|---|
448
490
  | `init()` called | No | Yes (email + name) | Yes (email + name + userHash) |
449
491
  | Contact form visible | Yes (full form) | Yes (message only) | Yes (message only) |
450
- | Privacy tab visible | Yes | Yes | Yes |
492
+ | Privacy tab visible | Yes (unless hidden in dashboard) | Yes (unless hidden) | Yes (unless hidden) |
451
493
  | Messages tab visible | No | No | Yes |
452
494
  | Name/email fields | Shown | Hidden | Hidden |
453
495
 
package/dist/index.cjs CHANGED
@@ -24,6 +24,7 @@ __export(index_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(index_exports);
26
26
  var DEFAULT_HOST = "https://heedb.com";
27
+ var CDN_WIDGET_URL = "https://cdn.jsdelivr.net/npm/@heedb/web-sdk/widget.js";
27
28
  var Heedb = {
28
29
  _scriptLoaded: false,
29
30
  /**
@@ -39,7 +40,7 @@ var Heedb = {
39
40
  const host = (_a = opts.host) != null ? _a : DEFAULT_HOST;
40
41
  if (!this._scriptLoaded) {
41
42
  const script = document.createElement("script");
42
- script.src = `${host}/widget.js`;
43
+ script.src = CDN_WIDGET_URL;
43
44
  script.setAttribute("data-api-key", opts.apiKey);
44
45
  script.setAttribute("data-host", host);
45
46
  script.onload = () => {
@@ -51,6 +52,20 @@ var Heedb = {
51
52
  this._identify(opts);
52
53
  }
53
54
  },
55
+ /**
56
+ * Clear the current user's identity and reset the widget to anonymous mode.
57
+ * Call this on logout to prevent the next user from seeing stale data.
58
+ *
59
+ * ```ts
60
+ * Heedb.reset();
61
+ * ```
62
+ */
63
+ reset() {
64
+ const w = window;
65
+ if (w.Heedb && typeof w.Heedb.reset === "function") {
66
+ w.Heedb.reset();
67
+ }
68
+ },
54
69
  /** @internal */
55
70
  _identify(opts) {
56
71
  const w = window;
@@ -58,7 +73,8 @@ var Heedb = {
58
73
  w.Heedb.init({
59
74
  email: opts.email,
60
75
  name: opts.name,
61
- userHash: opts.userHash
76
+ userHash: opts.userHash,
77
+ lang: opts.lang
62
78
  });
63
79
  }
64
80
  }
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/index.ts
2
2
  var DEFAULT_HOST = "https://heedb.com";
3
+ var CDN_WIDGET_URL = "https://cdn.jsdelivr.net/npm/@heedb/web-sdk/widget.js";
3
4
  var Heedb = {
4
5
  _scriptLoaded: false,
5
6
  /**
@@ -15,7 +16,7 @@ var Heedb = {
15
16
  const host = (_a = opts.host) != null ? _a : DEFAULT_HOST;
16
17
  if (!this._scriptLoaded) {
17
18
  const script = document.createElement("script");
18
- script.src = `${host}/widget.js`;
19
+ script.src = CDN_WIDGET_URL;
19
20
  script.setAttribute("data-api-key", opts.apiKey);
20
21
  script.setAttribute("data-host", host);
21
22
  script.onload = () => {
@@ -27,6 +28,20 @@ var Heedb = {
27
28
  this._identify(opts);
28
29
  }
29
30
  },
31
+ /**
32
+ * Clear the current user's identity and reset the widget to anonymous mode.
33
+ * Call this on logout to prevent the next user from seeing stale data.
34
+ *
35
+ * ```ts
36
+ * Heedb.reset();
37
+ * ```
38
+ */
39
+ reset() {
40
+ const w = window;
41
+ if (w.Heedb && typeof w.Heedb.reset === "function") {
42
+ w.Heedb.reset();
43
+ }
44
+ },
30
45
  /** @internal */
31
46
  _identify(opts) {
32
47
  const w = window;
@@ -34,7 +49,8 @@ var Heedb = {
34
49
  w.Heedb.init({
35
50
  email: opts.email,
36
51
  name: opts.name,
37
- userHash: opts.userHash
52
+ userHash: opts.userHash,
53
+ lang: opts.lang
38
54
  });
39
55
  }
40
56
  }
package/dist/widget.js CHANGED
@@ -1,156 +1,172 @@
1
- /* Heedb Widget v0.1.7 — https://heedb.com */
2
- "use strict";(()=>{(function(){var W,U,K,J,V;let w=document.currentScript||document.querySelector("script[data-api-key]"),E=(W=w==null?void 0:w.getAttribute("data-api-key"))!=null?W:"",N=(U=w==null?void 0:w.src)!=null?U:"",I=(w==null?void 0:w.getAttribute("data-host"))||(N?new URL(N).origin:"");if(!E){console.warn("[Heedb] Missing data-api-key on <script> tag.");return}let c={},u=!1,X={primary:"#18181b",text:"#18181b",bg:"#ffffff"},G={primary:"#e4e4e7",text:"#e4e4e7",bg:"#1a1a1a"};function R(){return c.mode==="dark"?!0:c.mode==="light"?!1:c.mode==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches:!1}function Y(){return u?G:X}function $(e,t){let n=c[e];return n!=null?String(n):t}let C=!1,h="contact",A="",L=(K=localStorage.getItem("heedb_name"))!=null?K:"",b=(J=localStorage.getItem("heedb_email"))!=null?J:"",y=(V=localStorage.getItem("heedb_token"))!=null?V:"",v=null,H=null;async function Q(e,t){try{let n=await D("/api/threads/token",{api_key:E,email:e,userHash:t});if(n.ok){let l=await n.json();if(l.widgetToken){y=l.widgetToken,localStorage.setItem("heedb_token",l.widgetToken);return}}y="",localStorage.removeItem("heedb_token")}catch(n){y="",localStorage.removeItem("heedb_token")}}window.Heedb={version:"0.1.7",init(e={}){e.name&&(L=e.name,localStorage.setItem("heedb_name",e.name)),e.email&&(b=e.email,localStorage.setItem("heedb_email",e.email),e.userHash?Q(e.email,e.userHash).then(()=>{z(),C&&v&&k()}):(z(),C&&v&&k()))},reset(){L="",b="",y="",localStorage.removeItem("heedb_name"),localStorage.removeItem("heedb_email"),localStorage.removeItem("heedb_token"),h="contact",C=!1,v&&(v.style.display="none"),z()}};function D(e,t){return fetch(`${I}${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}function Z(e){let t=new URL(`${I}/api/threads`);return t.searchParams.set("api_key",E),t.searchParams.set("email",e),y&&t.searchParams.set("token",y),fetch(t.toString()).then(n=>n.json())}function ee(e){let t=new URL(`${I}/api/threads/${e}`);return t.searchParams.set("api_key",E),t.searchParams.set("email",b),t.searchParams.set("token",y),fetch(t.toString()).then(n=>n.json())}function te(e,t){return D(`/api/threads/${e}/reply`,{api_key:E,email:b,token:y,message:t})}async function ne(){var e;try{let t=new URL(`${I}/api/widget-config`);t.searchParams.set("api_key",E);let n=await fetch(t.toString());if(n.ok)return(e=(await n.json()).config)!=null?e:{}}catch(t){}return{}}function O(){var f,x;let e=Y(),t=$(u?"darkPrimaryColor":"primaryColor",e.primary),n=$(u?"darkTextColor":"textColor",e.text),l=$(u?"darkBgColor":"bgColor",e.bg),o=(f=c.borderRadius)!=null?f:16,r=(x=c.buttonRadius)!=null?x:50,d=c.fontFamily||"system-ui, -apple-system, sans-serif",m=c.position==="bottom-left",p=r>=50?"50%":`${r}px`,s=Math.round(o*.5),i=c.triggerMode==="tag",g=c.triggerMode==="embedded"||i;return`
3
- .llp-btn {
4
- position: fixed; bottom: 24px; ${m?"left: 24px":"right: 24px"}; z-index: 999998;
5
- width: 52px; height: 52px; border-radius: ${p}; border: none;
1
+ /* Heedb Widget v1.0.1 — https://heedb.com */
2
+ "use strict";(()=>{(function(){var te,ae,ne,se,oe;let L=document.currentScript||document.querySelector("script[data-api-key]"),A=(te=L==null?void 0:L.getAttribute("data-api-key"))!=null?te:"",Y=(ae=L==null?void 0:L.src)!=null?ae:"",z=(L==null?void 0:L.getAttribute("data-host"))||(Y?new URL(Y).origin:"");if(!A){console.warn("[Heedb] Missing data-api-key on <script> tag.");return}let ie=1,r={},b=!1,re={primary:"#18181b",text:"#18181b",bg:"#ffffff"},le={primary:"#e4e4e7",text:"#e4e4e7",bg:"#1a1a1a"},j={en:{contactTab:"Message",privacyTab:"Privacy",messagesTab:"Messages",nameLabel:"Name",emailLabel:"Email",messageLabel:"Message",namePlaceholder:"Jane Smith",emailPlaceholder:"jane@example.com",messagePlaceholder:"How can we help?",sendMessage:"Send message",sending:"Sending\u2026",fillAllFields:"Please fill in all fields.",messageSentTitle:"Message sent!",messageSentBody:"We'll get back to you soon. Check your inbox for a confirmation email.",networkError:"Network error. Please try again.",somethingWrong:"Something went wrong.",rateLimited:"Too many messages. Please wait a moment.",requestType:"Request type",deleteData:"Delete my data",accessData:"Access my data",exportData:"Export my data",correctData:"Correct my data",restrictProcessing:"Restrict processing",objectProcessing:"Object to processing",other:"Other",submitRequest:"Submit request",submitting:"Submitting\u2026",requestSubmittedTitle:"Request submitted!",requestSubmittedBody:"Your privacy request has been received. We'll respond within 30 days.",contactUs:"Contact us",feedback:"Feedback",poweredBy:"Powered by Heedb",justNow:"Just now",minutesAgo:"{mins}m ago",hoursAgo:"{hours}h ago",send:"Send",backToMessages:"\u2190 Back to messages",noThreadsAuth:"Send a message below to view your message history.",sendAMessage:"+ Send a message",sendNewMessage:"+ Send a new message",noOpenMessages:"No open messages yet.",loading:"Loading\u2026",failedToLoad:"Failed to load messages.",failedToLoadConvo:"Failed to load conversation.",failedToSend:"Failed to send.",typeReply:"Type a reply\u2026",privacyRequest:"Privacy request",message:"Message"},es:{contactTab:"Mensaje",privacyTab:"Privacidad",messagesTab:"Mensajes",nameLabel:"Nombre",emailLabel:"Correo",messageLabel:"Mensaje",namePlaceholder:"Mar\xEDa Garc\xEDa",emailPlaceholder:"maria@empresa.com",messagePlaceholder:"\xBFC\xF3mo podemos ayudarte?",sendMessage:"Enviar mensaje",sending:"Enviando\u2026",fillAllFields:"Por favor, completa todos los campos.",messageSentTitle:"\xA1Mensaje enviado!",messageSentBody:"Te responderemos pronto. Revisa tu bandeja de entrada para un correo de confirmaci\xF3n.",networkError:"Error de red. Int\xE9ntalo de nuevo.",somethingWrong:"Algo sali\xF3 mal.",rateLimited:"Demasiados mensajes. Espera un momento.",requestType:"Tipo de solicitud",deleteData:"Eliminar mis datos",accessData:"Acceder a mis datos",exportData:"Exportar mis datos",correctData:"Corregir mis datos",restrictProcessing:"Restringir procesamiento",objectProcessing:"Oponerse al procesamiento",other:"Otro",submitRequest:"Enviar solicitud",submitting:"Enviando\u2026",requestSubmittedTitle:"\xA1Solicitud enviada!",requestSubmittedBody:"Tu solicitud de privacidad ha sido recibida. Responderemos en un plazo de 30 d\xEDas.",contactUs:"Cont\xE1ctanos",feedback:"Comentarios",poweredBy:"Impulsado por Heedb",justNow:"Ahora",minutesAgo:"hace {mins}m",hoursAgo:"hace {hours}h",send:"Enviar",backToMessages:"\u2190 Volver a mensajes",noThreadsAuth:"Env\xEDa un mensaje para ver tu historial.",sendAMessage:"+ Enviar un mensaje",sendNewMessage:"+ Enviar un nuevo mensaje",noOpenMessages:"No hay mensajes a\xFAn.",loading:"Cargando\u2026",failedToLoad:"No se pudieron cargar los mensajes.",failedToLoadConvo:"No se pudo cargar la conversaci\xF3n.",failedToSend:"No se pudo enviar.",typeReply:"Escribe una respuesta\u2026",privacyRequest:"Solicitud de privacidad",message:"Mensaje"},pt:{contactTab:"Mensagem",privacyTab:"Privacidade",messagesTab:"Mensagens",nameLabel:"Nome",emailLabel:"Email",messageLabel:"Mensagem",namePlaceholder:"Maria Silva",emailPlaceholder:"maria@empresa.com",messagePlaceholder:"Como podemos ajudar?",sendMessage:"Enviar mensagem",sending:"Enviando\u2026",fillAllFields:"Por favor, preencha todos os campos.",messageSentTitle:"Mensagem enviada!",messageSentBody:"Responderemos em breve. Verifique sua caixa de entrada para um email de confirma\xE7\xE3o.",networkError:"Erro de rede. Tente novamente.",somethingWrong:"Algo deu errado.",rateLimited:"Muitas mensagens. Aguarde um momento.",requestType:"Tipo de solicita\xE7\xE3o",deleteData:"Excluir meus dados",accessData:"Acessar meus dados",exportData:"Exportar meus dados",correctData:"Corrigir meus dados",restrictProcessing:"Restringir processamento",objectProcessing:"Opor-se ao processamento",other:"Outro",submitRequest:"Enviar solicita\xE7\xE3o",submitting:"Enviando\u2026",requestSubmittedTitle:"Solicita\xE7\xE3o enviada!",requestSubmittedBody:"Sua solicita\xE7\xE3o de privacidade foi recebida. Responderemos em at\xE9 30 dias.",contactUs:"Fale conosco",feedback:"Feedback",poweredBy:"Powered by Heedb",justNow:"Agora",minutesAgo:"h\xE1 {mins}m",hoursAgo:"h\xE1 {hours}h",send:"Enviar",backToMessages:"\u2190 Voltar \xE0s mensagens",noThreadsAuth:"Envie uma mensagem para ver seu hist\xF3rico.",sendAMessage:"+ Enviar uma mensagem",sendNewMessage:"+ Enviar uma nova mensagem",noOpenMessages:"Nenhuma mensagem ainda.",loading:"Carregando\u2026",failedToLoad:"N\xE3o foi poss\xEDvel carregar as mensagens.",failedToLoadConvo:"N\xE3o foi poss\xEDvel carregar a conversa.",failedToSend:"N\xE3o foi poss\xEDvel enviar.",typeReply:"Digite uma resposta\u2026",privacyRequest:"Solicita\xE7\xE3o de privacidade",message:"Mensagem"}},R="en";function n(e){var t,a,o;return(o=(a=(t=j[R])==null?void 0:t[e])!=null?a:j.en[e])!=null?o:e}function O(e){if(e)return e[R]||e.en}function G(){var a;let e=L==null?void 0:L.getAttribute("data-lang");if(e&&e in j)return e;if(F&&F in j)return F;if(r.language&&r.language in j)return r.language;let t=(a=document.documentElement.lang)==null?void 0:a.slice(0,2);return t&&t in j?t:"en"}let F;function J(){return r.mode==="dark"?!0:r.mode==="light"?!1:r.mode==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches:!1}function de(){return b?le:re}function N(e,t){let a=r[e];return a!=null?String(a):t}let S=!1,E="contact",K="",P=(ne=localStorage.getItem("heedb_name"))!=null?ne:"",k=(se=localStorage.getItem("heedb_email"))!=null?se:"",M=(oe=localStorage.getItem("heedb_token"))!=null?oe:"",f=null,_=null;async function ce(e,t){try{let a=await W("/api/threads/token",{api_key:A,email:e,userHash:t});if(a.ok){let o=await a.json();if(o.widgetToken){M=o.widgetToken,localStorage.setItem("heedb_token",o.widgetToken);return}}M="",localStorage.removeItem("heedb_token")}catch(a){M="",localStorage.removeItem("heedb_token")}}window.Heedb={version:"1.0.1",init(e={}){e.lang&&(F=e.lang,R=G(),Z(),S&&f&&C()),e.name&&(P=e.name,localStorage.setItem("heedb_name",e.name)),e.email&&(k=e.email,localStorage.setItem("heedb_email",e.email),e.userHash?ce(e.email,e.userHash).then(()=>{q(),S&&f&&C()}):(q(),S&&f&&C()))},reset(){P="",k="",M="",localStorage.removeItem("heedb_name"),localStorage.removeItem("heedb_email"),localStorage.removeItem("heedb_token"),E="contact",S=!1,f&&(f.style.display="none"),q()}};function W(e,t){return fetch(`${z}${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}function pe(e){let t=new URL(`${z}/api/threads`);return t.searchParams.set("api_key",A),t.searchParams.set("email",e),M&&t.searchParams.set("token",M),fetch(t.toString()).then(a=>a.json())}function me(e){let t=new URL(`${z}/api/threads/${e}`);return t.searchParams.set("api_key",A),t.searchParams.set("email",k),t.searchParams.set("token",M),fetch(t.toString()).then(a=>a.json())}function ge(e,t){return W(`/api/threads/${e}/reply`,{api_key:A,email:k,token:M,message:t})}async function ue(){var e;try{let t=new URL(`${z}/api/widget-config`);t.searchParams.set("api_key",A),t.searchParams.set("v",String(ie));let a=await fetch(t.toString());if(a.ok)return(e=(await a.json()).config)!=null?e:{}}catch(t){}return{}}function X(){var g,v;let e=de(),t=N(b?"darkPrimaryColor":"primaryColor",e.primary),a=N(b?"darkTextColor":"textColor",e.text),o=N(b?"darkBgColor":"bgColor",e.bg),i=(g=r.borderRadius)!=null?g:16,l=(v=r.buttonRadius)!=null?v:50,y=r.fontFamily||"system-ui, -apple-system, sans-serif",h=r.position==="bottom-left",c=l>=50?"50%":`${l}px`,p=Math.round(i*.5),d=r.triggerMode==="tag",m=r.triggerMode==="embedded"||d;return`
3
+ .heedb-btn {
4
+ position: fixed; bottom: 24px; ${h?"left: 24px":"right: 24px"}; z-index: 999998;
5
+ width: 52px; height: 52px; border-radius: ${c}; border: none;
6
6
  background: ${t}; color: #fff; font-size: 22px; cursor: pointer;
7
7
  box-shadow: 0 4px 16px rgba(0,0,0,.25);
8
- display: ${g?"none":"flex"}; align-items: center; justify-content: center;
9
- transition: transform .15s;
10
- }
11
- .llp-btn:hover { transform: scale(1.08); }
12
- .llp-btn-label { font-size: 14px; font-weight: 600; margin-left: 6px; }
13
- .llp-btn-icon { display: flex; align-items: center; justify-content: center; }
14
- .llp-btn-icon svg { width: 22px; height: 22px; fill: currentColor; }
15
- .llp-btn:has(.llp-btn-label) { width: auto; padding: 0 18px; gap: 4px; }
16
- .llp-tag {
17
- position: fixed !important; ${m?"left: 0 !important":"right: 0 !important"}; top: 50% !important; z-index: 999998 !important;
18
- transform: ${m?"rotate(90deg) translateX(-50%)":"rotate(-90deg) translateX(50%)"} !important;
19
- transform-origin: ${m?"left bottom":"right bottom"} !important;
8
+ display: ${m?"none":"flex"}; align-items: center; justify-content: center;
9
+ font-family: ${y}; transition: transform .15s;
10
+ }
11
+ .heedb-btn:hover { transform: scale(1.08); }
12
+ .heedb-btn-label { font-size: 14px; font-weight: 600; margin-left: 6px; }
13
+ .heedb-btn-icon { display: flex; align-items: center; justify-content: center; }
14
+ .heedb-btn-icon svg { width: 22px; height: 22px; fill: currentColor; }
15
+ .heedb-btn:has(.heedb-btn-label) { width: auto; padding: 0 18px; gap: 4px; }
16
+ .heedb-tag {
17
+ position: fixed !important; ${h?"left: 0 !important":"right: 0 !important"}; top: 50% !important; z-index: 999998 !important;
18
+ transform: ${h?"rotate(90deg) translateX(-50%)":"rotate(-90deg) translateX(50%)"} !important;
19
+ transform-origin: ${h?"left bottom":"right bottom"} !important;
20
20
  background: ${t}; color: #fff; border: none; cursor: pointer;
21
21
  padding: 8px 18px; font-size: 13px; font-weight: 600;
22
- font-family: ${d};
23
- border-radius: ${Math.min(r,12)}px ${Math.min(r,12)}px 0 0;
22
+ font-family: ${y};
23
+ border-radius: ${Math.min(l,12)}px ${Math.min(l,12)}px 0 0;
24
24
  box-shadow: 0 2px 12px rgba(0,0,0,.2);
25
25
  display: flex; align-items: center; gap: 6px;
26
26
  transition: opacity .15s;
27
27
  }
28
- .llp-tag:hover { opacity: .9; }
29
- .llp-tag-icon { font-size: 16px; }
30
- .llp-panel {
31
- position: fixed; bottom: 88px; ${m?"left: 24px":"right: 24px"}; z-index: 999999;
32
- width: 370px; max-height: 560px; border-radius: ${o}px;
33
- background: ${l}; box-shadow: 0 8px 32px rgba(0,0,0,.18);
28
+ .heedb-tag:hover { opacity: .9; }
29
+ .heedb-tag-icon { font-size: 16px; }
30
+ .heedb-tag-icon svg { width: 16px; height: 16px; fill: currentColor; }
31
+ .heedb-panel {
32
+ position: fixed; bottom: 88px; ${h?"left: 24px":"right: 24px"}; z-index: 999999;
33
+ width: 280px; max-height: 560px; border-radius: ${i}px;
34
+ background: ${o}; box-shadow: 0 8px 32px rgba(0,0,0,.18);
34
35
  display: flex; flex-direction: column; overflow: hidden;
35
- font-family: ${d}; font-size: 14px; color: ${n};
36
+ font-family: ${y}; font-size: 14px; color: ${a};
36
37
  transition: opacity .15s, transform .15s;
37
38
  }
38
- .llp-header {
39
+ .heedb-header {
39
40
  background: ${t}; color: #fff; padding: 14px 16px;
40
41
  display: flex; align-items: center; justify-content: space-between;
41
42
  }
42
- .llp-header h2 { margin: 0; font-size: 15px; font-weight: 600; }
43
- .llp-close {
43
+ .heedb-header h2 { margin: 0; font-size: 15px; font-weight: 600; }
44
+ .heedb-close {
44
45
  background: none; border: none; color: #fff; cursor: pointer;
45
46
  font-size: 18px; line-height: 1; padding: 0;
46
47
  }
47
- .llp-tabs {
48
- display: flex; border-bottom: 1px solid ${u?"#333":"#e4e4e7"};
48
+ .heedb-tabs {
49
+ display: flex; border-bottom: 1px solid ${b?"#333":"#e4e4e7"};
49
50
  }
50
- .llp-tab {
51
+ .heedb-tab {
51
52
  flex: 1; padding: 10px 0; border: none; background: none;
52
53
  cursor: pointer; font-size: 13px; font-weight: 500; color: #71717a;
53
54
  border-bottom: 2px solid transparent; margin-bottom: -1px;
54
55
  }
55
- .llp-tab.active { color: ${n}; border-bottom-color: ${t}; }
56
- .llp-body { padding: 16px; overflow-y: auto; flex: 1; }
57
- .llp-label { display: block; font-size: 12px; font-weight: 600; color: #52525b; margin-bottom: 4px; }
58
- .llp-input, .llp-textarea, .llp-select {
56
+ .heedb-tab.active { color: ${a}; border-bottom-color: ${t}; }
57
+ .heedb-body { padding: 16px; overflow-y: auto; flex: 1; }
58
+ .heedb-label { display: block; font-size: 12px; font-weight: 600; color: #52525b; margin-bottom: 4px; }
59
+ .heedb-input, .heedb-textarea, .heedb-select {
59
60
  width: 100%; box-sizing: border-box; padding: 8px 10px;
60
- border: 1px solid ${u?"#444":"#d4d4d8"}; border-radius: ${s}px;
61
- font-size: 13px; color: ${n}; margin-bottom: 10px;
62
- font-family: inherit; background: ${u?"#222":l};
61
+ border: 1px solid ${b?"#444":"#d4d4d8"}; border-radius: ${p}px;
62
+ font-size: 13px; color: ${a}; margin-bottom: 10px;
63
+ font-family: inherit; background: ${b?"#222":o};
63
64
  }
64
- .llp-textarea { min-height: 80px; resize: vertical; }
65
- .llp-input:focus, .llp-textarea:focus, .llp-select:focus {
65
+ .heedb-textarea { min-height: 80px; resize: vertical; }
66
+ .heedb-input:focus, .heedb-textarea:focus, .heedb-select:focus {
66
67
  outline: none; border-color: ${t};
67
68
  }
68
- .llp-btn-submit {
69
+ .heedb-btn-submit {
69
70
  width: 100%; padding: 10px; background: ${t}; color: #fff;
70
- border: none; border-radius: ${s}px; font-size: 14px; font-weight: 600;
71
+ border: none; border-radius: ${p}px; font-size: 14px; font-weight: 600;
71
72
  cursor: pointer; transition: opacity .15s;
72
73
  }
73
- .llp-btn-submit:hover { opacity: .85; }
74
- .llp-btn-submit:disabled { opacity: .5; cursor: not-allowed; }
75
- .llp-error { color: #ef4444; font-size: 12px; margin-bottom: 8px; }
76
- .llp-success { text-align: center; padding: 24px 8px; }
77
- .llp-success-icon { font-size: 36px; }
78
- .llp-success h3 { margin: 12px 0 6px; font-size: 15px; color: ${n}; }
79
- .llp-success p { margin: 0; color: #71717a; font-size: 13px; line-height: 1.5; }
80
- .llp-thread-item {
81
- padding: 10px 12px; border: 1px solid ${u?"#333":"#e4e4e7"}; border-radius: ${s}px;
74
+ .heedb-btn-submit:hover { opacity: .85; }
75
+ .heedb-btn-submit:disabled { opacity: .5; cursor: not-allowed; }
76
+ .heedb-error { color: #ef4444; font-size: 12px; margin-bottom: 8px; }
77
+ .heedb-success { text-align: center; padding: 24px 8px; }
78
+ .heedb-success-icon { font-size: 36px; }
79
+ .heedb-success h3 { margin: 12px 0 6px; font-size: 15px; color: ${a}; }
80
+ .heedb-success p { margin: 0; color: #71717a; font-size: 13px; line-height: 1.5; }
81
+ .heedb-thread-item {
82
+ padding: 10px 12px; border: 1px solid ${b?"#333":"#e4e4e7"}; border-radius: ${p}px;
82
83
  margin-bottom: 8px; cursor: pointer; display: block; color: inherit;
83
84
  transition: background .1s; background: none;
84
85
  }
85
- .llp-thread-item:hover { background: ${u?"#252525":"#f4f4f5"}; }
86
- .llp-thread-label { font-size: 12px; color: #71717a; margin-bottom: 2px; }
87
- .llp-thread-text { font-size: 13px; color: ${n}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
88
- .llp-thread-meta { font-size: 11px; color: #a1a1aa; margin-top: 3px; }
89
- .llp-badge { display: inline-block; padding: 1px 6px; border-radius: 9999px; font-size: 10px; font-weight: 600; }
90
- .llp-badge-open { background: #d1fae5; color: #065f46; }
91
- .llp-badge-replied { background: #dbeafe; color: #1e40af; }
92
- .llp-new-msg { margin-top: 12px; padding-top: 12px; border-top: 1px solid ${u?"#333":"#e4e4e7"}; }
93
- .llp-new-msg button {
94
- width: 100%; padding: 8px; background: none; border: 1px solid ${u?"#444":"#d4d4d8"};
95
- border-radius: ${s}px; font-size: 13px; cursor: pointer; color: ${u?"#999":"#52525b"};
96
- }
97
- .llp-new-msg button:hover { background: ${u?"#252525":"#f4f4f5"}; }
98
- .llp-footer {
99
- padding: 6px 16px; text-align: center; border-top: 1px solid ${u?"#333":"#f0f0f0"};
100
- }
101
- .llp-footer a {
86
+ .heedb-thread-item:hover { background: ${b?"#252525":"#f4f4f5"}; }
87
+ .heedb-thread-label { font-size: 12px; color: #71717a; margin-bottom: 2px; }
88
+ .heedb-thread-text { font-size: 13px; color: ${a}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
89
+ .heedb-thread-meta { font-size: 11px; color: #a1a1aa; margin-top: 3px; }
90
+ .heedb-badge { display: inline-block; padding: 1px 6px; border-radius: 9999px; font-size: 10px; font-weight: 600; }
91
+ .heedb-badge-open { background: #d1fae5; color: #065f46; }
92
+ .heedb-badge-replied { background: #dbeafe; color: #1e40af; }
93
+ .heedb-new-msg { margin-top: 12px; padding-top: 12px; border-top: 1px solid ${b?"#333":"#e4e4e7"}; }
94
+ .heedb-new-msg button {
95
+ width: 100%; padding: 8px; background: none; border: 1px solid ${b?"#444":"#d4d4d8"};
96
+ border-radius: ${p}px; font-size: 13px; cursor: pointer; color: ${b?"#999":"#52525b"};
97
+ }
98
+ .heedb-new-msg button:hover { background: ${b?"#252525":"#f4f4f5"}; }
99
+ .heedb-footer {
100
+ padding: 6px 16px; text-align: center; border-top: 1px solid ${b?"#333":"#f0f0f0"};
101
+ }
102
+ .heedb-footer a {
102
103
  font-size: 10px; color: #a1a1aa; text-decoration: none; font-weight: 500;
103
104
  }
104
- .llp-footer a:hover { color: #71717a; text-decoration: underline; }
105
+ .heedb-footer a:hover { color: #71717a; text-decoration: underline; }
105
106
 
106
107
  /* Chat view */
107
- .llp-chat-back {
108
+ .heedb-chat-back {
108
109
  background: none; border: none; cursor: pointer; font-size: 13px;
109
110
  color: ${t}; padding: 0; margin-bottom: 12px; font-weight: 500;
110
111
  display: flex; align-items: center; gap: 4px;
111
112
  }
112
- .llp-chat-back:hover { text-decoration: underline; }
113
- .llp-chat-messages {
113
+ .heedb-chat-back:hover { text-decoration: underline; }
114
+ .heedb-chat-messages {
114
115
  display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px;
115
116
  max-height: 320px; overflow-y: auto;
116
117
  }
117
- .llp-chat-bubble {
118
- padding: 8px 12px; border-radius: ${Math.max(s,8)}px; font-size: 13px;
118
+ .heedb-chat-bubble {
119
+ padding: 8px 12px; border-radius: ${Math.max(p,8)}px; font-size: 13px;
119
120
  line-height: 1.45; max-width: 85%; word-wrap: break-word;
120
121
  white-space: pre-wrap;
121
122
  }
122
- .llp-chat-inbound {
123
- background: ${u?"#252525":"#f4f4f5"}; color: ${n}; align-self: flex-start;
123
+ .heedb-chat-inbound {
124
+ background: ${b?"#252525":"#f4f4f5"}; color: ${a}; align-self: flex-start;
124
125
  border-bottom-left-radius: 4px;
125
126
  }
126
- .llp-chat-outbound {
127
+ .heedb-chat-outbound {
127
128
  background: ${t}; color: #fff; align-self: flex-end;
128
129
  border-bottom-right-radius: 4px;
129
130
  }
130
- .llp-chat-time {
131
+ .heedb-chat-time {
131
132
  font-size: 10px; color: #a1a1aa; margin-top: 2px;
132
133
  }
133
- .llp-chat-time-right { text-align: right; }
134
- .llp-chat-reply {
135
- display: flex; gap: 8px; border-top: 1px solid ${u?"#333":"#e4e4e7"}; padding-top: 12px;
134
+ .heedb-chat-time-right { text-align: right; }
135
+ .heedb-chat-reply {
136
+ display: flex; gap: 8px; border-top: 1px solid ${b?"#333":"#e4e4e7"}; padding-top: 12px;
136
137
  }
137
- .llp-chat-reply-input {
138
- flex: 1; padding: 8px 10px; border: 1px solid ${u?"#444":"#d4d4d8"}; border-radius: ${s}px;
139
- font-size: 13px; font-family: inherit; color: ${n}; background: ${u?"#222":l};
138
+ .heedb-chat-reply-input {
139
+ flex: 1; padding: 8px 10px; border: 1px solid ${b?"#444":"#d4d4d8"}; border-radius: ${p}px;
140
+ font-size: 13px; font-family: inherit; color: ${a}; background: ${b?"#222":o};
140
141
  resize: none; min-height: 36px; max-height: 80px; box-sizing: border-box;
141
142
  }
142
- .llp-chat-reply-input:focus { outline: none; border-color: ${t}; }
143
- .llp-chat-send {
143
+ .heedb-chat-reply-input:focus { outline: none; border-color: ${t}; }
144
+ .heedb-chat-send {
144
145
  padding: 8px 14px; background: ${t}; color: #fff; border: none;
145
- border-radius: ${s}px; font-size: 13px; font-weight: 600; cursor: pointer;
146
+ border-radius: ${p}px; font-size: 13px; font-weight: 600; cursor: pointer;
146
147
  transition: opacity .15s; white-space: nowrap; align-self: flex-end;
147
148
  }
148
- .llp-chat-send:hover { opacity: .85; }
149
- .llp-chat-send:disabled { opacity: .5; cursor: not-allowed; }
150
- `}function a(e,t={},n=[]){let l=document.createElement(e);for(let[o,r]of Object.entries(t))o==="class"?l.className=r:o==="style"?l.setAttribute("style",r):o.startsWith("on")&&typeof r=="function"?l.addEventListener(o.slice(2),r):l.setAttribute(o,String(r));for(let o of n)l.appendChild(typeof o=="string"?document.createTextNode(o):o);return l}function P(e,t,n=""){let l=document.createElement("input");return l.type=e,l.id=t,l.placeholder=n,l.className="llp-input",l}function ae(e,t=""){let n=document.createElement("textarea");return n.id=e,n.placeholder=t,n.className="llp-textarea",n}function oe(e,t){let n=document.createElement("select");n.id=e,n.className="llp-select";for(let l of t){let o=document.createElement("option");o.value=l.value,o.textContent=l.label,n.appendChild(o)}return n}function k(){if(!v)return;let e=v.querySelector(".llp-body");e.innerHTML="",h==="contact"?le(e):h==="privacy"?ie(e):h==="threads"?re(e):h==="thread-detail"&&ce(e),M&&(M.style.display=h==="thread-detail"?"none":"flex")}function le(e,t=""){let n=!!(L&&b),l=a("label",{class:"llp-label"},["Name"]),o=P("text","llp-name","Jane Smith");L&&(o.value=L);let r=a("label",{class:"llp-label"},["Email"]),d=P("email","llp-email","jane@example.com");(t||b)&&(d.value=t||b);let m=a("label",{class:"llp-label"},["Message"]),p=ae("llp-message","How can we help?"),s=a("div",{class:"llp-error",style:"display:none"}),i=a("button",{class:"llp-btn-submit"},["Send message"]);i.onclick=async()=>{let g=o.value.trim(),f=d.value.trim(),x=p.value.trim();if(s.style.display="none",!g||!f||!x){s.textContent="Please fill in all fields.",s.style.display="block";return}i.disabled=!0,i.textContent="Sending\u2026";try{let T=await D("/api/contact",{api_key:E,name:g,email:f,message:x});if(T.ok)b=f,localStorage.setItem("heedb_email",f),z(),q(e,"Message sent!","We'll get back to you soon. Check your inbox for a confirmation email.");else{let me=await T.json();s.textContent=me.error||"Something went wrong.",s.style.display="block",i.disabled=!1,i.textContent="Send message"}}catch(T){s.textContent="Network error. Please try again.",s.style.display="block",i.disabled=!1,i.textContent="Send message"}},n?e.append(m,p,s,i):e.append(l,o,r,d,m,p,s,i)}function ie(e){let t=!!(L&&b),n=a("label",{class:"llp-label"},["Name"]),l=P("text","llp-priv-name","Jane Smith");L&&(l.value=L);let o=a("label",{class:"llp-label"},["Email"]),r=P("email","llp-priv-email","jane@example.com");b&&(r.value=b);let d=a("label",{class:"llp-label"},["Request type"]),m=oe("llp-priv-type",[{value:"deletion",label:"Delete my data"},{value:"access",label:"Access my data"},{value:"portability",label:"Export my data"},{value:"correction",label:"Correct my data"},{value:"restriction",label:"Restrict processing"},{value:"objection",label:"Object to processing"},{value:"other",label:"Other"}]),p=a("div",{class:"llp-error",style:"display:none"}),s=a("button",{class:"llp-btn-submit"},["Submit request"]);s.onclick=async()=>{let i=l.value.trim(),g=r.value.trim(),f=m.value;if(p.style.display="none",!i||!g){p.textContent="Please fill in all fields.",p.style.display="block";return}s.disabled=!0,s.textContent="Submitting\u2026";try{let x=await D("/api/privacy-request",{api_key:E,name:i,email:g,request_type:f});if(x.ok)b=g,localStorage.setItem("heedb_email",g),z(),q(e,"Request submitted!","Your privacy request has been received. We'll respond within 30 days.");else{let T=await x.json();p.textContent=T.error||"Something went wrong.",p.style.display="block",s.disabled=!1,s.textContent="Submit request"}}catch(x){p.textContent="Network error. Please try again.",p.style.display="block",s.disabled=!1,s.textContent="Submit request"}},t?e.append(d,m,p,s):e.append(n,l,o,r,d,m,p,s)}async function re(e){var t;if(!y){e.innerHTML="";let n=a("p",{style:"color:#71717a;text-align:center;margin:8px 0;font-size:13px;line-height:1.5"},["Send a message below to view your message history."]),l=a("div",{class:"llp-new-msg"}),o=a("button",{},["+ Send a message"]);o.onclick=()=>{h="contact",S("contact"),k()},l.appendChild(o),e.append(n,l);return}e.innerHTML='<p style="color:#71717a;text-align:center">Loading\u2026</p>';try{let{threads:n}=await Z(b);if(e.innerHTML="",n.length===0){let r=a("p",{style:"color:#71717a;text-align:center;margin:8px 0"},["No open messages yet."]);e.appendChild(r)}else for(let r of n){let d=a("span",{class:`llp-badge llp-badge-${r.status}`},[r.status]),m=a("div",{class:"llp-thread-label"},[r.type==="privacy"?"Privacy request":"Message"," \u2022 "]);m.appendChild(d);let p=a("div",{class:"llp-thread-text"},[(t=r.preview)!=null?t:""]),s=new Date(r.createdAt).toLocaleDateString(),i=a("div",{class:"llp-thread-meta"},[s]),g=a("div",{class:"llp-thread-item"});g.append(m,p,i),g.onclick=()=>se(r.id),e.appendChild(g)}let l=a("div",{class:"llp-new-msg"}),o=a("button",{},["+ Send a new message"]);o.onclick=()=>{h="contact",S("contact"),k()},l.appendChild(o),e.appendChild(l)}catch(n){e.innerHTML='<p style="color:#ef4444;text-align:center">Failed to load messages.</p>'}}function se(e){A=e,h="thread-detail",k()}async function ce(e){e.innerHTML='<p style="color:#71717a;text-align:center">Loading\u2026</p>';let t=a("button",{class:"llp-chat-back"},["\u2190 Back to messages"]);t.onclick=()=>{h="threads",S("threads"),k()};try{let l=(await ee(A)).messages||[];e.innerHTML="",e.style.padding="12px",e.appendChild(t);let o=a("div",{class:"llp-chat-messages"});for(let i of l){let g=i.direction==="inbound",f=a("div",{style:`display:flex;flex-direction:column;${g?"align-items:flex-start":"align-items:flex-end"}`}),x=a("div",{class:`llp-chat-bubble ${g?"llp-chat-inbound":"llp-chat-outbound"}`},[de(i.body)]),T=a("div",{class:`llp-chat-time ${g?"":"llp-chat-time-right"}`},[pe(i.createdAt)]);f.append(x,T),o.appendChild(f)}e.appendChild(o),requestAnimationFrame(()=>{o.scrollTop=o.scrollHeight});let r=a("div",{class:"llp-chat-reply"}),d=document.createElement("textarea");d.className="llp-chat-reply-input",d.placeholder="Type a reply\u2026",d.rows=1,d.addEventListener("input",()=>{d.style.height="auto",d.style.height=Math.min(d.scrollHeight,80)+"px"});let m=a("button",{class:"llp-chat-send"},["Send"]),p=a("div",{class:"llp-error",style:"display:none;margin-top:4px"});async function s(){let i=d.value.trim();if(i){m.disabled=!0,m.textContent="\u2026",p.style.display="none";try{let g=await te(A,i);if(g.ok){let f=a("div",{style:"display:flex;flex-direction:column;align-items:flex-start"}),x=a("div",{class:"llp-chat-bubble llp-chat-inbound"},[i]),T=a("div",{class:"llp-chat-time"},["Just now"]);f.append(x,T),o.appendChild(f),o.scrollTop=o.scrollHeight,d.value="",d.style.height="auto"}else{let f=await g.json();p.textContent=f.error||"Failed to send.",p.style.display="block"}}catch(g){p.textContent="Network error. Please try again.",p.style.display="block"}m.disabled=!1,m.textContent="Send"}}m.onclick=s,d.addEventListener("keydown",i=>{i.key==="Enter"&&!i.shiftKey&&(i.preventDefault(),s())}),r.append(d,m),e.append(r,p),requestAnimationFrame(()=>d.focus())}catch(n){e.innerHTML="",e.appendChild(t),e.appendChild(a("p",{style:"color:#ef4444;text-align:center"},["Failed to load conversation."]))}}function de(e){let t=e.split(`
151
- `),n=[];for(let l of t){let o=l.trim();if(/^(On|Em|El|Le|Am|Il giorno) .+(<[^>]+@[^>]+>).*(wrote|escreveu|escribi|crit|schrieb|scritto)\s?:$/i.test(o)||/<[^>]+@[^>]+>/.test(o)&&o.endsWith(":")||/^-{3,}$/.test(o))break;/^>{1,}\s/.test(o)||n.push(l)}return n.join(`
152
- `).trim()}function pe(e){let t=new Date(e),l=new Date().getTime()-t.getTime(),o=Math.floor(l/6e4);if(o<1)return"Just now";if(o<60)return`${o}m ago`;let r=Math.floor(o/60);return r<24?`${r}h ago`:t.toLocaleDateString()}function q(e,t,n){e.innerHTML="";let l=a("div",{class:"llp-success"});l.innerHTML=`
153
- <div class="llp-success-icon">\u2705</div>
149
+ .heedb-chat-send:hover { opacity: .85; }
150
+ .heedb-chat-send:disabled { opacity: .5; cursor: not-allowed; }
151
+
152
+ /* Skeleton loading */
153
+ .heedb-skeleton { pointer-events: none; }
154
+ .heedb-skel-line {
155
+ background: ${b?"#333":"#e4e4e7"};
156
+ border-radius: 4px;
157
+ animation: heedb-pulse 1.5s ease-in-out infinite;
158
+ }
159
+ @keyframes heedb-pulse {
160
+ 0%, 100% { opacity: 0.4; }
161
+ 50% { opacity: 1; }
162
+ }
163
+
164
+ /* Body fade transition */
165
+ .heedb-body { transition: opacity .15s ease; }
166
+ `}function s(e,t={},a=[]){let o=document.createElement(e);for(let[i,l]of Object.entries(t))i==="class"?o.className=l:i==="style"?o.setAttribute("style",l):i.startsWith("on")&&typeof l=="function"?o.addEventListener(i.slice(2),l):o.setAttribute(i,String(l));for(let i of a)o.appendChild(typeof i=="string"?document.createTextNode(i):i);return o}function U(e,t,a=""){let o=document.createElement("input");return o.type=e,o.id=t,o.placeholder=a,o.className="heedb-input",o}function he(e,t=""){let a=document.createElement("textarea");return a.id=e,a.placeholder=t,a.className="heedb-textarea",a}function be(e,t){let a=document.createElement("select");a.id=e,a.className="heedb-select";for(let o of t){let i=document.createElement("option");i.value=o.value,i.textContent=o.label,a.appendChild(i)}return a}function C(){if(!f)return;let e=f.querySelector(".heedb-body");e.innerHTML="",E==="contact"?fe(e):E==="privacy"?xe(e):E==="threads"?ye(e):E==="thread-detail"&&Te(e),$&&($.style.display=E==="thread-detail"?"none":"flex")}function fe(e,t=""){let a=!!(P&&k),o=s("label",{class:"heedb-label"},[n("nameLabel")]),i=U("text","heedb-name",n("namePlaceholder"));P&&(i.value=P);let l=s("label",{class:"heedb-label"},[n("emailLabel")]),y=U("email","heedb-email",n("emailPlaceholder"));(t||k)&&(y.value=t||k);let h=O(r.messageLabel),c=h?s("label",{class:"heedb-label"},[h]):null,p=he("heedb-message",O(r.messagePlaceholder)||n("messagePlaceholder")),d=s("div",{class:"heedb-error",style:"display:none"}),m=s("button",{class:"heedb-btn-submit"},[n("sendMessage")]);m.onclick=async()=>{var x;let g=i.value.trim(),v=y.value.trim(),u=p.value.trim();if(d.style.display="none",!g||!v||!u){d.textContent=n("fillAllFields"),d.style.display="block";return}m.disabled=!0,m.textContent=n("sending");try{let T=await W("/api/contact",{api_key:A,name:g,email:v,message:u,lang:R});if(T.ok)k=v,localStorage.setItem("heedb_email",v),q(),Q(e,n("messageSentTitle"),n("messageSentBody"));else if(T.status===429){let w=parseInt((x=T.headers.get("Retry-After"))!=null?x:"60",10);d.textContent=n("rateLimited"),d.style.display="block",m.textContent=n("sendMessage"),setTimeout(()=>{m.disabled=!1,d.style.display="none"},w*1e3)}else{let w=await T.json();d.textContent=w.error||n("somethingWrong"),d.style.display="block",m.disabled=!1,m.textContent=n("sendMessage")}}catch(T){d.textContent=n("networkError"),d.style.display="block",m.disabled=!1,m.textContent=n("sendMessage")}},a?(c&&e.append(c),e.append(p,d,m)):(e.append(o,i,l,y),c&&e.append(c),e.append(p,d,m))}function xe(e){let t=!!(P&&k),a=s("label",{class:"heedb-label"},[n("nameLabel")]),o=U("text","heedb-priv-name",n("namePlaceholder"));P&&(o.value=P);let i=s("label",{class:"heedb-label"},[n("emailLabel")]),l=U("email","heedb-priv-email",n("emailPlaceholder"));k&&(l.value=k);let y=s("label",{class:"heedb-label"},[n("requestType")]),h=be("heedb-priv-type",[{value:"deletion",label:n("deleteData")},{value:"access",label:n("accessData")},{value:"portability",label:n("exportData")}]),c=s("div",{class:"heedb-error",style:"display:none"}),p=s("button",{class:"heedb-btn-submit"},[n("submitRequest")]);p.onclick=async()=>{var v;let d=o.value.trim(),m=l.value.trim(),g=h.value;if(c.style.display="none",!d||!m){c.textContent=n("fillAllFields"),c.style.display="block";return}p.disabled=!0,p.textContent=n("submitting");try{let u=await W("/api/privacy-request",{api_key:A,name:d,email:m,request_type:g,lang:R});if(u.ok)k=m,localStorage.setItem("heedb_email",m),q(),Q(e,n("requestSubmittedTitle"),n("requestSubmittedBody"));else if(u.status===429){let x=parseInt((v=u.headers.get("Retry-After"))!=null?v:"60",10);c.textContent=n("rateLimited"),c.style.display="block",p.textContent=n("submitRequest"),setTimeout(()=>{p.disabled=!1,c.style.display="none"},x*1e3)}else{let x=await u.json();c.textContent=x.error||n("somethingWrong"),c.style.display="block",p.disabled=!1,p.textContent=n("submitRequest")}}catch(u){c.textContent=n("networkError"),c.style.display="block",p.disabled=!1,p.textContent=n("submitRequest")}},t?e.append(y,h,c,p):e.append(a,o,i,l,y,h,c,p)}async function ye(e){var t;if(!M){e.innerHTML="";let a=s("p",{style:"color:#71717a;text-align:center;margin:8px 0;font-size:13px;line-height:1.5"},[n("noThreadsAuth")]),o=s("div",{class:"heedb-new-msg"}),i=s("button",{},[n("sendAMessage")]);i.onclick=()=>{E="contact",B("contact"),C()},o.appendChild(i),e.append(a,o);return}e.innerHTML="";for(let a=0;a<3;a++){let o=s("div",{class:"heedb-thread-item heedb-skeleton"});o.append(s("div",{class:"heedb-skel-line",style:"width:40%;height:12px"}),s("div",{class:"heedb-skel-line",style:"width:80%;height:13px;margin-top:6px"}),s("div",{class:"heedb-skel-line",style:"width:30%;height:11px;margin-top:4px"})),e.appendChild(o)}try{let{threads:a}=await pe(k);if(e.innerHTML="",e.style.opacity="0",requestAnimationFrame(()=>{e.style.opacity="1"}),a.length===0){let l=s("p",{style:"color:#71717a;text-align:center;margin:8px 0"},[O(r.emptyStateText)||n("noOpenMessages")]);e.appendChild(l)}else for(let l of a){let y=s("span",{class:`heedb-badge heedb-badge-${l.status}`},[l.status]),h=s("div",{class:"heedb-thread-label"},[l.type==="privacy"?n("privacyRequest"):n("message")," \u2022 "]);h.appendChild(y);let c=s("div",{class:"heedb-thread-text"},[(t=l.preview)!=null?t:""]),p=new Date(l.createdAt).toLocaleDateString(),d=s("div",{class:"heedb-thread-meta"},[p]),m=s("div",{class:"heedb-thread-item"});m.append(h,c,d),m.onclick=()=>ve(l.id),e.appendChild(m)}let o=s("div",{class:"heedb-new-msg"}),i=s("button",{},[n("sendNewMessage")]);i.onclick=()=>{E="contact",B("contact"),C()},o.appendChild(i),e.appendChild(o)}catch(a){e.innerHTML=`<p style="color:#ef4444;text-align:center">${n("failedToLoad")}</p>`}}function ve(e){K=e,E="thread-detail",C()}async function Te(e){e.innerHTML="",e.style.padding="12px";let t=s("div",{class:"heedb-skel-line",style:"width:50%;height:13px;margin-bottom:12px"});e.appendChild(t);let a=s("div",{style:"display:flex;flex-direction:column;gap:8px"}),o=["65%","50%","70%","45%"],i=["flex-start","flex-end","flex-start","flex-end"];for(let y=0;y<4;y++){let h=s("div",{style:`display:flex;flex-direction:column;align-items:${i[y]}`});h.appendChild(s("div",{class:"heedb-skel-line",style:`width:${o[y]};height:32px;border-radius:8px`})),a.appendChild(h)}e.appendChild(a);let l=s("button",{class:"heedb-chat-back"},[n("backToMessages")]);l.onclick=()=>{E="threads",B("threads"),C()};try{let h=(await me(K)).messages||[];e.innerHTML="",e.style.padding="12px",e.appendChild(l);let c=s("div",{class:"heedb-chat-messages"});for(let u of h){let x=u.direction==="inbound",T=s("div",{style:`display:flex;flex-direction:column;${x?"align-items:flex-start":"align-items:flex-end"}`}),w=s("div",{class:`heedb-chat-bubble ${x?"heedb-chat-inbound":"heedb-chat-outbound"}`},[we(u.body)]),H=s("div",{class:`heedb-chat-time ${x?"":"heedb-chat-time-right"}`},[ke(u.createdAt)]);T.append(w,H),c.appendChild(T)}e.appendChild(c),requestAnimationFrame(()=>{c.scrollTop=c.scrollHeight});let p=s("div",{class:"heedb-chat-reply"}),d=document.createElement("textarea");d.className="heedb-chat-reply-input",d.placeholder=n("typeReply"),d.rows=1,d.addEventListener("input",()=>{d.style.height="auto",d.style.height=Math.min(d.scrollHeight,80)+"px"});let m=s("button",{class:"heedb-chat-send"},[n("send")]),g=s("div",{class:"heedb-error",style:"display:none;margin-top:4px"});async function v(){let u=d.value.trim();if(u){m.disabled=!0,m.textContent="\u2026",g.style.display="none";try{let x=await ge(K,u);if(x.ok){let T=s("div",{style:"display:flex;flex-direction:column;align-items:flex-start"}),w=s("div",{class:"heedb-chat-bubble heedb-chat-inbound"},[u]),H=s("div",{class:"heedb-chat-time"},[n("justNow")]);T.append(w,H),c.appendChild(T),c.scrollTop=c.scrollHeight,d.value="",d.style.height="auto"}else{let T=await x.json();g.textContent=T.error||n("failedToSend"),g.style.display="block"}}catch(x){g.textContent=n("networkError"),g.style.display="block"}m.disabled=!1,m.textContent=n("send")}}m.onclick=v,d.addEventListener("keydown",u=>{u.key==="Enter"&&!u.shiftKey&&(u.preventDefault(),v())}),p.append(d,m),e.append(p,g),requestAnimationFrame(()=>d.focus())}catch(y){e.innerHTML="",e.appendChild(l),e.appendChild(s("p",{style:"color:#ef4444;text-align:center"},[n("failedToLoadConvo")]))}}function we(e){let t=e.split(`
167
+ `),a=[];for(let o of t){let i=o.trim();if(/^(On|Em|El|Le|Am|Il giorno) .+(<[^>]+@[^>]+>).*(wrote|escreveu|escribi|crit|schrieb|scritto)\s?:$/i.test(i)||/<[^>]+@[^>]+>/.test(i)&&i.endsWith(":")||/^-{3,}$/.test(i))break;/^>{1,}\s/.test(i)||a.push(o)}return a.join(`
168
+ `).trim()}function ke(e){let t=new Date(e),o=new Date().getTime()-t.getTime(),i=Math.floor(o/6e4);if(i<1)return n("justNow");if(i<60)return n("minutesAgo").replace("{mins}",String(i));let l=Math.floor(i/60);return l<24?n("hoursAgo").replace("{hours}",String(l)):t.toLocaleDateString()}function Q(e,t,a){e.innerHTML="";let o=s("div",{class:"heedb-success"});o.innerHTML=`
169
+ <div class="heedb-success-icon">\u2705</div>
154
170
  <h3>${t}</h3>
155
- <p>${n}</p>
156
- `,e.appendChild(l)}let M=null,_=null;function S(e){h=e,M&&M.querySelectorAll(".llp-tab").forEach(t=>{t.classList.toggle("active",t.dataset.mode===e)})}function z(){_&&(_.style.display=b&&y?"":"none")}let B=null;function ge(){u=R(),B&&(B.textContent=O())}async function F(){if(c=await ne(),u=R(),B=document.createElement("style"),B.textContent=O(),document.head.appendChild(B),c.customCSS){let i=document.createElement("style");i.textContent=c.customCSS,document.head.appendChild(i)}c.mode==="system"&&window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{ge(),C&&v&&k()});let e=c.triggerIcon?c.triggerIcon:c.triggerEmoji||"\u{1F4AC}",t=c.triggerText||"";if(H=a("button",{class:"llp-btn",title:"Contact us","aria-label":"Open contact widget"}),c.triggerIcon){let i=a("span",{class:"llp-btn-icon"});i.innerHTML=c.triggerIcon,H.appendChild(i)}else H.appendChild(document.createTextNode(c.triggerEmoji||"\u{1F4AC}"));if(t&&H.appendChild(a("span",{class:"llp-btn-label"},[t])),H.onclick=j,document.body.appendChild(H),c.triggerMode==="embedded"&&c.triggerSelector){let i=document.querySelector(c.triggerSelector);i&&i.addEventListener("click",g=>{g.preventDefault(),j()})}if(c.triggerMode==="tag"){let i=a("button",{class:"llp-tag","aria-label":"Open contact widget"}),g=a("span",{class:"llp-tag-icon"},[c.triggerEmoji||"\u{1F4AC}"]);i.appendChild(g),i.appendChild(document.createTextNode(c.triggerText||"Feedback")),i.onclick=j,document.body.appendChild(i)}v=a("div",{class:"llp-panel",style:"display:none"});let n=a("div",{class:"llp-header"}),l=a("h2",{},[c.headerTitle||"Contact us"]),o=a("button",{class:"llp-close","aria-label":"Close"},["\u2715"]);o.onclick=j,n.append(l,o),M=a("div",{class:"llp-tabs"});let r=a("button",{class:"llp-tab active","data-mode":"contact"},["Message"]),d=a("button",{class:"llp-tab","data-mode":"privacy"},["Privacy"]);_=a("button",{class:"llp-tab","data-mode":"threads"},["Messages"]),_.style.display=b&&y?"":"none",r.onclick=()=>{S("contact"),k()},d.onclick=()=>{S("privacy"),k()},_.onclick=()=>{S("threads"),k()},M.append(r,d,_);let m=a("div",{class:"llp-body"}),p=a("div",{class:"llp-footer"}),s=a("a",{href:"https://heedb.com",target:"_blank",rel:"noopener noreferrer"},["Powered by Heedb"]);p.appendChild(s),v.append(n,M,m,p),document.body.appendChild(v)}function j(){C=!C,v&&(v.style.display=C?"flex":"none",C&&(b&&y&&h!=="privacy"&&h!=="thread-detail"&&(h="threads",S("threads")),k()))}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",F):F()})();})();
171
+ <p>${a}</p>
172
+ `,e.appendChild(o)}let $=null,D=null;function B(e){E=e,$&&$.querySelectorAll(".heedb-tab").forEach(t=>{t.classList.toggle("active",t.dataset.mode===e)})}function q(){D&&(D.style.display=k&&M?"":"none")}let I=null;function Z(){b=J(),I&&(I.textContent=X())}async function ee(){if(r=await ue(),R=G(),b=J(),I=document.createElement("style"),I.textContent=X(),document.head.appendChild(I),r.customCSS){let g=document.createElement("style");g.textContent=r.customCSS,document.head.appendChild(g)}r.mode==="system"&&window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{Z(),S&&f&&C()});let e=r.triggerIcon?r.triggerIcon:r.triggerEmoji||"\u{1F4AC}",t=r.triggerText||"";if(_=s("button",{class:"heedb-btn",title:n("contactUs"),"aria-label":"Open contact widget"}),r.triggerIcon){let g=s("span",{class:"heedb-btn-icon"}),u=new DOMParser().parseFromString(r.triggerIcon,"image/svg+xml").querySelector("svg");if(u){u.querySelectorAll("script,foreignObject,iframe,object,embed").forEach(w=>w.remove());let x=document.createTreeWalker(u,NodeFilter.SHOW_ELEMENT),T;for(;T=x.nextNode();)for(let w of Array.from(T.attributes))(w.name.startsWith("on")||/^\s*javascript:/i.test(w.value))&&T.removeAttribute(w.name);g.appendChild(u)}_.appendChild(g)}else _.appendChild(document.createTextNode(r.triggerEmoji||"\u{1F4AC}"));if(t&&_.appendChild(s("span",{class:"heedb-btn-label"},[t])),_.onclick=V,document.body.appendChild(_),r.triggerMode==="embedded"&&r.triggerSelector){let g=document.querySelector(r.triggerSelector);g&&g.addEventListener("click",v=>{v.preventDefault(),V()})}if(r.triggerMode==="tag"){let g=s("button",{class:"heedb-tag","aria-label":"Open contact widget"}),v=s("span",{class:"heedb-tag-icon"});if(r.triggerIcon){let x=new DOMParser().parseFromString(r.triggerIcon,"image/svg+xml").querySelector("svg");if(x){x.querySelectorAll("script,foreignObject,iframe,object,embed").forEach(H=>H.remove());let T=document.createTreeWalker(x,NodeFilter.SHOW_ELEMENT),w;for(;w=T.nextNode();)for(let H of Array.from(w.attributes))(H.name.startsWith("on")||/^\s*javascript:/i.test(H.value))&&w.removeAttribute(H.name);v.appendChild(x)}}else v.appendChild(document.createTextNode(r.triggerEmoji||"\u{1F4AC}"));g.appendChild(v),g.appendChild(document.createTextNode(r.triggerText||n("feedback"))),g.onclick=V,document.body.appendChild(g)}f=s("div",{class:"heedb-panel",style:"display:none"});let a=s("div",{class:"heedb-header"}),o=s("h2",{},[r.headerTitle||n("contactUs")]),i=s("button",{class:"heedb-close","aria-label":"Close"},["\u2715"]);i.onclick=V,a.append(o,i),$=s("div",{class:"heedb-tabs"});let l=s("button",{class:"heedb-tab active","data-mode":"contact"},[O(r.contactTabLabel)||n("contactTab")]),h=r.showPrivacyTab!==!1?s("button",{class:"heedb-tab","data-mode":"privacy"},[n("privacyTab")]):null;D=s("button",{class:"heedb-tab","data-mode":"threads"},[n("messagesTab")]),D.style.display=k&&M?"":"none",l.onclick=()=>{B("contact"),C()},h&&(h.onclick=()=>{B("privacy"),C()}),D.onclick=()=>{B("threads"),C()},$.append(l),h&&$.append(h),$.append(D);let c=s("div",{class:"heedb-body"}),p=s("div",{class:"heedb-footer"}),d=new URLSearchParams({utm_source:"widget",utm_medium:"heedb-widget",utm_campaign:window.location.hostname}),m=s("a",{href:`https://heedb.com?${d.toString()}`,target:"_blank",rel:"noopener noreferrer"},[n("poweredBy")]);p.appendChild(m),f.append(a,$,c,p),document.body.appendChild(f)}function V(){S=!S,f&&(S?(f.style.display="flex",f.style.opacity="0",f.style.transform="translateY(8px)",requestAnimationFrame(()=>{f.style.opacity="1",f.style.transform="translateY(0)"}),k&&M&&E!=="privacy"&&E!=="thread-detail"&&(E="threads",B("threads")),C()):(f.style.opacity="0",f.style.transform="translateY(8px)",setTimeout(()=>{!S&&f&&(f.style.display="none")},150)))}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",ee):ee()})();})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heedb/web-sdk",
3
- "version": "0.1.7",
3
+ "version": "1.0.1",
4
4
  "description": "Drop-in feedback widget with email conversations for any website",
5
5
  "license": "MIT",
6
6
  "repository": {
package/widget.js CHANGED
@@ -1,156 +1,172 @@
1
- /* Heedb Widget v0.1.7 — https://heedb.com */
2
- "use strict";(()=>{(function(){var W,U,K,J,V;let w=document.currentScript||document.querySelector("script[data-api-key]"),E=(W=w==null?void 0:w.getAttribute("data-api-key"))!=null?W:"",N=(U=w==null?void 0:w.src)!=null?U:"",I=(w==null?void 0:w.getAttribute("data-host"))||(N?new URL(N).origin:"");if(!E){console.warn("[Heedb] Missing data-api-key on <script> tag.");return}let c={},u=!1,X={primary:"#18181b",text:"#18181b",bg:"#ffffff"},G={primary:"#e4e4e7",text:"#e4e4e7",bg:"#1a1a1a"};function R(){return c.mode==="dark"?!0:c.mode==="light"?!1:c.mode==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches:!1}function Y(){return u?G:X}function $(e,t){let n=c[e];return n!=null?String(n):t}let C=!1,h="contact",A="",L=(K=localStorage.getItem("heedb_name"))!=null?K:"",b=(J=localStorage.getItem("heedb_email"))!=null?J:"",y=(V=localStorage.getItem("heedb_token"))!=null?V:"",v=null,H=null;async function Q(e,t){try{let n=await D("/api/threads/token",{api_key:E,email:e,userHash:t});if(n.ok){let l=await n.json();if(l.widgetToken){y=l.widgetToken,localStorage.setItem("heedb_token",l.widgetToken);return}}y="",localStorage.removeItem("heedb_token")}catch(n){y="",localStorage.removeItem("heedb_token")}}window.Heedb={version:"0.1.7",init(e={}){e.name&&(L=e.name,localStorage.setItem("heedb_name",e.name)),e.email&&(b=e.email,localStorage.setItem("heedb_email",e.email),e.userHash?Q(e.email,e.userHash).then(()=>{z(),C&&v&&k()}):(z(),C&&v&&k()))},reset(){L="",b="",y="",localStorage.removeItem("heedb_name"),localStorage.removeItem("heedb_email"),localStorage.removeItem("heedb_token"),h="contact",C=!1,v&&(v.style.display="none"),z()}};function D(e,t){return fetch(`${I}${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}function Z(e){let t=new URL(`${I}/api/threads`);return t.searchParams.set("api_key",E),t.searchParams.set("email",e),y&&t.searchParams.set("token",y),fetch(t.toString()).then(n=>n.json())}function ee(e){let t=new URL(`${I}/api/threads/${e}`);return t.searchParams.set("api_key",E),t.searchParams.set("email",b),t.searchParams.set("token",y),fetch(t.toString()).then(n=>n.json())}function te(e,t){return D(`/api/threads/${e}/reply`,{api_key:E,email:b,token:y,message:t})}async function ne(){var e;try{let t=new URL(`${I}/api/widget-config`);t.searchParams.set("api_key",E);let n=await fetch(t.toString());if(n.ok)return(e=(await n.json()).config)!=null?e:{}}catch(t){}return{}}function O(){var f,x;let e=Y(),t=$(u?"darkPrimaryColor":"primaryColor",e.primary),n=$(u?"darkTextColor":"textColor",e.text),l=$(u?"darkBgColor":"bgColor",e.bg),o=(f=c.borderRadius)!=null?f:16,r=(x=c.buttonRadius)!=null?x:50,d=c.fontFamily||"system-ui, -apple-system, sans-serif",m=c.position==="bottom-left",p=r>=50?"50%":`${r}px`,s=Math.round(o*.5),i=c.triggerMode==="tag",g=c.triggerMode==="embedded"||i;return`
3
- .llp-btn {
4
- position: fixed; bottom: 24px; ${m?"left: 24px":"right: 24px"}; z-index: 999998;
5
- width: 52px; height: 52px; border-radius: ${p}; border: none;
1
+ /* Heedb Widget v1.0.1 — https://heedb.com */
2
+ "use strict";(()=>{(function(){var te,ae,ne,se,oe;let L=document.currentScript||document.querySelector("script[data-api-key]"),A=(te=L==null?void 0:L.getAttribute("data-api-key"))!=null?te:"",Y=(ae=L==null?void 0:L.src)!=null?ae:"",z=(L==null?void 0:L.getAttribute("data-host"))||(Y?new URL(Y).origin:"");if(!A){console.warn("[Heedb] Missing data-api-key on <script> tag.");return}let ie=1,r={},b=!1,re={primary:"#18181b",text:"#18181b",bg:"#ffffff"},le={primary:"#e4e4e7",text:"#e4e4e7",bg:"#1a1a1a"},j={en:{contactTab:"Message",privacyTab:"Privacy",messagesTab:"Messages",nameLabel:"Name",emailLabel:"Email",messageLabel:"Message",namePlaceholder:"Jane Smith",emailPlaceholder:"jane@example.com",messagePlaceholder:"How can we help?",sendMessage:"Send message",sending:"Sending\u2026",fillAllFields:"Please fill in all fields.",messageSentTitle:"Message sent!",messageSentBody:"We'll get back to you soon. Check your inbox for a confirmation email.",networkError:"Network error. Please try again.",somethingWrong:"Something went wrong.",rateLimited:"Too many messages. Please wait a moment.",requestType:"Request type",deleteData:"Delete my data",accessData:"Access my data",exportData:"Export my data",correctData:"Correct my data",restrictProcessing:"Restrict processing",objectProcessing:"Object to processing",other:"Other",submitRequest:"Submit request",submitting:"Submitting\u2026",requestSubmittedTitle:"Request submitted!",requestSubmittedBody:"Your privacy request has been received. We'll respond within 30 days.",contactUs:"Contact us",feedback:"Feedback",poweredBy:"Powered by Heedb",justNow:"Just now",minutesAgo:"{mins}m ago",hoursAgo:"{hours}h ago",send:"Send",backToMessages:"\u2190 Back to messages",noThreadsAuth:"Send a message below to view your message history.",sendAMessage:"+ Send a message",sendNewMessage:"+ Send a new message",noOpenMessages:"No open messages yet.",loading:"Loading\u2026",failedToLoad:"Failed to load messages.",failedToLoadConvo:"Failed to load conversation.",failedToSend:"Failed to send.",typeReply:"Type a reply\u2026",privacyRequest:"Privacy request",message:"Message"},es:{contactTab:"Mensaje",privacyTab:"Privacidad",messagesTab:"Mensajes",nameLabel:"Nombre",emailLabel:"Correo",messageLabel:"Mensaje",namePlaceholder:"Mar\xEDa Garc\xEDa",emailPlaceholder:"maria@empresa.com",messagePlaceholder:"\xBFC\xF3mo podemos ayudarte?",sendMessage:"Enviar mensaje",sending:"Enviando\u2026",fillAllFields:"Por favor, completa todos los campos.",messageSentTitle:"\xA1Mensaje enviado!",messageSentBody:"Te responderemos pronto. Revisa tu bandeja de entrada para un correo de confirmaci\xF3n.",networkError:"Error de red. Int\xE9ntalo de nuevo.",somethingWrong:"Algo sali\xF3 mal.",rateLimited:"Demasiados mensajes. Espera un momento.",requestType:"Tipo de solicitud",deleteData:"Eliminar mis datos",accessData:"Acceder a mis datos",exportData:"Exportar mis datos",correctData:"Corregir mis datos",restrictProcessing:"Restringir procesamiento",objectProcessing:"Oponerse al procesamiento",other:"Otro",submitRequest:"Enviar solicitud",submitting:"Enviando\u2026",requestSubmittedTitle:"\xA1Solicitud enviada!",requestSubmittedBody:"Tu solicitud de privacidad ha sido recibida. Responderemos en un plazo de 30 d\xEDas.",contactUs:"Cont\xE1ctanos",feedback:"Comentarios",poweredBy:"Impulsado por Heedb",justNow:"Ahora",minutesAgo:"hace {mins}m",hoursAgo:"hace {hours}h",send:"Enviar",backToMessages:"\u2190 Volver a mensajes",noThreadsAuth:"Env\xEDa un mensaje para ver tu historial.",sendAMessage:"+ Enviar un mensaje",sendNewMessage:"+ Enviar un nuevo mensaje",noOpenMessages:"No hay mensajes a\xFAn.",loading:"Cargando\u2026",failedToLoad:"No se pudieron cargar los mensajes.",failedToLoadConvo:"No se pudo cargar la conversaci\xF3n.",failedToSend:"No se pudo enviar.",typeReply:"Escribe una respuesta\u2026",privacyRequest:"Solicitud de privacidad",message:"Mensaje"},pt:{contactTab:"Mensagem",privacyTab:"Privacidade",messagesTab:"Mensagens",nameLabel:"Nome",emailLabel:"Email",messageLabel:"Mensagem",namePlaceholder:"Maria Silva",emailPlaceholder:"maria@empresa.com",messagePlaceholder:"Como podemos ajudar?",sendMessage:"Enviar mensagem",sending:"Enviando\u2026",fillAllFields:"Por favor, preencha todos os campos.",messageSentTitle:"Mensagem enviada!",messageSentBody:"Responderemos em breve. Verifique sua caixa de entrada para um email de confirma\xE7\xE3o.",networkError:"Erro de rede. Tente novamente.",somethingWrong:"Algo deu errado.",rateLimited:"Muitas mensagens. Aguarde um momento.",requestType:"Tipo de solicita\xE7\xE3o",deleteData:"Excluir meus dados",accessData:"Acessar meus dados",exportData:"Exportar meus dados",correctData:"Corrigir meus dados",restrictProcessing:"Restringir processamento",objectProcessing:"Opor-se ao processamento",other:"Outro",submitRequest:"Enviar solicita\xE7\xE3o",submitting:"Enviando\u2026",requestSubmittedTitle:"Solicita\xE7\xE3o enviada!",requestSubmittedBody:"Sua solicita\xE7\xE3o de privacidade foi recebida. Responderemos em at\xE9 30 dias.",contactUs:"Fale conosco",feedback:"Feedback",poweredBy:"Powered by Heedb",justNow:"Agora",minutesAgo:"h\xE1 {mins}m",hoursAgo:"h\xE1 {hours}h",send:"Enviar",backToMessages:"\u2190 Voltar \xE0s mensagens",noThreadsAuth:"Envie uma mensagem para ver seu hist\xF3rico.",sendAMessage:"+ Enviar uma mensagem",sendNewMessage:"+ Enviar uma nova mensagem",noOpenMessages:"Nenhuma mensagem ainda.",loading:"Carregando\u2026",failedToLoad:"N\xE3o foi poss\xEDvel carregar as mensagens.",failedToLoadConvo:"N\xE3o foi poss\xEDvel carregar a conversa.",failedToSend:"N\xE3o foi poss\xEDvel enviar.",typeReply:"Digite uma resposta\u2026",privacyRequest:"Solicita\xE7\xE3o de privacidade",message:"Mensagem"}},R="en";function n(e){var t,a,o;return(o=(a=(t=j[R])==null?void 0:t[e])!=null?a:j.en[e])!=null?o:e}function O(e){if(e)return e[R]||e.en}function G(){var a;let e=L==null?void 0:L.getAttribute("data-lang");if(e&&e in j)return e;if(F&&F in j)return F;if(r.language&&r.language in j)return r.language;let t=(a=document.documentElement.lang)==null?void 0:a.slice(0,2);return t&&t in j?t:"en"}let F;function J(){return r.mode==="dark"?!0:r.mode==="light"?!1:r.mode==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches:!1}function de(){return b?le:re}function N(e,t){let a=r[e];return a!=null?String(a):t}let S=!1,E="contact",K="",P=(ne=localStorage.getItem("heedb_name"))!=null?ne:"",k=(se=localStorage.getItem("heedb_email"))!=null?se:"",M=(oe=localStorage.getItem("heedb_token"))!=null?oe:"",f=null,_=null;async function ce(e,t){try{let a=await W("/api/threads/token",{api_key:A,email:e,userHash:t});if(a.ok){let o=await a.json();if(o.widgetToken){M=o.widgetToken,localStorage.setItem("heedb_token",o.widgetToken);return}}M="",localStorage.removeItem("heedb_token")}catch(a){M="",localStorage.removeItem("heedb_token")}}window.Heedb={version:"1.0.1",init(e={}){e.lang&&(F=e.lang,R=G(),Z(),S&&f&&C()),e.name&&(P=e.name,localStorage.setItem("heedb_name",e.name)),e.email&&(k=e.email,localStorage.setItem("heedb_email",e.email),e.userHash?ce(e.email,e.userHash).then(()=>{q(),S&&f&&C()}):(q(),S&&f&&C()))},reset(){P="",k="",M="",localStorage.removeItem("heedb_name"),localStorage.removeItem("heedb_email"),localStorage.removeItem("heedb_token"),E="contact",S=!1,f&&(f.style.display="none"),q()}};function W(e,t){return fetch(`${z}${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}function pe(e){let t=new URL(`${z}/api/threads`);return t.searchParams.set("api_key",A),t.searchParams.set("email",e),M&&t.searchParams.set("token",M),fetch(t.toString()).then(a=>a.json())}function me(e){let t=new URL(`${z}/api/threads/${e}`);return t.searchParams.set("api_key",A),t.searchParams.set("email",k),t.searchParams.set("token",M),fetch(t.toString()).then(a=>a.json())}function ge(e,t){return W(`/api/threads/${e}/reply`,{api_key:A,email:k,token:M,message:t})}async function ue(){var e;try{let t=new URL(`${z}/api/widget-config`);t.searchParams.set("api_key",A),t.searchParams.set("v",String(ie));let a=await fetch(t.toString());if(a.ok)return(e=(await a.json()).config)!=null?e:{}}catch(t){}return{}}function X(){var g,v;let e=de(),t=N(b?"darkPrimaryColor":"primaryColor",e.primary),a=N(b?"darkTextColor":"textColor",e.text),o=N(b?"darkBgColor":"bgColor",e.bg),i=(g=r.borderRadius)!=null?g:16,l=(v=r.buttonRadius)!=null?v:50,y=r.fontFamily||"system-ui, -apple-system, sans-serif",h=r.position==="bottom-left",c=l>=50?"50%":`${l}px`,p=Math.round(i*.5),d=r.triggerMode==="tag",m=r.triggerMode==="embedded"||d;return`
3
+ .heedb-btn {
4
+ position: fixed; bottom: 24px; ${h?"left: 24px":"right: 24px"}; z-index: 999998;
5
+ width: 52px; height: 52px; border-radius: ${c}; border: none;
6
6
  background: ${t}; color: #fff; font-size: 22px; cursor: pointer;
7
7
  box-shadow: 0 4px 16px rgba(0,0,0,.25);
8
- display: ${g?"none":"flex"}; align-items: center; justify-content: center;
9
- transition: transform .15s;
10
- }
11
- .llp-btn:hover { transform: scale(1.08); }
12
- .llp-btn-label { font-size: 14px; font-weight: 600; margin-left: 6px; }
13
- .llp-btn-icon { display: flex; align-items: center; justify-content: center; }
14
- .llp-btn-icon svg { width: 22px; height: 22px; fill: currentColor; }
15
- .llp-btn:has(.llp-btn-label) { width: auto; padding: 0 18px; gap: 4px; }
16
- .llp-tag {
17
- position: fixed !important; ${m?"left: 0 !important":"right: 0 !important"}; top: 50% !important; z-index: 999998 !important;
18
- transform: ${m?"rotate(90deg) translateX(-50%)":"rotate(-90deg) translateX(50%)"} !important;
19
- transform-origin: ${m?"left bottom":"right bottom"} !important;
8
+ display: ${m?"none":"flex"}; align-items: center; justify-content: center;
9
+ font-family: ${y}; transition: transform .15s;
10
+ }
11
+ .heedb-btn:hover { transform: scale(1.08); }
12
+ .heedb-btn-label { font-size: 14px; font-weight: 600; margin-left: 6px; }
13
+ .heedb-btn-icon { display: flex; align-items: center; justify-content: center; }
14
+ .heedb-btn-icon svg { width: 22px; height: 22px; fill: currentColor; }
15
+ .heedb-btn:has(.heedb-btn-label) { width: auto; padding: 0 18px; gap: 4px; }
16
+ .heedb-tag {
17
+ position: fixed !important; ${h?"left: 0 !important":"right: 0 !important"}; top: 50% !important; z-index: 999998 !important;
18
+ transform: ${h?"rotate(90deg) translateX(-50%)":"rotate(-90deg) translateX(50%)"} !important;
19
+ transform-origin: ${h?"left bottom":"right bottom"} !important;
20
20
  background: ${t}; color: #fff; border: none; cursor: pointer;
21
21
  padding: 8px 18px; font-size: 13px; font-weight: 600;
22
- font-family: ${d};
23
- border-radius: ${Math.min(r,12)}px ${Math.min(r,12)}px 0 0;
22
+ font-family: ${y};
23
+ border-radius: ${Math.min(l,12)}px ${Math.min(l,12)}px 0 0;
24
24
  box-shadow: 0 2px 12px rgba(0,0,0,.2);
25
25
  display: flex; align-items: center; gap: 6px;
26
26
  transition: opacity .15s;
27
27
  }
28
- .llp-tag:hover { opacity: .9; }
29
- .llp-tag-icon { font-size: 16px; }
30
- .llp-panel {
31
- position: fixed; bottom: 88px; ${m?"left: 24px":"right: 24px"}; z-index: 999999;
32
- width: 370px; max-height: 560px; border-radius: ${o}px;
33
- background: ${l}; box-shadow: 0 8px 32px rgba(0,0,0,.18);
28
+ .heedb-tag:hover { opacity: .9; }
29
+ .heedb-tag-icon { font-size: 16px; }
30
+ .heedb-tag-icon svg { width: 16px; height: 16px; fill: currentColor; }
31
+ .heedb-panel {
32
+ position: fixed; bottom: 88px; ${h?"left: 24px":"right: 24px"}; z-index: 999999;
33
+ width: 280px; max-height: 560px; border-radius: ${i}px;
34
+ background: ${o}; box-shadow: 0 8px 32px rgba(0,0,0,.18);
34
35
  display: flex; flex-direction: column; overflow: hidden;
35
- font-family: ${d}; font-size: 14px; color: ${n};
36
+ font-family: ${y}; font-size: 14px; color: ${a};
36
37
  transition: opacity .15s, transform .15s;
37
38
  }
38
- .llp-header {
39
+ .heedb-header {
39
40
  background: ${t}; color: #fff; padding: 14px 16px;
40
41
  display: flex; align-items: center; justify-content: space-between;
41
42
  }
42
- .llp-header h2 { margin: 0; font-size: 15px; font-weight: 600; }
43
- .llp-close {
43
+ .heedb-header h2 { margin: 0; font-size: 15px; font-weight: 600; }
44
+ .heedb-close {
44
45
  background: none; border: none; color: #fff; cursor: pointer;
45
46
  font-size: 18px; line-height: 1; padding: 0;
46
47
  }
47
- .llp-tabs {
48
- display: flex; border-bottom: 1px solid ${u?"#333":"#e4e4e7"};
48
+ .heedb-tabs {
49
+ display: flex; border-bottom: 1px solid ${b?"#333":"#e4e4e7"};
49
50
  }
50
- .llp-tab {
51
+ .heedb-tab {
51
52
  flex: 1; padding: 10px 0; border: none; background: none;
52
53
  cursor: pointer; font-size: 13px; font-weight: 500; color: #71717a;
53
54
  border-bottom: 2px solid transparent; margin-bottom: -1px;
54
55
  }
55
- .llp-tab.active { color: ${n}; border-bottom-color: ${t}; }
56
- .llp-body { padding: 16px; overflow-y: auto; flex: 1; }
57
- .llp-label { display: block; font-size: 12px; font-weight: 600; color: #52525b; margin-bottom: 4px; }
58
- .llp-input, .llp-textarea, .llp-select {
56
+ .heedb-tab.active { color: ${a}; border-bottom-color: ${t}; }
57
+ .heedb-body { padding: 16px; overflow-y: auto; flex: 1; }
58
+ .heedb-label { display: block; font-size: 12px; font-weight: 600; color: #52525b; margin-bottom: 4px; }
59
+ .heedb-input, .heedb-textarea, .heedb-select {
59
60
  width: 100%; box-sizing: border-box; padding: 8px 10px;
60
- border: 1px solid ${u?"#444":"#d4d4d8"}; border-radius: ${s}px;
61
- font-size: 13px; color: ${n}; margin-bottom: 10px;
62
- font-family: inherit; background: ${u?"#222":l};
61
+ border: 1px solid ${b?"#444":"#d4d4d8"}; border-radius: ${p}px;
62
+ font-size: 13px; color: ${a}; margin-bottom: 10px;
63
+ font-family: inherit; background: ${b?"#222":o};
63
64
  }
64
- .llp-textarea { min-height: 80px; resize: vertical; }
65
- .llp-input:focus, .llp-textarea:focus, .llp-select:focus {
65
+ .heedb-textarea { min-height: 80px; resize: vertical; }
66
+ .heedb-input:focus, .heedb-textarea:focus, .heedb-select:focus {
66
67
  outline: none; border-color: ${t};
67
68
  }
68
- .llp-btn-submit {
69
+ .heedb-btn-submit {
69
70
  width: 100%; padding: 10px; background: ${t}; color: #fff;
70
- border: none; border-radius: ${s}px; font-size: 14px; font-weight: 600;
71
+ border: none; border-radius: ${p}px; font-size: 14px; font-weight: 600;
71
72
  cursor: pointer; transition: opacity .15s;
72
73
  }
73
- .llp-btn-submit:hover { opacity: .85; }
74
- .llp-btn-submit:disabled { opacity: .5; cursor: not-allowed; }
75
- .llp-error { color: #ef4444; font-size: 12px; margin-bottom: 8px; }
76
- .llp-success { text-align: center; padding: 24px 8px; }
77
- .llp-success-icon { font-size: 36px; }
78
- .llp-success h3 { margin: 12px 0 6px; font-size: 15px; color: ${n}; }
79
- .llp-success p { margin: 0; color: #71717a; font-size: 13px; line-height: 1.5; }
80
- .llp-thread-item {
81
- padding: 10px 12px; border: 1px solid ${u?"#333":"#e4e4e7"}; border-radius: ${s}px;
74
+ .heedb-btn-submit:hover { opacity: .85; }
75
+ .heedb-btn-submit:disabled { opacity: .5; cursor: not-allowed; }
76
+ .heedb-error { color: #ef4444; font-size: 12px; margin-bottom: 8px; }
77
+ .heedb-success { text-align: center; padding: 24px 8px; }
78
+ .heedb-success-icon { font-size: 36px; }
79
+ .heedb-success h3 { margin: 12px 0 6px; font-size: 15px; color: ${a}; }
80
+ .heedb-success p { margin: 0; color: #71717a; font-size: 13px; line-height: 1.5; }
81
+ .heedb-thread-item {
82
+ padding: 10px 12px; border: 1px solid ${b?"#333":"#e4e4e7"}; border-radius: ${p}px;
82
83
  margin-bottom: 8px; cursor: pointer; display: block; color: inherit;
83
84
  transition: background .1s; background: none;
84
85
  }
85
- .llp-thread-item:hover { background: ${u?"#252525":"#f4f4f5"}; }
86
- .llp-thread-label { font-size: 12px; color: #71717a; margin-bottom: 2px; }
87
- .llp-thread-text { font-size: 13px; color: ${n}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
88
- .llp-thread-meta { font-size: 11px; color: #a1a1aa; margin-top: 3px; }
89
- .llp-badge { display: inline-block; padding: 1px 6px; border-radius: 9999px; font-size: 10px; font-weight: 600; }
90
- .llp-badge-open { background: #d1fae5; color: #065f46; }
91
- .llp-badge-replied { background: #dbeafe; color: #1e40af; }
92
- .llp-new-msg { margin-top: 12px; padding-top: 12px; border-top: 1px solid ${u?"#333":"#e4e4e7"}; }
93
- .llp-new-msg button {
94
- width: 100%; padding: 8px; background: none; border: 1px solid ${u?"#444":"#d4d4d8"};
95
- border-radius: ${s}px; font-size: 13px; cursor: pointer; color: ${u?"#999":"#52525b"};
96
- }
97
- .llp-new-msg button:hover { background: ${u?"#252525":"#f4f4f5"}; }
98
- .llp-footer {
99
- padding: 6px 16px; text-align: center; border-top: 1px solid ${u?"#333":"#f0f0f0"};
100
- }
101
- .llp-footer a {
86
+ .heedb-thread-item:hover { background: ${b?"#252525":"#f4f4f5"}; }
87
+ .heedb-thread-label { font-size: 12px; color: #71717a; margin-bottom: 2px; }
88
+ .heedb-thread-text { font-size: 13px; color: ${a}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
89
+ .heedb-thread-meta { font-size: 11px; color: #a1a1aa; margin-top: 3px; }
90
+ .heedb-badge { display: inline-block; padding: 1px 6px; border-radius: 9999px; font-size: 10px; font-weight: 600; }
91
+ .heedb-badge-open { background: #d1fae5; color: #065f46; }
92
+ .heedb-badge-replied { background: #dbeafe; color: #1e40af; }
93
+ .heedb-new-msg { margin-top: 12px; padding-top: 12px; border-top: 1px solid ${b?"#333":"#e4e4e7"}; }
94
+ .heedb-new-msg button {
95
+ width: 100%; padding: 8px; background: none; border: 1px solid ${b?"#444":"#d4d4d8"};
96
+ border-radius: ${p}px; font-size: 13px; cursor: pointer; color: ${b?"#999":"#52525b"};
97
+ }
98
+ .heedb-new-msg button:hover { background: ${b?"#252525":"#f4f4f5"}; }
99
+ .heedb-footer {
100
+ padding: 6px 16px; text-align: center; border-top: 1px solid ${b?"#333":"#f0f0f0"};
101
+ }
102
+ .heedb-footer a {
102
103
  font-size: 10px; color: #a1a1aa; text-decoration: none; font-weight: 500;
103
104
  }
104
- .llp-footer a:hover { color: #71717a; text-decoration: underline; }
105
+ .heedb-footer a:hover { color: #71717a; text-decoration: underline; }
105
106
 
106
107
  /* Chat view */
107
- .llp-chat-back {
108
+ .heedb-chat-back {
108
109
  background: none; border: none; cursor: pointer; font-size: 13px;
109
110
  color: ${t}; padding: 0; margin-bottom: 12px; font-weight: 500;
110
111
  display: flex; align-items: center; gap: 4px;
111
112
  }
112
- .llp-chat-back:hover { text-decoration: underline; }
113
- .llp-chat-messages {
113
+ .heedb-chat-back:hover { text-decoration: underline; }
114
+ .heedb-chat-messages {
114
115
  display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px;
115
116
  max-height: 320px; overflow-y: auto;
116
117
  }
117
- .llp-chat-bubble {
118
- padding: 8px 12px; border-radius: ${Math.max(s,8)}px; font-size: 13px;
118
+ .heedb-chat-bubble {
119
+ padding: 8px 12px; border-radius: ${Math.max(p,8)}px; font-size: 13px;
119
120
  line-height: 1.45; max-width: 85%; word-wrap: break-word;
120
121
  white-space: pre-wrap;
121
122
  }
122
- .llp-chat-inbound {
123
- background: ${u?"#252525":"#f4f4f5"}; color: ${n}; align-self: flex-start;
123
+ .heedb-chat-inbound {
124
+ background: ${b?"#252525":"#f4f4f5"}; color: ${a}; align-self: flex-start;
124
125
  border-bottom-left-radius: 4px;
125
126
  }
126
- .llp-chat-outbound {
127
+ .heedb-chat-outbound {
127
128
  background: ${t}; color: #fff; align-self: flex-end;
128
129
  border-bottom-right-radius: 4px;
129
130
  }
130
- .llp-chat-time {
131
+ .heedb-chat-time {
131
132
  font-size: 10px; color: #a1a1aa; margin-top: 2px;
132
133
  }
133
- .llp-chat-time-right { text-align: right; }
134
- .llp-chat-reply {
135
- display: flex; gap: 8px; border-top: 1px solid ${u?"#333":"#e4e4e7"}; padding-top: 12px;
134
+ .heedb-chat-time-right { text-align: right; }
135
+ .heedb-chat-reply {
136
+ display: flex; gap: 8px; border-top: 1px solid ${b?"#333":"#e4e4e7"}; padding-top: 12px;
136
137
  }
137
- .llp-chat-reply-input {
138
- flex: 1; padding: 8px 10px; border: 1px solid ${u?"#444":"#d4d4d8"}; border-radius: ${s}px;
139
- font-size: 13px; font-family: inherit; color: ${n}; background: ${u?"#222":l};
138
+ .heedb-chat-reply-input {
139
+ flex: 1; padding: 8px 10px; border: 1px solid ${b?"#444":"#d4d4d8"}; border-radius: ${p}px;
140
+ font-size: 13px; font-family: inherit; color: ${a}; background: ${b?"#222":o};
140
141
  resize: none; min-height: 36px; max-height: 80px; box-sizing: border-box;
141
142
  }
142
- .llp-chat-reply-input:focus { outline: none; border-color: ${t}; }
143
- .llp-chat-send {
143
+ .heedb-chat-reply-input:focus { outline: none; border-color: ${t}; }
144
+ .heedb-chat-send {
144
145
  padding: 8px 14px; background: ${t}; color: #fff; border: none;
145
- border-radius: ${s}px; font-size: 13px; font-weight: 600; cursor: pointer;
146
+ border-radius: ${p}px; font-size: 13px; font-weight: 600; cursor: pointer;
146
147
  transition: opacity .15s; white-space: nowrap; align-self: flex-end;
147
148
  }
148
- .llp-chat-send:hover { opacity: .85; }
149
- .llp-chat-send:disabled { opacity: .5; cursor: not-allowed; }
150
- `}function a(e,t={},n=[]){let l=document.createElement(e);for(let[o,r]of Object.entries(t))o==="class"?l.className=r:o==="style"?l.setAttribute("style",r):o.startsWith("on")&&typeof r=="function"?l.addEventListener(o.slice(2),r):l.setAttribute(o,String(r));for(let o of n)l.appendChild(typeof o=="string"?document.createTextNode(o):o);return l}function P(e,t,n=""){let l=document.createElement("input");return l.type=e,l.id=t,l.placeholder=n,l.className="llp-input",l}function ae(e,t=""){let n=document.createElement("textarea");return n.id=e,n.placeholder=t,n.className="llp-textarea",n}function oe(e,t){let n=document.createElement("select");n.id=e,n.className="llp-select";for(let l of t){let o=document.createElement("option");o.value=l.value,o.textContent=l.label,n.appendChild(o)}return n}function k(){if(!v)return;let e=v.querySelector(".llp-body");e.innerHTML="",h==="contact"?le(e):h==="privacy"?ie(e):h==="threads"?re(e):h==="thread-detail"&&ce(e),M&&(M.style.display=h==="thread-detail"?"none":"flex")}function le(e,t=""){let n=!!(L&&b),l=a("label",{class:"llp-label"},["Name"]),o=P("text","llp-name","Jane Smith");L&&(o.value=L);let r=a("label",{class:"llp-label"},["Email"]),d=P("email","llp-email","jane@example.com");(t||b)&&(d.value=t||b);let m=a("label",{class:"llp-label"},["Message"]),p=ae("llp-message","How can we help?"),s=a("div",{class:"llp-error",style:"display:none"}),i=a("button",{class:"llp-btn-submit"},["Send message"]);i.onclick=async()=>{let g=o.value.trim(),f=d.value.trim(),x=p.value.trim();if(s.style.display="none",!g||!f||!x){s.textContent="Please fill in all fields.",s.style.display="block";return}i.disabled=!0,i.textContent="Sending\u2026";try{let T=await D("/api/contact",{api_key:E,name:g,email:f,message:x});if(T.ok)b=f,localStorage.setItem("heedb_email",f),z(),q(e,"Message sent!","We'll get back to you soon. Check your inbox for a confirmation email.");else{let me=await T.json();s.textContent=me.error||"Something went wrong.",s.style.display="block",i.disabled=!1,i.textContent="Send message"}}catch(T){s.textContent="Network error. Please try again.",s.style.display="block",i.disabled=!1,i.textContent="Send message"}},n?e.append(m,p,s,i):e.append(l,o,r,d,m,p,s,i)}function ie(e){let t=!!(L&&b),n=a("label",{class:"llp-label"},["Name"]),l=P("text","llp-priv-name","Jane Smith");L&&(l.value=L);let o=a("label",{class:"llp-label"},["Email"]),r=P("email","llp-priv-email","jane@example.com");b&&(r.value=b);let d=a("label",{class:"llp-label"},["Request type"]),m=oe("llp-priv-type",[{value:"deletion",label:"Delete my data"},{value:"access",label:"Access my data"},{value:"portability",label:"Export my data"},{value:"correction",label:"Correct my data"},{value:"restriction",label:"Restrict processing"},{value:"objection",label:"Object to processing"},{value:"other",label:"Other"}]),p=a("div",{class:"llp-error",style:"display:none"}),s=a("button",{class:"llp-btn-submit"},["Submit request"]);s.onclick=async()=>{let i=l.value.trim(),g=r.value.trim(),f=m.value;if(p.style.display="none",!i||!g){p.textContent="Please fill in all fields.",p.style.display="block";return}s.disabled=!0,s.textContent="Submitting\u2026";try{let x=await D("/api/privacy-request",{api_key:E,name:i,email:g,request_type:f});if(x.ok)b=g,localStorage.setItem("heedb_email",g),z(),q(e,"Request submitted!","Your privacy request has been received. We'll respond within 30 days.");else{let T=await x.json();p.textContent=T.error||"Something went wrong.",p.style.display="block",s.disabled=!1,s.textContent="Submit request"}}catch(x){p.textContent="Network error. Please try again.",p.style.display="block",s.disabled=!1,s.textContent="Submit request"}},t?e.append(d,m,p,s):e.append(n,l,o,r,d,m,p,s)}async function re(e){var t;if(!y){e.innerHTML="";let n=a("p",{style:"color:#71717a;text-align:center;margin:8px 0;font-size:13px;line-height:1.5"},["Send a message below to view your message history."]),l=a("div",{class:"llp-new-msg"}),o=a("button",{},["+ Send a message"]);o.onclick=()=>{h="contact",S("contact"),k()},l.appendChild(o),e.append(n,l);return}e.innerHTML='<p style="color:#71717a;text-align:center">Loading\u2026</p>';try{let{threads:n}=await Z(b);if(e.innerHTML="",n.length===0){let r=a("p",{style:"color:#71717a;text-align:center;margin:8px 0"},["No open messages yet."]);e.appendChild(r)}else for(let r of n){let d=a("span",{class:`llp-badge llp-badge-${r.status}`},[r.status]),m=a("div",{class:"llp-thread-label"},[r.type==="privacy"?"Privacy request":"Message"," \u2022 "]);m.appendChild(d);let p=a("div",{class:"llp-thread-text"},[(t=r.preview)!=null?t:""]),s=new Date(r.createdAt).toLocaleDateString(),i=a("div",{class:"llp-thread-meta"},[s]),g=a("div",{class:"llp-thread-item"});g.append(m,p,i),g.onclick=()=>se(r.id),e.appendChild(g)}let l=a("div",{class:"llp-new-msg"}),o=a("button",{},["+ Send a new message"]);o.onclick=()=>{h="contact",S("contact"),k()},l.appendChild(o),e.appendChild(l)}catch(n){e.innerHTML='<p style="color:#ef4444;text-align:center">Failed to load messages.</p>'}}function se(e){A=e,h="thread-detail",k()}async function ce(e){e.innerHTML='<p style="color:#71717a;text-align:center">Loading\u2026</p>';let t=a("button",{class:"llp-chat-back"},["\u2190 Back to messages"]);t.onclick=()=>{h="threads",S("threads"),k()};try{let l=(await ee(A)).messages||[];e.innerHTML="",e.style.padding="12px",e.appendChild(t);let o=a("div",{class:"llp-chat-messages"});for(let i of l){let g=i.direction==="inbound",f=a("div",{style:`display:flex;flex-direction:column;${g?"align-items:flex-start":"align-items:flex-end"}`}),x=a("div",{class:`llp-chat-bubble ${g?"llp-chat-inbound":"llp-chat-outbound"}`},[de(i.body)]),T=a("div",{class:`llp-chat-time ${g?"":"llp-chat-time-right"}`},[pe(i.createdAt)]);f.append(x,T),o.appendChild(f)}e.appendChild(o),requestAnimationFrame(()=>{o.scrollTop=o.scrollHeight});let r=a("div",{class:"llp-chat-reply"}),d=document.createElement("textarea");d.className="llp-chat-reply-input",d.placeholder="Type a reply\u2026",d.rows=1,d.addEventListener("input",()=>{d.style.height="auto",d.style.height=Math.min(d.scrollHeight,80)+"px"});let m=a("button",{class:"llp-chat-send"},["Send"]),p=a("div",{class:"llp-error",style:"display:none;margin-top:4px"});async function s(){let i=d.value.trim();if(i){m.disabled=!0,m.textContent="\u2026",p.style.display="none";try{let g=await te(A,i);if(g.ok){let f=a("div",{style:"display:flex;flex-direction:column;align-items:flex-start"}),x=a("div",{class:"llp-chat-bubble llp-chat-inbound"},[i]),T=a("div",{class:"llp-chat-time"},["Just now"]);f.append(x,T),o.appendChild(f),o.scrollTop=o.scrollHeight,d.value="",d.style.height="auto"}else{let f=await g.json();p.textContent=f.error||"Failed to send.",p.style.display="block"}}catch(g){p.textContent="Network error. Please try again.",p.style.display="block"}m.disabled=!1,m.textContent="Send"}}m.onclick=s,d.addEventListener("keydown",i=>{i.key==="Enter"&&!i.shiftKey&&(i.preventDefault(),s())}),r.append(d,m),e.append(r,p),requestAnimationFrame(()=>d.focus())}catch(n){e.innerHTML="",e.appendChild(t),e.appendChild(a("p",{style:"color:#ef4444;text-align:center"},["Failed to load conversation."]))}}function de(e){let t=e.split(`
151
- `),n=[];for(let l of t){let o=l.trim();if(/^(On|Em|El|Le|Am|Il giorno) .+(<[^>]+@[^>]+>).*(wrote|escreveu|escribi|crit|schrieb|scritto)\s?:$/i.test(o)||/<[^>]+@[^>]+>/.test(o)&&o.endsWith(":")||/^-{3,}$/.test(o))break;/^>{1,}\s/.test(o)||n.push(l)}return n.join(`
152
- `).trim()}function pe(e){let t=new Date(e),l=new Date().getTime()-t.getTime(),o=Math.floor(l/6e4);if(o<1)return"Just now";if(o<60)return`${o}m ago`;let r=Math.floor(o/60);return r<24?`${r}h ago`:t.toLocaleDateString()}function q(e,t,n){e.innerHTML="";let l=a("div",{class:"llp-success"});l.innerHTML=`
153
- <div class="llp-success-icon">\u2705</div>
149
+ .heedb-chat-send:hover { opacity: .85; }
150
+ .heedb-chat-send:disabled { opacity: .5; cursor: not-allowed; }
151
+
152
+ /* Skeleton loading */
153
+ .heedb-skeleton { pointer-events: none; }
154
+ .heedb-skel-line {
155
+ background: ${b?"#333":"#e4e4e7"};
156
+ border-radius: 4px;
157
+ animation: heedb-pulse 1.5s ease-in-out infinite;
158
+ }
159
+ @keyframes heedb-pulse {
160
+ 0%, 100% { opacity: 0.4; }
161
+ 50% { opacity: 1; }
162
+ }
163
+
164
+ /* Body fade transition */
165
+ .heedb-body { transition: opacity .15s ease; }
166
+ `}function s(e,t={},a=[]){let o=document.createElement(e);for(let[i,l]of Object.entries(t))i==="class"?o.className=l:i==="style"?o.setAttribute("style",l):i.startsWith("on")&&typeof l=="function"?o.addEventListener(i.slice(2),l):o.setAttribute(i,String(l));for(let i of a)o.appendChild(typeof i=="string"?document.createTextNode(i):i);return o}function U(e,t,a=""){let o=document.createElement("input");return o.type=e,o.id=t,o.placeholder=a,o.className="heedb-input",o}function he(e,t=""){let a=document.createElement("textarea");return a.id=e,a.placeholder=t,a.className="heedb-textarea",a}function be(e,t){let a=document.createElement("select");a.id=e,a.className="heedb-select";for(let o of t){let i=document.createElement("option");i.value=o.value,i.textContent=o.label,a.appendChild(i)}return a}function C(){if(!f)return;let e=f.querySelector(".heedb-body");e.innerHTML="",E==="contact"?fe(e):E==="privacy"?xe(e):E==="threads"?ye(e):E==="thread-detail"&&Te(e),$&&($.style.display=E==="thread-detail"?"none":"flex")}function fe(e,t=""){let a=!!(P&&k),o=s("label",{class:"heedb-label"},[n("nameLabel")]),i=U("text","heedb-name",n("namePlaceholder"));P&&(i.value=P);let l=s("label",{class:"heedb-label"},[n("emailLabel")]),y=U("email","heedb-email",n("emailPlaceholder"));(t||k)&&(y.value=t||k);let h=O(r.messageLabel),c=h?s("label",{class:"heedb-label"},[h]):null,p=he("heedb-message",O(r.messagePlaceholder)||n("messagePlaceholder")),d=s("div",{class:"heedb-error",style:"display:none"}),m=s("button",{class:"heedb-btn-submit"},[n("sendMessage")]);m.onclick=async()=>{var x;let g=i.value.trim(),v=y.value.trim(),u=p.value.trim();if(d.style.display="none",!g||!v||!u){d.textContent=n("fillAllFields"),d.style.display="block";return}m.disabled=!0,m.textContent=n("sending");try{let T=await W("/api/contact",{api_key:A,name:g,email:v,message:u,lang:R});if(T.ok)k=v,localStorage.setItem("heedb_email",v),q(),Q(e,n("messageSentTitle"),n("messageSentBody"));else if(T.status===429){let w=parseInt((x=T.headers.get("Retry-After"))!=null?x:"60",10);d.textContent=n("rateLimited"),d.style.display="block",m.textContent=n("sendMessage"),setTimeout(()=>{m.disabled=!1,d.style.display="none"},w*1e3)}else{let w=await T.json();d.textContent=w.error||n("somethingWrong"),d.style.display="block",m.disabled=!1,m.textContent=n("sendMessage")}}catch(T){d.textContent=n("networkError"),d.style.display="block",m.disabled=!1,m.textContent=n("sendMessage")}},a?(c&&e.append(c),e.append(p,d,m)):(e.append(o,i,l,y),c&&e.append(c),e.append(p,d,m))}function xe(e){let t=!!(P&&k),a=s("label",{class:"heedb-label"},[n("nameLabel")]),o=U("text","heedb-priv-name",n("namePlaceholder"));P&&(o.value=P);let i=s("label",{class:"heedb-label"},[n("emailLabel")]),l=U("email","heedb-priv-email",n("emailPlaceholder"));k&&(l.value=k);let y=s("label",{class:"heedb-label"},[n("requestType")]),h=be("heedb-priv-type",[{value:"deletion",label:n("deleteData")},{value:"access",label:n("accessData")},{value:"portability",label:n("exportData")}]),c=s("div",{class:"heedb-error",style:"display:none"}),p=s("button",{class:"heedb-btn-submit"},[n("submitRequest")]);p.onclick=async()=>{var v;let d=o.value.trim(),m=l.value.trim(),g=h.value;if(c.style.display="none",!d||!m){c.textContent=n("fillAllFields"),c.style.display="block";return}p.disabled=!0,p.textContent=n("submitting");try{let u=await W("/api/privacy-request",{api_key:A,name:d,email:m,request_type:g,lang:R});if(u.ok)k=m,localStorage.setItem("heedb_email",m),q(),Q(e,n("requestSubmittedTitle"),n("requestSubmittedBody"));else if(u.status===429){let x=parseInt((v=u.headers.get("Retry-After"))!=null?v:"60",10);c.textContent=n("rateLimited"),c.style.display="block",p.textContent=n("submitRequest"),setTimeout(()=>{p.disabled=!1,c.style.display="none"},x*1e3)}else{let x=await u.json();c.textContent=x.error||n("somethingWrong"),c.style.display="block",p.disabled=!1,p.textContent=n("submitRequest")}}catch(u){c.textContent=n("networkError"),c.style.display="block",p.disabled=!1,p.textContent=n("submitRequest")}},t?e.append(y,h,c,p):e.append(a,o,i,l,y,h,c,p)}async function ye(e){var t;if(!M){e.innerHTML="";let a=s("p",{style:"color:#71717a;text-align:center;margin:8px 0;font-size:13px;line-height:1.5"},[n("noThreadsAuth")]),o=s("div",{class:"heedb-new-msg"}),i=s("button",{},[n("sendAMessage")]);i.onclick=()=>{E="contact",B("contact"),C()},o.appendChild(i),e.append(a,o);return}e.innerHTML="";for(let a=0;a<3;a++){let o=s("div",{class:"heedb-thread-item heedb-skeleton"});o.append(s("div",{class:"heedb-skel-line",style:"width:40%;height:12px"}),s("div",{class:"heedb-skel-line",style:"width:80%;height:13px;margin-top:6px"}),s("div",{class:"heedb-skel-line",style:"width:30%;height:11px;margin-top:4px"})),e.appendChild(o)}try{let{threads:a}=await pe(k);if(e.innerHTML="",e.style.opacity="0",requestAnimationFrame(()=>{e.style.opacity="1"}),a.length===0){let l=s("p",{style:"color:#71717a;text-align:center;margin:8px 0"},[O(r.emptyStateText)||n("noOpenMessages")]);e.appendChild(l)}else for(let l of a){let y=s("span",{class:`heedb-badge heedb-badge-${l.status}`},[l.status]),h=s("div",{class:"heedb-thread-label"},[l.type==="privacy"?n("privacyRequest"):n("message")," \u2022 "]);h.appendChild(y);let c=s("div",{class:"heedb-thread-text"},[(t=l.preview)!=null?t:""]),p=new Date(l.createdAt).toLocaleDateString(),d=s("div",{class:"heedb-thread-meta"},[p]),m=s("div",{class:"heedb-thread-item"});m.append(h,c,d),m.onclick=()=>ve(l.id),e.appendChild(m)}let o=s("div",{class:"heedb-new-msg"}),i=s("button",{},[n("sendNewMessage")]);i.onclick=()=>{E="contact",B("contact"),C()},o.appendChild(i),e.appendChild(o)}catch(a){e.innerHTML=`<p style="color:#ef4444;text-align:center">${n("failedToLoad")}</p>`}}function ve(e){K=e,E="thread-detail",C()}async function Te(e){e.innerHTML="",e.style.padding="12px";let t=s("div",{class:"heedb-skel-line",style:"width:50%;height:13px;margin-bottom:12px"});e.appendChild(t);let a=s("div",{style:"display:flex;flex-direction:column;gap:8px"}),o=["65%","50%","70%","45%"],i=["flex-start","flex-end","flex-start","flex-end"];for(let y=0;y<4;y++){let h=s("div",{style:`display:flex;flex-direction:column;align-items:${i[y]}`});h.appendChild(s("div",{class:"heedb-skel-line",style:`width:${o[y]};height:32px;border-radius:8px`})),a.appendChild(h)}e.appendChild(a);let l=s("button",{class:"heedb-chat-back"},[n("backToMessages")]);l.onclick=()=>{E="threads",B("threads"),C()};try{let h=(await me(K)).messages||[];e.innerHTML="",e.style.padding="12px",e.appendChild(l);let c=s("div",{class:"heedb-chat-messages"});for(let u of h){let x=u.direction==="inbound",T=s("div",{style:`display:flex;flex-direction:column;${x?"align-items:flex-start":"align-items:flex-end"}`}),w=s("div",{class:`heedb-chat-bubble ${x?"heedb-chat-inbound":"heedb-chat-outbound"}`},[we(u.body)]),H=s("div",{class:`heedb-chat-time ${x?"":"heedb-chat-time-right"}`},[ke(u.createdAt)]);T.append(w,H),c.appendChild(T)}e.appendChild(c),requestAnimationFrame(()=>{c.scrollTop=c.scrollHeight});let p=s("div",{class:"heedb-chat-reply"}),d=document.createElement("textarea");d.className="heedb-chat-reply-input",d.placeholder=n("typeReply"),d.rows=1,d.addEventListener("input",()=>{d.style.height="auto",d.style.height=Math.min(d.scrollHeight,80)+"px"});let m=s("button",{class:"heedb-chat-send"},[n("send")]),g=s("div",{class:"heedb-error",style:"display:none;margin-top:4px"});async function v(){let u=d.value.trim();if(u){m.disabled=!0,m.textContent="\u2026",g.style.display="none";try{let x=await ge(K,u);if(x.ok){let T=s("div",{style:"display:flex;flex-direction:column;align-items:flex-start"}),w=s("div",{class:"heedb-chat-bubble heedb-chat-inbound"},[u]),H=s("div",{class:"heedb-chat-time"},[n("justNow")]);T.append(w,H),c.appendChild(T),c.scrollTop=c.scrollHeight,d.value="",d.style.height="auto"}else{let T=await x.json();g.textContent=T.error||n("failedToSend"),g.style.display="block"}}catch(x){g.textContent=n("networkError"),g.style.display="block"}m.disabled=!1,m.textContent=n("send")}}m.onclick=v,d.addEventListener("keydown",u=>{u.key==="Enter"&&!u.shiftKey&&(u.preventDefault(),v())}),p.append(d,m),e.append(p,g),requestAnimationFrame(()=>d.focus())}catch(y){e.innerHTML="",e.appendChild(l),e.appendChild(s("p",{style:"color:#ef4444;text-align:center"},[n("failedToLoadConvo")]))}}function we(e){let t=e.split(`
167
+ `),a=[];for(let o of t){let i=o.trim();if(/^(On|Em|El|Le|Am|Il giorno) .+(<[^>]+@[^>]+>).*(wrote|escreveu|escribi|crit|schrieb|scritto)\s?:$/i.test(i)||/<[^>]+@[^>]+>/.test(i)&&i.endsWith(":")||/^-{3,}$/.test(i))break;/^>{1,}\s/.test(i)||a.push(o)}return a.join(`
168
+ `).trim()}function ke(e){let t=new Date(e),o=new Date().getTime()-t.getTime(),i=Math.floor(o/6e4);if(i<1)return n("justNow");if(i<60)return n("minutesAgo").replace("{mins}",String(i));let l=Math.floor(i/60);return l<24?n("hoursAgo").replace("{hours}",String(l)):t.toLocaleDateString()}function Q(e,t,a){e.innerHTML="";let o=s("div",{class:"heedb-success"});o.innerHTML=`
169
+ <div class="heedb-success-icon">\u2705</div>
154
170
  <h3>${t}</h3>
155
- <p>${n}</p>
156
- `,e.appendChild(l)}let M=null,_=null;function S(e){h=e,M&&M.querySelectorAll(".llp-tab").forEach(t=>{t.classList.toggle("active",t.dataset.mode===e)})}function z(){_&&(_.style.display=b&&y?"":"none")}let B=null;function ge(){u=R(),B&&(B.textContent=O())}async function F(){if(c=await ne(),u=R(),B=document.createElement("style"),B.textContent=O(),document.head.appendChild(B),c.customCSS){let i=document.createElement("style");i.textContent=c.customCSS,document.head.appendChild(i)}c.mode==="system"&&window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{ge(),C&&v&&k()});let e=c.triggerIcon?c.triggerIcon:c.triggerEmoji||"\u{1F4AC}",t=c.triggerText||"";if(H=a("button",{class:"llp-btn",title:"Contact us","aria-label":"Open contact widget"}),c.triggerIcon){let i=a("span",{class:"llp-btn-icon"});i.innerHTML=c.triggerIcon,H.appendChild(i)}else H.appendChild(document.createTextNode(c.triggerEmoji||"\u{1F4AC}"));if(t&&H.appendChild(a("span",{class:"llp-btn-label"},[t])),H.onclick=j,document.body.appendChild(H),c.triggerMode==="embedded"&&c.triggerSelector){let i=document.querySelector(c.triggerSelector);i&&i.addEventListener("click",g=>{g.preventDefault(),j()})}if(c.triggerMode==="tag"){let i=a("button",{class:"llp-tag","aria-label":"Open contact widget"}),g=a("span",{class:"llp-tag-icon"},[c.triggerEmoji||"\u{1F4AC}"]);i.appendChild(g),i.appendChild(document.createTextNode(c.triggerText||"Feedback")),i.onclick=j,document.body.appendChild(i)}v=a("div",{class:"llp-panel",style:"display:none"});let n=a("div",{class:"llp-header"}),l=a("h2",{},[c.headerTitle||"Contact us"]),o=a("button",{class:"llp-close","aria-label":"Close"},["\u2715"]);o.onclick=j,n.append(l,o),M=a("div",{class:"llp-tabs"});let r=a("button",{class:"llp-tab active","data-mode":"contact"},["Message"]),d=a("button",{class:"llp-tab","data-mode":"privacy"},["Privacy"]);_=a("button",{class:"llp-tab","data-mode":"threads"},["Messages"]),_.style.display=b&&y?"":"none",r.onclick=()=>{S("contact"),k()},d.onclick=()=>{S("privacy"),k()},_.onclick=()=>{S("threads"),k()},M.append(r,d,_);let m=a("div",{class:"llp-body"}),p=a("div",{class:"llp-footer"}),s=a("a",{href:"https://heedb.com",target:"_blank",rel:"noopener noreferrer"},["Powered by Heedb"]);p.appendChild(s),v.append(n,M,m,p),document.body.appendChild(v)}function j(){C=!C,v&&(v.style.display=C?"flex":"none",C&&(b&&y&&h!=="privacy"&&h!=="thread-detail"&&(h="threads",S("threads")),k()))}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",F):F()})();})();
171
+ <p>${a}</p>
172
+ `,e.appendChild(o)}let $=null,D=null;function B(e){E=e,$&&$.querySelectorAll(".heedb-tab").forEach(t=>{t.classList.toggle("active",t.dataset.mode===e)})}function q(){D&&(D.style.display=k&&M?"":"none")}let I=null;function Z(){b=J(),I&&(I.textContent=X())}async function ee(){if(r=await ue(),R=G(),b=J(),I=document.createElement("style"),I.textContent=X(),document.head.appendChild(I),r.customCSS){let g=document.createElement("style");g.textContent=r.customCSS,document.head.appendChild(g)}r.mode==="system"&&window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{Z(),S&&f&&C()});let e=r.triggerIcon?r.triggerIcon:r.triggerEmoji||"\u{1F4AC}",t=r.triggerText||"";if(_=s("button",{class:"heedb-btn",title:n("contactUs"),"aria-label":"Open contact widget"}),r.triggerIcon){let g=s("span",{class:"heedb-btn-icon"}),u=new DOMParser().parseFromString(r.triggerIcon,"image/svg+xml").querySelector("svg");if(u){u.querySelectorAll("script,foreignObject,iframe,object,embed").forEach(w=>w.remove());let x=document.createTreeWalker(u,NodeFilter.SHOW_ELEMENT),T;for(;T=x.nextNode();)for(let w of Array.from(T.attributes))(w.name.startsWith("on")||/^\s*javascript:/i.test(w.value))&&T.removeAttribute(w.name);g.appendChild(u)}_.appendChild(g)}else _.appendChild(document.createTextNode(r.triggerEmoji||"\u{1F4AC}"));if(t&&_.appendChild(s("span",{class:"heedb-btn-label"},[t])),_.onclick=V,document.body.appendChild(_),r.triggerMode==="embedded"&&r.triggerSelector){let g=document.querySelector(r.triggerSelector);g&&g.addEventListener("click",v=>{v.preventDefault(),V()})}if(r.triggerMode==="tag"){let g=s("button",{class:"heedb-tag","aria-label":"Open contact widget"}),v=s("span",{class:"heedb-tag-icon"});if(r.triggerIcon){let x=new DOMParser().parseFromString(r.triggerIcon,"image/svg+xml").querySelector("svg");if(x){x.querySelectorAll("script,foreignObject,iframe,object,embed").forEach(H=>H.remove());let T=document.createTreeWalker(x,NodeFilter.SHOW_ELEMENT),w;for(;w=T.nextNode();)for(let H of Array.from(w.attributes))(H.name.startsWith("on")||/^\s*javascript:/i.test(H.value))&&w.removeAttribute(H.name);v.appendChild(x)}}else v.appendChild(document.createTextNode(r.triggerEmoji||"\u{1F4AC}"));g.appendChild(v),g.appendChild(document.createTextNode(r.triggerText||n("feedback"))),g.onclick=V,document.body.appendChild(g)}f=s("div",{class:"heedb-panel",style:"display:none"});let a=s("div",{class:"heedb-header"}),o=s("h2",{},[r.headerTitle||n("contactUs")]),i=s("button",{class:"heedb-close","aria-label":"Close"},["\u2715"]);i.onclick=V,a.append(o,i),$=s("div",{class:"heedb-tabs"});let l=s("button",{class:"heedb-tab active","data-mode":"contact"},[O(r.contactTabLabel)||n("contactTab")]),h=r.showPrivacyTab!==!1?s("button",{class:"heedb-tab","data-mode":"privacy"},[n("privacyTab")]):null;D=s("button",{class:"heedb-tab","data-mode":"threads"},[n("messagesTab")]),D.style.display=k&&M?"":"none",l.onclick=()=>{B("contact"),C()},h&&(h.onclick=()=>{B("privacy"),C()}),D.onclick=()=>{B("threads"),C()},$.append(l),h&&$.append(h),$.append(D);let c=s("div",{class:"heedb-body"}),p=s("div",{class:"heedb-footer"}),d=new URLSearchParams({utm_source:"widget",utm_medium:"heedb-widget",utm_campaign:window.location.hostname}),m=s("a",{href:`https://heedb.com?${d.toString()}`,target:"_blank",rel:"noopener noreferrer"},[n("poweredBy")]);p.appendChild(m),f.append(a,$,c,p),document.body.appendChild(f)}function V(){S=!S,f&&(S?(f.style.display="flex",f.style.opacity="0",f.style.transform="translateY(8px)",requestAnimationFrame(()=>{f.style.opacity="1",f.style.transform="translateY(0)"}),k&&M&&E!=="privacy"&&E!=="thread-detail"&&(E="threads",B("threads")),C()):(f.style.opacity="0",f.style.transform="translateY(8px)",setTimeout(()=>{!S&&f&&(f.style.display="none")},150)))}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",ee):ee()})();})();