wakz-chat-widget 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.js +702 -479
  2. package/package.json +1 -13
  3. package/README.md +0 -1
package/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * WAKZ Chat Widget v3.0.0
2
+ * WAKZ Chat Widget v4.0.0
3
3
  * ─────────────────────────────────────────────────────────────────
4
4
  * A production-grade, self-contained chat widget using Shadow DOM.
5
- * Complete UI/UX revampglass morphism, centered modal, modern design.
5
+ * Liquid Glass designpill header, floating input, dark user bubbles.
6
6
  *
7
7
  * Embed: <script src="/wakz-widget.js" data-api-key="xxx" data-server="https://..." async></script>
8
8
  *
@@ -127,17 +127,24 @@
127
127
  return fetch(url, merged).finally(function () { clearTimeout(timer); });
128
128
  }
129
129
 
130
+ /** XSS-safe: escape HTML entities */
131
+ function _escapeHTML(str) {
132
+ var div = document.createElement('div');
133
+ div.appendChild(document.createTextNode(str));
134
+ return div.innerHTML;
135
+ }
136
+
130
137
  /* ════════════════════════════════════════════════════════════════
131
138
  SVG ICONS (inline for zero-dependency)
132
139
  ════════════════════════════════════════════════════════════════ */
133
140
 
134
141
  var _ICONS = {
135
142
  chatBubble:
136
- '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>',
143
+ '<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',
137
144
  send:
138
- '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>',
145
+ '<svg width="18" height="18" viewBox="0 0 24 24" fill="none"><path d="M19 12H5M5 12L11 6M5 12L11 18" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>',
139
146
  close:
140
- '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',
147
+ '<svg width="14" height="14" viewBox="0 0 24 24" fill="none"><line x1="18" y1="6" x2="6" y2="18" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/><line x1="6" y1="6" x2="18" y2="18" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg>',
141
148
  error:
142
149
  '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>'
143
150
  };
@@ -149,7 +156,7 @@
149
156
  var _I18N = {
150
157
  ar: {
151
158
  placeholder: 'اكتب رسالتك...',
152
- online: 'متصل',
159
+ online: 'متصل الآن',
153
160
  offline: 'غير متصل',
154
161
  errorMsg: 'حدث خطأ في الاتصال. يرجى المحاولة مرة أخرى.',
155
162
  retry: 'إعادة المحاولة',
@@ -157,7 +164,8 @@
157
164
  openChat: 'فتح المحادثة',
158
165
  closeChat: 'إغلاق المحادثة',
159
166
  sendMessage: 'إرسال',
160
- humanBadge: '👤 فريق الدعم'
167
+ humanBadge: 'فريق الدعم',
168
+ defaultSubtitle: 'المساعد الذكي'
161
169
  },
162
170
  en: {
163
171
  placeholder: 'Type your message...',
@@ -169,7 +177,8 @@
169
177
  openChat: 'Open chat',
170
178
  closeChat: 'Close chat',
171
179
  sendMessage: 'Send',
172
- humanBadge: '👤 Support Team'
180
+ humanBadge: 'Support Team',
181
+ defaultSubtitle: 'Smart Assistant'
173
182
  },
174
183
  fr: {
175
184
  placeholder: 'Tapez votre message...',
@@ -181,7 +190,8 @@
181
190
  openChat: 'Ouvrir le chat',
182
191
  closeChat: 'Fermer le chat',
183
192
  sendMessage: 'Envoyer',
184
- humanBadge: '👤 Équipe de support'
193
+ humanBadge: 'Équipe de support',
194
+ defaultSubtitle: 'Assistant intelligent'
185
195
  }
186
196
  };
187
197
 
@@ -195,10 +205,11 @@
195
205
 
196
206
  var _DEFAULTS = {
197
207
  botName: 'WAKZ',
208
+ botSubtitle: '',
198
209
  welcomeMessage: '',
199
- primaryColor: '#171717',
200
- chatBg: '#f8f9fa',
201
- btnColor: '#171717',
210
+ primaryColor: '#111111',
211
+ chatBg: '#ffffff',
212
+ btnColor: '#111111',
202
213
  widgetBg: '#ffffff',
203
214
  position: 'bottom-right',
204
215
  language: 'en',
@@ -245,16 +256,18 @@
245
256
  self._root = null;
246
257
  self._overlay = null;
247
258
  self._chatWindow = null;
248
- self._messagesContainer = null;
249
- self._inputArea = null;
259
+ self._messagesInner = null;
260
+ self._inputWrap = null;
250
261
  self._inputEl = null;
251
262
  self._sendBtn = null;
252
263
  self._toggleBtn = null;
253
264
  self._statusDot = null;
265
+ self._headerTitleEl = null;
266
+ self._headerSubtitleEl = null;
267
+ self._headerStatusPill = null;
254
268
  self._headerStatusDot = null;
255
269
  self._headerStatusText = null;
256
- self._headerAvatarEl = null;
257
- self._headerNameEl = null;
270
+ self._closeBtn = null;
258
271
 
259
272
  /* ── Bootstrap ── */
260
273
  self._injectCSS();
@@ -265,7 +278,7 @@
265
278
  }
266
279
 
267
280
  /* ════════════════════════════════════════════════════════════════
268
- CSS — Complete styling injected into Shadow DOM (v3.0.0 revamp)
281
+ CSS — Complete Liquid Glass design (v4.0.0)
269
282
  ════════════════════════════════════════════════════════════════ */
270
283
 
271
284
  WAKZWidget.prototype._injectCSS = function () {
@@ -275,18 +288,12 @@
275
288
  self._styleEl.textContent = [
276
289
  /* ── CSS Custom Properties (theming) ── */
277
290
  ':host {',
278
- ' --wakz-primary: #171717;',
279
- ' --wakz-btn: #171717;',
280
- ' --wakz-chat-bg: #f8f9fa;',
291
+ ' --wakz-primary: #111111;',
292
+ ' --wakz-btn: #111111;',
293
+ ' --wakz-chat-bg: #ffffff;',
281
294
  ' --wakz-widget-bg: #ffffff;',
282
- ' --wakz-icon-radius: 50%;',
283
- ' --wakz-shadow-sm: 0 1px 3px rgba(0,0,0,.08), 0 1px 2px rgba(0,0,0,.06);',
284
- ' --wakz-shadow-md: 0 4px 12px rgba(0,0,0,.1), 0 2px 4px rgba(0,0,0,.06);',
285
- ' --wakz-shadow-lg: 0 25px 60px rgba(0,0,0,.15), 0 10px 20px rgba(0,0,0,.1);',
286
- ' --wakz-transition: 200ms ease;',
287
- ' --wakz-font: \'Inter\', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;',
288
295
  ' all: initial;',
289
- ' font-family: var(--wakz-font);',
296
+ ' font-family: "Cairo", "Tajawal", "IBM Plex Sans Arabic", system-ui, sans-serif;',
290
297
  '}',
291
298
 
292
299
  /* ── Reset ── */
@@ -297,38 +304,57 @@
297
304
  '}',
298
305
 
299
306
  /* ══════════════════════════════════════════════════
300
- FLOATING ACTION BUTTON (FAB) — 48px, independent color
307
+ ANIMATIONS
308
+ ══════════════════════════════════════════════════ */
309
+ '@keyframes wakz-fade-slide-up {',
310
+ ' from { opacity: 0; transform: translateY(6px); }',
311
+ ' to { opacity: 1; transform: translateY(0); }',
312
+ '}',
313
+
314
+ '@keyframes wakz-typing-bounce {',
315
+ ' 0%, 60%, 100% { transform: translateY(0); opacity: 0.35; }',
316
+ ' 30% { transform: translateY(-4px); opacity: 1; }',
317
+ '}',
318
+
319
+ '@keyframes wakz-pulse-green {',
320
+ ' 0%, 100% { box-shadow: 0 0 0 2px rgba(34,197,94,0.2); }',
321
+ ' 50% { box-shadow: 0 0 0 4px rgba(34,197,94,0.08); }',
322
+ '}',
323
+
324
+ '@keyframes wakz-fab-enter {',
325
+ ' 0% { opacity: 0; transform: scale(0.3); }',
326
+ ' 50% { opacity: 1; transform: scale(1.12); }',
327
+ ' 70% { transform: scale(0.92); }',
328
+ ' 100% { transform: scale(1); }',
329
+ '}',
330
+
331
+ /* ══════════════════════════════════════════════════
332
+ FLOATING ACTION BUTTON (FAB) — 56px black circle
301
333
  ══════════════════════════════════════════════════ */
302
334
  '.wakz-fab {',
303
335
  ' position: fixed;',
304
336
  ' z-index: 2147483647;',
305
- ' width: 48px;',
306
- ' height: 48px;',
307
- ' border-radius: var(--wakz-icon-radius);',
337
+ ' width: 56px;',
338
+ ' height: 56px;',
339
+ ' border-radius: 50%;',
308
340
  ' border: none;',
309
341
  ' cursor: pointer;',
310
342
  ' display: flex;',
311
343
  ' align-items: center;',
312
344
  ' justify-content: center;',
313
- ' box-shadow: 0 4px 14px rgba(0,0,0,.15), 0 2px 6px rgba(0,0,0,.1);',
314
- ' transition: transform var(--wakz-transition), box-shadow var(--wakz-transition);',
345
+ ' color: #ffffff;',
346
+ ' background: var(--wakz-btn);',
347
+ ' box-shadow: 0 4px 20px rgba(0,0,0,0.2), 0 1px 6px rgba(0,0,0,0.12);',
348
+ ' transition: transform 0.3s cubic-bezier(0.22,1,0.36,1), box-shadow 0.3s cubic-bezier(0.22,1,0.36,1);',
315
349
  ' outline: none;',
316
350
  ' -webkit-tap-highlight-color: transparent;',
317
- ' background: var(--wakz-btn);',
318
351
  '}',
319
352
  '.wakz-fab:hover {',
320
- ' transform: scale(1.06);',
321
- ' box-shadow: 0 8px 24px rgba(0,0,0,.2), 0 4px 10px rgba(0,0,0,.12);',
322
- '}',
323
- '.wakz-fab:active {',
324
- ' transform: scale(0.94);',
325
- '}',
326
- '.wakz-fab svg {',
327
- ' width: 22px;',
328
- ' height: 22px;',
329
- ' color: #ffffff;',
330
- ' pointer-events: none;',
353
+ ' transform: scale(1.1);',
354
+ ' box-shadow: 0 6px 28px rgba(0,0,0,0.25), 0 2px 8px rgba(0,0,0,0.15);',
331
355
  '}',
356
+ '.wakz-fab:active { transform: scale(0.93); }',
357
+ '.wakz-fab svg { width: 26px; height: 26px; color: #fff; pointer-events: none; }',
332
358
 
333
359
  /* ── FAB Positioning ── */
334
360
  '.wakz-fab-pos-br { bottom: 24px; right: 24px; }',
@@ -341,14 +367,8 @@
341
367
  '}',
342
368
 
343
369
  /* ── FAB Entrance Bounce ── */
344
- '@keyframes wakz-fab-enter {',
345
- ' 0% { opacity: 0; transform: scale(0.3); }',
346
- ' 50% { opacity: 1; transform: scale(1.12); }',
347
- ' 70% { transform: scale(0.92); }',
348
- ' 100% { transform: scale(1); }',
349
- '}',
350
370
  '.wakz-fab-enter {',
351
- ' animation: wakz-fab-enter 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;',
371
+ ' animation: wakz-fab-enter 0.6s cubic-bezier(0.34,1.56,0.64,1) forwards;',
352
372
  '}',
353
373
 
354
374
  /* ══════════════════════════════════════════════════
@@ -365,31 +385,18 @@
365
385
  ' z-index: 2;',
366
386
  ' transition: background 0.3s ease;',
367
387
  '}',
368
- '.wakz-fab-pos-bl .wakz-fab-dot {',
369
- ' right: auto;',
370
- ' left: -1px;',
371
- '}',
372
-
373
- /* ── Online (green pulse) ── */
388
+ '.wakz-fab-pos-bl .wakz-fab-dot { right: auto; left: -1px; }',
374
389
  '.wakz-fab-dot.online {',
375
390
  ' background: #22c55e;',
391
+ ' animation: wakz-pulse-green 2.5s ease-in-out infinite;',
376
392
  '}',
377
- '@keyframes wakz-dot-pulse {',
378
- ' 0%, 100% { box-shadow: 0 0 0 0 rgba(34,197,94,0.5); }',
379
- ' 50% { box-shadow: 0 0 0 5px rgba(34,197,94,0); }',
380
- '}',
381
- '.wakz-fab-dot.online {',
382
- ' animation: wakz-dot-pulse 2s ease-in-out infinite;',
383
- '}',
384
-
385
- /* ── Offline (red, no pulse) ── */
386
393
  '.wakz-fab-dot.offline {',
387
394
  ' background: #ef4444;',
388
395
  ' animation: none;',
389
396
  '}',
390
397
 
391
398
  /* ══════════════════════════════════════════════════
392
- OVERLAY / BACKDROP — glass blur behind modal
399
+ OVERLAY / BACKDROP — blur behind modal
393
400
  ══════════════════════════════════════════════════ */
394
401
  '.wakz-overlay {',
395
402
  ' position: fixed;',
@@ -400,7 +407,7 @@
400
407
  ' -webkit-backdrop-filter: blur(4px);',
401
408
  ' opacity: 0;',
402
409
  ' pointer-events: none;',
403
- ' transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);',
410
+ ' transition: opacity 0.3s cubic-bezier(0.4,0,0.2,1);',
404
411
  '}',
405
412
  '.wakz-overlay.wakz-visible {',
406
413
  ' opacity: 1;',
@@ -408,7 +415,7 @@
408
415
  '}',
409
416
 
410
417
  /* ══════════════════════════════════════════════════
411
- CHAT WINDOW — Centered Modal
418
+ CHAT WINDOW — Centered, 420x560, 24px radius
412
419
  ══════════════════════════════════════════════════ */
413
420
  '.wakz-window {',
414
421
  ' position: fixed;',
@@ -416,18 +423,23 @@
416
423
  ' top: 50%;',
417
424
  ' left: 50%;',
418
425
  ' transform: translate(-50%, -50%) scale(0.95);',
419
- ' width: 390px;',
420
- ' height: min(580px, 80vh);',
421
- ' border-radius: 16px;',
426
+ ' width: 420px;',
427
+ ' height: 560px;',
428
+ ' max-width: calc(100vw - 24px);',
429
+ ' max-height: calc(100vh - 24px);',
430
+ ' border-radius: 24px;',
422
431
  ' overflow: hidden;',
423
432
  ' display: flex;',
424
433
  ' flex-direction: column;',
425
434
  ' background: var(--wakz-widget-bg);',
426
- ' box-shadow: 0 25px 60px rgba(0,0,0,0.15), 0 10px 20px rgba(0,0,0,0.1);',
435
+ ' box-shadow:',
436
+ ' 0 0 0 0.5px rgba(0,0,0,0.06),',
437
+ ' 0 8px 40px rgba(0,0,0,0.08),',
438
+ ' 0 2px 12px rgba(0,0,0,0.04);',
427
439
  ' opacity: 0;',
428
440
  ' pointer-events: none;',
429
- ' transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1),',
430
- ' transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);',
441
+ ' transition: opacity 0.3s cubic-bezier(0.4,0,0.2,1),',
442
+ ' transform 0.3s cubic-bezier(0.4,0,0.2,1);',
431
443
  '}',
432
444
  '.wakz-window.wakz-visible {',
433
445
  ' opacity: 1;',
@@ -436,249 +448,342 @@
436
448
  '}',
437
449
 
438
450
  /* ══════════════════════════════════════════════════
439
- HEADER — Glass effect matching main site
451
+ FLOATING HEADER WRAP absolute over messages
440
452
  ══════════════════════════════════════════════════ */
441
- '.wakz-hdr {',
442
- ' flex-shrink: 0;',
443
- ' height: 52px;',
444
- ' padding: 0 16px;',
445
- ' display: flex;',
446
- ' align-items: center;',
447
- ' justify-content: space-between;',
448
- ' color: #171717;',
449
- ' cursor: default;',
450
- ' user-select: none;',
451
- ' background: rgba(255,255,255,0.85);',
452
- ' backdrop-filter: blur(24px);',
453
- ' -webkit-backdrop-filter: blur(24px);',
454
- ' border-bottom: 1px solid rgba(229,229,229,0.6);',
455
- ' box-shadow: 0 4px 12px rgba(0,0,0,0.05);',
456
- ' border-radius: 16px 16px 0 0;',
453
+ '.wakz-header-wrap {',
454
+ ' position: absolute;',
455
+ ' top: 12px;',
456
+ ' right: 12px;',
457
+ ' left: 12px;',
458
+ ' z-index: 100;',
459
+ ' pointer-events: none;',
457
460
  '}',
458
- '.wakz-hdr-left {',
461
+
462
+ /* ── HEADER — Liquid Glass Pill ── */
463
+ '.wakz-header {',
464
+ ' pointer-events: all;',
459
465
  ' display: flex;',
460
466
  ' align-items: center;',
461
- ' gap: 10px;',
462
- ' min-width: 0;',
463
- ' flex: 1;',
467
+ ' justify-content: space-between;',
468
+ ' position: relative;',
469
+ ' overflow: hidden;',
470
+ ' backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
471
+ ' -webkit-backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
472
+ ' background: rgba(255,255,255,0.82);',
473
+ ' border: 0.5px solid rgba(255,255,255,0.7);',
474
+ ' border-radius: 9999px;',
475
+ ' box-shadow:',
476
+ ' inset 0 1px 0 0 rgba(255,255,255,0.9),',
477
+ ' inset 0 -1px 0 0 rgba(0,0,0,0.04),',
478
+ ' 0 0 0 0.5px rgba(0,0,0,0.06),',
479
+ ' 0 8px 32px rgba(0,0,0,0.08),',
480
+ ' 0 2px 8px rgba(0,0,0,0.04);',
481
+ ' padding: 8px 8px 8px 12px;',
482
+ ' gap: 12px;',
464
483
  '}',
465
- '.wakz-hdr-right {',
466
- ' display: flex;',
467
- ' align-items: center;',
468
- ' gap: 8px;',
469
- ' flex-shrink: 0;',
484
+
485
+ /* ── Specular Highlight (real DOM element, not ::before) ── */
486
+ '.wakz-specular {',
487
+ ' position: absolute;',
488
+ ' top: 0;',
489
+ ' left: 15%;',
490
+ ' right: 15%;',
491
+ ' height: 1px;',
492
+ ' background: linear-gradient(',
493
+ ' 90deg,',
494
+ ' transparent,',
495
+ ' rgba(255,255,255,0.6) 20%,',
496
+ ' rgba(255,255,255,0.95) 50%,',
497
+ ' rgba(255,255,255,0.6) 80%,',
498
+ ' transparent',
499
+ ' );',
500
+ ' border-radius: inherit;',
501
+ ' pointer-events: none;',
502
+ ' z-index: 1;',
470
503
  '}',
471
504
 
472
- /* ── Bot Avatar (32px circle) ── */
473
- '.wakz-avatar {',
474
- ' width: 32px;',
475
- ' height: 32px;',
476
- ' border-radius: 50%;',
477
- ' background: rgba(23,23,23,0.1);',
505
+ /* ── Brand (right side in RTL) ── */
506
+ '.wakz-hdr-brand {',
478
507
  ' display: flex;',
479
508
  ' align-items: center;',
480
- ' justify-content: center;',
481
- ' font-weight: 700;',
482
- ' font-size: 14px;',
483
509
  ' flex-shrink: 0;',
484
- ' color: var(--wakz-primary);',
510
+ ' padding: 0 6px;',
485
511
  '}',
486
-
487
- /* ── Header Info ── */
488
512
  '.wakz-hdr-info {',
489
513
  ' display: flex;',
490
514
  ' flex-direction: column;',
491
- ' min-width: 0;',
515
+ ' gap: 1px;',
492
516
  '}',
493
- '.wakz-hdr-name {',
517
+ '.wakz-hdr-title {',
494
518
  ' font-size: 15px;',
495
- ' font-weight: 600;',
496
- ' line-height: 1.3;',
497
- ' color: #171717;',
498
- ' white-space: nowrap;',
499
- ' overflow: hidden;',
500
- ' text-overflow: ellipsis;',
519
+ ' font-weight: 900;',
520
+ ' color: #0a0a0a;',
521
+ ' letter-spacing: -0.2px;',
522
+ ' line-height: 1.2;',
523
+ ' font-family: "Cairo", sans-serif;',
501
524
  '}',
502
- '.wakz-hdr-status {',
525
+ '.wakz-hdr-subtitle {',
503
526
  ' font-size: 11px;',
504
- ' color: #A3A3A3;',
527
+ ' font-weight: 500;',
528
+ ' color: #999;',
529
+ ' line-height: 1.2;',
530
+ ' font-family: "Tajawal", "Cairo", sans-serif;',
531
+ '}',
532
+
533
+ /* ── Actions (left side in RTL) ── */
534
+ '.wakz-hdr-actions {',
505
535
  ' display: flex;',
506
536
  ' align-items: center;',
507
- ' gap: 4px;',
508
- ' margin-top: 1px;',
537
+ ' gap: 8px;',
538
+ ' flex-shrink: 0;',
509
539
  '}',
510
540
 
511
- /* ── Header Status Dot (6px) ── */
512
- '.wakz-hdr-status-dot {',
541
+ /* ── Status Pill ── */
542
+ '.wakz-status-pill {',
543
+ ' display: inline-flex;',
544
+ ' align-items: center;',
545
+ ' gap: 5px;',
546
+ ' padding: 4px 10px;',
547
+ ' border-radius: 50px;',
548
+ ' font-size: 11px;',
549
+ ' font-weight: 600;',
550
+ ' font-family: "Cairo", sans-serif;',
551
+ ' white-space: nowrap;',
552
+ ' transition: all 0.3s ease;',
553
+ '}',
554
+ '.wakz-status-pill--online {',
555
+ ' background: rgba(34,197,94,0.08);',
556
+ ' color: #16a34a;',
557
+ ' border: 1px solid rgba(34,197,94,0.15);',
558
+ '}',
559
+ '.wakz-status-pill--offline {',
560
+ ' background: rgba(156,163,175,0.1);',
561
+ ' color: #6b7280;',
562
+ ' border: 1px solid rgba(156,163,175,0.15);',
563
+ '}',
564
+
565
+ /* ── Status Dot inside pill (6px) ── */
566
+ '.wakz-status-dot {',
513
567
  ' width: 6px;',
514
568
  ' height: 6px;',
515
569
  ' border-radius: 50%;',
516
- ' display: inline-block;',
517
570
  ' flex-shrink: 0;',
518
- ' transition: background 0.3s ease;',
519
571
  '}',
520
- '.wakz-hdr-status-dot.online { background: #22c55e; }',
521
- '.wakz-hdr-status-dot.offline { background: #ef4444; }',
572
+ '.wakz-status-pill--online .wakz-status-dot {',
573
+ ' background: #22c55e;',
574
+ ' animation: wakz-pulse-green 2.5s ease-in-out infinite;',
575
+ '}',
576
+ '.wakz-status-pill--offline .wakz-status-dot {',
577
+ ' background: #9ca3af;',
578
+ '}',
522
579
 
523
- /* ── Close Button (28px circle, dark) ── */
580
+ /* ── Close Button (glass circle) ── */
524
581
  '.wakz-close {',
525
- ' width: 28px;',
526
- ' height: 28px;',
582
+ ' width: 30px;',
583
+ ' height: 30px;',
584
+ ' min-width: 30px;',
585
+ ' min-height: 30px;',
527
586
  ' border-radius: 50%;',
528
587
  ' border: none;',
529
- ' background: rgba(23,23,23,0.05);',
530
- ' color: #525252;',
531
588
  ' cursor: pointer;',
532
589
  ' display: flex;',
533
590
  ' align-items: center;',
534
591
  ' justify-content: center;',
535
- ' transition: background var(--wakz-transition), color var(--wakz-transition);',
592
+ ' color: #888;',
593
+ ' position: relative;',
594
+ ' overflow: hidden;',
595
+ ' backdrop-filter: blur(20px) saturate(180%);',
596
+ ' -webkit-backdrop-filter: blur(20px) saturate(180%);',
597
+ ' background: rgba(255,255,255,0.6);',
598
+ ' border: 0.5px solid rgba(255,255,255,0.6);',
599
+ ' box-shadow:',
600
+ ' inset 0 1px 0 0 rgba(255,255,255,0.8),',
601
+ ' 0 1px 4px rgba(0,0,0,0.04);',
602
+ ' transition: all 0.2s cubic-bezier(0.22,1,0.36,1);',
536
603
  ' outline: none;',
537
- ' flex-shrink: 0;',
538
604
  '}',
539
605
  '.wakz-close:hover {',
540
- ' background: rgba(23,23,23,0.1);',
541
- ' color: #171717;',
542
- '}',
543
- '.wakz-close svg {',
544
- ' width: 16px;',
545
- ' height: 16px;',
606
+ ' background: rgba(255,80,80,0.08);',
607
+ ' color: #ef4444;',
608
+ ' transform: scale(1.1);',
609
+ ' box-shadow:',
610
+ ' inset 0 1px 0 0 rgba(255,255,255,0.8),',
611
+ ' 0 2px 8px rgba(239,68,68,0.1);',
546
612
  '}',
613
+ '.wakz-close:active { transform: scale(0.92); }',
614
+ '.wakz-close svg { width: 14px; height: 14px; }',
547
615
 
548
616
  /* ══════════════════════════════════════════════════
549
- MESSAGES AREA — scrollable, padding-bottom for input
617
+ MESSAGES AREA — scrollable
550
618
  ══════════════════════════════════════════════════ */
551
619
  '.wakz-msgs {',
552
620
  ' flex: 1;',
553
621
  ' overflow-y: auto;',
554
622
  ' overflow-x: hidden;',
555
- ' padding: 16px 14px 88px;',
556
- ' display: flex;',
557
- ' flex-direction: column;',
558
- ' gap: 4px;',
623
+ ' padding: 0;',
624
+ ' padding-top: 76px;',
625
+ ' padding-bottom: 100px;',
626
+ ' padding-right: 14px;',
627
+ ' padding-left: 14px;',
559
628
  ' scroll-behavior: smooth;',
560
- ' background: var(--wakz-chat-bg);',
561
629
  ' position: relative;',
562
630
  '}',
563
- '.wakz-msgs::-webkit-scrollbar { width: 4px; }',
631
+ '.wakz-msgs::-webkit-scrollbar { width: 3px; }',
564
632
  '.wakz-msgs::-webkit-scrollbar-track { background: transparent; }',
565
633
  '.wakz-msgs::-webkit-scrollbar-thumb {',
566
- ' background: rgba(0,0,0,0.1);',
567
- ' border-radius: 10px;',
634
+ ' background: rgba(0,0,0,0.08);',
635
+ ' border-radius: 99px;',
636
+ '}',
637
+
638
+ '.wakz-msgs-inner {',
639
+ ' display: flex;',
640
+ ' flex-direction: column;',
641
+ ' gap: 6px;',
568
642
  '}',
569
643
 
570
644
  /* ══════════════════════════════════════════════════
571
- MESSAGE ROWS — new v3 styles
645
+ MESSAGE ROWS
572
646
  ══════════════════════════════════════════════════ */
573
647
  '.wakz-msg-row {',
574
648
  ' display: flex;',
575
- ' animation: wakz-msg-in 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;',
576
- '}',
577
- '.wakz-msg-row.bot {',
578
- ' align-self: flex-start;',
579
- ' align-items: flex-start;',
580
- ' gap: 8px;',
581
- ' max-width: 80%;',
582
- '}',
583
- '.wakz-msg-row.user {',
584
- ' align-self: flex-end;',
585
- ' max-width: 75%;',
649
+ ' align-items: flex-end;',
650
+ ' width: 100%;',
651
+ ' animation: wakz-fade-slide-up 0.3s cubic-bezier(0.22,1,0.36,1) both;',
586
652
  '}',
587
653
 
588
- '@keyframes wakz-msg-in {',
589
- ' 0% { opacity: 0; transform: translateY(8px); }',
590
- ' 100% { opacity: 1; transform: translateY(0); }',
654
+ /* ── USER MESSAGE — dark bubble ── */
655
+ '.wakz-msg-row--user { justify-content: flex-end; }',
656
+ '.wakz-user-card {',
657
+ ' max-width: 78%;',
658
+ ' padding: 10px 14px 8px;',
659
+ ' background: #111111;',
660
+ ' color: #ffffff;',
661
+ ' border-radius: 18px 18px 5px 18px;',
662
+ ' box-shadow: 0 2px 10px rgba(0,0,0,0.06), 0 1px 3px rgba(0,0,0,0.03);',
591
663
  '}',
592
-
593
- /* ── User Bubbles ── */
594
- '.wakz-bubble.user {',
595
- ' padding: 10px 14px;',
596
- ' font-size: 14px;',
597
- ' line-height: 1.55;',
598
- ' word-wrap: break-word;',
599
- ' overflow-wrap: break-word;',
664
+ '.wakz-user-text {',
665
+ ' font-size: 13.5px;',
666
+ ' font-weight: 400;',
667
+ ' line-height: 1.7;',
600
668
  ' white-space: pre-wrap;',
601
- ' border-radius: 14px;',
602
- ' border-bottom-right-radius: 4px;',
603
- ' background: var(--wakz-primary);',
604
- ' color: #ffffff;',
605
- ' box-shadow: 0 2px 8px rgba(0,0,0,0.08);',
669
+ ' word-break: break-word;',
670
+ ' text-align: right;',
671
+ ' font-family: "Tajawal", "Cairo", sans-serif;',
672
+ '}',
673
+ '.wakz-user-time {',
674
+ ' font-size: 9.5px;',
675
+ ' color: rgba(255,255,255,0.4);',
676
+ ' display: block;',
677
+ ' margin-top: 4px;',
678
+ ' text-align: left;',
679
+ ' font-family: "Tajawal", sans-serif;',
606
680
  '}',
607
681
 
608
- /* ── Bot MessagesNO bubble, text directly on background ── */
682
+ /* ── BOT MESSAGEno bubble, on background ── */
683
+ '.wakz-msg-row--bot { justify-content: flex-start; }',
609
684
  '.wakz-bot-content {',
685
+ ' max-width: 78%;',
610
686
  ' display: flex;',
611
687
  ' flex-direction: column;',
612
- ' gap: 2px;',
613
- ' min-width: 0;',
688
+ ' align-items: flex-end;',
689
+ ' gap: 1px;',
690
+ '}',
691
+ '.wakz-bot-label {',
692
+ ' font-size: 10px;',
693
+ ' font-weight: 700;',
694
+ ' color: #aaa;',
695
+ ' letter-spacing: 0.1px;',
696
+ ' padding: 0 4px;',
697
+ ' font-family: "Cairo", sans-serif;',
614
698
  '}',
615
699
  '.wakz-bot-text {',
616
- ' font-size: 14px;',
617
- ' line-height: 1.6;',
618
- ' color: #404040;',
619
- ' word-wrap: break-word;',
620
- ' overflow-wrap: break-word;',
700
+ ' font-size: 13.5px;',
701
+ ' font-weight: 400;',
702
+ ' line-height: 1.75;',
703
+ ' color: #333333;',
621
704
  ' white-space: pre-wrap;',
705
+ ' word-break: break-word;',
706
+ ' text-align: right;',
707
+ ' font-family: "Tajawal", "Cairo", sans-serif;',
708
+ ' padding: 0 4px;',
622
709
  '}',
623
- '.wakz-bot-ts {',
624
- ' font-size: 10px;',
625
- ' color: #A3A3A3;',
710
+ '.wakz-bot-time {',
711
+ ' font-size: 9.5px;',
712
+ ' color: #cccccc;',
713
+ ' display: block;',
714
+ ' margin-top: 1px;',
715
+ ' text-align: left;',
716
+ ' padding-left: 4px;',
717
+ ' font-family: "Tajawal", sans-serif;',
626
718
  '}',
627
719
 
628
- /* ── Bot Avatar (22px, inline with message) ── */
629
- '.wakz-bot-avatar {',
630
- ' width: 22px;',
631
- ' height: 22px;',
632
- ' border-radius: 50%;',
633
- ' background: rgba(23,23,23,0.08);',
720
+ /* ── SUPPORT MESSAGE green accent ── */
721
+ '.wakz-msg-row--support { justify-content: flex-start; }',
722
+ '.wakz-support-content {',
723
+ ' max-width: 78%;',
634
724
  ' display: flex;',
635
- ' align-items: center;',
636
- ' justify-content: center;',
637
- ' font-weight: 700;',
725
+ ' flex-direction: column;',
726
+ ' align-items: flex-end;',
727
+ ' gap: 1px;',
728
+ ' border-right: 2.5px solid #22c55e;',
729
+ ' padding-right: 10px;',
730
+ '}',
731
+ '.wakz-support-label {',
638
732
  ' font-size: 10px;',
733
+ ' font-weight: 700;',
734
+ ' color: #16a34a;',
735
+ ' letter-spacing: 0.1px;',
736
+ ' padding: 0 4px;',
737
+ ' font-family: "Cairo", sans-serif;',
738
+ ' display: flex;',
739
+ ' align-items: center;',
740
+ ' gap: 4px;',
741
+ '}',
742
+ '.wakz-support-label-dot {',
743
+ ' width: 4px;',
744
+ ' height: 4px;',
745
+ ' border-radius: 50%;',
746
+ ' background: #22c55e;',
639
747
  ' flex-shrink: 0;',
640
- ' color: var(--wakz-primary);',
641
- ' margin-top: 2px;',
642
748
  '}',
643
-
644
- /* ── User Timestamp ── */
645
- '.wakz-ts {',
646
- ' display: block;',
647
- ' font-size: 10px;',
648
- ' opacity: 0.7;',
649
- ' margin-top: 3px;',
749
+ '.wakz-support-text {',
750
+ ' font-size: 13.5px;',
751
+ ' font-weight: 400;',
752
+ ' line-height: 1.75;',
753
+ ' color: #333333;',
754
+ ' white-space: pre-wrap;',
755
+ ' word-break: break-word;',
650
756
  ' text-align: right;',
757
+ ' font-family: "Tajawal", "Cairo", sans-serif;',
758
+ ' padding: 0 4px;',
759
+ '}',
760
+ '.wakz-support-time {',
761
+ ' font-size: 9.5px;',
762
+ ' color: #cccccc;',
763
+ ' display: block;',
764
+ ' margin-top: 1px;',
765
+ ' text-align: left;',
766
+ ' padding-left: 4px;',
767
+ ' font-family: "Tajawal", sans-serif;',
651
768
  '}',
652
769
 
653
770
  /* ── Error Messages ── */
654
- '.wakz-bubble.error-bubble {',
771
+ '.wakz-error-bubble {',
772
+ ' max-width: 78%;',
655
773
  ' padding: 10px 14px;',
656
- ' font-size: 14px;',
657
- ' line-height: 1.55;',
658
- ' word-wrap: break-word;',
659
- ' overflow-wrap: break-word;',
774
+ ' font-size: 13.5px;',
775
+ ' line-height: 1.6;',
660
776
  ' white-space: pre-wrap;',
777
+ ' word-break: break-word;',
661
778
  ' border-radius: 14px;',
662
779
  ' border-bottom-left-radius: 4px;',
663
780
  ' background: #FEF2F2;',
664
781
  ' color: #DC2626;',
665
782
  ' border: 1px solid #FECACA;',
783
+ ' font-family: "Tajawal", "Cairo", sans-serif;',
666
784
  '}',
667
785
 
668
- /* ── Human Agent Badge ── */
669
- '.wakz-human-badge {',
670
- ' display: inline-block;',
671
- ' font-size: 10px;',
672
- ' background: rgba(22, 163, 74, 0.08);',
673
- ' color: #16A34A;',
674
- ' border-radius: 6px;',
675
- ' padding: 2px 8px;',
676
- ' margin-top: 4px;',
677
- ' font-weight: 600;',
678
- ' letter-spacing: 0.2px;',
679
- '}',
680
-
681
- /* ── Retry Button (inside error bubble) ── */
786
+ /* ── Retry Button ── */
682
787
  '.wakz-retry {',
683
788
  ' display: inline-flex;',
684
789
  ' align-items: center;',
@@ -692,183 +797,226 @@
692
797
  ' background: #ffffff;',
693
798
  ' color: #dc2626;',
694
799
  ' cursor: pointer;',
695
- ' font-family: var(--wakz-font);',
696
- ' transition: background var(--wakz-transition), border-color var(--wakz-transition);',
800
+ ' font-family: "Cairo", "Tajawal", sans-serif;',
801
+ ' transition: background 0.2s ease, border-color 0.2s ease;',
697
802
  ' outline: none;',
698
803
  '}',
699
- '.wakz-retry:hover {',
700
- ' background: #fef2f2;',
701
- ' border-color: #f87171;',
702
- '}',
804
+ '.wakz-retry:hover { background: #fef2f2; border-color: #f87171; }',
703
805
 
704
806
  /* ══════════════════════════════════════════════════
705
- TYPING INDICATOR — no bubble, just dots on background
807
+ TYPING INDICATOR
706
808
  ══════════════════════════════════════════════════ */
707
809
  '.wakz-typing-row {',
708
810
  ' display: flex;',
709
- ' align-items: flex-start;',
710
- ' gap: 8px;',
711
- ' align-self: flex-start;',
712
- ' animation: wakz-msg-in 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;',
811
+ ' align-items: flex-end;',
812
+ ' justify-content: flex-start;',
813
+ ' width: 100%;',
814
+ ' animation: wakz-fade-slide-up 0.25s ease both;',
815
+ '}',
816
+ '.wakz-typing-content {',
817
+ ' display: flex;',
818
+ ' flex-direction: column;',
819
+ ' align-items: flex-end;',
820
+ ' gap: 3px;',
821
+ '}',
822
+ '.wakz-typing-label {',
823
+ ' font-size: 10px;',
824
+ ' font-weight: 700;',
825
+ ' color: #aaa;',
826
+ ' padding: 0 4px;',
827
+ ' font-family: "Cairo", sans-serif;',
713
828
  '}',
714
- '.wakz-typing {',
829
+ '.wakz-typing-dots {',
715
830
  ' display: flex;',
716
831
  ' align-items: center;',
717
832
  ' gap: 4px;',
718
- ' padding: 6px 0;',
833
+ ' padding: 8px 12px;',
719
834
  '}',
720
- '.wakz-typing-dot {',
835
+ '.wakz-typing-dots span {',
721
836
  ' width: 6px;',
722
837
  ' height: 6px;',
723
838
  ' border-radius: 50%;',
724
- ' background: #A3A3A3;',
725
- ' animation: wakz-bounce-dot 1.4s ease-in-out infinite;',
726
- '}',
727
- '.wakz-typing-dot:nth-child(2) { animation-delay: 0.16s; }',
728
- '.wakz-typing-dot:nth-child(3) { animation-delay: 0.32s; }',
729
- '@keyframes wakz-bounce-dot {',
730
- ' 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }',
731
- ' 30% { transform: translateY(-7px); opacity: 1; }',
839
+ ' background: #bbb;',
840
+ ' animation: wakz-typing-bounce 1.4s ease-in-out infinite;',
732
841
  '}',
842
+ '.wakz-typing-dots span:nth-child(1) { animation-delay: 0s; }',
843
+ '.wakz-typing-dots span:nth-child(2) { animation-delay: 0.18s; }',
844
+ '.wakz-typing-dots span:nth-child(3) { animation-delay: 0.36s; }',
733
845
 
734
846
  /* ══════════════════════════════════════════════════
735
- INPUT AREAFloating, glass effect, inside messages
847
+ FLOATING INPUT WRAPabsolute bottom
736
848
  ══════════════════════════════════════════════════ */
737
- '.wakz-input-area {',
849
+ '.wakz-input-wrap {',
738
850
  ' position: absolute;',
739
851
  ' bottom: 12px;',
740
- ' left: 12px;',
741
852
  ' right: 12px;',
853
+ ' left: 12px;',
854
+ ' z-index: 100;',
855
+ ' pointer-events: none;',
856
+ '}',
857
+ '.wakz-input-row {',
858
+ ' pointer-events: all;',
859
+ ' width: 100%;',
742
860
  ' display: flex;',
743
- ' align-items: flex-end;',
861
+ ' align-items: center;',
744
862
  ' gap: 8px;',
745
- ' padding: 8px 10px 8px 14px;',
746
- ' border-radius: 12px;',
863
+ '}',
864
+
865
+ /* ── Input Glass Pill ── */
866
+ '.wakz-input-glass {',
867
+ ' flex: 1;',
868
+ ' display: flex;',
869
+ ' align-items: center;',
870
+ ' position: relative;',
871
+ ' overflow: hidden;',
872
+ ' backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
873
+ ' -webkit-backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
747
874
  ' background: rgba(255,255,255,0.85);',
748
- ' backdrop-filter: blur(24px);',
749
- ' -webkit-backdrop-filter: blur(24px);',
750
- ' border: 1px solid rgba(229,229,229,0.6);',
751
- ' box-shadow: 0 4px 12px rgba(0,0,0,0.05);',
752
- ' z-index: 10;',
875
+ ' border: 0.5px solid rgba(255,255,255,0.7);',
876
+ ' border-radius: 9999px;',
877
+ ' box-shadow:',
878
+ ' inset 0 1px 0 0 rgba(255,255,255,0.9),',
879
+ ' inset 0 -1px 0 0 rgba(0,0,0,0.04),',
880
+ ' 0 0 0 0.5px rgba(0,0,0,0.06),',
881
+ ' 0 8px 32px rgba(0,0,0,0.08),',
882
+ ' 0 2px 8px rgba(0,0,0,0.04);',
883
+ ' padding: 8px 16px;',
884
+ '}',
885
+
886
+ /* ── Input specular highlight ── */
887
+ '.wakz-input-specular {',
888
+ ' position: absolute;',
889
+ ' top: 0;',
890
+ ' left: 10%;',
891
+ ' right: 10%;',
892
+ ' height: 1px;',
893
+ ' background: linear-gradient(',
894
+ ' 90deg,',
895
+ ' transparent,',
896
+ ' rgba(255,255,255,0.5) 20%,',
897
+ ' rgba(255,255,255,0.8) 50%,',
898
+ ' rgba(255,255,255,0.5) 80%,',
899
+ ' transparent',
900
+ ' );',
901
+ ' border-radius: inherit;',
902
+ ' pointer-events: none;',
903
+ ' z-index: 1;',
753
904
  '}',
905
+
906
+ /* ── Textarea ── */
754
907
  '.wakz-input {',
755
908
  ' flex: 1;',
909
+ ' resize: none;',
756
910
  ' border: none;',
757
- ' border-radius: 0;',
758
- ' padding: 6px 4px;',
759
- ' font-size: 14px;',
760
- ' line-height: 1.4;',
761
911
  ' outline: none;',
762
- ' font-family: var(--wakz-font);',
763
- ' resize: none;',
764
- ' max-height: 80px;',
765
- ' min-height: 22px;',
766
- ' overflow-y: auto;',
767
912
  ' background: transparent;',
768
- ' color: #171717;',
769
- '}',
770
- '.wakz-input:focus {',
771
- ' outline: none;',
913
+ ' font-family: "Tajawal", "Cairo", sans-serif;',
914
+ ' font-size: 13.5px;',
915
+ ' font-weight: 400;',
916
+ ' color: #111;',
917
+ ' line-height: 1.5;',
918
+ ' padding: 1px 4px;',
919
+ ' max-height: 48px;',
920
+ ' overflow-y: auto;',
921
+ ' align-self: center;',
772
922
  '}',
773
923
  '.wakz-input::placeholder {',
774
- ' color: #A3A3A3;',
924
+ ' color: #bbb;',
925
+ ' font-weight: 400;',
926
+ ' font-family: "Cairo", "Tajawal", sans-serif;',
775
927
  '}',
928
+ '.wakz-input:focus { outline: none; }',
929
+ '.wakz-input::-webkit-scrollbar { width: 3px; }',
930
+ '.wakz-input::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.1); border-radius: 99px; }',
776
931
 
777
- /* ── Send Button (36px floating circle, separate from input) ── */
932
+ /* ── Send Button 40px circle, separate ── */
778
933
  '.wakz-send {',
779
- ' width: 36px;',
780
- ' height: 36px;',
781
- ' min-width: 36px;',
934
+ ' flex-shrink: 0;',
935
+ ' width: 40px;',
936
+ ' height: 40px;',
937
+ ' min-width: 40px;',
938
+ ' min-height: 40px;',
782
939
  ' border-radius: 50%;',
783
940
  ' border: none;',
784
- ' color: #ffffff;',
785
941
  ' cursor: pointer;',
786
942
  ' display: flex;',
787
943
  ' align-items: center;',
788
944
  ' justify-content: center;',
789
- ' flex-shrink: 0;',
790
- ' transition: transform var(--wakz-transition), opacity var(--wakz-transition), box-shadow var(--wakz-transition);',
945
+ ' position: relative;',
946
+ ' overflow: hidden;',
947
+ ' transition: all 0.25s cubic-bezier(0.22,1,0.36,1);',
791
948
  ' outline: none;',
792
- ' background: var(--wakz-primary);',
793
- ' box-shadow: 0 2px 8px rgba(0,0,0,0.12);',
794
- '}',
795
- '.wakz-send:hover:not(:disabled) {',
796
- ' transform: scale(1.05);',
797
- ' box-shadow: 0 4px 14px rgba(0,0,0,0.18);',
798
- '}',
799
- '.wakz-send:disabled {',
800
- ' opacity: 0.3;',
801
- ' cursor: not-allowed;',
802
- '}',
803
- '.wakz-send:not(:disabled):active {',
804
- ' transform: scale(0.92);',
949
+ ' backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
950
+ ' -webkit-backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
951
+ ' background: rgba(255,255,255,0.82);',
952
+ ' border: 0.5px solid rgba(255,255,255,0.7);',
953
+ ' box-shadow:',
954
+ ' inset 0 1px 0 0 rgba(255,255,255,0.9),',
955
+ ' inset 0 -1px 0 0 rgba(0,0,0,0.04),',
956
+ ' 0 0 0 0.5px rgba(0,0,0,0.06),',
957
+ ' 0 4px 16px rgba(0,0,0,0.06);',
958
+ ' color: #bbb;',
805
959
  '}',
960
+ '.wakz-send:disabled { cursor: default; }',
806
961
  '.wakz-send svg {',
807
- ' width: 16px;',
808
- ' height: 16px;',
962
+ ' width: 18px;',
963
+ ' height: 18px;',
809
964
  ' pointer-events: none;',
810
965
  '}',
811
-
812
- /* ══════════════════════════════════════════════════
813
- WELCOME MESSAGE — same as bot (no bubble)
814
- ══════════════════════════════════════════════════ */
815
- '.wakz-welcome-wrap {',
816
- ' display: flex;',
817
- ' align-items: flex-start;',
818
- ' gap: 8px;',
819
- ' max-width: 80%;',
820
- ' align-self: flex-start;',
821
- ' animation: wakz-msg-in 0.35s cubic-bezier(0.4, 0, 0.2, 1) forwards;',
966
+ /* ── Send Active State ── */
967
+ '.wakz-send--active {',
968
+ ' background: #111111;',
969
+ ' border-color: #111111;',
970
+ ' color: #ffffff;',
971
+ ' filter: none;',
972
+ ' backdrop-filter: none;',
973
+ ' -webkit-backdrop-filter: none;',
974
+ ' box-shadow: 0 4px 20px rgba(0,0,0,0.22), 0 1px 6px rgba(0,0,0,0.12);',
822
975
  '}',
976
+ '.wakz-send--active:hover:not(:disabled) {',
977
+ ' background: #222;',
978
+ ' transform: scale(1.08);',
979
+ ' box-shadow: 0 6px 24px rgba(0,0,0,0.28), 0 2px 8px rgba(0,0,0,0.14);',
980
+ '}',
981
+ '.wakz-send--active:active:not(:disabled) { transform: scale(0.93); }',
823
982
 
824
983
  /* ══════════════════════════════════════════════════
825
984
  RTL SUPPORT
826
985
  ══════════════════════════════════════════════════ */
827
986
  '.wakz-rtl { direction: rtl; }',
828
- '.wakz-rtl .wakz-bubble.user {',
829
- ' border-bottom-right-radius: 14px;',
830
- ' border-bottom-left-radius: 4px;',
987
+ '.wakz-rtl .wakz-user-card {',
988
+ ' border-radius: 18px 18px 18px 5px;',
831
989
  '}',
832
- '.wakz-rtl .wakz-bubble.error-bubble {',
990
+ '.wakz-rtl .wakz-error-bubble {',
833
991
  ' border-bottom-left-radius: 14px;',
834
992
  ' border-bottom-right-radius: 4px;',
835
993
  '}',
836
- '.wakz-rtl .wakz-ts {',
837
- ' text-align: left;',
838
- '}',
839
994
 
840
995
  /* ══════════════════════════════════════════════════
841
- MOBILE RESPONSIVE — centered modal, NOT fullscreen
996
+ RESPONSIVE
842
997
  ══════════════════════════════════════════════════ */
843
- '@media (max-width: 480px) {',
998
+ '@media (max-width: 440px) {',
844
999
  ' .wakz-window {',
845
- ' width: calc(100vw - 32px) !important;',
846
- ' height: min(500px, 75vh) !important;',
847
- ' }',
848
- ' .wakz-window.wakz-visible {',
849
- ' transform: translate(-50%, -50%) scale(1);',
850
- ' }',
851
- ' .wakz-fab {',
852
- ' width: 44px;',
853
- ' height: 44px;',
854
- ' }',
855
- ' .wakz-fab-pos-br { bottom: 16px; right: 16px; }',
856
- ' .wakz-fab-pos-bl { bottom: 16px; left: 16px; }',
857
- ' .wakz-input-area {',
858
- ' left: 10px;',
859
- ' right: 10px;',
860
- ' bottom: 10px;',
861
- ' padding: 6px 8px 6px 12px;',
862
- ' }',
863
- ' .wakz-msgs {',
864
- ' padding: 14px 12px 84px;',
1000
+ ' width: 100% !important;',
1001
+ ' height: 100% !important;',
1002
+ ' max-width: 100% !important;',
1003
+ ' max-height: 100% !important;',
1004
+ ' border-radius: 0 !important;',
1005
+ ' box-shadow: none !important;',
865
1006
  ' }',
1007
+ '}',
1008
+ '@media (max-width: 380px) {',
1009
+ ' .wakz-hdr-title { font-size: 13px; }',
1010
+ ' .wakz-status-pill span:last-child { display: none; }',
1011
+ ' .wakz-status-pill { padding: 4px 8px; }',
1012
+ ' .wakz-send { width: 36px; height: 36px; min-width: 36px; min-height: 36px; }',
1013
+ ' .wakz-close { width: 26px; height: 26px; min-width: 26px; min-height: 26px; }',
866
1014
  '}'
867
1015
  ].join('\n');
868
1016
  };
869
1017
 
870
1018
  /* ════════════════════════════════════════════════════════════════
871
- DOM CREATION — v3.0.0 new structure
1019
+ DOM CREATION — v4.0.0 Liquid Glass structure
872
1020
  ════════════════════════════════════════════════════════════════ */
873
1021
 
874
1022
  WAKZWidget.prototype._createDOM = function () {
@@ -882,6 +1030,13 @@
882
1030
  document.body.appendChild(self._host);
883
1031
  self._shadow = self._host.attachShadow({ mode: 'closed' });
884
1032
 
1033
+ /* ── Google Fonts link (injected into shadow root) ── */
1034
+ var fontsLink = _el('link', {
1035
+ rel: 'stylesheet',
1036
+ href: 'https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700;900&family=Tajawal:wght@300;400;500;700&display=swap'
1037
+ });
1038
+ self._shadow.appendChild(fontsLink);
1039
+
885
1040
  /* ── Root wrapper ── */
886
1041
  self._root = _el('div', { className: 'wakz' + (isRtl ? ' wakz-rtl' : '') });
887
1042
  self._shadow.appendChild(self._styleEl);
@@ -904,46 +1059,69 @@
904
1059
  self._overlay = _el('div', { className: 'wakz-overlay' });
905
1060
  self._root.appendChild(self._overlay);
906
1061
 
907
- /* ══════════════ CHAT WINDOW (Centered Modal) ══════════════ */
1062
+ /* ══════════════ CHAT WINDOW ══════════════ */
908
1063
  self._chatWindow = _el('div', { className: 'wakz-window' });
909
1064
 
910
- /* ── Header (glass effect, dark text) ── */
911
- var headerEl = _el('div', { className: 'wakz-hdr' });
1065
+ /* ── Messages Container (with floating header + input inside) ── */
1066
+ self._messagesContainer = _el('div', { className: 'wakz-msgs' });
912
1067
 
913
- /* Left side: avatar + name + status */
914
- var headerLeft = _el('div', { className: 'wakz-hdr-left' });
915
- var avatarLetter = (self.config.botName || 'W')[0].toUpperCase();
916
- self._headerAvatarEl = _el('div', { className: 'wakz-avatar' }, [avatarLetter]);
917
- headerLeft.appendChild(self._headerAvatarEl);
1068
+ /* ══════════════ FLOATING HEADER (pill, absolute over messages) ══════════════ */
1069
+ var headerWrap = _el('div', { className: 'wakz-header-wrap' });
1070
+ var header = _el('div', { className: 'wakz-header' });
918
1071
 
919
- var headerInfo = _el('div', { className: 'wakz-hdr-info' });
920
- self._headerNameEl = _el('span', { className: 'wakz-hdr-name' }, [self.config.botName]);
921
- headerInfo.appendChild(self._headerNameEl);
1072
+ /* Specular highlight (real DOM element, not ::before) */
1073
+ header.appendChild(_el('div', { className: 'wakz-specular' }));
922
1074
 
923
- var statusLine = _el('span', { className: 'wakz-hdr-status' });
924
- self._headerStatusDot = _el('span', { className: 'wakz-hdr-status-dot ' + (self.config.online ? 'online' : 'offline') });
925
- if (self.config.showStatus) statusLine.appendChild(self._headerStatusDot);
926
- self._headerStatusText = document.createTextNode(self.config.online ? str.online : str.offline);
927
- statusLine.appendChild(self._headerStatusText);
928
- headerInfo.appendChild(statusLine);
1075
+ /* Brand side (right in RTL) */
1076
+ var brand = _el('div', { className: 'wakz-hdr-brand' });
1077
+ var info = _el('div', { className: 'wakz-hdr-info' });
1078
+ self._headerTitleEl = _el('span', { className: 'wakz-hdr-title' }, [self.config.botName]);
1079
+ info.appendChild(self._headerTitleEl);
929
1080
 
930
- headerLeft.appendChild(headerInfo);
931
- headerEl.appendChild(headerLeft);
1081
+ var subtitleText = self.config.botSubtitle || str.defaultSubtitle || '';
1082
+ self._headerSubtitleEl = _el('span', { className: 'wakz-hdr-subtitle' }, [subtitleText]);
1083
+ info.appendChild(self._headerSubtitleEl);
932
1084
 
933
- /* Right side: status dot + text + close button */
934
- var headerRight = _el('div', { className: 'wakz-hdr-right' });
935
- var closeBtn = _el('button', { className: 'wakz-close', 'aria-label': str.closeChat });
936
- closeBtn.innerHTML = _ICONS.close;
937
- headerRight.appendChild(closeBtn);
938
- headerEl.appendChild(headerRight);
1085
+ brand.appendChild(info);
1086
+ header.appendChild(brand);
939
1087
 
940
- self._chatWindow.appendChild(headerEl);
1088
+ /* Actions side (left in RTL) */
1089
+ var actions = _el('div', { className: 'wakz-hdr-actions' });
941
1090
 
942
- /* ── Messages Container (with floating input area inside) ── */
943
- self._messagesContainer = _el('div', { className: 'wakz-msgs' });
1091
+ /* Status pill */
1092
+ self._headerStatusPill = _el('div', {
1093
+ className: 'wakz-status-pill ' + (self.config.online ? 'wakz-status-pill--online' : 'wakz-status-pill--offline')
1094
+ });
1095
+ if (self.config.showStatus) {
1096
+ self._headerStatusDot = _el('span', { className: 'wakz-status-dot' });
1097
+ self._headerStatusPill.appendChild(self._headerStatusDot);
1098
+ self._headerStatusText = document.createTextNode(self.config.online ? str.online : str.offline);
1099
+ self._headerStatusPill.appendChild(self._headerStatusText);
1100
+ }
1101
+ actions.appendChild(self._headerStatusPill);
1102
+
1103
+ /* Close button (glass circle) */
1104
+ self._closeBtn = _el('button', { className: 'wakz-close', 'aria-label': str.closeChat });
1105
+ self._closeBtn.innerHTML = _ICONS.close;
1106
+ actions.appendChild(self._closeBtn);
1107
+
1108
+ header.appendChild(actions);
1109
+ headerWrap.appendChild(header);
1110
+ self._messagesContainer.appendChild(headerWrap);
1111
+
1112
+ /* ── Messages inner (scrollable content) ── */
1113
+ self._messagesInner = _el('div', { className: 'wakz-msgs-inner' });
1114
+ self._messagesContainer.appendChild(self._messagesInner);
944
1115
 
945
- /* ── Floating Input Area (inside messages container) ── */
946
- self._inputArea = _el('div', { className: 'wakz-input-area' });
1116
+ /* ══════════════ FLOATING INPUT (pill, absolute bottom) ══════════════ */
1117
+ self._inputWrap = _el('div', { className: 'wakz-input-wrap' });
1118
+ var inputRow = _el('div', { className: 'wakz-input-row' });
1119
+
1120
+ /* Input glass pill */
1121
+ var inputGlass = _el('div', { className: 'wakz-input-glass' });
1122
+
1123
+ /* Specular highlight for input glass */
1124
+ inputGlass.appendChild(_el('div', { className: 'wakz-input-specular' }));
947
1125
 
948
1126
  self._inputEl = _el('textarea', {
949
1127
  className: 'wakz-input',
@@ -951,18 +1129,21 @@
951
1129
  rows: 1,
952
1130
  dir: isRtl ? 'rtl' : 'ltr'
953
1131
  });
954
- self._inputArea.appendChild(self._inputEl);
1132
+ inputGlass.appendChild(self._inputEl);
1133
+ inputRow.appendChild(inputGlass);
955
1134
 
1135
+ /* Send button (40px circle, separate from input) */
956
1136
  self._sendBtn = _el('button', {
957
1137
  className: 'wakz-send',
958
1138
  'aria-label': str.sendMessage
959
1139
  });
960
1140
  self._sendBtn.innerHTML = _ICONS.send;
961
- self._inputArea.appendChild(self._sendBtn);
1141
+ inputRow.appendChild(self._sendBtn);
962
1142
 
963
- self._messagesContainer.appendChild(self._inputArea);
964
- self._chatWindow.appendChild(self._messagesContainer);
1143
+ self._inputWrap.appendChild(inputRow);
1144
+ self._messagesContainer.appendChild(self._inputWrap);
965
1145
 
1146
+ self._chatWindow.appendChild(self._messagesContainer);
966
1147
  self._root.appendChild(self._chatWindow);
967
1148
  };
968
1149
 
@@ -984,7 +1165,7 @@
984
1165
  });
985
1166
 
986
1167
  /* Close button click */
987
- self._chatWindow.querySelector('.wakz-close').addEventListener('click', function () {
1168
+ self._closeBtn.addEventListener('click', function () {
988
1169
  self.toggleChat(false);
989
1170
  });
990
1171
 
@@ -1001,10 +1182,16 @@
1001
1182
  }
1002
1183
  });
1003
1184
 
1004
- /* Auto-resize textarea (max 80px) */
1185
+ /* Auto-resize textarea (max 48px) + toggle send active state */
1005
1186
  self._inputEl.addEventListener('input', function () {
1006
1187
  self._inputEl.style.height = 'auto';
1007
- self._inputEl.style.height = Math.min(self._inputEl.scrollHeight, 80) + 'px';
1188
+ self._inputEl.style.height = Math.min(self._inputEl.scrollHeight, 48) + 'px';
1189
+ var hasText = (self._inputEl.value || '').trim().length > 0;
1190
+ if (hasText) {
1191
+ self._sendBtn.classList.add('wakz-send--active');
1192
+ } else {
1193
+ self._sendBtn.classList.remove('wakz-send--active');
1194
+ }
1008
1195
  });
1009
1196
 
1010
1197
  /* Escape to close */
@@ -1100,9 +1287,13 @@
1100
1287
  self._statusDot.className = 'wakz-fab-dot offline';
1101
1288
  self._statusDot.style.display = '';
1102
1289
  }
1103
- /* Update header status */
1290
+ /* Update header status pill to offline */
1291
+ if (self._headerStatusPill) {
1292
+ self._headerStatusPill.className = 'wakz-status-pill wakz-status-pill--offline';
1293
+ self._headerStatusPill.style.display = '';
1294
+ }
1104
1295
  if (self._headerStatusDot) {
1105
- self._headerStatusDot.className = 'wakz-hdr-status-dot offline';
1296
+ self._headerStatusDot.className = 'wakz-status-dot';
1106
1297
  }
1107
1298
  if (self._headerStatusText) {
1108
1299
  self._headerStatusText.textContent = _strings(self.config.language).offline;
@@ -1123,7 +1314,6 @@
1123
1314
  hostStyle.setProperty('--wakz-btn', cfg.btnColor);
1124
1315
  hostStyle.setProperty('--wakz-chat-bg', cfg.chatBg);
1125
1316
  hostStyle.setProperty('--wakz-widget-bg', cfg.widgetBg);
1126
- hostStyle.setProperty('--wakz-icon-radius', cfg.iconRadius || '50%');
1127
1317
 
1128
1318
  /* ── RTL ── */
1129
1319
  if (isRtl) self._root.classList.add('wakz-rtl');
@@ -1143,17 +1333,24 @@
1143
1333
  /* ── Overlay ── */
1144
1334
  self._overlay.className = 'wakz-overlay' + (self.isOpen ? ' wakz-visible' : '');
1145
1335
 
1146
- /* ── Bot Name & Avatar ── */
1147
- if (self._headerNameEl) self._headerNameEl.textContent = cfg.botName;
1148
- if (self._headerAvatarEl) self._headerAvatarEl.textContent = (cfg.botName || 'W')[0].toUpperCase();
1149
-
1150
- /* ── Header Status ── */
1151
- if (self._headerStatusDot) {
1152
- self._headerStatusDot.className = 'wakz-hdr-status-dot ' + (cfg.online ? 'online' : 'offline');
1153
- self._headerStatusDot.style.display = cfg.showStatus ? '' : 'none';
1336
+ /* ── Header Title & Subtitle (DYNAMIC from config) ── */
1337
+ if (self._headerTitleEl) self._headerTitleEl.textContent = cfg.botName;
1338
+ if (self._headerSubtitleEl) {
1339
+ var sub = cfg.botSubtitle || str.defaultSubtitle || '';
1340
+ self._headerSubtitleEl.textContent = sub;
1154
1341
  }
1155
- if (self._headerStatusText) {
1156
- self._headerStatusText.textContent = cfg.online ? str.online : str.offline;
1342
+
1343
+ /* ── Header Status Pill ── */
1344
+ if (self._headerStatusPill) {
1345
+ self._headerStatusPill.className = 'wakz-status-pill ' + (cfg.online ? 'wakz-status-pill--online' : 'wakz-status-pill--offline');
1346
+ self._headerStatusPill.style.display = cfg.showStatus ? '' : 'none';
1347
+ /* Rebuild pill content if needed */
1348
+ if (self._headerStatusDot) {
1349
+ self._headerStatusDot.className = 'wakz-status-dot';
1350
+ }
1351
+ if (self._headerStatusText) {
1352
+ self._headerStatusText.textContent = cfg.online ? str.online : str.offline;
1353
+ }
1157
1354
  }
1158
1355
 
1159
1356
  /* ── Input ── */
@@ -1161,8 +1358,7 @@
1161
1358
  self._inputEl.dir = isRtl ? 'rtl' : 'ltr';
1162
1359
 
1163
1360
  /* ── Close button label ── */
1164
- var closeBtn = self._chatWindow.querySelector('.wakz-close');
1165
- if (closeBtn) closeBtn.setAttribute('aria-label', str.closeChat);
1361
+ if (self._closeBtn) self._closeBtn.setAttribute('aria-label', str.closeChat);
1166
1362
 
1167
1363
  /* ── Send button label ── */
1168
1364
  self._sendBtn.setAttribute('aria-label', str.sendMessage);
@@ -1280,11 +1476,10 @@
1280
1476
 
1281
1477
  WAKZWidget.prototype._clearMessages = function () {
1282
1478
  var self = this;
1283
- /* Remove all children except the input area */
1284
- var children = Array.prototype.slice.call(self._messagesContainer.children);
1285
- for (var i = 0; i < children.length; i++) {
1286
- if (children[i] !== self._inputArea) {
1287
- self._messagesContainer.removeChild(children[i]);
1479
+ /* Remove all children from messages-inner */
1480
+ if (self._messagesInner) {
1481
+ while (self._messagesInner.firstChild) {
1482
+ self._messagesInner.removeChild(self._messagesInner.firstChild);
1288
1483
  }
1289
1484
  }
1290
1485
  self.messages = [];
@@ -1292,33 +1487,34 @@
1292
1487
  };
1293
1488
 
1294
1489
  /* ════════════════════════════════════════════════════════════════
1295
- APPEND WELCOME MESSAGE — no bubble style, matching bot messages
1490
+ APPEND WELCOME MESSAGE — no bubble, matching bot messages
1296
1491
  ════════════════════════════════════════════════════════════════ */
1297
1492
 
1298
1493
  WAKZWidget.prototype._appendWelcomeMessage = function (text) {
1299
1494
  var self = this;
1300
1495
  if (!text) return;
1301
1496
 
1302
- var wrap = _el('div', { className: 'wakz-welcome-wrap' });
1303
-
1304
- /* Bot avatar (22px) */
1305
- var avatar = _el('div', { className: 'wakz-bot-avatar' },
1306
- [(self.config.botName || 'W')[0].toUpperCase()]);
1307
- wrap.appendChild(avatar);
1497
+ var row = _el('div', { className: 'wakz-msg-row wakz-msg-row--bot' });
1308
1498
 
1309
- /* Bot text content — no bubble */
1310
1499
  var content = _el('div', { className: 'wakz-bot-content' });
1311
- content.appendChild(_el('div', { className: 'wakz-bot-text' }, [text]));
1312
- wrap.appendChild(content);
1313
1500
 
1314
- /* Insert before input area */
1315
- self._messagesContainer.insertBefore(wrap, self._inputArea);
1501
+ /* Bot label */
1502
+ var label = _el('span', { className: 'wakz-bot-label' }, [self.config.botName]);
1503
+ content.appendChild(label);
1504
+
1505
+ /* Bot text */
1506
+ var textEl = _el('p', { className: 'wakz-bot-text' });
1507
+ textEl.textContent = text;
1508
+ content.appendChild(textEl);
1509
+
1510
+ row.appendChild(content);
1511
+ self._messagesInner.appendChild(row);
1316
1512
  self.messages.push({ sender: 'bot', text: text });
1317
1513
  self._scrollToBottom();
1318
1514
  };
1319
1515
 
1320
1516
  /* ════════════════════════════════════════════════════════════════
1321
- APPEND MESSAGE TO CHAT — v3 rendering
1517
+ APPEND MESSAGE TO CHAT — v4 rendering
1322
1518
  ════════════════════════════════════════════════════════════════ */
1323
1519
 
1324
1520
  WAKZWidget.prototype._appendMessage = function (sender, text, isError, timestamp, isHumanAgent) {
@@ -1342,26 +1538,22 @@
1342
1538
  }
1343
1539
 
1344
1540
  if (sender === 'user') {
1345
- /* ── USER MESSAGE: colored bubble with tail ── */
1346
- var row = _el('div', { className: 'wakz-msg-row user' });
1347
-
1348
- var bubbleClass = 'wakz-bubble user';
1349
- if (isError) bubbleClass += ' error-bubble';
1350
- var bubble = _el('div', { className: bubbleClass });
1351
- bubble.appendChild(document.createTextNode(text));
1352
- bubble.appendChild(_el('span', { className: 'wakz-ts' }, [tsText]));
1353
-
1354
- /* Retry button for error user messages */
1541
+ /* ── USER MESSAGE: dark bubble (#111) ── */
1355
1542
  if (isError) {
1356
- var str = _strings(self.config.language);
1357
- var retryBtn = _el('button', { className: 'wakz-retry' }, [
1358
- _ICONS.error + ' ' + str.retry
1543
+ /* Error: red error bubble */
1544
+ var errRow = _el('div', { className: 'wakz-msg-row wakz-msg-row--user' });
1545
+ var errBubble = _el('div', { className: 'wakz-error-bubble' });
1546
+ errBubble.appendChild(document.createTextNode(text));
1547
+
1548
+ var errStr = _strings(self.config.language);
1549
+ var errRetryBtn = _el('button', { className: 'wakz-retry' }, [
1550
+ _ICONS.error + ' ' + errStr.retry
1359
1551
  ]);
1360
- (function (rowCapture) {
1361
- retryBtn.addEventListener('click', function () {
1552
+ (function (rowCapture, errText) {
1553
+ errRetryBtn.addEventListener('click', function () {
1362
1554
  if (rowCapture.parentNode) rowCapture.parentNode.removeChild(rowCapture);
1363
1555
  for (var i = self.messages.length - 1; i >= 0; i--) {
1364
- if (self.messages[i].text === text && self.messages[i].isError) {
1556
+ if (self.messages[i].text === errText && self.messages[i].isError) {
1365
1557
  self.messages.splice(i, 1);
1366
1558
  break;
1367
1559
  }
@@ -1375,36 +1567,60 @@
1375
1567
  }
1376
1568
  if (lastUserMsg) self._sendToAPI(lastUserMsg);
1377
1569
  });
1378
- })(row);
1379
- bubble.appendChild(retryBtn);
1570
+ })(errRow, text);
1571
+ errBubble.appendChild(errRetryBtn);
1572
+ errRow.appendChild(errBubble);
1573
+ self._messagesInner.appendChild(errRow);
1574
+ self.messages.push({ sender: sender, text: text, isError: !!isError });
1575
+ } else {
1576
+ /* Normal user message: dark bubble */
1577
+ var userRow = _el('div', { className: 'wakz-msg-row wakz-msg-row--user' });
1578
+ var userCard = _el('div', { className: 'wakz-user-card' });
1579
+
1580
+ var userText = _el('p', { className: 'wakz-user-text' });
1581
+ userText.textContent = text; /* XSS safe: textContent */
1582
+ userCard.appendChild(userText);
1583
+
1584
+ userCard.appendChild(_el('span', { className: 'wakz-user-time' }, [tsText]));
1585
+ userRow.appendChild(userCard);
1586
+ self._messagesInner.appendChild(userRow);
1587
+ self.messages.push({ sender: sender, text: text, isError: false });
1380
1588
  }
1381
-
1382
- row.appendChild(bubble);
1383
- self._messagesContainer.insertBefore(row, self._inputArea);
1384
- self.messages.push({ sender: sender, text: text, isError: !!isError });
1589
+ } else if (isHumanAgent) {
1590
+ /* ── SUPPORT MESSAGE: green accent ── */
1591
+ var supRow = _el('div', { className: 'wakz-msg-row wakz-msg-row--support' });
1592
+ var supContent = _el('div', { className: 'wakz-support-content' });
1593
+
1594
+ /* Support label with dot */
1595
+ var supLabel = _el('span', { className: 'wakz-support-label' });
1596
+ supLabel.appendChild(_el('span', { className: 'wakz-support-label-dot' }));
1597
+ var supStr = _strings(self.config.language);
1598
+ supLabel.appendChild(document.createTextNode(supStr.humanBadge || 'Support Team'));
1599
+ supContent.appendChild(supLabel);
1600
+
1601
+ /* Support text */
1602
+ var supText = _el('p', { className: 'wakz-support-text' });
1603
+ supText.textContent = text; /* XSS safe: textContent */
1604
+ supContent.appendChild(supText);
1605
+
1606
+ supContent.appendChild(_el('span', { className: 'wakz-support-time' }, [tsText]));
1607
+ supRow.appendChild(supContent);
1608
+ self._messagesInner.appendChild(supRow);
1609
+ self.messages.push({ sender: 'support', text: text, isError: false });
1385
1610
  } else {
1386
- /* ── BOT / HUMAN AGENT MESSAGE: no bubble, text on background ── */
1387
- var botRow = _el('div', { className: 'wakz-msg-row bot' });
1388
-
1389
- /* Small bot avatar (22px) */
1390
- var botAvatar = _el('div', { className: 'wakz-bot-avatar' },
1391
- [(self.config.botName || 'W')[0].toUpperCase()]);
1392
- botRow.appendChild(botAvatar);
1393
-
1394
- /* Content wrapper */
1395
- var botContent = _el('div', { className: 'wakz-bot-content' });
1396
-
1611
+ /* ── BOT MESSAGE: no bubble, on background ── */
1397
1612
  if (isError) {
1398
- /* Error: subtle red area */
1399
- var errBubble = _el('div', { className: 'wakz-bubble error-bubble' });
1400
- errBubble.appendChild(document.createTextNode(text));
1401
-
1402
- var errStr = _strings(self.config.language);
1403
- var errRetryBtn = _el('button', { className: 'wakz-retry' }, [
1404
- _ICONS.error + ' ' + errStr.retry
1613
+ /* Error: red error bubble */
1614
+ var botErrRow = _el('div', { className: 'wakz-msg-row wakz-msg-row--bot' });
1615
+ var botErrBubble = _el('div', { className: 'wakz-error-bubble' });
1616
+ botErrBubble.appendChild(document.createTextNode(text));
1617
+
1618
+ var botErrStr = _strings(self.config.language);
1619
+ var botErrRetry = _el('button', { className: 'wakz-retry' }, [
1620
+ _ICONS.error + ' ' + botErrStr.retry
1405
1621
  ]);
1406
1622
  (function (rowCapture, errText) {
1407
- errRetryBtn.addEventListener('click', function () {
1623
+ botErrRetry.addEventListener('click', function () {
1408
1624
  if (rowCapture.parentNode) rowCapture.parentNode.removeChild(rowCapture);
1409
1625
  for (var i = self.messages.length - 1; i >= 0; i--) {
1410
1626
  if (self.messages[i].text === errText && self.messages[i].isError) {
@@ -1421,34 +1637,38 @@
1421
1637
  }
1422
1638
  if (lastUserMsg) self._sendToAPI(lastUserMsg);
1423
1639
  });
1424
- })(botRow, text);
1425
- errBubble.appendChild(errRetryBtn);
1426
- botContent.appendChild(errBubble);
1640
+ })(botErrRow, text);
1641
+ botErrBubble.appendChild(botErrRetry);
1642
+ botErrRow.appendChild(botErrBubble);
1643
+ self._messagesInner.appendChild(botErrRow);
1644
+ self.messages.push({ sender: sender, text: text, isError: true });
1427
1645
  } else {
1428
- /* Normal bot/human message: no bubble */
1429
- botContent.appendChild(_el('div', { className: 'wakz-bot-text' }, [text]));
1646
+ /* Normal bot message: no bubble */
1647
+ var botRow = _el('div', { className: 'wakz-msg-row wakz-msg-row--bot' });
1648
+ var botContent = _el('div', { className: 'wakz-bot-content' });
1649
+
1650
+ /* Bot label */
1651
+ botContent.appendChild(_el('span', { className: 'wakz-bot-label' }, [self.config.botName]));
1652
+
1653
+ /* Bot text */
1654
+ var botTextEl = _el('p', { className: 'wakz-bot-text' });
1655
+ botTextEl.textContent = text; /* XSS safe: textContent */
1656
+ botContent.appendChild(botTextEl);
1430
1657
 
1431
1658
  /* Timestamp */
1432
- botContent.appendChild(_el('span', { className: 'wakz-bot-ts' }, [tsText]));
1659
+ botContent.appendChild(_el('span', { className: 'wakz-bot-time' }, [tsText]));
1433
1660
 
1434
- /* Human agent badge */
1435
- if (isHumanAgent) {
1436
- var iStr = _strings(self.config.language);
1437
- var badge = _el('span', { className: 'wakz-human-badge' }, [iStr.humanBadge || '👤 فريق الدعم']);
1438
- botContent.appendChild(badge);
1439
- }
1661
+ botRow.appendChild(botContent);
1662
+ self._messagesInner.appendChild(botRow);
1663
+ self.messages.push({ sender: sender, text: text, isError: false });
1440
1664
  }
1441
-
1442
- botRow.appendChild(botContent);
1443
- self._messagesContainer.insertBefore(botRow, self._inputArea);
1444
- self.messages.push({ sender: sender, text: text, isError: !!isError });
1445
1665
  }
1446
1666
 
1447
1667
  self._scrollToBottom();
1448
1668
  };
1449
1669
 
1450
1670
  /* ════════════════════════════════════════════════════════════════
1451
- TYPING INDICATOR — no bubble, dots on background with avatar
1671
+ TYPING INDICATOR — dots with label, no bubble
1452
1672
  ════════════════════════════════════════════════════════════════ */
1453
1673
 
1454
1674
  WAKZWidget.prototype._showTyping = function () {
@@ -1457,18 +1677,20 @@
1457
1677
 
1458
1678
  self._typingEl = _el('div', { className: 'wakz-typing-row' });
1459
1679
 
1460
- /* Small avatar for consistency */
1461
- self._typingEl.appendChild(_el('div', { className: 'wakz-bot-avatar' },
1462
- [(self.config.botName || 'W')[0].toUpperCase()]));
1680
+ var typingContent = _el('div', { className: 'wakz-typing-content' });
1681
+
1682
+ /* Typing label */
1683
+ typingContent.appendChild(_el('span', { className: 'wakz-typing-label' }, [self.config.botName]));
1463
1684
 
1464
- /* Bouncing dots — no bubble wrapper */
1465
- var typingDots = _el('div', { className: 'wakz-typing' });
1466
- typingDots.appendChild(_el('span', { className: 'wakz-typing-dot' }));
1467
- typingDots.appendChild(_el('span', { className: 'wakz-typing-dot' }));
1468
- typingDots.appendChild(_el('span', { className: 'wakz-typing-dot' }));
1469
- self._typingEl.appendChild(typingDots);
1685
+ /* Bouncing dots */
1686
+ var typingDots = _el('div', { className: 'wakz-typing-dots' });
1687
+ typingDots.appendChild(_el('span'));
1688
+ typingDots.appendChild(_el('span'));
1689
+ typingDots.appendChild(_el('span'));
1690
+ typingContent.appendChild(typingDots);
1470
1691
 
1471
- self._messagesContainer.insertBefore(self._typingEl, self._inputArea);
1692
+ self._typingEl.appendChild(typingContent);
1693
+ self._messagesInner.appendChild(self._typingEl);
1472
1694
  self._scrollToBottom();
1473
1695
  };
1474
1696
 
@@ -1508,6 +1730,7 @@
1508
1730
  /* Clear input */
1509
1731
  self._inputEl.value = '';
1510
1732
  self._inputEl.style.height = 'auto';
1733
+ self._sendBtn.classList.remove('wakz-send--active');
1511
1734
 
1512
1735
  /* Send to API */
1513
1736
  self._sendToAPI(text);
@@ -1587,7 +1810,7 @@
1587
1810
  ════════════════════════════════════════════════════════════════ */
1588
1811
 
1589
1812
  function boot() {
1590
- try { new WAKZWidget(); } catch (e) { console.error('[WAKZ Widget v3.0.0] Init error:', e); }
1813
+ try { new WAKZWidget(); } catch (e) { console.error('[WAKZ Widget v4.0.0] Init error:', e); }
1591
1814
  }
1592
1815
 
1593
1816
  if (document.readyState === 'loading') {