ttp-agent-sdk 2.45.7 → 2.45.14

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-29T06:35:24.857Z";
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.14";
20307
+ var BUILD_TIME = "2026-06-29T06:35:24.857Z";
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,40 @@ 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, ")"));
25066
+ // Per-segment START signal: this segment's first frame just scheduled (≈ playback start).
25067
+ // Mirrors the per-segment 'segmentDone' (end) event; lets the backend fire speech-synced
25068
+ // actions exactly when THIS line begins playing (vs the coarse, once-per-burst playbackStarted).
25069
+ if (_this4.currentSegmentId != null) {
25070
+ _this4.emit('segmentStarted', {
25071
+ segmentId: _this4.currentSegmentId
25072
+ });
25073
+ }
24862
25074
  _this4.pendingSentenceText = null;
24863
25075
  _this4.pendingSynced = null;
25076
+ _this4.pendingSegmentId = null;
24864
25077
 
24865
25078
  // Start checker if not running
24866
25079
  if (!_this4.isCheckingTranscripts) {
24867
25080
  _this4.startTranscriptChecker();
24868
25081
  }
25082
+ } else if (_this4.sentenceTimings.length > 0) {
25083
+ // Subsequent chunk of the current segment: extend its end on the audio clock.
25084
+ _this4.sentenceTimings[_this4.sentenceTimings.length - 1].endTime = segFrameEnd;
24869
25085
  }
24870
25086
 
24871
25087
  // Schedule this chunk to start at nextStartTime
@@ -24920,8 +25136,10 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
24920
25136
  if (_this4.scheduledBuffers === 0 && _this4.preparedBuffer.length === 0 && _this4.pcmChunkQueue.length === 0 && !_this4._isStopped) {
24921
25137
  _this4.isPlaying = false;
24922
25138
  _this4.isSchedulingFrames = false;
24923
- console.log('🛑 AudioPlayer: Emitting playbackStopped event (all buffers finished)');
24924
- _this4.emit('playbackStopped');
25139
+ console.log('🛑 AudioPlayer: Emitting playbackStopped event (all buffers finished, segmentId: ' + _this4.currentSegmentId + ')');
25140
+ _this4.emit('playbackStopped', {
25141
+ segmentId: _this4.currentSegmentId
25142
+ });
24925
25143
  } else if (_this4.preparedBuffer.length > 0 && !_this4._isStopped) {
24926
25144
  // More frames available, schedule them immediately
24927
25145
 
@@ -24957,8 +25175,10 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
24957
25175
  };
24958
25176
  if (!_this4.isPlaying) {
24959
25177
  _this4.isPlaying = true;
24960
- console.log('🎵 AudioPlayer: Emitting playbackStarted event');
24961
- _this4.emit('playbackStarted');
25178
+ console.log('🎵 AudioPlayer: Emitting playbackStarted event (segmentId: ' + _this4.currentSegmentId + ')');
25179
+ _this4.emit('playbackStarted', {
25180
+ segmentId: _this4.currentSegmentId
25181
+ });
24962
25182
  }
24963
25183
  case 3:
24964
25184
  return _context3.a(2);
@@ -26302,14 +26522,66 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26302
26522
  // Note: scheduledBuffers was already reset to 0 above when clearing scheduledSources
26303
26523
  this.nextStartTime = 0;
26304
26524
 
26525
+ // Report per-segment completion for the interrupted burst BEFORE clearing timing state.
26526
+ // Audible segment → barged_in (ms heard); scheduled-but-unstarted → interrupted;
26527
+ // already-elapsed but unreported → finished. Plus any pending segment (audio_start arrived
26528
+ // but no chunks scheduled yet) → interrupted.
26529
+ try {
26530
+ var nowTs = this.audioContext ? this.audioContext.currentTime : 0;
26531
+ var _iterator = _createForOfIteratorHelper(this.sentenceTimings),
26532
+ _step;
26533
+ try {
26534
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
26535
+ var timing = _step.value;
26536
+ if (timing.doneReported) continue;
26537
+ timing.doneReported = true;
26538
+ var status = void 0,
26539
+ playedMs = void 0;
26540
+ if (timing.endTime != null && nowTs >= timing.endTime) {
26541
+ status = 'finished';
26542
+ playedMs = Math.round((timing.endTime - timing.startTime) * 1000);
26543
+ } else if (nowTs <= timing.startTime) {
26544
+ status = 'interrupted';
26545
+ playedMs = 0;
26546
+ } else {
26547
+ status = 'barged_in';
26548
+ playedMs = Math.round((nowTs - timing.startTime) * 1000);
26549
+ }
26550
+ this.emit('segmentDone', {
26551
+ segmentId: timing.segmentId,
26552
+ status: status,
26553
+ playedMs: playedMs
26554
+ });
26555
+ }
26556
+ } catch (err) {
26557
+ _iterator.e(err);
26558
+ } finally {
26559
+ _iterator.f();
26560
+ }
26561
+ if (this.pendingSegmentId != null) {
26562
+ this.emit('segmentDone', {
26563
+ segmentId: this.pendingSegmentId,
26564
+ status: 'interrupted',
26565
+ playedMs: 0
26566
+ });
26567
+ }
26568
+ } catch (e) {
26569
+ console.warn('⚠️ AudioPlayer: segmentDone (barge-in) reporting failed:', e && e.message);
26570
+ }
26571
+ // Capture the last segment that was playing for the coarse playbackStopped below
26572
+ // (clearTranscriptState resets currentSegmentId).
26573
+ var stoppedSegmentId = this.currentSegmentId;
26574
+
26305
26575
  // Clear transcript state
26306
26576
  this.clearTranscriptState();
26307
26577
 
26308
26578
  // Emit stopped event - CRITICAL for barge-in
26309
26579
 
26310
26580
  if (wasPlaying) {
26311
- console.log('🛑 AudioPlayer: Emitting playbackStopped event (stopImmediate called)');
26312
- this.emit('playbackStopped');
26581
+ console.log('🛑 AudioPlayer: Emitting playbackStopped event (stopImmediate called, segmentId: ' + stoppedSegmentId + ')');
26582
+ this.emit('playbackStopped', {
26583
+ segmentId: stoppedSegmentId
26584
+ });
26313
26585
  }
26314
26586
  }
26315
26587
 
@@ -26319,7 +26591,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26319
26591
  */
26320
26592
  }, {
26321
26593
  key: "markNewSentence",
26322
- value: function markNewSentence(text, synced) {
26594
+ value: function markNewSentence(text, synced, segmentId) {
26323
26595
  var _this0 = this;
26324
26596
  var wasStopped = this._isStopped;
26325
26597
  var isCurrentlyPlaying = this.isPlaying || this.scheduledSources.size > 0;
@@ -26364,10 +26636,12 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26364
26636
  console.log("\uD83D\uDCDD AudioPlayer: New sentence queued while audio playing - will start after current sentence finishes");
26365
26637
  }
26366
26638
 
26367
- // Always update pending sentence text and synced actions (for transcript display)
26639
+ // Always update pending sentence text, synced actions (for transcript display), and the
26640
+ // backend-assigned segment id (echoed back on the playback events for this segment).
26368
26641
  this.pendingSentenceText = text;
26369
26642
  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, ")"));
26643
+ this.pendingSegmentId = segmentId != null ? segmentId : null;
26644
+ 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
26645
 
26372
26646
  // CRITICAL: Set timeout to detect empty sentences (audio_start but no chunks)
26373
26647
  // This prevents queue blocking if backend sends audio_start but no audio chunks follow
@@ -26379,6 +26653,18 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26379
26653
  // Check if this sentence still has no chunks after timeout
26380
26654
  if (_this0.pendingSentenceText === sentenceText && _this0.scheduledBuffers === 0 && _this0.preparedBuffer.length === 0 && _this0.pcmChunkQueue.length === 0 && !_this0._isStopped) {
26381
26655
  console.warn("\u26A0\uFE0F AudioPlayer: Empty sentence detected after 5s timeout - no chunks received for: \"".concat(sentenceText.substring(0, 40), "...\""));
26656
+ // If this empty sentence carried a segment id, report it done (nothing was heard) and
26657
+ // adopt it as current so the coarse stop below matches the backend's last-sent id.
26658
+ if (_this0.pendingSegmentId != null) {
26659
+ var emptySegId = _this0.pendingSegmentId;
26660
+ _this0.currentSegmentId = emptySegId;
26661
+ _this0.pendingSegmentId = null;
26662
+ _this0.emit('segmentDone', {
26663
+ segmentId: emptySegId,
26664
+ status: 'finished',
26665
+ playedMs: 0
26666
+ });
26667
+ }
26382
26668
  // Clear pending sentence to unblock next sentence
26383
26669
  if (_this0.pendingSentenceText === sentenceText) {
26384
26670
  _this0.pendingSentenceText = null;
@@ -26387,7 +26673,9 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26387
26673
  // Only if we're not currently playing (to avoid interrupting real playback)
26388
26674
  if (!_this0.isPlaying && _this0.scheduledSources.size === 0) {
26389
26675
  console.log('🛑 AudioPlayer: Emitting playbackStopped for empty sentence timeout');
26390
- _this0.emit('playbackStopped');
26676
+ _this0.emit('playbackStopped', {
26677
+ segmentId: _this0.currentSegmentId
26678
+ });
26391
26679
  }
26392
26680
  }
26393
26681
  _this0._emptySentenceTimeout = null;
@@ -26407,31 +26695,64 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26407
26695
  var _checkLoop = function checkLoop() {
26408
26696
  if (!_this1.isCheckingTranscripts || !_this1.audioContext) return;
26409
26697
  var currentTime = _this1.audioContext.currentTime;
26410
- var _iterator = _createForOfIteratorHelper(_this1.sentenceTimings),
26411
- _step;
26698
+ var _iterator2 = _createForOfIteratorHelper(_this1.sentenceTimings),
26699
+ _step2;
26412
26700
  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;
26701
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
26702
+ var _timing = _step2.value;
26703
+ if (!_timing.displayed && _timing.text && currentTime >= _timing.startTime) {
26704
+ _timing.displayed = true;
26417
26705
  var eventData = {
26418
- text: timing.text
26706
+ text: _timing.text
26419
26707
  };
26420
- if (timing.synced) {
26421
- eventData.synced = timing.synced;
26708
+ if (_timing.synced) {
26709
+ eventData.synced = _timing.synced;
26422
26710
  }
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, ")"));
26711
+ 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
26712
  _this1.emit('transcriptDisplay', eventData);
26425
26713
  }
26714
+ // Per-segment natural finish: this segment's audio window has fully elapsed.
26715
+ if (!_timing.doneReported && _timing.endTime != null && currentTime >= _timing.endTime) {
26716
+ _timing.doneReported = true;
26717
+ var _playedMs = Math.round((_timing.endTime - _timing.startTime) * 1000);
26718
+ _this1.emit('segmentDone', {
26719
+ segmentId: _timing.segmentId,
26720
+ status: 'finished',
26721
+ playedMs: _playedMs
26722
+ });
26723
+ }
26426
26724
  }
26427
26725
  } catch (err) {
26428
- _iterator.e(err);
26726
+ _iterator2.e(err);
26429
26727
  } finally {
26430
- _iterator.f();
26728
+ _iterator2.f();
26431
26729
  }
26432
26730
  if (_this1.isPlaying || _this1.scheduledBuffers > 0) {
26433
26731
  requestAnimationFrame(_checkLoop);
26434
26732
  } else {
26733
+ // Playback drained naturally — flush any segment whose finish tick we may have missed
26734
+ // (the last buffer's onended can flip isPlaying=false before this loop's next tick).
26735
+ var _iterator3 = _createForOfIteratorHelper(_this1.sentenceTimings),
26736
+ _step3;
26737
+ try {
26738
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
26739
+ var timing = _step3.value;
26740
+ if (!timing.doneReported) {
26741
+ timing.doneReported = true;
26742
+ var end = timing.endTime != null ? timing.endTime : timing.startTime;
26743
+ var playedMs = Math.round((end - timing.startTime) * 1000);
26744
+ _this1.emit('segmentDone', {
26745
+ segmentId: timing.segmentId,
26746
+ status: 'finished',
26747
+ playedMs: playedMs
26748
+ });
26749
+ }
26750
+ }
26751
+ } catch (err) {
26752
+ _iterator3.e(err);
26753
+ } finally {
26754
+ _iterator3.f();
26755
+ }
26435
26756
  _this1.isCheckingTranscripts = false;
26436
26757
  console.log('📝 AudioPlayer: Transcript checker stopped');
26437
26758
  }
@@ -26447,6 +26768,8 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26447
26768
  value: function clearTranscriptState() {
26448
26769
  this.pendingSentenceText = null;
26449
26770
  this.pendingSynced = null;
26771
+ this.pendingSegmentId = null;
26772
+ this.currentSegmentId = null;
26450
26773
  this.sentenceTimings = [];
26451
26774
  this.isCheckingTranscripts = false;
26452
26775
  console.log('📝 AudioPlayer: Transcript state cleared');
@@ -26596,13 +26919,13 @@ __webpack_require__.r(__webpack_exports__);
26596
26919
  /* harmony import */ var _utils_screenshot_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../utils/screenshot.js */ "./src/utils/screenshot.js");
26597
26920
  /* harmony import */ var _utils_visual_tools_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../utils/visual-tools.js */ "./src/utils/visual-tools.js");
26598
26921
  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); }
26922
+ 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; } } }; }
26923
+ 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; } }
26924
+ 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
26925
  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
26926
  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
26927
  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
26928
  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
26929
  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
26930
  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
26931
  function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
@@ -27169,19 +27492,23 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
27169
27492
  key: "setupAudioPlayerEvents",
27170
27493
  value: function setupAudioPlayerEvents() {
27171
27494
  var _this3 = this;
27172
- this.audioPlayer.on('playbackStarted', function () {
27495
+ this.audioPlayer.on('playbackStarted', function (info) {
27173
27496
  _this3.isPlaying = true;
27174
27497
  _this3.emit('playbackStarted');
27175
27498
 
27176
27499
  // Transcripts are displayed when they arrive (between sentences)
27177
27500
  // No need to handle transcript display here - it's handled in handleTranscript()
27178
27501
 
27179
- // Notify server - CRITICAL for barge-in detection
27502
+ // Notify server - CRITICAL for barge-in detection.
27503
+ // Carry the segmentId of the burst that started playing (echoed from audio_start) so the
27504
+ // backend can correlate playback events with the bursts it sent.
27180
27505
 
27181
27506
  if (_this3.isConnected) {
27182
- console.log('📤 VoiceSDK v2: Sending audio_started_playing message to server');
27507
+ var segmentId = info && info.segmentId != null ? info.segmentId : null;
27508
+ console.log('📤 VoiceSDK v2: Sending audio_started_playing message to server (segmentId: ' + segmentId + ')');
27183
27509
  _this3.sendMessage({
27184
- t: 'audio_started_playing'
27510
+ t: 'audio_started_playing',
27511
+ segmentId: segmentId
27185
27512
  });
27186
27513
  } else {
27187
27514
  console.warn('⚠️ VoiceSDK v2: Cannot send audio_started_playing - not connected');
@@ -27205,39 +27532,62 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
27205
27532
  _this3.emit('transcriptDisplay', fullTranscriptData);
27206
27533
  _this3.emit('transcript', fullTranscriptData);
27207
27534
  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
- }
27535
+ console.log("\uD83D\uDCDD VoiceSDK v2: Dispatching ".concat(transcriptData.synced.length, " synced action(s)"));
27536
+ void _this3._dispatchSyncedActions(transcriptData.synced);
27221
27537
  }
27222
27538
  });
27223
- this.audioPlayer.on('playbackStopped', function () {
27539
+ this.audioPlayer.on('playbackStopped', function (info) {
27224
27540
  _this3.isPlaying = false;
27225
27541
  _this3.emit('playbackStopped');
27226
27542
 
27227
27543
  // When playback stops, keep currentPlayingSentenceId to track which sentence just finished
27228
27544
  // The next transcript will arrive between sentences and will be displayed immediately
27229
27545
 
27230
- // Notify server - CRITICAL for barge-in detection
27546
+ // Notify server - CRITICAL for barge-in detection.
27547
+ // Carry the segmentId of the last burst that was playing so the backend's idle gate can
27548
+ // match this stop against the last burst it sent (deterministic "fully idle").
27231
27549
 
27232
27550
  if (_this3.isConnected) {
27233
- console.log('📤 VoiceSDK v2: Sending audio_stopped_playing message to server');
27551
+ var segmentId = info && info.segmentId != null ? info.segmentId : null;
27552
+ console.log('📤 VoiceSDK v2: Sending audio_stopped_playing message to server (segmentId: ' + segmentId + ')');
27234
27553
  _this3.sendMessage({
27235
- t: 'audio_stopped_playing'
27554
+ t: 'audio_stopped_playing',
27555
+ segmentId: segmentId
27236
27556
  });
27237
27557
  } else {
27238
27558
  console.warn('⚠️ VoiceSDK v2: Cannot send audio_stopped_playing - not connected');
27239
27559
  }
27240
27560
  });
27561
+
27562
+ // Per-segment playback completion (finished / barged_in / interrupted) with the ms of THIS
27563
+ // segment actually heard. Additive telemetry alongside the coarse started/stopped events.
27564
+
27565
+ this.audioPlayer.on('segmentDone', function (info) {
27566
+ if (!info) return;
27567
+ if (_this3.isConnected) {
27568
+ console.log('📤 VoiceSDK v2: Sending audio_segment_done (segmentId: ' + info.segmentId + ', status: ' + info.status + ', playedMs: ' + info.playedMs + ')');
27569
+ _this3.sendMessage({
27570
+ t: 'audio_segment_done',
27571
+ segmentId: info.segmentId != null ? info.segmentId : null,
27572
+ status: info.status,
27573
+ playedMs: info.playedMs
27574
+ });
27575
+ }
27576
+ });
27577
+
27578
+ // Per-segment START — fired when a sentence's first frame schedules (≈ it begins playing).
27579
+ // The backend uses this to fire sync_with_speech tool execution exactly as the line is heard.
27580
+
27581
+ this.audioPlayer.on('segmentStarted', function (info) {
27582
+ if (!info || info.segmentId == null) return;
27583
+ if (_this3.isConnected) {
27584
+ console.log('📤 VoiceSDK v2: Sending audio_segment_started (segmentId: ' + info.segmentId + ')');
27585
+ _this3.sendMessage({
27586
+ t: 'audio_segment_started',
27587
+ segmentId: info.segmentId
27588
+ });
27589
+ }
27590
+ });
27241
27591
  this.audioPlayer.on('playbackError', function (error) {
27242
27592
  _this3.emit('playbackError', error);
27243
27593
  _this3.emit('error', error);
@@ -27602,7 +27952,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
27602
27952
 
27603
27953
  // Include SDK build time for debugging
27604
27954
  if (true) {
27605
- helloMessage.lastBuildTime = "2026-06-14T07:18:03.004Z";
27955
+ helloMessage.lastBuildTime = "2026-06-29T06:35:24.857Z";
27606
27956
  }
27607
27957
 
27608
27958
  // Page context is intentionally NOT attached to the hello message.
@@ -27757,7 +28107,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
27757
28107
  case 'audio_start':
27758
28108
  // Backend sends audio_start with transcript text before audio chunks
27759
28109
  // 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);
28110
+ console.log('📝 VoiceSDK v2: Received audio_start with text:', message.text, '(segmentId:', message.segmentId, ')');
27761
28111
 
27762
28112
  // CRITICAL: Record timestamp to prevent premature stop_playing messages from cutting sentences
27763
28113
  this.lastAudioStartTime = Date.now();
@@ -27773,7 +28123,10 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
27773
28123
  if (synced) {
27774
28124
  console.log("\uD83D\uDCDD VoiceSDK v2: audio_start carries ".concat(synced.length, " synced action(s)"));
27775
28125
  }
27776
- this.audioPlayer.markNewSentence(message.text, synced);
28126
+ // Pass the backend-assigned segmentId (may be undefined for legacy backends) so the
28127
+ // player can echo it back on this segment's playback events.
28128
+ var segmentId = message.segmentId != null ? message.segmentId : null;
28129
+ this.audioPlayer.markNewSentence(message.text, synced, segmentId);
27777
28130
  }
27778
28131
  // Also emit as message for other listeners
27779
28132
  this.emit('message', message);
@@ -28302,6 +28655,104 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28302
28655
  }
28303
28656
  }
28304
28657
 
28658
+ /**
28659
+ * Dispatch widget actions synced to a TTS sentence boundary.
28660
+ * run_partner_script envelopes must go through the same handler as WS traffic
28661
+ * (show_media and other t= messages still emit as generic message events).
28662
+ * @private
28663
+ */
28664
+ }, {
28665
+ key: "_dispatchSyncedActions",
28666
+ value: (function () {
28667
+ var _dispatchSyncedActions2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(actions) {
28668
+ var _iterator, _step, raw, _t2;
28669
+ return _regenerator().w(function (_context3) {
28670
+ while (1) switch (_context3.p = _context3.n) {
28671
+ case 0:
28672
+ _iterator = _createForOfIteratorHelper(actions);
28673
+ _context3.p = 1;
28674
+ _iterator.s();
28675
+ case 2:
28676
+ if ((_step = _iterator.n()).done) {
28677
+ _context3.n = 4;
28678
+ break;
28679
+ }
28680
+ raw = _step.value;
28681
+ _context3.n = 3;
28682
+ return this._dispatchSyncedAction(raw);
28683
+ case 3:
28684
+ _context3.n = 2;
28685
+ break;
28686
+ case 4:
28687
+ _context3.n = 6;
28688
+ break;
28689
+ case 5:
28690
+ _context3.p = 5;
28691
+ _t2 = _context3.v;
28692
+ _iterator.e(_t2);
28693
+ case 6:
28694
+ _context3.p = 6;
28695
+ _iterator.f();
28696
+ return _context3.f(6);
28697
+ case 7:
28698
+ return _context3.a(2);
28699
+ }
28700
+ }, _callee3, this, [[1, 5, 6, 7]]);
28701
+ }));
28702
+ function _dispatchSyncedActions(_x) {
28703
+ return _dispatchSyncedActions2.apply(this, arguments);
28704
+ }
28705
+ return _dispatchSyncedActions;
28706
+ }())
28707
+ }, {
28708
+ key: "_dispatchSyncedAction",
28709
+ value: function () {
28710
+ var _dispatchSyncedAction2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(action) {
28711
+ var message, _t3;
28712
+ return _regenerator().w(function (_context4) {
28713
+ while (1) switch (_context4.p = _context4.n) {
28714
+ case 0:
28715
+ message = action;
28716
+ if (!(typeof message === 'string')) {
28717
+ _context4.n = 3;
28718
+ break;
28719
+ }
28720
+ _context4.p = 1;
28721
+ message = JSON.parse(message);
28722
+ _context4.n = 3;
28723
+ break;
28724
+ case 2:
28725
+ _context4.p = 2;
28726
+ _t3 = _context4.v;
28727
+ console.warn('⚠️ VoiceSDK v2: Ignoring invalid synced action string:', action);
28728
+ return _context4.a(2);
28729
+ case 3:
28730
+ if (!(!message || _typeof(message) !== 'object')) {
28731
+ _context4.n = 4;
28732
+ break;
28733
+ }
28734
+ return _context4.a(2);
28735
+ case 4:
28736
+ if (!(message.t === 'run_partner_script')) {
28737
+ _context4.n = 6;
28738
+ break;
28739
+ }
28740
+ _context4.n = 5;
28741
+ return this._handleRunPartnerScript(message);
28742
+ case 5:
28743
+ return _context4.a(2);
28744
+ case 6:
28745
+ this.emit('message', message);
28746
+ case 7:
28747
+ return _context4.a(2);
28748
+ }
28749
+ }, _callee4, this, [[1, 2]]);
28750
+ }));
28751
+ function _dispatchSyncedAction(_x2) {
28752
+ return _dispatchSyncedAction2.apply(this, arguments);
28753
+ }
28754
+ return _dispatchSyncedAction;
28755
+ }()
28305
28756
  /**
28306
28757
  * Handle a run_partner_script envelope (async partner-adapter dispatch).
28307
28758
  *
@@ -28320,30 +28771,30 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28320
28771
  }, {
28321
28772
  key: "_handleRunPartnerScript",
28322
28773
  value: (function () {
28323
- var _handleRunPartnerScript2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(message) {
28774
+ var _handleRunPartnerScript2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(message) {
28324
28775
  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) {
28776
+ var _ref, requestId, partnerId, action, args, handler, startedAt, result, elapsedMs, ok, reason, extras, preview, _elapsedMs, _t4;
28777
+ return _regenerator().w(function (_context5) {
28778
+ while (1) switch (_context5.p = _context5.n) {
28328
28779
  case 0:
28329
28780
  _ref = message || {}, requestId = _ref.requestId, partnerId = _ref.partnerId, action = _ref.action;
28330
28781
  args = message && message.args || {};
28331
28782
  if (requestId) {
28332
- _context3.n = 1;
28783
+ _context5.n = 1;
28333
28784
  break;
28334
28785
  }
28335
28786
  console.warn('⚠️ VoiceSDK v2: run_partner_script missing requestId; dropping', message);
28336
- return _context3.a(2);
28787
+ return _context5.a(2);
28337
28788
  case 1:
28338
28789
  if (!_core_ClientScriptManager_js__WEBPACK_IMPORTED_MODULE_5__.ClientScriptManager.isClientToolsScript(message)) {
28339
- _context3.n = 2;
28790
+ _context5.n = 2;
28340
28791
  break;
28341
28792
  }
28342
- return _context3.a(2, this.clientScriptManager.handleRunPartnerScript(message));
28793
+ return _context5.a(2, this.clientScriptManager.handleRunPartnerScript(message));
28343
28794
  case 2:
28344
28795
  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
28796
  if (handler) {
28346
- _context3.n = 3;
28797
+ _context5.n = 3;
28347
28798
  break;
28348
28799
  }
28349
28800
  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 +28806,18 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28355
28806
  ok: false,
28356
28807
  error: 'no_handler_registered'
28357
28808
  });
28358
- return _context3.a(2);
28809
+ return _context5.a(2);
28359
28810
  case 3:
28360
28811
  startedAt = Date.now();
28361
28812
  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;
28813
+ _context5.p = 4;
28814
+ _context5.n = 5;
28364
28815
  return handler({
28365
28816
  action: action,
28366
28817
  args: args
28367
28818
  });
28368
28819
  case 5:
28369
- result = _context3.v;
28820
+ result = _context5.v;
28370
28821
  elapsedMs = Date.now() - startedAt; // Adapters return { ok, ... } themselves. Honor that flag if present;
28371
28822
  // otherwise treat presence-of-result as success.
28372
28823
  ok = result && _typeof(result) === 'object' && 'ok' in result ? !!result.ok : true; // Surface the failure reason inline so debugging doesn't require pulling
@@ -28393,27 +28844,27 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28393
28844
  ok: ok,
28394
28845
  result: result
28395
28846
  });
28396
- _context3.n = 7;
28847
+ _context5.n = 7;
28397
28848
  break;
28398
28849
  case 6:
28399
- _context3.p = 6;
28400
- _t2 = _context3.v;
28850
+ _context5.p = 6;
28851
+ _t4 = _context5.v;
28401
28852
  _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);
28853
+ console.error("\uD83E\uDDE9 VoiceSDK v2: run_partner_script threw partner=".concat(partnerId, " action=").concat(action, " requestId=").concat(requestId, " (").concat(_elapsedMs, "ms):"), _t4);
28403
28854
  this.sendMessage({
28404
28855
  t: 'run_partner_script_result',
28405
28856
  requestId: requestId,
28406
28857
  partnerId: partnerId,
28407
28858
  action: action,
28408
28859
  ok: false,
28409
- error: _t2 && _t2.message || String(_t2)
28860
+ error: _t4 && _t4.message || String(_t4)
28410
28861
  });
28411
28862
  case 7:
28412
- return _context3.a(2);
28863
+ return _context5.a(2);
28413
28864
  }
28414
- }, _callee3, this, [[4, 6]]);
28865
+ }, _callee5, this, [[4, 6]]);
28415
28866
  }));
28416
- function _handleRunPartnerScript(_x) {
28867
+ function _handleRunPartnerScript(_x3) {
28417
28868
  return _handleRunPartnerScript2.apply(this, arguments);
28418
28869
  }
28419
28870
  return _handleRunPartnerScript;
@@ -28458,7 +28909,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28458
28909
  }, {
28459
28910
  key: "injectData",
28460
28911
  value: (function () {
28461
- var _injectData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(data) {
28912
+ var _injectData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6(data) {
28462
28913
  var _this7 = this;
28463
28914
  var options,
28464
28915
  trimmedData,
@@ -28469,15 +28920,15 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28469
28920
  timeout,
28470
28921
  source,
28471
28922
  message,
28472
- _args4 = arguments;
28473
- return _regenerator().w(function (_context4) {
28474
- while (1) switch (_context4.n) {
28923
+ _args6 = arguments;
28924
+ return _regenerator().w(function (_context6) {
28925
+ while (1) switch (_context6.n) {
28475
28926
  case 0:
28476
- options = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : {};
28927
+ options = _args6.length > 1 && _args6[1] !== undefined ? _args6[1] : {};
28477
28928
  // Validation: data content
28478
28929
  trimmedData = data === null || data === void 0 ? void 0 : data.trim();
28479
28930
  if (trimmedData) {
28480
- _context4.n = 1;
28931
+ _context6.n = 1;
28481
28932
  break;
28482
28933
  }
28483
28934
  error = {
@@ -28489,7 +28940,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28489
28940
  throw new Error(error.message);
28490
28941
  case 1:
28491
28942
  if (!(!this.isConnected || !this.websocket)) {
28492
- _context4.n = 2;
28943
+ _context6.n = 2;
28493
28944
  break;
28494
28945
  }
28495
28946
  _error = {
@@ -28501,7 +28952,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28501
28952
  throw new Error(_error.message);
28502
28953
  case 2:
28503
28954
  if (!(trimmedData.length > 5000)) {
28504
- _context4.n = 3;
28955
+ _context6.n = 3;
28505
28956
  break;
28506
28957
  }
28507
28958
  _error2 = {
@@ -28530,7 +28981,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28530
28981
  }
28531
28982
 
28532
28983
  // Return Promise that resolves when acknowledgment is received
28533
- return _context4.a(2, new Promise(function (_resolve, _reject) {
28984
+ return _context6.a(2, new Promise(function (_resolve, _reject) {
28534
28985
  // Set up timeout
28535
28986
  var timeoutId = setTimeout(function () {
28536
28987
  // Remove from pending map
@@ -28581,9 +29032,9 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28581
29032
  }
28582
29033
  }));
28583
29034
  }
28584
- }, _callee4, this);
29035
+ }, _callee6, this);
28585
29036
  }));
28586
- function injectData(_x2) {
29037
+ function injectData(_x4) {
28587
29038
  return _injectData.apply(this, arguments);
28588
29039
  }
28589
29040
  return injectData;
@@ -28713,20 +29164,20 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28713
29164
  }, {
28714
29165
  key: "handleBinaryMessage",
28715
29166
  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) {
29167
+ var _handleBinaryMessage = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7(data) {
29168
+ var arrayBuffer, processedAudio, playbackFormat, container, encoding, pcmData, codec, decoded, _t5;
29169
+ return _regenerator().w(function (_context7) {
29170
+ while (1) switch (_context7.p = _context7.n) {
28720
29171
  case 0:
28721
29172
  if (!(data instanceof Blob)) {
28722
- _context5.n = 2;
29173
+ _context7.n = 2;
28723
29174
  break;
28724
29175
  }
28725
- _context5.n = 1;
29176
+ _context7.n = 1;
28726
29177
  return data.arrayBuffer();
28727
29178
  case 1:
28728
- arrayBuffer = _context5.v;
28729
- _context5.n = 3;
29179
+ arrayBuffer = _context7.v;
29180
+ _context7.n = 3;
28730
29181
  break;
28731
29182
  case 2:
28732
29183
  arrayBuffer = data;
@@ -28734,21 +29185,21 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28734
29185
  // Convert format if needed (before passing to AudioPlayer)
28735
29186
  processedAudio = arrayBuffer;
28736
29187
  if (!(this.formatConverter && this.formatConverter.needsConversion())) {
28737
- _context5.n = 7;
29188
+ _context7.n = 7;
28738
29189
  break;
28739
29190
  }
28740
- _context5.p = 4;
28741
- _context5.n = 5;
29191
+ _context7.p = 4;
29192
+ _context7.n = 5;
28742
29193
  return this.formatConverter.convert(arrayBuffer);
28743
29194
  case 5:
28744
- processedAudio = _context5.v;
29195
+ processedAudio = _context7.v;
28745
29196
  console.log('✅ VoiceSDK v2: Audio converted to requested format');
28746
- _context5.n = 7;
29197
+ _context7.n = 7;
28747
29198
  break;
28748
29199
  case 6:
28749
- _context5.p = 6;
28750
- _t3 = _context5.v;
28751
- console.error('❌ VoiceSDK v2: Format conversion failed:', _t3);
29200
+ _context7.p = 6;
29201
+ _t5 = _context7.v;
29202
+ console.error('❌ VoiceSDK v2: Format conversion failed:', _t5);
28752
29203
  console.warn(' Using backend format without conversion');
28753
29204
  processedAudio = arrayBuffer; // Fall back to original
28754
29205
  case 7:
@@ -28798,11 +29249,11 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28798
29249
  this.audioPlayer.playAudio(processedAudio);
28799
29250
  }
28800
29251
  case 8:
28801
- return _context5.a(2);
29252
+ return _context7.a(2);
28802
29253
  }
28803
- }, _callee5, this, [[4, 6]]);
29254
+ }, _callee7, this, [[4, 6]]);
28804
29255
  }));
28805
- function handleBinaryMessage(_x3) {
29256
+ function handleBinaryMessage(_x5) {
28806
29257
  return _handleBinaryMessage.apply(this, arguments);
28807
29258
  }
28808
29259
  return handleBinaryMessage;
@@ -28990,22 +29441,22 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
28990
29441
  }, {
28991
29442
  key: "startRecording",
28992
29443
  value: (function () {
28993
- var _startRecording = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
29444
+ var _startRecording = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
28994
29445
  var existingMediaStream,
28995
29446
  error,
28996
29447
  _error4,
28997
29448
  _error5,
28998
29449
  permissionError,
28999
- _args6 = arguments,
29000
- _t4,
29001
- _t5,
29002
- _t6;
29003
- return _regenerator().w(function (_context6) {
29004
- while (1) switch (_context6.p = _context6.n) {
29450
+ _args8 = arguments,
29451
+ _t6,
29452
+ _t7,
29453
+ _t8;
29454
+ return _regenerator().w(function (_context8) {
29455
+ while (1) switch (_context8.p = _context8.n) {
29005
29456
  case 0:
29006
- existingMediaStream = _args6.length > 0 && _args6[0] !== undefined ? _args6[0] : null;
29457
+ existingMediaStream = _args8.length > 0 && _args8[0] !== undefined ? _args8[0] : null;
29007
29458
  if (this.isConnected) {
29008
- _context6.n = 1;
29459
+ _context8.n = 1;
29009
29460
  break;
29010
29461
  }
29011
29462
  error = new Error('Not connected to voice server');
@@ -29013,14 +29464,14 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29013
29464
  throw error;
29014
29465
  case 1:
29015
29466
  if (!this.isRecording) {
29016
- _context6.n = 2;
29467
+ _context8.n = 2;
29017
29468
  break;
29018
29469
  }
29019
29470
  console.warn('VoiceSDK v2: Already recording');
29020
- return _context6.a(2, true);
29471
+ return _context8.a(2, true);
29021
29472
  case 2:
29022
29473
  if (!this.disclaimersPending) {
29023
- _context6.n = 3;
29474
+ _context8.n = 3;
29024
29475
  break;
29025
29476
  }
29026
29477
  _error4 = new Error('Server disclaimers must be accepted before recording. Call sendDisclaimerAck(true) first.');
@@ -29029,28 +29480,28 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29029
29480
  throw _error4;
29030
29481
  case 3:
29031
29482
  console.log('🎤 VoiceSDK v2: Starting recording...');
29032
- _context6.p = 4;
29483
+ _context8.p = 4;
29033
29484
  // CRITICAL for mobile browsers: Request microphone permission FIRST
29034
29485
  // iOS: Pass existingMediaStream to avoid second getUserMedia (can fail on iOS)
29035
29486
  console.log('🎤 VoiceSDK v2: Requesting microphone permission (mobile-friendly)...');
29036
- _context6.n = 5;
29487
+ _context8.n = 5;
29037
29488
  return this.audioRecorder.start(existingMediaStream ? {
29038
29489
  existingMediaStream: existingMediaStream
29039
29490
  } : {});
29040
29491
  case 5:
29041
29492
  if (!(!this.isConnected || !this.websocket || this.websocket.readyState !== WebSocket.OPEN)) {
29042
- _context6.n = 10;
29493
+ _context8.n = 10;
29043
29494
  break;
29044
29495
  }
29045
- _context6.p = 6;
29046
- _context6.n = 7;
29496
+ _context8.p = 6;
29497
+ _context8.n = 7;
29047
29498
  return this.audioRecorder.stop();
29048
29499
  case 7:
29049
- _context6.n = 9;
29500
+ _context8.n = 9;
29050
29501
  break;
29051
29502
  case 8:
29052
- _context6.p = 8;
29053
- _t4 = _context6.v;
29503
+ _context8.p = 8;
29504
+ _t6 = _context8.v;
29054
29505
  case 9:
29055
29506
  _error5 = new Error('Connection lost - server may have rejected the call');
29056
29507
  _error5.name = 'ServerRejected';
@@ -29059,7 +29510,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29059
29510
  // The error handler in VoiceInterface will handle it appropriately
29060
29511
  throw _error5;
29061
29512
  case 10:
29062
- _context6.n = 11;
29513
+ _context8.n = 11;
29063
29514
  return this.audioPlayer.resumeAudioContext();
29064
29515
  case 11:
29065
29516
  // After permission is granted, send start_continuous_mode message to server
@@ -29070,45 +29521,45 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29070
29521
 
29071
29522
  // Request screen wake lock to keep screen on during voice call (mobile)
29072
29523
  this._requestWakeLock();
29073
- return _context6.a(2, true);
29524
+ return _context8.a(2, true);
29074
29525
  case 12:
29075
- _context6.p = 12;
29076
- _t5 = _context6.v;
29526
+ _context8.p = 12;
29527
+ _t7 = _context8.v;
29077
29528
  if (!(this.audioRecorder && this.audioRecorder.isRecording)) {
29078
- _context6.n = 16;
29529
+ _context8.n = 16;
29079
29530
  break;
29080
29531
  }
29081
- _context6.p = 13;
29082
- _context6.n = 14;
29532
+ _context8.p = 13;
29533
+ _context8.n = 14;
29083
29534
  return this.audioRecorder.stop();
29084
29535
  case 14:
29085
- _context6.n = 16;
29536
+ _context8.n = 16;
29086
29537
  break;
29087
29538
  case 15:
29088
- _context6.p = 15;
29089
- _t6 = _context6.v;
29539
+ _context8.p = 15;
29540
+ _t8 = _context8.v;
29090
29541
  case 16:
29091
- if (!(_t5.isServerRejection || _t5.name === 'ServerRejected')) {
29092
- _context6.n = 17;
29542
+ if (!(_t7.isServerRejection || _t7.name === 'ServerRejected')) {
29543
+ _context8.n = 17;
29093
29544
  break;
29094
29545
  }
29095
- return _context6.a(2, false);
29546
+ return _context8.a(2, false);
29096
29547
  case 17:
29097
29548
  // Log and emit other errors (permission denied, etc.)
29098
- console.error('❌ VoiceSDK v2: Failed to start recording:', _t5);
29549
+ console.error('❌ VoiceSDK v2: Failed to start recording:', _t7);
29099
29550
 
29100
29551
  // Provide helpful error messages for permission issues
29101
- if (_t5.name === 'NotAllowedError' || _t5.name === 'PermissionDeniedError') {
29552
+ if (_t7.name === 'NotAllowedError' || _t7.name === 'PermissionDeniedError') {
29102
29553
  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;
29554
+ permissionError.name = _t7.name;
29555
+ permissionError.originalError = _t7;
29105
29556
  this.emit('error', permissionError);
29106
29557
  } else {
29107
- this.emit('error', _t5);
29558
+ this.emit('error', _t7);
29108
29559
  }
29109
- return _context6.a(2, false);
29560
+ return _context8.a(2, false);
29110
29561
  }
29111
- }, _callee6, this, [[13, 15], [6, 8], [4, 12]]);
29562
+ }, _callee8, this, [[13, 15], [6, 8], [4, 12]]);
29112
29563
  }));
29113
29564
  function startRecording() {
29114
29565
  return _startRecording.apply(this, arguments);
@@ -29122,20 +29573,20 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29122
29573
  }, {
29123
29574
  key: "stopRecording",
29124
29575
  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) {
29576
+ var _stopRecording = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
29577
+ var _t9;
29578
+ return _regenerator().w(function (_context9) {
29579
+ while (1) switch (_context9.p = _context9.n) {
29129
29580
  case 0:
29130
29581
  if (this.isRecording) {
29131
- _context7.n = 1;
29582
+ _context9.n = 1;
29132
29583
  break;
29133
29584
  }
29134
29585
  console.warn('VoiceSDK v2: Not recording');
29135
- return _context7.a(2, true);
29586
+ return _context9.a(2, true);
29136
29587
  case 1:
29137
29588
  console.log('🛑 VoiceSDK v2: Stopping recording...');
29138
- _context7.p = 2;
29589
+ _context9.p = 2;
29139
29590
  // Send stop_continuous_mode message to server
29140
29591
 
29141
29592
  this.sendMessage({
@@ -29153,21 +29604,21 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29153
29604
  this._releaseWakeLock();
29154
29605
 
29155
29606
  // Stop capturing audio from microphone
29156
- _context7.n = 3;
29607
+ _context9.n = 3;
29157
29608
  return this.audioRecorder.stop();
29158
29609
  case 3:
29159
29610
  // Stop any playing audio
29160
29611
 
29161
29612
  this.stopAudioPlayback();
29162
- return _context7.a(2, true);
29613
+ return _context9.a(2, true);
29163
29614
  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);
29615
+ _context9.p = 4;
29616
+ _t9 = _context9.v;
29617
+ console.error('VoiceSDK v2: Error stopping recording:', _t9);
29618
+ this.emit('error', _t9);
29619
+ return _context9.a(2, false);
29169
29620
  }
29170
- }, _callee7, this, [[2, 4]]);
29621
+ }, _callee9, this, [[2, 4]]);
29171
29622
  }));
29172
29623
  function stopRecording() {
29173
29624
  return _stopRecording.apply(this, arguments);
@@ -29181,27 +29632,27 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29181
29632
  }, {
29182
29633
  key: "toggleRecording",
29183
29634
  value: (function () {
29184
- var _toggleRecording = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
29185
- return _regenerator().w(function (_context8) {
29186
- while (1) switch (_context8.n) {
29635
+ var _toggleRecording = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
29636
+ return _regenerator().w(function (_context0) {
29637
+ while (1) switch (_context0.n) {
29187
29638
  case 0:
29188
29639
  if (!this.isRecording) {
29189
- _context8.n = 2;
29640
+ _context0.n = 2;
29190
29641
  break;
29191
29642
  }
29192
- _context8.n = 1;
29643
+ _context0.n = 1;
29193
29644
  return this.stopRecording();
29194
29645
  case 1:
29195
- return _context8.a(2, _context8.v);
29646
+ return _context0.a(2, _context0.v);
29196
29647
  case 2:
29197
- _context8.n = 3;
29648
+ _context0.n = 3;
29198
29649
  return this.startRecording();
29199
29650
  case 3:
29200
- return _context8.a(2, _context8.v);
29651
+ return _context0.a(2, _context0.v);
29201
29652
  case 4:
29202
- return _context8.a(2);
29653
+ return _context0.a(2);
29203
29654
  }
29204
- }, _callee8, this);
29655
+ }, _callee0, this);
29205
29656
  }));
29206
29657
  function toggleRecording() {
29207
29658
  return _toggleRecording.apply(this, arguments);
@@ -29232,33 +29683,33 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29232
29683
  }, {
29233
29684
  key: "_requestWakeLock",
29234
29685
  value: (function () {
29235
- var _requestWakeLock2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
29686
+ var _requestWakeLock2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1() {
29236
29687
  var _this9 = this;
29237
- var _t8;
29238
- return _regenerator().w(function (_context9) {
29239
- while (1) switch (_context9.p = _context9.n) {
29688
+ var _t0;
29689
+ return _regenerator().w(function (_context1) {
29690
+ while (1) switch (_context1.p = _context1.n) {
29240
29691
  case 0:
29241
29692
  if ('wakeLock' in navigator) {
29242
- _context9.n = 1;
29693
+ _context1.n = 1;
29243
29694
  break;
29244
29695
  }
29245
29696
  console.log('📱 VoiceSDK v2: Wake Lock API not available in this browser');
29246
- return _context9.a(2);
29697
+ return _context1.a(2);
29247
29698
  case 1:
29248
29699
  if (!(this.wakeLock !== null || this._wakeLockRequesting)) {
29249
- _context9.n = 2;
29700
+ _context1.n = 2;
29250
29701
  break;
29251
29702
  }
29252
29703
  console.log('📱 VoiceSDK v2: Wake lock already active or being requested');
29253
- return _context9.a(2);
29704
+ return _context1.a(2);
29254
29705
  case 2:
29255
- _context9.p = 2;
29706
+ _context1.p = 2;
29256
29707
  this._wakeLockRequesting = true;
29257
29708
  // Request wake lock (screen type keeps screen on)
29258
- _context9.n = 3;
29709
+ _context1.n = 3;
29259
29710
  return navigator.wakeLock.request('screen');
29260
29711
  case 3:
29261
- this.wakeLock = _context9.v;
29712
+ this.wakeLock = _context1.v;
29262
29713
  console.log('📱 VoiceSDK v2: Screen wake lock activated - screen will stay on during call');
29263
29714
 
29264
29715
  // Handle wake lock release (e.g., user switches tabs, locks device)
@@ -29266,23 +29717,23 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29266
29717
  console.log('📱 VoiceSDK v2: Wake lock released by system');
29267
29718
  _this9.wakeLock = null;
29268
29719
  });
29269
- _context9.n = 5;
29720
+ _context1.n = 5;
29270
29721
  break;
29271
29722
  case 4:
29272
- _context9.p = 4;
29273
- _t8 = _context9.v;
29723
+ _context1.p = 4;
29724
+ _t0 = _context1.v;
29274
29725
  // Wake lock request failed (e.g., permission denied, battery saver mode)
29275
- console.warn('📱 VoiceSDK v2: Failed to request wake lock:', _t8.message);
29726
+ console.warn('📱 VoiceSDK v2: Failed to request wake lock:', _t0.message);
29276
29727
  this.wakeLock = null;
29277
29728
  // Don't throw - this is a nice-to-have feature, not critical
29278
29729
  case 5:
29279
- _context9.p = 5;
29730
+ _context1.p = 5;
29280
29731
  this._wakeLockRequesting = false;
29281
- return _context9.f(5);
29732
+ return _context1.f(5);
29282
29733
  case 6:
29283
- return _context9.a(2);
29734
+ return _context1.a(2);
29284
29735
  }
29285
- }, _callee9, this, [[2, 4, 5, 6]]);
29736
+ }, _callee1, this, [[2, 4, 5, 6]]);
29286
29737
  }));
29287
29738
  function _requestWakeLock() {
29288
29739
  return _requestWakeLock2.apply(this, arguments);
@@ -29297,34 +29748,34 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29297
29748
  }, {
29298
29749
  key: "_releaseWakeLock",
29299
29750
  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) {
29751
+ var _releaseWakeLock2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee10() {
29752
+ var _t1;
29753
+ return _regenerator().w(function (_context10) {
29754
+ while (1) switch (_context10.p = _context10.n) {
29304
29755
  case 0:
29305
29756
  if (!(this.wakeLock === null)) {
29306
- _context0.n = 1;
29757
+ _context10.n = 1;
29307
29758
  break;
29308
29759
  }
29309
- return _context0.a(2);
29760
+ return _context10.a(2);
29310
29761
  case 1:
29311
- _context0.p = 1;
29312
- _context0.n = 2;
29762
+ _context10.p = 1;
29763
+ _context10.n = 2;
29313
29764
  return this.wakeLock.release();
29314
29765
  case 2:
29315
29766
  this.wakeLock = null;
29316
29767
  console.log('📱 VoiceSDK v2: Screen wake lock released');
29317
- _context0.n = 4;
29768
+ _context10.n = 4;
29318
29769
  break;
29319
29770
  case 3:
29320
- _context0.p = 3;
29321
- _t9 = _context0.v;
29322
- console.warn('📱 VoiceSDK v2: Error releasing wake lock:', _t9.message);
29771
+ _context10.p = 3;
29772
+ _t1 = _context10.v;
29773
+ console.warn('📱 VoiceSDK v2: Error releasing wake lock:', _t1.message);
29323
29774
  this.wakeLock = null;
29324
29775
  case 4:
29325
- return _context0.a(2);
29776
+ return _context10.a(2);
29326
29777
  }
29327
- }, _callee0, this, [[1, 3]]);
29778
+ }, _callee10, this, [[1, 3]]);
29328
29779
  }));
29329
29780
  function _releaseWakeLock() {
29330
29781
  return _releaseWakeLock2.apply(this, arguments);
@@ -29348,21 +29799,21 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29348
29799
  }, {
29349
29800
  key: "handleBargeIn",
29350
29801
  value: (function () {
29351
- var _handleBargeIn = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1() {
29352
- return _regenerator().w(function (_context1) {
29353
- while (1) switch (_context1.n) {
29802
+ var _handleBargeIn = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee11() {
29803
+ return _regenerator().w(function (_context11) {
29804
+ while (1) switch (_context11.n) {
29354
29805
  case 0:
29355
29806
  this.stopAudioPlayback();
29356
29807
  if (this.isRecording) {
29357
- _context1.n = 1;
29808
+ _context11.n = 1;
29358
29809
  break;
29359
29810
  }
29360
- _context1.n = 1;
29811
+ _context11.n = 1;
29361
29812
  return this.startRecording();
29362
29813
  case 1:
29363
- return _context1.a(2);
29814
+ return _context11.a(2);
29364
29815
  }
29365
- }, _callee1, this);
29816
+ }, _callee11, this);
29366
29817
  }));
29367
29818
  function handleBargeIn() {
29368
29819
  return _handleBargeIn.apply(this, arguments);
@@ -32275,10 +32726,17 @@ var TTPChatWidget = /*#__PURE__*/function () {
32275
32726
  this._flavorObj = this.config.flavor && _typeof(this.config.flavor) === 'object' ? this.config.flavor : null;
32276
32727
  if (this._flavorObj && this._flavorObj.type) {
32277
32728
  this._initFlavor(this._flavorObj.type);
32278
- this._initEcommerceVoiceStrip();
32279
- } else if (this._flavorObj && !this._flavorObj.type) {
32729
+ } else if (this._flavorObj && !this._flavorObj.type && this._flavorObj.callView !== 'minimized') {
32730
+ // A flavor object with neither a "type" nor callView:'minimized' is malformed.
32731
+ // (callView:'minimized' alone is a valid flavor-less minimized-strip config.)
32280
32732
  console.error('[TTPChatWidget] flavor object is set but missing required "type" field. Widget will run in vanilla mode.');
32281
32733
  }
32734
+ // The desktop minimized bottom strip is flavor-independent: it only needs
32735
+ // flavor.callView === 'minimized' (+ desktop width). Init it regardless of
32736
+ // whether a flavor type is present, so callView:'minimized' works standalone
32737
+ // with no partner/flavor. _initEcommerceVoiceStrip() self-guards and no-ops
32738
+ // when callView !== 'minimized' or on mobile.
32739
+ this._initEcommerceVoiceStrip();
32282
32740
  }
32283
32741
 
32284
32742
  /**
@@ -32694,7 +33152,11 @@ var TTPChatWidget = /*#__PURE__*/function () {
32694
33152
  offset: positionConfig.offset || {
32695
33153
  x: 20,
32696
33154
  y: 20
32697
- }
33155
+ },
33156
+ // When true, the launcher pill / mobile FAB can be dragged around the
33157
+ // viewport. Set position.draggablePersist:false to reset position each load.
33158
+ draggable: false,
33159
+ draggablePersist: true
32698
33160
  }, _typeof(userConfig.position) === 'object' ? userConfig.position : {}),
32699
33161
  // Button Configuration
32700
33162
  button: _objectSpread({
@@ -33330,6 +33792,125 @@ var TTPChatWidget = /*#__PURE__*/function () {
33330
33792
  var footer = (_root$querySelector = root.querySelector) === null || _root$querySelector === void 0 ? void 0 : _root$querySelector.call(root, '.ttp-footer');
33331
33793
  if (footer) footer.style.display = visible ? '' : 'none';
33332
33794
  }
33795
+
33796
+ /**
33797
+ * Resolve the most recent conversation id used by either channel.
33798
+ * Prefers a live voice/text SDK value, then falls back to persisted state.
33799
+ * @returns {string|null}
33800
+ */
33801
+ }, {
33802
+ key: "_getLastConversationId",
33803
+ value: function _getLastConversationId() {
33804
+ var _this$voiceInterface3, _this$sdk;
33805
+ 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;
33806
+ if (live) return live;
33807
+ 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;
33808
+ if (textId) return textId;
33809
+ try {
33810
+ var raw = sessionStorage.getItem('voice_resume_state');
33811
+ if (raw) {
33812
+ var s = JSON.parse(raw);
33813
+ if (s && s.conversationId) return s.conversationId;
33814
+ }
33815
+ } catch (_) {/* ignore */}
33816
+ try {
33817
+ var t = localStorage.getItem('ttp_text_chat_conversation_id');
33818
+ if (t) return t;
33819
+ } catch (_) {/* ignore */}
33820
+ return null;
33821
+ }
33822
+
33823
+ /** Inline TalkToPC logo mark (speech bubble + sound waves). */
33824
+ }, {
33825
+ key: "_aboutLogoSVG",
33826
+ value: function _aboutLogoSVG() {
33827
+ 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>";
33828
+ }
33829
+
33830
+ /**
33831
+ * Inject the "About" dialog styles into document.head once.
33832
+ * Global (light DOM) so the dialog renders above the desktop minimized strip,
33833
+ * which lives outside the shadow root at the maximum z-index.
33834
+ */
33835
+ }, {
33836
+ key: "_ensureAboutStyles",
33837
+ value: function _ensureAboutStyles() {
33838
+ if (document.getElementById('ttp-about-dialog-styles')) return;
33839
+ var style = document.createElement('style');
33840
+ style.id = 'ttp-about-dialog-styles';
33841
+ 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 ";
33842
+ document.head.appendChild(style);
33843
+ }
33844
+
33845
+ /** Open the shared "About" dialog (logo + SDK version + last conversation id). */
33846
+ }, {
33847
+ key: "_openAboutModal",
33848
+ value: function _openAboutModal() {
33849
+ var _this8 = this,
33850
+ _overlay$querySelecto;
33851
+ // Toggle: if already open, close it.
33852
+ if (this._aboutOverlay) {
33853
+ this._closeAboutModal();
33854
+ return;
33855
+ }
33856
+ this._ensureAboutStyles();
33857
+ var version = true ? "2.45.14" : 0;
33858
+ var convId = this._getLastConversationId();
33859
+ var t = function t(k, fb) {
33860
+ try {
33861
+ var _this8$voiceInterface, _this8$voiceInterface2, _this8$textInterface, _this8$textInterface$;
33862
+ 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;
33863
+ } catch (_) {
33864
+ return fb;
33865
+ }
33866
+ };
33867
+ var title = t('aboutTitle', 'About');
33868
+ var versionLabel = t('aboutVersion', 'SDK version');
33869
+ var convLabel = t('aboutConversationId', 'Last conversation ID');
33870
+ var noneLabel = t('aboutNoConversation', 'No conversation yet');
33871
+ var overlay = document.createElement('div');
33872
+ overlay.className = 'ttp-about-overlay';
33873
+ 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>");
33874
+
33875
+ // Fill dynamic values via textContent to avoid any injection.
33876
+ var verEl = overlay.querySelector('[data-about-version]');
33877
+ if (verEl) verEl.textContent = version ? "v".concat(version) : '—';
33878
+ var convEl = overlay.querySelector('[data-about-conv]');
33879
+ if (convEl) {
33880
+ convEl.textContent = convId || noneLabel;
33881
+ if (!convId) convEl.classList.add('ttp-about-muted');
33882
+ }
33883
+ var close = function close() {
33884
+ return _this8._closeAboutModal();
33885
+ };
33886
+ overlay.addEventListener('click', function (e) {
33887
+ if (e.target === overlay) close();
33888
+ });
33889
+ (_overlay$querySelecto = overlay.querySelector('.ttp-about-close')) === null || _overlay$querySelecto === void 0 || _overlay$querySelecto.addEventListener('click', function (e) {
33890
+ e.stopPropagation();
33891
+ close();
33892
+ });
33893
+ this._aboutKeyHandler = function (e) {
33894
+ if (e.key === 'Escape') close();
33895
+ };
33896
+ document.addEventListener('keydown', this._aboutKeyHandler);
33897
+ document.body.appendChild(overlay);
33898
+ this._aboutOverlay = overlay;
33899
+ }
33900
+
33901
+ /** Close the "About" dialog if open. */
33902
+ }, {
33903
+ key: "_closeAboutModal",
33904
+ value: function _closeAboutModal() {
33905
+ if (this._aboutKeyHandler) {
33906
+ document.removeEventListener('keydown', this._aboutKeyHandler);
33907
+ this._aboutKeyHandler = null;
33908
+ }
33909
+ if (this._aboutOverlay) {
33910
+ this._aboutOverlay.remove();
33911
+ this._aboutOverlay = null;
33912
+ }
33913
+ }
33333
33914
  }, {
33334
33915
  key: "generatePositionStyles",
33335
33916
  value: function generatePositionStyles() {
@@ -33461,13 +34042,14 @@ var TTPChatWidget = /*#__PURE__*/function () {
33461
34042
  var callActivePanelBg = callSurfaceGradient;
33462
34043
  var voiceIdleVisibleSelector = '#voiceInterface.active #voiceIdleState:not([style*="display: none"]):not([style*="display:none"])';
33463
34044
  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 ");
34045
+ 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
34046
  }
33466
34047
  }, {
33467
34048
  key: "setupWidgetEvents",
33468
34049
  value: function setupWidgetEvents() {
33469
- var _this8 = this,
33470
- _this$config$behavior8;
34050
+ var _this9 = this,
34051
+ _this$config$behavior8,
34052
+ _this$config$position5;
33471
34053
  if (!this.shadowRoot) return;
33472
34054
 
33473
34055
  // Setup prompt animation visibility and interactions
@@ -33478,16 +34060,18 @@ var TTPChatWidget = /*#__PURE__*/function () {
33478
34060
  if (launcherBtn) {
33479
34061
  launcherBtn.onclick = function (e) {
33480
34062
  e.stopPropagation();
33481
- if (_this8.config.promptAnimation.hideAfterClick) {
33482
- _this8.hidePrompt();
34063
+ // A drag just ended — don't treat the trailing click as "open panel".
34064
+ if (_this9._suppressLauncherClick) return;
34065
+ if (_this9.config.promptAnimation.hideAfterClick) {
34066
+ _this9.hidePrompt();
33483
34067
  }
33484
- _this8.togglePanel();
34068
+ _this9.togglePanel();
33485
34069
  };
33486
34070
  }
33487
34071
  var closeBtn = this.shadowRoot.getElementById('closeBtn');
33488
34072
  if (closeBtn) {
33489
34073
  closeBtn.onclick = function () {
33490
- _this8._doTogglePanel();
34074
+ _this9._doTogglePanel();
33491
34075
  };
33492
34076
  }
33493
34077
 
@@ -33495,31 +34079,41 @@ var TTPChatWidget = /*#__PURE__*/function () {
33495
34079
  var closeIdle = this.shadowRoot.getElementById('ttpCloseIdle');
33496
34080
  if (closeIdle) {
33497
34081
  closeIdle.onclick = function () {
33498
- return _this8._doTogglePanel();
34082
+ return _this9._doTogglePanel();
33499
34083
  };
33500
34084
  }
33501
34085
  var closeActive = this.shadowRoot.getElementById('ttpCloseActive');
33502
34086
  if (closeActive) {
33503
34087
  closeActive.onclick = function () {
33504
- return _this8._doTogglePanel();
34088
+ return _this9._doTogglePanel();
33505
34089
  };
33506
34090
  }
33507
34091
 
34092
+ // "About" info buttons (present in every view: idle / active / compact /
34093
+ // mobile idle / mobile active / text top-bar). One shared dialog.
34094
+ this.shadowRoot.querySelectorAll('.ttp-info-btn').forEach(function (btn) {
34095
+ btn.onclick = function (e) {
34096
+ e.stopPropagation();
34097
+ e.preventDefault();
34098
+ _this9._openAboutModal();
34099
+ };
34100
+ });
34101
+
33508
34102
  // "Send a Message" button in idle view → switch to text interface
33509
34103
  var startTextBtn = this.shadowRoot.getElementById('startTextBtn');
33510
34104
  if (startTextBtn) {
33511
34105
  startTextBtn.onclick = function () {
33512
- return _this8.showText();
34106
+ return _this9.showText();
33513
34107
  };
33514
34108
  }
33515
34109
  var textUnifiedBackBtn = this.shadowRoot.getElementById('textUnifiedBackBtn');
33516
34110
  if (textUnifiedBackBtn) {
33517
34111
  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';
34112
+ var _this9$config$behavio;
34113
+ var widgetMode = ((_this9$config$behavio = _this9.config.behavior) === null || _this9$config$behavio === void 0 ? void 0 : _this9$config$behavio.mode) || 'unified';
33520
34114
  if (widgetMode !== 'unified') return;
33521
- _this8.showLanding();
33522
- _this8._openMobileCallTextLanding();
34115
+ _this9.showLanding();
34116
+ _this9._openMobileCallTextLanding();
33523
34117
  };
33524
34118
  }
33525
34119
 
@@ -33549,30 +34143,30 @@ var TTPChatWidget = /*#__PURE__*/function () {
33549
34143
  // Setup back button handler
33550
34144
  if (backBtn) {
33551
34145
  backBtn.onclick = function () {
33552
- var _this8$voiceInterface, _this8$voiceInterface3;
34146
+ var _this9$voiceInterface, _this9$voiceInterface3;
33553
34147
  // 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;
34148
+ if ((_this9$voiceInterface = _this9.voiceInterface) !== null && _this9$voiceInterface !== void 0 && _this9$voiceInterface.isShowingDomainError) {
34149
+ var _this9$voiceInterface2;
33556
34150
  console.log('🔙 Back button clicked - clearing domain error and returning to voice hero');
33557
34151
  // Clear the domain error flag
33558
- _this8.voiceInterface.isShowingDomainError = false;
34152
+ _this9.voiceInterface.isShowingDomainError = false;
33559
34153
  // 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();
34154
+ if ((_this9$voiceInterface2 = _this9.voiceInterface) !== null && _this9$voiceInterface2 !== void 0 && _this9$voiceInterface2.resetConnectingState) {
34155
+ _this9.voiceInterface.resetConnectingState();
33562
34156
  }
33563
- _this8.showLanding();
33564
- _this8._openMobileCallTextLanding();
34157
+ _this9.showLanding();
34158
+ _this9._openMobileCallTextLanding();
33565
34159
  return;
33566
34160
  }
33567
- if ((_this8$voiceInterface3 = _this8.voiceInterface) !== null && _this8$voiceInterface3 !== void 0 && _this8$voiceInterface3.isActive) {
34161
+ if ((_this9$voiceInterface3 = _this9.voiceInterface) !== null && _this9$voiceInterface3 !== void 0 && _this9$voiceInterface3.isActive) {
33568
34162
  // If call is active, show message inside widget instead of modal
33569
- _this8.showBackButtonWarning();
34163
+ _this9.showBackButtonWarning();
33570
34164
  } else if (window.innerWidth <= 768) {
33571
- _this8.showLanding();
33572
- _this8._openMobileCallTextLanding();
34165
+ _this9.showLanding();
34166
+ _this9._openMobileCallTextLanding();
33573
34167
  } else {
33574
34168
  // Desktop: return to voice hero (unified home)
33575
- _this8.showLanding();
34169
+ _this9.showLanding();
33576
34170
  }
33577
34171
  };
33578
34172
  }
@@ -33615,7 +34209,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33615
34209
  // Setup header button handlers
33616
34210
  if (newChatBtn) {
33617
34211
  newChatBtn.onclick = function () {
33618
- return _this8.textInterface.startNewChat();
34212
+ return _this9.textInterface.startNewChat();
33619
34213
  };
33620
34214
  // Hide new chat on unified home (voice hero) initially
33621
34215
  if (isUnified && this.currentView !== 'text') {
@@ -33626,11 +34220,328 @@ var TTPChatWidget = /*#__PURE__*/function () {
33626
34220
  // Mobile floating button & landing overlay
33627
34221
  this.setupMobileWidgetEvents();
33628
34222
 
34223
+ // Optional: make the launcher pill / mobile FAB + the open panel draggable
34224
+ // (they move together as one unit). The minimized strip is wired separately
34225
+ // in _initEcommerceVoiceStrip() since it lives outside the shadow DOM.
34226
+ if ((_this$config$position5 = this.config.position) !== null && _this$config$position5 !== void 0 && _this$config$position5.draggable) {
34227
+ this.setupDraggableWidget();
34228
+ }
34229
+
33629
34230
  // Keyboard navigation
33630
34231
  if (this.config.accessibility.keyboardNavigation) {
33631
34232
  this.setupKeyboardNavigation();
33632
34233
  }
33633
34234
  }
34235
+
34236
+ /**
34237
+ * Page-scoped namespace for persisted drag positions (origin+path) so the same
34238
+ * widget on different routes keeps independent spots.
34239
+ */
34240
+ }, {
34241
+ key: "_dragScope",
34242
+ value: function _dragScope() {
34243
+ var scope = '';
34244
+ try {
34245
+ scope = window.location.origin + window.location.pathname;
34246
+ } catch (e) {/* sandboxed */}
34247
+ return scope;
34248
+ }
34249
+
34250
+ /** localStorage key for a dragged surface ('unit' = pill+panel, 'strip'). */
34251
+ }, {
34252
+ key: "_dragStorageKey",
34253
+ value: function _dragStorageKey(kind) {
34254
+ return 'ttp-widget-' + kind + '-pos::' + this._dragScope();
34255
+ }
34256
+
34257
+ /**
34258
+ * The launcher pill and the chat panel move together as one unit. They share a
34259
+ * single translate offset (`this._unitOffset`) so dragging either one (the pill,
34260
+ * the mobile FAB, or a panel header) moves both — they never split apart.
34261
+ */
34262
+ }, {
34263
+ key: "_unitEls",
34264
+ value: function _unitEls() {
34265
+ var root = this.shadowRoot;
34266
+ if (!root) return [];
34267
+ return [root.getElementById('text-chat-button-container'), root.getElementById('text-chat-panel')].filter(Boolean);
34268
+ }
34269
+
34270
+ /** Apply the shared unit offset as a translate transform to both elements. */
34271
+ }, {
34272
+ key: "_applyUnitOffset",
34273
+ value: function _applyUnitOffset() {
34274
+ var o = this._unitOffset || (this._unitOffset = {
34275
+ x: 0,
34276
+ y: 0
34277
+ });
34278
+ var value = "translate(".concat(o.x, "px, ").concat(o.y, "px)");
34279
+ this._unitEls().forEach(function (el) {
34280
+ return el.style.setProperty('transform', value, 'important');
34281
+ });
34282
+ }
34283
+
34284
+ /**
34285
+ * Base (offset-0) viewport rects of the currently-visible unit elements. The
34286
+ * applied transform equals `this._unitOffset`, so subtracting it recovers the
34287
+ * anchored position. Hidden elements (display:none → 0×0) are skipped.
34288
+ */
34289
+ }, {
34290
+ key: "_unitBaseRects",
34291
+ value: function _unitBaseRects() {
34292
+ var o = this._unitOffset || {
34293
+ x: 0,
34294
+ y: 0
34295
+ };
34296
+ var rects = [];
34297
+ this._unitEls().forEach(function (el) {
34298
+ var r = el.getBoundingClientRect();
34299
+ if (!r.width && !r.height) return; // hidden
34300
+ rects.push({
34301
+ left: r.left - o.x,
34302
+ top: r.top - o.y,
34303
+ right: r.right - o.x,
34304
+ bottom: r.bottom - o.y
34305
+ });
34306
+ });
34307
+ return rects;
34308
+ }
34309
+
34310
+ /**
34311
+ * Clamp a desired unit offset so every visible unit element stays within the
34312
+ * viewport (8px margin). Constraints from all visible elements are intersected.
34313
+ */
34314
+ }, {
34315
+ key: "_clampUnitOffset",
34316
+ value: function _clampUnitOffset(x, y, bases) {
34317
+ var margin = 8;
34318
+ var vw = window.innerWidth,
34319
+ vh = window.innerHeight;
34320
+ var minX = -Infinity,
34321
+ maxX = Infinity,
34322
+ minY = -Infinity,
34323
+ maxY = Infinity;
34324
+ bases.forEach(function (b) {
34325
+ minX = Math.max(minX, margin - b.left);
34326
+ maxX = Math.min(maxX, vw - margin - b.right);
34327
+ minY = Math.max(minY, margin - b.top);
34328
+ maxY = Math.min(maxY, vh - margin - b.bottom);
34329
+ });
34330
+ // Element taller/wider than the viewport → keep its top/left edge visible.
34331
+ if (minX > maxX) maxX = minX;
34332
+ if (minY > maxY) maxY = minY;
34333
+ if (!bases.length) return {
34334
+ x: x,
34335
+ y: y
34336
+ };
34337
+ return {
34338
+ x: Math.min(Math.max(x, minX), maxX),
34339
+ y: Math.min(Math.max(y, minY), maxY)
34340
+ };
34341
+ }
34342
+
34343
+ /** Re-clamp the unit to the current viewport (e.g. on resize or panel open). */
34344
+ }, {
34345
+ key: "_reclampUnit",
34346
+ value: function _reclampUnit() {
34347
+ if (!this._unitOffset) return;
34348
+ var bases = this._unitBaseRects();
34349
+ if (!bases.length) return;
34350
+ this._unitOffset = this._clampUnitOffset(this._unitOffset.x, this._unitOffset.y, bases);
34351
+ this._applyUnitOffset();
34352
+ }
34353
+
34354
+ /** Restore a saved unit offset (deferred so elements can be measured at offset 0). */
34355
+ }, {
34356
+ key: "_restoreUnitOffset",
34357
+ value: function _restoreUnitOffset(key) {
34358
+ var _this0 = this;
34359
+ var saved;
34360
+ try {
34361
+ saved = JSON.parse(window.localStorage.getItem(key) || 'null');
34362
+ } catch (e) {
34363
+ return;
34364
+ }
34365
+ if (!saved || typeof saved.x !== 'number' || typeof saved.y !== 'number') return;
34366
+ requestAnimationFrame(function () {
34367
+ _this0._unitOffset = {
34368
+ x: 0,
34369
+ y: 0
34370
+ }; // ensure DOM matches before measuring
34371
+ var bases = _this0._unitBaseRects();
34372
+ _this0._unitOffset = _this0._clampUnitOffset(saved.x, saved.y, bases);
34373
+ _this0._applyUnitOffset();
34374
+ });
34375
+ }
34376
+
34377
+ /**
34378
+ * Wire a single handle to drag the whole pill+panel unit (shared offset).
34379
+ * @param {HTMLElement} handle
34380
+ * @param {Object} opts
34381
+ * @param {boolean} opts.persist
34382
+ * @param {string} opts.key localStorage key
34383
+ * @param {string} [opts.restCursor] idle cursor (default 'grab')
34384
+ * @param {string} [opts.excludeSelector] don't start a drag from these (e.g. buttons)
34385
+ * @param {Function} [opts.onMoved] called once after a real drag ends
34386
+ */
34387
+ }, {
34388
+ key: "_attachUnitDrag",
34389
+ value: function _attachUnitDrag(handle, opts) {
34390
+ var _this1 = this;
34391
+ var persist = opts.persist,
34392
+ key = opts.key,
34393
+ excludeSelector = opts.excludeSelector,
34394
+ onMoved = opts.onMoved;
34395
+ var restCursor = opts.restCursor || 'grab';
34396
+ handle.style.setProperty('touch-action', 'none');
34397
+ handle.style.setProperty('cursor', restCursor);
34398
+ var DRAG_THRESHOLD = 5; // px before a press becomes a drag
34399
+ var startX = 0,
34400
+ startY = 0,
34401
+ baseX = 0,
34402
+ baseY = 0,
34403
+ bases = [];
34404
+ var dragging = false,
34405
+ moved = false;
34406
+ var onMove = function onMove(e) {
34407
+ var dx = e.clientX - startX;
34408
+ var dy = e.clientY - startY;
34409
+ if (!moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;
34410
+ moved = true;
34411
+ _this1._unitOffset = _this1._clampUnitOffset(baseX + dx, baseY + dy, bases);
34412
+ _this1._applyUnitOffset();
34413
+ };
34414
+ var _onUp = function onUp(e) {
34415
+ window.removeEventListener('pointermove', onMove);
34416
+ window.removeEventListener('pointerup', _onUp);
34417
+ handle.style.setProperty('cursor', restCursor);
34418
+ try {
34419
+ handle.releasePointerCapture(e.pointerId);
34420
+ } catch (err) {/* not captured */}
34421
+ dragging = false;
34422
+ if (moved) {
34423
+ if (typeof onMoved === 'function') onMoved();
34424
+ if (persist && key) {
34425
+ try {
34426
+ window.localStorage.setItem(key, JSON.stringify(_this1._unitOffset));
34427
+ } catch (err) {/* unavailable */}
34428
+ }
34429
+ }
34430
+ };
34431
+ var onDown = function onDown(e) {
34432
+ if (e.button != null && e.button !== 0) return; // primary / touch / pen only
34433
+ if (dragging) return;
34434
+ if (excludeSelector && e.target && e.target.closest && e.target.closest(excludeSelector)) return;
34435
+ dragging = true;
34436
+ moved = false;
34437
+ var o = _this1._unitOffset || (_this1._unitOffset = {
34438
+ x: 0,
34439
+ y: 0
34440
+ });
34441
+ startX = e.clientX;
34442
+ startY = e.clientY;
34443
+ baseX = o.x;
34444
+ baseY = o.y;
34445
+ bases = _this1._unitBaseRects();
34446
+ handle.style.setProperty('cursor', 'grabbing');
34447
+ try {
34448
+ handle.setPointerCapture(e.pointerId);
34449
+ } catch (err) {/* unsupported */}
34450
+ window.addEventListener('pointermove', onMove);
34451
+ window.addEventListener('pointerup', _onUp);
34452
+ };
34453
+ handle.addEventListener('pointerdown', onDown);
34454
+ }
34455
+
34456
+ /**
34457
+ * Make the launcher pill / mobile FAB AND the open chat panel draggable as one
34458
+ * unit — dragging any of them moves both, so they never split apart. Pill/FAB
34459
+ * drags suppress the trailing click (so the panel doesn't toggle); panel header
34460
+ * bars (.ttp-header / .ttp-call-topbar / .text-interface-top-bar) are drag
34461
+ * handles too, with their interactive controls (e.g. close) excluded.
34462
+ */
34463
+ }, {
34464
+ key: "setupDraggableWidget",
34465
+ value: function setupDraggableWidget() {
34466
+ var _this$config$position6,
34467
+ _this10 = this;
34468
+ var root = this.shadowRoot;
34469
+ if (!root) return;
34470
+ var container = root.getElementById('text-chat-button-container');
34471
+ var panel = root.getElementById('text-chat-panel');
34472
+ if (!container && !panel) return;
34473
+ this._unitOffset = this._unitOffset || {
34474
+ x: 0,
34475
+ y: 0
34476
+ };
34477
+ var persist = ((_this$config$position6 = this.config.position) === null || _this$config$position6 === void 0 ? void 0 : _this$config$position6.draggablePersist) !== false;
34478
+ var key = this._dragStorageKey('unit');
34479
+ if (persist) this._restoreUnitOffset(key);
34480
+
34481
+ // Launcher handles: pill + mobile FAB (suppress the click after a drag).
34482
+ [root.getElementById('text-chat-button'), root.querySelector('.ttp-mobile-fab')].filter(Boolean).forEach(function (h) {
34483
+ return _this10._attachUnitDrag(h, {
34484
+ persist: persist,
34485
+ key: key,
34486
+ restCursor: 'grab',
34487
+ onMoved: function onMoved() {
34488
+ _this10._suppressLauncherClick = true;
34489
+ setTimeout(function () {
34490
+ _this10._suppressLauncherClick = false;
34491
+ }, 0);
34492
+ }
34493
+ });
34494
+ });
34495
+
34496
+ // Panel handles: header bars across voice idle / active call / text views.
34497
+ if (panel) {
34498
+ ['.ttp-header', '.ttp-call-topbar', '.text-interface-top-bar'].map(function (sel) {
34499
+ return panel.querySelector(sel);
34500
+ }).filter(Boolean).forEach(function (h) {
34501
+ return _this10._attachUnitDrag(h, {
34502
+ persist: persist,
34503
+ key: key,
34504
+ restCursor: 'move',
34505
+ excludeSelector: 'button, a, input, textarea, select, [contenteditable]'
34506
+ });
34507
+ });
34508
+ }
34509
+
34510
+ // Re-apply any in-memory offset to freshly-rendered elements (re-render).
34511
+ this._applyUnitOffset();
34512
+ this._bindDragResize();
34513
+ }
34514
+
34515
+ /**
34516
+ * Make the desktop minimized voice strip (EcommerceVoiceStrip) draggable. The
34517
+ * strip lives outside the shadow DOM and owns its own drag logic; we just hand
34518
+ * it a persistence key (so it remembers its spot independently of the unit).
34519
+ */
34520
+ }, {
34521
+ key: "setupDraggableStrip",
34522
+ value: function setupDraggableStrip() {
34523
+ var _this$config$position7;
34524
+ var strip = this._ecommerceVoiceStrip;
34525
+ if (!strip || typeof strip.enableDrag !== 'function') return;
34526
+ strip.enableDrag({
34527
+ persist: ((_this$config$position7 = this.config.position) === null || _this$config$position7 === void 0 ? void 0 : _this$config$position7.draggablePersist) !== false,
34528
+ storageKey: this._dragStorageKey('strip')
34529
+ });
34530
+ }
34531
+
34532
+ /** Bind a single resize listener that re-clamps every dragged surface. */
34533
+ }, {
34534
+ key: "_bindDragResize",
34535
+ value: function _bindDragResize() {
34536
+ var _this11 = this;
34537
+ if (this._dragResizeBound) return;
34538
+ this._dragResizeBound = true;
34539
+ window.addEventListener('resize', function () {
34540
+ var _this11$_ecommerceVoi, _this11$_ecommerceVoi2;
34541
+ _this11._reclampUnit();
34542
+ (_this11$_ecommerceVoi = _this11._ecommerceVoiceStrip) === null || _this11$_ecommerceVoi === void 0 || (_this11$_ecommerceVoi2 = _this11$_ecommerceVoi.reclampDrag) === null || _this11$_ecommerceVoi2 === void 0 || _this11$_ecommerceVoi2.call(_this11$_ecommerceVoi);
34543
+ });
34544
+ }
33634
34545
  }, {
33635
34546
  key: "startNewChat",
33636
34547
  value: function startNewChat() {
@@ -33677,9 +34588,9 @@ var TTPChatWidget = /*#__PURE__*/function () {
33677
34588
  }, {
33678
34589
  key: "_isDomainErrorVisible",
33679
34590
  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');
34591
+ var _this$voiceInterface4, _this$voiceInterface5, _idleState$dataset;
34592
+ if ((_this$voiceInterface4 = this.voiceInterface) !== null && _this$voiceInterface4 !== void 0 && _this$voiceInterface4.isShowingDomainError) return true;
34593
+ 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
34594
  return idleState && ((_idleState$dataset = idleState.dataset) === null || _idleState$dataset === void 0 ? void 0 : _idleState$dataset.domainError) === 'true';
33684
34595
  }
33685
34596
  }, {
@@ -33707,7 +34618,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33707
34618
  }, {
33708
34619
  key: "_openMobileCallTextLanding",
33709
34620
  value: function _openMobileCallTextLanding() {
33710
- var _this9 = this;
34621
+ var _this12 = this;
33711
34622
  if (!this.shadowRoot || window.innerWidth > 768) return;
33712
34623
  var mobileFab = this.shadowRoot.querySelector('.ttp-mobile-fab');
33713
34624
  var mobileLanding = this.shadowRoot.getElementById('ttpMobileLanding');
@@ -33718,30 +34629,30 @@ var TTPChatWidget = /*#__PURE__*/function () {
33718
34629
  // "Back" button: composedPath includes the panel but not #ttpMobileLanding, so it treated
33719
34630
  // the click as "outside" and closed the landing immediately (user only saw the FAB again).
33720
34631
  var open = function open() {
33721
- if (!_this9.shadowRoot || window.innerWidth > 768) return;
33722
- var panel = _this9.shadowRoot.getElementById('text-chat-panel');
34632
+ if (!_this12.shadowRoot || window.innerWidth > 768) return;
34633
+ var panel = _this12.shadowRoot.getElementById('text-chat-panel');
33723
34634
  if (panel) {
33724
34635
  panel.classList.remove('open');
33725
- _this9.isOpen = false;
34636
+ _this12.isOpen = false;
33726
34637
  }
33727
- if (_this9.config.promptAnimation.hideAfterClick) {
33728
- _this9.hidePrompt();
34638
+ if (_this12.config.promptAnimation.hideAfterClick) {
34639
+ _this12.hidePrompt();
33729
34640
  }
33730
- var errorBanner = _this9.shadowRoot.getElementById('ttpMobileLandingError');
34641
+ var errorBanner = _this12.shadowRoot.getElementById('ttpMobileLandingError');
33731
34642
  if (errorBanner) errorBanner.style.display = 'none';
33732
- var fab = _this9.shadowRoot.querySelector('.ttp-mobile-fab');
33733
- var landing = _this9.shadowRoot.getElementById('ttpMobileLanding');
34643
+ var fab = _this12.shadowRoot.querySelector('.ttp-mobile-fab');
34644
+ var landing = _this12.shadowRoot.getElementById('ttpMobileLanding');
33734
34645
  if (!fab || !landing) return;
33735
34646
  fab.style.display = 'none';
33736
34647
  landing.classList.add('active');
33737
- _this9.isMobileLandingOpen = true;
34648
+ _this12.isMobileLandingOpen = true;
33738
34649
  };
33739
34650
  queueMicrotask(open);
33740
34651
  }
33741
34652
  }, {
33742
34653
  key: "setupMobileWidgetEvents",
33743
34654
  value: function setupMobileWidgetEvents() {
33744
- var _this0 = this;
34655
+ var _this13 = this;
33745
34656
  if (!this.shadowRoot) return;
33746
34657
  var mobileFab = this.shadowRoot.querySelector('.ttp-mobile-fab');
33747
34658
  var mobileLanding = this.shadowRoot.getElementById('ttpMobileLanding');
@@ -33749,10 +34660,12 @@ var TTPChatWidget = /*#__PURE__*/function () {
33749
34660
  var closeMobileLanding = function closeMobileLanding() {
33750
34661
  mobileLanding.classList.remove('active');
33751
34662
  mobileFab.style.display = '';
33752
- _this0.isMobileLandingOpen = false;
34663
+ _this13.isMobileLandingOpen = false;
33753
34664
  };
33754
34665
  mobileFab.onclick = function () {
33755
- return _this0._openMobileCallTextLanding();
34666
+ // A drag just ended — don't open the landing on the trailing click.
34667
+ if (_this13._suppressLauncherClick) return;
34668
+ _this13._openMobileCallTextLanding();
33756
34669
  };
33757
34670
  var mobileClose = mobileLanding.querySelector('.ttp-mobile-landing__close');
33758
34671
  if (mobileClose) {
@@ -33762,18 +34675,18 @@ var TTPChatWidget = /*#__PURE__*/function () {
33762
34675
  if (mobileCallBtn) {
33763
34676
  mobileCallBtn.onclick = function () {
33764
34677
  closeMobileLanding();
33765
- var panel = _this0.shadowRoot.getElementById('text-chat-panel');
34678
+ var panel = _this13.shadowRoot.getElementById('text-chat-panel');
33766
34679
  if (panel) {
33767
34680
  panel.style.removeProperty('display');
33768
34681
  panel.classList.add('open');
33769
- _this0.isOpen = true;
34682
+ _this13.isOpen = true;
33770
34683
  }
33771
34684
  mobileFab.style.display = 'none';
33772
- _this0.showVoice();
34685
+ _this13.showVoice();
33773
34686
  // Landing already chose "Voice call" — start the call (mic permission / pre-prompt) instead of
33774
34687
  // leaving users on a second "Start Call" tap that feels broken.
33775
34688
  queueMicrotask(function () {
33776
- _this0.startVoiceCall().catch(function (err) {
34689
+ _this13.startVoiceCall().catch(function (err) {
33777
34690
  console.error('[TTPChatWidget] Mobile landing voice start failed:', err);
33778
34691
  });
33779
34692
  });
@@ -33783,20 +34696,20 @@ var TTPChatWidget = /*#__PURE__*/function () {
33783
34696
  if (mobileChatBtn) {
33784
34697
  mobileChatBtn.onclick = function () {
33785
34698
  closeMobileLanding();
33786
- var panel = _this0.shadowRoot.getElementById('text-chat-panel');
34699
+ var panel = _this13.shadowRoot.getElementById('text-chat-panel');
33787
34700
  if (panel) {
33788
34701
  panel.style.removeProperty('display');
33789
34702
  panel.classList.add('open');
33790
- _this0.isOpen = true;
34703
+ _this13.isOpen = true;
33791
34704
  }
33792
34705
  mobileFab.style.display = 'none';
33793
- _this0.showText();
34706
+ _this13.showText();
33794
34707
  };
33795
34708
  }
33796
34709
 
33797
34710
  // Close mobile landing on outside click
33798
34711
  document.addEventListener('click', function (e) {
33799
- if (!_this0.isMobileLandingOpen) return;
34712
+ if (!_this13.isMobileLandingOpen) return;
33800
34713
  var path = e.composedPath();
33801
34714
  if (!path.includes(mobileLanding) && !path.includes(mobileFab)) {
33802
34715
  closeMobileLanding();
@@ -33805,7 +34718,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33805
34718
 
33806
34719
  // Close mobile landing on Escape
33807
34720
  document.addEventListener('keydown', function (e) {
33808
- if (e.key === 'Escape' && _this0.isMobileLandingOpen) {
34721
+ if (e.key === 'Escape' && _this13.isMobileLandingOpen) {
33809
34722
  closeMobileLanding();
33810
34723
  }
33811
34724
  });
@@ -33821,19 +34734,19 @@ var TTPChatWidget = /*#__PURE__*/function () {
33821
34734
  _prevIsMobile = nowMobile;
33822
34735
  if (nowMobile) {
33823
34736
  // 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');
34737
+ if (_this13.isOpen) {
34738
+ var _this13$shadowRoot, _this13$shadowRoot2;
34739
+ var panel = (_this13$shadowRoot = _this13.shadowRoot) === null || _this13$shadowRoot === void 0 ? void 0 : _this13$shadowRoot.getElementById('text-chat-panel');
33827
34740
  if (panel) {
33828
34741
  panel.classList.remove('open');
33829
- _this0.isOpen = false;
34742
+ _this13.isOpen = false;
33830
34743
  }
33831
- var pill = (_this0$shadowRoot2 = _this0.shadowRoot) === null || _this0$shadowRoot2 === void 0 ? void 0 : _this0$shadowRoot2.getElementById('text-chat-button');
34744
+ var pill = (_this13$shadowRoot2 = _this13.shadowRoot) === null || _this13$shadowRoot2 === void 0 ? void 0 : _this13$shadowRoot2.getElementById('text-chat-button');
33832
34745
  if (pill) pill.classList.remove('open');
33833
34746
  }
33834
34747
  } else {
33835
34748
  // Switched mobile → desktop: close mobile landing/FAB so only desktop pill shows
33836
- if (_this0.isMobileLandingOpen) {
34749
+ if (_this13.isMobileLandingOpen) {
33837
34750
  closeMobileLanding();
33838
34751
  }
33839
34752
  // Ensure mobile FAB is reset to CSS-controlled state (media query hides it on desktop)
@@ -33845,10 +34758,10 @@ var TTPChatWidget = /*#__PURE__*/function () {
33845
34758
  }, {
33846
34759
  key: "setupKeyboardNavigation",
33847
34760
  value: function setupKeyboardNavigation() {
33848
- var _this1 = this;
34761
+ var _this14 = this;
33849
34762
  document.addEventListener('keydown', function (e) {
33850
- if (e.key === 'Escape' && _this1.isOpen) {
33851
- _this1.togglePanel();
34763
+ if (e.key === 'Escape' && _this14.isOpen) {
34764
+ _this14.togglePanel();
33852
34765
  }
33853
34766
  });
33854
34767
  }
@@ -33859,7 +34772,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33859
34772
  }, {
33860
34773
  key: "setupPromptAnimation",
33861
34774
  value: function setupPromptAnimation() {
33862
- var _this10 = this;
34775
+ var _this15 = this;
33863
34776
  if (!this.shadowRoot) return;
33864
34777
  var promptConfig = this.config.promptAnimation || {};
33865
34778
  // Default to disabled if not specified (enabled === true means explicitly enabled)
@@ -33889,7 +34802,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33889
34802
  // Auto-hide after configured seconds (only if widget is closed)
33890
34803
  if (!this.isOpen && promptConfig.hideAfterSeconds !== null && promptConfig.hideAfterSeconds > 0) {
33891
34804
  this.promptAutoHideTimer = setTimeout(function () {
33892
- _this10.hidePrompt();
34805
+ _this15.hidePrompt();
33893
34806
  }, promptConfig.hideAfterSeconds * 1000);
33894
34807
  }
33895
34808
 
@@ -33901,7 +34814,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33901
34814
  // Wrap the callback to also hide pulse rings
33902
34815
  this.config.onConversationStart = function () {
33903
34816
  // Hide pulse rings when call starts
33904
- var pulseRings = _this10.shadowRoot.getElementById('prompt-pulse-rings');
34817
+ var pulseRings = _this15.shadowRoot.getElementById('prompt-pulse-rings');
33905
34818
  if (pulseRings) pulseRings.style.display = 'none';
33906
34819
 
33907
34820
  // Call original callback if it exists
@@ -33913,7 +34826,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33913
34826
  // Also listen to recordingStarted event from SDK if available
33914
34827
  if (this.voiceInterface.sdk.voiceSDK) {
33915
34828
  this.voiceInterface.sdk.voiceSDK.on('recordingStarted', function () {
33916
- var pulseRings = _this10.shadowRoot.getElementById('prompt-pulse-rings');
34829
+ var pulseRings = _this15.shadowRoot.getElementById('prompt-pulse-rings');
33917
34830
  if (pulseRings) pulseRings.style.display = 'none';
33918
34831
  });
33919
34832
  }
@@ -33961,7 +34874,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
33961
34874
  }, {
33962
34875
  key: "showPrompt",
33963
34876
  value: function showPrompt() {
33964
- var _this11 = this;
34877
+ var _this16 = this;
33965
34878
  if (!this.shadowRoot) return;
33966
34879
  var promptConfig = this.config.promptAnimation || {};
33967
34880
  // Default to enabled if not specified
@@ -33981,8 +34894,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
33981
34894
  // Function to actually show the elements
33982
34895
  var doShow = function doShow() {
33983
34896
  // 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) {
34897
+ var promptBubble = _this16.shadowRoot.getElementById('prompt-bubble');
34898
+ if (!promptBubble && _this16.shadowRoot !== document) {
33986
34899
  promptBubble = document.getElementById('prompt-bubble');
33987
34900
  }
33988
34901
  if (promptBubble) {
@@ -33996,8 +34909,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
33996
34909
 
33997
34910
  // Show pulse rings if enabled
33998
34911
  if (promptConfig.showPulseRings !== false) {
33999
- var _pulseRings = _this11.shadowRoot.getElementById('prompt-pulse-rings');
34000
- if (!_pulseRings && _this11.shadowRoot !== document) {
34912
+ var _pulseRings = _this16.shadowRoot.getElementById('prompt-pulse-rings');
34913
+ if (!_pulseRings && _this16.shadowRoot !== document) {
34001
34914
  _pulseRings = document.getElementById('prompt-pulse-rings');
34002
34915
  }
34003
34916
  if (_pulseRings) {
@@ -34034,7 +34947,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34034
34947
  }
34035
34948
  // Start new timer
34036
34949
  this.promptAutoHideTimer = setTimeout(function () {
34037
- _this11.hidePrompt();
34950
+ _this16.hidePrompt();
34038
34951
  }, promptConfig.hideAfterSeconds * 1000);
34039
34952
  }
34040
34953
  }
@@ -34050,14 +34963,23 @@ var TTPChatWidget = /*#__PURE__*/function () {
34050
34963
  }, {
34051
34964
  key: "_doTogglePanel",
34052
34965
  value: function _doTogglePanel() {
34053
- var _this12 = this;
34966
+ var _this17 = this;
34054
34967
  if (!this.shadowRoot) return;
34055
34968
  this.isOpen = !this.isOpen;
34056
34969
  var panel = this.shadowRoot.getElementById('text-chat-panel');
34057
34970
  if (panel) {
34058
34971
  panel.classList.toggle('open');
34059
34972
  if (this.isOpen) {
34973
+ var _this$config$position8;
34060
34974
  panel.style.removeProperty('display');
34975
+ // The panel joins the dragged unit when it opens; re-clamp now that it
34976
+ // has real dimensions (it was hidden/zero-size while closed).
34977
+ if ((_this$config$position8 = this.config.position) !== null && _this$config$position8 !== void 0 && _this$config$position8.draggable) {
34978
+ this._applyUnitOffset();
34979
+ requestAnimationFrame(function () {
34980
+ return _this17._reclampUnit();
34981
+ });
34982
+ }
34061
34983
  }
34062
34984
  }
34063
34985
 
@@ -34072,7 +34994,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34072
34994
  // Panel is opening - hide prompt
34073
34995
  this.hidePrompt();
34074
34996
  setTimeout(function () {
34075
- var input = _this12.shadowRoot.getElementById('messageInput');
34997
+ var input = _this17.shadowRoot.getElementById('messageInput');
34076
34998
  if (input) input.focus();
34077
34999
  }, 100);
34078
35000
  } else {
@@ -34084,13 +35006,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
34084
35006
  // Panel is closing - show prompt (if enabled)
34085
35007
  this.showPrompt();
34086
35008
  setTimeout(function () {
34087
- var _this12$config$prompt;
34088
- var promptBubble = _this12.shadowRoot.getElementById('prompt-bubble');
35009
+ var _this17$config$prompt;
35010
+ var promptBubble = _this17.shadowRoot.getElementById('prompt-bubble');
34089
35011
  if (promptBubble && promptBubble.style.display === 'none') {
34090
35012
  promptBubble.style.display = 'block';
34091
35013
  }
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) {
35014
+ var pulseRings = _this17.shadowRoot.getElementById('prompt-pulse-rings');
35015
+ if (pulseRings && ((_this17$config$prompt = _this17.config.promptAnimation) === null || _this17$config$prompt === void 0 ? void 0 : _this17$config$prompt.showPulseRings) !== false) {
34094
35016
  if (pulseRings.style.display === 'none') {
34095
35017
  pulseRings.style.display = 'block';
34096
35018
  }
@@ -34282,8 +35204,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
34282
35204
  }, {
34283
35205
  key: "showBackButtonWarning",
34284
35206
  value: function showBackButtonWarning() {
34285
- var _this$voiceInterface5, _this$voiceInterface$;
34286
- if (!((_this$voiceInterface5 = this.voiceInterface) !== null && _this$voiceInterface5 !== void 0 && _this$voiceInterface5.isActive)) return;
35207
+ var _this$voiceInterface6, _this$voiceInterface$;
35208
+ if (!((_this$voiceInterface6 = this.voiceInterface) !== null && _this$voiceInterface6 !== void 0 && _this$voiceInterface6.isActive)) return;
34287
35209
 
34288
35210
  // Show warning message in the voice interface
34289
35211
  if ((_this$voiceInterface$ = this.voiceInterface.desktop) !== null && _this$voiceInterface$ !== void 0 && _this$voiceInterface$.showBackButtonWarning) {
@@ -34364,7 +35286,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34364
35286
  _this$config$voice0,
34365
35287
  _this$config$voice1,
34366
35288
  _this$config$voice10,
34367
- _this13 = this;
35289
+ _this18 = this;
34368
35290
  // Deep merge nested objects
34369
35291
  var mergedConfig = _objectSpread({}, this.config);
34370
35292
 
@@ -34582,20 +35504,20 @@ var TTPChatWidget = /*#__PURE__*/function () {
34582
35504
  outputBitDepth: ((_this$config$voice10 = this.config.voice) === null || _this$config$voice10 === void 0 ? void 0 : _this$config$voice10.outputBitDepth) || 16,
34583
35505
  desktopMinimizedEcommerceStripUi: desktopMinimizedEcommerceStripUi,
34584
35506
  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);
35507
+ var _this18$_ecommerceVoi;
35508
+ (_this18$_ecommerceVoi = _this18._ecommerceVoiceStrip) === null || _this18$_ecommerceVoi === void 0 || _this18$_ecommerceVoi.show();
35509
+ if (_this18.isOpen) _this18.minimize();
35510
+ _this18._setPanelFooterVisible(false);
35511
+ _this18._setEcommerceStripLauncherVisible(false);
34590
35512
  } : undefined,
34591
35513
  onDesktopMinimizedStripLauncherRestore: desktopMinimizedEcommerceStripUi ? function () {
34592
- return _this13._restoreDesktopEcommerceStripChrome();
35514
+ return _this18._restoreDesktopEcommerceStripChrome();
34593
35515
  } : undefined,
34594
35516
  // Pass event callbacks to voice interface (forward only; panel is not auto-minimized on call start)
34595
35517
  onConversationStart: function onConversationStart() {
34596
- if (typeof _this13.config.onConversationStart === 'function') {
34597
- var _this13$config;
34598
- (_this13$config = _this13.config).onConversationStart.apply(_this13$config, arguments);
35518
+ if (typeof _this18.config.onConversationStart === 'function') {
35519
+ var _this18$config;
35520
+ (_this18$config = _this18.config).onConversationStart.apply(_this18$config, arguments);
34599
35521
  }
34600
35522
  },
34601
35523
  onConversationEnd: this.config.onConversationEnd,
@@ -34604,48 +35526,48 @@ var TTPChatWidget = /*#__PURE__*/function () {
34604
35526
  onAudioStoppedPlaying: this.config.onAudioStoppedPlaying,
34605
35527
  onSubtitleDisplay: this.config.onSubtitleDisplay,
34606
35528
  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';
35529
+ var _this18$config$behavi;
35530
+ if (_this18._isDomainErrorVisible()) return;
35531
+ var widgetMode = ((_this18$config$behavi = _this18.config.behavior) === null || _this18$config$behavi === void 0 ? void 0 : _this18$config$behavi.mode) || 'unified';
34610
35532
  if (widgetMode === 'unified') {
34611
35533
  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');
35534
+ var _this18$shadowRoot, _this18$shadowRoot2;
35535
+ var panel = (_this18$shadowRoot = _this18.shadowRoot) === null || _this18$shadowRoot === void 0 ? void 0 : _this18$shadowRoot.getElementById('text-chat-panel');
34614
35536
  if (panel) {
34615
35537
  panel.classList.remove('open');
34616
- _this13.isOpen = false;
35538
+ _this18.isOpen = false;
34617
35539
  }
34618
- var fab = (_this13$shadowRoot2 = _this13.shadowRoot) === null || _this13$shadowRoot2 === void 0 ? void 0 : _this13$shadowRoot2.querySelector('.ttp-mobile-fab');
35540
+ var fab = (_this18$shadowRoot2 = _this18.shadowRoot) === null || _this18$shadowRoot2 === void 0 ? void 0 : _this18$shadowRoot2.querySelector('.ttp-mobile-fab');
34619
35541
  if (fab) fab.style.display = '';
34620
35542
  }
34621
- _this13.showLanding();
35543
+ _this18.showLanding();
34622
35544
  }
34623
35545
  },
34624
35546
  onShowVoice: function onShowVoice() {
34625
- _this13.showVoice();
35547
+ _this18.showVoice();
34626
35548
  },
34627
35549
  onShowLanding: function onShowLanding() {
34628
- _this13.showLanding();
35550
+ _this18.showLanding();
34629
35551
  },
34630
35552
  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';
35553
+ var _this18$config$behavi2;
35554
+ if (_this18._isDomainErrorVisible()) return;
35555
+ var widgetMode = ((_this18$config$behavi2 = _this18.config.behavior) === null || _this18$config$behavi2 === void 0 ? void 0 : _this18$config$behavi2.mode) || 'unified';
34634
35556
  if (widgetMode === 'voice-only') {
34635
- _this13.showVoice();
35557
+ _this18.showVoice();
34636
35558
  return;
34637
35559
  }
34638
35560
  if (widgetMode !== 'unified') return;
34639
35561
  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');
35562
+ var _this18$shadowRoot3;
35563
+ var panel = (_this18$shadowRoot3 = _this18.shadowRoot) === null || _this18$shadowRoot3 === void 0 ? void 0 : _this18$shadowRoot3.getElementById('text-chat-panel');
34642
35564
  if (panel) {
34643
35565
  panel.classList.remove('open');
34644
- _this13.isOpen = false;
35566
+ _this18.isOpen = false;
34645
35567
  }
34646
- _this13._openMobileCallTextLanding();
35568
+ _this18._openMobileCallTextLanding();
34647
35569
  } else {
34648
- _this13.showLanding();
35570
+ _this18.showLanding();
34649
35571
  }
34650
35572
  },
34651
35573
  direction: this.getEffectiveTextDirection()
@@ -34692,8 +35614,9 @@ var TTPChatWidget = /*#__PURE__*/function () {
34692
35614
  }, {
34693
35615
  key: "_initEcommerceVoiceStrip",
34694
35616
  value: function _initEcommerceVoiceStrip() {
34695
- var _this14 = this,
34696
- _this$voiceInterface6;
35617
+ var _this19 = this,
35618
+ _this$config$position9,
35619
+ _this$voiceInterface7;
34697
35620
  var flavor = this.config.flavor && _typeof(this.config.flavor) === 'object' ? this.config.flavor : null;
34698
35621
  if (window.innerWidth <= 768) return;
34699
35622
  if (!flavor || flavor.callView !== 'minimized') return;
@@ -34714,31 +35637,34 @@ var TTPChatWidget = /*#__PURE__*/function () {
34714
35637
  endCallButtonColor: v.endCallButtonColor || '#ef4444'
34715
35638
  },
34716
35639
  getVoiceUiState: function getVoiceUiState() {
34717
- var _this14$voiceInterfac, _this14$voiceInterfac2, _this14$voiceInterfac3;
35640
+ var _this19$voiceInterfac, _this19$voiceInterfac2, _this19$voiceInterfac3;
34718
35641
  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)
35642
+ isMicMuted: !!((_this19$voiceInterfac = _this19.voiceInterface) !== null && _this19$voiceInterfac !== void 0 && _this19$voiceInterfac.isMicMuted),
35643
+ isPaused: !!((_this19$voiceInterfac2 = _this19.voiceInterface) !== null && _this19$voiceInterfac2 !== void 0 && _this19$voiceInterfac2.isPaused),
35644
+ isSpeakerMuted: !!((_this19$voiceInterfac3 = _this19.voiceInterface) !== null && _this19$voiceInterfac3 !== void 0 && _this19$voiceInterfac3.isSpeakerMuted)
34722
35645
  };
34723
35646
  },
35647
+ onAbout: function onAbout() {
35648
+ return _this19._openAboutModal();
35649
+ },
34724
35650
  onHangup: function onHangup() {
34725
- if (_this14.voiceInterface) _this14.voiceInterface.endVoiceCall();
35651
+ if (_this19.voiceInterface) _this19.voiceInterface.endVoiceCall();
34726
35652
  },
34727
35653
  onToggleMute: function onToggleMute() {
34728
- if (_this14.voiceInterface) _this14.voiceInterface.toggleMute();
35654
+ if (_this19.voiceInterface) _this19.voiceInterface.toggleMute();
34729
35655
  strip.syncFromVoice();
34730
35656
  },
34731
35657
  onTogglePause: function onTogglePause() {
34732
- if (_this14.voiceInterface) _this14.voiceInterface.togglePause();
35658
+ if (_this19.voiceInterface) _this19.voiceInterface.togglePause();
34733
35659
  strip.syncFromVoice();
34734
35660
  },
34735
35661
  onToggleSpeaker: function onToggleSpeaker() {
34736
- if (_this14.voiceInterface) _this14.voiceInterface.toggleSpeaker();
35662
+ if (_this19.voiceInterface) _this19.voiceInterface.toggleSpeaker();
34737
35663
  strip.syncFromVoice();
34738
35664
  },
34739
35665
  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;
35666
+ var _this19$voiceInterfac4;
35667
+ 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
35668
  if (voiceSDK && typeof voiceSDK.sendMessage === 'function') {
34743
35669
  voiceSDK.sendMessage({
34744
35670
  t: 'text_inject',
@@ -34749,8 +35675,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
34749
35675
  });
34750
35676
  this._ecommerceVoiceStrip = strip;
34751
35677
 
35678
+ // Make the strip draggable too when position.draggable is enabled.
35679
+ if ((_this$config$position9 = this.config.position) !== null && _this$config$position9 !== void 0 && _this$config$position9.draggable) {
35680
+ this.setupDraggableStrip();
35681
+ }
35682
+
34752
35683
  // Show strip when conversation starts
34753
- var agentSDK = (_this$voiceInterface6 = this.voiceInterface) === null || _this$voiceInterface6 === void 0 ? void 0 : _this$voiceInterface6.sdk;
35684
+ var agentSDK = (_this$voiceInterface7 = this.voiceInterface) === null || _this$voiceInterface7 === void 0 ? void 0 : _this$voiceInterface7.sdk;
34754
35685
  if (agentSDK) {
34755
35686
  var origConvStart = agentSDK.onConversationStart;
34756
35687
  agentSDK.onConversationStart = function () {
@@ -34788,7 +35719,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34788
35719
  var _this$voiceInterface$2;
34789
35720
  var origOnCallEnd = this.voiceInterface.config.onCallEnd;
34790
35721
  this.voiceInterface.config.onCallEnd = function () {
34791
- _this14._restoreDesktopEcommerceStripChrome();
35722
+ _this19._restoreDesktopEcommerceStripChrome();
34792
35723
  if (typeof origOnCallEnd === 'function') origOnCallEnd();
34793
35724
  };
34794
35725
 
@@ -34912,7 +35843,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34912
35843
  key: "injectData",
34913
35844
  value: (function () {
34914
35845
  var _injectData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6(data) {
34915
- var _this$voiceInterface7;
35846
+ var _this$voiceInterface8;
34916
35847
  var options,
34917
35848
  voiceSDK,
34918
35849
  ack,
@@ -34937,7 +35868,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
34937
35868
  throw new Error('Voice call is not active');
34938
35869
  case 2:
34939
35870
  // Check if SDK is available
34940
- voiceSDK = (_this$voiceInterface7 = this.voiceInterface) === null || _this$voiceInterface7 === void 0 ? void 0 : _this$voiceInterface7.getVoiceSDK();
35871
+ voiceSDK = (_this$voiceInterface8 = this.voiceInterface) === null || _this$voiceInterface8 === void 0 ? void 0 : _this$voiceInterface8.getVoiceSDK();
34941
35872
  if (voiceSDK) {
34942
35873
  _context6.n = 3;
34943
35874
  break;
@@ -35202,7 +36133,7 @@ var TextInterface = /*#__PURE__*/function () {
35202
36133
  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
36134
  var unifiedMode = ((_this$config$behavior = this.config.behavior) === null || _this$config$behavior === void 0 ? void 0 : _this$config$behavior.mode) === 'unified';
35204
36135
  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>") : '';
36136
+ 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
36137
  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
36138
  }
35208
36139
 
@@ -35334,7 +36265,7 @@ var TextInterface = /*#__PURE__*/function () {
35334
36265
 
35335
36266
  // Add !important to display rules when not using Shadow DOM (to override theme CSS)
35336
36267
  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 ");
36268
+ 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
36269
  }
35339
36270
 
35340
36271
  /**
@@ -37412,6 +38343,7 @@ var VoiceInterface = /*#__PURE__*/function () {
37412
38343
  clearInterval(this.callTimerInterval);
37413
38344
  this.callTimerInterval = null;
37414
38345
  }
38346
+ this.callStartTime = null;
37415
38347
 
37416
38348
  // Hide active state, show idle state first
37417
38349
  activeState = this.shadowRoot.getElementById('voiceActiveState');
@@ -37580,6 +38512,10 @@ var VoiceInterface = /*#__PURE__*/function () {
37580
38512
  clearInterval(this.callTimerInterval);
37581
38513
  this.callTimerInterval = null;
37582
38514
  }
38515
+ // Reset the start time so the next call's timer block (gated on !callStartTime)
38516
+ // actually restarts the interval. Without this, the timer only ever runs for the
38517
+ // first call and stays stuck at 00:00 on every subsequent call.
38518
+ this.callStartTime = null;
37583
38519
 
37584
38520
  // Clean up text inject timeouts and handlers (desktop)
37585
38521
  if (this._textInjectTimeout) {
@@ -40327,6 +41263,21 @@ var Templates = /*#__PURE__*/function () {
40327
41263
  return this.voiceInterface.getTooltip(key);
40328
41264
  }
40329
41265
 
41266
+ /**
41267
+ * Shared "About" info ("i") button markup. Opens the About dialog
41268
+ * (SDK version + last conversation id) wired by TTPChatWidget.
41269
+ * @param {string} [extraClass] - extra class(es) for positioning per view
41270
+ * @returns {string}
41271
+ */
41272
+ }, {
41273
+ key: "infoButton",
41274
+ value: function infoButton() {
41275
+ var extraClass = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
41276
+ var cls = extraClass ? "ttp-info-btn ".concat(extraClass) : 'ttp-info-btn';
41277
+ var label = this.t('aboutTitle') || 'About';
41278
+ 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>");
41279
+ }
41280
+
40330
41281
  /**
40331
41282
  * Generate HTML for voice interface.
40332
41283
  * Automatically detects mobile vs desktop based on voiceInterface.isMobile
@@ -40357,7 +41308,7 @@ var Templates = /*#__PURE__*/function () {
40357
41308
  var transcriptPlaceholder = this.t('transcriptWillAppear') || '';
40358
41309
  var transcriptDir = (0,_rtlText_js__WEBPACK_IMPORTED_MODULE_0__.dirForTranscriptSnippet)(transcriptPlaceholder, this.config);
40359
41310
  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>");
41311
+ 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
41312
  }
40362
41313
 
40363
41314
  /**
@@ -40374,7 +41325,7 @@ var Templates = /*#__PURE__*/function () {
40374
41325
  var headerAvatarUrl = resolveIdleHeaderAvatarUrl(this.config);
40375
41326
  var mobileAvatarInner = headerAvatarUrl ? "<img src=\"".concat(escapeHtmlAttr(headerAvatarUrl), "\" alt=\"\" class=\"voice-avatar-img\" />") : '🤖';
40376
41327
  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) {
41328
+ 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
41329
  return "<div class=\"mobile-waveform-bar\" data-index=\"".concat(i, "\"></div>");
40379
41330
  }).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
41331
  }
@@ -41219,7 +42170,11 @@ __webpack_require__.r(__webpack_exports__);
41219
42170
  "typeMessage": "Type your message...",
41220
42171
  "sendMessageAria": "Send message",
41221
42172
  "domainNotValidated": "Domain not validated",
41222
- "domainErrorMessage": "This domain is not whitelisted. Please contact the administrator to whitelist your website URL."
42173
+ "domainErrorMessage": "This domain is not whitelisted. Please contact the administrator to whitelist your website URL.",
42174
+ "aboutTitle": "About",
42175
+ "aboutVersion": "SDK version",
42176
+ "aboutConversationId": "Last conversation ID",
42177
+ "aboutNoConversation": "No conversation yet"
41223
42178
  },
41224
42179
  "he": {
41225
42180
  "landingTitle": "איך תרצה לתקשר?",
@@ -41252,7 +42207,11 @@ __webpack_require__.r(__webpack_exports__);
41252
42207
  "typeMessage": "הקלד הודעה...",
41253
42208
  "sendMessageAria": "שלח הודעה",
41254
42209
  "domainNotValidated": "דומיין לא מאומת",
41255
- "domainErrorMessage": "דומיין זה לא ברשימת המורשים. אנא פנה למנהל המערכת כדי להוסיף את כתובת האתר שלך לרשימה."
42210
+ "domainErrorMessage": "דומיין זה לא ברשימת המורשים. אנא פנה למנהל המערכת כדי להוסיף את כתובת האתר שלך לרשימה.",
42211
+ "aboutTitle": "אודות",
42212
+ "aboutVersion": "גרסת SDK",
42213
+ "aboutConversationId": "מזהה שיחה אחרון",
42214
+ "aboutNoConversation": "אין שיחה עדיין"
41256
42215
  },
41257
42216
  "ar": {
41258
42217
  "landingTitle": "كيف تريد التواصل؟",
@@ -41285,7 +42244,11 @@ __webpack_require__.r(__webpack_exports__);
41285
42244
  "typeMessage": "اكتب رسالة...",
41286
42245
  "sendMessageAria": "إرسال رسالة",
41287
42246
  "domainNotValidated": "النطاق غير معتمد",
41288
- "domainErrorMessage": "هذا النطاق غير مسموح به. يرجى الاتصال بالمسؤول لإضافة عنوان موقع الويب الخاص بك إلى القائمة."
42247
+ "domainErrorMessage": "هذا النطاق غير مسموح به. يرجى الاتصال بالمسؤول لإضافة عنوان موقع الويب الخاص بك إلى القائمة.",
42248
+ "aboutTitle": "حول",
42249
+ "aboutVersion": "إصدار SDK",
42250
+ "aboutConversationId": "معرّف آخر محادثة",
42251
+ "aboutNoConversation": "لا توجد محادثة بعد"
41289
42252
  },
41290
42253
  "ru": {
41291
42254
  "landingTitle": "Как вы хотите общаться?",
@@ -41318,7 +42281,11 @@ __webpack_require__.r(__webpack_exports__);
41318
42281
  "typeMessage": "Введите сообщение...",
41319
42282
  "sendMessageAria": "Отправить сообщение",
41320
42283
  "domainNotValidated": "Домен не проверен",
41321
- "domainErrorMessage": "Этот домен не в белом списке. Пожалуйста, свяжитесь с администратором, чтобы добавить URL вашего веб-сайта в список."
42284
+ "domainErrorMessage": "Этот домен не в белом списке. Пожалуйста, свяжитесь с администратором, чтобы добавить URL вашего веб-сайта в список.",
42285
+ "aboutTitle": "О приложении",
42286
+ "aboutVersion": "Версия SDK",
42287
+ "aboutConversationId": "ID последнего разговора",
42288
+ "aboutNoConversation": "Разговоров пока нет"
41322
42289
  },
41323
42290
  "es": {
41324
42291
  "landingTitle": "¿Cómo te gustaría comunicarte?",
@@ -41351,7 +42318,11 @@ __webpack_require__.r(__webpack_exports__);
41351
42318
  "typeMessage": "Escribe un mensaje...",
41352
42319
  "sendMessageAria": "Enviar mensaje",
41353
42320
  "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."
42321
+ "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.",
42322
+ "aboutTitle": "Acerca de",
42323
+ "aboutVersion": "Versión del SDK",
42324
+ "aboutConversationId": "ID de última conversación",
42325
+ "aboutNoConversation": "Aún no hay conversación"
41355
42326
  },
41356
42327
  "fr": {
41357
42328
  "landingTitle": "Comment souhaitez-vous communiquer?",
@@ -41384,7 +42355,11 @@ __webpack_require__.r(__webpack_exports__);
41384
42355
  "typeMessage": "Tapez votre message...",
41385
42356
  "sendMessageAria": "Envoyer un message",
41386
42357
  "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."
42358
+ "domainErrorMessage": "Ce domaine n'est pas sur la liste blanche. Veuillez contacter l'administrateur pour ajouter l'URL de votre site Web à la liste.",
42359
+ "aboutTitle": "À propos",
42360
+ "aboutVersion": "Version du SDK",
42361
+ "aboutConversationId": "ID de la dernière conversation",
42362
+ "aboutNoConversation": "Aucune conversation pour l'instant"
41388
42363
  },
41389
42364
  "de": {
41390
42365
  "landingTitle": "Wie möchten Sie kommunizieren?",
@@ -41417,7 +42392,11 @@ __webpack_require__.r(__webpack_exports__);
41417
42392
  "typeMessage": "Geben Sie eine Nachricht ein...",
41418
42393
  "sendMessageAria": "Nachricht senden",
41419
42394
  "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."
42395
+ "domainErrorMessage": "Diese Domain steht nicht auf der Whitelist. Bitte kontaktieren Sie den Administrator, um die URL Ihrer Website zur Liste hinzuzufügen.",
42396
+ "aboutTitle": "Über",
42397
+ "aboutVersion": "SDK-Version",
42398
+ "aboutConversationId": "Letzte Konversations-ID",
42399
+ "aboutNoConversation": "Noch keine Konversation"
41421
42400
  }
41422
42401
  });
41423
42402