ttp-agent-sdk 2.45.7 → 2.45.12

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.
@@ -10641,7 +10641,8 @@ __webpack_require__.r(__webpack_exports__);
10641
10641
  /* harmony export */ CLIENT_TOOLS_PARTNER_ID: () => (/* binding */ CLIENT_TOOLS_PARTNER_ID),
10642
10642
  /* harmony export */ ClientScriptManager: () => (/* binding */ ClientScriptManager)
10643
10643
  /* harmony export */ });
10644
- /* harmony import */ var _ecommerce_PartnerScriptRunner_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../ecommerce/PartnerScriptRunner.js */ "./src/ecommerce/PartnerScriptRunner.js");
10644
+ /* harmony import */ var _ClientToolsRegistry_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ClientToolsRegistry.js */ "./src/core/ClientToolsRegistry.js");
10645
+ /* harmony import */ var _ecommerce_PartnerScriptRunner_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../ecommerce/PartnerScriptRunner.js */ "./src/ecommerce/PartnerScriptRunner.js");
10645
10646
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
10646
10647
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
10647
10648
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -10688,11 +10689,10 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
10688
10689
  */
10689
10690
 
10690
10691
 
10692
+
10691
10693
  /** Reserved partner id for the flavor-independent client-tool bundle. */
10692
10694
  var CLIENT_TOOLS_PARTNER_ID = '__client_tools__';
10693
-
10694
- /** Mirror of ClientToolsRegistry.MAX_RESULT_SIZE — 50KB cap on result payloads. */
10695
- var MAX_RESULT_SIZE = 50000;
10695
+ var MAX_RESULT_SIZE = _ClientToolsRegistry_js__WEBPACK_IMPORTED_MODULE_0__["default"].MAX_RESULT_SIZE;
10696
10696
  var LOG = '[ClientScriptManager]';
10697
10697
  var ClientScriptManager = /*#__PURE__*/function () {
10698
10698
  /**
@@ -10711,7 +10711,7 @@ var ClientScriptManager = /*#__PURE__*/function () {
10711
10711
  _classCallCheck(this, ClientScriptManager);
10712
10712
  this._send = typeof send === 'function' ? send : function () {};
10713
10713
  this._label = label;
10714
- this.runner = new _ecommerce_PartnerScriptRunner_js__WEBPACK_IMPORTED_MODULE_0__.PartnerScriptRunner({
10714
+ this.runner = new _ecommerce_PartnerScriptRunner_js__WEBPACK_IMPORTED_MODULE_1__.PartnerScriptRunner({
10715
10715
  genericCtx: true
10716
10716
  });
10717
10717
  // Unsolicited adapter pushes (ctx.emit) go back over the same channel.
@@ -10735,7 +10735,7 @@ var ClientScriptManager = /*#__PURE__*/function () {
10735
10735
  * {@link isClientToolsToolCall}) against the client-tool runner and answer
10736
10736
  * with the standard `client_tool_result` / `client_tool_error` envelopes —
10737
10737
  * the exact shapes ClientToolsRegistry sends, since the backend awaits the
10738
- * reply keyed by `toolCallId`. Enforces the 50KB result cap.
10738
+ * reply keyed by `toolCallId`. Enforces the result-size cap ({@link ClientToolsRegistry.MAX_RESULT_SIZE}).
10739
10739
  *
10740
10740
  * @param {object} message { toolCallId, toolName, parameters:{ action, args, partner_id } }
10741
10741
  * @param {string|null} conversationId the SDK's current conversation id
@@ -10875,7 +10875,7 @@ var ClientScriptManager = /*#__PURE__*/function () {
10875
10875
  /**
10876
10876
  * Execute a `run_partner_script` envelope against the client-tool runner and
10877
10877
  * post the `run_partner_script_result` back over the channel. Enforces the
10878
- * 50KB result-size cap (oversize → ok:false, error:'RESULT_TOO_LARGE').
10878
+ * result-size cap (mirror ClientToolsRegistry.MAX_RESULT_SIZE).
10879
10879
  *
10880
10880
  * An unknown action (e.g. bundle not yet received) resolves to ok:false with
10881
10881
  * the runner's `adapter_not_in_bundle` reason — same behavior as the existing
@@ -10908,7 +10908,7 @@ var ClientScriptManager = /*#__PURE__*/function () {
10908
10908
  case 3:
10909
10909
  result = _context2.v;
10910
10910
  elapsedMs = Date.now() - startedAt;
10911
- ok = result && _typeof(result) === 'object' && 'ok' in result ? !!result.ok : true; // 50KB result-size cap (mirror ClientToolsRegistry.MAX_RESULT_SIZE).
10911
+ ok = result && _typeof(result) === 'object' && 'ok' in result ? !!result.ok : true; // Result-size cap (mirror ClientToolsRegistry.MAX_RESULT_SIZE).
10912
10912
  serializedSize = 0;
10913
10913
  try {
10914
10914
  serializedSize = JSON.stringify(result).length;
@@ -11045,7 +11045,7 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
11045
11045
  * the registered handler and sends back the result or error.
11046
11046
  */
11047
11047
  var ClientToolsRegistry = /*#__PURE__*/function () {
11048
- // 500KB for results containing images (base64)
11048
+ // ~500KB cap on all client_tool_result payloads
11049
11049
 
11050
11050
  function ClientToolsRegistry(sendMessage) {
11051
11051
  var getConversationId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
@@ -11205,10 +11205,7 @@ var ClientToolsRegistry = /*#__PURE__*/function () {
11205
11205
  value: function sendResult(toolCallId, toolName, result, executionTimeMs) {
11206
11206
  var conversationId = this.getConversationId();
11207
11207
  var timestamp = new Date().toISOString();
11208
-
11209
- // Size validation — images (base64) get a higher limit than text-only results
11210
- var hasImage = result && _typeof(result) === 'object' && result.image && result.mimeType;
11211
- var maxSize = hasImage ? ClientToolsRegistry.MAX_IMAGE_RESULT_SIZE : ClientToolsRegistry.MAX_RESULT_SIZE;
11208
+ var maxSize = ClientToolsRegistry.MAX_RESULT_SIZE;
11212
11209
  var serializedSize = 0;
11213
11210
  try {
11214
11211
  serializedSize = JSON.stringify(result).length;
@@ -11218,7 +11215,9 @@ var ClientToolsRegistry = /*#__PURE__*/function () {
11218
11215
  if (serializedSize > maxSize) {
11219
11216
  var sizeKB = Math.round(serializedSize / 1024);
11220
11217
  var limitKB = Math.round(maxSize / 1024);
11221
- console.error("\uD83D\uDD27 ClientTools: Result for '".concat(toolName, "' exceeds size limit (").concat(sizeKB, "KB > ").concat(limitKB, "KB)"));
11218
+ var productCount = result && Array.isArray(result.products) ? result.products.length : null;
11219
+ var detail = productCount != null ? " (".concat(productCount, " products in payload \u2014 trim search.api rows or raise cap)") : '';
11220
+ console.error("\uD83D\uDD27 ClientTools: Result for '".concat(toolName, "' exceeds size limit (").concat(sizeKB, "KB > ").concat(limitKB, "KB)").concat(detail), (result === null || result === void 0 ? void 0 : result.reason) || (result === null || result === void 0 ? void 0 : result.error) || '');
11222
11221
  this.sendError(toolCallId, toolName, "Result too large: ".concat(sizeKB, "KB exceeds ").concat(limitKB, "KB limit"), 'RESULT_TOO_LARGE', executionTimeMs);
11223
11222
  return;
11224
11223
  }
@@ -11278,9 +11277,7 @@ var ClientToolsRegistry = /*#__PURE__*/function () {
11278
11277
  }
11279
11278
  }]);
11280
11279
  }();
11281
- _defineProperty(ClientToolsRegistry, "MAX_RESULT_SIZE", 50000);
11282
- // 50KB for text-only results
11283
- _defineProperty(ClientToolsRegistry, "MAX_IMAGE_RESULT_SIZE", 512000);
11280
+ _defineProperty(ClientToolsRegistry, "MAX_RESULT_SIZE", 512000);
11284
11281
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ClientToolsRegistry);
11285
11282
 
11286
11283
  /***/ }),
@@ -11947,7 +11944,7 @@ var TextChatSDK = /*#__PURE__*/function (_EventEmitter) {
11947
11944
 
11948
11945
  // SDK build time for debugging
11949
11946
  if (true) {
11950
- helloMessage.lastBuildTime = "2026-06-14T07:18:03.004Z";
11947
+ helloMessage.lastBuildTime = "2026-06-28T10:02:02.645Z";
11951
11948
  }
11952
11949
  try {
11953
11950
  this.ws.send(JSON.stringify(helloMessage));
@@ -13564,6 +13561,7 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
13564
13561
  this.onTogglePause = opts.onTogglePause || function () {};
13565
13562
  this.onToggleSpeaker = opts.onToggleSpeaker || function () {};
13566
13563
  this.onSendText = opts.onSendText || function () {};
13564
+ this.onAbout = typeof opts.onAbout === 'function' ? opts.onAbout : null;
13567
13565
  this._kbdOpen = false;
13568
13566
  this._el = null;
13569
13567
  this._build();
@@ -13651,11 +13649,8 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
13651
13649
  }, {
13652
13650
  key: "_footerHtml",
13653
13651
  value: function _footerHtml() {
13654
- if (!this.footer) return '';
13655
- var _this$footer = this.footer,
13656
- brandUrl = _this$footer.brandUrl,
13657
- brandName = _this$footer.brandName;
13658
- return "\n <div id=\"ttp-ecom-footer\" class=\"ttp-ecom-footer\">\n <span>Powered by <a href=\"".concat(brandUrl, "\" target=\"_blank\" rel=\"noopener noreferrer\"><b>").concat(brandName, "</b></a></span>\n </div>");
13652
+ var brand = this.footer ? "<span>Powered by <a href=\"".concat(this.footer.brandUrl, "\" target=\"_blank\" rel=\"noopener noreferrer\"><b>").concat(this.footer.brandName, "</b></a></span>") : '';
13653
+ return "\n <div id=\"ttp-ecom-footer\" class=\"ttp-ecom-footer\">\n ".concat(brand, "\n <button type=\"button\" class=\"ttp-ecom-info-btn\" id=\"ttp-ecom-btn-info\" title=\"About\" aria-label=\"About\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"9\"/>\n <line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"16\"/>\n <circle cx=\"12\" cy=\"7.7\" r=\"1.05\" fill=\"currentColor\" stroke=\"none\"/>\n </svg>\n </button>\n </div>");
13659
13654
  }
13660
13655
  }, {
13661
13656
  key: "_wireEvents",
@@ -13684,6 +13679,12 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
13684
13679
  return $('ttp-ecom-input').focus();
13685
13680
  }, 50);
13686
13681
  });
13682
+ var infoBtn = $('ttp-ecom-btn-info');
13683
+ if (infoBtn) {
13684
+ infoBtn.addEventListener('click', function () {
13685
+ if (_this.onAbout) _this.onAbout();
13686
+ });
13687
+ }
13687
13688
  $('ttp-ecom-btn-end').addEventListener('click', function () {
13688
13689
  return _this.onHangup();
13689
13690
  });
@@ -13703,11 +13704,16 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
13703
13704
  }, {
13704
13705
  key: "show",
13705
13706
  value: function show() {
13707
+ var _this2 = this;
13706
13708
  var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
13707
13709
  if (!this._el) return;
13708
13710
  if (opts.reset !== false) this._reset();
13709
13711
  this._el.style.display = '';
13710
13712
  this.syncFromVoice();
13713
+ // Now that the strip has real dimensions, clamp any restored drag position.
13714
+ if (this._dragEnabled) requestAnimationFrame(function () {
13715
+ return _this2.reclampDrag();
13716
+ });
13711
13717
  }
13712
13718
  }, {
13713
13719
  key: "hide",
@@ -13839,6 +13845,177 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
13839
13845
  if (!this.getVoiceUiState) return;
13840
13846
  this.syncFromVoice();
13841
13847
  }
13848
+
13849
+ /**
13850
+ * Make the strip draggable by its body. The wrapper is centered with
13851
+ * `translateX(-50%)`; a drag offset is layered on top of that. Control buttons
13852
+ * and the text input don't start a drag. Position is clamped to the viewport
13853
+ * (re-clamped on show/resize) and optionally persisted under `storageKey`.
13854
+ *
13855
+ * @param {Object} opts
13856
+ * @param {boolean} [opts.persist=true]
13857
+ * @param {string} [opts.storageKey]
13858
+ */
13859
+ }, {
13860
+ key: "enableDrag",
13861
+ value: function enableDrag() {
13862
+ var _this3 = this;
13863
+ var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
13864
+ if (!this._el || this._dragEnabled) return;
13865
+ var wrapper = this._el; // fixed, centered via translateX(-50%)
13866
+ var handle = wrapper.querySelector('#ttp-ecom-strip');
13867
+ if (!handle) return;
13868
+ this._dragEnabled = true;
13869
+ this._dragPersist = opts.persist !== false;
13870
+ this._dragKey = opts.storageKey || '';
13871
+ this._dragOffset = {
13872
+ x: 0,
13873
+ y: 0
13874
+ };
13875
+ handle.style.setProperty('cursor', 'move');
13876
+ handle.style.setProperty('touch-action', 'none');
13877
+ var EXCLUDE = 'button, a, input, textarea, select, [contenteditable]';
13878
+ var THRESHOLD = 5;
13879
+ var startX = 0,
13880
+ startY = 0,
13881
+ baseX = 0,
13882
+ baseY = 0,
13883
+ baseRect = null;
13884
+ var dragging = false,
13885
+ moved = false;
13886
+ var onMove = function onMove(e) {
13887
+ var dx = e.clientX - startX,
13888
+ dy = e.clientY - startY;
13889
+ if (!moved && Math.hypot(dx, dy) < THRESHOLD) return;
13890
+ moved = true;
13891
+ _this3._dragOffset = _this3._clampDragOffset(baseX + dx, baseY + dy, baseRect);
13892
+ _this3._applyDragOffset();
13893
+ };
13894
+ var _onUp = function onUp(e) {
13895
+ window.removeEventListener('pointermove', onMove);
13896
+ window.removeEventListener('pointerup', _onUp);
13897
+ handle.style.setProperty('cursor', 'move');
13898
+ try {
13899
+ handle.releasePointerCapture(e.pointerId);
13900
+ } catch (err) {/* not captured */}
13901
+ dragging = false;
13902
+ if (moved && _this3._dragPersist && _this3._dragKey) {
13903
+ try {
13904
+ window.localStorage.setItem(_this3._dragKey, JSON.stringify(_this3._dragOffset));
13905
+ } catch (err) {/* unavailable */}
13906
+ }
13907
+ };
13908
+ var onDown = function onDown(e) {
13909
+ if (e.button != null && e.button !== 0) return; // primary / touch / pen only
13910
+ if (dragging) return;
13911
+ if (e.target && e.target.closest && e.target.closest(EXCLUDE)) return;
13912
+ dragging = true;
13913
+ moved = false;
13914
+ startX = e.clientX;
13915
+ startY = e.clientY;
13916
+ baseX = _this3._dragOffset.x;
13917
+ baseY = _this3._dragOffset.y;
13918
+ baseRect = _this3._dragBaseRect();
13919
+ handle.style.setProperty('cursor', 'grabbing');
13920
+ try {
13921
+ handle.setPointerCapture(e.pointerId);
13922
+ } catch (err) {/* unsupported */}
13923
+ window.addEventListener('pointermove', onMove);
13924
+ window.addEventListener('pointerup', _onUp);
13925
+ };
13926
+ handle.addEventListener('pointerdown', onDown);
13927
+
13928
+ // Restore saved offset (unclamped here — the strip is hidden until show(),
13929
+ // where it gets clamped against real dimensions).
13930
+ if (this._dragPersist && this._dragKey) {
13931
+ try {
13932
+ var saved = JSON.parse(window.localStorage.getItem(this._dragKey) || 'null');
13933
+ if (saved && typeof saved.x === 'number' && typeof saved.y === 'number') {
13934
+ this._dragOffset = {
13935
+ x: saved.x,
13936
+ y: saved.y
13937
+ };
13938
+ this._applyDragOffset();
13939
+ }
13940
+ } catch (err) {/* ignore corrupt storage */}
13941
+ }
13942
+ }
13943
+
13944
+ /**
13945
+ * Base (offset-0) viewport rect used for clamping. Measures the *visible* inner
13946
+ * strip (`#ttp-ecom-strip`), not the wrapper: the wrapper is fixed at `bottom:0`
13947
+ * with bottom padding (incl. safe-area inset), so its bottom edge hugs the
13948
+ * viewport bottom and would wrongly forbid any downward drag. The drag offset is
13949
+ * applied to the wrapper, but both elements move together by the same amount, so
13950
+ * the inner strip's offset-0 rect is just its current rect minus the offset.
13951
+ */
13952
+ }, {
13953
+ key: "_dragBaseRect",
13954
+ value: function _dragBaseRect() {
13955
+ var o = this._dragOffset || {
13956
+ x: 0,
13957
+ y: 0
13958
+ };
13959
+ var inner = this._el && this._el.querySelector('#ttp-ecom-strip') || this._el;
13960
+ var r = inner.getBoundingClientRect();
13961
+ return {
13962
+ left: r.left - o.x,
13963
+ top: r.top - o.y,
13964
+ right: r.right - o.x,
13965
+ bottom: r.bottom - o.y
13966
+ };
13967
+ }
13968
+
13969
+ /**
13970
+ * Clamp a drag offset so the strip stays within the viewport. An 8px margin is
13971
+ * kept on the top/left/right edges. The bottom is allowed to drag *past* the
13972
+ * viewport edge so the strip can be tucked partly off-screen — but at least
13973
+ * `MIN_VISIBLE` (10px) of its top stays on screen so it can always be grabbed
13974
+ * and dragged back up.
13975
+ */
13976
+ }, {
13977
+ key: "_clampDragOffset",
13978
+ value: function _clampDragOffset(x, y, base) {
13979
+ if (!base) return {
13980
+ x: x,
13981
+ y: y
13982
+ };
13983
+ var margin = 8;
13984
+ var MIN_VISIBLE = 10;
13985
+ var minX = margin - base.left,
13986
+ maxX = window.innerWidth - margin - base.right;
13987
+ var minY = margin - base.top,
13988
+ maxY = window.innerHeight - MIN_VISIBLE - base.top;
13989
+ if (minX > maxX) maxX = minX;
13990
+ if (minY > maxY) maxY = minY;
13991
+ return {
13992
+ x: Math.min(Math.max(x, minX), maxX),
13993
+ y: Math.min(Math.max(y, minY), maxY)
13994
+ };
13995
+ }
13996
+
13997
+ /** Apply the drag offset on top of the centering transform. */
13998
+ }, {
13999
+ key: "_applyDragOffset",
14000
+ value: function _applyDragOffset() {
14001
+ if (!this._el) return;
14002
+ var o = this._dragOffset || {
14003
+ x: 0,
14004
+ y: 0
14005
+ };
14006
+ this._el.style.setProperty('transform', "translateX(-50%) translate(".concat(o.x, "px, ").concat(o.y, "px)"), 'important');
14007
+ }
14008
+
14009
+ /** Re-clamp the dragged strip to the current viewport (on show / resize). */
14010
+ }, {
14011
+ key: "reclampDrag",
14012
+ value: function reclampDrag() {
14013
+ if (!this._dragEnabled || !this._el) return;
14014
+ var r = this._el.getBoundingClientRect();
14015
+ if (!r.width && !r.height) return; // hidden — nothing to clamp yet
14016
+ this._dragOffset = this._clampDragOffset(this._dragOffset.x, this._dragOffset.y, this._dragBaseRect());
14017
+ this._applyDragOffset();
14018
+ }
13842
14019
  }, {
13843
14020
  key: "destroy",
13844
14021
  value: function destroy() {
@@ -13850,12 +14027,12 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
13850
14027
  }, {
13851
14028
  key: "_reset",
13852
14029
  value: function _reset() {
13853
- var _this2 = this,
14030
+ var _this4 = this,
13854
14031
  _$,
13855
14032
  _$2;
13856
14033
  this._kbdOpen = false;
13857
14034
  var $ = function $(id) {
13858
- return _this2._el.querySelector('#' + id);
14035
+ return _this4._el.querySelector('#' + id);
13859
14036
  };
13860
14037
  var tx = $('ttp-ecom-transcript');
13861
14038
  if (tx) {
@@ -13898,7 +14075,7 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
13898
14075
  }
13899
14076
  }]);
13900
14077
  }();
13901
- EcommerceVoiceStrip._CSS = "\n#ttp-ecom-strip-wrapper {\n position: fixed;\n left: 50%;\n bottom: 0;\n transform: translateX(-50%);\n width: min(720px, calc(100vw - 40px));\n max-width: calc(100vw - 40px);\n z-index: 2147483647;\n box-sizing: border-box;\n padding: 0 14px max(14px, env(safe-area-inset-bottom, 0px));\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n font-feature-settings: \"kern\" 1, \"liga\" 1;\n pointer-events: none;\n}\n#ttp-ecom-strip-wrapper * { box-sizing: border-box; }\n\n/* Layered glass dock: rim light, soft lift, optional backdrop tint */\n#ttp-ecom-strip {\n pointer-events: auto;\n position: relative;\n isolation: isolate;\n margin: 0;\n border-radius: 26px;\n border: 1px solid rgba(255, 255, 255, 0.18);\n background: var(--ecom-strip-bg, linear-gradient(145deg, #5b21b6 0%, #3730a3 42%, #1e1b4b 100%));\n background-clip: padding-box;\n color: var(--ecom-fg, #ffffff);\n box-shadow:\n 0 0 0 1px rgba(0, 0, 0, 0.18) inset,\n 0 1px 0 rgba(255, 255, 255, 0.14) inset,\n 0 -20px 40px -8px rgba(0, 0, 0, 0.22) inset,\n 0 12px 32px rgba(0, 0, 0, 0.22),\n 0 28px 56px -16px rgba(0, 0, 0, 0.45),\n 0 0 80px -20px rgba(99, 102, 241, 0.35);\n overflow: visible;\n}\n\n#ttp-ecom-strip::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n z-index: 0;\n background: linear-gradient(\n 165deg,\n rgba(255, 255, 255, 0.08) 0%,\n rgba(255, 255, 255, 0) 42%,\n rgba(0, 0, 0, 0.12) 100%\n );\n}\n\n/* LIVE chip \u2014 glass capsule (backdrop blur), straddles top edge */\n#ttp-ecom-live-edge {\n position: absolute;\n left: 50%;\n top: 0;\n transform: translate(-50%, -50%);\n z-index: 4;\n max-width: calc(100% - 52px);\n pointer-events: none;\n padding: 3px 14px 4px;\n border-radius: 999px;\n background: rgba(8, 6, 24, 0.78);\n border: 1px solid rgba(255, 255, 255, 0.28);\n box-shadow:\n 0 0 0 1px rgba(0, 0, 0, 0.35),\n 0 4px 16px rgba(0, 0, 0, 0.35),\n inset 0 1px 0 rgba(255, 255, 255, 0.12);\n}\n@supports (backdrop-filter: blur(1px)) {\n #ttp-ecom-live-edge {\n backdrop-filter: blur(14px) saturate(180%);\n -webkit-backdrop-filter: blur(14px) saturate(180%);\n }\n}\n\n#ttp-ecom-main-row {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 18px 16px 12px;\n min-height: 48px;\n}\n\n#ttp-ecom-footer {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 16px 10px;\n margin-top: -4px;\n border-top: 1px solid rgba(255, 255, 255, 0.06);\n padding-top: 6px;\n}\n#ttp-ecom-footer span {\n font-size: 10px;\n color: rgba(255, 255, 255, 0.35);\n white-space: nowrap;\n}\n#ttp-ecom-footer a {\n color: rgba(167, 139, 250, 0.95);\n text-decoration: none;\n font-weight: 600;\n}\n#ttp-ecom-footer a:hover { opacity: 0.85; }\n#ttp-ecom-footer a b { font-weight: 700; }\n\n#ttp-ecom-left-controls,\n#ttp-ecom-right-cluster {\n display: flex;\n align-items: center;\n gap: 7px;\n flex-shrink: 0;\n}\n\n/* Inset \u201Cmeter bridge\u201D for transcript \u2014 keeps one-line layout, adds depth */\n#ttp-ecom-center {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n justify-content: center;\n text-align: start;\n padding: 7px 12px 7px 14px;\n border-radius: 16px;\n background: rgba(0, 0, 0, 0.16);\n border: 1px solid rgba(255, 255, 255, 0.08);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.07),\n inset 0 -1px 0 rgba(0, 0, 0, 0.12);\n}\n\n#ttp-ecom-live-row {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n min-width: 0;\n}\n\n#ttp-ecom-live-label {\n font-size: 9px;\n font-weight: 800;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--ecom-accent, #4ade80);\n opacity: 0.98;\n white-space: nowrap;\n}\n\n#ttp-ecom-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--ecom-accent, #4ade80);\n flex-shrink: 0;\n box-shadow: 0 0 14px rgba(74, 222, 128, 0.45);\n animation: ttp-ecom-blink 1.35s ease-in-out infinite;\n}\n#ttp-ecom-dot.paused {\n animation: none;\n opacity: 0.45;\n background: rgba(255,255,255,0.35);\n box-shadow: none;\n}\n@keyframes ttp-ecom-blink {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.25; transform: scale(0.92); }\n}\n\n#ttp-ecom-transcript {\n font-size: 12px;\n line-height: 1.42;\n letter-spacing: 0.015em;\n color: rgba(255, 255, 255, 0.94);\n width: 100%;\n max-width: 100%;\n overflow: hidden;\n word-break: break-word;\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n}\n\n#ttp-ecom-transcript.ttp-ecom-transcript--user {\n color: rgba(255, 244, 214, 0.98);\n font-weight: 600;\n letter-spacing: 0.02em;\n text-shadow: 0 0 28px rgba(251, 191, 36, 0.22);\n}\n\n/* Squircle glass controls */\n#ttp-ecom-strip .ttp-ecom-ctrl {\n width: 36px;\n height: 36px;\n border-radius: 12px;\n border: 1px solid rgba(255, 255, 255, 0.16);\n background: linear-gradient(165deg, rgba(255,255,255,0.14) 0%, rgba(255,255,255,0.05) 100%);\n color: rgba(255, 255, 255, 0.92);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n position: relative;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.18),\n 0 2px 8px rgba(0, 0, 0, 0.15);\n transition: background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, transform 0.14s ease;\n outline: none;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl:hover {\n background: linear-gradient(165deg, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0.08) 100%);\n border-color: rgba(255, 255, 255, 0.32);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.22),\n 0 4px 14px rgba(0, 0, 0, 0.2);\n}\n#ttp-ecom-strip .ttp-ecom-ctrl:active { transform: scale(0.94); }\n#ttp-ecom-strip .ttp-ecom-ctrl:focus-visible {\n outline: 2px solid rgba(165, 180, 252, 0.95);\n outline-offset: 2px;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-active {\n background: linear-gradient(165deg, rgba(129, 140, 248, 0.45) 0%, rgba(99, 102, 241, 0.28) 100%) !important;\n border-color: rgba(196, 181, 253, 0.65) !important;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 0 1px rgba(99, 102, 241, 0.35),\n 0 6px 18px rgba(79, 70, 229, 0.35) !important;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-warn {\n background: linear-gradient(165deg, rgba(252, 165, 165, 0.22) 0%, rgba(239, 68, 68, 0.2) 100%) !important;\n border-color: rgba(252, 165, 165, 0.55) !important;\n}\n\n#ttp-ecom-strip .ttp-ecom-ctrl-end {\n width: 40px;\n height: 40px;\n border-radius: 14px;\n background: linear-gradient(165deg, #fb7185 0%, var(--ecom-end, #ef4444) 52%, #991b1b 100%) !important;\n border: none !important;\n color: #fff !important;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.25),\n 0 0 0 2px rgba(0, 0, 0, 0.12),\n 0 6px 22px rgba(239, 68, 68, 0.48);\n transform: rotate(135deg);\n transition: filter 0.18s ease, transform 0.14s ease, box-shadow 0.2s ease;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-end:hover {\n filter: brightness(1.06);\n transform: rotate(135deg) scale(1.05);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.28),\n 0 0 0 2px rgba(0, 0, 0, 0.12),\n 0 10px 28px rgba(239, 68, 68, 0.52);\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-end:active {\n transform: rotate(135deg) scale(0.94);\n}\n\n/* Mini waveform */\n#ttp-ecom-strip .ttp-ecom-mini-wave {\n display: flex;\n align-items: center;\n gap: 3px;\n height: 24px;\n padding: 0 4px;\n opacity: 0.9;\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb {\n width: 3px;\n border-radius: 3px;\n background: linear-gradient(180deg, #ddd6fe 0%, var(--ecom-accent, #a78bfa) 100%);\n animation: ttp-ecom-wa 0.78s ease-in-out infinite;\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(1) { height: 6px; animation-delay: 0s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(2) { height: 11px; animation-delay: 0.1s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(3) { height: 16px; animation-delay: 0.2s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(4) { height: 9px; animation-delay: 0.15s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(5) { height: 12px; animation-delay: 0.05s; }\n@keyframes ttp-ecom-wa {\n 0%, 100% { transform: scaleY(0.38); opacity: 0.5; }\n 50% { transform: scaleY(1); opacity: 1; }\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb.paused {\n animation-play-state: paused;\n transform: scaleY(0.32);\n opacity: 0.28;\n}\n\n/* Input row */\n#ttp-ecom-input-row {\n display: none;\n position: relative;\n z-index: 1;\n align-items: center;\n gap: 10px;\n padding: 0 14px 12px;\n margin-top: -2px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n#ttp-ecom-input-row.open {\n display: flex;\n}\n#ttp-ecom-input {\n flex: 1;\n height: 40px;\n border-radius: 12px;\n border: 1px solid rgba(255, 255, 255, 0.18);\n background: rgba(0, 0, 0, 0.22);\n color: #fff;\n font-size: 14px;\n padding: 0 14px;\n outline: none;\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);\n transition: border-color 0.18s ease, box-shadow 0.18s ease;\n}\n#ttp-ecom-input::placeholder { color: rgba(255, 255, 255, 0.42); }\n#ttp-ecom-input:focus {\n border-color: rgba(165, 180, 252, 0.65);\n box-shadow:\n inset 0 1px 2px rgba(0, 0, 0, 0.2),\n 0 0 0 3px rgba(99, 102, 241, 0.25);\n}\n\n#ttp-ecom-strip .ttp-ecom-send {\n width: 36px;\n height: 36px;\n border-radius: 12px;\n border: none;\n background: linear-gradient(165deg, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0.1) 100%);\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2);\n transition: background 0.18s ease, transform 0.12s ease;\n}\n#ttp-ecom-strip .ttp-ecom-send:hover {\n background: linear-gradient(165deg, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0.14) 100%);\n}\n#ttp-ecom-strip .ttp-ecom-send:active { transform: scale(0.94); }\n\n@media (max-width: 520px) {\n #ttp-ecom-strip .ttp-ecom-mini-wave { display: none; }\n #ttp-ecom-main-row { gap: 7px; padding: 16px 12px 10px; }\n #ttp-ecom-strip .ttp-ecom-ctrl { width: 36px; height: 36px; }\n #ttp-ecom-strip .ttp-ecom-ctrl-end { width: 40px; height: 40px; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n #ttp-ecom-dot { animation: none; opacity: 0.9; }\n #ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb { animation: none; opacity: 0.65; }\n}\n";
14078
+ EcommerceVoiceStrip._CSS = "\n#ttp-ecom-strip-wrapper {\n position: fixed;\n left: 50%;\n bottom: 0;\n transform: translateX(-50%);\n width: min(720px, calc(100vw - 40px));\n max-width: calc(100vw - 40px);\n z-index: 2147483647;\n box-sizing: border-box;\n padding: 0 14px max(14px, env(safe-area-inset-bottom, 0px));\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n font-feature-settings: \"kern\" 1, \"liga\" 1;\n pointer-events: none;\n}\n#ttp-ecom-strip-wrapper * { box-sizing: border-box; }\n\n/* Layered glass dock: rim light, soft lift, optional backdrop tint */\n#ttp-ecom-strip {\n pointer-events: auto;\n position: relative;\n isolation: isolate;\n margin: 0;\n border-radius: 26px;\n border: 1px solid rgba(255, 255, 255, 0.18);\n background: var(--ecom-strip-bg, linear-gradient(145deg, #5b21b6 0%, #3730a3 42%, #1e1b4b 100%));\n background-clip: padding-box;\n color: var(--ecom-fg, #ffffff);\n box-shadow:\n 0 0 0 1px rgba(0, 0, 0, 0.18) inset,\n 0 1px 0 rgba(255, 255, 255, 0.14) inset,\n 0 -20px 40px -8px rgba(0, 0, 0, 0.22) inset,\n 0 12px 32px rgba(0, 0, 0, 0.22),\n 0 28px 56px -16px rgba(0, 0, 0, 0.45),\n 0 0 80px -20px rgba(99, 102, 241, 0.35);\n overflow: visible;\n}\n\n#ttp-ecom-strip::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n z-index: 0;\n background: linear-gradient(\n 165deg,\n rgba(255, 255, 255, 0.08) 0%,\n rgba(255, 255, 255, 0) 42%,\n rgba(0, 0, 0, 0.12) 100%\n );\n}\n\n/* LIVE chip \u2014 glass capsule (backdrop blur), straddles top edge */\n#ttp-ecom-live-edge {\n position: absolute;\n left: 50%;\n top: 0;\n transform: translate(-50%, -50%);\n z-index: 4;\n max-width: calc(100% - 52px);\n pointer-events: none;\n padding: 3px 14px 4px;\n border-radius: 999px;\n background: rgba(8, 6, 24, 0.78);\n border: 1px solid rgba(255, 255, 255, 0.28);\n box-shadow:\n 0 0 0 1px rgba(0, 0, 0, 0.35),\n 0 4px 16px rgba(0, 0, 0, 0.35),\n inset 0 1px 0 rgba(255, 255, 255, 0.12);\n}\n@supports (backdrop-filter: blur(1px)) {\n #ttp-ecom-live-edge {\n backdrop-filter: blur(14px) saturate(180%);\n -webkit-backdrop-filter: blur(14px) saturate(180%);\n }\n}\n\n#ttp-ecom-main-row {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 18px 16px 12px;\n min-height: 48px;\n}\n\n#ttp-ecom-footer {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 0 16px 10px;\n margin-top: -4px;\n border-top: 1px solid rgba(255, 255, 255, 0.06);\n padding-top: 6px;\n}\n.ttp-ecom-info-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 2px;\n margin: 0;\n background: none;\n border: none;\n cursor: pointer;\n line-height: 0;\n border-radius: 50%;\n color: rgba(255, 255, 255, 0.35);\n transition: color 0.2s, background 0.2s;\n}\n.ttp-ecom-info-btn:hover {\n color: rgba(255, 255, 255, 0.7);\n background: rgba(255, 255, 255, 0.08);\n}\n.ttp-ecom-info-btn svg { display: block; }\n#ttp-ecom-footer span {\n font-size: 10px;\n color: rgba(255, 255, 255, 0.35);\n white-space: nowrap;\n}\n#ttp-ecom-footer a {\n color: rgba(167, 139, 250, 0.95);\n text-decoration: none;\n font-weight: 600;\n}\n#ttp-ecom-footer a:hover { opacity: 0.85; }\n#ttp-ecom-footer a b { font-weight: 700; }\n\n#ttp-ecom-left-controls,\n#ttp-ecom-right-cluster {\n display: flex;\n align-items: center;\n gap: 7px;\n flex-shrink: 0;\n}\n\n/* Inset \u201Cmeter bridge\u201D for transcript \u2014 keeps one-line layout, adds depth */\n#ttp-ecom-center {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n justify-content: center;\n text-align: start;\n padding: 7px 12px 7px 14px;\n border-radius: 16px;\n background: rgba(0, 0, 0, 0.16);\n border: 1px solid rgba(255, 255, 255, 0.08);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.07),\n inset 0 -1px 0 rgba(0, 0, 0, 0.12);\n}\n\n#ttp-ecom-live-row {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n min-width: 0;\n}\n\n#ttp-ecom-live-label {\n font-size: 9px;\n font-weight: 800;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--ecom-accent, #4ade80);\n opacity: 0.98;\n white-space: nowrap;\n}\n\n#ttp-ecom-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--ecom-accent, #4ade80);\n flex-shrink: 0;\n box-shadow: 0 0 14px rgba(74, 222, 128, 0.45);\n animation: ttp-ecom-blink 1.35s ease-in-out infinite;\n}\n#ttp-ecom-dot.paused {\n animation: none;\n opacity: 0.45;\n background: rgba(255,255,255,0.35);\n box-shadow: none;\n}\n@keyframes ttp-ecom-blink {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.25; transform: scale(0.92); }\n}\n\n#ttp-ecom-transcript {\n font-size: 12px;\n line-height: 1.42;\n letter-spacing: 0.015em;\n color: rgba(255, 255, 255, 0.94);\n width: 100%;\n max-width: 100%;\n overflow: hidden;\n word-break: break-word;\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n}\n\n#ttp-ecom-transcript.ttp-ecom-transcript--user {\n color: rgba(255, 244, 214, 0.98);\n font-weight: 600;\n letter-spacing: 0.02em;\n text-shadow: 0 0 28px rgba(251, 191, 36, 0.22);\n}\n\n/* Squircle glass controls */\n#ttp-ecom-strip .ttp-ecom-ctrl {\n width: 36px;\n height: 36px;\n border-radius: 12px;\n border: 1px solid rgba(255, 255, 255, 0.16);\n background: linear-gradient(165deg, rgba(255,255,255,0.14) 0%, rgba(255,255,255,0.05) 100%);\n color: rgba(255, 255, 255, 0.92);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n position: relative;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.18),\n 0 2px 8px rgba(0, 0, 0, 0.15);\n transition: background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, transform 0.14s ease;\n outline: none;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl:hover {\n background: linear-gradient(165deg, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0.08) 100%);\n border-color: rgba(255, 255, 255, 0.32);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.22),\n 0 4px 14px rgba(0, 0, 0, 0.2);\n}\n#ttp-ecom-strip .ttp-ecom-ctrl:active { transform: scale(0.94); }\n#ttp-ecom-strip .ttp-ecom-ctrl:focus-visible {\n outline: 2px solid rgba(165, 180, 252, 0.95);\n outline-offset: 2px;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-active {\n background: linear-gradient(165deg, rgba(129, 140, 248, 0.45) 0%, rgba(99, 102, 241, 0.28) 100%) !important;\n border-color: rgba(196, 181, 253, 0.65) !important;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 0 1px rgba(99, 102, 241, 0.35),\n 0 6px 18px rgba(79, 70, 229, 0.35) !important;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-warn {\n background: linear-gradient(165deg, rgba(252, 165, 165, 0.22) 0%, rgba(239, 68, 68, 0.2) 100%) !important;\n border-color: rgba(252, 165, 165, 0.55) !important;\n}\n\n#ttp-ecom-strip .ttp-ecom-ctrl-end {\n width: 40px;\n height: 40px;\n border-radius: 14px;\n background: linear-gradient(165deg, #fb7185 0%, var(--ecom-end, #ef4444) 52%, #991b1b 100%) !important;\n border: none !important;\n color: #fff !important;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.25),\n 0 0 0 2px rgba(0, 0, 0, 0.12),\n 0 6px 22px rgba(239, 68, 68, 0.48);\n transform: rotate(135deg);\n transition: filter 0.18s ease, transform 0.14s ease, box-shadow 0.2s ease;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-end:hover {\n filter: brightness(1.06);\n transform: rotate(135deg) scale(1.05);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.28),\n 0 0 0 2px rgba(0, 0, 0, 0.12),\n 0 10px 28px rgba(239, 68, 68, 0.52);\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-end:active {\n transform: rotate(135deg) scale(0.94);\n}\n\n/* Mini waveform */\n#ttp-ecom-strip .ttp-ecom-mini-wave {\n display: flex;\n align-items: center;\n gap: 3px;\n height: 24px;\n padding: 0 4px;\n opacity: 0.9;\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb {\n width: 3px;\n border-radius: 3px;\n background: linear-gradient(180deg, #ddd6fe 0%, var(--ecom-accent, #a78bfa) 100%);\n animation: ttp-ecom-wa 0.78s ease-in-out infinite;\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(1) { height: 6px; animation-delay: 0s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(2) { height: 11px; animation-delay: 0.1s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(3) { height: 16px; animation-delay: 0.2s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(4) { height: 9px; animation-delay: 0.15s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(5) { height: 12px; animation-delay: 0.05s; }\n@keyframes ttp-ecom-wa {\n 0%, 100% { transform: scaleY(0.38); opacity: 0.5; }\n 50% { transform: scaleY(1); opacity: 1; }\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb.paused {\n animation-play-state: paused;\n transform: scaleY(0.32);\n opacity: 0.28;\n}\n\n/* Input row */\n#ttp-ecom-input-row {\n display: none;\n position: relative;\n z-index: 1;\n align-items: center;\n gap: 10px;\n padding: 0 14px 12px;\n margin-top: -2px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n#ttp-ecom-input-row.open {\n display: flex;\n}\n#ttp-ecom-input {\n flex: 1;\n height: 40px;\n border-radius: 12px;\n border: 1px solid rgba(255, 255, 255, 0.18);\n background: rgba(0, 0, 0, 0.22);\n color: #fff;\n font-size: 14px;\n padding: 0 14px;\n outline: none;\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);\n transition: border-color 0.18s ease, box-shadow 0.18s ease;\n}\n#ttp-ecom-input::placeholder { color: rgba(255, 255, 255, 0.42); }\n#ttp-ecom-input:focus {\n border-color: rgba(165, 180, 252, 0.65);\n box-shadow:\n inset 0 1px 2px rgba(0, 0, 0, 0.2),\n 0 0 0 3px rgba(99, 102, 241, 0.25);\n}\n\n#ttp-ecom-strip .ttp-ecom-send {\n width: 36px;\n height: 36px;\n border-radius: 12px;\n border: none;\n background: linear-gradient(165deg, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0.1) 100%);\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2);\n transition: background 0.18s ease, transform 0.12s ease;\n}\n#ttp-ecom-strip .ttp-ecom-send:hover {\n background: linear-gradient(165deg, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0.14) 100%);\n}\n#ttp-ecom-strip .ttp-ecom-send:active { transform: scale(0.94); }\n\n@media (max-width: 520px) {\n #ttp-ecom-strip .ttp-ecom-mini-wave { display: none; }\n #ttp-ecom-main-row { gap: 7px; padding: 16px 12px 10px; }\n #ttp-ecom-strip .ttp-ecom-ctrl { width: 36px; height: 36px; }\n #ttp-ecom-strip .ttp-ecom-ctrl-end { width: 40px; height: 40px; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n #ttp-ecom-dot { animation: none; opacity: 0.9; }\n #ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb { animation: none; opacity: 0.65; }\n}\n";
13902
14079
 
13903
14080
  /***/ }),
13904
14081
 
@@ -15519,7 +15696,7 @@ var PartnerScriptRunner = /*#__PURE__*/function () {
15519
15696
  value: (function () {
15520
15697
  var _runAdapterBody2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(action, args, entry) {
15521
15698
  var _entry$version4;
15522
- var eventName, safeArgs, productIds, _productIds$, idStr, _idStr, ctx, result, postCtx, _t3, _t4, _t5;
15699
+ var eventName, safeArgs, productIds, _productIds$, idStr, _idStr, ctx, result, _result$totalCount, bytes, kb, extra, postCtx, _t3, _t4, _t5;
15523
15700
  return _regenerator().w(function (_context3) {
15524
15701
  while (1) switch (_context3.p = _context3.n) {
15525
15702
  case 0:
@@ -15583,6 +15760,19 @@ var PartnerScriptRunner = /*#__PURE__*/function () {
15583
15760
  error: String((_t4 === null || _t4 === void 0 ? void 0 : _t4.message) || _t4)
15584
15761
  });
15585
15762
  case 7:
15763
+ // Payload size diagnostics — log before ClientToolsRegistry rejects oversize results.
15764
+ try {
15765
+ bytes = JSON.stringify(result).length;
15766
+ kb = Math.round(bytes / 1024);
15767
+ extra = action === 'search.api' && result && _typeof(result) === 'object' ? " products=".concat(Array.isArray(result.products) ? result.products.length : '?', " totalCount=").concat((_result$totalCount = result.totalCount) !== null && _result$totalCount !== void 0 ? _result$totalCount : '?') : '';
15768
+ console.log("".concat(LOG, " ").concat(action, " done ok=").concat(adapterResultOk(result), " payload=").concat(kb, "KB").concat(extra));
15769
+ if (bytes > 480000) {
15770
+ console.warn("".concat(LOG, " ").concat(action, " payload near/over 512KB wire limit (").concat(kb, "KB) \u2014 backend may see totalCount=0"));
15771
+ }
15772
+ } catch (_unused) {/* ignore circular refs */}
15773
+
15774
+ // Inline post-hook runs only when main succeeded (mirror of after-hook
15775
+ // gating). Best-effort: errors are logged, the main result is still returned.
15586
15776
  if (!(entry.postFn && adapterResultOk(result))) {
15587
15777
  _context3.n = 11;
15588
15778
  break;
@@ -20113,8 +20303,8 @@ var VoiceSDK = _v2_VoiceSDK_js__WEBPACK_IMPORTED_MODULE_0__["default"];
20113
20303
 
20114
20304
 
20115
20305
  // Version - injected at build time from package.json via webpack DefinePlugin
20116
- var VERSION = "2.45.7";
20117
- var BUILD_TIME = "2026-06-14T07:18:03.004Z";
20306
+ var VERSION = "2.45.12";
20307
+ var BUILD_TIME = "2026-06-28T10:02:02.645Z";
20118
20308
  console.log("%c TTP Agent SDK v".concat(VERSION, " (").concat(BUILD_TIME, ") "), 'background: #4f46e5; color: white; font-size: 12px; font-weight: bold; padding: 2px 6px; border-radius: 4px;');
20119
20309
 
20120
20310
  // Named exports
@@ -24406,9 +24596,17 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
24406
24596
  // Transcript sync
24407
24597
  _this.pendingSentenceText = null; // Text waiting for first audio chunk
24408
24598
  _this.pendingSynced = null; // Synced actions waiting for first audio chunk
24409
- _this.sentenceTimings = []; // [{startTime, text, synced, displayed}, ...]
24599
+ _this.sentenceTimings = []; // [{segmentId, startTime, endTime, text, synced, displayed, doneReported}, ...]
24410
24600
  _this.isCheckingTranscripts = false;
24411
24601
 
24602
+ // Audio segment correlation (backend-assigned id carried on audio_start). pendingSegmentId
24603
+ // waits for the segment's first chunk, then is promoted to currentSegmentId at scheduling.
24604
+ // currentSegmentId is stamped onto playbackStarted/playbackStopped so the backend can match
24605
+ // the "stopped" against the last burst it sent. Per-segment completion is reported via the
24606
+ // 'segmentDone' event (finished / barged_in / interrupted + playedMs).
24607
+ _this.pendingSegmentId = null;
24608
+ _this.currentSegmentId = null;
24609
+
24412
24610
  // Flag to prevent queuing new audio after stopImmediate() is called (barge-in protection)
24413
24611
  // This prevents race conditions where audio chunks arrive after stop but before sources are stopped
24414
24612
  // Cleared when markNewSentence() is called (signals new audio is starting)
@@ -24790,7 +24988,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
24790
24988
  // Keep scheduling frames as long as we have them and haven't reached the lookahead limit
24791
24989
  scheduledCount = 0;
24792
24990
  _loop = /*#__PURE__*/_regenerator().m(function _loop() {
24793
- var preparedFrame, source, currentTime, isMobile, startupBuffer, minStartTime, startTime;
24991
+ var preparedFrame, source, currentTime, isMobile, startupBuffer, minStartTime, segFrameEnd, startTime;
24794
24992
  return _regenerator().w(function (_context3) {
24795
24993
  while (1) switch (_context3.n) {
24796
24994
  case 0:
@@ -24850,22 +25048,32 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
24850
25048
  // Always use nextStartTime (which is already calculated for seamless playback)
24851
25049
  }
24852
25050
 
24853
- // ✅ MOVED OUTSIDE - Record sentence timing on first chunk of EACH sentence
24854
- if (_this4.pendingSentenceText) {
25051
+ // Audio-clock window for THIS frame: [nextStartTime, nextStartTime + duration).
25052
+ segFrameEnd = _this4.nextStartTime + preparedFrame.duration; // ✅ MOVED OUTSIDE - Record sentence timing on first chunk of EACH sentence
25053
+ if (_this4.pendingSentenceText || _this4.pendingSegmentId != null) {
25054
+ // First chunk of a new segment: open a timing entry and adopt its id as current.
24855
25055
  _this4.sentenceTimings.push({
25056
+ segmentId: _this4.pendingSegmentId,
24856
25057
  startTime: _this4.nextStartTime,
25058
+ endTime: segFrameEnd,
24857
25059
  text: _this4.pendingSentenceText,
24858
25060
  synced: _this4.pendingSynced,
24859
- displayed: false
25061
+ displayed: false,
25062
+ doneReported: false
24860
25063
  });
24861
- console.log("\uD83D\uDCDD AudioPlayer: Sentence scheduled at ".concat(_this4.nextStartTime.toFixed(3), "s: \"").concat(_this4.pendingSentenceText.substring(0, 40), "...\" (synced: ").concat(_this4.pendingSynced ? _this4.pendingSynced.length : 0, ")"));
25064
+ _this4.currentSegmentId = _this4.pendingSegmentId;
25065
+ console.log("\uD83D\uDCDD AudioPlayer: Sentence scheduled at ".concat(_this4.nextStartTime.toFixed(3), "s (segmentId: ").concat(_this4.pendingSegmentId, "): \"").concat((_this4.pendingSentenceText || '').substring(0, 40), "...\" (synced: ").concat(_this4.pendingSynced ? _this4.pendingSynced.length : 0, ")"));
24862
25066
  _this4.pendingSentenceText = null;
24863
25067
  _this4.pendingSynced = null;
25068
+ _this4.pendingSegmentId = null;
24864
25069
 
24865
25070
  // Start checker if not running
24866
25071
  if (!_this4.isCheckingTranscripts) {
24867
25072
  _this4.startTranscriptChecker();
24868
25073
  }
25074
+ } else if (_this4.sentenceTimings.length > 0) {
25075
+ // Subsequent chunk of the current segment: extend its end on the audio clock.
25076
+ _this4.sentenceTimings[_this4.sentenceTimings.length - 1].endTime = segFrameEnd;
24869
25077
  }
24870
25078
 
24871
25079
  // Schedule this chunk to start at nextStartTime
@@ -24920,8 +25128,10 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
24920
25128
  if (_this4.scheduledBuffers === 0 && _this4.preparedBuffer.length === 0 && _this4.pcmChunkQueue.length === 0 && !_this4._isStopped) {
24921
25129
  _this4.isPlaying = false;
24922
25130
  _this4.isSchedulingFrames = false;
24923
- console.log('🛑 AudioPlayer: Emitting playbackStopped event (all buffers finished)');
24924
- _this4.emit('playbackStopped');
25131
+ console.log('🛑 AudioPlayer: Emitting playbackStopped event (all buffers finished, segmentId: ' + _this4.currentSegmentId + ')');
25132
+ _this4.emit('playbackStopped', {
25133
+ segmentId: _this4.currentSegmentId
25134
+ });
24925
25135
  } else if (_this4.preparedBuffer.length > 0 && !_this4._isStopped) {
24926
25136
  // More frames available, schedule them immediately
24927
25137
 
@@ -24957,8 +25167,10 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
24957
25167
  };
24958
25168
  if (!_this4.isPlaying) {
24959
25169
  _this4.isPlaying = true;
24960
- console.log('🎵 AudioPlayer: Emitting playbackStarted event');
24961
- _this4.emit('playbackStarted');
25170
+ console.log('🎵 AudioPlayer: Emitting playbackStarted event (segmentId: ' + _this4.currentSegmentId + ')');
25171
+ _this4.emit('playbackStarted', {
25172
+ segmentId: _this4.currentSegmentId
25173
+ });
24962
25174
  }
24963
25175
  case 3:
24964
25176
  return _context3.a(2);
@@ -26302,14 +26514,66 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26302
26514
  // Note: scheduledBuffers was already reset to 0 above when clearing scheduledSources
26303
26515
  this.nextStartTime = 0;
26304
26516
 
26517
+ // Report per-segment completion for the interrupted burst BEFORE clearing timing state.
26518
+ // Audible segment → barged_in (ms heard); scheduled-but-unstarted → interrupted;
26519
+ // already-elapsed but unreported → finished. Plus any pending segment (audio_start arrived
26520
+ // but no chunks scheduled yet) → interrupted.
26521
+ try {
26522
+ var nowTs = this.audioContext ? this.audioContext.currentTime : 0;
26523
+ var _iterator = _createForOfIteratorHelper(this.sentenceTimings),
26524
+ _step;
26525
+ try {
26526
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
26527
+ var timing = _step.value;
26528
+ if (timing.doneReported) continue;
26529
+ timing.doneReported = true;
26530
+ var status = void 0,
26531
+ playedMs = void 0;
26532
+ if (timing.endTime != null && nowTs >= timing.endTime) {
26533
+ status = 'finished';
26534
+ playedMs = Math.round((timing.endTime - timing.startTime) * 1000);
26535
+ } else if (nowTs <= timing.startTime) {
26536
+ status = 'interrupted';
26537
+ playedMs = 0;
26538
+ } else {
26539
+ status = 'barged_in';
26540
+ playedMs = Math.round((nowTs - timing.startTime) * 1000);
26541
+ }
26542
+ this.emit('segmentDone', {
26543
+ segmentId: timing.segmentId,
26544
+ status: status,
26545
+ playedMs: playedMs
26546
+ });
26547
+ }
26548
+ } catch (err) {
26549
+ _iterator.e(err);
26550
+ } finally {
26551
+ _iterator.f();
26552
+ }
26553
+ if (this.pendingSegmentId != null) {
26554
+ this.emit('segmentDone', {
26555
+ segmentId: this.pendingSegmentId,
26556
+ status: 'interrupted',
26557
+ playedMs: 0
26558
+ });
26559
+ }
26560
+ } catch (e) {
26561
+ console.warn('⚠️ AudioPlayer: segmentDone (barge-in) reporting failed:', e && e.message);
26562
+ }
26563
+ // Capture the last segment that was playing for the coarse playbackStopped below
26564
+ // (clearTranscriptState resets currentSegmentId).
26565
+ var stoppedSegmentId = this.currentSegmentId;
26566
+
26305
26567
  // Clear transcript state
26306
26568
  this.clearTranscriptState();
26307
26569
 
26308
26570
  // Emit stopped event - CRITICAL for barge-in
26309
26571
 
26310
26572
  if (wasPlaying) {
26311
- console.log('🛑 AudioPlayer: Emitting playbackStopped event (stopImmediate called)');
26312
- this.emit('playbackStopped');
26573
+ console.log('🛑 AudioPlayer: Emitting playbackStopped event (stopImmediate called, segmentId: ' + stoppedSegmentId + ')');
26574
+ this.emit('playbackStopped', {
26575
+ segmentId: stoppedSegmentId
26576
+ });
26313
26577
  }
26314
26578
  }
26315
26579
 
@@ -26319,7 +26583,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26319
26583
  */
26320
26584
  }, {
26321
26585
  key: "markNewSentence",
26322
- value: function markNewSentence(text, synced) {
26586
+ value: function markNewSentence(text, synced, segmentId) {
26323
26587
  var _this0 = this;
26324
26588
  var wasStopped = this._isStopped;
26325
26589
  var isCurrentlyPlaying = this.isPlaying || this.scheduledSources.size > 0;
@@ -26364,10 +26628,12 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26364
26628
  console.log("\uD83D\uDCDD AudioPlayer: New sentence queued while audio playing - will start after current sentence finishes");
26365
26629
  }
26366
26630
 
26367
- // Always update pending sentence text and synced actions (for transcript display)
26631
+ // Always update pending sentence text, synced actions (for transcript display), and the
26632
+ // backend-assigned segment id (echoed back on the playback events for this segment).
26368
26633
  this.pendingSentenceText = text;
26369
26634
  this.pendingSynced = synced || null;
26370
- console.log("\uD83D\uDCDD AudioPlayer: New sentence marked: \"".concat(text.substring(0, 40), "...\" (wasStopped: ").concat(wasStopped, ", isPlaying: ").concat(isCurrentlyPlaying, ", synced: ").concat(synced ? synced.length : 0, ")"));
26635
+ this.pendingSegmentId = segmentId != null ? segmentId : null;
26636
+ console.log("\uD83D\uDCDD AudioPlayer: New sentence marked (segmentId: ".concat(this.pendingSegmentId, "): \"").concat(text.substring(0, 40), "...\" (wasStopped: ").concat(wasStopped, ", isPlaying: ").concat(isCurrentlyPlaying, ", synced: ").concat(synced ? synced.length : 0, ")"));
26371
26637
 
26372
26638
  // CRITICAL: Set timeout to detect empty sentences (audio_start but no chunks)
26373
26639
  // This prevents queue blocking if backend sends audio_start but no audio chunks follow
@@ -26379,6 +26645,18 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26379
26645
  // Check if this sentence still has no chunks after timeout
26380
26646
  if (_this0.pendingSentenceText === sentenceText && _this0.scheduledBuffers === 0 && _this0.preparedBuffer.length === 0 && _this0.pcmChunkQueue.length === 0 && !_this0._isStopped) {
26381
26647
  console.warn("\u26A0\uFE0F AudioPlayer: Empty sentence detected after 5s timeout - no chunks received for: \"".concat(sentenceText.substring(0, 40), "...\""));
26648
+ // If this empty sentence carried a segment id, report it done (nothing was heard) and
26649
+ // adopt it as current so the coarse stop below matches the backend's last-sent id.
26650
+ if (_this0.pendingSegmentId != null) {
26651
+ var emptySegId = _this0.pendingSegmentId;
26652
+ _this0.currentSegmentId = emptySegId;
26653
+ _this0.pendingSegmentId = null;
26654
+ _this0.emit('segmentDone', {
26655
+ segmentId: emptySegId,
26656
+ status: 'finished',
26657
+ playedMs: 0
26658
+ });
26659
+ }
26382
26660
  // Clear pending sentence to unblock next sentence
26383
26661
  if (_this0.pendingSentenceText === sentenceText) {
26384
26662
  _this0.pendingSentenceText = null;
@@ -26387,7 +26665,9 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26387
26665
  // Only if we're not currently playing (to avoid interrupting real playback)
26388
26666
  if (!_this0.isPlaying && _this0.scheduledSources.size === 0) {
26389
26667
  console.log('🛑 AudioPlayer: Emitting playbackStopped for empty sentence timeout');
26390
- _this0.emit('playbackStopped');
26668
+ _this0.emit('playbackStopped', {
26669
+ segmentId: _this0.currentSegmentId
26670
+ });
26391
26671
  }
26392
26672
  }
26393
26673
  _this0._emptySentenceTimeout = null;
@@ -26407,31 +26687,64 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26407
26687
  var _checkLoop = function checkLoop() {
26408
26688
  if (!_this1.isCheckingTranscripts || !_this1.audioContext) return;
26409
26689
  var currentTime = _this1.audioContext.currentTime;
26410
- var _iterator = _createForOfIteratorHelper(_this1.sentenceTimings),
26411
- _step;
26690
+ var _iterator2 = _createForOfIteratorHelper(_this1.sentenceTimings),
26691
+ _step2;
26412
26692
  try {
26413
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
26414
- var timing = _step.value;
26415
- if (!timing.displayed && currentTime >= timing.startTime) {
26416
- timing.displayed = true;
26693
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
26694
+ var _timing = _step2.value;
26695
+ if (!_timing.displayed && _timing.text && currentTime >= _timing.startTime) {
26696
+ _timing.displayed = true;
26417
26697
  var eventData = {
26418
- text: timing.text
26698
+ text: _timing.text
26419
26699
  };
26420
- if (timing.synced) {
26421
- eventData.synced = timing.synced;
26700
+ if (_timing.synced) {
26701
+ eventData.synced = _timing.synced;
26422
26702
  }
26423
- console.log("\uD83D\uDCDD AudioPlayer: Display transcript at ".concat(currentTime.toFixed(3), "s: \"").concat(timing.text.substring(0, 40), "...\" (synced: ").concat(timing.synced ? timing.synced.length : 0, ")"));
26703
+ console.log("\uD83D\uDCDD AudioPlayer: Display transcript at ".concat(currentTime.toFixed(3), "s: \"").concat(_timing.text.substring(0, 40), "...\" (synced: ").concat(_timing.synced ? _timing.synced.length : 0, ")"));
26424
26704
  _this1.emit('transcriptDisplay', eventData);
26425
26705
  }
26706
+ // Per-segment natural finish: this segment's audio window has fully elapsed.
26707
+ if (!_timing.doneReported && _timing.endTime != null && currentTime >= _timing.endTime) {
26708
+ _timing.doneReported = true;
26709
+ var _playedMs = Math.round((_timing.endTime - _timing.startTime) * 1000);
26710
+ _this1.emit('segmentDone', {
26711
+ segmentId: _timing.segmentId,
26712
+ status: 'finished',
26713
+ playedMs: _playedMs
26714
+ });
26715
+ }
26426
26716
  }
26427
26717
  } catch (err) {
26428
- _iterator.e(err);
26718
+ _iterator2.e(err);
26429
26719
  } finally {
26430
- _iterator.f();
26720
+ _iterator2.f();
26431
26721
  }
26432
26722
  if (_this1.isPlaying || _this1.scheduledBuffers > 0) {
26433
26723
  requestAnimationFrame(_checkLoop);
26434
26724
  } else {
26725
+ // Playback drained naturally — flush any segment whose finish tick we may have missed
26726
+ // (the last buffer's onended can flip isPlaying=false before this loop's next tick).
26727
+ var _iterator3 = _createForOfIteratorHelper(_this1.sentenceTimings),
26728
+ _step3;
26729
+ try {
26730
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
26731
+ var timing = _step3.value;
26732
+ if (!timing.doneReported) {
26733
+ timing.doneReported = true;
26734
+ var end = timing.endTime != null ? timing.endTime : timing.startTime;
26735
+ var playedMs = Math.round((end - timing.startTime) * 1000);
26736
+ _this1.emit('segmentDone', {
26737
+ segmentId: timing.segmentId,
26738
+ status: 'finished',
26739
+ playedMs: playedMs
26740
+ });
26741
+ }
26742
+ }
26743
+ } catch (err) {
26744
+ _iterator3.e(err);
26745
+ } finally {
26746
+ _iterator3.f();
26747
+ }
26435
26748
  _this1.isCheckingTranscripts = false;
26436
26749
  console.log('📝 AudioPlayer: Transcript checker stopped');
26437
26750
  }
@@ -26447,6 +26760,8 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26447
26760
  value: function clearTranscriptState() {
26448
26761
  this.pendingSentenceText = null;
26449
26762
  this.pendingSynced = null;
26763
+ this.pendingSegmentId = null;
26764
+ this.currentSegmentId = null;
26450
26765
  this.sentenceTimings = [];
26451
26766
  this.isCheckingTranscripts = false;
26452
26767
  console.log('📝 AudioPlayer: Transcript state cleared');
@@ -26596,13 +26911,13 @@ __webpack_require__.r(__webpack_exports__);
26596
26911
  /* harmony import */ var _utils_screenshot_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../utils/screenshot.js */ "./src/utils/screenshot.js");
26597
26912
  /* harmony import */ var _utils_visual_tools_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../utils/visual-tools.js */ "./src/utils/visual-tools.js");
26598
26913
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
26914
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
26915
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
26916
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
26599
26917
  function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
26600
26918
  function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); }
26601
26919
  function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
26602
26920
  function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
26603
- function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
26604
- function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
26605
- function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
26606
26921
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
26607
26922
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
26608
26923
  function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
@@ -27169,19 +27484,23 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
27169
27484
  key: "setupAudioPlayerEvents",
27170
27485
  value: function setupAudioPlayerEvents() {
27171
27486
  var _this3 = this;
27172
- this.audioPlayer.on('playbackStarted', function () {
27487
+ this.audioPlayer.on('playbackStarted', function (info) {
27173
27488
  _this3.isPlaying = true;
27174
27489
  _this3.emit('playbackStarted');
27175
27490
 
27176
27491
  // Transcripts are displayed when they arrive (between sentences)
27177
27492
  // No need to handle transcript display here - it's handled in handleTranscript()
27178
27493
 
27179
- // Notify server - CRITICAL for barge-in detection
27494
+ // Notify server - CRITICAL for barge-in detection.
27495
+ // Carry the segmentId of the burst that started playing (echoed from audio_start) so the
27496
+ // backend can correlate playback events with the bursts it sent.
27180
27497
 
27181
27498
  if (_this3.isConnected) {
27182
- console.log('📤 VoiceSDK v2: Sending audio_started_playing message to server');
27499
+ var segmentId = info && info.segmentId != null ? info.segmentId : null;
27500
+ console.log('📤 VoiceSDK v2: Sending audio_started_playing message to server (segmentId: ' + segmentId + ')');
27183
27501
  _this3.sendMessage({
27184
- t: 'audio_started_playing'
27502
+ t: 'audio_started_playing',
27503
+ segmentId: segmentId
27185
27504
  });
27186
27505
  } else {
27187
27506
  console.warn('⚠️ VoiceSDK v2: Cannot send audio_started_playing - not connected');
@@ -27205,39 +27524,48 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
27205
27524
  _this3.emit('transcriptDisplay', fullTranscriptData);
27206
27525
  _this3.emit('transcript', fullTranscriptData);
27207
27526
  if (transcriptData.synced && Array.isArray(transcriptData.synced)) {
27208
- console.log("\uD83D\uDCDD VoiceSDK v2: Emitting ".concat(transcriptData.synced.length, " synced action(s) as message events"));
27209
- var _iterator = _createForOfIteratorHelper(transcriptData.synced),
27210
- _step;
27211
- try {
27212
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
27213
- var action = _step.value;
27214
- _this3.emit('message', action);
27215
- }
27216
- } catch (err) {
27217
- _iterator.e(err);
27218
- } finally {
27219
- _iterator.f();
27220
- }
27527
+ console.log("\uD83D\uDCDD VoiceSDK v2: Dispatching ".concat(transcriptData.synced.length, " synced action(s)"));
27528
+ void _this3._dispatchSyncedActions(transcriptData.synced);
27221
27529
  }
27222
27530
  });
27223
- this.audioPlayer.on('playbackStopped', function () {
27531
+ this.audioPlayer.on('playbackStopped', function (info) {
27224
27532
  _this3.isPlaying = false;
27225
27533
  _this3.emit('playbackStopped');
27226
27534
 
27227
27535
  // When playback stops, keep currentPlayingSentenceId to track which sentence just finished
27228
27536
  // The next transcript will arrive between sentences and will be displayed immediately
27229
27537
 
27230
- // Notify server - CRITICAL for barge-in detection
27538
+ // Notify server - CRITICAL for barge-in detection.
27539
+ // Carry the segmentId of the last burst that was playing so the backend's idle gate can
27540
+ // match this stop against the last burst it sent (deterministic "fully idle").
27231
27541
 
27232
27542
  if (_this3.isConnected) {
27233
- console.log('📤 VoiceSDK v2: Sending audio_stopped_playing message to server');
27543
+ var segmentId = info && info.segmentId != null ? info.segmentId : null;
27544
+ console.log('📤 VoiceSDK v2: Sending audio_stopped_playing message to server (segmentId: ' + segmentId + ')');
27234
27545
  _this3.sendMessage({
27235
- t: 'audio_stopped_playing'
27546
+ t: 'audio_stopped_playing',
27547
+ segmentId: segmentId
27236
27548
  });
27237
27549
  } else {
27238
27550
  console.warn('⚠️ VoiceSDK v2: Cannot send audio_stopped_playing - not connected');
27239
27551
  }
27240
27552
  });
27553
+
27554
+ // Per-segment playback completion (finished / barged_in / interrupted) with the ms of THIS
27555
+ // segment actually heard. Additive telemetry alongside the coarse started/stopped events.
27556
+
27557
+ this.audioPlayer.on('segmentDone', function (info) {
27558
+ if (!info) return;
27559
+ if (_this3.isConnected) {
27560
+ console.log('📤 VoiceSDK v2: Sending audio_segment_done (segmentId: ' + info.segmentId + ', status: ' + info.status + ', playedMs: ' + info.playedMs + ')');
27561
+ _this3.sendMessage({
27562
+ t: 'audio_segment_done',
27563
+ segmentId: info.segmentId != null ? info.segmentId : null,
27564
+ status: info.status,
27565
+ playedMs: info.playedMs
27566
+ });
27567
+ }
27568
+ });
27241
27569
  this.audioPlayer.on('playbackError', function (error) {
27242
27570
  _this3.emit('playbackError', error);
27243
27571
  _this3.emit('error', error);
@@ -27602,7 +27930,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
27602
27930
 
27603
27931
  // Include SDK build time for debugging
27604
27932
  if (true) {
27605
- helloMessage.lastBuildTime = "2026-06-14T07:18:03.004Z";
27933
+ helloMessage.lastBuildTime = "2026-06-28T10:02:02.645Z";
27606
27934
  }
27607
27935
 
27608
27936
  // Page context is intentionally NOT attached to the hello message.
@@ -27757,7 +28085,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
27757
28085
  case 'audio_start':
27758
28086
  // Backend sends audio_start with transcript text before audio chunks
27759
28087
  // Store the text in AudioPlayer for synced display when audio actually starts playing
27760
- console.log('📝 VoiceSDK v2: Received audio_start with text:', message.text);
28088
+ console.log('📝 VoiceSDK v2: Received audio_start with text:', message.text, '(segmentId:', message.segmentId, ')');
27761
28089
 
27762
28090
  // CRITICAL: Record timestamp to prevent premature stop_playing messages from cutting sentences
27763
28091
  this.lastAudioStartTime = Date.now();
@@ -27773,7 +28101,10 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
27773
28101
  if (synced) {
27774
28102
  console.log("\uD83D\uDCDD VoiceSDK v2: audio_start carries ".concat(synced.length, " synced action(s)"));
27775
28103
  }
27776
- this.audioPlayer.markNewSentence(message.text, synced);
28104
+ // Pass the backend-assigned segmentId (may be undefined for legacy backends) so the
28105
+ // player can echo it back on this segment's playback events.
28106
+ var segmentId = message.segmentId != null ? message.segmentId : null;
28107
+ this.audioPlayer.markNewSentence(message.text, synced, segmentId);
27777
28108
  }
27778
28109
  // Also emit as message for other listeners
27779
28110
  this.emit('message', message);
@@ -28302,6 +28633,104 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28302
28633
  }
28303
28634
  }
28304
28635
 
28636
+ /**
28637
+ * Dispatch widget actions synced to a TTS sentence boundary.
28638
+ * run_partner_script envelopes must go through the same handler as WS traffic
28639
+ * (show_media and other t= messages still emit as generic message events).
28640
+ * @private
28641
+ */
28642
+ }, {
28643
+ key: "_dispatchSyncedActions",
28644
+ value: (function () {
28645
+ var _dispatchSyncedActions2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(actions) {
28646
+ var _iterator, _step, raw, _t2;
28647
+ return _regenerator().w(function (_context3) {
28648
+ while (1) switch (_context3.p = _context3.n) {
28649
+ case 0:
28650
+ _iterator = _createForOfIteratorHelper(actions);
28651
+ _context3.p = 1;
28652
+ _iterator.s();
28653
+ case 2:
28654
+ if ((_step = _iterator.n()).done) {
28655
+ _context3.n = 4;
28656
+ break;
28657
+ }
28658
+ raw = _step.value;
28659
+ _context3.n = 3;
28660
+ return this._dispatchSyncedAction(raw);
28661
+ case 3:
28662
+ _context3.n = 2;
28663
+ break;
28664
+ case 4:
28665
+ _context3.n = 6;
28666
+ break;
28667
+ case 5:
28668
+ _context3.p = 5;
28669
+ _t2 = _context3.v;
28670
+ _iterator.e(_t2);
28671
+ case 6:
28672
+ _context3.p = 6;
28673
+ _iterator.f();
28674
+ return _context3.f(6);
28675
+ case 7:
28676
+ return _context3.a(2);
28677
+ }
28678
+ }, _callee3, this, [[1, 5, 6, 7]]);
28679
+ }));
28680
+ function _dispatchSyncedActions(_x) {
28681
+ return _dispatchSyncedActions2.apply(this, arguments);
28682
+ }
28683
+ return _dispatchSyncedActions;
28684
+ }())
28685
+ }, {
28686
+ key: "_dispatchSyncedAction",
28687
+ value: function () {
28688
+ var _dispatchSyncedAction2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(action) {
28689
+ var message, _t3;
28690
+ return _regenerator().w(function (_context4) {
28691
+ while (1) switch (_context4.p = _context4.n) {
28692
+ case 0:
28693
+ message = action;
28694
+ if (!(typeof message === 'string')) {
28695
+ _context4.n = 3;
28696
+ break;
28697
+ }
28698
+ _context4.p = 1;
28699
+ message = JSON.parse(message);
28700
+ _context4.n = 3;
28701
+ break;
28702
+ case 2:
28703
+ _context4.p = 2;
28704
+ _t3 = _context4.v;
28705
+ console.warn('⚠️ VoiceSDK v2: Ignoring invalid synced action string:', action);
28706
+ return _context4.a(2);
28707
+ case 3:
28708
+ if (!(!message || _typeof(message) !== 'object')) {
28709
+ _context4.n = 4;
28710
+ break;
28711
+ }
28712
+ return _context4.a(2);
28713
+ case 4:
28714
+ if (!(message.t === 'run_partner_script')) {
28715
+ _context4.n = 6;
28716
+ break;
28717
+ }
28718
+ _context4.n = 5;
28719
+ return this._handleRunPartnerScript(message);
28720
+ case 5:
28721
+ return _context4.a(2);
28722
+ case 6:
28723
+ this.emit('message', message);
28724
+ case 7:
28725
+ return _context4.a(2);
28726
+ }
28727
+ }, _callee4, this, [[1, 2]]);
28728
+ }));
28729
+ function _dispatchSyncedAction(_x2) {
28730
+ return _dispatchSyncedAction2.apply(this, arguments);
28731
+ }
28732
+ return _dispatchSyncedAction;
28733
+ }()
28305
28734
  /**
28306
28735
  * Handle a run_partner_script envelope (async partner-adapter dispatch).
28307
28736
  *
@@ -28320,30 +28749,30 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28320
28749
  }, {
28321
28750
  key: "_handleRunPartnerScript",
28322
28751
  value: (function () {
28323
- var _handleRunPartnerScript2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(message) {
28752
+ var _handleRunPartnerScript2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(message) {
28324
28753
  var _this$clientToolsRegi;
28325
- var _ref, requestId, partnerId, action, args, handler, startedAt, result, elapsedMs, ok, reason, extras, preview, _elapsedMs, _t2;
28326
- return _regenerator().w(function (_context3) {
28327
- while (1) switch (_context3.p = _context3.n) {
28754
+ var _ref, requestId, partnerId, action, args, handler, startedAt, result, elapsedMs, ok, reason, extras, preview, _elapsedMs, _t4;
28755
+ return _regenerator().w(function (_context5) {
28756
+ while (1) switch (_context5.p = _context5.n) {
28328
28757
  case 0:
28329
28758
  _ref = message || {}, requestId = _ref.requestId, partnerId = _ref.partnerId, action = _ref.action;
28330
28759
  args = message && message.args || {};
28331
28760
  if (requestId) {
28332
- _context3.n = 1;
28761
+ _context5.n = 1;
28333
28762
  break;
28334
28763
  }
28335
28764
  console.warn('⚠️ VoiceSDK v2: run_partner_script missing requestId; dropping', message);
28336
- return _context3.a(2);
28765
+ return _context5.a(2);
28337
28766
  case 1:
28338
28767
  if (!_core_ClientScriptManager_js__WEBPACK_IMPORTED_MODULE_5__.ClientScriptManager.isClientToolsScript(message)) {
28339
- _context3.n = 2;
28768
+ _context5.n = 2;
28340
28769
  break;
28341
28770
  }
28342
- return _context3.a(2, this.clientScriptManager.handleRunPartnerScript(message));
28771
+ return _context5.a(2, this.clientScriptManager.handleRunPartnerScript(message));
28343
28772
  case 2:
28344
28773
  handler = (_this$clientToolsRegi = this.clientToolsRegistry) === null || _this$clientToolsRegi === void 0 || (_this$clientToolsRegi = _this$clientToolsRegi.handlers) === null || _this$clientToolsRegi === void 0 ? void 0 : _this$clientToolsRegi.get('run_partner_script');
28345
28774
  if (handler) {
28346
- _context3.n = 3;
28775
+ _context5.n = 3;
28347
28776
  break;
28348
28777
  }
28349
28778
  console.error("\uD83E\uDDE9 VoiceSDK v2: no run_partner_script handler registered (ecommerce flavor not loaded?); requestId=".concat(requestId, " partner=").concat(partnerId, " action=").concat(action));
@@ -28355,18 +28784,18 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28355
28784
  ok: false,
28356
28785
  error: 'no_handler_registered'
28357
28786
  });
28358
- return _context3.a(2);
28787
+ return _context5.a(2);
28359
28788
  case 3:
28360
28789
  startedAt = Date.now();
28361
28790
  console.log("\uD83E\uDDE9 VoiceSDK v2: run_partner_script dispatch partner=".concat(partnerId, " action=").concat(action, " requestId=").concat(requestId));
28362
- _context3.p = 4;
28363
- _context3.n = 5;
28791
+ _context5.p = 4;
28792
+ _context5.n = 5;
28364
28793
  return handler({
28365
28794
  action: action,
28366
28795
  args: args
28367
28796
  });
28368
28797
  case 5:
28369
- result = _context3.v;
28798
+ result = _context5.v;
28370
28799
  elapsedMs = Date.now() - startedAt; // Adapters return { ok, ... } themselves. Honor that flag if present;
28371
28800
  // otherwise treat presence-of-result as success.
28372
28801
  ok = result && _typeof(result) === 'object' && 'ok' in result ? !!result.ok : true; // Surface the failure reason inline so debugging doesn't require pulling
@@ -28393,27 +28822,27 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28393
28822
  ok: ok,
28394
28823
  result: result
28395
28824
  });
28396
- _context3.n = 7;
28825
+ _context5.n = 7;
28397
28826
  break;
28398
28827
  case 6:
28399
- _context3.p = 6;
28400
- _t2 = _context3.v;
28828
+ _context5.p = 6;
28829
+ _t4 = _context5.v;
28401
28830
  _elapsedMs = Date.now() - startedAt;
28402
- console.error("\uD83E\uDDE9 VoiceSDK v2: run_partner_script threw partner=".concat(partnerId, " action=").concat(action, " requestId=").concat(requestId, " (").concat(_elapsedMs, "ms):"), _t2);
28831
+ console.error("\uD83E\uDDE9 VoiceSDK v2: run_partner_script threw partner=".concat(partnerId, " action=").concat(action, " requestId=").concat(requestId, " (").concat(_elapsedMs, "ms):"), _t4);
28403
28832
  this.sendMessage({
28404
28833
  t: 'run_partner_script_result',
28405
28834
  requestId: requestId,
28406
28835
  partnerId: partnerId,
28407
28836
  action: action,
28408
28837
  ok: false,
28409
- error: _t2 && _t2.message || String(_t2)
28838
+ error: _t4 && _t4.message || String(_t4)
28410
28839
  });
28411
28840
  case 7:
28412
- return _context3.a(2);
28841
+ return _context5.a(2);
28413
28842
  }
28414
- }, _callee3, this, [[4, 6]]);
28843
+ }, _callee5, this, [[4, 6]]);
28415
28844
  }));
28416
- function _handleRunPartnerScript(_x) {
28845
+ function _handleRunPartnerScript(_x3) {
28417
28846
  return _handleRunPartnerScript2.apply(this, arguments);
28418
28847
  }
28419
28848
  return _handleRunPartnerScript;
@@ -28458,7 +28887,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28458
28887
  }, {
28459
28888
  key: "injectData",
28460
28889
  value: (function () {
28461
- var _injectData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(data) {
28890
+ var _injectData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6(data) {
28462
28891
  var _this7 = this;
28463
28892
  var options,
28464
28893
  trimmedData,
@@ -28469,15 +28898,15 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28469
28898
  timeout,
28470
28899
  source,
28471
28900
  message,
28472
- _args4 = arguments;
28473
- return _regenerator().w(function (_context4) {
28474
- while (1) switch (_context4.n) {
28901
+ _args6 = arguments;
28902
+ return _regenerator().w(function (_context6) {
28903
+ while (1) switch (_context6.n) {
28475
28904
  case 0:
28476
- options = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : {};
28905
+ options = _args6.length > 1 && _args6[1] !== undefined ? _args6[1] : {};
28477
28906
  // Validation: data content
28478
28907
  trimmedData = data === null || data === void 0 ? void 0 : data.trim();
28479
28908
  if (trimmedData) {
28480
- _context4.n = 1;
28909
+ _context6.n = 1;
28481
28910
  break;
28482
28911
  }
28483
28912
  error = {
@@ -28489,7 +28918,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28489
28918
  throw new Error(error.message);
28490
28919
  case 1:
28491
28920
  if (!(!this.isConnected || !this.websocket)) {
28492
- _context4.n = 2;
28921
+ _context6.n = 2;
28493
28922
  break;
28494
28923
  }
28495
28924
  _error = {
@@ -28501,7 +28930,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28501
28930
  throw new Error(_error.message);
28502
28931
  case 2:
28503
28932
  if (!(trimmedData.length > 5000)) {
28504
- _context4.n = 3;
28933
+ _context6.n = 3;
28505
28934
  break;
28506
28935
  }
28507
28936
  _error2 = {
@@ -28530,7 +28959,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28530
28959
  }
28531
28960
 
28532
28961
  // Return Promise that resolves when acknowledgment is received
28533
- return _context4.a(2, new Promise(function (_resolve, _reject) {
28962
+ return _context6.a(2, new Promise(function (_resolve, _reject) {
28534
28963
  // Set up timeout
28535
28964
  var timeoutId = setTimeout(function () {
28536
28965
  // Remove from pending map
@@ -28581,9 +29010,9 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28581
29010
  }
28582
29011
  }));
28583
29012
  }
28584
- }, _callee4, this);
29013
+ }, _callee6, this);
28585
29014
  }));
28586
- function injectData(_x2) {
29015
+ function injectData(_x4) {
28587
29016
  return _injectData.apply(this, arguments);
28588
29017
  }
28589
29018
  return injectData;
@@ -28713,20 +29142,20 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28713
29142
  }, {
28714
29143
  key: "handleBinaryMessage",
28715
29144
  value: (function () {
28716
- var _handleBinaryMessage = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(data) {
28717
- var arrayBuffer, processedAudio, playbackFormat, container, encoding, pcmData, codec, decoded, _t3;
28718
- return _regenerator().w(function (_context5) {
28719
- while (1) switch (_context5.p = _context5.n) {
29145
+ var _handleBinaryMessage = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7(data) {
29146
+ var arrayBuffer, processedAudio, playbackFormat, container, encoding, pcmData, codec, decoded, _t5;
29147
+ return _regenerator().w(function (_context7) {
29148
+ while (1) switch (_context7.p = _context7.n) {
28720
29149
  case 0:
28721
29150
  if (!(data instanceof Blob)) {
28722
- _context5.n = 2;
29151
+ _context7.n = 2;
28723
29152
  break;
28724
29153
  }
28725
- _context5.n = 1;
29154
+ _context7.n = 1;
28726
29155
  return data.arrayBuffer();
28727
29156
  case 1:
28728
- arrayBuffer = _context5.v;
28729
- _context5.n = 3;
29157
+ arrayBuffer = _context7.v;
29158
+ _context7.n = 3;
28730
29159
  break;
28731
29160
  case 2:
28732
29161
  arrayBuffer = data;
@@ -28734,21 +29163,21 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28734
29163
  // Convert format if needed (before passing to AudioPlayer)
28735
29164
  processedAudio = arrayBuffer;
28736
29165
  if (!(this.formatConverter && this.formatConverter.needsConversion())) {
28737
- _context5.n = 7;
29166
+ _context7.n = 7;
28738
29167
  break;
28739
29168
  }
28740
- _context5.p = 4;
28741
- _context5.n = 5;
29169
+ _context7.p = 4;
29170
+ _context7.n = 5;
28742
29171
  return this.formatConverter.convert(arrayBuffer);
28743
29172
  case 5:
28744
- processedAudio = _context5.v;
29173
+ processedAudio = _context7.v;
28745
29174
  console.log('✅ VoiceSDK v2: Audio converted to requested format');
28746
- _context5.n = 7;
29175
+ _context7.n = 7;
28747
29176
  break;
28748
29177
  case 6:
28749
- _context5.p = 6;
28750
- _t3 = _context5.v;
28751
- console.error('❌ VoiceSDK v2: Format conversion failed:', _t3);
29178
+ _context7.p = 6;
29179
+ _t5 = _context7.v;
29180
+ console.error('❌ VoiceSDK v2: Format conversion failed:', _t5);
28752
29181
  console.warn(' Using backend format without conversion');
28753
29182
  processedAudio = arrayBuffer; // Fall back to original
28754
29183
  case 7:
@@ -28798,11 +29227,11 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28798
29227
  this.audioPlayer.playAudio(processedAudio);
28799
29228
  }
28800
29229
  case 8:
28801
- return _context5.a(2);
29230
+ return _context7.a(2);
28802
29231
  }
28803
- }, _callee5, this, [[4, 6]]);
29232
+ }, _callee7, this, [[4, 6]]);
28804
29233
  }));
28805
- function handleBinaryMessage(_x3) {
29234
+ function handleBinaryMessage(_x5) {
28806
29235
  return _handleBinaryMessage.apply(this, arguments);
28807
29236
  }
28808
29237
  return handleBinaryMessage;
@@ -28990,22 +29419,22 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28990
29419
  }, {
28991
29420
  key: "startRecording",
28992
29421
  value: (function () {
28993
- var _startRecording = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
29422
+ var _startRecording = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
28994
29423
  var existingMediaStream,
28995
29424
  error,
28996
29425
  _error4,
28997
29426
  _error5,
28998
29427
  permissionError,
28999
- _args6 = arguments,
29000
- _t4,
29001
- _t5,
29002
- _t6;
29003
- return _regenerator().w(function (_context6) {
29004
- while (1) switch (_context6.p = _context6.n) {
29428
+ _args8 = arguments,
29429
+ _t6,
29430
+ _t7,
29431
+ _t8;
29432
+ return _regenerator().w(function (_context8) {
29433
+ while (1) switch (_context8.p = _context8.n) {
29005
29434
  case 0:
29006
- existingMediaStream = _args6.length > 0 && _args6[0] !== undefined ? _args6[0] : null;
29435
+ existingMediaStream = _args8.length > 0 && _args8[0] !== undefined ? _args8[0] : null;
29007
29436
  if (this.isConnected) {
29008
- _context6.n = 1;
29437
+ _context8.n = 1;
29009
29438
  break;
29010
29439
  }
29011
29440
  error = new Error('Not connected to voice server');
@@ -29013,14 +29442,14 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29013
29442
  throw error;
29014
29443
  case 1:
29015
29444
  if (!this.isRecording) {
29016
- _context6.n = 2;
29445
+ _context8.n = 2;
29017
29446
  break;
29018
29447
  }
29019
29448
  console.warn('VoiceSDK v2: Already recording');
29020
- return _context6.a(2, true);
29449
+ return _context8.a(2, true);
29021
29450
  case 2:
29022
29451
  if (!this.disclaimersPending) {
29023
- _context6.n = 3;
29452
+ _context8.n = 3;
29024
29453
  break;
29025
29454
  }
29026
29455
  _error4 = new Error('Server disclaimers must be accepted before recording. Call sendDisclaimerAck(true) first.');
@@ -29029,28 +29458,28 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29029
29458
  throw _error4;
29030
29459
  case 3:
29031
29460
  console.log('🎤 VoiceSDK v2: Starting recording...');
29032
- _context6.p = 4;
29461
+ _context8.p = 4;
29033
29462
  // CRITICAL for mobile browsers: Request microphone permission FIRST
29034
29463
  // iOS: Pass existingMediaStream to avoid second getUserMedia (can fail on iOS)
29035
29464
  console.log('🎤 VoiceSDK v2: Requesting microphone permission (mobile-friendly)...');
29036
- _context6.n = 5;
29465
+ _context8.n = 5;
29037
29466
  return this.audioRecorder.start(existingMediaStream ? {
29038
29467
  existingMediaStream: existingMediaStream
29039
29468
  } : {});
29040
29469
  case 5:
29041
29470
  if (!(!this.isConnected || !this.websocket || this.websocket.readyState !== WebSocket.OPEN)) {
29042
- _context6.n = 10;
29471
+ _context8.n = 10;
29043
29472
  break;
29044
29473
  }
29045
- _context6.p = 6;
29046
- _context6.n = 7;
29474
+ _context8.p = 6;
29475
+ _context8.n = 7;
29047
29476
  return this.audioRecorder.stop();
29048
29477
  case 7:
29049
- _context6.n = 9;
29478
+ _context8.n = 9;
29050
29479
  break;
29051
29480
  case 8:
29052
- _context6.p = 8;
29053
- _t4 = _context6.v;
29481
+ _context8.p = 8;
29482
+ _t6 = _context8.v;
29054
29483
  case 9:
29055
29484
  _error5 = new Error('Connection lost - server may have rejected the call');
29056
29485
  _error5.name = 'ServerRejected';
@@ -29059,7 +29488,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29059
29488
  // The error handler in VoiceInterface will handle it appropriately
29060
29489
  throw _error5;
29061
29490
  case 10:
29062
- _context6.n = 11;
29491
+ _context8.n = 11;
29063
29492
  return this.audioPlayer.resumeAudioContext();
29064
29493
  case 11:
29065
29494
  // After permission is granted, send start_continuous_mode message to server
@@ -29070,45 +29499,45 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29070
29499
 
29071
29500
  // Request screen wake lock to keep screen on during voice call (mobile)
29072
29501
  this._requestWakeLock();
29073
- return _context6.a(2, true);
29502
+ return _context8.a(2, true);
29074
29503
  case 12:
29075
- _context6.p = 12;
29076
- _t5 = _context6.v;
29504
+ _context8.p = 12;
29505
+ _t7 = _context8.v;
29077
29506
  if (!(this.audioRecorder && this.audioRecorder.isRecording)) {
29078
- _context6.n = 16;
29507
+ _context8.n = 16;
29079
29508
  break;
29080
29509
  }
29081
- _context6.p = 13;
29082
- _context6.n = 14;
29510
+ _context8.p = 13;
29511
+ _context8.n = 14;
29083
29512
  return this.audioRecorder.stop();
29084
29513
  case 14:
29085
- _context6.n = 16;
29514
+ _context8.n = 16;
29086
29515
  break;
29087
29516
  case 15:
29088
- _context6.p = 15;
29089
- _t6 = _context6.v;
29517
+ _context8.p = 15;
29518
+ _t8 = _context8.v;
29090
29519
  case 16:
29091
- if (!(_t5.isServerRejection || _t5.name === 'ServerRejected')) {
29092
- _context6.n = 17;
29520
+ if (!(_t7.isServerRejection || _t7.name === 'ServerRejected')) {
29521
+ _context8.n = 17;
29093
29522
  break;
29094
29523
  }
29095
- return _context6.a(2, false);
29524
+ return _context8.a(2, false);
29096
29525
  case 17:
29097
29526
  // Log and emit other errors (permission denied, etc.)
29098
- console.error('❌ VoiceSDK v2: Failed to start recording:', _t5);
29527
+ console.error('❌ VoiceSDK v2: Failed to start recording:', _t7);
29099
29528
 
29100
29529
  // Provide helpful error messages for permission issues
29101
- if (_t5.name === 'NotAllowedError' || _t5.name === 'PermissionDeniedError') {
29530
+ if (_t7.name === 'NotAllowedError' || _t7.name === 'PermissionDeniedError') {
29102
29531
  permissionError = new Error('Microphone permission denied. Please allow microphone access in your browser settings and try again.');
29103
- permissionError.name = _t5.name;
29104
- permissionError.originalError = _t5;
29532
+ permissionError.name = _t7.name;
29533
+ permissionError.originalError = _t7;
29105
29534
  this.emit('error', permissionError);
29106
29535
  } else {
29107
- this.emit('error', _t5);
29536
+ this.emit('error', _t7);
29108
29537
  }
29109
- return _context6.a(2, false);
29538
+ return _context8.a(2, false);
29110
29539
  }
29111
- }, _callee6, this, [[13, 15], [6, 8], [4, 12]]);
29540
+ }, _callee8, this, [[13, 15], [6, 8], [4, 12]]);
29112
29541
  }));
29113
29542
  function startRecording() {
29114
29543
  return _startRecording.apply(this, arguments);
@@ -29122,20 +29551,20 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29122
29551
  }, {
29123
29552
  key: "stopRecording",
29124
29553
  value: (function () {
29125
- var _stopRecording = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7() {
29126
- var _t7;
29127
- return _regenerator().w(function (_context7) {
29128
- while (1) switch (_context7.p = _context7.n) {
29554
+ var _stopRecording = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
29555
+ var _t9;
29556
+ return _regenerator().w(function (_context9) {
29557
+ while (1) switch (_context9.p = _context9.n) {
29129
29558
  case 0:
29130
29559
  if (this.isRecording) {
29131
- _context7.n = 1;
29560
+ _context9.n = 1;
29132
29561
  break;
29133
29562
  }
29134
29563
  console.warn('VoiceSDK v2: Not recording');
29135
- return _context7.a(2, true);
29564
+ return _context9.a(2, true);
29136
29565
  case 1:
29137
29566
  console.log('🛑 VoiceSDK v2: Stopping recording...');
29138
- _context7.p = 2;
29567
+ _context9.p = 2;
29139
29568
  // Send stop_continuous_mode message to server
29140
29569
 
29141
29570
  this.sendMessage({
@@ -29153,21 +29582,21 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29153
29582
  this._releaseWakeLock();
29154
29583
 
29155
29584
  // Stop capturing audio from microphone
29156
- _context7.n = 3;
29585
+ _context9.n = 3;
29157
29586
  return this.audioRecorder.stop();
29158
29587
  case 3:
29159
29588
  // Stop any playing audio
29160
29589
 
29161
29590
  this.stopAudioPlayback();
29162
- return _context7.a(2, true);
29591
+ return _context9.a(2, true);
29163
29592
  case 4:
29164
- _context7.p = 4;
29165
- _t7 = _context7.v;
29166
- console.error('VoiceSDK v2: Error stopping recording:', _t7);
29167
- this.emit('error', _t7);
29168
- return _context7.a(2, false);
29593
+ _context9.p = 4;
29594
+ _t9 = _context9.v;
29595
+ console.error('VoiceSDK v2: Error stopping recording:', _t9);
29596
+ this.emit('error', _t9);
29597
+ return _context9.a(2, false);
29169
29598
  }
29170
- }, _callee7, this, [[2, 4]]);
29599
+ }, _callee9, this, [[2, 4]]);
29171
29600
  }));
29172
29601
  function stopRecording() {
29173
29602
  return _stopRecording.apply(this, arguments);
@@ -29181,27 +29610,27 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29181
29610
  }, {
29182
29611
  key: "toggleRecording",
29183
29612
  value: (function () {
29184
- var _toggleRecording = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
29185
- return _regenerator().w(function (_context8) {
29186
- while (1) switch (_context8.n) {
29613
+ var _toggleRecording = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
29614
+ return _regenerator().w(function (_context0) {
29615
+ while (1) switch (_context0.n) {
29187
29616
  case 0:
29188
29617
  if (!this.isRecording) {
29189
- _context8.n = 2;
29618
+ _context0.n = 2;
29190
29619
  break;
29191
29620
  }
29192
- _context8.n = 1;
29621
+ _context0.n = 1;
29193
29622
  return this.stopRecording();
29194
29623
  case 1:
29195
- return _context8.a(2, _context8.v);
29624
+ return _context0.a(2, _context0.v);
29196
29625
  case 2:
29197
- _context8.n = 3;
29626
+ _context0.n = 3;
29198
29627
  return this.startRecording();
29199
29628
  case 3:
29200
- return _context8.a(2, _context8.v);
29629
+ return _context0.a(2, _context0.v);
29201
29630
  case 4:
29202
- return _context8.a(2);
29631
+ return _context0.a(2);
29203
29632
  }
29204
- }, _callee8, this);
29633
+ }, _callee0, this);
29205
29634
  }));
29206
29635
  function toggleRecording() {
29207
29636
  return _toggleRecording.apply(this, arguments);
@@ -29232,33 +29661,33 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29232
29661
  }, {
29233
29662
  key: "_requestWakeLock",
29234
29663
  value: (function () {
29235
- var _requestWakeLock2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
29664
+ var _requestWakeLock2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1() {
29236
29665
  var _this9 = this;
29237
- var _t8;
29238
- return _regenerator().w(function (_context9) {
29239
- while (1) switch (_context9.p = _context9.n) {
29666
+ var _t0;
29667
+ return _regenerator().w(function (_context1) {
29668
+ while (1) switch (_context1.p = _context1.n) {
29240
29669
  case 0:
29241
29670
  if ('wakeLock' in navigator) {
29242
- _context9.n = 1;
29671
+ _context1.n = 1;
29243
29672
  break;
29244
29673
  }
29245
29674
  console.log('📱 VoiceSDK v2: Wake Lock API not available in this browser');
29246
- return _context9.a(2);
29675
+ return _context1.a(2);
29247
29676
  case 1:
29248
29677
  if (!(this.wakeLock !== null || this._wakeLockRequesting)) {
29249
- _context9.n = 2;
29678
+ _context1.n = 2;
29250
29679
  break;
29251
29680
  }
29252
29681
  console.log('📱 VoiceSDK v2: Wake lock already active or being requested');
29253
- return _context9.a(2);
29682
+ return _context1.a(2);
29254
29683
  case 2:
29255
- _context9.p = 2;
29684
+ _context1.p = 2;
29256
29685
  this._wakeLockRequesting = true;
29257
29686
  // Request wake lock (screen type keeps screen on)
29258
- _context9.n = 3;
29687
+ _context1.n = 3;
29259
29688
  return navigator.wakeLock.request('screen');
29260
29689
  case 3:
29261
- this.wakeLock = _context9.v;
29690
+ this.wakeLock = _context1.v;
29262
29691
  console.log('📱 VoiceSDK v2: Screen wake lock activated - screen will stay on during call');
29263
29692
 
29264
29693
  // Handle wake lock release (e.g., user switches tabs, locks device)
@@ -29266,23 +29695,23 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29266
29695
  console.log('📱 VoiceSDK v2: Wake lock released by system');
29267
29696
  _this9.wakeLock = null;
29268
29697
  });
29269
- _context9.n = 5;
29698
+ _context1.n = 5;
29270
29699
  break;
29271
29700
  case 4:
29272
- _context9.p = 4;
29273
- _t8 = _context9.v;
29701
+ _context1.p = 4;
29702
+ _t0 = _context1.v;
29274
29703
  // Wake lock request failed (e.g., permission denied, battery saver mode)
29275
- console.warn('📱 VoiceSDK v2: Failed to request wake lock:', _t8.message);
29704
+ console.warn('📱 VoiceSDK v2: Failed to request wake lock:', _t0.message);
29276
29705
  this.wakeLock = null;
29277
29706
  // Don't throw - this is a nice-to-have feature, not critical
29278
29707
  case 5:
29279
- _context9.p = 5;
29708
+ _context1.p = 5;
29280
29709
  this._wakeLockRequesting = false;
29281
- return _context9.f(5);
29710
+ return _context1.f(5);
29282
29711
  case 6:
29283
- return _context9.a(2);
29712
+ return _context1.a(2);
29284
29713
  }
29285
- }, _callee9, this, [[2, 4, 5, 6]]);
29714
+ }, _callee1, this, [[2, 4, 5, 6]]);
29286
29715
  }));
29287
29716
  function _requestWakeLock() {
29288
29717
  return _requestWakeLock2.apply(this, arguments);
@@ -29297,34 +29726,34 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29297
29726
  }, {
29298
29727
  key: "_releaseWakeLock",
29299
29728
  value: (function () {
29300
- var _releaseWakeLock2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
29301
- var _t9;
29302
- return _regenerator().w(function (_context0) {
29303
- while (1) switch (_context0.p = _context0.n) {
29729
+ var _releaseWakeLock2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee10() {
29730
+ var _t1;
29731
+ return _regenerator().w(function (_context10) {
29732
+ while (1) switch (_context10.p = _context10.n) {
29304
29733
  case 0:
29305
29734
  if (!(this.wakeLock === null)) {
29306
- _context0.n = 1;
29735
+ _context10.n = 1;
29307
29736
  break;
29308
29737
  }
29309
- return _context0.a(2);
29738
+ return _context10.a(2);
29310
29739
  case 1:
29311
- _context0.p = 1;
29312
- _context0.n = 2;
29740
+ _context10.p = 1;
29741
+ _context10.n = 2;
29313
29742
  return this.wakeLock.release();
29314
29743
  case 2:
29315
29744
  this.wakeLock = null;
29316
29745
  console.log('📱 VoiceSDK v2: Screen wake lock released');
29317
- _context0.n = 4;
29746
+ _context10.n = 4;
29318
29747
  break;
29319
29748
  case 3:
29320
- _context0.p = 3;
29321
- _t9 = _context0.v;
29322
- console.warn('📱 VoiceSDK v2: Error releasing wake lock:', _t9.message);
29749
+ _context10.p = 3;
29750
+ _t1 = _context10.v;
29751
+ console.warn('📱 VoiceSDK v2: Error releasing wake lock:', _t1.message);
29323
29752
  this.wakeLock = null;
29324
29753
  case 4:
29325
- return _context0.a(2);
29754
+ return _context10.a(2);
29326
29755
  }
29327
- }, _callee0, this, [[1, 3]]);
29756
+ }, _callee10, this, [[1, 3]]);
29328
29757
  }));
29329
29758
  function _releaseWakeLock() {
29330
29759
  return _releaseWakeLock2.apply(this, arguments);
@@ -29348,21 +29777,21 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29348
29777
  }, {
29349
29778
  key: "handleBargeIn",
29350
29779
  value: (function () {
29351
- var _handleBargeIn = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1() {
29352
- return _regenerator().w(function (_context1) {
29353
- while (1) switch (_context1.n) {
29780
+ var _handleBargeIn = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee11() {
29781
+ return _regenerator().w(function (_context11) {
29782
+ while (1) switch (_context11.n) {
29354
29783
  case 0:
29355
29784
  this.stopAudioPlayback();
29356
29785
  if (this.isRecording) {
29357
- _context1.n = 1;
29786
+ _context11.n = 1;
29358
29787
  break;
29359
29788
  }
29360
- _context1.n = 1;
29789
+ _context11.n = 1;
29361
29790
  return this.startRecording();
29362
29791
  case 1:
29363
- return _context1.a(2);
29792
+ return _context11.a(2);
29364
29793
  }
29365
- }, _callee1, this);
29794
+ }, _callee11, this);
29366
29795
  }));
29367
29796
  function handleBargeIn() {
29368
29797
  return _handleBargeIn.apply(this, arguments);
@@ -32275,10 +32704,17 @@ var TTPChatWidget = /*#__PURE__*/function () {
32275
32704
  this._flavorObj = this.config.flavor && _typeof(this.config.flavor) === 'object' ? this.config.flavor : null;
32276
32705
  if (this._flavorObj && this._flavorObj.type) {
32277
32706
  this._initFlavor(this._flavorObj.type);
32278
- this._initEcommerceVoiceStrip();
32279
- } else if (this._flavorObj && !this._flavorObj.type) {
32707
+ } else if (this._flavorObj && !this._flavorObj.type && this._flavorObj.callView !== 'minimized') {
32708
+ // A flavor object with neither a "type" nor callView:'minimized' is malformed.
32709
+ // (callView:'minimized' alone is a valid flavor-less minimized-strip config.)
32280
32710
  console.error('[TTPChatWidget] flavor object is set but missing required "type" field. Widget will run in vanilla mode.');
32281
32711
  }
32712
+ // The desktop minimized bottom strip is flavor-independent: it only needs
32713
+ // flavor.callView === 'minimized' (+ desktop width). Init it regardless of
32714
+ // whether a flavor type is present, so callView:'minimized' works standalone
32715
+ // with no partner/flavor. _initEcommerceVoiceStrip() self-guards and no-ops
32716
+ // when callView !== 'minimized' or on mobile.
32717
+ this._initEcommerceVoiceStrip();
32282
32718
  }
32283
32719
 
32284
32720
  /**
@@ -32694,7 +33130,11 @@ var TTPChatWidget = /*#__PURE__*/function () {
32694
33130
  offset: positionConfig.offset || {
32695
33131
  x: 20,
32696
33132
  y: 20
32697
- }
33133
+ },
33134
+ // When true, the launcher pill / mobile FAB can be dragged around the
33135
+ // viewport. Set position.draggablePersist:false to reset position each load.
33136
+ draggable: false,
33137
+ draggablePersist: true
32698
33138
  }, _typeof(userConfig.position) === 'object' ? userConfig.position : {}),
32699
33139
  // Button Configuration
32700
33140
  button: _objectSpread({
@@ -33330,6 +33770,125 @@ var TTPChatWidget = /*#__PURE__*/function () {
33330
33770
  var footer = (_root$querySelector = root.querySelector) === null || _root$querySelector === void 0 ? void 0 : _root$querySelector.call(root, '.ttp-footer');
33331
33771
  if (footer) footer.style.display = visible ? '' : 'none';
33332
33772
  }
33773
+
33774
+ /**
33775
+ * Resolve the most recent conversation id used by either channel.
33776
+ * Prefers a live voice/text SDK value, then falls back to persisted state.
33777
+ * @returns {string|null}
33778
+ */
33779
+ }, {
33780
+ key: "_getLastConversationId",
33781
+ value: function _getLastConversationId() {
33782
+ var _this$voiceInterface3, _this$sdk;
33783
+ var live = (_this$voiceInterface3 = this.voiceInterface) === null || _this$voiceInterface3 === void 0 || (_this$voiceInterface3 = _this$voiceInterface3.sdk) === null || _this$voiceInterface3 === void 0 || (_this$voiceInterface3 = _this$voiceInterface3.voiceSDK) === null || _this$voiceInterface3 === void 0 ? void 0 : _this$voiceInterface3.conversationId;
33784
+ if (live) return live;
33785
+ var textId = (_this$sdk = this.sdk) === null || _this$sdk === void 0 || (_this$sdk = _this$sdk.config) === null || _this$sdk === void 0 ? void 0 : _this$sdk.conversationId;
33786
+ if (textId) return textId;
33787
+ try {
33788
+ var raw = sessionStorage.getItem('voice_resume_state');
33789
+ if (raw) {
33790
+ var s = JSON.parse(raw);
33791
+ if (s && s.conversationId) return s.conversationId;
33792
+ }
33793
+ } catch (_) {/* ignore */}
33794
+ try {
33795
+ var t = localStorage.getItem('ttp_text_chat_conversation_id');
33796
+ if (t) return t;
33797
+ } catch (_) {/* ignore */}
33798
+ return null;
33799
+ }
33800
+
33801
+ /** Inline TalkToPC logo mark (speech bubble + sound waves). */
33802
+ }, {
33803
+ key: "_aboutLogoSVG",
33804
+ value: function _aboutLogoSVG() {
33805
+ return "<svg class=\"ttp-about-logo-mark\" width=\"34\" height=\"34\" viewBox=\"0 0 48 48\" fill=\"none\" aria-hidden=\"true\">\n <rect x=\"4\" y=\"6\" width=\"40\" height=\"30\" rx=\"10\" fill=\"url(#ttpAboutGrad)\"/>\n <path d=\"M16 36l-4 7 11-7z\" fill=\"url(#ttpAboutGrad)\"/>\n <g stroke=\"#ffffff\" stroke-width=\"2.6\" stroke-linecap=\"round\">\n <line x1=\"18\" y1=\"17\" x2=\"18\" y2=\"25\"/>\n <line x1=\"24\" y1=\"13\" x2=\"24\" y2=\"29\"/>\n <line x1=\"30\" y1=\"18\" x2=\"30\" y2=\"24\"/>\n </g>\n <defs>\n <linearGradient id=\"ttpAboutGrad\" x1=\"4\" y1=\"6\" x2=\"44\" y2=\"43\" gradientUnits=\"userSpaceOnUse\">\n <stop stop-color=\"#8b5cf6\"/>\n <stop offset=\"1\" stop-color=\"#6d28d9\"/>\n </linearGradient>\n </defs>\n </svg>";
33806
+ }
33807
+
33808
+ /**
33809
+ * Inject the "About" dialog styles into document.head once.
33810
+ * Global (light DOM) so the dialog renders above the desktop minimized strip,
33811
+ * which lives outside the shadow root at the maximum z-index.
33812
+ */
33813
+ }, {
33814
+ key: "_ensureAboutStyles",
33815
+ value: function _ensureAboutStyles() {
33816
+ if (document.getElementById('ttp-about-dialog-styles')) return;
33817
+ var style = document.createElement('style');
33818
+ style.id = 'ttp-about-dialog-styles';
33819
+ style.textContent = "\n .ttp-about-overlay {\n position: fixed; inset: 0; z-index: 2147483647;\n display: flex; align-items: center; justify-content: center;\n padding: 16px; box-sizing: border-box;\n background: rgba(15,15,25,0.55);\n backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);\n animation: ttpAboutFade 0.18s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n }\n @keyframes ttpAboutFade { from { opacity: 0; } to { opacity: 1; } }\n .ttp-about-card {\n position: relative; width: 100%; max-width: 320px; box-sizing: border-box;\n background: #ffffff; color: #1f2937; border-radius: 16px;\n padding: 24px 22px 22px; box-shadow: 0 24px 60px rgba(0,0,0,0.35);\n text-align: center; animation: ttpAboutPop 0.2s ease-out;\n }\n @keyframes ttpAboutPop {\n from { transform: translateY(8px) scale(0.98); opacity: 0; }\n to { transform: translateY(0) scale(1); opacity: 1; }\n }\n .ttp-about-close {\n position: absolute; top: 10px; inset-inline-end: 10px;\n background: none; border: none; cursor: pointer; color: #9ca3af;\n padding: 6px; line-height: 0; border-radius: 50%;\n transition: background 0.2s, color 0.2s;\n }\n .ttp-about-close:hover { background: #f3f4f6; color: #4b5563; }\n .ttp-about-logo {\n display: flex; align-items: center; justify-content: center;\n gap: 8px; margin-bottom: 14px;\n }\n .ttp-about-logo-mark { display: block; flex-shrink: 0; }\n .ttp-about-brand {\n font-size: 20px; font-weight: 800; letter-spacing: -0.2px; color: #6d28d9;\n }\n .ttp-about-title {\n font-size: 13px; font-weight: 600; text-transform: uppercase;\n letter-spacing: 1px; color: #9ca3af; margin-bottom: 16px;\n }\n .ttp-about-rows {\n display: flex; flex-direction: column; gap: 10px; text-align: start;\n }\n .ttp-about-row {\n display: flex; flex-direction: column; gap: 3px;\n background: #f9fafb; border: 1px solid #f0f0f4;\n border-radius: 10px; padding: 10px 12px;\n }\n .ttp-about-key {\n font-size: 11px; font-weight: 600; text-transform: uppercase;\n letter-spacing: 0.5px; color: #9ca3af;\n }\n .ttp-about-val {\n font-size: 14px; font-weight: 600; color: #1f2937; word-break: break-all;\n }\n .ttp-about-mono {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12.5px; font-weight: 500;\n }\n .ttp-about-muted { color: #9ca3af; font-weight: 500; font-style: italic; }\n ";
33820
+ document.head.appendChild(style);
33821
+ }
33822
+
33823
+ /** Open the shared "About" dialog (logo + SDK version + last conversation id). */
33824
+ }, {
33825
+ key: "_openAboutModal",
33826
+ value: function _openAboutModal() {
33827
+ var _this8 = this,
33828
+ _overlay$querySelecto;
33829
+ // Toggle: if already open, close it.
33830
+ if (this._aboutOverlay) {
33831
+ this._closeAboutModal();
33832
+ return;
33833
+ }
33834
+ this._ensureAboutStyles();
33835
+ var version = true ? "2.45.12" : 0;
33836
+ var convId = this._getLastConversationId();
33837
+ var t = function t(k, fb) {
33838
+ try {
33839
+ var _this8$voiceInterface, _this8$voiceInterface2, _this8$textInterface, _this8$textInterface$;
33840
+ return ((_this8$voiceInterface = _this8.voiceInterface) === null || _this8$voiceInterface === void 0 || (_this8$voiceInterface2 = _this8$voiceInterface.t) === null || _this8$voiceInterface2 === void 0 ? void 0 : _this8$voiceInterface2.call(_this8$voiceInterface, k)) || ((_this8$textInterface = _this8.textInterface) === null || _this8$textInterface === void 0 || (_this8$textInterface$ = _this8$textInterface.t) === null || _this8$textInterface$ === void 0 ? void 0 : _this8$textInterface$.call(_this8$textInterface, k)) || fb;
33841
+ } catch (_) {
33842
+ return fb;
33843
+ }
33844
+ };
33845
+ var title = t('aboutTitle', 'About');
33846
+ var versionLabel = t('aboutVersion', 'SDK version');
33847
+ var convLabel = t('aboutConversationId', 'Last conversation ID');
33848
+ var noneLabel = t('aboutNoConversation', 'No conversation yet');
33849
+ var overlay = document.createElement('div');
33850
+ overlay.className = 'ttp-about-overlay';
33851
+ overlay.innerHTML = "\n <div class=\"ttp-about-card\" role=\"dialog\" aria-modal=\"true\" aria-label=\"".concat(title, "\">\n <button type=\"button\" class=\"ttp-about-close\" aria-label=\"Close\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\">\n <path d=\"M10 2L2 10M2 2l8 8\"/>\n </svg>\n </button>\n <div class=\"ttp-about-logo\">").concat(this._aboutLogoSVG(), "<span class=\"ttp-about-brand\">TalkToPC</span></div>\n <div class=\"ttp-about-title\">").concat(title, "</div>\n <div class=\"ttp-about-rows\">\n <div class=\"ttp-about-row\">\n <span class=\"ttp-about-key\">").concat(versionLabel, "</span>\n <span class=\"ttp-about-val\" data-about-version></span>\n </div>\n <div class=\"ttp-about-row\">\n <span class=\"ttp-about-key\">").concat(convLabel, "</span>\n <span class=\"ttp-about-val ttp-about-mono\" data-about-conv></span>\n </div>\n </div>\n </div>");
33852
+
33853
+ // Fill dynamic values via textContent to avoid any injection.
33854
+ var verEl = overlay.querySelector('[data-about-version]');
33855
+ if (verEl) verEl.textContent = version ? "v".concat(version) : '—';
33856
+ var convEl = overlay.querySelector('[data-about-conv]');
33857
+ if (convEl) {
33858
+ convEl.textContent = convId || noneLabel;
33859
+ if (!convId) convEl.classList.add('ttp-about-muted');
33860
+ }
33861
+ var close = function close() {
33862
+ return _this8._closeAboutModal();
33863
+ };
33864
+ overlay.addEventListener('click', function (e) {
33865
+ if (e.target === overlay) close();
33866
+ });
33867
+ (_overlay$querySelecto = overlay.querySelector('.ttp-about-close')) === null || _overlay$querySelecto === void 0 || _overlay$querySelecto.addEventListener('click', function (e) {
33868
+ e.stopPropagation();
33869
+ close();
33870
+ });
33871
+ this._aboutKeyHandler = function (e) {
33872
+ if (e.key === 'Escape') close();
33873
+ };
33874
+ document.addEventListener('keydown', this._aboutKeyHandler);
33875
+ document.body.appendChild(overlay);
33876
+ this._aboutOverlay = overlay;
33877
+ }
33878
+
33879
+ /** Close the "About" dialog if open. */
33880
+ }, {
33881
+ key: "_closeAboutModal",
33882
+ value: function _closeAboutModal() {
33883
+ if (this._aboutKeyHandler) {
33884
+ document.removeEventListener('keydown', this._aboutKeyHandler);
33885
+ this._aboutKeyHandler = null;
33886
+ }
33887
+ if (this._aboutOverlay) {
33888
+ this._aboutOverlay.remove();
33889
+ this._aboutOverlay = null;
33890
+ }
33891
+ }
33333
33892
  }, {
33334
33893
  key: "generatePositionStyles",
33335
33894
  value: function generatePositionStyles() {
@@ -33461,13 +34020,14 @@ var TTPChatWidget = /*#__PURE__*/function () {
33461
34020
  var callActivePanelBg = callSurfaceGradient;
33462
34021
  var voiceIdleVisibleSelector = '#voiceInterface.active #voiceIdleState:not([style*="display: none"]):not([style*="display:none"])';
33463
34022
  var voiceActiveVisibleSelector = '#voiceInterface.active #voiceActiveState:not([style*="display: none"]):not([style*="display:none"])';
33464
- return "\n /* Inline style display overrides - ensures JS show/hide works with !important CSS */\n #text-chat-panel [style*=\"display: none\"],\n #text-chat-panel [style*=\"display:none\"],\n #text-chat-button-container [style*=\"display: none\"],\n #text-chat-button-container [style*=\"display:none\"],\n #ttpMobileLanding[style*=\"display: none\"],\n #ttpMobileLanding[style*=\"display:none\"] {\n display: none !important;\n }\n #text-chat-panel [style*=\"display: flex\"],\n #text-chat-panel [style*=\"display:flex\"],\n #text-chat-button-container [style*=\"display: flex\"],\n #text-chat-button-container [style*=\"display:flex\"] {\n display: flex !important;\n }\n #text-chat-panel [style*=\"display: block\"],\n #text-chat-panel [style*=\"display:block\"] {\n display: block !important;\n }\n\n /* MOBILE FIRST - Default styles for all devices */\n #text-chat-widget {\n position: fixed !important;\n z-index: 10000".concat(important, ";\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif").concat(important, ";\n /* Mobile defaults */\n right: 10px").concat(important, ";\n bottom: 10px").concat(important, ";\n left: auto").concat(important, ";\n top: auto").concat(important, ";\n }\n \n /* Desktop positioning (only on larger screens) */\n @media (min-width: 769px) {\n #text-chat-widget {\n ").concat(positionStyles, "\n right: ").concat(this.config.position.horizontal === 'right' ? '20px' : 'auto').concat(important, ";\n left: ").concat(this.config.position.horizontal === 'left' ? '20px' : 'auto').concat(important, ";\n bottom: ").concat(this.config.position.vertical === 'bottom' ? '20px' : 'auto').concat(important, ";\n top: ").concat(this.config.position.vertical === 'top' ? '20px' : 'auto').concat(important, ";\n }\n }\n \n /* Mobile override (force mobile positioning) */\n @media (max-width: 768px) {\n #text-chat-widget {\n right: 10px !important;\n bottom: 10px !important;\n left: auto !important;\n top: auto !important;\n transform: none !important;\n }\n }\n \n @media (max-width: 480px) {\n #text-chat-widget {\n right: 8px !important;\n bottom: 8px !important;\n left: auto !important;\n top: auto !important;\n }\n }\n \n /* \u2500\u2500 Desktop Pill Launcher \u2500\u2500 */\n #text-chat-button {\n position: relative").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 8px").concat(important, ";\n padding-block: 10px").concat(important, ";\n padding-inline-start: 6px").concat(important, ";\n padding-inline-end: 12px").concat(important, ";\n z-index: 1").concat(important, ";\n background: ").concat(pillGradient, ";\n border: 1px solid rgba(139,92,246,0.15)").concat(important, ";\n border-radius: 999px").concat(important, ";\n box-shadow: 0 8px 32px rgba(0,0,0,0.25), 0 2px 8px rgba(0,0,0,0.15)").concat(important, ";\n cursor: pointer").concat(important, ";\n transition: box-shadow 0.25s, transform 0.2s, padding 0.3s, gap 0.3s").concat(important, ";\n font-family: inherit").concat(important, ";\n color: ").concat(pillTextColor, ";\n overflow: hidden").concat(important, ";\n box-sizing: border-box").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n #text-chat-button:hover {\n transform: translateY(-1px)").concat(important, ";\n box-shadow: 0 10px 40px rgba(0,0,0,0.35), 0 4px 12px rgba(0,0,0,0.2)").concat(important, ";\n }\n #text-chat-button.open {\n gap: 0px").concat(important, ";\n padding: 9px").concat(important, ";\n width: auto").concat(important, ";\n min-width: 0").concat(important, ";\n max-width: none").concat(important, ";\n }\n\n @media (min-width: 769px) {\n #text-chat-button {\n width: 158px").concat(important, ";\n min-width: 158px").concat(important, ";\n max-width: 158px").concat(important, ";\n }\n }\n\n .ttp-pill-icon {\n width: 36px").concat(important, "; height: 36px").concat(important, "; border-radius: 50%").concat(important, ";\n background: #ffffff").concat(important, ";\n display: flex").concat(important, "; align-items: center").concat(important, "; justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n .ttp-launcher-logo {\n width: 22px").concat(important, "; height: 22px").concat(important, "; border-radius: 50%").concat(important, ";\n object-fit: cover").concat(important, ";\n }\n\n /* Default pill launcher: same animated waveform as mobile FAB / landing */\n .ttp-pill-icon--wave {\n background: rgba(255, 255, 255, 0.15)").concat(important, ";\n }\n .ttp-pill-waveform {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 2px").concat(important, ";\n height: 16px").concat(important, ";\n }\n .ttp-pill-waveform .bar {\n width: 2px").concat(important, ";\n background: #fff").concat(important, ";\n border-radius: 1px").concat(important, ";\n animation: ttpWaveAnimation 0.8s ease-in-out infinite").concat(important, ";\n }\n .ttp-pill-waveform .bar:nth-child(1) { height: 5px").concat(important, "; animation-delay: 0s").concat(important, "; }\n .ttp-pill-waveform .bar:nth-child(2) { height: 10px").concat(important, "; animation-delay: 0.1s").concat(important, "; }\n .ttp-pill-waveform .bar:nth-child(3) { height: 16px").concat(important, "; animation-delay: 0.2s").concat(important, "; }\n .ttp-pill-waveform .bar:nth-child(4) { height: 8px").concat(important, "; animation-delay: 0.3s").concat(important, "; }\n .ttp-pill-waveform .bar:nth-child(5) { height: 12px").concat(important, "; animation-delay: 0.4s").concat(important, "; }\n\n .ttp-pill-text {\n display: flex").concat(important, "; flex-direction: column").concat(important, "; gap: 2px").concat(important, ";\n max-width: 82px").concat(important, ";\n opacity: 1").concat(important, ";\n overflow: hidden").concat(important, ";\n white-space: nowrap").concat(important, ";\n transition: max-width 0.3s, opacity 0.2s").concat(important, ";\n }\n #text-chat-button.open .ttp-pill-text {\n max-width: 0").concat(important, ";\n opacity: 0").concat(important, ";\n }\n .ttp-pill-title {\n font-size: 13px").concat(important, "; font-weight: 600").concat(important, "; color: ").concat(pillTextColor, ";\n line-height: 1.25").concat(important, ";\n overflow: hidden").concat(important, ";\n text-overflow: ellipsis").concat(important, ";\n }\n .ttp-pill-status {\n display: flex").concat(important, "; align-items: center").concat(important, "; gap: 4px").concat(important, ";\n font-size: 11px").concat(important, "; color: ").concat(pillTextColor, "8c;\n line-height: 1.25").concat(important, ";\n }\n\n /* Online dot (inside pill status) */\n .ttp-launcher-dot {\n width: 7px").concat(important, "; height: 7px").concat(important, "; border-radius: 50%").concat(important, ";\n background: ").concat(pillDotColor, ";\n flex-shrink: 0").concat(important, ";\n animation: ttp-dot-pulse 2s ease-in-out infinite").concat(important, ";\n }\n @keyframes ttp-dot-pulse { 0%,100%{opacity:1} 50%{opacity:.4} }\n \n @media (max-width: 768px) {\n #text-chat-widget {\n right: 10px !important;\n bottom: 10px !important;\n left: auto !important;\n top: auto !important;\n transform: none !important;\n }\n \n #text-chat-button-container {\n width: auto !important;\n height: auto !important;\n }\n \n #text-chat-panel {\n position: fixed !important;\n right: 10px !important;\n left: auto !important;\n bottom: 92px !important; /* 56px button + 20px gap + 16px footer */\n top: auto !important;\n width: 340px !important;\n max-width: calc(100vw - 20px) !important;\n height: auto !important;\n max-height: calc(100vh - 130px) !important;\n transform: none !important;\n margin: 0 !important;\n }\n \n #text-chat-panel .widget-header {\n padding: 10px 14px").concat(important, ";\n min-height: 56px").concat(important, ";\n }\n \n #text-chat-panel .header-title {\n font-size: 15px").concat(important, ";\n }\n \n #text-chat-panel .header-icon {\n width: 40px").concat(important, ";\n height: 40px").concat(important, ";\n min-width: 40px").concat(important, ";\n min-height: 40px").concat(important, ";\n }\n \n #text-chat-input {\n font-size: 16px !important; /* Prevents iOS zoom on focus */\n padding: 12px 16px !important;\n min-height: 48px !important;\n }\n \n #text-chat-send {\n min-width: 48px !important;\n min-height: 48px !important;\n width: 48px !important;\n height: 48px !important;\n }\n \n }\n \n @media (max-width: 480px) {\n #text-chat-widget {\n right: 8px !important;\n bottom: 8px !important;\n left: auto !important;\n top: auto !important;\n }\n \n #text-chat-button-container {\n width: auto !important;\n height: auto !important;\n }\n \n #text-chat-panel {\n right: 8px !important;\n left: auto !important;\n bottom: 86px !important; /* 54px button + 20px gap + 12px footer */\n top: auto !important;\n width: 340px !important;\n max-width: calc(100vw - 16px) !important;\n height: auto !important;\n max-height: calc(100vh - 120px) !important;\n }\n \n #text-chat-panel .widget-header {\n padding: 8px 12px").concat(important, ";\n min-height: 52px").concat(important, ";\n }\n \n #text-chat-panel .header-title {\n font-size: 14px").concat(important, ";\n }\n \n }\n \n ").concat(anim.enableHover ? "\n #text-chat-button:hover {\n transform: translateY(-1px);\n }\n " : '', "\n \n /* Prompt Animation Keyframes */\n @keyframes widget-shimmer {\n 0% { transform: translateX(-100%); }\n 100% { transform: translateX(200%); }\n }\n \n @keyframes widget-ripple {\n 0% { transform: scale(1); opacity: 0.6; }\n 100% { transform: scale(2.5); opacity: 0; }\n }\n \n @keyframes widget-float {\n 0%, 100% { transform: translateX(-50%) translateY(0); }\n 50% { transform: translateX(-50%) translateY(-8px); }\n }\n \n @keyframes widget-bounce {\n 0%, 100% { transform: translateX(-50%) translateY(0); }\n 50% { transform: translateX(-50%) translateY(-10px); }\n }\n \n @keyframes widget-pulse-ring {\n 0% { transform: scale(1); opacity: 0.4; }\n 100% { transform: scale(1.8); opacity: 0; }\n }\n \n /* Prompt Bubble Container */\n #text-chat-button-container {\n position: fixed").concat(important, ";\n ").concat(this.config.position.vertical === 'bottom' ? "bottom: ".concat(((_this$config$position = this.config.position.offset) === null || _this$config$position === void 0 ? void 0 : _this$config$position.y) || 20, "px;") : "top: ".concat(((_this$config$position2 = this.config.position.offset) === null || _this$config$position2 === void 0 ? void 0 : _this$config$position2.y) || 20, "px;"), "\n ").concat(this.config.position.horizontal === 'right' ? "right: ".concat(((_this$config$position3 = this.config.position.offset) === null || _this$config$position3 === void 0 ? void 0 : _this$config$position3.x) || 20, "px;") : "left: ".concat(((_this$config$position4 = this.config.position.offset) === null || _this$config$position4 === void 0 ? void 0 : _this$config$position4.x) || 20, "px;"), "\n width: auto").concat(important, ";\n height: auto").concat(important, ";\n z-index: 10001").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n }\n \n @media (max-width: 768px) {\n #text-chat-button-container {\n right: 10px !important;\n bottom: 10px !important;\n left: auto !important;\n top: auto !important;\n }\n }\n \n @media (max-width: 480px) {\n #text-chat-button-container {\n right: 8px !important;\n bottom: 8px !important;\n left: auto !important;\n top: auto !important;\n }\n }\n \n /* Prompt Bubble Styles */\n .prompt-bubble {\n position: absolute").concat(important, ";\n z-index: 10002").concat(important, ";\n pointer-events: none").concat(important, ";\n white-space: nowrap").concat(important, ";\n }\n \n .prompt-bubble.top {\n bottom: calc(100% + 18px)").concat(important, ";\n left: 50%").concat(important, ";\n transform: translateX(-50%)").concat(important, ";\n }\n \n .prompt-bubble.left {\n right: calc(100% + 12px)").concat(important, ";\n top: 50%").concat(important, ";\n transform: translateY(-50%)").concat(important, ";\n }\n \n .prompt-bubble.right {\n left: calc(100% + 12px)").concat(important, ";\n top: 50%").concat(important, ";\n transform: translateY(-50%)").concat(important, ";\n }\n \n /* Ensure animations preserve horizontal centering for top position */\n .prompt-bubble.top.animation-bounce {\n animation: widget-bounce 1s ease-in-out infinite").concat(important, ";\n transform: translateX(-50%)").concat(important, "; /* Keep centering */\n }\n \n .prompt-bubble.top.animation-float {\n animation: widget-float 2s ease-in-out infinite").concat(important, ";\n transform: translateX(-50%)").concat(important, "; /* Keep centering */\n }\n \n .prompt-bubble.top.animation-pulse {\n animation: pulse 2s ease-in-out infinite").concat(important, ";\n transform: translateX(-50%)").concat(important, "; /* Keep centering */\n }\n \n .prompt-bubble-content {\n position: relative").concat(important, ";\n padding: 8px 16px").concat(important, ";\n border-radius: 20px").concat(important, ";\n font-weight: 500").concat(important, ";\n font-size: 14px").concat(important, ";\n box-shadow: 0 4px 15px rgba(124, 58, 237, 0.3)").concat(important, ";\n overflow: hidden").concat(important, ";\n }\n \n .prompt-bubble-shimmer {\n position: absolute").concat(important, ";\n inset: 0").concat(important, ";\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.25), transparent)").concat(important, ";\n animation: widget-shimmer 2s infinite").concat(important, ";\n }\n \n .prompt-bubble.animation-bounce {\n animation: widget-bounce 1s ease-in-out infinite").concat(important, ";\n }\n \n .prompt-bubble.animation-pulse {\n animation: pulse 2s ease-in-out infinite").concat(important, ";\n }\n \n .prompt-bubble.animation-float {\n animation: widget-float 2s ease-in-out infinite").concat(important, ";\n }\n \n /* Ensure top-positioned bubbles maintain horizontal centering during animations */\n .prompt-bubble.top.animation-bounce,\n .prompt-bubble.top.animation-float,\n .prompt-bubble.top.animation-pulse {\n /* Animation keyframes already include translateX(-50%) for centering */\n }\n \n /* Prompt Bubble Arrow */\n .prompt-bubble-arrow {\n position: absolute").concat(important, ";\n width: 0").concat(important, ";\n height: 0").concat(important, ";\n border: 8px solid transparent").concat(important, ";\n }\n \n .prompt-bubble.top .prompt-bubble-arrow {\n top: 100%").concat(important, ";\n left: 50%").concat(important, ";\n transform: translateX(-50%)").concat(important, ";\n border-top-color: var(--prompt-bubble-bg-color, #7c3aed)").concat(important, ";\n border-bottom: none").concat(important, ";\n margin-left: 0").concat(important, ";\n }\n \n .prompt-bubble.left .prompt-bubble-arrow {\n left: 100%").concat(important, ";\n top: 50%").concat(important, ";\n transform: translateY(-50%)").concat(important, ";\n border-left-color: var(--prompt-bubble-bg-color, #7c3aed)").concat(important, ";\n border-right: none").concat(important, ";\n }\n \n .prompt-bubble.right .prompt-bubble-arrow {\n right: 100%").concat(important, ";\n top: 50%").concat(important, ";\n transform: translateY(-50%)").concat(important, ";\n border-right-color: var(--prompt-bubble-bg-color, #7c3aed)").concat(important, ";\n border-left: none").concat(important, ";\n }\n \n /* Pulse Rings */\n .prompt-pulse-rings {\n position: absolute").concat(important, ";\n inset: 0").concat(important, ";\n border-radius: 50%").concat(important, ";\n pointer-events: none").concat(important, ";\n }\n \n .prompt-pulse-ring {\n position: absolute").concat(important, ";\n inset: 0").concat(important, ";\n border-radius: 50%").concat(important, ";\n animation: widget-pulse-ring 2s ease-out infinite").concat(important, ";\n }\n \n .prompt-pulse-ring:nth-child(2) {\n animation-delay: 0.5s").concat(important, ";\n }\n \n /* Mobile adjustments for prompt bubble */\n @media (max-width: 768px) {\n .prompt-bubble-content {\n font-size: 12px").concat(important, ";\n padding: 6px 12px").concat(important, ";\n }\n \n .prompt-bubble.top {\n bottom: calc(100% + 14px)").concat(important, ";\n }\n \n .prompt-bubble.left,\n .prompt-bubble.right {\n display: none").concat(important, "; /* Hide side prompts on mobile */\n }\n }\n \n /* Shared panel chrome; size/position differ \u2014 desktop card vs mobile sheet (see @media blocks earlier) */\n #text-chat-panel {\n display: none").concat(important, ";\n position: fixed").concat(important, ";\n background: ").concat(panelBg, ";\n border-radius: 20px").concat(important, ";\n border: ").concat(panel.border || '1px solid rgba(255,255,255,0.08)', ";\n flex-direction: column").concat(important, ";\n overflow: hidden").concat(important, ";\n box-shadow: 0 24px 60px rgba(0,0,0,0.6)").concat(important, ";\n opacity: 0").concat(important, ";\n pointer-events: none").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n\n /* Desktop / tablet: floating 340px card anchored to launcher */\n @media (min-width: 769px) {\n #text-chat-panel {\n bottom: calc(54px + 24px)").concat(important, "; /* launcher pill + gap */\n ").concat(this.config.position.horizontal === 'right' ? 'right: 20px;' : 'left: 20px;', "\n width: 340px").concat(important, ";\n max-width: calc(100vw - 40px)").concat(important, ";\n height: auto").concat(important, ";\n max-height: calc(100vh - 100px)").concat(important, ";\n transform-origin: bottom right").concat(important, ";\n }\n /* Text chat: fixed height so the message list scrolls instead of growing the panel per message */\n #text-chat-panel:has(.text-interface.active) {\n height: min(520px, calc(100vh - 100px))").concat(important, ";\n }\n }\n \n #text-chat-panel.open {\n display: flex").concat(important, ";\n opacity: 1").concat(important, ";\n pointer-events: auto").concat(important, ";\n }\n\n /* Shell for panel inner */\n .widget-shell { width: 100%").concat(important, "; padding: 0").concat(important, "; border-radius: 20px").concat(important, "; background: transparent").concat(important, "; overflow: hidden").concat(important, "; display: flex").concat(important, "; flex-direction: column").concat(important, "; box-sizing: border-box").concat(important, "; flex: 1").concat(important, "; min-height: 0").concat(important, "; }\n .panel-inner { width: 100%").concat(important, "; background: ").concat(panelBg, "; border-radius: 20px").concat(important, "; border: none").concat(important, "; overflow: hidden").concat(important, "; display:flex").concat(important, "; flex-direction: column").concat(important, "; padding: 0").concat(important, "; box-sizing: border-box").concat(important, "; max-width: 100%").concat(important, "; flex: 1").concat(important, "; min-height: 0").concat(important, "; }\n\n #text-chat-panel .widget-container {\n width: 100%").concat(important, "; background: ").concat(panelBg, "; overflow: visible").concat(important, "; display: flex").concat(important, "; flex-direction: column").concat(important, "; border-radius: 20px").concat(important, "; flex: 1").concat(important, "; min-height: 0").concat(important, ";\n }\n\n /* Voice idle: one gradient for voice UI + footer (Powered by), not a flat strip under buttons */\n #text-chat-panel.open:has(").concat(voiceIdleVisibleSelector, ") {\n background: linear-gradient(160deg, ").concat(idleHeroGrad1, " 0%, ").concat(idleHeroGrad2, " 100%)").concat(important, ";\n }\n #text-chat-panel .widget-container:has(").concat(voiceIdleVisibleSelector, ") {\n background: linear-gradient(160deg, ").concat(idleHeroGrad1, " 0%, ").concat(idleHeroGrad2, " 100%)").concat(important, ";\n }\n\n /* Voice active call: same hero gradient as idle + mobile minimized bar */\n #text-chat-panel.open:has(").concat(voiceActiveVisibleSelector, ") {\n background: ").concat(callActivePanelBg).concat(important, ";\n }\n #text-chat-panel .widget-container:has(").concat(voiceActiveVisibleSelector, ") {\n background: ").concat(callActivePanelBg).concat(important, ";\n }\n #text-chat-panel.open:has(").concat(voiceActiveVisibleSelector, ") .widget-shell {\n background: ").concat(callActivePanelBg).concat(important, ";\n }\n #text-chat-panel.open:has(").concat(voiceActiveVisibleSelector, ") .panel-inner {\n background: ").concat(callActivePanelBg).concat(important, ";\n }\n #text-chat-panel.open:has(").concat(voiceActiveVisibleSelector, ") .ttp-footer {\n background: ").concat(callActivePanelBg).concat(important, ";\n }\n\n ").concat(textUsesVoiceTheme ? "\n /* Text chat with voice theme: same hero surface as voice idle; inner shells transparent */\n #text-chat-panel.open:has(.text-interface.active) {\n background: ".concat(callSurfaceGradient).concat(important, ";\n }\n #text-chat-panel.open:has(.text-interface.active) .widget-shell,\n #text-chat-panel.open:has(.text-interface.active) .panel-inner,\n #text-chat-panel.open:has(.text-interface.active) .widget-container {\n background: transparent").concat(important, ";\n }\n #text-chat-panel.open:has(.text-interface.active) .ttp-footer {\n background: transparent").concat(important, ";\n border-top-color: rgba(255,255,255,0.06)").concat(important, ";\n }\n #text-chat-panel.open:has(.text-interface.active) .ttp-footer span {\n color: rgba(255,255,255,0.35)").concat(important, ";\n }\n #text-chat-panel.open:has(.text-interface.active) .ttp-footer a {\n color: ").concat(footerLinkOnDarkHero).concat(important, ";\n }\n ") : '', "\n \n /* Voice may scroll as a whole; text chat keeps a fixed shell and scrolls #messagesContainer only */\n #text-chat-panel .widget-container > .voice-interface {\n flex: 1").concat(important, ";\n min-height: 0").concat(important, ";\n overflow-y: auto").concat(important, ";\n overflow-x: visible").concat(important, ";\n }\n #text-chat-panel .widget-container > .text-interface {\n flex: 1").concat(important, ";\n min-height: 0").concat(important, ";\n overflow: hidden").concat(important, ";\n overflow-x: visible").concat(important, ";\n }\n \n /* Header is removed in new design - hero serves as header */\n #text-chat-panel .widget-header { display: none").concat(important, "; }\n\n ").concat(showVoice ? this.voiceInterface.generateCSS() : '', "\n ").concat(showText ? this.textInterface.generateCSS() : '', "\n \n /* Footer Branding */\n .ttp-footer {\n padding: 6px 18px 10px").concat(important, ";\n border-top: 1px solid ").concat(footerBorderColor, ";\n display: flex").concat(important, ";\n justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n box-sizing: border-box").concat(important, ";\n background: transparent").concat(important, ";\n }\n .ttp-footer span { font-size: 10px").concat(important, "; color: ").concat(footerTextColor, "; }\n .ttp-footer a { color: ").concat(footerLinkColor, "; text-decoration: none").concat(important, "; font-weight: 600").concat(important, "; }\n .ttp-footer a:hover { opacity: 0.85").concat(important, "; }\n .ttp-footer a b { font-weight: 700").concat(important, "; }\n \n #text-chat-send-hint {\n text-align: center").concat(important, ";\n line-height: 1.4").concat(important, ";\n }\n \n .agent-thinking {\n font-style: italic").concat(important, ";\n color: #6B7280").concat(important, ";\n }\n\n /* ========================================\n MOBILE PILL BUTTON & LANDING OVERLAY\n Hidden on desktop, shown on mobile only\n ======================================== */\n .ttp-mobile-fab {\n display: none").concat(important, ";\n }\n\n .ttp-mobile-landing {\n display: none").concat(important, ";\n }\n\n @keyframes ttpWaveAnimation {\n 0%, 100% { transform: scaleY(0.4); }\n 50% { transform: scaleY(1); }\n }\n\n @keyframes ttpPulseAnimation {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n\n @media (max-width: 768px) {\n /* Hide desktop pill button on mobile */\n #text-chat-button {\n display: none !important;\n }\n\n /* Re-flow the container for pill shape */\n #text-chat-button-container {\n width: auto !important;\n height: auto !important;\n min-width: 0 !important;\n min-height: 0 !important;\n max-width: none !important;\n max-height: none !important;\n }\n\n /* Show mobile pill button */\n .ttp-mobile-fab {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 10px").concat(important, ";\n padding: 10px 16px 10px 12px").concat(important, ";\n background: ").concat(pillGradient, ";\n border: none").concat(important, ";\n border-radius: 24px").concat(important, ";\n cursor: pointer").concat(important, ";\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3)").concat(important, ";\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1)").concat(important, ";\n z-index: 1").concat(important, ";\n font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif").concat(important, ";\n touch-action: manipulation").concat(important, ";\n -webkit-tap-highlight-color: transparent").concat(important, ";\n }\n\n .ttp-mobile-fab:hover {\n transform: translateY(-3px)").concat(important, ";\n box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4)").concat(important, ";\n }\n\n .ttp-mobile-fab__icon-wrap {\n width: 36px").concat(important, ";\n height: 36px").concat(important, ";\n border-radius: 50%").concat(important, ";\n background: rgba(255, 255, 255, 0.15)").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n\n .ttp-mobile-fab__waveform {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 2px").concat(important, ";\n height: 16px").concat(important, ";\n }\n\n .ttp-mobile-fab__waveform .bar {\n width: 2px").concat(important, ";\n background: #fff").concat(important, ";\n border-radius: 1px").concat(important, ";\n animation: ttpWaveAnimation 0.8s ease-in-out infinite").concat(important, ";\n }\n\n .ttp-mobile-fab__waveform .bar:nth-child(1) { height: 5px").concat(important, "; animation-delay: 0s").concat(important, "; }\n .ttp-mobile-fab__waveform .bar:nth-child(2) { height: 10px").concat(important, "; animation-delay: 0.1s").concat(important, "; }\n .ttp-mobile-fab__waveform .bar:nth-child(3) { height: 16px").concat(important, "; animation-delay: 0.2s").concat(important, "; }\n .ttp-mobile-fab__waveform .bar:nth-child(4) { height: 8px").concat(important, "; animation-delay: 0.3s").concat(important, "; }\n .ttp-mobile-fab__waveform .bar:nth-child(5) { height: 12px").concat(important, "; animation-delay: 0.4s").concat(important, "; }\n\n .ttp-mobile-fab__label-wrap {\n display: flex").concat(important, ";\n flex-direction: column").concat(important, ";\n align-items: flex-start").concat(important, ";\n gap: 1px").concat(important, ";\n }\n\n .ttp-mobile-fab__label {\n color: ").concat(pillTextColor, ";\n font-size: 14px").concat(important, ";\n font-weight: 600").concat(important, ";\n line-height: 1.2").concat(important, ";\n }\n\n .ttp-mobile-fab__status {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 4px").concat(important, ";\n font-size: 11px").concat(important, ";\n color: ").concat(pillTextColor, "b3;\n line-height: 1.2").concat(important, ";\n }\n\n .ttp-mobile-fab__dot {\n width: 6px").concat(important, ";\n height: 6px").concat(important, ";\n background: ").concat(pillDotColor, ";\n border-radius: 50%").concat(important, ";\n box-shadow: 0 0 6px ").concat(pillDotColor, "99;\n }\n\n /* ---- Mobile Landing Overlay ---- */\n .ttp-mobile-landing.active {\n display: block").concat(important, ";\n position: fixed").concat(important, ";\n bottom: 16px").concat(important, ";\n left: 12px").concat(important, ";\n right: 12px").concat(important, ";\n background: ").concat(pillGradient, ";\n border-radius: 20px").concat(important, ";\n overflow: hidden").concat(important, ";\n box-shadow:\n 0 10px 40px rgba(0, 0, 0, 0.3),\n 0 0 0 1px rgba(255, 255, 255, 0.1) inset").concat(important, ";\n z-index: 10002").concat(important, ";\n font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif").concat(important, ";\n }\n\n .ttp-mobile-landing::before {\n content: ''").concat(important, ";\n position: absolute").concat(important, ";\n top: 0").concat(important, ";\n left: 0").concat(important, ";\n right: 0").concat(important, ";\n height: 1px").concat(important, ";\n background: linear-gradient(90deg,\n transparent 0%,\n rgba(255, 255, 255, 0.3) 50%,\n transparent 100%);\n }\n\n .ttp-mobile-landing__header {\n padding: 14px 16px").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 12px").concat(important, ";\n }\n\n .ttp-mobile-landing__avatar {\n width: 44px").concat(important, ";\n height: 44px").concat(important, ";\n border-radius: 12px").concat(important, ";\n background: rgba(255, 255, 255, 0.15)").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n\n .ttp-mobile-landing__waveform {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 3px").concat(important, ";\n height: 20px").concat(important, ";\n }\n\n .ttp-mobile-landing__waveform .bar {\n width: 3px").concat(important, ";\n background: rgba(255, 255, 255, 0.9)").concat(important, ";\n border-radius: 2px").concat(important, ";\n animation: ttpWaveAnimation 0.8s ease-in-out infinite").concat(important, ";\n }\n\n .ttp-mobile-landing__waveform .bar:nth-child(1) { height: 6px").concat(important, "; animation-delay: 0s").concat(important, "; }\n .ttp-mobile-landing__waveform .bar:nth-child(2) { height: 12px").concat(important, "; animation-delay: 0.1s").concat(important, "; }\n .ttp-mobile-landing__waveform .bar:nth-child(3) { height: 20px").concat(important, "; animation-delay: 0.2s").concat(important, "; }\n .ttp-mobile-landing__waveform .bar:nth-child(4) { height: 10px").concat(important, "; animation-delay: 0.3s").concat(important, "; }\n .ttp-mobile-landing__waveform .bar:nth-child(5) { height: 16px").concat(important, "; animation-delay: 0.4s").concat(important, "; }\n\n .ttp-mobile-landing__info {\n flex: 1").concat(important, ";\n min-width: 0").concat(important, ";\n }\n\n .ttp-mobile-landing__name {\n color: #fff").concat(important, ";\n font-size: 15px").concat(important, ";\n font-weight: 600").concat(important, ";\n margin-bottom: 2px").concat(important, ";\n }\n\n .ttp-mobile-landing__status {\n color: rgba(255, 255, 255, 0.7)").concat(important, ";\n font-size: 12px").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 5px").concat(important, ";\n }\n\n .ttp-mobile-landing__dot {\n width: 6px").concat(important, ";\n height: 6px").concat(important, ";\n background: ").concat(header.onlineIndicatorDotColor || '#10b981', ";\n border-radius: 50%").concat(important, ";\n animation: ttpPulseAnimation 2s ease-in-out infinite").concat(important, ";\n }\n\n .ttp-mobile-landing__close {\n width: 32px").concat(important, ";\n height: 32px").concat(important, ";\n border-radius: 10px").concat(important, ";\n background: rgba(255, 255, 255, 0.1)").concat(important, ";\n border: none").concat(important, ";\n color: rgba(255, 255, 255, 0.7)").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n cursor: pointer").concat(important, ";\n transition: all 0.2s").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n\n .ttp-mobile-landing__close:hover {\n background: rgba(255, 255, 255, 0.2)").concat(important, ";\n color: #fff").concat(important, ";\n }\n\n .ttp-mobile-landing__error {\n margin: 0 14px 10px").concat(important, ";\n padding: 10px 12px").concat(important, ";\n background: #fef2f2").concat(important, ";\n border: 1px solid #fecaca").concat(important, ";\n border-radius: 10px").concat(important, ";\n display: flex").concat(important, ";\n align-items: flex-start").concat(important, ";\n gap: 8px").concat(important, ";\n color: #b91c1c").concat(important, ";\n font-size: 13px").concat(important, ";\n line-height: 1.4").concat(important, ";\n }\n .ttp-mobile-landing__error svg {\n flex-shrink: 0").concat(important, ";\n margin-top: 1px").concat(important, ";\n stroke: #dc2626").concat(important, ";\n }\n\n .ttp-mobile-landing__actions {\n padding: 0 14px 14px").concat(important, ";\n display: flex").concat(important, ";\n gap: 10px").concat(important, ";\n }\n\n .ttp-mobile-landing__btn {\n flex: 1").concat(important, ";\n padding: 14px").concat(important, ";\n border-radius: 12px").concat(important, ";\n border: none").concat(important, ";\n cursor: pointer").concat(important, ";\n font-family: inherit").concat(important, ";\n font-size: 14px").concat(important, ";\n font-weight: 600").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n gap: 10px").concat(important, ";\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1)").concat(important, ";\n touch-action: manipulation").concat(important, ";\n -webkit-tap-highlight-color: transparent").concat(important, ";\n }\n\n .ttp-mobile-landing__btn svg {\n width: 20px").concat(important, ";\n height: 20px").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n\n .ttp-mobile-landing__btn--call {\n background: #fff").concat(important, ";\n color: ").concat(header.backgroundColor || '#7C3AED', ";\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15)").concat(important, ";\n }\n\n .ttp-mobile-landing__btn--call:hover {\n transform: translateY(-2px)").concat(important, ";\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2)").concat(important, ";\n }\n\n .ttp-mobile-landing__btn--text {\n background: rgba(255, 255, 255, 0.15)").concat(important, ";\n color: #fff").concat(important, ";\n border: 1px solid rgba(255, 255, 255, 0.1)").concat(important, ";\n }\n\n .ttp-mobile-landing__btn--text:hover {\n background: rgba(255, 255, 255, 0.2)").concat(important, ";\n border-color: rgba(255, 255, 255, 0.2)").concat(important, ";\n }\n\n .ttp-mobile-landing__footer {\n padding: 10px 16px").concat(important, ";\n display: flex").concat(important, ";\n justify-content: center").concat(important, ";\n border-top: 1px solid rgba(255, 255, 255, 0.08)").concat(important, ";\n }\n\n .ttp-mobile-landing__powered {\n color: rgba(255, 255, 255, 0.4)").concat(important, ";\n font-size: 11px").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 4px").concat(important, ";\n }\n\n .ttp-mobile-landing__powered svg {\n width: 10px").concat(important, ";\n height: 10px").concat(important, ";\n color: #f59e0b").concat(important, ";\n }\n\n .ttp-mobile-landing__powered a {\n color: ").concat(footerLinkColor).concat(important, ";\n text-decoration: none").concat(important, ";\n }\n\n .ttp-mobile-landing__powered a:hover {\n opacity: 0.88").concat(important, ";\n }\n }\n ");
34023
+ return "\n /* Inline style display overrides - ensures JS show/hide works with !important CSS */\n #text-chat-panel [style*=\"display: none\"],\n #text-chat-panel [style*=\"display:none\"],\n #text-chat-button-container [style*=\"display: none\"],\n #text-chat-button-container [style*=\"display:none\"],\n #ttpMobileLanding[style*=\"display: none\"],\n #ttpMobileLanding[style*=\"display:none\"] {\n display: none !important;\n }\n #text-chat-panel [style*=\"display: flex\"],\n #text-chat-panel [style*=\"display:flex\"],\n #text-chat-button-container [style*=\"display: flex\"],\n #text-chat-button-container [style*=\"display:flex\"] {\n display: flex !important;\n }\n #text-chat-panel [style*=\"display: block\"],\n #text-chat-panel [style*=\"display:block\"] {\n display: block !important;\n }\n\n /* MOBILE FIRST - Default styles for all devices */\n #text-chat-widget {\n position: fixed !important;\n z-index: 10000".concat(important, ";\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif").concat(important, ";\n /* Mobile defaults */\n right: 10px").concat(important, ";\n bottom: 10px").concat(important, ";\n left: auto").concat(important, ";\n top: auto").concat(important, ";\n }\n \n /* Desktop positioning (only on larger screens) */\n @media (min-width: 769px) {\n #text-chat-widget {\n ").concat(positionStyles, "\n right: ").concat(this.config.position.horizontal === 'right' ? '20px' : 'auto').concat(important, ";\n left: ").concat(this.config.position.horizontal === 'left' ? '20px' : 'auto').concat(important, ";\n bottom: ").concat(this.config.position.vertical === 'bottom' ? '20px' : 'auto').concat(important, ";\n top: ").concat(this.config.position.vertical === 'top' ? '20px' : 'auto').concat(important, ";\n }\n }\n \n /* Mobile override (force mobile positioning) */\n @media (max-width: 768px) {\n #text-chat-widget {\n right: 10px !important;\n bottom: 10px !important;\n left: auto !important;\n top: auto !important;\n transform: none !important;\n }\n }\n \n @media (max-width: 480px) {\n #text-chat-widget {\n right: 8px !important;\n bottom: 8px !important;\n left: auto !important;\n top: auto !important;\n }\n }\n \n /* \u2500\u2500 Desktop Pill Launcher \u2500\u2500 */\n #text-chat-button {\n position: relative").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 8px").concat(important, ";\n padding-block: 10px").concat(important, ";\n padding-inline-start: 6px").concat(important, ";\n padding-inline-end: 12px").concat(important, ";\n z-index: 1").concat(important, ";\n background: ").concat(pillGradient, ";\n border: 1px solid rgba(139,92,246,0.15)").concat(important, ";\n border-radius: 999px").concat(important, ";\n box-shadow: 0 8px 32px rgba(0,0,0,0.25), 0 2px 8px rgba(0,0,0,0.15)").concat(important, ";\n cursor: pointer").concat(important, ";\n transition: box-shadow 0.25s, transform 0.2s, padding 0.3s, gap 0.3s").concat(important, ";\n font-family: inherit").concat(important, ";\n color: ").concat(pillTextColor, ";\n overflow: hidden").concat(important, ";\n box-sizing: border-box").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n #text-chat-button:hover {\n transform: translateY(-1px)").concat(important, ";\n box-shadow: 0 10px 40px rgba(0,0,0,0.35), 0 4px 12px rgba(0,0,0,0.2)").concat(important, ";\n }\n #text-chat-button.open {\n gap: 0px").concat(important, ";\n padding: 9px").concat(important, ";\n width: auto").concat(important, ";\n min-width: 0").concat(important, ";\n max-width: none").concat(important, ";\n }\n\n @media (min-width: 769px) {\n #text-chat-button {\n width: 158px").concat(important, ";\n min-width: 158px").concat(important, ";\n max-width: 158px").concat(important, ";\n }\n }\n\n .ttp-pill-icon {\n width: 36px").concat(important, "; height: 36px").concat(important, "; border-radius: 50%").concat(important, ";\n background: #ffffff").concat(important, ";\n display: flex").concat(important, "; align-items: center").concat(important, "; justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n .ttp-launcher-logo {\n width: 22px").concat(important, "; height: 22px").concat(important, "; border-radius: 50%").concat(important, ";\n object-fit: cover").concat(important, ";\n }\n\n /* Default pill launcher: same animated waveform as mobile FAB / landing */\n .ttp-pill-icon--wave {\n background: rgba(255, 255, 255, 0.15)").concat(important, ";\n }\n .ttp-pill-waveform {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 2px").concat(important, ";\n height: 16px").concat(important, ";\n }\n .ttp-pill-waveform .bar {\n width: 2px").concat(important, ";\n background: #fff").concat(important, ";\n border-radius: 1px").concat(important, ";\n animation: ttpWaveAnimation 0.8s ease-in-out infinite").concat(important, ";\n }\n .ttp-pill-waveform .bar:nth-child(1) { height: 5px").concat(important, "; animation-delay: 0s").concat(important, "; }\n .ttp-pill-waveform .bar:nth-child(2) { height: 10px").concat(important, "; animation-delay: 0.1s").concat(important, "; }\n .ttp-pill-waveform .bar:nth-child(3) { height: 16px").concat(important, "; animation-delay: 0.2s").concat(important, "; }\n .ttp-pill-waveform .bar:nth-child(4) { height: 8px").concat(important, "; animation-delay: 0.3s").concat(important, "; }\n .ttp-pill-waveform .bar:nth-child(5) { height: 12px").concat(important, "; animation-delay: 0.4s").concat(important, "; }\n\n .ttp-pill-text {\n display: flex").concat(important, "; flex-direction: column").concat(important, "; gap: 2px").concat(important, ";\n max-width: 82px").concat(important, ";\n opacity: 1").concat(important, ";\n overflow: hidden").concat(important, ";\n white-space: nowrap").concat(important, ";\n transition: max-width 0.3s, opacity 0.2s").concat(important, ";\n }\n #text-chat-button.open .ttp-pill-text {\n max-width: 0").concat(important, ";\n opacity: 0").concat(important, ";\n }\n .ttp-pill-title {\n font-size: 13px").concat(important, "; font-weight: 600").concat(important, "; color: ").concat(pillTextColor, ";\n line-height: 1.25").concat(important, ";\n overflow: hidden").concat(important, ";\n text-overflow: ellipsis").concat(important, ";\n }\n .ttp-pill-status {\n display: flex").concat(important, "; align-items: center").concat(important, "; gap: 4px").concat(important, ";\n font-size: 11px").concat(important, "; color: ").concat(pillTextColor, "8c;\n line-height: 1.25").concat(important, ";\n }\n\n /* Online dot (inside pill status) */\n .ttp-launcher-dot {\n width: 7px").concat(important, "; height: 7px").concat(important, "; border-radius: 50%").concat(important, ";\n background: ").concat(pillDotColor, ";\n flex-shrink: 0").concat(important, ";\n animation: ttp-dot-pulse 2s ease-in-out infinite").concat(important, ";\n }\n @keyframes ttp-dot-pulse { 0%,100%{opacity:1} 50%{opacity:.4} }\n \n @media (max-width: 768px) {\n #text-chat-widget {\n right: 10px !important;\n bottom: 10px !important;\n left: auto !important;\n top: auto !important;\n transform: none !important;\n }\n \n #text-chat-button-container {\n width: auto !important;\n height: auto !important;\n }\n \n #text-chat-panel {\n position: fixed !important;\n right: 10px !important;\n left: auto !important;\n bottom: 92px !important; /* 56px button + 20px gap + 16px footer */\n top: auto !important;\n width: 340px !important;\n max-width: calc(100vw - 20px) !important;\n height: auto !important;\n max-height: calc(100vh - 130px) !important;\n transform: none !important;\n margin: 0 !important;\n }\n \n #text-chat-panel .widget-header {\n padding: 10px 14px").concat(important, ";\n min-height: 56px").concat(important, ";\n }\n \n #text-chat-panel .header-title {\n font-size: 15px").concat(important, ";\n }\n \n #text-chat-panel .header-icon {\n width: 40px").concat(important, ";\n height: 40px").concat(important, ";\n min-width: 40px").concat(important, ";\n min-height: 40px").concat(important, ";\n }\n \n #text-chat-input {\n font-size: 16px !important; /* Prevents iOS zoom on focus */\n padding: 12px 16px !important;\n min-height: 48px !important;\n }\n \n #text-chat-send {\n min-width: 48px !important;\n min-height: 48px !important;\n width: 48px !important;\n height: 48px !important;\n }\n \n }\n \n @media (max-width: 480px) {\n #text-chat-widget {\n right: 8px !important;\n bottom: 8px !important;\n left: auto !important;\n top: auto !important;\n }\n \n #text-chat-button-container {\n width: auto !important;\n height: auto !important;\n }\n \n #text-chat-panel {\n right: 8px !important;\n left: auto !important;\n bottom: 86px !important; /* 54px button + 20px gap + 12px footer */\n top: auto !important;\n width: 340px !important;\n max-width: calc(100vw - 16px) !important;\n height: auto !important;\n max-height: calc(100vh - 120px) !important;\n }\n \n #text-chat-panel .widget-header {\n padding: 8px 12px").concat(important, ";\n min-height: 52px").concat(important, ";\n }\n \n #text-chat-panel .header-title {\n font-size: 14px").concat(important, ";\n }\n \n }\n \n ").concat(anim.enableHover ? "\n #text-chat-button:hover {\n transform: translateY(-1px);\n }\n " : '', "\n \n /* Prompt Animation Keyframes */\n @keyframes widget-shimmer {\n 0% { transform: translateX(-100%); }\n 100% { transform: translateX(200%); }\n }\n \n @keyframes widget-ripple {\n 0% { transform: scale(1); opacity: 0.6; }\n 100% { transform: scale(2.5); opacity: 0; }\n }\n \n @keyframes widget-float {\n 0%, 100% { transform: translateX(-50%) translateY(0); }\n 50% { transform: translateX(-50%) translateY(-8px); }\n }\n \n @keyframes widget-bounce {\n 0%, 100% { transform: translateX(-50%) translateY(0); }\n 50% { transform: translateX(-50%) translateY(-10px); }\n }\n \n @keyframes widget-pulse-ring {\n 0% { transform: scale(1); opacity: 0.4; }\n 100% { transform: scale(1.8); opacity: 0; }\n }\n \n /* Prompt Bubble Container */\n #text-chat-button-container {\n position: fixed").concat(important, ";\n ").concat(this.config.position.vertical === 'bottom' ? "bottom: ".concat(((_this$config$position = this.config.position.offset) === null || _this$config$position === void 0 ? void 0 : _this$config$position.y) || 20, "px;") : "top: ".concat(((_this$config$position2 = this.config.position.offset) === null || _this$config$position2 === void 0 ? void 0 : _this$config$position2.y) || 20, "px;"), "\n ").concat(this.config.position.horizontal === 'right' ? "right: ".concat(((_this$config$position3 = this.config.position.offset) === null || _this$config$position3 === void 0 ? void 0 : _this$config$position3.x) || 20, "px;") : "left: ".concat(((_this$config$position4 = this.config.position.offset) === null || _this$config$position4 === void 0 ? void 0 : _this$config$position4.x) || 20, "px;"), "\n width: auto").concat(important, ";\n height: auto").concat(important, ";\n z-index: 10001").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n }\n \n @media (max-width: 768px) {\n #text-chat-button-container {\n right: 10px !important;\n bottom: 10px !important;\n left: auto !important;\n top: auto !important;\n }\n }\n \n @media (max-width: 480px) {\n #text-chat-button-container {\n right: 8px !important;\n bottom: 8px !important;\n left: auto !important;\n top: auto !important;\n }\n }\n \n /* Prompt Bubble Styles */\n .prompt-bubble {\n position: absolute").concat(important, ";\n z-index: 10002").concat(important, ";\n pointer-events: none").concat(important, ";\n white-space: nowrap").concat(important, ";\n }\n \n .prompt-bubble.top {\n bottom: calc(100% + 18px)").concat(important, ";\n left: 50%").concat(important, ";\n transform: translateX(-50%)").concat(important, ";\n }\n \n .prompt-bubble.left {\n right: calc(100% + 12px)").concat(important, ";\n top: 50%").concat(important, ";\n transform: translateY(-50%)").concat(important, ";\n }\n \n .prompt-bubble.right {\n left: calc(100% + 12px)").concat(important, ";\n top: 50%").concat(important, ";\n transform: translateY(-50%)").concat(important, ";\n }\n \n /* Ensure animations preserve horizontal centering for top position */\n .prompt-bubble.top.animation-bounce {\n animation: widget-bounce 1s ease-in-out infinite").concat(important, ";\n transform: translateX(-50%)").concat(important, "; /* Keep centering */\n }\n \n .prompt-bubble.top.animation-float {\n animation: widget-float 2s ease-in-out infinite").concat(important, ";\n transform: translateX(-50%)").concat(important, "; /* Keep centering */\n }\n \n .prompt-bubble.top.animation-pulse {\n animation: pulse 2s ease-in-out infinite").concat(important, ";\n transform: translateX(-50%)").concat(important, "; /* Keep centering */\n }\n \n .prompt-bubble-content {\n position: relative").concat(important, ";\n padding: 8px 16px").concat(important, ";\n border-radius: 20px").concat(important, ";\n font-weight: 500").concat(important, ";\n font-size: 14px").concat(important, ";\n box-shadow: 0 4px 15px rgba(124, 58, 237, 0.3)").concat(important, ";\n overflow: hidden").concat(important, ";\n }\n \n .prompt-bubble-shimmer {\n position: absolute").concat(important, ";\n inset: 0").concat(important, ";\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.25), transparent)").concat(important, ";\n animation: widget-shimmer 2s infinite").concat(important, ";\n }\n \n .prompt-bubble.animation-bounce {\n animation: widget-bounce 1s ease-in-out infinite").concat(important, ";\n }\n \n .prompt-bubble.animation-pulse {\n animation: pulse 2s ease-in-out infinite").concat(important, ";\n }\n \n .prompt-bubble.animation-float {\n animation: widget-float 2s ease-in-out infinite").concat(important, ";\n }\n \n /* Ensure top-positioned bubbles maintain horizontal centering during animations */\n .prompt-bubble.top.animation-bounce,\n .prompt-bubble.top.animation-float,\n .prompt-bubble.top.animation-pulse {\n /* Animation keyframes already include translateX(-50%) for centering */\n }\n \n /* Prompt Bubble Arrow */\n .prompt-bubble-arrow {\n position: absolute").concat(important, ";\n width: 0").concat(important, ";\n height: 0").concat(important, ";\n border: 8px solid transparent").concat(important, ";\n }\n \n .prompt-bubble.top .prompt-bubble-arrow {\n top: 100%").concat(important, ";\n left: 50%").concat(important, ";\n transform: translateX(-50%)").concat(important, ";\n border-top-color: var(--prompt-bubble-bg-color, #7c3aed)").concat(important, ";\n border-bottom: none").concat(important, ";\n margin-left: 0").concat(important, ";\n }\n \n .prompt-bubble.left .prompt-bubble-arrow {\n left: 100%").concat(important, ";\n top: 50%").concat(important, ";\n transform: translateY(-50%)").concat(important, ";\n border-left-color: var(--prompt-bubble-bg-color, #7c3aed)").concat(important, ";\n border-right: none").concat(important, ";\n }\n \n .prompt-bubble.right .prompt-bubble-arrow {\n right: 100%").concat(important, ";\n top: 50%").concat(important, ";\n transform: translateY(-50%)").concat(important, ";\n border-right-color: var(--prompt-bubble-bg-color, #7c3aed)").concat(important, ";\n border-left: none").concat(important, ";\n }\n \n /* Pulse Rings */\n .prompt-pulse-rings {\n position: absolute").concat(important, ";\n inset: 0").concat(important, ";\n border-radius: 50%").concat(important, ";\n pointer-events: none").concat(important, ";\n }\n \n .prompt-pulse-ring {\n position: absolute").concat(important, ";\n inset: 0").concat(important, ";\n border-radius: 50%").concat(important, ";\n animation: widget-pulse-ring 2s ease-out infinite").concat(important, ";\n }\n \n .prompt-pulse-ring:nth-child(2) {\n animation-delay: 0.5s").concat(important, ";\n }\n \n /* Mobile adjustments for prompt bubble */\n @media (max-width: 768px) {\n .prompt-bubble-content {\n font-size: 12px").concat(important, ";\n padding: 6px 12px").concat(important, ";\n }\n \n .prompt-bubble.top {\n bottom: calc(100% + 14px)").concat(important, ";\n }\n \n .prompt-bubble.left,\n .prompt-bubble.right {\n display: none").concat(important, "; /* Hide side prompts on mobile */\n }\n }\n \n /* Shared panel chrome; size/position differ \u2014 desktop card vs mobile sheet (see @media blocks earlier) */\n #text-chat-panel {\n display: none").concat(important, ";\n position: fixed").concat(important, ";\n background: ").concat(panelBg, ";\n border-radius: 20px").concat(important, ";\n border: ").concat(panel.border || '1px solid rgba(255,255,255,0.08)', ";\n flex-direction: column").concat(important, ";\n overflow: hidden").concat(important, ";\n box-shadow: 0 24px 60px rgba(0,0,0,0.6)").concat(important, ";\n opacity: 0").concat(important, ";\n pointer-events: none").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n\n /* Desktop / tablet: floating 340px card anchored to launcher */\n @media (min-width: 769px) {\n #text-chat-panel {\n bottom: calc(54px + 24px)").concat(important, "; /* launcher pill + gap */\n ").concat(this.config.position.horizontal === 'right' ? 'right: 20px;' : 'left: 20px;', "\n width: 340px").concat(important, ";\n max-width: calc(100vw - 40px)").concat(important, ";\n height: auto").concat(important, ";\n max-height: calc(100vh - 100px)").concat(important, ";\n transform-origin: bottom right").concat(important, ";\n }\n /* Text chat: fixed height so the message list scrolls instead of growing the panel per message */\n #text-chat-panel:has(.text-interface.active) {\n height: min(520px, calc(100vh - 100px))").concat(important, ";\n }\n }\n \n #text-chat-panel.open {\n display: flex").concat(important, ";\n opacity: 1").concat(important, ";\n pointer-events: auto").concat(important, ";\n }\n\n /* Shell for panel inner */\n .widget-shell { width: 100%").concat(important, "; padding: 0").concat(important, "; border-radius: 20px").concat(important, "; background: transparent").concat(important, "; overflow: hidden").concat(important, "; display: flex").concat(important, "; flex-direction: column").concat(important, "; box-sizing: border-box").concat(important, "; flex: 1").concat(important, "; min-height: 0").concat(important, "; }\n .panel-inner { width: 100%").concat(important, "; background: ").concat(panelBg, "; border-radius: 20px").concat(important, "; border: none").concat(important, "; overflow: hidden").concat(important, "; display:flex").concat(important, "; flex-direction: column").concat(important, "; padding: 0").concat(important, "; box-sizing: border-box").concat(important, "; max-width: 100%").concat(important, "; flex: 1").concat(important, "; min-height: 0").concat(important, "; }\n\n #text-chat-panel .widget-container {\n width: 100%").concat(important, "; background: ").concat(panelBg, "; overflow: visible").concat(important, "; display: flex").concat(important, "; flex-direction: column").concat(important, "; border-radius: 20px").concat(important, "; flex: 1").concat(important, "; min-height: 0").concat(important, ";\n }\n\n /* Voice idle: one gradient for voice UI + footer (Powered by), not a flat strip under buttons */\n #text-chat-panel.open:has(").concat(voiceIdleVisibleSelector, ") {\n background: linear-gradient(160deg, ").concat(idleHeroGrad1, " 0%, ").concat(idleHeroGrad2, " 100%)").concat(important, ";\n }\n #text-chat-panel .widget-container:has(").concat(voiceIdleVisibleSelector, ") {\n background: linear-gradient(160deg, ").concat(idleHeroGrad1, " 0%, ").concat(idleHeroGrad2, " 100%)").concat(important, ";\n }\n\n /* Voice active call: same hero gradient as idle + mobile minimized bar */\n #text-chat-panel.open:has(").concat(voiceActiveVisibleSelector, ") {\n background: ").concat(callActivePanelBg).concat(important, ";\n }\n #text-chat-panel .widget-container:has(").concat(voiceActiveVisibleSelector, ") {\n background: ").concat(callActivePanelBg).concat(important, ";\n }\n #text-chat-panel.open:has(").concat(voiceActiveVisibleSelector, ") .widget-shell {\n background: ").concat(callActivePanelBg).concat(important, ";\n }\n #text-chat-panel.open:has(").concat(voiceActiveVisibleSelector, ") .panel-inner {\n background: ").concat(callActivePanelBg).concat(important, ";\n }\n #text-chat-panel.open:has(").concat(voiceActiveVisibleSelector, ") .ttp-footer {\n background: ").concat(callActivePanelBg).concat(important, ";\n }\n\n ").concat(textUsesVoiceTheme ? "\n /* Text chat with voice theme: same hero surface as voice idle; inner shells transparent */\n #text-chat-panel.open:has(.text-interface.active) {\n background: ".concat(callSurfaceGradient).concat(important, ";\n }\n #text-chat-panel.open:has(.text-interface.active) .widget-shell,\n #text-chat-panel.open:has(.text-interface.active) .panel-inner,\n #text-chat-panel.open:has(.text-interface.active) .widget-container {\n background: transparent").concat(important, ";\n }\n #text-chat-panel.open:has(.text-interface.active) .ttp-footer {\n background: transparent").concat(important, ";\n border-top-color: rgba(255,255,255,0.06)").concat(important, ";\n }\n #text-chat-panel.open:has(.text-interface.active) .ttp-footer span {\n color: rgba(255,255,255,0.35)").concat(important, ";\n }\n #text-chat-panel.open:has(.text-interface.active) .ttp-footer a {\n color: ").concat(footerLinkOnDarkHero).concat(important, ";\n }\n ") : '', "\n \n /* Voice may scroll as a whole; text chat keeps a fixed shell and scrolls #messagesContainer only */\n #text-chat-panel .widget-container > .voice-interface {\n flex: 1").concat(important, ";\n min-height: 0").concat(important, ";\n overflow-y: auto").concat(important, ";\n overflow-x: visible").concat(important, ";\n }\n #text-chat-panel .widget-container > .text-interface {\n flex: 1").concat(important, ";\n min-height: 0").concat(important, ";\n overflow: hidden").concat(important, ";\n overflow-x: visible").concat(important, ";\n }\n \n /* Header is removed in new design - hero serves as header */\n #text-chat-panel .widget-header { display: none").concat(important, "; }\n\n ").concat(showVoice ? this.voiceInterface.generateCSS() : '', "\n ").concat(showText ? this.textInterface.generateCSS() : '', "\n \n /* Footer Branding */\n .ttp-footer {\n padding: 6px 18px 10px").concat(important, ";\n border-top: 1px solid ").concat(footerBorderColor, ";\n display: flex").concat(important, ";\n justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n box-sizing: border-box").concat(important, ";\n background: transparent").concat(important, ";\n }\n .ttp-footer span { font-size: 10px").concat(important, "; color: ").concat(footerTextColor, "; }\n .ttp-footer a { color: ").concat(footerLinkColor, "; text-decoration: none").concat(important, "; font-weight: 600").concat(important, "; }\n .ttp-footer a:hover { opacity: 0.85").concat(important, "; }\n .ttp-footer a b { font-weight: 700").concat(important, "; }\n \n #text-chat-send-hint {\n text-align: center").concat(important, ";\n line-height: 1.4").concat(important, ";\n }\n \n .agent-thinking {\n font-style: italic").concat(important, ";\n color: #6B7280").concat(important, ";\n }\n\n /* ========================================\n MOBILE PILL BUTTON & LANDING OVERLAY\n Hidden on desktop, shown on mobile only\n ======================================== */\n .ttp-mobile-fab {\n display: none").concat(important, ";\n }\n\n .ttp-mobile-landing {\n display: none").concat(important, ";\n }\n\n @keyframes ttpWaveAnimation {\n 0%, 100% { transform: scaleY(0.4); }\n 50% { transform: scaleY(1); }\n }\n\n @keyframes ttpPulseAnimation {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n\n @media (max-width: 768px) {\n /* Hide desktop pill button on mobile */\n #text-chat-button {\n display: none !important;\n }\n\n /* Re-flow the container for pill shape */\n #text-chat-button-container {\n width: auto !important;\n height: auto !important;\n min-width: 0 !important;\n min-height: 0 !important;\n max-width: none !important;\n max-height: none !important;\n }\n\n /* Show mobile pill button */\n .ttp-mobile-fab {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 10px").concat(important, ";\n padding: 10px 16px 10px 12px").concat(important, ";\n background: ").concat(pillGradient, ";\n border: none").concat(important, ";\n border-radius: 24px").concat(important, ";\n cursor: pointer").concat(important, ";\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3)").concat(important, ";\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1)").concat(important, ";\n z-index: 1").concat(important, ";\n font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif").concat(important, ";\n touch-action: manipulation").concat(important, ";\n -webkit-tap-highlight-color: transparent").concat(important, ";\n }\n\n .ttp-mobile-fab:hover {\n transform: translateY(-3px)").concat(important, ";\n box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4)").concat(important, ";\n }\n\n .ttp-mobile-fab__icon-wrap {\n width: 36px").concat(important, ";\n height: 36px").concat(important, ";\n border-radius: 50%").concat(important, ";\n background: rgba(255, 255, 255, 0.15)").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n\n .ttp-mobile-fab__waveform {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 2px").concat(important, ";\n height: 16px").concat(important, ";\n }\n\n .ttp-mobile-fab__waveform .bar {\n width: 2px").concat(important, ";\n background: #fff").concat(important, ";\n border-radius: 1px").concat(important, ";\n animation: ttpWaveAnimation 0.8s ease-in-out infinite").concat(important, ";\n }\n\n .ttp-mobile-fab__waveform .bar:nth-child(1) { height: 5px").concat(important, "; animation-delay: 0s").concat(important, "; }\n .ttp-mobile-fab__waveform .bar:nth-child(2) { height: 10px").concat(important, "; animation-delay: 0.1s").concat(important, "; }\n .ttp-mobile-fab__waveform .bar:nth-child(3) { height: 16px").concat(important, "; animation-delay: 0.2s").concat(important, "; }\n .ttp-mobile-fab__waveform .bar:nth-child(4) { height: 8px").concat(important, "; animation-delay: 0.3s").concat(important, "; }\n .ttp-mobile-fab__waveform .bar:nth-child(5) { height: 12px").concat(important, "; animation-delay: 0.4s").concat(important, "; }\n\n .ttp-mobile-fab__label-wrap {\n display: flex").concat(important, ";\n flex-direction: column").concat(important, ";\n align-items: flex-start").concat(important, ";\n gap: 1px").concat(important, ";\n }\n\n .ttp-mobile-fab__label {\n color: ").concat(pillTextColor, ";\n font-size: 14px").concat(important, ";\n font-weight: 600").concat(important, ";\n line-height: 1.2").concat(important, ";\n }\n\n .ttp-mobile-fab__status {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 4px").concat(important, ";\n font-size: 11px").concat(important, ";\n color: ").concat(pillTextColor, "b3;\n line-height: 1.2").concat(important, ";\n }\n\n .ttp-mobile-fab__dot {\n width: 6px").concat(important, ";\n height: 6px").concat(important, ";\n background: ").concat(pillDotColor, ";\n border-radius: 50%").concat(important, ";\n box-shadow: 0 0 6px ").concat(pillDotColor, "99;\n }\n\n /* ---- Mobile Landing Overlay ---- */\n .ttp-mobile-landing.active {\n display: block").concat(important, ";\n position: fixed").concat(important, ";\n bottom: 16px").concat(important, ";\n left: 12px").concat(important, ";\n right: 12px").concat(important, ";\n background: ").concat(pillGradient, ";\n border-radius: 20px").concat(important, ";\n overflow: hidden").concat(important, ";\n box-shadow:\n 0 10px 40px rgba(0, 0, 0, 0.3),\n 0 0 0 1px rgba(255, 255, 255, 0.1) inset").concat(important, ";\n z-index: 10002").concat(important, ";\n font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif").concat(important, ";\n }\n\n .ttp-mobile-landing::before {\n content: ''").concat(important, ";\n position: absolute").concat(important, ";\n top: 0").concat(important, ";\n left: 0").concat(important, ";\n right: 0").concat(important, ";\n height: 1px").concat(important, ";\n background: linear-gradient(90deg,\n transparent 0%,\n rgba(255, 255, 255, 0.3) 50%,\n transparent 100%);\n }\n\n .ttp-mobile-landing__header {\n padding: 14px 16px").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 12px").concat(important, ";\n }\n\n .ttp-mobile-landing__avatar {\n width: 44px").concat(important, ";\n height: 44px").concat(important, ";\n border-radius: 12px").concat(important, ";\n background: rgba(255, 255, 255, 0.15)").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n\n .ttp-mobile-landing__waveform {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 3px").concat(important, ";\n height: 20px").concat(important, ";\n }\n\n .ttp-mobile-landing__waveform .bar {\n width: 3px").concat(important, ";\n background: rgba(255, 255, 255, 0.9)").concat(important, ";\n border-radius: 2px").concat(important, ";\n animation: ttpWaveAnimation 0.8s ease-in-out infinite").concat(important, ";\n }\n\n .ttp-mobile-landing__waveform .bar:nth-child(1) { height: 6px").concat(important, "; animation-delay: 0s").concat(important, "; }\n .ttp-mobile-landing__waveform .bar:nth-child(2) { height: 12px").concat(important, "; animation-delay: 0.1s").concat(important, "; }\n .ttp-mobile-landing__waveform .bar:nth-child(3) { height: 20px").concat(important, "; animation-delay: 0.2s").concat(important, "; }\n .ttp-mobile-landing__waveform .bar:nth-child(4) { height: 10px").concat(important, "; animation-delay: 0.3s").concat(important, "; }\n .ttp-mobile-landing__waveform .bar:nth-child(5) { height: 16px").concat(important, "; animation-delay: 0.4s").concat(important, "; }\n\n .ttp-mobile-landing__info {\n flex: 1").concat(important, ";\n min-width: 0").concat(important, ";\n }\n\n .ttp-mobile-landing__name {\n color: #fff").concat(important, ";\n font-size: 15px").concat(important, ";\n font-weight: 600").concat(important, ";\n margin-bottom: 2px").concat(important, ";\n }\n\n .ttp-mobile-landing__status {\n color: rgba(255, 255, 255, 0.7)").concat(important, ";\n font-size: 12px").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 5px").concat(important, ";\n }\n\n .ttp-mobile-landing__dot {\n width: 6px").concat(important, ";\n height: 6px").concat(important, ";\n background: ").concat(header.onlineIndicatorDotColor || '#10b981', ";\n border-radius: 50%").concat(important, ";\n animation: ttpPulseAnimation 2s ease-in-out infinite").concat(important, ";\n }\n\n .ttp-mobile-landing__close {\n width: 32px").concat(important, ";\n height: 32px").concat(important, ";\n border-radius: 10px").concat(important, ";\n background: rgba(255, 255, 255, 0.1)").concat(important, ";\n border: none").concat(important, ";\n color: rgba(255, 255, 255, 0.7)").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n cursor: pointer").concat(important, ";\n transition: all 0.2s").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n\n .ttp-mobile-landing__close:hover {\n background: rgba(255, 255, 255, 0.2)").concat(important, ";\n color: #fff").concat(important, ";\n }\n\n .ttp-mobile-landing__error {\n margin: 0 14px 10px").concat(important, ";\n padding: 10px 12px").concat(important, ";\n background: #fef2f2").concat(important, ";\n border: 1px solid #fecaca").concat(important, ";\n border-radius: 10px").concat(important, ";\n display: flex").concat(important, ";\n align-items: flex-start").concat(important, ";\n gap: 8px").concat(important, ";\n color: #b91c1c").concat(important, ";\n font-size: 13px").concat(important, ";\n line-height: 1.4").concat(important, ";\n }\n .ttp-mobile-landing__error svg {\n flex-shrink: 0").concat(important, ";\n margin-top: 1px").concat(important, ";\n stroke: #dc2626").concat(important, ";\n }\n\n .ttp-mobile-landing__actions {\n padding: 0 14px 14px").concat(important, ";\n display: flex").concat(important, ";\n gap: 10px").concat(important, ";\n }\n\n .ttp-mobile-landing__btn {\n flex: 1").concat(important, ";\n padding: 14px").concat(important, ";\n border-radius: 12px").concat(important, ";\n border: none").concat(important, ";\n cursor: pointer").concat(important, ";\n font-family: inherit").concat(important, ";\n font-size: 14px").concat(important, ";\n font-weight: 600").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n gap: 10px").concat(important, ";\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1)").concat(important, ";\n touch-action: manipulation").concat(important, ";\n -webkit-tap-highlight-color: transparent").concat(important, ";\n }\n\n .ttp-mobile-landing__btn svg {\n width: 20px").concat(important, ";\n height: 20px").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n\n .ttp-mobile-landing__btn--call {\n background: #fff").concat(important, ";\n color: ").concat(header.backgroundColor || '#7C3AED', ";\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15)").concat(important, ";\n }\n\n .ttp-mobile-landing__btn--call:hover {\n transform: translateY(-2px)").concat(important, ";\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2)").concat(important, ";\n }\n\n .ttp-mobile-landing__btn--text {\n background: rgba(255, 255, 255, 0.15)").concat(important, ";\n color: #fff").concat(important, ";\n border: 1px solid rgba(255, 255, 255, 0.1)").concat(important, ";\n }\n\n .ttp-mobile-landing__btn--text:hover {\n background: rgba(255, 255, 255, 0.2)").concat(important, ";\n border-color: rgba(255, 255, 255, 0.2)").concat(important, ";\n }\n\n .ttp-mobile-landing__footer {\n padding: 10px 16px").concat(important, ";\n display: flex").concat(important, ";\n justify-content: center").concat(important, ";\n border-top: 1px solid rgba(255, 255, 255, 0.08)").concat(important, ";\n }\n\n .ttp-mobile-landing__powered {\n color: rgba(255, 255, 255, 0.4)").concat(important, ";\n font-size: 11px").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 4px").concat(important, ";\n }\n\n .ttp-mobile-landing__powered svg {\n width: 10px").concat(important, ";\n height: 10px").concat(important, ";\n color: #f59e0b").concat(important, ";\n }\n\n .ttp-mobile-landing__powered a {\n color: ").concat(footerLinkColor).concat(important, ";\n text-decoration: none").concat(important, ";\n }\n\n .ttp-mobile-landing__powered a:hover {\n opacity: 0.88").concat(important, ";\n }\n }\n\n /* ========================================\n \"About\" info (\"i\") button + dialog\n ======================================== */\n .ttp-header-actions {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 4px").concat(important, ";\n }\n .ttp-info-btn {\n background: none").concat(important, ";\n border: none").concat(important, ";\n cursor: pointer").concat(important, ";\n color: currentColor").concat(important, ";\n opacity: 0.7").concat(important, ";\n padding: 4px").concat(important, ";\n margin: 0").concat(important, ";\n display: inline-flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n border-radius: 50%").concat(important, ";\n line-height: 0").concat(important, ";\n transition: opacity 0.2s, background 0.2s").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n .ttp-info-btn:hover {\n opacity: 1").concat(important, ";\n background: rgba(127,127,127,0.18)").concat(important, ";\n }\n .ttp-info-btn svg { display: block").concat(important, "; }\n /* Floating variant for views without a header row (mobile idle) */\n .ttp-info-btn--floating {\n position: absolute").concat(important, ";\n top: 10px").concat(important, ";\n inset-inline-end: 10px").concat(important, ";\n z-index: 5").concat(important, ";\n }\n .ttp-info-btn--onbadge {\n width: 22px").concat(important, ";\n height: 22px").concat(important, ";\n padding: 3px").concat(important, ";\n }\n .ttp-info-btn--onbadge svg { width: 13px").concat(important, "; height: 13px").concat(important, "; }\n ");
33465
34024
  }
33466
34025
  }, {
33467
34026
  key: "setupWidgetEvents",
33468
34027
  value: function setupWidgetEvents() {
33469
- var _this8 = this,
33470
- _this$config$behavior8;
34028
+ var _this9 = this,
34029
+ _this$config$behavior8,
34030
+ _this$config$position5;
33471
34031
  if (!this.shadowRoot) return;
33472
34032
 
33473
34033
  // Setup prompt animation visibility and interactions
@@ -33478,16 +34038,18 @@ var TTPChatWidget = /*#__PURE__*/function () {
33478
34038
  if (launcherBtn) {
33479
34039
  launcherBtn.onclick = function (e) {
33480
34040
  e.stopPropagation();
33481
- if (_this8.config.promptAnimation.hideAfterClick) {
33482
- _this8.hidePrompt();
34041
+ // A drag just ended — don't treat the trailing click as "open panel".
34042
+ if (_this9._suppressLauncherClick) return;
34043
+ if (_this9.config.promptAnimation.hideAfterClick) {
34044
+ _this9.hidePrompt();
33483
34045
  }
33484
- _this8.togglePanel();
34046
+ _this9.togglePanel();
33485
34047
  };
33486
34048
  }
33487
34049
  var closeBtn = this.shadowRoot.getElementById('closeBtn');
33488
34050
  if (closeBtn) {
33489
34051
  closeBtn.onclick = function () {
33490
- _this8._doTogglePanel();
34052
+ _this9._doTogglePanel();
33491
34053
  };
33492
34054
  }
33493
34055
 
@@ -33495,31 +34057,41 @@ var TTPChatWidget = /*#__PURE__*/function () {
33495
34057
  var closeIdle = this.shadowRoot.getElementById('ttpCloseIdle');
33496
34058
  if (closeIdle) {
33497
34059
  closeIdle.onclick = function () {
33498
- return _this8._doTogglePanel();
34060
+ return _this9._doTogglePanel();
33499
34061
  };
33500
34062
  }
33501
34063
  var closeActive = this.shadowRoot.getElementById('ttpCloseActive');
33502
34064
  if (closeActive) {
33503
34065
  closeActive.onclick = function () {
33504
- return _this8._doTogglePanel();
34066
+ return _this9._doTogglePanel();
33505
34067
  };
33506
34068
  }
33507
34069
 
34070
+ // "About" info buttons (present in every view: idle / active / compact /
34071
+ // mobile idle / mobile active / text top-bar). One shared dialog.
34072
+ this.shadowRoot.querySelectorAll('.ttp-info-btn').forEach(function (btn) {
34073
+ btn.onclick = function (e) {
34074
+ e.stopPropagation();
34075
+ e.preventDefault();
34076
+ _this9._openAboutModal();
34077
+ };
34078
+ });
34079
+
33508
34080
  // "Send a Message" button in idle view → switch to text interface
33509
34081
  var startTextBtn = this.shadowRoot.getElementById('startTextBtn');
33510
34082
  if (startTextBtn) {
33511
34083
  startTextBtn.onclick = function () {
33512
- return _this8.showText();
34084
+ return _this9.showText();
33513
34085
  };
33514
34086
  }
33515
34087
  var textUnifiedBackBtn = this.shadowRoot.getElementById('textUnifiedBackBtn');
33516
34088
  if (textUnifiedBackBtn) {
33517
34089
  textUnifiedBackBtn.onclick = function () {
33518
- var _this8$config$behavio;
33519
- var widgetMode = ((_this8$config$behavio = _this8.config.behavior) === null || _this8$config$behavio === void 0 ? void 0 : _this8$config$behavio.mode) || 'unified';
34090
+ var _this9$config$behavio;
34091
+ var widgetMode = ((_this9$config$behavio = _this9.config.behavior) === null || _this9$config$behavio === void 0 ? void 0 : _this9$config$behavio.mode) || 'unified';
33520
34092
  if (widgetMode !== 'unified') return;
33521
- _this8.showLanding();
33522
- _this8._openMobileCallTextLanding();
34093
+ _this9.showLanding();
34094
+ _this9._openMobileCallTextLanding();
33523
34095
  };
33524
34096
  }
33525
34097
 
@@ -33549,30 +34121,30 @@ var TTPChatWidget = /*#__PURE__*/function () {
33549
34121
  // Setup back button handler
33550
34122
  if (backBtn) {
33551
34123
  backBtn.onclick = function () {
33552
- var _this8$voiceInterface, _this8$voiceInterface3;
34124
+ var _this9$voiceInterface, _this9$voiceInterface3;
33553
34125
  // Check if we're showing a domain error — clear it and return to voice hero
33554
- if ((_this8$voiceInterface = _this8.voiceInterface) !== null && _this8$voiceInterface !== void 0 && _this8$voiceInterface.isShowingDomainError) {
33555
- var _this8$voiceInterface2;
34126
+ if ((_this9$voiceInterface = _this9.voiceInterface) !== null && _this9$voiceInterface !== void 0 && _this9$voiceInterface.isShowingDomainError) {
34127
+ var _this9$voiceInterface2;
33556
34128
  console.log('🔙 Back button clicked - clearing domain error and returning to voice hero');
33557
34129
  // Clear the domain error flag
33558
- _this8.voiceInterface.isShowingDomainError = false;
34130
+ _this9.voiceInterface.isShowingDomainError = false;
33559
34131
  // Reset the connecting state (this will restore normal UI)
33560
- if ((_this8$voiceInterface2 = _this8.voiceInterface) !== null && _this8$voiceInterface2 !== void 0 && _this8$voiceInterface2.resetConnectingState) {
33561
- _this8.voiceInterface.resetConnectingState();
34132
+ if ((_this9$voiceInterface2 = _this9.voiceInterface) !== null && _this9$voiceInterface2 !== void 0 && _this9$voiceInterface2.resetConnectingState) {
34133
+ _this9.voiceInterface.resetConnectingState();
33562
34134
  }
33563
- _this8.showLanding();
33564
- _this8._openMobileCallTextLanding();
34135
+ _this9.showLanding();
34136
+ _this9._openMobileCallTextLanding();
33565
34137
  return;
33566
34138
  }
33567
- if ((_this8$voiceInterface3 = _this8.voiceInterface) !== null && _this8$voiceInterface3 !== void 0 && _this8$voiceInterface3.isActive) {
34139
+ if ((_this9$voiceInterface3 = _this9.voiceInterface) !== null && _this9$voiceInterface3 !== void 0 && _this9$voiceInterface3.isActive) {
33568
34140
  // If call is active, show message inside widget instead of modal
33569
- _this8.showBackButtonWarning();
34141
+ _this9.showBackButtonWarning();
33570
34142
  } else if (window.innerWidth <= 768) {
33571
- _this8.showLanding();
33572
- _this8._openMobileCallTextLanding();
34143
+ _this9.showLanding();
34144
+ _this9._openMobileCallTextLanding();
33573
34145
  } else {
33574
34146
  // Desktop: return to voice hero (unified home)
33575
- _this8.showLanding();
34147
+ _this9.showLanding();
33576
34148
  }
33577
34149
  };
33578
34150
  }
@@ -33615,7 +34187,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33615
34187
  // Setup header button handlers
33616
34188
  if (newChatBtn) {
33617
34189
  newChatBtn.onclick = function () {
33618
- return _this8.textInterface.startNewChat();
34190
+ return _this9.textInterface.startNewChat();
33619
34191
  };
33620
34192
  // Hide new chat on unified home (voice hero) initially
33621
34193
  if (isUnified && this.currentView !== 'text') {
@@ -33626,11 +34198,328 @@ var TTPChatWidget = /*#__PURE__*/function () {
33626
34198
  // Mobile floating button & landing overlay
33627
34199
  this.setupMobileWidgetEvents();
33628
34200
 
34201
+ // Optional: make the launcher pill / mobile FAB + the open panel draggable
34202
+ // (they move together as one unit). The minimized strip is wired separately
34203
+ // in _initEcommerceVoiceStrip() since it lives outside the shadow DOM.
34204
+ if ((_this$config$position5 = this.config.position) !== null && _this$config$position5 !== void 0 && _this$config$position5.draggable) {
34205
+ this.setupDraggableWidget();
34206
+ }
34207
+
33629
34208
  // Keyboard navigation
33630
34209
  if (this.config.accessibility.keyboardNavigation) {
33631
34210
  this.setupKeyboardNavigation();
33632
34211
  }
33633
34212
  }
34213
+
34214
+ /**
34215
+ * Page-scoped namespace for persisted drag positions (origin+path) so the same
34216
+ * widget on different routes keeps independent spots.
34217
+ */
34218
+ }, {
34219
+ key: "_dragScope",
34220
+ value: function _dragScope() {
34221
+ var scope = '';
34222
+ try {
34223
+ scope = window.location.origin + window.location.pathname;
34224
+ } catch (e) {/* sandboxed */}
34225
+ return scope;
34226
+ }
34227
+
34228
+ /** localStorage key for a dragged surface ('unit' = pill+panel, 'strip'). */
34229
+ }, {
34230
+ key: "_dragStorageKey",
34231
+ value: function _dragStorageKey(kind) {
34232
+ return 'ttp-widget-' + kind + '-pos::' + this._dragScope();
34233
+ }
34234
+
34235
+ /**
34236
+ * The launcher pill and the chat panel move together as one unit. They share a
34237
+ * single translate offset (`this._unitOffset`) so dragging either one (the pill,
34238
+ * the mobile FAB, or a panel header) moves both — they never split apart.
34239
+ */
34240
+ }, {
34241
+ key: "_unitEls",
34242
+ value: function _unitEls() {
34243
+ var root = this.shadowRoot;
34244
+ if (!root) return [];
34245
+ return [root.getElementById('text-chat-button-container'), root.getElementById('text-chat-panel')].filter(Boolean);
34246
+ }
34247
+
34248
+ /** Apply the shared unit offset as a translate transform to both elements. */
34249
+ }, {
34250
+ key: "_applyUnitOffset",
34251
+ value: function _applyUnitOffset() {
34252
+ var o = this._unitOffset || (this._unitOffset = {
34253
+ x: 0,
34254
+ y: 0
34255
+ });
34256
+ var value = "translate(".concat(o.x, "px, ").concat(o.y, "px)");
34257
+ this._unitEls().forEach(function (el) {
34258
+ return el.style.setProperty('transform', value, 'important');
34259
+ });
34260
+ }
34261
+
34262
+ /**
34263
+ * Base (offset-0) viewport rects of the currently-visible unit elements. The
34264
+ * applied transform equals `this._unitOffset`, so subtracting it recovers the
34265
+ * anchored position. Hidden elements (display:none → 0×0) are skipped.
34266
+ */
34267
+ }, {
34268
+ key: "_unitBaseRects",
34269
+ value: function _unitBaseRects() {
34270
+ var o = this._unitOffset || {
34271
+ x: 0,
34272
+ y: 0
34273
+ };
34274
+ var rects = [];
34275
+ this._unitEls().forEach(function (el) {
34276
+ var r = el.getBoundingClientRect();
34277
+ if (!r.width && !r.height) return; // hidden
34278
+ rects.push({
34279
+ left: r.left - o.x,
34280
+ top: r.top - o.y,
34281
+ right: r.right - o.x,
34282
+ bottom: r.bottom - o.y
34283
+ });
34284
+ });
34285
+ return rects;
34286
+ }
34287
+
34288
+ /**
34289
+ * Clamp a desired unit offset so every visible unit element stays within the
34290
+ * viewport (8px margin). Constraints from all visible elements are intersected.
34291
+ */
34292
+ }, {
34293
+ key: "_clampUnitOffset",
34294
+ value: function _clampUnitOffset(x, y, bases) {
34295
+ var margin = 8;
34296
+ var vw = window.innerWidth,
34297
+ vh = window.innerHeight;
34298
+ var minX = -Infinity,
34299
+ maxX = Infinity,
34300
+ minY = -Infinity,
34301
+ maxY = Infinity;
34302
+ bases.forEach(function (b) {
34303
+ minX = Math.max(minX, margin - b.left);
34304
+ maxX = Math.min(maxX, vw - margin - b.right);
34305
+ minY = Math.max(minY, margin - b.top);
34306
+ maxY = Math.min(maxY, vh - margin - b.bottom);
34307
+ });
34308
+ // Element taller/wider than the viewport → keep its top/left edge visible.
34309
+ if (minX > maxX) maxX = minX;
34310
+ if (minY > maxY) maxY = minY;
34311
+ if (!bases.length) return {
34312
+ x: x,
34313
+ y: y
34314
+ };
34315
+ return {
34316
+ x: Math.min(Math.max(x, minX), maxX),
34317
+ y: Math.min(Math.max(y, minY), maxY)
34318
+ };
34319
+ }
34320
+
34321
+ /** Re-clamp the unit to the current viewport (e.g. on resize or panel open). */
34322
+ }, {
34323
+ key: "_reclampUnit",
34324
+ value: function _reclampUnit() {
34325
+ if (!this._unitOffset) return;
34326
+ var bases = this._unitBaseRects();
34327
+ if (!bases.length) return;
34328
+ this._unitOffset = this._clampUnitOffset(this._unitOffset.x, this._unitOffset.y, bases);
34329
+ this._applyUnitOffset();
34330
+ }
34331
+
34332
+ /** Restore a saved unit offset (deferred so elements can be measured at offset 0). */
34333
+ }, {
34334
+ key: "_restoreUnitOffset",
34335
+ value: function _restoreUnitOffset(key) {
34336
+ var _this0 = this;
34337
+ var saved;
34338
+ try {
34339
+ saved = JSON.parse(window.localStorage.getItem(key) || 'null');
34340
+ } catch (e) {
34341
+ return;
34342
+ }
34343
+ if (!saved || typeof saved.x !== 'number' || typeof saved.y !== 'number') return;
34344
+ requestAnimationFrame(function () {
34345
+ _this0._unitOffset = {
34346
+ x: 0,
34347
+ y: 0
34348
+ }; // ensure DOM matches before measuring
34349
+ var bases = _this0._unitBaseRects();
34350
+ _this0._unitOffset = _this0._clampUnitOffset(saved.x, saved.y, bases);
34351
+ _this0._applyUnitOffset();
34352
+ });
34353
+ }
34354
+
34355
+ /**
34356
+ * Wire a single handle to drag the whole pill+panel unit (shared offset).
34357
+ * @param {HTMLElement} handle
34358
+ * @param {Object} opts
34359
+ * @param {boolean} opts.persist
34360
+ * @param {string} opts.key localStorage key
34361
+ * @param {string} [opts.restCursor] idle cursor (default 'grab')
34362
+ * @param {string} [opts.excludeSelector] don't start a drag from these (e.g. buttons)
34363
+ * @param {Function} [opts.onMoved] called once after a real drag ends
34364
+ */
34365
+ }, {
34366
+ key: "_attachUnitDrag",
34367
+ value: function _attachUnitDrag(handle, opts) {
34368
+ var _this1 = this;
34369
+ var persist = opts.persist,
34370
+ key = opts.key,
34371
+ excludeSelector = opts.excludeSelector,
34372
+ onMoved = opts.onMoved;
34373
+ var restCursor = opts.restCursor || 'grab';
34374
+ handle.style.setProperty('touch-action', 'none');
34375
+ handle.style.setProperty('cursor', restCursor);
34376
+ var DRAG_THRESHOLD = 5; // px before a press becomes a drag
34377
+ var startX = 0,
34378
+ startY = 0,
34379
+ baseX = 0,
34380
+ baseY = 0,
34381
+ bases = [];
34382
+ var dragging = false,
34383
+ moved = false;
34384
+ var onMove = function onMove(e) {
34385
+ var dx = e.clientX - startX;
34386
+ var dy = e.clientY - startY;
34387
+ if (!moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;
34388
+ moved = true;
34389
+ _this1._unitOffset = _this1._clampUnitOffset(baseX + dx, baseY + dy, bases);
34390
+ _this1._applyUnitOffset();
34391
+ };
34392
+ var _onUp = function onUp(e) {
34393
+ window.removeEventListener('pointermove', onMove);
34394
+ window.removeEventListener('pointerup', _onUp);
34395
+ handle.style.setProperty('cursor', restCursor);
34396
+ try {
34397
+ handle.releasePointerCapture(e.pointerId);
34398
+ } catch (err) {/* not captured */}
34399
+ dragging = false;
34400
+ if (moved) {
34401
+ if (typeof onMoved === 'function') onMoved();
34402
+ if (persist && key) {
34403
+ try {
34404
+ window.localStorage.setItem(key, JSON.stringify(_this1._unitOffset));
34405
+ } catch (err) {/* unavailable */}
34406
+ }
34407
+ }
34408
+ };
34409
+ var onDown = function onDown(e) {
34410
+ if (e.button != null && e.button !== 0) return; // primary / touch / pen only
34411
+ if (dragging) return;
34412
+ if (excludeSelector && e.target && e.target.closest && e.target.closest(excludeSelector)) return;
34413
+ dragging = true;
34414
+ moved = false;
34415
+ var o = _this1._unitOffset || (_this1._unitOffset = {
34416
+ x: 0,
34417
+ y: 0
34418
+ });
34419
+ startX = e.clientX;
34420
+ startY = e.clientY;
34421
+ baseX = o.x;
34422
+ baseY = o.y;
34423
+ bases = _this1._unitBaseRects();
34424
+ handle.style.setProperty('cursor', 'grabbing');
34425
+ try {
34426
+ handle.setPointerCapture(e.pointerId);
34427
+ } catch (err) {/* unsupported */}
34428
+ window.addEventListener('pointermove', onMove);
34429
+ window.addEventListener('pointerup', _onUp);
34430
+ };
34431
+ handle.addEventListener('pointerdown', onDown);
34432
+ }
34433
+
34434
+ /**
34435
+ * Make the launcher pill / mobile FAB AND the open chat panel draggable as one
34436
+ * unit — dragging any of them moves both, so they never split apart. Pill/FAB
34437
+ * drags suppress the trailing click (so the panel doesn't toggle); panel header
34438
+ * bars (.ttp-header / .ttp-call-topbar / .text-interface-top-bar) are drag
34439
+ * handles too, with their interactive controls (e.g. close) excluded.
34440
+ */
34441
+ }, {
34442
+ key: "setupDraggableWidget",
34443
+ value: function setupDraggableWidget() {
34444
+ var _this$config$position6,
34445
+ _this10 = this;
34446
+ var root = this.shadowRoot;
34447
+ if (!root) return;
34448
+ var container = root.getElementById('text-chat-button-container');
34449
+ var panel = root.getElementById('text-chat-panel');
34450
+ if (!container && !panel) return;
34451
+ this._unitOffset = this._unitOffset || {
34452
+ x: 0,
34453
+ y: 0
34454
+ };
34455
+ var persist = ((_this$config$position6 = this.config.position) === null || _this$config$position6 === void 0 ? void 0 : _this$config$position6.draggablePersist) !== false;
34456
+ var key = this._dragStorageKey('unit');
34457
+ if (persist) this._restoreUnitOffset(key);
34458
+
34459
+ // Launcher handles: pill + mobile FAB (suppress the click after a drag).
34460
+ [root.getElementById('text-chat-button'), root.querySelector('.ttp-mobile-fab')].filter(Boolean).forEach(function (h) {
34461
+ return _this10._attachUnitDrag(h, {
34462
+ persist: persist,
34463
+ key: key,
34464
+ restCursor: 'grab',
34465
+ onMoved: function onMoved() {
34466
+ _this10._suppressLauncherClick = true;
34467
+ setTimeout(function () {
34468
+ _this10._suppressLauncherClick = false;
34469
+ }, 0);
34470
+ }
34471
+ });
34472
+ });
34473
+
34474
+ // Panel handles: header bars across voice idle / active call / text views.
34475
+ if (panel) {
34476
+ ['.ttp-header', '.ttp-call-topbar', '.text-interface-top-bar'].map(function (sel) {
34477
+ return panel.querySelector(sel);
34478
+ }).filter(Boolean).forEach(function (h) {
34479
+ return _this10._attachUnitDrag(h, {
34480
+ persist: persist,
34481
+ key: key,
34482
+ restCursor: 'move',
34483
+ excludeSelector: 'button, a, input, textarea, select, [contenteditable]'
34484
+ });
34485
+ });
34486
+ }
34487
+
34488
+ // Re-apply any in-memory offset to freshly-rendered elements (re-render).
34489
+ this._applyUnitOffset();
34490
+ this._bindDragResize();
34491
+ }
34492
+
34493
+ /**
34494
+ * Make the desktop minimized voice strip (EcommerceVoiceStrip) draggable. The
34495
+ * strip lives outside the shadow DOM and owns its own drag logic; we just hand
34496
+ * it a persistence key (so it remembers its spot independently of the unit).
34497
+ */
34498
+ }, {
34499
+ key: "setupDraggableStrip",
34500
+ value: function setupDraggableStrip() {
34501
+ var _this$config$position7;
34502
+ var strip = this._ecommerceVoiceStrip;
34503
+ if (!strip || typeof strip.enableDrag !== 'function') return;
34504
+ strip.enableDrag({
34505
+ persist: ((_this$config$position7 = this.config.position) === null || _this$config$position7 === void 0 ? void 0 : _this$config$position7.draggablePersist) !== false,
34506
+ storageKey: this._dragStorageKey('strip')
34507
+ });
34508
+ }
34509
+
34510
+ /** Bind a single resize listener that re-clamps every dragged surface. */
34511
+ }, {
34512
+ key: "_bindDragResize",
34513
+ value: function _bindDragResize() {
34514
+ var _this11 = this;
34515
+ if (this._dragResizeBound) return;
34516
+ this._dragResizeBound = true;
34517
+ window.addEventListener('resize', function () {
34518
+ var _this11$_ecommerceVoi, _this11$_ecommerceVoi2;
34519
+ _this11._reclampUnit();
34520
+ (_this11$_ecommerceVoi = _this11._ecommerceVoiceStrip) === null || _this11$_ecommerceVoi === void 0 || (_this11$_ecommerceVoi2 = _this11$_ecommerceVoi.reclampDrag) === null || _this11$_ecommerceVoi2 === void 0 || _this11$_ecommerceVoi2.call(_this11$_ecommerceVoi);
34521
+ });
34522
+ }
33634
34523
  }, {
33635
34524
  key: "startNewChat",
33636
34525
  value: function startNewChat() {
@@ -33677,9 +34566,9 @@ var TTPChatWidget = /*#__PURE__*/function () {
33677
34566
  }, {
33678
34567
  key: "_isDomainErrorVisible",
33679
34568
  value: function _isDomainErrorVisible() {
33680
- var _this$voiceInterface3, _this$voiceInterface4, _idleState$dataset;
33681
- if ((_this$voiceInterface3 = this.voiceInterface) !== null && _this$voiceInterface3 !== void 0 && _this$voiceInterface3.isShowingDomainError) return true;
33682
- var idleState = (_this$voiceInterface4 = this.voiceInterface) === null || _this$voiceInterface4 === void 0 || (_this$voiceInterface4 = _this$voiceInterface4.shadowRoot) === null || _this$voiceInterface4 === void 0 ? void 0 : _this$voiceInterface4.getElementById('voiceIdleState');
34569
+ var _this$voiceInterface4, _this$voiceInterface5, _idleState$dataset;
34570
+ if ((_this$voiceInterface4 = this.voiceInterface) !== null && _this$voiceInterface4 !== void 0 && _this$voiceInterface4.isShowingDomainError) return true;
34571
+ var idleState = (_this$voiceInterface5 = this.voiceInterface) === null || _this$voiceInterface5 === void 0 || (_this$voiceInterface5 = _this$voiceInterface5.shadowRoot) === null || _this$voiceInterface5 === void 0 ? void 0 : _this$voiceInterface5.getElementById('voiceIdleState');
33683
34572
  return idleState && ((_idleState$dataset = idleState.dataset) === null || _idleState$dataset === void 0 ? void 0 : _idleState$dataset.domainError) === 'true';
33684
34573
  }
33685
34574
  }, {
@@ -33707,7 +34596,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33707
34596
  }, {
33708
34597
  key: "_openMobileCallTextLanding",
33709
34598
  value: function _openMobileCallTextLanding() {
33710
- var _this9 = this;
34599
+ var _this12 = this;
33711
34600
  if (!this.shadowRoot || window.innerWidth > 768) return;
33712
34601
  var mobileFab = this.shadowRoot.querySelector('.ttp-mobile-fab');
33713
34602
  var mobileLanding = this.shadowRoot.getElementById('ttpMobileLanding');
@@ -33718,30 +34607,30 @@ var TTPChatWidget = /*#__PURE__*/function () {
33718
34607
  // "Back" button: composedPath includes the panel but not #ttpMobileLanding, so it treated
33719
34608
  // the click as "outside" and closed the landing immediately (user only saw the FAB again).
33720
34609
  var open = function open() {
33721
- if (!_this9.shadowRoot || window.innerWidth > 768) return;
33722
- var panel = _this9.shadowRoot.getElementById('text-chat-panel');
34610
+ if (!_this12.shadowRoot || window.innerWidth > 768) return;
34611
+ var panel = _this12.shadowRoot.getElementById('text-chat-panel');
33723
34612
  if (panel) {
33724
34613
  panel.classList.remove('open');
33725
- _this9.isOpen = false;
34614
+ _this12.isOpen = false;
33726
34615
  }
33727
- if (_this9.config.promptAnimation.hideAfterClick) {
33728
- _this9.hidePrompt();
34616
+ if (_this12.config.promptAnimation.hideAfterClick) {
34617
+ _this12.hidePrompt();
33729
34618
  }
33730
- var errorBanner = _this9.shadowRoot.getElementById('ttpMobileLandingError');
34619
+ var errorBanner = _this12.shadowRoot.getElementById('ttpMobileLandingError');
33731
34620
  if (errorBanner) errorBanner.style.display = 'none';
33732
- var fab = _this9.shadowRoot.querySelector('.ttp-mobile-fab');
33733
- var landing = _this9.shadowRoot.getElementById('ttpMobileLanding');
34621
+ var fab = _this12.shadowRoot.querySelector('.ttp-mobile-fab');
34622
+ var landing = _this12.shadowRoot.getElementById('ttpMobileLanding');
33734
34623
  if (!fab || !landing) return;
33735
34624
  fab.style.display = 'none';
33736
34625
  landing.classList.add('active');
33737
- _this9.isMobileLandingOpen = true;
34626
+ _this12.isMobileLandingOpen = true;
33738
34627
  };
33739
34628
  queueMicrotask(open);
33740
34629
  }
33741
34630
  }, {
33742
34631
  key: "setupMobileWidgetEvents",
33743
34632
  value: function setupMobileWidgetEvents() {
33744
- var _this0 = this;
34633
+ var _this13 = this;
33745
34634
  if (!this.shadowRoot) return;
33746
34635
  var mobileFab = this.shadowRoot.querySelector('.ttp-mobile-fab');
33747
34636
  var mobileLanding = this.shadowRoot.getElementById('ttpMobileLanding');
@@ -33749,10 +34638,12 @@ var TTPChatWidget = /*#__PURE__*/function () {
33749
34638
  var closeMobileLanding = function closeMobileLanding() {
33750
34639
  mobileLanding.classList.remove('active');
33751
34640
  mobileFab.style.display = '';
33752
- _this0.isMobileLandingOpen = false;
34641
+ _this13.isMobileLandingOpen = false;
33753
34642
  };
33754
34643
  mobileFab.onclick = function () {
33755
- return _this0._openMobileCallTextLanding();
34644
+ // A drag just ended — don't open the landing on the trailing click.
34645
+ if (_this13._suppressLauncherClick) return;
34646
+ _this13._openMobileCallTextLanding();
33756
34647
  };
33757
34648
  var mobileClose = mobileLanding.querySelector('.ttp-mobile-landing__close');
33758
34649
  if (mobileClose) {
@@ -33762,18 +34653,18 @@ var TTPChatWidget = /*#__PURE__*/function () {
33762
34653
  if (mobileCallBtn) {
33763
34654
  mobileCallBtn.onclick = function () {
33764
34655
  closeMobileLanding();
33765
- var panel = _this0.shadowRoot.getElementById('text-chat-panel');
34656
+ var panel = _this13.shadowRoot.getElementById('text-chat-panel');
33766
34657
  if (panel) {
33767
34658
  panel.style.removeProperty('display');
33768
34659
  panel.classList.add('open');
33769
- _this0.isOpen = true;
34660
+ _this13.isOpen = true;
33770
34661
  }
33771
34662
  mobileFab.style.display = 'none';
33772
- _this0.showVoice();
34663
+ _this13.showVoice();
33773
34664
  // Landing already chose "Voice call" — start the call (mic permission / pre-prompt) instead of
33774
34665
  // leaving users on a second "Start Call" tap that feels broken.
33775
34666
  queueMicrotask(function () {
33776
- _this0.startVoiceCall().catch(function (err) {
34667
+ _this13.startVoiceCall().catch(function (err) {
33777
34668
  console.error('[TTPChatWidget] Mobile landing voice start failed:', err);
33778
34669
  });
33779
34670
  });
@@ -33783,20 +34674,20 @@ var TTPChatWidget = /*#__PURE__*/function () {
33783
34674
  if (mobileChatBtn) {
33784
34675
  mobileChatBtn.onclick = function () {
33785
34676
  closeMobileLanding();
33786
- var panel = _this0.shadowRoot.getElementById('text-chat-panel');
34677
+ var panel = _this13.shadowRoot.getElementById('text-chat-panel');
33787
34678
  if (panel) {
33788
34679
  panel.style.removeProperty('display');
33789
34680
  panel.classList.add('open');
33790
- _this0.isOpen = true;
34681
+ _this13.isOpen = true;
33791
34682
  }
33792
34683
  mobileFab.style.display = 'none';
33793
- _this0.showText();
34684
+ _this13.showText();
33794
34685
  };
33795
34686
  }
33796
34687
 
33797
34688
  // Close mobile landing on outside click
33798
34689
  document.addEventListener('click', function (e) {
33799
- if (!_this0.isMobileLandingOpen) return;
34690
+ if (!_this13.isMobileLandingOpen) return;
33800
34691
  var path = e.composedPath();
33801
34692
  if (!path.includes(mobileLanding) && !path.includes(mobileFab)) {
33802
34693
  closeMobileLanding();
@@ -33805,7 +34696,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33805
34696
 
33806
34697
  // Close mobile landing on Escape
33807
34698
  document.addEventListener('keydown', function (e) {
33808
- if (e.key === 'Escape' && _this0.isMobileLandingOpen) {
34699
+ if (e.key === 'Escape' && _this13.isMobileLandingOpen) {
33809
34700
  closeMobileLanding();
33810
34701
  }
33811
34702
  });
@@ -33821,19 +34712,19 @@ var TTPChatWidget = /*#__PURE__*/function () {
33821
34712
  _prevIsMobile = nowMobile;
33822
34713
  if (nowMobile) {
33823
34714
  // Switched desktop → mobile: close desktop panel so only mobile FAB shows
33824
- if (_this0.isOpen) {
33825
- var _this0$shadowRoot, _this0$shadowRoot2;
33826
- var panel = (_this0$shadowRoot = _this0.shadowRoot) === null || _this0$shadowRoot === void 0 ? void 0 : _this0$shadowRoot.getElementById('text-chat-panel');
34715
+ if (_this13.isOpen) {
34716
+ var _this13$shadowRoot, _this13$shadowRoot2;
34717
+ var panel = (_this13$shadowRoot = _this13.shadowRoot) === null || _this13$shadowRoot === void 0 ? void 0 : _this13$shadowRoot.getElementById('text-chat-panel');
33827
34718
  if (panel) {
33828
34719
  panel.classList.remove('open');
33829
- _this0.isOpen = false;
34720
+ _this13.isOpen = false;
33830
34721
  }
33831
- var pill = (_this0$shadowRoot2 = _this0.shadowRoot) === null || _this0$shadowRoot2 === void 0 ? void 0 : _this0$shadowRoot2.getElementById('text-chat-button');
34722
+ var pill = (_this13$shadowRoot2 = _this13.shadowRoot) === null || _this13$shadowRoot2 === void 0 ? void 0 : _this13$shadowRoot2.getElementById('text-chat-button');
33832
34723
  if (pill) pill.classList.remove('open');
33833
34724
  }
33834
34725
  } else {
33835
34726
  // Switched mobile → desktop: close mobile landing/FAB so only desktop pill shows
33836
- if (_this0.isMobileLandingOpen) {
34727
+ if (_this13.isMobileLandingOpen) {
33837
34728
  closeMobileLanding();
33838
34729
  }
33839
34730
  // Ensure mobile FAB is reset to CSS-controlled state (media query hides it on desktop)
@@ -33845,10 +34736,10 @@ var TTPChatWidget = /*#__PURE__*/function () {
33845
34736
  }, {
33846
34737
  key: "setupKeyboardNavigation",
33847
34738
  value: function setupKeyboardNavigation() {
33848
- var _this1 = this;
34739
+ var _this14 = this;
33849
34740
  document.addEventListener('keydown', function (e) {
33850
- if (e.key === 'Escape' && _this1.isOpen) {
33851
- _this1.togglePanel();
34741
+ if (e.key === 'Escape' && _this14.isOpen) {
34742
+ _this14.togglePanel();
33852
34743
  }
33853
34744
  });
33854
34745
  }
@@ -33859,7 +34750,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33859
34750
  }, {
33860
34751
  key: "setupPromptAnimation",
33861
34752
  value: function setupPromptAnimation() {
33862
- var _this10 = this;
34753
+ var _this15 = this;
33863
34754
  if (!this.shadowRoot) return;
33864
34755
  var promptConfig = this.config.promptAnimation || {};
33865
34756
  // Default to disabled if not specified (enabled === true means explicitly enabled)
@@ -33889,7 +34780,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33889
34780
  // Auto-hide after configured seconds (only if widget is closed)
33890
34781
  if (!this.isOpen && promptConfig.hideAfterSeconds !== null && promptConfig.hideAfterSeconds > 0) {
33891
34782
  this.promptAutoHideTimer = setTimeout(function () {
33892
- _this10.hidePrompt();
34783
+ _this15.hidePrompt();
33893
34784
  }, promptConfig.hideAfterSeconds * 1000);
33894
34785
  }
33895
34786
 
@@ -33901,7 +34792,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33901
34792
  // Wrap the callback to also hide pulse rings
33902
34793
  this.config.onConversationStart = function () {
33903
34794
  // Hide pulse rings when call starts
33904
- var pulseRings = _this10.shadowRoot.getElementById('prompt-pulse-rings');
34795
+ var pulseRings = _this15.shadowRoot.getElementById('prompt-pulse-rings');
33905
34796
  if (pulseRings) pulseRings.style.display = 'none';
33906
34797
 
33907
34798
  // Call original callback if it exists
@@ -33913,7 +34804,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33913
34804
  // Also listen to recordingStarted event from SDK if available
33914
34805
  if (this.voiceInterface.sdk.voiceSDK) {
33915
34806
  this.voiceInterface.sdk.voiceSDK.on('recordingStarted', function () {
33916
- var pulseRings = _this10.shadowRoot.getElementById('prompt-pulse-rings');
34807
+ var pulseRings = _this15.shadowRoot.getElementById('prompt-pulse-rings');
33917
34808
  if (pulseRings) pulseRings.style.display = 'none';
33918
34809
  });
33919
34810
  }
@@ -33961,7 +34852,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33961
34852
  }, {
33962
34853
  key: "showPrompt",
33963
34854
  value: function showPrompt() {
33964
- var _this11 = this;
34855
+ var _this16 = this;
33965
34856
  if (!this.shadowRoot) return;
33966
34857
  var promptConfig = this.config.promptAnimation || {};
33967
34858
  // Default to enabled if not specified
@@ -33981,8 +34872,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
33981
34872
  // Function to actually show the elements
33982
34873
  var doShow = function doShow() {
33983
34874
  // Show prompt bubble (check both shadow root and document for compatibility)
33984
- var promptBubble = _this11.shadowRoot.getElementById('prompt-bubble');
33985
- if (!promptBubble && _this11.shadowRoot !== document) {
34875
+ var promptBubble = _this16.shadowRoot.getElementById('prompt-bubble');
34876
+ if (!promptBubble && _this16.shadowRoot !== document) {
33986
34877
  promptBubble = document.getElementById('prompt-bubble');
33987
34878
  }
33988
34879
  if (promptBubble) {
@@ -33996,8 +34887,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
33996
34887
 
33997
34888
  // Show pulse rings if enabled
33998
34889
  if (promptConfig.showPulseRings !== false) {
33999
- var _pulseRings = _this11.shadowRoot.getElementById('prompt-pulse-rings');
34000
- if (!_pulseRings && _this11.shadowRoot !== document) {
34890
+ var _pulseRings = _this16.shadowRoot.getElementById('prompt-pulse-rings');
34891
+ if (!_pulseRings && _this16.shadowRoot !== document) {
34001
34892
  _pulseRings = document.getElementById('prompt-pulse-rings');
34002
34893
  }
34003
34894
  if (_pulseRings) {
@@ -34034,7 +34925,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34034
34925
  }
34035
34926
  // Start new timer
34036
34927
  this.promptAutoHideTimer = setTimeout(function () {
34037
- _this11.hidePrompt();
34928
+ _this16.hidePrompt();
34038
34929
  }, promptConfig.hideAfterSeconds * 1000);
34039
34930
  }
34040
34931
  }
@@ -34050,14 +34941,23 @@ var TTPChatWidget = /*#__PURE__*/function () {
34050
34941
  }, {
34051
34942
  key: "_doTogglePanel",
34052
34943
  value: function _doTogglePanel() {
34053
- var _this12 = this;
34944
+ var _this17 = this;
34054
34945
  if (!this.shadowRoot) return;
34055
34946
  this.isOpen = !this.isOpen;
34056
34947
  var panel = this.shadowRoot.getElementById('text-chat-panel');
34057
34948
  if (panel) {
34058
34949
  panel.classList.toggle('open');
34059
34950
  if (this.isOpen) {
34951
+ var _this$config$position8;
34060
34952
  panel.style.removeProperty('display');
34953
+ // The panel joins the dragged unit when it opens; re-clamp now that it
34954
+ // has real dimensions (it was hidden/zero-size while closed).
34955
+ if ((_this$config$position8 = this.config.position) !== null && _this$config$position8 !== void 0 && _this$config$position8.draggable) {
34956
+ this._applyUnitOffset();
34957
+ requestAnimationFrame(function () {
34958
+ return _this17._reclampUnit();
34959
+ });
34960
+ }
34061
34961
  }
34062
34962
  }
34063
34963
 
@@ -34072,7 +34972,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34072
34972
  // Panel is opening - hide prompt
34073
34973
  this.hidePrompt();
34074
34974
  setTimeout(function () {
34075
- var input = _this12.shadowRoot.getElementById('messageInput');
34975
+ var input = _this17.shadowRoot.getElementById('messageInput');
34076
34976
  if (input) input.focus();
34077
34977
  }, 100);
34078
34978
  } else {
@@ -34084,13 +34984,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
34084
34984
  // Panel is closing - show prompt (if enabled)
34085
34985
  this.showPrompt();
34086
34986
  setTimeout(function () {
34087
- var _this12$config$prompt;
34088
- var promptBubble = _this12.shadowRoot.getElementById('prompt-bubble');
34987
+ var _this17$config$prompt;
34988
+ var promptBubble = _this17.shadowRoot.getElementById('prompt-bubble');
34089
34989
  if (promptBubble && promptBubble.style.display === 'none') {
34090
34990
  promptBubble.style.display = 'block';
34091
34991
  }
34092
- var pulseRings = _this12.shadowRoot.getElementById('prompt-pulse-rings');
34093
- if (pulseRings && ((_this12$config$prompt = _this12.config.promptAnimation) === null || _this12$config$prompt === void 0 ? void 0 : _this12$config$prompt.showPulseRings) !== false) {
34992
+ var pulseRings = _this17.shadowRoot.getElementById('prompt-pulse-rings');
34993
+ if (pulseRings && ((_this17$config$prompt = _this17.config.promptAnimation) === null || _this17$config$prompt === void 0 ? void 0 : _this17$config$prompt.showPulseRings) !== false) {
34094
34994
  if (pulseRings.style.display === 'none') {
34095
34995
  pulseRings.style.display = 'block';
34096
34996
  }
@@ -34282,8 +35182,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
34282
35182
  }, {
34283
35183
  key: "showBackButtonWarning",
34284
35184
  value: function showBackButtonWarning() {
34285
- var _this$voiceInterface5, _this$voiceInterface$;
34286
- if (!((_this$voiceInterface5 = this.voiceInterface) !== null && _this$voiceInterface5 !== void 0 && _this$voiceInterface5.isActive)) return;
35185
+ var _this$voiceInterface6, _this$voiceInterface$;
35186
+ if (!((_this$voiceInterface6 = this.voiceInterface) !== null && _this$voiceInterface6 !== void 0 && _this$voiceInterface6.isActive)) return;
34287
35187
 
34288
35188
  // Show warning message in the voice interface
34289
35189
  if ((_this$voiceInterface$ = this.voiceInterface.desktop) !== null && _this$voiceInterface$ !== void 0 && _this$voiceInterface$.showBackButtonWarning) {
@@ -34364,7 +35264,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34364
35264
  _this$config$voice0,
34365
35265
  _this$config$voice1,
34366
35266
  _this$config$voice10,
34367
- _this13 = this;
35267
+ _this18 = this;
34368
35268
  // Deep merge nested objects
34369
35269
  var mergedConfig = _objectSpread({}, this.config);
34370
35270
 
@@ -34582,20 +35482,20 @@ var TTPChatWidget = /*#__PURE__*/function () {
34582
35482
  outputBitDepth: ((_this$config$voice10 = this.config.voice) === null || _this$config$voice10 === void 0 ? void 0 : _this$config$voice10.outputBitDepth) || 16,
34583
35483
  desktopMinimizedEcommerceStripUi: desktopMinimizedEcommerceStripUi,
34584
35484
  onDesktopMinimizedStripCallStart: desktopMinimizedEcommerceStripUi ? function () {
34585
- var _this13$_ecommerceVoi;
34586
- (_this13$_ecommerceVoi = _this13._ecommerceVoiceStrip) === null || _this13$_ecommerceVoi === void 0 || _this13$_ecommerceVoi.show();
34587
- if (_this13.isOpen) _this13.minimize();
34588
- _this13._setPanelFooterVisible(false);
34589
- _this13._setEcommerceStripLauncherVisible(false);
35485
+ var _this18$_ecommerceVoi;
35486
+ (_this18$_ecommerceVoi = _this18._ecommerceVoiceStrip) === null || _this18$_ecommerceVoi === void 0 || _this18$_ecommerceVoi.show();
35487
+ if (_this18.isOpen) _this18.minimize();
35488
+ _this18._setPanelFooterVisible(false);
35489
+ _this18._setEcommerceStripLauncherVisible(false);
34590
35490
  } : undefined,
34591
35491
  onDesktopMinimizedStripLauncherRestore: desktopMinimizedEcommerceStripUi ? function () {
34592
- return _this13._restoreDesktopEcommerceStripChrome();
35492
+ return _this18._restoreDesktopEcommerceStripChrome();
34593
35493
  } : undefined,
34594
35494
  // Pass event callbacks to voice interface (forward only; panel is not auto-minimized on call start)
34595
35495
  onConversationStart: function onConversationStart() {
34596
- if (typeof _this13.config.onConversationStart === 'function') {
34597
- var _this13$config;
34598
- (_this13$config = _this13.config).onConversationStart.apply(_this13$config, arguments);
35496
+ if (typeof _this18.config.onConversationStart === 'function') {
35497
+ var _this18$config;
35498
+ (_this18$config = _this18.config).onConversationStart.apply(_this18$config, arguments);
34599
35499
  }
34600
35500
  },
34601
35501
  onConversationEnd: this.config.onConversationEnd,
@@ -34604,48 +35504,48 @@ var TTPChatWidget = /*#__PURE__*/function () {
34604
35504
  onAudioStoppedPlaying: this.config.onAudioStoppedPlaying,
34605
35505
  onSubtitleDisplay: this.config.onSubtitleDisplay,
34606
35506
  onCallEnd: function onCallEnd() {
34607
- var _this13$config$behavi;
34608
- if (_this13._isDomainErrorVisible()) return;
34609
- var widgetMode = ((_this13$config$behavi = _this13.config.behavior) === null || _this13$config$behavi === void 0 ? void 0 : _this13$config$behavi.mode) || 'unified';
35507
+ var _this18$config$behavi;
35508
+ if (_this18._isDomainErrorVisible()) return;
35509
+ var widgetMode = ((_this18$config$behavi = _this18.config.behavior) === null || _this18$config$behavi === void 0 ? void 0 : _this18$config$behavi.mode) || 'unified';
34610
35510
  if (widgetMode === 'unified') {
34611
35511
  if (window.innerWidth <= 768) {
34612
- var _this13$shadowRoot, _this13$shadowRoot2;
34613
- var panel = (_this13$shadowRoot = _this13.shadowRoot) === null || _this13$shadowRoot === void 0 ? void 0 : _this13$shadowRoot.getElementById('text-chat-panel');
35512
+ var _this18$shadowRoot, _this18$shadowRoot2;
35513
+ var panel = (_this18$shadowRoot = _this18.shadowRoot) === null || _this18$shadowRoot === void 0 ? void 0 : _this18$shadowRoot.getElementById('text-chat-panel');
34614
35514
  if (panel) {
34615
35515
  panel.classList.remove('open');
34616
- _this13.isOpen = false;
35516
+ _this18.isOpen = false;
34617
35517
  }
34618
- var fab = (_this13$shadowRoot2 = _this13.shadowRoot) === null || _this13$shadowRoot2 === void 0 ? void 0 : _this13$shadowRoot2.querySelector('.ttp-mobile-fab');
35518
+ var fab = (_this18$shadowRoot2 = _this18.shadowRoot) === null || _this18$shadowRoot2 === void 0 ? void 0 : _this18$shadowRoot2.querySelector('.ttp-mobile-fab');
34619
35519
  if (fab) fab.style.display = '';
34620
35520
  }
34621
- _this13.showLanding();
35521
+ _this18.showLanding();
34622
35522
  }
34623
35523
  },
34624
35524
  onShowVoice: function onShowVoice() {
34625
- _this13.showVoice();
35525
+ _this18.showVoice();
34626
35526
  },
34627
35527
  onShowLanding: function onShowLanding() {
34628
- _this13.showLanding();
35528
+ _this18.showLanding();
34629
35529
  },
34630
35530
  onDisclaimerDeclined: function onDisclaimerDeclined() {
34631
- var _this13$config$behavi2;
34632
- if (_this13._isDomainErrorVisible()) return;
34633
- var widgetMode = ((_this13$config$behavi2 = _this13.config.behavior) === null || _this13$config$behavi2 === void 0 ? void 0 : _this13$config$behavi2.mode) || 'unified';
35531
+ var _this18$config$behavi2;
35532
+ if (_this18._isDomainErrorVisible()) return;
35533
+ var widgetMode = ((_this18$config$behavi2 = _this18.config.behavior) === null || _this18$config$behavi2 === void 0 ? void 0 : _this18$config$behavi2.mode) || 'unified';
34634
35534
  if (widgetMode === 'voice-only') {
34635
- _this13.showVoice();
35535
+ _this18.showVoice();
34636
35536
  return;
34637
35537
  }
34638
35538
  if (widgetMode !== 'unified') return;
34639
35539
  if (window.innerWidth <= 768) {
34640
- var _this13$shadowRoot3;
34641
- var panel = (_this13$shadowRoot3 = _this13.shadowRoot) === null || _this13$shadowRoot3 === void 0 ? void 0 : _this13$shadowRoot3.getElementById('text-chat-panel');
35540
+ var _this18$shadowRoot3;
35541
+ var panel = (_this18$shadowRoot3 = _this18.shadowRoot) === null || _this18$shadowRoot3 === void 0 ? void 0 : _this18$shadowRoot3.getElementById('text-chat-panel');
34642
35542
  if (panel) {
34643
35543
  panel.classList.remove('open');
34644
- _this13.isOpen = false;
35544
+ _this18.isOpen = false;
34645
35545
  }
34646
- _this13._openMobileCallTextLanding();
35546
+ _this18._openMobileCallTextLanding();
34647
35547
  } else {
34648
- _this13.showLanding();
35548
+ _this18.showLanding();
34649
35549
  }
34650
35550
  },
34651
35551
  direction: this.getEffectiveTextDirection()
@@ -34692,8 +35592,9 @@ var TTPChatWidget = /*#__PURE__*/function () {
34692
35592
  }, {
34693
35593
  key: "_initEcommerceVoiceStrip",
34694
35594
  value: function _initEcommerceVoiceStrip() {
34695
- var _this14 = this,
34696
- _this$voiceInterface6;
35595
+ var _this19 = this,
35596
+ _this$config$position9,
35597
+ _this$voiceInterface7;
34697
35598
  var flavor = this.config.flavor && _typeof(this.config.flavor) === 'object' ? this.config.flavor : null;
34698
35599
  if (window.innerWidth <= 768) return;
34699
35600
  if (!flavor || flavor.callView !== 'minimized') return;
@@ -34714,31 +35615,34 @@ var TTPChatWidget = /*#__PURE__*/function () {
34714
35615
  endCallButtonColor: v.endCallButtonColor || '#ef4444'
34715
35616
  },
34716
35617
  getVoiceUiState: function getVoiceUiState() {
34717
- var _this14$voiceInterfac, _this14$voiceInterfac2, _this14$voiceInterfac3;
35618
+ var _this19$voiceInterfac, _this19$voiceInterfac2, _this19$voiceInterfac3;
34718
35619
  return {
34719
- isMicMuted: !!((_this14$voiceInterfac = _this14.voiceInterface) !== null && _this14$voiceInterfac !== void 0 && _this14$voiceInterfac.isMicMuted),
34720
- isPaused: !!((_this14$voiceInterfac2 = _this14.voiceInterface) !== null && _this14$voiceInterfac2 !== void 0 && _this14$voiceInterfac2.isPaused),
34721
- isSpeakerMuted: !!((_this14$voiceInterfac3 = _this14.voiceInterface) !== null && _this14$voiceInterfac3 !== void 0 && _this14$voiceInterfac3.isSpeakerMuted)
35620
+ isMicMuted: !!((_this19$voiceInterfac = _this19.voiceInterface) !== null && _this19$voiceInterfac !== void 0 && _this19$voiceInterfac.isMicMuted),
35621
+ isPaused: !!((_this19$voiceInterfac2 = _this19.voiceInterface) !== null && _this19$voiceInterfac2 !== void 0 && _this19$voiceInterfac2.isPaused),
35622
+ isSpeakerMuted: !!((_this19$voiceInterfac3 = _this19.voiceInterface) !== null && _this19$voiceInterfac3 !== void 0 && _this19$voiceInterfac3.isSpeakerMuted)
34722
35623
  };
34723
35624
  },
35625
+ onAbout: function onAbout() {
35626
+ return _this19._openAboutModal();
35627
+ },
34724
35628
  onHangup: function onHangup() {
34725
- if (_this14.voiceInterface) _this14.voiceInterface.endVoiceCall();
35629
+ if (_this19.voiceInterface) _this19.voiceInterface.endVoiceCall();
34726
35630
  },
34727
35631
  onToggleMute: function onToggleMute() {
34728
- if (_this14.voiceInterface) _this14.voiceInterface.toggleMute();
35632
+ if (_this19.voiceInterface) _this19.voiceInterface.toggleMute();
34729
35633
  strip.syncFromVoice();
34730
35634
  },
34731
35635
  onTogglePause: function onTogglePause() {
34732
- if (_this14.voiceInterface) _this14.voiceInterface.togglePause();
35636
+ if (_this19.voiceInterface) _this19.voiceInterface.togglePause();
34733
35637
  strip.syncFromVoice();
34734
35638
  },
34735
35639
  onToggleSpeaker: function onToggleSpeaker() {
34736
- if (_this14.voiceInterface) _this14.voiceInterface.toggleSpeaker();
35640
+ if (_this19.voiceInterface) _this19.voiceInterface.toggleSpeaker();
34737
35641
  strip.syncFromVoice();
34738
35642
  },
34739
35643
  onSendText: function onSendText(text) {
34740
- var _this14$voiceInterfac4;
34741
- var voiceSDK = (_this14$voiceInterfac4 = _this14.voiceInterface) === null || _this14$voiceInterfac4 === void 0 || (_this14$voiceInterfac4 = _this14$voiceInterfac4.sdk) === null || _this14$voiceInterfac4 === void 0 ? void 0 : _this14$voiceInterfac4.voiceSDK;
35644
+ var _this19$voiceInterfac4;
35645
+ var voiceSDK = (_this19$voiceInterfac4 = _this19.voiceInterface) === null || _this19$voiceInterfac4 === void 0 || (_this19$voiceInterfac4 = _this19$voiceInterfac4.sdk) === null || _this19$voiceInterfac4 === void 0 ? void 0 : _this19$voiceInterfac4.voiceSDK;
34742
35646
  if (voiceSDK && typeof voiceSDK.sendMessage === 'function') {
34743
35647
  voiceSDK.sendMessage({
34744
35648
  t: 'text_inject',
@@ -34749,8 +35653,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
34749
35653
  });
34750
35654
  this._ecommerceVoiceStrip = strip;
34751
35655
 
35656
+ // Make the strip draggable too when position.draggable is enabled.
35657
+ if ((_this$config$position9 = this.config.position) !== null && _this$config$position9 !== void 0 && _this$config$position9.draggable) {
35658
+ this.setupDraggableStrip();
35659
+ }
35660
+
34752
35661
  // Show strip when conversation starts
34753
- var agentSDK = (_this$voiceInterface6 = this.voiceInterface) === null || _this$voiceInterface6 === void 0 ? void 0 : _this$voiceInterface6.sdk;
35662
+ var agentSDK = (_this$voiceInterface7 = this.voiceInterface) === null || _this$voiceInterface7 === void 0 ? void 0 : _this$voiceInterface7.sdk;
34754
35663
  if (agentSDK) {
34755
35664
  var origConvStart = agentSDK.onConversationStart;
34756
35665
  agentSDK.onConversationStart = function () {
@@ -34788,7 +35697,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34788
35697
  var _this$voiceInterface$2;
34789
35698
  var origOnCallEnd = this.voiceInterface.config.onCallEnd;
34790
35699
  this.voiceInterface.config.onCallEnd = function () {
34791
- _this14._restoreDesktopEcommerceStripChrome();
35700
+ _this19._restoreDesktopEcommerceStripChrome();
34792
35701
  if (typeof origOnCallEnd === 'function') origOnCallEnd();
34793
35702
  };
34794
35703
 
@@ -34912,7 +35821,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34912
35821
  key: "injectData",
34913
35822
  value: (function () {
34914
35823
  var _injectData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6(data) {
34915
- var _this$voiceInterface7;
35824
+ var _this$voiceInterface8;
34916
35825
  var options,
34917
35826
  voiceSDK,
34918
35827
  ack,
@@ -34937,7 +35846,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34937
35846
  throw new Error('Voice call is not active');
34938
35847
  case 2:
34939
35848
  // Check if SDK is available
34940
- voiceSDK = (_this$voiceInterface7 = this.voiceInterface) === null || _this$voiceInterface7 === void 0 ? void 0 : _this$voiceInterface7.getVoiceSDK();
35849
+ voiceSDK = (_this$voiceInterface8 = this.voiceInterface) === null || _this$voiceInterface8 === void 0 ? void 0 : _this$voiceInterface8.getVoiceSDK();
34941
35850
  if (voiceSDK) {
34942
35851
  _context6.n = 3;
34943
35852
  break;
@@ -35202,7 +36111,7 @@ var TextInterface = /*#__PURE__*/function () {
35202
36111
  var inputPlaceholder = this.config.inputPlaceholder || ((_this$config$panel = this.config.panel) === null || _this$config$panel === void 0 ? void 0 : _this$config$panel.inputPlaceholder) || this.t('typeMessage') || 'Type your message...';
35203
36112
  var unifiedMode = ((_this$config$behavior = this.config.behavior) === null || _this$config$behavior === void 0 ? void 0 : _this$config$behavior.mode) === 'unified';
35204
36113
  var backArrow = this.config.direction === 'rtl' ? '→' : '←';
35205
- var backBar = unifiedMode ? "\n <div class=\"text-interface-top-bar\">\n <button type=\"button\" class=\"text-interface-back-btn\" id=\"textUnifiedBackBtn\" aria-label=\"".concat(this.t('back'), "\">\n <span class=\"text-interface-back-icon\" aria-hidden=\"true\">").concat(backArrow, "</span>\n <span class=\"text-interface-back-label\">").concat(this.t('back'), "</span>\n </button>\n </div>") : '';
36114
+ var backBar = unifiedMode ? "\n <div class=\"text-interface-top-bar\">\n <button type=\"button\" class=\"text-interface-back-btn\" id=\"textUnifiedBackBtn\" aria-label=\"".concat(this.t('back'), "\">\n <span class=\"text-interface-back-icon\" aria-hidden=\"true\">").concat(backArrow, "</span>\n <span class=\"text-interface-back-label\">").concat(this.t('back'), "</span>\n </button>\n <button type=\"button\" class=\"ttp-info-btn\" aria-label=\"").concat(this.t('aboutTitle') || 'About', "\" title=\"").concat(this.t('aboutTitle') || 'About', "\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"9\"/>\n <line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"16\"/>\n <circle cx=\"12\" cy=\"7.7\" r=\"1.05\" fill=\"currentColor\" stroke=\"none\"/>\n </svg>\n </button>\n </div>") : '';
35206
36115
  return "<div class=\"text-interface\" id=\"textInterface\">\n ".concat(backBar, "\n <div class=\"messages-container\" id=\"messagesContainer\">\n <div class=\"empty-state\">\n <div class=\"empty-state-icon\">\uD83D\uDCAC</div>\n <div class=\"empty-state-title\">").concat(this.t('hello'), "</div>\n <div class=\"empty-state-text\">").concat(this.t('sendMessage'), "</div>\n </div>\n </div>\n <div class=\"input-container\">\n <div class=\"input-wrapper\" style=\"flex:1;\">\n <textarea class=\"message-input\" id=\"messageInput\" placeholder=\"").concat(inputPlaceholder, "\" rows=\"1\" dir=\"").concat(this.config.direction || 'ltr', "\"></textarea>\n </div>\n <button class=\"send-button\" id=\"sendButton\" aria-label=\"").concat(this.t('sendMessageAria'), "\">").concat(this.config.sendButtonText || '➤', "</button>\n ").concat((_this$config$sendButt = this.config.sendButtonHint) !== null && _this$config$sendButt !== void 0 && _this$config$sendButt.text || (_this$config$panel2 = this.config.panel) !== null && _this$config$panel2 !== void 0 && (_this$config$panel2 = _this$config$panel2.sendButtonHint) !== null && _this$config$panel2 !== void 0 && _this$config$panel2.text ? "\n <div class=\"send-button-hint\" style=\"color: ".concat(((_this$config$sendButt2 = this.config.sendButtonHint) === null || _this$config$sendButt2 === void 0 ? void 0 : _this$config$sendButt2.color) || ((_this$config$panel3 = this.config.panel) === null || _this$config$panel3 === void 0 || (_this$config$panel3 = _this$config$panel3.sendButtonHint) === null || _this$config$panel3 === void 0 ? void 0 : _this$config$panel3.color) || '#6B7280', "; font-size: ").concat(((_this$config$sendButt3 = this.config.sendButtonHint) === null || _this$config$sendButt3 === void 0 ? void 0 : _this$config$sendButt3.fontSize) || ((_this$config$panel4 = this.config.panel) === null || _this$config$panel4 === void 0 || (_this$config$panel4 = _this$config$panel4.sendButtonHint) === null || _this$config$panel4 === void 0 ? void 0 : _this$config$panel4.fontSize) || '14px', "; text-align: center; margin-top: 4px;\">\n ").concat(((_this$config$sendButt4 = this.config.sendButtonHint) === null || _this$config$sendButt4 === void 0 ? void 0 : _this$config$sendButt4.text) || ((_this$config$panel5 = this.config.panel) === null || _this$config$panel5 === void 0 || (_this$config$panel5 = _this$config$panel5.sendButtonHint) === null || _this$config$panel5 === void 0 ? void 0 : _this$config$panel5.text), "\n </div>\n ") : '', "\n </div>\n </div>");
35207
36116
  }
35208
36117
 
@@ -35334,7 +36243,7 @@ var TextInterface = /*#__PURE__*/function () {
35334
36243
 
35335
36244
  // Add !important to display rules when not using Shadow DOM (to override theme CSS)
35336
36245
  var important = this.config.useShadowDOM === false ? ' !important' : '';
35337
- return "\n .text-interface-top-bar {\n flex-shrink: 0".concat(important, ";\n padding: 10px 12px 8px").concat(important, ";\n border-bottom: 1px solid ").concat(topBarBorder).concat(important, ";\n background: ").concat(topBarBg).concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n }\n .text-interface-back-btn {\n display: inline-flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 6px").concat(important, ";\n padding: 6px 10px").concat(important, ";\n margin: 0").concat(important, ";\n border: none").concat(important, ";\n border-radius: 8px").concat(important, ";\n background: transparent").concat(important, ";\n color: ").concat(backBtnColor).concat(important, ";\n font-size: 16px").concat(important, ";\n font-weight: 600").concat(important, ";\n cursor: pointer").concat(important, ";\n font-family: inherit").concat(important, ";\n }\n .text-interface-back-btn:hover {\n background: ").concat(backBtnHoverBg).concat(important, ";\n color: ").concat(backBtnHoverColor).concat(important, ";\n }\n .text-interface-back-icon {\n font-size: 18px").concat(important, ";\n line-height: 1").concat(important, ";\n }\n .text-interface-back-label {\n line-height: 1.2").concat(important, ";\n }\n /* Messages container using new classes */\n #messagesContainer { \n flex: 1").concat(important, "; \n overflow-y: auto").concat(important, "; \n overflow-x: hidden").concat(important, "; \n padding: 20px").concat(important, "; \n background: ").concat(messagesAreaBg).concat(important, "; \n display: flex").concat(important, "; \n flex-direction: column").concat(important, "; \n gap: 16px").concat(important, "; \n min-height: 0").concat(important, "; \n }\n .empty-state { \n flex: 1").concat(important, "; \n display: flex").concat(important, "; \n flex-direction: column").concat(important, "; \n align-items: center").concat(important, "; \n justify-content: center").concat(important, "; \n gap: 12px").concat(important, "; \n color: ").concat(emptyMuted).concat(important, "; \n text-align: center").concat(important, "; \n padding: 20px").concat(important, "; \n }\n .empty-state-icon { font-size: 52px").concat(important, "; opacity: 0.3").concat(important, "; }\n .empty-state-title { font-size: 22px").concat(important, "; font-weight: 700").concat(important, "; color: ").concat(emptyTitle).concat(important, "; }\n .empty-state-text { font-size: 15px").concat(important, "; max-width: 300px").concat(important, "; line-height: 1.45").concat(important, "; }\n\n .text-interface { \n display: none").concat(important, "; \n flex: 1").concat(important, "; \n flex-direction: column").concat(important, "; \n min-height: 0").concat(important, "; \n overflow: hidden").concat(important, "; \n }\n .text-interface.active { display: flex").concat(important, "; }\n \n .message { \n display: flex").concat(important, "; \n gap: 8px").concat(important, "; \n padding: 4px 0").concat(important, "; \n max-width: 100%").concat(important, "; \n align-items: center").concat(important, "; \n }\n .message.edge-left { flex-direction: row").concat(important, "; }\n .message.edge-right { flex-direction: row-reverse").concat(important, "; }\n .message-bubble { \n padding: 14px 16px").concat(important, "; \n border-radius: ").concat(messages.borderRadius, "px").concat(important, "; \n max-width: 80%").concat(important, "; \n font-size: ").concat(messages.fontSize).concat(important, "; \n line-height: 1.45").concat(important, ";\n word-wrap: break-word").concat(important, "; \n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, "; \n direction: ").concat(this.config.direction || 'ltr', ";\n }\n .message.user .message-bubble { \n background: ").concat(userBubbleBg).concat(important, "; \n color: ").concat(userBubbleTextColor).concat(important, "; \n }\n .message.agent .message-bubble { \n background: ").concat(agentBubbleBg).concat(important, "; \n color: ").concat(agentBubbleTextColor).concat(important, "; \n border: ").concat(agentBubbleBorder).concat(important, "; \n }\n\n .message.user { \n align-self: ").concat(this.config.direction === 'rtl' ? 'flex-start' : 'flex-end').concat(important, "; \n }\n .message.agent { \n align-self: ").concat(this.config.direction === 'rtl' ? 'flex-end' : 'flex-start').concat(important, "; \n }\n .message .message-bubble { \n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left', " !important; \n }\n ").concat(this.config.direction === 'rtl' ? "\n .message-bubble {\n text-align: right !important;\n }\n " : '', "\n .message-avatar { \n width: ").concat(avatarSize).concat(important, "; \n height: ").concat(avatarSize).concat(important, "; \n min-width: ").concat(avatarSize).concat(important, "; \n border-radius: 50%").concat(important, "; \n display: flex").concat(important, "; \n align-items: center").concat(important, "; \n justify-content: center").concat(important, "; \n flex-shrink: 0").concat(important, "; \n color: inherit").concat(important, "; \n font-size: ").concat(useVoiceTheme ? '14' : '20', "px").concat(important, "; \n line-height: 1").concat(important, "; \n background: transparent").concat(important, "; \n border: none").concat(important, "; \n box-sizing: border-box").concat(important, "; \n }\n .message-avatar.user { background: ").concat(avatarUserBg).concat(important, "; color: ").concat(avatarUserColor).concat(important, "; }\n .message-avatar.agent { background: ").concat(avatarAgentBg).concat(important, "; }\n \n .message.system {\n background: ").concat(messages.systemBackgroundColor, ";\n align-self: flex-start").concat(important, ";\n }\n .message.error {\n background: ").concat(messages.errorBackgroundColor, ";\n align-self: flex-start").concat(important, ";\n }\n \n .input-container {\n display: flex").concat(important, ";\n gap: 8px").concat(important, ";\n padding: 12px 16px").concat(important, ";\n background: ").concat(inputContainerBg).concat(important, ";\n border-top: 1px solid ").concat(inputContainerBorderTop).concat(important, ";\n align-items: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n flex-direction: ").concat(this.config.direction === 'rtl' ? 'row-reverse' : 'row').concat(important, ";\n }\n \n .input-wrapper {\n position: relative").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n }\n \n .message-input {\n width: 100%").concat(important, ";\n min-height: ").concat(TEXT_INPUT_MIN_HEIGHT_PX, "px").concat(important, ";\n max-height: ").concat(TEXT_INPUT_MAX_HEIGHT_PX, "px").concat(important, ";\n padding: ").concat(inputPadding, ";\n border: 1px solid ").concat(inputBorderColor, ";\n border-radius: ").concat(inputBorderRadius, "px;\n font-size: ").concat(inputFontSize, ";\n font-family: inherit").concat(important, ";\n line-height: 1.4").concat(important, ";\n resize: none").concat(important, ";\n overflow-y: auto").concat(important, ";\n background: ").concat(inputBackgroundColor, ";\n color: ").concat(inputTextColor, ";\n vertical-align: top").concat(important, ";\n margin: 0").concat(important, ";\n display: block").concat(important, ";\n white-space: pre-wrap").concat(important, ";\n word-wrap: break-word").concat(important, ";\n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, ";\n direction: ").concat(this.config.direction || 'ltr', ";\n -webkit-appearance: none").concat(important, ";\n appearance: none").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n \n .message-input:focus {\n outline: none").concat(important, ";\n border-color: ").concat(inputFocusColor, ";\n background: ").concat(inputFocusBg).concat(important, ";\n box-shadow: ").concat(inputFocusBoxShadow, ";\n }\n \n .message-input::placeholder {\n color: ").concat(placeholderColor).concat(important, ";\n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, ";\n }\n \n .send-button {\n width: 44px").concat(important, ";\n height: 44px").concat(important, ";\n border-radius: 50%").concat(important, ";\n border: none").concat(important, ";\n background: ").concat(sendButtonColor, ";\n color: ").concat(sendButtonTextColor, ";\n font-size: ").concat(this.config.sendButtonFontSize || ((_this$config$panel15 = this.config.panel) === null || _this$config$panel15 === void 0 ? void 0 : _this$config$panel15.sendButtonFontSize) || '20px', ";\n font-weight: ").concat(this.config.sendButtonFontWeight || ((_this$config$panel16 = this.config.panel) === null || _this$config$panel16 === void 0 ? void 0 : _this$config$panel16.sendButtonFontWeight) || '500', ";\n cursor: pointer").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n transition: all 0.2s ease").concat(important, ";\n box-shadow: 0 4px 12px rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", 0.32)").concat(important, ";\n }\n \n .send-button:hover:not(:disabled) {\n background: ").concat(sendButtonHoverColor, ";\n transform: scale(1.05)").concat(important, ";\n box-shadow: 0 6px 16px rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", 0.42)").concat(important, ";\n }\n \n .send-button-hint {\n width: 100%").concat(important, ";\n text-align: center").concat(important, ";\n margin-top: 4px").concat(important, ";\n }\n \n .send-button:disabled {\n opacity: 0.5").concat(important, ";\n cursor: not-allowed").concat(important, ";\n }\n \n .typing-indicator {\n display: inline-flex").concat(important, ";\n gap: 4px").concat(important, ";\n align-items: center").concat(important, ";\n }\n \n .typing-dot {\n width: 6px").concat(important, ";\n height: 6px").concat(important, ";\n border-radius: 50%").concat(important, ";\n background: rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", ").concat(typingDotAlpha, ")").concat(important, ";\n animation: typingDot 1.4s ease-in-out infinite").concat(important, ";\n }\n \n .typing-dot:nth-child(2) { animation-delay: 0.2s").concat(important, "; }\n .typing-dot:nth-child(3) { animation-delay: 0.4s").concat(important, "; }\n \n @keyframes typingDot {\n 0%, 60%, 100% { transform: translateY(0); opacity: 0.7; }\n 30% { transform: translateY(-8px); opacity: 1; }\n }\n \n .error-message {\n padding: 12px").concat(important, ";\n background: ").concat(errorBubbleBg, ";\n border-radius: ").concat(messages.borderRadius, "px;\n color: ").concat(errorBubbleColor).concat(important, ";\n border: ").concat(errorBubbleBorder).concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n margin: 8px 0").concat(important, ";\n }\n \n ").concat(useVoiceTheme ? "\n #textInterface.active .input-container .send-button-hint {\n color: rgba(255,255,255,0.72)".concat(important, ";\n }\n ") : '', "\n \n @media (max-width: 768px) {\n #messagesContainer {\n padding: 12px").concat(important, ";\n gap: 12px").concat(important, ";\n }\n \n .message-bubble {\n max-width: 85%").concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n padding: 12px 14px").concat(important, ";\n }\n \n .text-input-container {\n padding: 10px").concat(important, ";\n gap: 8px").concat(important, ";\n }\n \n #text-chat-input {\n font-size: 16px !important; /* Prevents iOS zoom on focus */\n padding: 10px 14px").concat(important, ";\n min-height: 44px").concat(important, ";\n }\n \n #text-chat-send {\n min-width: 56px").concat(important, ";\n min-height: 44px").concat(important, ";\n width: 56px").concat(important, ";\n height: 44px").concat(important, ";\n }\n \n .empty-state-icon {\n font-size: 44px").concat(important, ";\n }\n \n .empty-state-title {\n font-size: 20px").concat(important, ";\n }\n \n .empty-state-text {\n font-size: 14px").concat(important, ";\n }\n }\n \n @media (max-width: 480px) {\n #messagesContainer {\n padding: 10px").concat(important, ";\n gap: 10px").concat(important, ";\n }\n \n .message-bubble {\n max-width: 90%").concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n padding: 10px 12px").concat(important, ";\n }\n \n .text-input-container {\n padding: 8px").concat(important, ";\n }\n \n #text-chat-input {\n font-size: 16px !important;\n padding: 8px 12px").concat(important, ";\n }\n }\n ");
36246
+ return "\n .text-interface-top-bar {\n flex-shrink: 0".concat(important, ";\n padding: 10px 12px 8px").concat(important, ";\n border-bottom: 1px solid ").concat(topBarBorder).concat(important, ";\n background: ").concat(topBarBg).concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: space-between").concat(important, ";\n }\n .text-interface-top-bar .ttp-info-btn {\n color: ").concat(backBtnColor).concat(important, ";\n }\n .text-interface-top-bar .ttp-info-btn:hover {\n background: ").concat(backBtnHoverBg).concat(important, ";\n color: ").concat(backBtnHoverColor).concat(important, ";\n }\n .text-interface-back-btn {\n display: inline-flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 6px").concat(important, ";\n padding: 6px 10px").concat(important, ";\n margin: 0").concat(important, ";\n border: none").concat(important, ";\n border-radius: 8px").concat(important, ";\n background: transparent").concat(important, ";\n color: ").concat(backBtnColor).concat(important, ";\n font-size: 16px").concat(important, ";\n font-weight: 600").concat(important, ";\n cursor: pointer").concat(important, ";\n font-family: inherit").concat(important, ";\n }\n .text-interface-back-btn:hover {\n background: ").concat(backBtnHoverBg).concat(important, ";\n color: ").concat(backBtnHoverColor).concat(important, ";\n }\n .text-interface-back-icon {\n font-size: 18px").concat(important, ";\n line-height: 1").concat(important, ";\n }\n .text-interface-back-label {\n line-height: 1.2").concat(important, ";\n }\n /* Messages container using new classes */\n #messagesContainer { \n flex: 1").concat(important, "; \n overflow-y: auto").concat(important, "; \n overflow-x: hidden").concat(important, "; \n padding: 20px").concat(important, "; \n background: ").concat(messagesAreaBg).concat(important, "; \n display: flex").concat(important, "; \n flex-direction: column").concat(important, "; \n gap: 16px").concat(important, "; \n min-height: 0").concat(important, "; \n }\n .empty-state { \n flex: 1").concat(important, "; \n display: flex").concat(important, "; \n flex-direction: column").concat(important, "; \n align-items: center").concat(important, "; \n justify-content: center").concat(important, "; \n gap: 12px").concat(important, "; \n color: ").concat(emptyMuted).concat(important, "; \n text-align: center").concat(important, "; \n padding: 20px").concat(important, "; \n }\n .empty-state-icon { font-size: 52px").concat(important, "; opacity: 0.3").concat(important, "; }\n .empty-state-title { font-size: 22px").concat(important, "; font-weight: 700").concat(important, "; color: ").concat(emptyTitle).concat(important, "; }\n .empty-state-text { font-size: 15px").concat(important, "; max-width: 300px").concat(important, "; line-height: 1.45").concat(important, "; }\n\n .text-interface { \n display: none").concat(important, "; \n flex: 1").concat(important, "; \n flex-direction: column").concat(important, "; \n min-height: 0").concat(important, "; \n overflow: hidden").concat(important, "; \n }\n .text-interface.active { display: flex").concat(important, "; }\n \n .message { \n display: flex").concat(important, "; \n gap: 8px").concat(important, "; \n padding: 4px 0").concat(important, "; \n max-width: 100%").concat(important, "; \n align-items: center").concat(important, "; \n }\n .message.edge-left { flex-direction: row").concat(important, "; }\n .message.edge-right { flex-direction: row-reverse").concat(important, "; }\n .message-bubble { \n padding: 14px 16px").concat(important, "; \n border-radius: ").concat(messages.borderRadius, "px").concat(important, "; \n max-width: 80%").concat(important, "; \n font-size: ").concat(messages.fontSize).concat(important, "; \n line-height: 1.45").concat(important, ";\n word-wrap: break-word").concat(important, "; \n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, "; \n direction: ").concat(this.config.direction || 'ltr', ";\n }\n .message.user .message-bubble { \n background: ").concat(userBubbleBg).concat(important, "; \n color: ").concat(userBubbleTextColor).concat(important, "; \n }\n .message.agent .message-bubble { \n background: ").concat(agentBubbleBg).concat(important, "; \n color: ").concat(agentBubbleTextColor).concat(important, "; \n border: ").concat(agentBubbleBorder).concat(important, "; \n }\n\n .message.user { \n align-self: ").concat(this.config.direction === 'rtl' ? 'flex-start' : 'flex-end').concat(important, "; \n }\n .message.agent { \n align-self: ").concat(this.config.direction === 'rtl' ? 'flex-end' : 'flex-start').concat(important, "; \n }\n .message .message-bubble { \n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left', " !important; \n }\n ").concat(this.config.direction === 'rtl' ? "\n .message-bubble {\n text-align: right !important;\n }\n " : '', "\n .message-avatar { \n width: ").concat(avatarSize).concat(important, "; \n height: ").concat(avatarSize).concat(important, "; \n min-width: ").concat(avatarSize).concat(important, "; \n border-radius: 50%").concat(important, "; \n display: flex").concat(important, "; \n align-items: center").concat(important, "; \n justify-content: center").concat(important, "; \n flex-shrink: 0").concat(important, "; \n color: inherit").concat(important, "; \n font-size: ").concat(useVoiceTheme ? '14' : '20', "px").concat(important, "; \n line-height: 1").concat(important, "; \n background: transparent").concat(important, "; \n border: none").concat(important, "; \n box-sizing: border-box").concat(important, "; \n }\n .message-avatar.user { background: ").concat(avatarUserBg).concat(important, "; color: ").concat(avatarUserColor).concat(important, "; }\n .message-avatar.agent { background: ").concat(avatarAgentBg).concat(important, "; }\n \n .message.system {\n background: ").concat(messages.systemBackgroundColor, ";\n align-self: flex-start").concat(important, ";\n }\n .message.error {\n background: ").concat(messages.errorBackgroundColor, ";\n align-self: flex-start").concat(important, ";\n }\n \n .input-container {\n display: flex").concat(important, ";\n gap: 8px").concat(important, ";\n padding: 12px 16px").concat(important, ";\n background: ").concat(inputContainerBg).concat(important, ";\n border-top: 1px solid ").concat(inputContainerBorderTop).concat(important, ";\n align-items: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n flex-direction: ").concat(this.config.direction === 'rtl' ? 'row-reverse' : 'row').concat(important, ";\n }\n \n .input-wrapper {\n position: relative").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n }\n \n .message-input {\n width: 100%").concat(important, ";\n min-height: ").concat(TEXT_INPUT_MIN_HEIGHT_PX, "px").concat(important, ";\n max-height: ").concat(TEXT_INPUT_MAX_HEIGHT_PX, "px").concat(important, ";\n padding: ").concat(inputPadding, ";\n border: 1px solid ").concat(inputBorderColor, ";\n border-radius: ").concat(inputBorderRadius, "px;\n font-size: ").concat(inputFontSize, ";\n font-family: inherit").concat(important, ";\n line-height: 1.4").concat(important, ";\n resize: none").concat(important, ";\n overflow-y: auto").concat(important, ";\n background: ").concat(inputBackgroundColor, ";\n color: ").concat(inputTextColor, ";\n vertical-align: top").concat(important, ";\n margin: 0").concat(important, ";\n display: block").concat(important, ";\n white-space: pre-wrap").concat(important, ";\n word-wrap: break-word").concat(important, ";\n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, ";\n direction: ").concat(this.config.direction || 'ltr', ";\n -webkit-appearance: none").concat(important, ";\n appearance: none").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n \n .message-input:focus {\n outline: none").concat(important, ";\n border-color: ").concat(inputFocusColor, ";\n background: ").concat(inputFocusBg).concat(important, ";\n box-shadow: ").concat(inputFocusBoxShadow, ";\n }\n \n .message-input::placeholder {\n color: ").concat(placeholderColor).concat(important, ";\n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, ";\n }\n \n .send-button {\n width: 44px").concat(important, ";\n height: 44px").concat(important, ";\n border-radius: 50%").concat(important, ";\n border: none").concat(important, ";\n background: ").concat(sendButtonColor, ";\n color: ").concat(sendButtonTextColor, ";\n font-size: ").concat(this.config.sendButtonFontSize || ((_this$config$panel15 = this.config.panel) === null || _this$config$panel15 === void 0 ? void 0 : _this$config$panel15.sendButtonFontSize) || '20px', ";\n font-weight: ").concat(this.config.sendButtonFontWeight || ((_this$config$panel16 = this.config.panel) === null || _this$config$panel16 === void 0 ? void 0 : _this$config$panel16.sendButtonFontWeight) || '500', ";\n cursor: pointer").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n transition: all 0.2s ease").concat(important, ";\n box-shadow: 0 4px 12px rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", 0.32)").concat(important, ";\n }\n \n .send-button:hover:not(:disabled) {\n background: ").concat(sendButtonHoverColor, ";\n transform: scale(1.05)").concat(important, ";\n box-shadow: 0 6px 16px rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", 0.42)").concat(important, ";\n }\n \n .send-button-hint {\n width: 100%").concat(important, ";\n text-align: center").concat(important, ";\n margin-top: 4px").concat(important, ";\n }\n \n .send-button:disabled {\n opacity: 0.5").concat(important, ";\n cursor: not-allowed").concat(important, ";\n }\n \n .typing-indicator {\n display: inline-flex").concat(important, ";\n gap: 4px").concat(important, ";\n align-items: center").concat(important, ";\n }\n \n .typing-dot {\n width: 6px").concat(important, ";\n height: 6px").concat(important, ";\n border-radius: 50%").concat(important, ";\n background: rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", ").concat(typingDotAlpha, ")").concat(important, ";\n animation: typingDot 1.4s ease-in-out infinite").concat(important, ";\n }\n \n .typing-dot:nth-child(2) { animation-delay: 0.2s").concat(important, "; }\n .typing-dot:nth-child(3) { animation-delay: 0.4s").concat(important, "; }\n \n @keyframes typingDot {\n 0%, 60%, 100% { transform: translateY(0); opacity: 0.7; }\n 30% { transform: translateY(-8px); opacity: 1; }\n }\n \n .error-message {\n padding: 12px").concat(important, ";\n background: ").concat(errorBubbleBg, ";\n border-radius: ").concat(messages.borderRadius, "px;\n color: ").concat(errorBubbleColor).concat(important, ";\n border: ").concat(errorBubbleBorder).concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n margin: 8px 0").concat(important, ";\n }\n \n ").concat(useVoiceTheme ? "\n #textInterface.active .input-container .send-button-hint {\n color: rgba(255,255,255,0.72)".concat(important, ";\n }\n ") : '', "\n \n @media (max-width: 768px) {\n #messagesContainer {\n padding: 12px").concat(important, ";\n gap: 12px").concat(important, ";\n }\n \n .message-bubble {\n max-width: 85%").concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n padding: 12px 14px").concat(important, ";\n }\n \n .text-input-container {\n padding: 10px").concat(important, ";\n gap: 8px").concat(important, ";\n }\n \n #text-chat-input {\n font-size: 16px !important; /* Prevents iOS zoom on focus */\n padding: 10px 14px").concat(important, ";\n min-height: 44px").concat(important, ";\n }\n \n #text-chat-send {\n min-width: 56px").concat(important, ";\n min-height: 44px").concat(important, ";\n width: 56px").concat(important, ";\n height: 44px").concat(important, ";\n }\n \n .empty-state-icon {\n font-size: 44px").concat(important, ";\n }\n \n .empty-state-title {\n font-size: 20px").concat(important, ";\n }\n \n .empty-state-text {\n font-size: 14px").concat(important, ";\n }\n }\n \n @media (max-width: 480px) {\n #messagesContainer {\n padding: 10px").concat(important, ";\n gap: 10px").concat(important, ";\n }\n \n .message-bubble {\n max-width: 90%").concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n padding: 10px 12px").concat(important, ";\n }\n \n .text-input-container {\n padding: 8px").concat(important, ";\n }\n \n #text-chat-input {\n font-size: 16px !important;\n padding: 8px 12px").concat(important, ";\n }\n }\n ");
35338
36247
  }
35339
36248
 
35340
36249
  /**
@@ -37412,6 +38321,7 @@ var VoiceInterface = /*#__PURE__*/function () {
37412
38321
  clearInterval(this.callTimerInterval);
37413
38322
  this.callTimerInterval = null;
37414
38323
  }
38324
+ this.callStartTime = null;
37415
38325
 
37416
38326
  // Hide active state, show idle state first
37417
38327
  activeState = this.shadowRoot.getElementById('voiceActiveState');
@@ -37580,6 +38490,10 @@ var VoiceInterface = /*#__PURE__*/function () {
37580
38490
  clearInterval(this.callTimerInterval);
37581
38491
  this.callTimerInterval = null;
37582
38492
  }
38493
+ // Reset the start time so the next call's timer block (gated on !callStartTime)
38494
+ // actually restarts the interval. Without this, the timer only ever runs for the
38495
+ // first call and stays stuck at 00:00 on every subsequent call.
38496
+ this.callStartTime = null;
37583
38497
 
37584
38498
  // Clean up text inject timeouts and handlers (desktop)
37585
38499
  if (this._textInjectTimeout) {
@@ -40327,6 +41241,21 @@ var Templates = /*#__PURE__*/function () {
40327
41241
  return this.voiceInterface.getTooltip(key);
40328
41242
  }
40329
41243
 
41244
+ /**
41245
+ * Shared "About" info ("i") button markup. Opens the About dialog
41246
+ * (SDK version + last conversation id) wired by TTPChatWidget.
41247
+ * @param {string} [extraClass] - extra class(es) for positioning per view
41248
+ * @returns {string}
41249
+ */
41250
+ }, {
41251
+ key: "infoButton",
41252
+ value: function infoButton() {
41253
+ var extraClass = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
41254
+ var cls = extraClass ? "ttp-info-btn ".concat(extraClass) : 'ttp-info-btn';
41255
+ var label = this.t('aboutTitle') || 'About';
41256
+ return "<button type=\"button\" class=\"".concat(cls, "\" aria-label=\"").concat(escapeHtmlAttr(label), "\" title=\"").concat(escapeHtmlAttr(label), "\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"9\"/>\n <line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"16\"/>\n <circle cx=\"12\" cy=\"7.7\" r=\"1.05\" fill=\"currentColor\" stroke=\"none\"/>\n </svg>\n </button>");
41257
+ }
41258
+
40330
41259
  /**
40331
41260
  * Generate HTML for voice interface.
40332
41261
  * Automatically detects mobile vs desktop based on voiceInterface.isMobile
@@ -40357,7 +41286,7 @@ var Templates = /*#__PURE__*/function () {
40357
41286
  var transcriptPlaceholder = this.t('transcriptWillAppear') || '';
40358
41287
  var transcriptDir = (0,_rtlText_js__WEBPACK_IMPORTED_MODULE_0__.dirForTranscriptSnippet)(transcriptPlaceholder, this.config);
40359
41288
  var voiceInputDir = (0,_rtlText_js__WEBPACK_IMPORTED_MODULE_0__.dirForAssistantStreamingText)(this.config);
40360
- return "<div class=\"voice-interface\" id=\"voiceInterface\">\n <!-- Idle View -->\n <div id=\"voiceIdleState\">\n <div class=\"ttp-hero\">\n <div class=\"ttp-header\">\n <div class=\"ttp-agent\">\n <div class=\"ttp-avatar-wrap\">\n <div class=\"".concat(idleAvatarClass, "\">").concat(idleAvatarInner, "</div>\n <div class=\"ttp-online-dot\"></div>\n </div>\n <div>\n <div class=\"ttp-agent-name\">").concat(agentName, "</div>\n <div class=\"ttp-agent-role\">").concat(agentRole, "</div>\n </div>\n </div>\n <button type=\"button\" class=\"ttp-close-btn\" id=\"ttpCloseIdle\" aria-label=\"Close widget\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M10 2L2 10M2 2l8 8\"/>\n </svg>\n </button>\n </div>\n <div class=\"ttp-headline\">").concat(headline, "</div>\n <div class=\"ttp-subline\">").concat(subline, "</div>\n </div>\n\n <div class=\"ttp-body\">\n <button type=\"button\" class=\"ttp-btn-primary\" id=\"startCallBtn\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"").concat(this.config.startCallButtonTextColor || 'white', "\" stroke-width=\"2\">\n <path d=\"M12 2a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V5a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2M12 19v3M8 22h8\"/>\n </svg>\n ").concat(this.getText('startCallButtonText', 'startCall') || 'Start Voice Call', "\n </button>\n ").concat((((_this$config$behavior = this.config.behavior) === null || _this$config$behavior === void 0 ? void 0 : _this$config$behavior.mode) || 'unified') !== 'voice-only' ? "\n <button type=\"button\" class=\"ttp-btn-secondary\" id=\"startTextBtn\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n ".concat(this.config.sendMessageText || this.getText('sendMessageText', 'sendMessage') || 'Send a Message', "\n </button>\n ") : '', "\n ").concat((_this$config$whatsapp = this.config.whatsapp) !== null && _this$config$whatsapp !== void 0 && _this$config$whatsapp.number ? "\n <a class=\"ttp-btn-wa\" id=\"ttpWhatsAppBtn\"\n href=\"https://wa.me/".concat(this.config.whatsapp.number).concat(this.config.whatsapp.text ? '?text=' + encodeURIComponent(this.config.whatsapp.text) : '', "\"\n target=\"_blank\" rel=\"noopener\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"#25d366\">\n <path d=\"M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.655-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z\"/>\n </svg>\n WhatsApp\n </a>\n ") : '', "\n </div>\n </div>\n\n <!-- Active Call View -->\n <div id=\"voiceActiveState\" style=\"display: none;\">\n <!-- Full voice section (hidden when items/rooms are shown) -->\n <div class=\"desktop-voice-section\" id=\"desktopVoiceSection\">\n <div class=\"ttp-call-hero\">\n <div class=\"ttp-call-topbar\">\n <div class=\"ttp-rec\">\n <div class=\"ttp-rec-dot\"></div>\n <span class=\"ttp-timer\" id=\"desktopTimerText\">00:00</span>\n </div>\n <span class=\"ttp-call-label\">Voice call active</span>\n <button type=\"button\" class=\"ttp-close-btn\" id=\"ttpCloseActive\" aria-label=\"Close widget\">\n <svg width=\"9\" height=\"9\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M10 2L2 10M2 2l8 8\"/>\n </svg>\n </button>\n </div>\n\n <div class=\"ttp-orb-wrap\">\n <div class=\"ttp-orb-rings\">\n <div class=\"ttp-ring ttp-ring-1\"></div>\n <div class=\"ttp-ring ttp-ring-2\"></div>\n <div class=\"ttp-orb\" id=\"desktopMainWaveform\">\n <div class=\"ttp-wave\" id=\"ttp-wave\"></div>\n </div>\n </div>\n <div class=\"ttp-listen-label\" id=\"desktopStatusText\">").concat(this.t('listening') || 'Listening to you...', "</div>\n </div>\n </div>\n\n <div class=\"ttp-controls\">\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopMuteBtn\" title=\"").concat(this.getTooltip('mute'), "\" aria-label=\"Mute microphone\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-mic-icon\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-mic-off-icon\" style=\"display: none; position: absolute;\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopPauseBtn\" title=\"Pause call\" aria-label=\"Pause call\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"desktop-pause-icon\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\" class=\"desktop-play-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"6,4 20,12 6,20\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopSpeakerBtn\" title=\"").concat(this.getTooltip('speaker'), "\" aria-label=\"Toggle speaker\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-speaker-icon\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-speaker-off-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-end-btn\" id=\"desktopEndCallBtn\" title=\"").concat(this.getTooltip('endCall'), "\" aria-label=\"End call\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.99 12 19.79 19.79 0 0 1 1.97 3.4 2 2 0 0 1 3.95 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"/>\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Compact voice section (shown when items/rooms are visible) -->\n <div class=\"compact-voice-section\" id=\"compactVoiceSection\" style=\"display: none;\">\n <div class=\"compact-left\">\n <div class=\"compact-avatar\" id=\"desktopAvatarCompact\">\n <div class=\"ttp-orb compact-orb\" id=\"desktopMainWaveformCompact\">\n <div class=\"ttp-wave\"></div>\n </div>\n </div>\n <div class=\"compact-info\">\n <div class=\"compact-timer\" id=\"desktopTimerCompact\">\n <span class=\"ttp-rec-dot\"></span>\n <span id=\"compactTimerText\">00:00</span>\n </div>\n <div class=\"compact-status\" id=\"desktopStatusCompact\">\n <span id=\"compactStatusText\">").concat(this.t('listening') || 'Listening...', "</span>\n </div>\n </div>\n </div>\n <div class=\"compact-controls\">\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopMuteBtnCompact\" title=\"").concat(this.getTooltip('mute'), "\" aria-label=\"Mute microphone\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-mic-icon\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-mic-off-icon\" style=\"display: none; position: absolute;\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopPauseBtnCompact\" title=\"Pause call\" aria-label=\"Pause call\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"desktop-pause-icon\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\" class=\"desktop-play-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"6,4 20,12 6,20\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopSpeakerBtnCompact\" title=\"").concat(this.getTooltip('speaker'), "\" aria-label=\"Toggle speaker\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-speaker-icon\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-speaker-off-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn danger\" id=\"desktopEndCallBtnCompact\" title=\"").concat(this.getTooltip('endCall'), "\" aria-label=\"End call\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" style=\"overflow: visible;\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.99 12 19.79 19.79 0 0 1 1.97 3.4 2 2 0 0 1 3.95 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\" transform=\"rotate(135 12 12)\"/>\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Transcript -->\n <div class=\"ttp-transcript desktop-conversation-panel\" id=\"desktopConversationPanel\" dir=\"").concat(textDir, "\">\n <div class=\"ttp-transcript-hdr\" id=\"conversationHeader\">\n <span class=\"ttp-live-label\">Live</span>\n <span class=\"ttp-toggle-text\" id=\"conversationToggleText\">Show history</span>\n <div class=\"ttp-dots\">\n <div class=\"ttp-dot\"></div>\n <div class=\"ttp-dot\"></div>\n <div class=\"ttp-dot\"></div>\n </div>\n </div>\n <div class=\"live-transcript-collapsed\" id=\"liveTranscriptCollapsed\">\n <div class=\"ttp-transcript-text\" id=\"liveTextCollapsed\" dir=\"").concat(transcriptDir, "\">\n ").concat(this.t('transcriptWillAppear') || 'Transcript will appear here...', "<span class=\"ttp-cursor\"></span>\n </div>\n </div>\n <div class=\"conversation-history\" id=\"conversationHistory\">\n <div class=\"conversation-messages\" id=\"conversationMessages\"></div>\n <div class=\"live-message-row\" id=\"liveMessageRow\" style=\"display: none;\">\n <div class=\"message-bubble\" dir=\"").concat(transcriptDir, "\">\n <span class=\"live-badge\">Live</span>\n <span id=\"liveMessageText\"></span><span class=\"ttp-cursor\"></span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Type row -->\n <div class=\"ttp-type-row voice-text-input-area\">\n <input class=\"ttp-input\" type=\"text\" id=\"voiceTextInput\" dir=\"").concat(voiceInputDir, "\" placeholder=\"").concat(this.getText('inputPlaceholder', 'typeMessage') || 'Or type here…', "\" aria-label=\"Type a message\" />\n <button type=\"button\" class=\"ttp-send-btn\" id=\"voiceSendBtn\" aria-label=\"Send message\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"/>\n </svg>\n </button>\n </div>\n </div>\n </div>");
41289
+ return "<div class=\"voice-interface\" id=\"voiceInterface\">\n <!-- Idle View -->\n <div id=\"voiceIdleState\">\n <div class=\"ttp-hero\">\n <div class=\"ttp-header\">\n <div class=\"ttp-agent\">\n <div class=\"ttp-avatar-wrap\">\n <div class=\"".concat(idleAvatarClass, "\">").concat(idleAvatarInner, "</div>\n <div class=\"ttp-online-dot\"></div>\n </div>\n <div>\n <div class=\"ttp-agent-name\">").concat(agentName, "</div>\n <div class=\"ttp-agent-role\">").concat(agentRole, "</div>\n </div>\n </div>\n <div class=\"ttp-header-actions\">\n ").concat(this.infoButton(), "\n <button type=\"button\" class=\"ttp-close-btn\" id=\"ttpCloseIdle\" aria-label=\"Close widget\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M10 2L2 10M2 2l8 8\"/>\n </svg>\n </button>\n </div>\n </div>\n <div class=\"ttp-headline\">").concat(headline, "</div>\n <div class=\"ttp-subline\">").concat(subline, "</div>\n </div>\n\n <div class=\"ttp-body\">\n <button type=\"button\" class=\"ttp-btn-primary\" id=\"startCallBtn\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"").concat(this.config.startCallButtonTextColor || 'white', "\" stroke-width=\"2\">\n <path d=\"M12 2a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V5a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2M12 19v3M8 22h8\"/>\n </svg>\n ").concat(this.getText('startCallButtonText', 'startCall') || 'Start Voice Call', "\n </button>\n ").concat((((_this$config$behavior = this.config.behavior) === null || _this$config$behavior === void 0 ? void 0 : _this$config$behavior.mode) || 'unified') !== 'voice-only' ? "\n <button type=\"button\" class=\"ttp-btn-secondary\" id=\"startTextBtn\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n ".concat(this.config.sendMessageText || this.getText('sendMessageText', 'sendMessage') || 'Send a Message', "\n </button>\n ") : '', "\n ").concat((_this$config$whatsapp = this.config.whatsapp) !== null && _this$config$whatsapp !== void 0 && _this$config$whatsapp.number ? "\n <a class=\"ttp-btn-wa\" id=\"ttpWhatsAppBtn\"\n href=\"https://wa.me/".concat(this.config.whatsapp.number).concat(this.config.whatsapp.text ? '?text=' + encodeURIComponent(this.config.whatsapp.text) : '', "\"\n target=\"_blank\" rel=\"noopener\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"#25d366\">\n <path d=\"M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.655-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z\"/>\n </svg>\n WhatsApp\n </a>\n ") : '', "\n </div>\n </div>\n\n <!-- Active Call View -->\n <div id=\"voiceActiveState\" style=\"display: none;\">\n <!-- Full voice section (hidden when items/rooms are shown) -->\n <div class=\"desktop-voice-section\" id=\"desktopVoiceSection\">\n <div class=\"ttp-call-hero\">\n <div class=\"ttp-call-topbar\">\n <div class=\"ttp-rec\">\n <div class=\"ttp-rec-dot\"></div>\n <span class=\"ttp-timer\" id=\"desktopTimerText\">00:00</span>\n </div>\n <span class=\"ttp-call-label\">Voice call active</span>\n <div class=\"ttp-header-actions\">\n ").concat(this.infoButton(), "\n <button type=\"button\" class=\"ttp-close-btn\" id=\"ttpCloseActive\" aria-label=\"Close widget\">\n <svg width=\"9\" height=\"9\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M10 2L2 10M2 2l8 8\"/>\n </svg>\n </button>\n </div>\n </div>\n\n <div class=\"ttp-orb-wrap\">\n <div class=\"ttp-orb-rings\">\n <div class=\"ttp-ring ttp-ring-1\"></div>\n <div class=\"ttp-ring ttp-ring-2\"></div>\n <div class=\"ttp-orb\" id=\"desktopMainWaveform\">\n <div class=\"ttp-wave\" id=\"ttp-wave\"></div>\n </div>\n </div>\n <div class=\"ttp-listen-label\" id=\"desktopStatusText\">").concat(this.t('listening') || 'Listening to you...', "</div>\n </div>\n </div>\n\n <div class=\"ttp-controls\">\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopMuteBtn\" title=\"").concat(this.getTooltip('mute'), "\" aria-label=\"Mute microphone\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-mic-icon\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-mic-off-icon\" style=\"display: none; position: absolute;\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopPauseBtn\" title=\"Pause call\" aria-label=\"Pause call\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"desktop-pause-icon\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\" class=\"desktop-play-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"6,4 20,12 6,20\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopSpeakerBtn\" title=\"").concat(this.getTooltip('speaker'), "\" aria-label=\"Toggle speaker\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-speaker-icon\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-speaker-off-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-end-btn\" id=\"desktopEndCallBtn\" title=\"").concat(this.getTooltip('endCall'), "\" aria-label=\"End call\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.99 12 19.79 19.79 0 0 1 1.97 3.4 2 2 0 0 1 3.95 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"/>\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Compact voice section (shown when items/rooms are visible) -->\n <div class=\"compact-voice-section\" id=\"compactVoiceSection\" style=\"display: none;\">\n <div class=\"compact-left\">\n <div class=\"compact-avatar\" id=\"desktopAvatarCompact\">\n <div class=\"ttp-orb compact-orb\" id=\"desktopMainWaveformCompact\">\n <div class=\"ttp-wave\"></div>\n </div>\n </div>\n <div class=\"compact-info\">\n <div class=\"compact-timer\" id=\"desktopTimerCompact\">\n <span class=\"ttp-rec-dot\"></span>\n <span id=\"compactTimerText\">00:00</span>\n </div>\n <div class=\"compact-status\" id=\"desktopStatusCompact\">\n <span id=\"compactStatusText\">").concat(this.t('listening') || 'Listening...', "</span>\n </div>\n </div>\n </div>\n <div class=\"compact-controls\">\n ").concat(this.infoButton('ttp-info-btn--onctrl'), "\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopMuteBtnCompact\" title=\"").concat(this.getTooltip('mute'), "\" aria-label=\"Mute microphone\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-mic-icon\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-mic-off-icon\" style=\"display: none; position: absolute;\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopPauseBtnCompact\" title=\"Pause call\" aria-label=\"Pause call\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"desktop-pause-icon\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\" class=\"desktop-play-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"6,4 20,12 6,20\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopSpeakerBtnCompact\" title=\"").concat(this.getTooltip('speaker'), "\" aria-label=\"Toggle speaker\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-speaker-icon\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-speaker-off-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn danger\" id=\"desktopEndCallBtnCompact\" title=\"").concat(this.getTooltip('endCall'), "\" aria-label=\"End call\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" style=\"overflow: visible;\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.99 12 19.79 19.79 0 0 1 1.97 3.4 2 2 0 0 1 3.95 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\" transform=\"rotate(135 12 12)\"/>\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Transcript -->\n <div class=\"ttp-transcript desktop-conversation-panel\" id=\"desktopConversationPanel\" dir=\"").concat(textDir, "\">\n <div class=\"ttp-transcript-hdr\" id=\"conversationHeader\">\n <span class=\"ttp-live-label\">Live</span>\n <span class=\"ttp-toggle-text\" id=\"conversationToggleText\">Show history</span>\n <div class=\"ttp-dots\">\n <div class=\"ttp-dot\"></div>\n <div class=\"ttp-dot\"></div>\n <div class=\"ttp-dot\"></div>\n </div>\n </div>\n <div class=\"live-transcript-collapsed\" id=\"liveTranscriptCollapsed\">\n <div class=\"ttp-transcript-text\" id=\"liveTextCollapsed\" dir=\"").concat(transcriptDir, "\">\n ").concat(this.t('transcriptWillAppear') || 'Transcript will appear here...', "<span class=\"ttp-cursor\"></span>\n </div>\n </div>\n <div class=\"conversation-history\" id=\"conversationHistory\">\n <div class=\"conversation-messages\" id=\"conversationMessages\"></div>\n <div class=\"live-message-row\" id=\"liveMessageRow\" style=\"display: none;\">\n <div class=\"message-bubble\" dir=\"").concat(transcriptDir, "\">\n <span class=\"live-badge\">Live</span>\n <span id=\"liveMessageText\"></span><span class=\"ttp-cursor\"></span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Type row -->\n <div class=\"ttp-type-row voice-text-input-area\">\n <input class=\"ttp-input\" type=\"text\" id=\"voiceTextInput\" dir=\"").concat(voiceInputDir, "\" placeholder=\"").concat(this.getText('inputPlaceholder', 'typeMessage') || 'Or type here…', "\" aria-label=\"Type a message\" />\n <button type=\"button\" class=\"ttp-send-btn\" id=\"voiceSendBtn\" aria-label=\"Send message\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"/>\n </svg>\n </button>\n </div>\n </div>\n </div>");
40361
41290
  }
40362
41291
 
40363
41292
  /**
@@ -40374,7 +41303,7 @@ var Templates = /*#__PURE__*/function () {
40374
41303
  var headerAvatarUrl = resolveIdleHeaderAvatarUrl(this.config);
40375
41304
  var mobileAvatarInner = headerAvatarUrl ? "<img src=\"".concat(escapeHtmlAttr(headerAvatarUrl), "\" alt=\"\" class=\"voice-avatar-img\" />") : '🤖';
40376
41305
  var mobileAvatarClass = headerAvatarUrl ? 'voice-avatar voice-avatar--image' : 'voice-avatar';
40377
- return "<div class=\"voice-interface mobile-voice-interface\" id=\"voiceInterface\" dir=\"".concat(textDir, "\">\n <!-- Before Call State (same as desktop) -->\n <div id=\"voiceIdleState\">\n <div class=\"").concat(mobileAvatarClass, "\" id=\"voiceAvatar\">").concat(mobileAvatarInner, "</div>\n <div class=\"voice-status\">\n <div class=\"voice-status-title\">").concat(this.getText('startCallTitle', 'clickToStartCall'), "</div>\n <div class=\"voice-status-subtitle\">").concat(this.getText('startCallSubtitle', 'realTimeVoice'), "</div>\n </div>\n <button type=\"button\" class=\"start-call-btn\" id=\"startCallBtn\">\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M20.01 15.38c-1.23 0-2.42-.2-3.53-.56-.35-.12-.74-.03-1.01.24l-1.57 1.97c-2.83-1.35-5.48-3.9-6.89-6.83l1.95-1.66c.27-.28.35-.67.24-1.02-.37-1.11-.56-2.3-.56-3.53 0-.54-.45-.99-.99-.99H4.19C3.65 3 3 3.24 3 3.99 3 13.28 10.73 21 20.01 21c.71 0 .99-.63.99-1.18v-3.45c0-.54-.45-.99-.99-.99z\"/>\n </svg>\n <span>").concat(this.getText('startCallButtonText', 'startCall'), "</span>\n </button>\n </div>\n \n <!-- Mobile Active Call State - Hidden placeholder (actual bar will be appended to body) -->\n <div id=\"voiceActiveState\" class=\"mobile-active-state\" style=\"display: none;\">\n <!-- Duration Badge -->\n <div class=\"mobile-duration-badge\" id=\"mobileDurationBadge\">\n <div class=\"mobile-duration-dot\"></div>\n <span id=\"mobileDurationText\">00:00</span>\n </div>\n \n <!-- Main Bar -->\n <div class=\"mobile-voice-bar\">\n <!-- Top Row: Status, Waveform, Controls -->\n <div class=\"mobile-top-row\">\n <!-- Status Indicator -->\n <div class=\"mobile-status-indicator\">\n <div class=\"mobile-status-dot\" id=\"mobileStatusDot\"></div>\n <span class=\"mobile-status-text\" id=\"mobileStatusText\">Listening...</span>\n </div>\n \n <!-- Centered Waveform -->\n <div class=\"mobile-waveform-center\" id=\"mobileWaveform\">\n ").concat(Array(7).fill(0).map(function (_, i) {
41306
+ return "<div class=\"voice-interface mobile-voice-interface\" id=\"voiceInterface\" dir=\"".concat(textDir, "\">\n <!-- Before Call State (same as desktop) -->\n <div id=\"voiceIdleState\">\n ").concat(this.infoButton('ttp-info-btn--floating'), "\n <div class=\"").concat(mobileAvatarClass, "\" id=\"voiceAvatar\">").concat(mobileAvatarInner, "</div>\n <div class=\"voice-status\">\n <div class=\"voice-status-title\">").concat(this.getText('startCallTitle', 'clickToStartCall'), "</div>\n <div class=\"voice-status-subtitle\">").concat(this.getText('startCallSubtitle', 'realTimeVoice'), "</div>\n </div>\n <button type=\"button\" class=\"start-call-btn\" id=\"startCallBtn\">\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M20.01 15.38c-1.23 0-2.42-.2-3.53-.56-.35-.12-.74-.03-1.01.24l-1.57 1.97c-2.83-1.35-5.48-3.9-6.89-6.83l1.95-1.66c.27-.28.35-.67.24-1.02-.37-1.11-.56-2.3-.56-3.53 0-.54-.45-.99-.99-.99H4.19C3.65 3 3 3.24 3 3.99 3 13.28 10.73 21 20.01 21c.71 0 .99-.63.99-1.18v-3.45c0-.54-.45-.99-.99-.99z\"/>\n </svg>\n <span>").concat(this.getText('startCallButtonText', 'startCall'), "</span>\n </button>\n </div>\n \n <!-- Mobile Active Call State - Hidden placeholder (actual bar will be appended to body) -->\n <div id=\"voiceActiveState\" class=\"mobile-active-state\" style=\"display: none;\">\n <!-- Duration Badge -->\n <div class=\"mobile-duration-badge\" id=\"mobileDurationBadge\">\n <div class=\"mobile-duration-dot\"></div>\n <span id=\"mobileDurationText\">00:00</span>\n ").concat(this.infoButton('ttp-info-btn--onbadge'), "\n </div>\n\n <!-- Main Bar -->\n <div class=\"mobile-voice-bar\">\n <!-- Top Row: Status, Waveform, Controls -->\n <div class=\"mobile-top-row\">\n <!-- Status Indicator -->\n <div class=\"mobile-status-indicator\">\n <div class=\"mobile-status-dot\" id=\"mobileStatusDot\"></div>\n <span class=\"mobile-status-text\" id=\"mobileStatusText\">Listening...</span>\n </div>\n \n <!-- Centered Waveform -->\n <div class=\"mobile-waveform-center\" id=\"mobileWaveform\">\n ").concat(Array(7).fill(0).map(function (_, i) {
40378
41307
  return "<div class=\"mobile-waveform-bar\" data-index=\"".concat(i, "\"></div>");
40379
41308
  }).join(''), "\n </div>\n \n <!-- Controls -->\n <div class=\"mobile-controls\">\n <button type=\"button\" class=\"mobile-control-btn\" id=\"mobileMuteBtn\" aria-label=\"Mute microphone\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"mobile-mic-icon\">\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\"/>\n </svg>\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"mobile-mic-off-icon\" style=\"display: none;\">\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\"/>\n <line x1=\"4\" y1=\"4\" x2=\"20\" y2=\"20\" stroke=\"#ef4444\" stroke-width=\"1.5\" opacity=\"0.85\"/>\n </svg>\n </button>\n \n <button type=\"button\" class=\"mobile-control-btn\" id=\"mobilePauseBtn\" aria-label=\"Pause call\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2\" class=\"mobile-pause-icon\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"#fff\" stroke=\"none\" class=\"mobile-play-icon\" style=\"display: none;\">\n <polygon points=\"6,4 20,12 6,20\"/>\n </svg>\n </button>\n\n <button type=\"button\" class=\"mobile-control-btn\" id=\"mobileSpeakerBtn\" aria-label=\"Toggle speaker\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"mobile-speaker-icon\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n </svg>\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"mobile-speaker-off-icon\" style=\"display: none;\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n <line x1=\"4\" y1=\"4\" x2=\"20\" y2=\"20\" stroke=\"#ef4444\" stroke-width=\"1.5\" opacity=\"0.85\"/>\n </svg>\n </button>\n\n <button type=\"button\" class=\"mobile-end-call-btn\" id=\"mobileEndCallBtn\" aria-label=\"End call\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M10.68 13.31a16 16 0 0 0 3.41 2.6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7 2 2 0 0 1 1.72 2v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.42 19.42 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.63A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91\"/>\n <line x1=\"22\" x2=\"2\" y1=\"2\" y2=\"22\"/>\n </svg>\n </button>\n </div>\n </div>\n \n <!-- Bottom Row: Transcript (expandable) -->\n <button type=\"button\" class=\"mobile-transcript-row\" id=\"mobileTranscriptRow\">\n <p class=\"mobile-transcript-text\" id=\"mobileTranscriptText\" dir=\"").concat(transcriptDir, "\">").concat(this.t('transcriptWillAppear'), "</p>\n <div class=\"mobile-transcript-footer\">\n <span class=\"mobile-expand-hint\">tap to expand & type</span>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"opacity: 0.6;\">\n <path d=\"M7 17L17 7M17 7H7M17 7V17\"/>\n </svg>\n </div>\n </button>\n </div>\n </div>\n \n <!-- Expanded Transcript Overlay -->\n <div class=\"mobile-transcript-overlay\" id=\"mobileTranscriptOverlay\">\n <div class=\"mobile-expanded-transcript\" id=\"mobileExpandedTranscript\">\n <!-- Header -->\n <div class=\"mobile-transcript-header\">\n <div class=\"mobile-header-left\">\n <div class=\"mobile-header-status\">\n <div class=\"mobile-header-status-dot\"></div>\n <span class=\"mobile-header-status-text\" id=\"mobileHeaderStatusText\">Listening...</span>\n <span class=\"mobile-header-duration\" id=\"mobileHeaderDuration\">00:00</span>\n </div>\n <span class=\"mobile-transcript-label\">CONVERSATION</span>\n </div>\n <button type=\"button\" class=\"mobile-close-transcript-btn\" id=\"mobileCloseTranscriptBtn\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n </div>\n \n <!-- Messages Container -->\n <div class=\"mobile-messages-container\" id=\"mobileMessagesContainer\">\n <!-- Messages will be dynamically added here -->\n </div>\n \n <!-- Text Input Area -->\n <div class=\"mobile-input-area\">\n <div class=\"mobile-input-wrapper\">\n <input\n type=\"text\"\n placeholder=\"Type a message...\"\n id=\"mobileTextInput\"\n class=\"mobile-text-input\"\n dir=\"").concat(voiceInputDir, "\"\n />\n <button type=\"button\" class=\"mobile-send-btn\" id=\"mobileSendBtn\" disabled>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\"/>\n </svg>\n </button>\n </div>\n <p class=\"mobile-input-hint\">\uD83C\uDF99\uFE0F Voice is still active \u2022 Type or speak</p>\n </div>\n </div>\n </div>\n </div>");
40380
41309
  }
@@ -41219,7 +42148,11 @@ __webpack_require__.r(__webpack_exports__);
41219
42148
  "typeMessage": "Type your message...",
41220
42149
  "sendMessageAria": "Send message",
41221
42150
  "domainNotValidated": "Domain not validated",
41222
- "domainErrorMessage": "This domain is not whitelisted. Please contact the administrator to whitelist your website URL."
42151
+ "domainErrorMessage": "This domain is not whitelisted. Please contact the administrator to whitelist your website URL.",
42152
+ "aboutTitle": "About",
42153
+ "aboutVersion": "SDK version",
42154
+ "aboutConversationId": "Last conversation ID",
42155
+ "aboutNoConversation": "No conversation yet"
41223
42156
  },
41224
42157
  "he": {
41225
42158
  "landingTitle": "איך תרצה לתקשר?",
@@ -41252,7 +42185,11 @@ __webpack_require__.r(__webpack_exports__);
41252
42185
  "typeMessage": "הקלד הודעה...",
41253
42186
  "sendMessageAria": "שלח הודעה",
41254
42187
  "domainNotValidated": "דומיין לא מאומת",
41255
- "domainErrorMessage": "דומיין זה לא ברשימת המורשים. אנא פנה למנהל המערכת כדי להוסיף את כתובת האתר שלך לרשימה."
42188
+ "domainErrorMessage": "דומיין זה לא ברשימת המורשים. אנא פנה למנהל המערכת כדי להוסיף את כתובת האתר שלך לרשימה.",
42189
+ "aboutTitle": "אודות",
42190
+ "aboutVersion": "גרסת SDK",
42191
+ "aboutConversationId": "מזהה שיחה אחרון",
42192
+ "aboutNoConversation": "אין שיחה עדיין"
41256
42193
  },
41257
42194
  "ar": {
41258
42195
  "landingTitle": "كيف تريد التواصل؟",
@@ -41285,7 +42222,11 @@ __webpack_require__.r(__webpack_exports__);
41285
42222
  "typeMessage": "اكتب رسالة...",
41286
42223
  "sendMessageAria": "إرسال رسالة",
41287
42224
  "domainNotValidated": "النطاق غير معتمد",
41288
- "domainErrorMessage": "هذا النطاق غير مسموح به. يرجى الاتصال بالمسؤول لإضافة عنوان موقع الويب الخاص بك إلى القائمة."
42225
+ "domainErrorMessage": "هذا النطاق غير مسموح به. يرجى الاتصال بالمسؤول لإضافة عنوان موقع الويب الخاص بك إلى القائمة.",
42226
+ "aboutTitle": "حول",
42227
+ "aboutVersion": "إصدار SDK",
42228
+ "aboutConversationId": "معرّف آخر محادثة",
42229
+ "aboutNoConversation": "لا توجد محادثة بعد"
41289
42230
  },
41290
42231
  "ru": {
41291
42232
  "landingTitle": "Как вы хотите общаться?",
@@ -41318,7 +42259,11 @@ __webpack_require__.r(__webpack_exports__);
41318
42259
  "typeMessage": "Введите сообщение...",
41319
42260
  "sendMessageAria": "Отправить сообщение",
41320
42261
  "domainNotValidated": "Домен не проверен",
41321
- "domainErrorMessage": "Этот домен не в белом списке. Пожалуйста, свяжитесь с администратором, чтобы добавить URL вашего веб-сайта в список."
42262
+ "domainErrorMessage": "Этот домен не в белом списке. Пожалуйста, свяжитесь с администратором, чтобы добавить URL вашего веб-сайта в список.",
42263
+ "aboutTitle": "О приложении",
42264
+ "aboutVersion": "Версия SDK",
42265
+ "aboutConversationId": "ID последнего разговора",
42266
+ "aboutNoConversation": "Разговоров пока нет"
41322
42267
  },
41323
42268
  "es": {
41324
42269
  "landingTitle": "¿Cómo te gustaría comunicarte?",
@@ -41351,7 +42296,11 @@ __webpack_require__.r(__webpack_exports__);
41351
42296
  "typeMessage": "Escribe un mensaje...",
41352
42297
  "sendMessageAria": "Enviar mensaje",
41353
42298
  "domainNotValidated": "Dominio no validado",
41354
- "domainErrorMessage": "Este dominio no está en la lista blanca. Por favor, contacte al administrador para agregar la URL de su sitio web a la lista."
42299
+ "domainErrorMessage": "Este dominio no está en la lista blanca. Por favor, contacte al administrador para agregar la URL de su sitio web a la lista.",
42300
+ "aboutTitle": "Acerca de",
42301
+ "aboutVersion": "Versión del SDK",
42302
+ "aboutConversationId": "ID de última conversación",
42303
+ "aboutNoConversation": "Aún no hay conversación"
41355
42304
  },
41356
42305
  "fr": {
41357
42306
  "landingTitle": "Comment souhaitez-vous communiquer?",
@@ -41384,7 +42333,11 @@ __webpack_require__.r(__webpack_exports__);
41384
42333
  "typeMessage": "Tapez votre message...",
41385
42334
  "sendMessageAria": "Envoyer un message",
41386
42335
  "domainNotValidated": "Domaine non validé",
41387
- "domainErrorMessage": "Ce domaine n'est pas sur la liste blanche. Veuillez contacter l'administrateur pour ajouter l'URL de votre site Web à la liste."
42336
+ "domainErrorMessage": "Ce domaine n'est pas sur la liste blanche. Veuillez contacter l'administrateur pour ajouter l'URL de votre site Web à la liste.",
42337
+ "aboutTitle": "À propos",
42338
+ "aboutVersion": "Version du SDK",
42339
+ "aboutConversationId": "ID de la dernière conversation",
42340
+ "aboutNoConversation": "Aucune conversation pour l'instant"
41388
42341
  },
41389
42342
  "de": {
41390
42343
  "landingTitle": "Wie möchten Sie kommunizieren?",
@@ -41417,7 +42370,11 @@ __webpack_require__.r(__webpack_exports__);
41417
42370
  "typeMessage": "Geben Sie eine Nachricht ein...",
41418
42371
  "sendMessageAria": "Nachricht senden",
41419
42372
  "domainNotValidated": "Domain nicht validiert",
41420
- "domainErrorMessage": "Diese Domain steht nicht auf der Whitelist. Bitte kontaktieren Sie den Administrator, um die URL Ihrer Website zur Liste hinzuzufügen."
42373
+ "domainErrorMessage": "Diese Domain steht nicht auf der Whitelist. Bitte kontaktieren Sie den Administrator, um die URL Ihrer Website zur Liste hinzuzufügen.",
42374
+ "aboutTitle": "Über",
42375
+ "aboutVersion": "SDK-Version",
42376
+ "aboutConversationId": "Letzte Konversations-ID",
42377
+ "aboutNoConversation": "Noch keine Konversation"
41421
42378
  }
41422
42379
  });
41423
42380