ttp-agent-sdk 2.34.13 → 2.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ENHANCED_WIDGET_GUIDE.md +5 -32
- package/GETTING_STARTED.md +20 -73
- package/README.md +14 -38
- package/WORDPRESS_WIX_GUIDE.md +8 -18
- package/dist/agent-widget.dev.js +389 -275
- package/dist/agent-widget.dev.js.map +1 -1
- package/dist/agent-widget.esm.js +1 -1
- package/dist/agent-widget.esm.js.map +1 -1
- package/dist/agent-widget.js +1 -1
- package/dist/agent-widget.js.map +1 -1
- package/dist/examples/test-text-chat.html +2 -26
- package/dist/index.html +169 -439
- package/examples/test-text-chat.html +2 -26
- package/package.json +2 -2
- package/SIGNED_LINK_GUIDE.md +0 -249
- package/dist/examples/test-signed-link.html +0 -503
- package/examples/test-signed-link.html +0 -503
package/dist/agent-widget.dev.js
CHANGED
|
@@ -9704,9 +9704,7 @@ var WebSocketManager = /*#__PURE__*/function (_EventEmitter) {
|
|
|
9704
9704
|
// Store resolve/reject for later use
|
|
9705
9705
|
_this2.connectResolve = resolve;
|
|
9706
9706
|
_this2.connectReject = reject;
|
|
9707
|
-
|
|
9708
|
-
// Get connection from singleton
|
|
9709
|
-
var url = _this2.config.signedUrl || _this2.config.websocketUrl;
|
|
9707
|
+
var url = _this2.config.websocketUrl;
|
|
9710
9708
|
_WebSocketSingleton_js__WEBPACK_IMPORTED_MODULE_1__["default"].getConnection(url, _this2.config).then(function (connection) {
|
|
9711
9709
|
_this2.ws = connection;
|
|
9712
9710
|
|
|
@@ -9754,7 +9752,7 @@ var WebSocketManager = /*#__PURE__*/function (_EventEmitter) {
|
|
|
9754
9752
|
|
|
9755
9753
|
// Use singleton's event forwarding
|
|
9756
9754
|
var handleOpen = function handleOpen(event, url) {
|
|
9757
|
-
var expectedUrl = _this3.config.
|
|
9755
|
+
var expectedUrl = _this3.config.websocketUrl;
|
|
9758
9756
|
if (url === expectedUrl) {
|
|
9759
9757
|
_this3.isConnected = true;
|
|
9760
9758
|
_this3.emit('connected');
|
|
@@ -9768,14 +9766,14 @@ var WebSocketManager = /*#__PURE__*/function (_EventEmitter) {
|
|
|
9768
9766
|
}
|
|
9769
9767
|
};
|
|
9770
9768
|
var handleClose = function handleClose(event, url) {
|
|
9771
|
-
var expectedUrl = _this3.config.
|
|
9769
|
+
var expectedUrl = _this3.config.websocketUrl;
|
|
9772
9770
|
if (url === expectedUrl) {
|
|
9773
9771
|
_this3.isConnected = false;
|
|
9774
9772
|
_this3.emit('disconnected', event);
|
|
9775
9773
|
}
|
|
9776
9774
|
};
|
|
9777
9775
|
var handleError = function handleError(event, url) {
|
|
9778
|
-
var expectedUrl = _this3.config.
|
|
9776
|
+
var expectedUrl = _this3.config.websocketUrl;
|
|
9779
9777
|
if (url === expectedUrl) {
|
|
9780
9778
|
_this3.emit('error', event);
|
|
9781
9779
|
|
|
@@ -9788,7 +9786,7 @@ var WebSocketManager = /*#__PURE__*/function (_EventEmitter) {
|
|
|
9788
9786
|
}
|
|
9789
9787
|
};
|
|
9790
9788
|
var handleMessage = function handleMessage(event, url) {
|
|
9791
|
-
var expectedUrl = _this3.config.
|
|
9789
|
+
var expectedUrl = _this3.config.websocketUrl;
|
|
9792
9790
|
if (url === expectedUrl) {
|
|
9793
9791
|
_this3.handleMessage(event);
|
|
9794
9792
|
}
|
|
@@ -9824,7 +9822,7 @@ var WebSocketManager = /*#__PURE__*/function (_EventEmitter) {
|
|
|
9824
9822
|
}
|
|
9825
9823
|
|
|
9826
9824
|
// Release connection from singleton
|
|
9827
|
-
var url = this.config.
|
|
9825
|
+
var url = this.config.websocketUrl;
|
|
9828
9826
|
if (url) {
|
|
9829
9827
|
_WebSocketSingleton_js__WEBPACK_IMPORTED_MODULE_1__["default"].releaseConnection(url);
|
|
9830
9828
|
}
|
|
@@ -10210,7 +10208,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
|
|
|
10210
10208
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
10211
10209
|
/**
|
|
10212
10210
|
* CartSummary - Compact cart summary bar at the bottom of the ecommerce area.
|
|
10213
|
-
* Shows item count and
|
|
10211
|
+
* Shows item count, total, and a "View Cart" link. Hidden when cart is empty.
|
|
10214
10212
|
*/
|
|
10215
10213
|
var CartSummary = /*#__PURE__*/function () {
|
|
10216
10214
|
function CartSummary() {
|
|
@@ -10218,6 +10216,8 @@ var CartSummary = /*#__PURE__*/function () {
|
|
|
10218
10216
|
this.element = null;
|
|
10219
10217
|
this.itemCount = 0;
|
|
10220
10218
|
this.total = 0;
|
|
10219
|
+
this.currency = '$';
|
|
10220
|
+
this.cartUrl = '/cart';
|
|
10221
10221
|
}
|
|
10222
10222
|
return _createClass(CartSummary, [{
|
|
10223
10223
|
key: "render",
|
|
@@ -10225,19 +10225,20 @@ var CartSummary = /*#__PURE__*/function () {
|
|
|
10225
10225
|
var el = document.createElement('div');
|
|
10226
10226
|
el.className = 'ttp-cart-summary';
|
|
10227
10227
|
el.style.display = 'none';
|
|
10228
|
-
el.innerHTML = "\n <div class=\"ttp-cart-info\">\n <span class=\"ttp-cart-icon\">\uD83D\uDED2</span>\n <span class=\"ttp-cart-count\">0 items</span>\n
|
|
10228
|
+
el.innerHTML = "\n <div class=\"ttp-cart-info\">\n <span class=\"ttp-cart-icon\">\uD83D\uDED2</span>\n <span class=\"ttp-cart-count\">0 items</span>\n <span class=\"ttp-cart-separator\">\xB7</span>\n <span class=\"ttp-cart-total\">".concat(this.currency, "0.00</span>\n </div>\n <a class=\"ttp-cart-view\" href=\"").concat(this.cartUrl, "\" target=\"_top\">View Cart \u203A</a>\n ");
|
|
10229
10229
|
this.element = el;
|
|
10230
10230
|
return el;
|
|
10231
10231
|
}
|
|
10232
10232
|
}, {
|
|
10233
10233
|
key: "update",
|
|
10234
|
-
value: function update(itemCount, total) {
|
|
10234
|
+
value: function update(itemCount, total, currency) {
|
|
10235
10235
|
this.itemCount = itemCount;
|
|
10236
10236
|
this.total = total;
|
|
10237
|
+
if (currency) this.currency = currency;
|
|
10237
10238
|
if (this.element) {
|
|
10238
10239
|
this.element.style.display = itemCount > 0 ? 'flex' : 'none';
|
|
10239
10240
|
this.element.querySelector('.ttp-cart-count').textContent = "".concat(itemCount, " item").concat(itemCount !== 1 ? 's' : '');
|
|
10240
|
-
this.element.querySelector('.ttp-cart-total').textContent = "
|
|
10241
|
+
this.element.querySelector('.ttp-cart-total').textContent = "".concat(this.currency).concat(total.toFixed(2));
|
|
10241
10242
|
}
|
|
10242
10243
|
}
|
|
10243
10244
|
}]);
|
|
@@ -10453,12 +10454,12 @@ var EcommerceManager = /*#__PURE__*/function () {
|
|
|
10453
10454
|
return;
|
|
10454
10455
|
}
|
|
10455
10456
|
this._switchToCompactMode();
|
|
10456
|
-
this._expandPanel();
|
|
10457
10457
|
this._setContainerMode('products');
|
|
10458
10458
|
this.productPicker.hide();
|
|
10459
10459
|
var effectiveLayout = layout || (products.length <= 4 ? 'cards' : 'list');
|
|
10460
10460
|
var pickerEl = this.productPicker.show(products, title, effectiveLayout);
|
|
10461
10461
|
this.container.insertBefore(pickerEl, this.container.firstChild);
|
|
10462
|
+
this._expandPanelToFit(products.length, effectiveLayout);
|
|
10462
10463
|
}
|
|
10463
10464
|
}, {
|
|
10464
10465
|
key: "handleCartUpdated",
|
|
@@ -10515,11 +10516,30 @@ var EcommerceManager = /*#__PURE__*/function () {
|
|
|
10515
10516
|
}
|
|
10516
10517
|
}
|
|
10517
10518
|
}, {
|
|
10518
|
-
key: "
|
|
10519
|
-
value: function
|
|
10519
|
+
key: "_expandPanelToFit",
|
|
10520
|
+
value: function _expandPanelToFit(productCount, layout) {
|
|
10520
10521
|
if (!this.shadowRoot) return;
|
|
10521
10522
|
var panel = this.shadowRoot.getElementById('text-chat-panel');
|
|
10522
|
-
if (panel)
|
|
10523
|
+
if (!panel) return;
|
|
10524
|
+
|
|
10525
|
+
// Compact voice bar: 62px (min-height from CSS)
|
|
10526
|
+
// Picker header: 40px (padding 10px*2 + title 16px + border 1px)
|
|
10527
|
+
// Picker outer margin: 20px (margin 8px*2 + border 2px + shadow)
|
|
10528
|
+
// Conversation area: 150px (transcript + input + padding)
|
|
10529
|
+
var chrome = 62 + 40 + 20 + 150;
|
|
10530
|
+
var productsHeight;
|
|
10531
|
+
if (layout === 'cards') {
|
|
10532
|
+
// Card: image 85 + details ~195 + border 2 = ~282px
|
|
10533
|
+
// Container padding: 24px (12px * 2) + breathing room
|
|
10534
|
+
productsHeight = 360;
|
|
10535
|
+
} else {
|
|
10536
|
+
// List item: ~58px each, container padding 20px
|
|
10537
|
+
productsHeight = Math.min(productCount * 58 + 20, 400);
|
|
10538
|
+
}
|
|
10539
|
+
var totalHeight = chrome + productsHeight;
|
|
10540
|
+
var clampedHeight = Math.min(Math.max(totalHeight, 450), 800);
|
|
10541
|
+
panel.classList.add('ttp-panel-expanded');
|
|
10542
|
+
panel.style.height = "".concat(clampedHeight, "px");
|
|
10523
10543
|
}
|
|
10524
10544
|
}, {
|
|
10525
10545
|
key: "_shrinkPanel",
|
|
@@ -10880,6 +10900,7 @@ var TTPEcommerceWidget = /*#__PURE__*/function () {
|
|
|
10880
10900
|
var _this = this;
|
|
10881
10901
|
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
10882
10902
|
_classCallCheck(this, TTPEcommerceWidget);
|
|
10903
|
+
console.log('[TTPEcommerceWidget] v2.35 initialized');
|
|
10883
10904
|
this.partnerConfig = config.partner || {};
|
|
10884
10905
|
this.cartConfig = config.cart || {};
|
|
10885
10906
|
this.widget = new _widget_TTPChatWidget_js__WEBPACK_IMPORTED_MODULE_0__.TTPChatWidget(config);
|
|
@@ -10912,34 +10933,31 @@ var TTPEcommerceWidget = /*#__PURE__*/function () {
|
|
|
10912
10933
|
}
|
|
10913
10934
|
var self = this;
|
|
10914
10935
|
var originalConnect = agentSDK.connect.bind(agentSDK);
|
|
10915
|
-
agentSDK.connect = /*#__PURE__*/function () {
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
|
|
10931
|
-
}
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
|
|
10936
|
-
|
|
10937
|
-
}
|
|
10938
|
-
})
|
|
10939
|
-
|
|
10940
|
-
return _ref.apply(this, arguments);
|
|
10941
|
-
};
|
|
10942
|
-
}();
|
|
10936
|
+
agentSDK.connect = /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
10937
|
+
return _regenerator().w(function (_context) {
|
|
10938
|
+
while (1) switch (_context.n) {
|
|
10939
|
+
case 0:
|
|
10940
|
+
_context.n = 1;
|
|
10941
|
+
return originalConnect();
|
|
10942
|
+
case 1:
|
|
10943
|
+
if (this.voiceSDK) {
|
|
10944
|
+
this.voiceSDK.on('message', function (message) {
|
|
10945
|
+
var type = message.t || message.type;
|
|
10946
|
+
if (type === 'show_products') {
|
|
10947
|
+
self.ecommerce.handleShowProducts(message);
|
|
10948
|
+
} else if (type === 'cart_updated') {
|
|
10949
|
+
self._handleCartUpdatedFromServer(message);
|
|
10950
|
+
} else if (type === 'add_to_store_cart') {
|
|
10951
|
+
self._handleAddToStoreCart(message);
|
|
10952
|
+
}
|
|
10953
|
+
});
|
|
10954
|
+
console.log('[TTPEcommerceWidget] E-commerce message listener attached');
|
|
10955
|
+
}
|
|
10956
|
+
case 2:
|
|
10957
|
+
return _context.a(2);
|
|
10958
|
+
}
|
|
10959
|
+
}, _callee, this);
|
|
10960
|
+
}));
|
|
10943
10961
|
}
|
|
10944
10962
|
|
|
10945
10963
|
// ═══════════════════════════════════════════
|
|
@@ -10994,7 +11012,7 @@ var TTPEcommerceWidget = /*#__PURE__*/function () {
|
|
|
10994
11012
|
}
|
|
10995
11013
|
}, _callee2, null, [[0, 2]]);
|
|
10996
11014
|
}));
|
|
10997
|
-
return function (
|
|
11015
|
+
return function (_x) {
|
|
10998
11016
|
return _ref2.apply(this, arguments);
|
|
10999
11017
|
};
|
|
11000
11018
|
}());
|
|
@@ -11026,6 +11044,88 @@ var TTPEcommerceWidget = /*#__PURE__*/function () {
|
|
|
11026
11044
|
}
|
|
11027
11045
|
|
|
11028
11046
|
// ═══════════════════════════════════════════
|
|
11047
|
+
// SHOPIFY STORE CART (client-side via AJAX Cart API)
|
|
11048
|
+
// ═══════════════════════════════════════════
|
|
11049
|
+
|
|
11050
|
+
/**
|
|
11051
|
+
* Handle add_to_store_cart message from the backend.
|
|
11052
|
+
* Calls Shopify's /cart/add.js from the browser so the item goes into
|
|
11053
|
+
* the store's session-based cart (not a headless Storefront API cart).
|
|
11054
|
+
*
|
|
11055
|
+
* We don't attempt to refresh the theme's cart UI (icon badge, drawer)
|
|
11056
|
+
* because there's no universal mechanism — every theme is different.
|
|
11057
|
+
* The user will see the updated cart when they navigate to /cart or refresh.
|
|
11058
|
+
* Our own CartToast + CartSummary provide immediate visual feedback.
|
|
11059
|
+
*/
|
|
11060
|
+
}, {
|
|
11061
|
+
key: "_handleAddToStoreCart",
|
|
11062
|
+
value: function () {
|
|
11063
|
+
var _handleAddToStoreCart2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(data) {
|
|
11064
|
+
var variantId, quantity, productName, price, _cartResponse$items, _cartResponse$items2, response, cartResponse, cartData, _t3;
|
|
11065
|
+
return _regenerator().w(function (_context4) {
|
|
11066
|
+
while (1) switch (_context4.p = _context4.n) {
|
|
11067
|
+
case 0:
|
|
11068
|
+
variantId = data.variantId, quantity = data.quantity, productName = data.productName, price = data.price;
|
|
11069
|
+
_context4.p = 1;
|
|
11070
|
+
_context4.n = 2;
|
|
11071
|
+
return fetch('/cart/add.js', {
|
|
11072
|
+
method: 'POST',
|
|
11073
|
+
headers: {
|
|
11074
|
+
'Content-Type': 'application/json'
|
|
11075
|
+
},
|
|
11076
|
+
body: JSON.stringify({
|
|
11077
|
+
items: [{
|
|
11078
|
+
id: parseInt(variantId, 10),
|
|
11079
|
+
quantity: quantity || 1
|
|
11080
|
+
}]
|
|
11081
|
+
})
|
|
11082
|
+
});
|
|
11083
|
+
case 2:
|
|
11084
|
+
response = _context4.v;
|
|
11085
|
+
if (response.ok) {
|
|
11086
|
+
_context4.n = 3;
|
|
11087
|
+
break;
|
|
11088
|
+
}
|
|
11089
|
+
console.error('[TTPEcommerceWidget] Failed to add to Shopify cart:', response.status, response.statusText);
|
|
11090
|
+
return _context4.a(2);
|
|
11091
|
+
case 3:
|
|
11092
|
+
_context4.n = 4;
|
|
11093
|
+
return response.json();
|
|
11094
|
+
case 4:
|
|
11095
|
+
cartResponse = _context4.v;
|
|
11096
|
+
console.log('[TTPEcommerceWidget] Added to Shopify store cart:', cartResponse);
|
|
11097
|
+
_context4.n = 5;
|
|
11098
|
+
return fetch('/cart.js').then(function (r) {
|
|
11099
|
+
return r.json();
|
|
11100
|
+
});
|
|
11101
|
+
case 5:
|
|
11102
|
+
cartData = _context4.v;
|
|
11103
|
+
this._handleCartUpdatedFromServer({
|
|
11104
|
+
action: 'added',
|
|
11105
|
+
product: {
|
|
11106
|
+
id: variantId,
|
|
11107
|
+
name: productName || ((_cartResponse$items = cartResponse.items) === null || _cartResponse$items === void 0 || (_cartResponse$items = _cartResponse$items[0]) === null || _cartResponse$items === void 0 ? void 0 : _cartResponse$items.title) || 'Product',
|
|
11108
|
+
price: price || ((_cartResponse$items2 = cartResponse.items) === null || _cartResponse$items2 === void 0 || (_cartResponse$items2 = _cartResponse$items2[0]) === null || _cartResponse$items2 === void 0 ? void 0 : _cartResponse$items2.price) / 100 || 0
|
|
11109
|
+
},
|
|
11110
|
+
cartTotal: cartData.total_price / 100,
|
|
11111
|
+
cartItemCount: cartData.item_count
|
|
11112
|
+
});
|
|
11113
|
+
_context4.n = 7;
|
|
11114
|
+
break;
|
|
11115
|
+
case 6:
|
|
11116
|
+
_context4.p = 6;
|
|
11117
|
+
_t3 = _context4.v;
|
|
11118
|
+
console.error('[TTPEcommerceWidget] Error adding to Shopify cart:', _t3);
|
|
11119
|
+
case 7:
|
|
11120
|
+
return _context4.a(2);
|
|
11121
|
+
}
|
|
11122
|
+
}, _callee4, this, [[1, 6]]);
|
|
11123
|
+
}));
|
|
11124
|
+
function _handleAddToStoreCart(_x2) {
|
|
11125
|
+
return _handleAddToStoreCart2.apply(this, arguments);
|
|
11126
|
+
}
|
|
11127
|
+
return _handleAddToStoreCart;
|
|
11128
|
+
}() // ═══════════════════════════════════════════
|
|
11029
11129
|
// PRODUCT SELECTION (server manages cart)
|
|
11030
11130
|
// ═══════════════════════════════════════════
|
|
11031
11131
|
}, {
|
|
@@ -11081,45 +11181,45 @@ var TTPEcommerceWidget = /*#__PURE__*/function () {
|
|
|
11081
11181
|
self.ecommerce.handleMessage(payload);
|
|
11082
11182
|
},
|
|
11083
11183
|
showProducts: function () {
|
|
11084
|
-
var _showProducts = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
11184
|
+
var _showProducts = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(query) {
|
|
11085
11185
|
var limit,
|
|
11086
11186
|
sessionId,
|
|
11087
11187
|
baseUrl,
|
|
11088
11188
|
response,
|
|
11089
11189
|
data,
|
|
11090
|
-
|
|
11091
|
-
|
|
11092
|
-
return _regenerator().w(function (
|
|
11093
|
-
while (1) switch (
|
|
11190
|
+
_args5 = arguments,
|
|
11191
|
+
_t4;
|
|
11192
|
+
return _regenerator().w(function (_context5) {
|
|
11193
|
+
while (1) switch (_context5.p = _context5.n) {
|
|
11094
11194
|
case 0:
|
|
11095
|
-
limit =
|
|
11096
|
-
sessionId =
|
|
11195
|
+
limit = _args5.length > 1 && _args5[1] !== undefined ? _args5[1] : 5;
|
|
11196
|
+
sessionId = _args5.length > 2 && _args5[2] !== undefined ? _args5[2] : 'test';
|
|
11097
11197
|
baseUrl = window.__TTP_MOCK_API__ || 'https://backend.talktopc.com';
|
|
11098
|
-
|
|
11099
|
-
|
|
11198
|
+
_context5.p = 1;
|
|
11199
|
+
_context5.n = 2;
|
|
11100
11200
|
return fetch("".concat(baseUrl, "/api/partner/mock-store/products/search?q=").concat(encodeURIComponent(query), "&limit=").concat(limit, "&sessionId=").concat(encodeURIComponent(sessionId)));
|
|
11101
11201
|
case 2:
|
|
11102
|
-
response =
|
|
11103
|
-
|
|
11202
|
+
response = _context5.v;
|
|
11203
|
+
_context5.n = 3;
|
|
11104
11204
|
return response.json();
|
|
11105
11205
|
case 3:
|
|
11106
|
-
data =
|
|
11206
|
+
data = _context5.v;
|
|
11107
11207
|
self.ecommerce.handleShowProducts({
|
|
11108
11208
|
t: 'show_products',
|
|
11109
11209
|
products: data.products,
|
|
11110
11210
|
title: "".concat(data.totalCount, " results for \"").concat(query, "\""),
|
|
11111
11211
|
layout: data.products.length <= 4 ? 'cards' : 'list'
|
|
11112
11212
|
});
|
|
11113
|
-
|
|
11213
|
+
_context5.n = 5;
|
|
11114
11214
|
break;
|
|
11115
11215
|
case 4:
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
console.error('[TTPEcommerceWidget] showProducts failed:',
|
|
11216
|
+
_context5.p = 4;
|
|
11217
|
+
_t4 = _context5.v;
|
|
11218
|
+
console.error('[TTPEcommerceWidget] showProducts failed:', _t4);
|
|
11119
11219
|
case 5:
|
|
11120
|
-
return
|
|
11220
|
+
return _context5.a(2);
|
|
11121
11221
|
}
|
|
11122
|
-
},
|
|
11222
|
+
}, _callee5, null, [[1, 4]]);
|
|
11123
11223
|
}));
|
|
11124
11224
|
function showProducts(_x3) {
|
|
11125
11225
|
return _showProducts.apply(this, arguments);
|
|
@@ -11230,7 +11330,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
11230
11330
|
* Follows the same pattern as Styles.generateCSS().
|
|
11231
11331
|
*/
|
|
11232
11332
|
function generateEcommerceCSS() {
|
|
11233
|
-
return "\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n ECOMMERCE AREA\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/*\n * When products are visible, expand the panel to 800px.\n * When the class is removed, the panel returns to its CSS-defined default.\n */\n#text-chat-panel.ttp-panel-expanded {\n height: 800px !important;\n}\n\n/*\n * Layout overrides when ecommerce layer is active.\n * voiceActiveState is a flex column: [voice-controls] [ecommerce] [conversation].\n * Ecommerce area fills the middle and scrolls; conversation panel stays at bottom.\n */\n#voiceActiveState {\n flex: 1 1 0 !important;\n min-height: 0 !important;\n overflow: hidden !important;\n}\n\n.desktop-voice-section {\n flex-shrink: 1 !important;\n}\n\n.desktop-conversation-panel {\n flex: 1 1 0 !important;\n min-height: 0 !important;\n display: flex !important;\n flex-direction: column !important;\n}\n\n.desktop-conversation-panel .live-transcript-collapsed {\n flex: 1 1 0 !important;\n min-height: 40px !important;\n overflow: hidden !important;\n}\n\n.desktop-conversation-panel .voice-text-input-area {\n margin-top: auto !important;\n padding: 3px 16px !important;\n}\n\n.desktop-conversation-panel .voice-input-hint {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .desktop-voice-section {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .compact-voice-section {\n display: flex !important;\n}\n\n#voiceActiveState.ttp-products-visible .desktop-conversation-panel {\n flex: 0 0 auto !important;\n}\n\n#voiceActiveState.ttp-products-visible .conversation-history {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .live-transcript-collapsed {\n flex: 0 0 auto !important;\n}\n\n.voice-text-input-area {\n flex-shrink: 0 !important;\n}\n\n.conversation-history {\n flex: 1 1 0 !important;\n min-height: 0 !important;\n overflow-y: auto !important;\n}\n\n.ttp-ecommerce-area {\n display: flex;\n flex-direction: column;\n width: 100%;\n flex: 1 1 0;\n min-height: 0;\n overflow-x: hidden;\n overflow-y: auto;\n position: relative;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT PICKER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-picker {\n background: #fff;\n border-radius: 14px;\n border: 1px solid #e5e7eb;\n box-shadow: 0 6px 24px rgba(0,0,0,0.08);\n margin: 8px 12px;\n overflow: hidden;\n animation: ttpSlideUp 0.25s ease;\n display: flex;\n flex-direction: column;\n}\n\n@keyframes ttpSlideUp {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.ttp-picker-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 14px;\n border-bottom: 1px solid #f1f5f9;\n flex-shrink: 0;\n}\n\n.ttp-picker-title {\n font-size: 12px;\n font-weight: 600;\n color: #64748b;\n}\n\n.ttp-picker-close {\n background: none;\n border: none;\n cursor: pointer;\n color: #94a3b8;\n font-size: 14px;\n padding: 2px 6px;\n border-radius: 4px;\n}\n.ttp-picker-close:hover {\n background: #f1f5f9;\n color: #475569;\n}\n\n/* Horizontal card layout */\n.ttp-products-horizontal {\n display: flex;\n gap: 10px;\n padding: 12px;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: thin;\n}\n.ttp-products-horizontal::-webkit-scrollbar { height: 4px; }\n.ttp-products-horizontal::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 2px; }\n\n/* Vertical list layout */\n.ttp-products-vertical {\n padding: 8px 12px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex: 1;\n min-height: 0;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT CARD (horizontal)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-card {\n width: 140px;\n flex-shrink: 0;\n background: #fff;\n border-radius: 12px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n transition: border-color 0.15s;\n}\n.ttp-product-card:hover { border-color: #3b82f6; }\n\n.ttp-product-image {\n height: 85px;\n background: #f8fafc;\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n overflow: hidden;\n}\n.ttp-product-image img {\n max-width: 90%;\n max-height: 75px;\n object-fit: contain;\n}\n\n.ttp-stock-badge {\n position: absolute;\n top: 4px; right: 4px;\n background: #fef2f2;\n color: #ef4444;\n font-size: 9px;\n font-weight: 600;\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.ttp-product-details {\n padding: 8px 10px 10px;\n}\n\n.ttp-product-name {\n font-size: 12px;\n font-weight: 600;\n color: #1e293b;\n line-height: 1.3;\n min-height: 30px;\n}\n\n.ttp-product-meta {\n font-size: 10px;\n color: #94a3b8;\n margin-top: 2px;\n}\n\n.ttp-product-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 6px;\n}\n\n.ttp-product-price {\n font-size: 14px;\n font-weight: 700;\n color: #1e293b;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT COMPACT (list view)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-compact {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n background: #fff;\n border-radius: 10px;\n border: 1px solid #e5e7eb;\n transition: border-color 0.15s;\n}\n.ttp-product-compact:hover { border-color: #3b82f6; }\n\n.ttp-product-image-sm {\n width: 40px; height: 40px;\n border-radius: 8px;\n background: #f8fafc;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n overflow: hidden;\n}\n.ttp-product-image-sm img {\n max-width: 36px;\n max-height: 36px;\n object-fit: contain;\n}\n\n.ttp-product-compact .ttp-product-info {\n flex: 1;\n min-width: 0;\n}\n.ttp-product-compact .ttp-product-name {\n min-height: auto;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ttp-product-compact .ttp-product-action {\n text-align: right;\n flex-shrink: 0;\n}\n.ttp-product-compact .ttp-product-price {\n font-size: 13px;\n}\n\n.ttp-out-of-stock {\n font-size: 10px;\n color: #ef4444;\n font-weight: 500;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n ADD BUTTON\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-add-btn {\n padding: 4px 14px;\n border-radius: 8px;\n border: none;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n background: #3b82f6;\n color: #fff;\n transition: all 0.15s;\n}\n.ttp-add-btn:hover { background: #2563eb; }\n.ttp-add-btn:active { transform: scale(0.95); }\n.ttp-add-btn.ttp-added { background: #10b981 !important; }\n.ttp-add-btn:disabled { cursor: default; }\n.ttp-add-btn.ttp-update-btn { background: #f59e0b; }\n.ttp-add-btn.ttp-update-btn:hover { background: #d97706; }\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CART TOAST\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-cart-toast {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n margin: 0 12px;\n background: #f0fdf4;\n border-radius: 12px;\n border: 1px solid #bbf7d0;\n animation: ttpToastIn 0.25s ease;\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n z-index: 10;\n box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n}\n\n@keyframes ttpToastIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ttp-cart-toast.ttp-toast-hiding {\n animation: ttpSlideDown 0.3s ease forwards;\n}\n\n@keyframes ttpSlideDown {\n to { opacity: 0; transform: translateY(-8px); height: 0; padding: 0; margin: 0; overflow: hidden; }\n}\n\n.ttp-toast-icon {\n width: 24px; height: 24px;\n border-radius: 50%;\n background: #10b981;\n color: #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 700;\n flex-shrink: 0;\n}\n\n.ttp-toast-content { flex: 1; min-width: 0; }\n.ttp-toast-title { font-size: 12px; font-weight: 600; color: #166534; }\n.ttp-toast-product {\n font-size: 11px;\n color: #15803d;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ttp-toast-undo {\n background: none;\n border: 1px solid #86efac;\n border-radius: 6px;\n padding: 3px 8px;\n font-size: 10px;\n color: #15803d;\n cursor: pointer;\n font-weight: 600;\n flex-shrink: 0;\n}\n.ttp-toast-undo:hover { background: #dcfce7; }\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CART SUMMARY BAR\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-cart-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 14px;\n margin: 4px 12px 8px;\n background: #f8fafc;\n border-radius: 10px;\n border: 1px solid #e2e8f0;\n}\n\n.ttp-cart-info {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.ttp-cart-icon { font-size: 14px; }\n.ttp-cart-count { font-size: 12px; font-weight: 600; color: #475569; }\n.ttp-cart-total { font-size: 14px; font-weight: 700; color: #1e293b; }\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n QUANTITY/WEIGHT STEPPER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-stepper {\n display: flex;\n align-items: center;\n gap: 2px;\n margin: 4px 0;\n}\n\n.ttp-stepper-btn {\n width: 24px;\n height: 24px;\n border-radius: 6px;\n border: 1px solid #e2e8f0;\n background: #f8fafc;\n color: #475569;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n line-height: 1;\n transition: all 0.15s;\n flex-shrink: 0;\n}\n\n.ttp-stepper-btn:hover:not(:disabled) {\n background: #e2e8f0;\n border-color: #cbd5e1;\n}\n\n.ttp-stepper-btn:active:not(:disabled) {\n transform: scale(0.9);\n}\n\n.ttp-stepper-btn:disabled,\n.ttp-stepper-disabled {\n opacity: 0.35;\n cursor: default;\n}\n\n.ttp-stepper-value {\n font-size: 12px;\n font-weight: 600;\n color: #1e293b;\n min-width: 36px;\n text-align: center;\n user-select: none;\n}\n\n.ttp-product-compact .ttp-stepper {\n justify-content: flex-end;\n}\n\n.ttp-product-compact .ttp-product-action {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 2px;\n}\n\n.ttp-product-card .ttp-stepper {\n justify-content: center;\n margin: 4px 0;\n}\n\n.ttp-product-card .ttp-product-footer {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n}\n\n ";
|
|
11333
|
+
return "\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n ECOMMERCE AREA\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/*\n * When products are visible, expand the panel dynamically.\n * Actual height is set via inline style by EcommerceManager._expandPanelToFit().\n * When the class is removed, the panel returns to its CSS-defined default.\n */\n#text-chat-panel.ttp-panel-expanded {\n transition: height 0.25s ease;\n}\n\n/*\n * Layout overrides when ecommerce layer is active.\n * voiceActiveState is a flex column: [voice-controls] [ecommerce] [conversation].\n * Ecommerce area fills the middle and scrolls; conversation panel stays at bottom.\n */\n#voiceActiveState {\n flex: 1 1 0 !important;\n min-height: 0 !important;\n overflow: hidden !important;\n}\n\n.desktop-voice-section {\n flex-shrink: 1 !important;\n}\n\n.desktop-conversation-panel {\n flex: 1 1 0 !important;\n min-height: 0 !important;\n display: flex !important;\n flex-direction: column !important;\n}\n\n.desktop-conversation-panel .live-transcript-collapsed {\n flex: 1 1 0 !important;\n min-height: 40px !important;\n overflow: hidden !important;\n}\n\n.desktop-conversation-panel .voice-text-input-area {\n margin-top: auto !important;\n padding: 3px 16px !important;\n}\n\n.desktop-conversation-panel .voice-input-hint {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .desktop-voice-section {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .compact-voice-section {\n display: flex !important;\n}\n\n#voiceActiveState.ttp-products-visible .desktop-conversation-panel {\n flex: 0 0 auto !important;\n}\n\n#voiceActiveState.ttp-products-visible .conversation-history {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .live-transcript-collapsed {\n flex: 0 0 auto !important;\n}\n\n.voice-text-input-area {\n flex-shrink: 0 !important;\n}\n\n.conversation-history {\n flex: 1 1 0 !important;\n min-height: 0 !important;\n overflow-y: auto !important;\n}\n\n.ttp-ecommerce-area {\n display: flex;\n flex-direction: column;\n width: 100%;\n flex: 1 1 0;\n min-height: 0;\n overflow-x: hidden;\n overflow-y: auto;\n position: relative;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT PICKER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-picker {\n background: #fff;\n border-radius: 14px;\n border: 1px solid #e5e7eb;\n box-shadow: 0 6px 24px rgba(0,0,0,0.08);\n margin: 8px 12px;\n overflow: hidden;\n animation: ttpSlideUp 0.25s ease;\n display: flex;\n flex-direction: column;\n}\n\n@keyframes ttpSlideUp {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.ttp-picker-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 14px;\n border-bottom: 1px solid #f1f5f9;\n flex-shrink: 0;\n}\n\n.ttp-picker-title {\n font-size: 12px;\n font-weight: 600;\n color: #64748b;\n}\n\n.ttp-picker-close {\n background: none;\n border: none;\n cursor: pointer;\n color: #94a3b8;\n font-size: 14px;\n padding: 2px 6px;\n border-radius: 4px;\n}\n.ttp-picker-close:hover {\n background: #f1f5f9;\n color: #475569;\n}\n\n/* Horizontal card layout */\n.ttp-products-horizontal {\n display: flex;\n gap: 10px;\n padding: 12px;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: thin;\n}\n.ttp-products-horizontal::-webkit-scrollbar { height: 4px; }\n.ttp-products-horizontal::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 2px; }\n\n/* Vertical list layout */\n.ttp-products-vertical {\n padding: 8px 12px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex: 1;\n min-height: 0;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT CARD (horizontal)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-card {\n width: 140px;\n flex-shrink: 0;\n background: #fff;\n border-radius: 12px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n transition: border-color 0.15s;\n}\n.ttp-product-card:hover { border-color: #3b82f6; }\n\n.ttp-product-image {\n height: 85px;\n background: #f8fafc;\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n overflow: hidden;\n}\n.ttp-product-image img {\n max-width: 90%;\n max-height: 75px;\n object-fit: contain;\n}\n\n.ttp-stock-badge {\n position: absolute;\n top: 4px; right: 4px;\n background: #fef2f2;\n color: #ef4444;\n font-size: 9px;\n font-weight: 600;\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.ttp-product-details {\n padding: 8px 10px 10px;\n}\n\n.ttp-product-name {\n font-size: 12px;\n font-weight: 600;\n color: #1e293b;\n line-height: 1.3;\n min-height: 30px;\n}\n\n.ttp-product-meta {\n font-size: 10px;\n color: #94a3b8;\n margin-top: 2px;\n}\n\n.ttp-product-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 6px;\n}\n\n.ttp-product-price {\n font-size: 14px;\n font-weight: 700;\n color: #1e293b;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT COMPACT (list view)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-compact {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n background: #fff;\n border-radius: 10px;\n border: 1px solid #e5e7eb;\n transition: border-color 0.15s;\n}\n.ttp-product-compact:hover { border-color: #3b82f6; }\n\n.ttp-product-image-sm {\n width: 40px; height: 40px;\n border-radius: 8px;\n background: #f8fafc;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n overflow: hidden;\n}\n.ttp-product-image-sm img {\n max-width: 36px;\n max-height: 36px;\n object-fit: contain;\n}\n\n.ttp-product-compact .ttp-product-info {\n flex: 1;\n min-width: 0;\n}\n.ttp-product-compact .ttp-product-name {\n min-height: auto;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ttp-product-compact .ttp-product-action {\n text-align: right;\n flex-shrink: 0;\n}\n.ttp-product-compact .ttp-product-price {\n font-size: 13px;\n}\n\n.ttp-out-of-stock {\n font-size: 10px;\n color: #ef4444;\n font-weight: 500;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n ADD BUTTON\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-add-btn {\n padding: 4px 14px;\n border-radius: 8px;\n border: none;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n background: #3b82f6;\n color: #fff;\n transition: all 0.15s;\n}\n.ttp-add-btn:hover { background: #2563eb; }\n.ttp-add-btn:active { transform: scale(0.95); }\n.ttp-add-btn.ttp-added { background: #10b981 !important; }\n.ttp-add-btn:disabled { cursor: default; }\n.ttp-add-btn.ttp-update-btn { background: #f59e0b; }\n.ttp-add-btn.ttp-update-btn:hover { background: #d97706; }\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CART TOAST\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-cart-toast {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n margin: 0 12px;\n background: #f0fdf4;\n border-radius: 12px;\n border: 1px solid #bbf7d0;\n animation: ttpToastIn 0.25s ease;\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n z-index: 10;\n box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n}\n\n@keyframes ttpToastIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ttp-cart-toast.ttp-toast-hiding {\n animation: ttpSlideDown 0.3s ease forwards;\n}\n\n@keyframes ttpSlideDown {\n to { opacity: 0; transform: translateY(-8px); height: 0; padding: 0; margin: 0; overflow: hidden; }\n}\n\n.ttp-toast-icon {\n width: 24px; height: 24px;\n border-radius: 50%;\n background: #10b981;\n color: #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 700;\n flex-shrink: 0;\n}\n\n.ttp-toast-content { flex: 1; min-width: 0; }\n.ttp-toast-title { font-size: 12px; font-weight: 600; color: #166534; }\n.ttp-toast-product {\n font-size: 11px;\n color: #15803d;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ttp-toast-undo {\n background: none;\n border: 1px solid #86efac;\n border-radius: 6px;\n padding: 3px 8px;\n font-size: 10px;\n color: #15803d;\n cursor: pointer;\n font-weight: 600;\n flex-shrink: 0;\n}\n.ttp-toast-undo:hover { background: #dcfce7; }\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CART SUMMARY BAR\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-cart-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 14px;\n margin: 4px 12px 8px;\n background: #f8fafc;\n border-radius: 10px;\n border: 1px solid #e2e8f0;\n}\n\n.ttp-cart-info {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.ttp-cart-icon { font-size: 14px; }\n.ttp-cart-count { font-size: 12px; font-weight: 600; color: #475569; }\n.ttp-cart-separator { font-size: 12px; color: #94a3b8; }\n.ttp-cart-total { font-size: 13px; font-weight: 700; color: #1e293b; }\n.ttp-cart-view {\n font-size: 12px;\n font-weight: 600;\n color: #6366f1;\n text-decoration: none;\n cursor: pointer;\n white-space: nowrap;\n}\n.ttp-cart-view:hover {\n color: #4f46e5;\n text-decoration: underline;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n QUANTITY/WEIGHT STEPPER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-stepper {\n display: flex;\n align-items: center;\n gap: 2px;\n margin: 4px 0;\n}\n\n.ttp-stepper-btn {\n width: 24px;\n height: 24px;\n border-radius: 6px;\n border: 1px solid #e2e8f0;\n background: #f8fafc;\n color: #475569;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n line-height: 1;\n transition: all 0.15s;\n flex-shrink: 0;\n}\n\n.ttp-stepper-btn:hover:not(:disabled) {\n background: #e2e8f0;\n border-color: #cbd5e1;\n}\n\n.ttp-stepper-btn:active:not(:disabled) {\n transform: scale(0.9);\n}\n\n.ttp-stepper-btn:disabled,\n.ttp-stepper-disabled {\n opacity: 0.35;\n cursor: default;\n}\n\n.ttp-stepper-value {\n font-size: 12px;\n font-weight: 600;\n color: #1e293b;\n min-width: 36px;\n text-align: center;\n user-select: none;\n}\n\n.ttp-product-compact .ttp-stepper {\n justify-content: flex-end;\n}\n\n.ttp-product-compact .ttp-product-action {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 2px;\n}\n\n.ttp-product-card .ttp-stepper {\n justify-content: center;\n margin: 4px 0;\n}\n\n.ttp-product-card .ttp-product-footer {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n}\n\n ";
|
|
11234
11334
|
}
|
|
11235
11335
|
|
|
11236
11336
|
/***/ }),
|
|
@@ -14129,8 +14229,6 @@ function registerVisualTools(registry) {
|
|
|
14129
14229
|
});
|
|
14130
14230
|
if (missingTools.length > 0) {
|
|
14131
14231
|
console.error('[TTP] ❌ Some visual tools failed to register:', missingTools);
|
|
14132
|
-
} else {
|
|
14133
|
-
console.log('[TTP] 👁️ Visual assistant tools registered successfully:', registeredTools);
|
|
14134
14232
|
}
|
|
14135
14233
|
}
|
|
14136
14234
|
|
|
@@ -14258,9 +14356,9 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
14258
14356
|
_this = _callSuper(this, AudioPlayer);
|
|
14259
14357
|
|
|
14260
14358
|
// Version identification log
|
|
14261
|
-
console.log('%c🔊 AUDIO PLAYER -
|
|
14262
|
-
console.log('%
|
|
14263
|
-
console.log('%cBuild: 2026-
|
|
14359
|
+
console.log('%c🔊 AUDIO PLAYER - MIC/SPEAKER RESET ON NEW CALL ENABLED', 'background: #10b981; color: white; font-size: 14px; font-weight: bold; padding: 4px 8px; border-radius: 4px;');
|
|
14360
|
+
console.log('%cFix: Mic/speaker mute state + UI fully reset on call end and call start', 'background: #d1fae5; color: #065f46; font-size: 12px; padding: 2px 6px; border-radius: 3px;');
|
|
14361
|
+
console.log('%cBuild: 2026-02-26-MIC-SPEAKER-RESET', 'background: #e0e7ff; color: #1e40af; font-size: 11px; padding: 2px 6px; border-radius: 3px;');
|
|
14264
14362
|
console.log('');
|
|
14265
14363
|
_this.config = config;
|
|
14266
14364
|
_this.audioContext = null;
|
|
@@ -14641,7 +14739,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
14641
14739
|
value: (function () {
|
|
14642
14740
|
var _schedulePreparedFrames = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
|
|
14643
14741
|
var _this4 = this;
|
|
14644
|
-
var queuedFrames, targetLookaheadFrames,
|
|
14742
|
+
var queuedFrames, targetLookaheadFrames, scheduledCount, _loop, _ret, _t;
|
|
14645
14743
|
return _regenerator().w(function (_context3) {
|
|
14646
14744
|
while (1) switch (_context3.p = _context3.n) {
|
|
14647
14745
|
case 0:
|
|
@@ -14679,12 +14777,9 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
14679
14777
|
// ✅ NEW: Wait for AudioContext to be in 'running' state before proceeding
|
|
14680
14778
|
// This is critical for mobile devices where AudioContext initialization takes time
|
|
14681
14779
|
// Replaces fixed timeouts with event-driven waiting
|
|
14682
|
-
console.log('🔍 [scheduleWAV] BEFORE waitForAudioContextReady - state:', (_this$audioContext2 = this.audioContext) === null || _this$audioContext2 === void 0 ? void 0 : _this$audioContext2.state, 'currentTime:', (_this$audioContext3 = this.audioContext) === null || _this$audioContext3 === void 0 ? void 0 : _this$audioContext3.currentTime);
|
|
14683
14780
|
_context3.n = 4;
|
|
14684
14781
|
return this.waitForAudioContextReady();
|
|
14685
14782
|
case 4:
|
|
14686
|
-
console.log('🔍 [scheduleWAV] AFTER waitForAudioContextReady - state:', (_this$audioContext4 = this.audioContext) === null || _this$audioContext4 === void 0 ? void 0 : _this$audioContext4.state, 'currentTime:', (_this$audioContext5 = this.audioContext) === null || _this$audioContext5 === void 0 ? void 0 : _this$audioContext5.currentTime);
|
|
14687
|
-
|
|
14688
14783
|
// Schedule frames up to target lookahead (ensures smooth playback)
|
|
14689
14784
|
// Keep scheduling frames as long as we have them and haven't reached the lookahead limit
|
|
14690
14785
|
scheduledCount = 0;
|
|
@@ -15500,20 +15595,13 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
15500
15595
|
value: (function () {
|
|
15501
15596
|
var _waitForAudioContextReady = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
|
|
15502
15597
|
var _this6 = this;
|
|
15503
|
-
var
|
|
15598
|
+
var audioContext;
|
|
15504
15599
|
return _regenerator().w(function (_context5) {
|
|
15505
15600
|
while (1) switch (_context5.n) {
|
|
15506
15601
|
case 0:
|
|
15507
|
-
console.log('🔍 [waitForAudioContextReady] ENTRY - audioContext exists:', !!this.audioContext);
|
|
15508
|
-
|
|
15509
|
-
// ✅ Add null check - ensure AudioContext exists
|
|
15510
15602
|
if (!this.audioContext) {
|
|
15511
|
-
console.log('🔍 [waitForAudioContextReady] Creating AudioContext...');
|
|
15512
15603
|
this.initializeAudioContext();
|
|
15513
|
-
console.log('🔍 [waitForAudioContextReady] After initializeAudioContext - state:', (_this$audioContext6 = this.audioContext) === null || _this$audioContext6 === void 0 ? void 0 : _this$audioContext6.state, 'currentTime:', (_this$audioContext7 = this.audioContext) === null || _this$audioContext7 === void 0 ? void 0 : _this$audioContext7.currentTime);
|
|
15514
15604
|
}
|
|
15515
|
-
|
|
15516
|
-
// ✅ Add null check after initialization
|
|
15517
15605
|
if (this.audioContext) {
|
|
15518
15606
|
_context5.n = 1;
|
|
15519
15607
|
break;
|
|
@@ -15522,46 +15610,33 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
15522
15610
|
return _context5.a(2, Promise.resolve());
|
|
15523
15611
|
case 1:
|
|
15524
15612
|
audioContext = this.audioContext;
|
|
15525
|
-
console.log('🔍 [waitForAudioContextReady] Initial state:', audioContext.state, 'currentTime:', audioContext.currentTime);
|
|
15526
|
-
|
|
15527
|
-
// If already running, proceed immediately
|
|
15528
15613
|
if (!(audioContext.state === 'running')) {
|
|
15529
15614
|
_context5.n = 2;
|
|
15530
15615
|
break;
|
|
15531
15616
|
}
|
|
15532
|
-
console.log('🔍 [waitForAudioContextReady] Already running - returning immediately, currentTime:', audioContext.currentTime);
|
|
15533
15617
|
return _context5.a(2, Promise.resolve());
|
|
15534
15618
|
case 2:
|
|
15535
15619
|
if (!(audioContext.state === 'suspended')) {
|
|
15536
|
-
_context5.n =
|
|
15620
|
+
_context5.n = 4;
|
|
15537
15621
|
break;
|
|
15538
15622
|
}
|
|
15539
|
-
console.log('🔍 [waitForAudioContextReady] State is suspended - calling resume()...');
|
|
15540
15623
|
_context5.n = 3;
|
|
15541
15624
|
return audioContext.resume();
|
|
15542
15625
|
case 3:
|
|
15543
|
-
console.log('🔍 [waitForAudioContextReady] After resume() - state:', audioContext.state, 'currentTime:', audioContext.currentTime);
|
|
15544
|
-
|
|
15545
|
-
// Wait for actual state change (not fixed timeout)
|
|
15546
15626
|
if (!(audioContext.state !== 'running')) {
|
|
15547
15627
|
_context5.n = 4;
|
|
15548
15628
|
break;
|
|
15549
15629
|
}
|
|
15550
|
-
console.log('🔍 [waitForAudioContextReady] Still not running after resume() - waiting for statechange event...');
|
|
15551
15630
|
return _context5.a(2, new Promise(function (resolve) {
|
|
15552
15631
|
var timeout = setTimeout(function () {
|
|
15553
|
-
// ✅ Clean up temporary listener
|
|
15554
15632
|
if (audioContext && _this6._waitForReadyStateHandler) {
|
|
15555
15633
|
audioContext.removeEventListener('statechange', _this6._waitForReadyStateHandler);
|
|
15556
15634
|
_this6._waitForReadyStateHandler = null;
|
|
15557
15635
|
}
|
|
15558
|
-
console.warn('⚠️ AudioPlayer: AudioContext did not become running within timeout - proceeding anyway
|
|
15559
|
-
resolve();
|
|
15560
|
-
}, 2000);
|
|
15561
|
-
|
|
15636
|
+
console.warn('⚠️ AudioPlayer: AudioContext did not become running within timeout - proceeding anyway');
|
|
15637
|
+
resolve();
|
|
15638
|
+
}, 2000);
|
|
15562
15639
|
var checkState = function checkState() {
|
|
15563
|
-
console.log('🔍 [waitForAudioContextReady] statechange event fired - state:', audioContext === null || audioContext === void 0 ? void 0 : audioContext.state, 'currentTime:', audioContext === null || audioContext === void 0 ? void 0 : audioContext.currentTime);
|
|
15564
|
-
// ✅ Add null check - audioContext might be null when handler fires
|
|
15565
15640
|
if (!audioContext) {
|
|
15566
15641
|
clearTimeout(timeout);
|
|
15567
15642
|
_this6._waitForReadyStateHandler = null;
|
|
@@ -15571,45 +15646,33 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
15571
15646
|
}
|
|
15572
15647
|
if (audioContext.state === 'running') {
|
|
15573
15648
|
clearTimeout(timeout);
|
|
15574
|
-
// ✅ Clean up temporary listener
|
|
15575
15649
|
if (_this6._waitForReadyStateHandler) {
|
|
15576
15650
|
audioContext.removeEventListener('statechange', _this6._waitForReadyStateHandler);
|
|
15577
15651
|
_this6._waitForReadyStateHandler = null;
|
|
15578
15652
|
}
|
|
15579
|
-
console.log('✅ [waitForAudioContextReady] AudioContext became running via statechange, currentTime:', audioContext.currentTime);
|
|
15580
15653
|
resolve();
|
|
15581
15654
|
}
|
|
15582
15655
|
};
|
|
15583
|
-
|
|
15584
|
-
// ✅ Store listener reference for cleanup
|
|
15585
15656
|
_this6._waitForReadyStateHandler = checkState;
|
|
15586
15657
|
audioContext.addEventListener('statechange', checkState);
|
|
15587
|
-
|
|
15588
|
-
// Check immediately in case state changed synchronously
|
|
15589
|
-
console.log('🔍 [waitForAudioContextReady] Synchronous check - state:', audioContext === null || audioContext === void 0 ? void 0 : audioContext.state);
|
|
15590
15658
|
if (audioContext && audioContext.state === 'running') {
|
|
15591
15659
|
clearTimeout(timeout);
|
|
15592
|
-
// ✅ Clean up temporary listener
|
|
15593
15660
|
if (_this6._waitForReadyStateHandler) {
|
|
15594
15661
|
audioContext.removeEventListener('statechange', _this6._waitForReadyStateHandler);
|
|
15595
15662
|
_this6._waitForReadyStateHandler = null;
|
|
15596
15663
|
}
|
|
15597
|
-
console.log('✅ [waitForAudioContextReady] State became running synchronously, currentTime:', audioContext.currentTime);
|
|
15598
15664
|
resolve();
|
|
15599
15665
|
}
|
|
15600
15666
|
}));
|
|
15601
15667
|
case 4:
|
|
15602
|
-
console.log('🔍 [waitForAudioContextReady] State is running after resume() - returning, currentTime:', audioContext.currentTime);
|
|
15603
|
-
case 5:
|
|
15604
15668
|
if (!(audioContext.state === 'closed')) {
|
|
15605
|
-
_context5.n =
|
|
15669
|
+
_context5.n = 5;
|
|
15606
15670
|
break;
|
|
15607
15671
|
}
|
|
15608
15672
|
console.warn('⚠️ AudioPlayer: AudioContext was closed, recreating...');
|
|
15609
15673
|
this.initializeAudioContext();
|
|
15610
15674
|
return _context5.a(2, this.waitForAudioContextReady());
|
|
15611
|
-
case
|
|
15612
|
-
console.log('🔍 [waitForAudioContextReady] EXIT - state:', audioContext.state, 'currentTime:', audioContext.currentTime);
|
|
15675
|
+
case 5:
|
|
15613
15676
|
return _context5.a(2, Promise.resolve());
|
|
15614
15677
|
}
|
|
15615
15678
|
}, _callee4, this);
|
|
@@ -16454,14 +16517,15 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
16454
16517
|
_classCallCheck(this, VoiceSDK_v2);
|
|
16455
16518
|
_this = _callSuper(this, VoiceSDK_v2);
|
|
16456
16519
|
_this.version = '2.0.0';
|
|
16520
|
+
|
|
16521
|
+
// Backward compat: signedUrl → websocketUrl
|
|
16522
|
+
if (config.signedUrl && !config.websocketUrl) {
|
|
16523
|
+
console.warn('⚠️ VoiceSDK: signedUrl is deprecated — use websocketUrl for custom backend URLs, or just provide agentId + appId');
|
|
16524
|
+
config.websocketUrl = config.signedUrl;
|
|
16525
|
+
}
|
|
16457
16526
|
_this.config = {
|
|
16458
16527
|
// Connection
|
|
16459
|
-
|
|
16460
|
-
signedUrl: config.signedUrl || config.websocketUrl || 'wss://speech.talktopc.com/ws/conv',
|
|
16461
|
-
// Support both signedUrl and websocketUrl for backward compatibility
|
|
16462
|
-
websocketUrl: config.signedUrl || config.websocketUrl || 'wss://speech.talktopc.com/ws/conv',
|
|
16463
|
-
// Keep for internal use
|
|
16464
|
-
|
|
16528
|
+
websocketUrl: config.websocketUrl || 'wss://speech.talktopc.com/ws/conv',
|
|
16465
16529
|
agentId: config.agentId,
|
|
16466
16530
|
appId: config.appId,
|
|
16467
16531
|
// Input format (what we send to server)
|
|
@@ -16576,12 +16640,6 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
16576
16640
|
|
|
16577
16641
|
// Setup page unload handler for resume state storage
|
|
16578
16642
|
_this._setupPageUnloadHandler();
|
|
16579
|
-
console.log('🎵 VoiceSDK v2 initialized:', {
|
|
16580
|
-
version: _this.version,
|
|
16581
|
-
outputContainer: _this.config.outputContainer,
|
|
16582
|
-
outputEncoding: _this.config.outputEncoding,
|
|
16583
|
-
outputSampleRate: _this.config.outputSampleRate
|
|
16584
|
-
});
|
|
16585
16643
|
return _this;
|
|
16586
16644
|
}
|
|
16587
16645
|
|
|
@@ -16693,8 +16751,6 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
16693
16751
|
});
|
|
16694
16752
|
console.error('❌ VoiceSDK: Some visual tools failed to register:', missing);
|
|
16695
16753
|
console.error(' Registered visual tools:', registeredVisualTools);
|
|
16696
|
-
} else {
|
|
16697
|
-
console.log('✅ VoiceSDK: All visual tools registered:', registeredVisualTools);
|
|
16698
16754
|
}
|
|
16699
16755
|
} catch (error) {
|
|
16700
16756
|
console.error('❌ VoiceSDK: Error registering visual assistant tools:', error);
|
|
@@ -16715,10 +16771,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
16715
16771
|
console.error('❌ VoiceSDK: Missing internal tools:', _missing);
|
|
16716
16772
|
console.error(' Expected 7 internal tools:', requiredInternalTools);
|
|
16717
16773
|
console.error(' Registered:', registeredInternalTools);
|
|
16718
|
-
} else {
|
|
16719
|
-
console.log('✅ VoiceSDK: All 7 internal tools registered:', registeredInternalTools);
|
|
16720
16774
|
}
|
|
16721
|
-
console.log('🔧 VoiceSDK: All registered tools after _registerBuiltInTools():', allRegisteredTools);
|
|
16722
16775
|
}
|
|
16723
16776
|
|
|
16724
16777
|
/**
|
|
@@ -17031,7 +17084,6 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
17031
17084
|
this.emit('error', new Error(outputError));
|
|
17032
17085
|
return;
|
|
17033
17086
|
}
|
|
17034
|
-
console.log('✅ VoiceSDK v2: Format validation passed');
|
|
17035
17087
|
}
|
|
17036
17088
|
|
|
17037
17089
|
/**
|
|
@@ -17160,37 +17212,28 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
17160
17212
|
}, {
|
|
17161
17213
|
key: "buildWebSocketUrl",
|
|
17162
17214
|
value: function buildWebSocketUrl() {
|
|
17163
|
-
var baseUrl = this.config.
|
|
17164
|
-
|
|
17165
|
-
// Parse existing URL to check what params are already there
|
|
17215
|
+
var baseUrl = this.config.websocketUrl;
|
|
17166
17216
|
var url = new URL(baseUrl, 'wss://placeholder.com');
|
|
17167
|
-
var
|
|
17217
|
+
var params = url.searchParams;
|
|
17168
17218
|
|
|
17169
|
-
//
|
|
17170
|
-
|
|
17171
|
-
|
|
17219
|
+
// Strip any legacy signed_token param
|
|
17220
|
+
params.delete('signed_token');
|
|
17221
|
+
if (this.config.agentId && !params.has('agentId')) {
|
|
17222
|
+
params.append('agentId', this.config.agentId);
|
|
17172
17223
|
}
|
|
17173
|
-
|
|
17174
|
-
|
|
17175
|
-
if (this.config.appId && !existingParams.has('appId')) {
|
|
17176
|
-
existingParams.append('appId', this.config.appId);
|
|
17224
|
+
if (this.config.appId && !params.has('appId')) {
|
|
17225
|
+
params.append('appId', this.config.appId);
|
|
17177
17226
|
}
|
|
17178
|
-
|
|
17179
|
-
// Include conversationId for resume attempt (if available)
|
|
17180
17227
|
var storedConversationId = this.getStoredConversationId();
|
|
17181
|
-
if (storedConversationId && !
|
|
17182
|
-
|
|
17228
|
+
if (storedConversationId && !params.has('conversationId')) {
|
|
17229
|
+
params.append('conversationId', storedConversationId);
|
|
17183
17230
|
console.log('🔄 VoiceSDK v2: Attempting resume via query param:', storedConversationId);
|
|
17184
17231
|
}
|
|
17185
|
-
|
|
17186
|
-
// Include current page for resume context tracking
|
|
17187
17232
|
var currentPage = window.location.pathname + window.location.search;
|
|
17188
|
-
if (currentPage && !
|
|
17189
|
-
|
|
17233
|
+
if (currentPage && !params.has('currentPage')) {
|
|
17234
|
+
params.append('currentPage', currentPage);
|
|
17190
17235
|
}
|
|
17191
|
-
|
|
17192
|
-
// Reconstruct URL with all params
|
|
17193
|
-
var queryString = existingParams.toString();
|
|
17236
|
+
var queryString = params.toString();
|
|
17194
17237
|
if (queryString) {
|
|
17195
17238
|
return "".concat(url.origin).concat(url.pathname, "?").concat(queryString);
|
|
17196
17239
|
}
|
|
@@ -17237,7 +17280,6 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
17237
17280
|
// Connection opened
|
|
17238
17281
|
|
|
17239
17282
|
_this6.websocket.onopen = function () {
|
|
17240
|
-
console.log('✅ VoiceSDK v2: WebSocket connected');
|
|
17241
17283
|
_this6.isConnected = true;
|
|
17242
17284
|
_this6.hasEverConnected = true; // Mark that we've successfully connected
|
|
17243
17285
|
|
|
@@ -17249,7 +17291,6 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
17249
17291
|
|
|
17250
17292
|
// Verify all tools are registered (safeguard)
|
|
17251
17293
|
var registeredTools = _this6.clientToolsRegistry.getRegisteredTools();
|
|
17252
|
-
console.log('🔧 VoiceSDK v2: Registered tools on connect:', registeredTools);
|
|
17253
17294
|
|
|
17254
17295
|
// Re-register tools if they're missing (safety check)
|
|
17255
17296
|
// 7 internal tools: read_page, capture_screen, and 5 action tools (matches backend tool names)
|
|
@@ -20404,8 +20445,6 @@ var AgentSDK = /*#__PURE__*/function () {
|
|
|
20404
20445
|
// Get visualAssistant from config or agentSettingsOverride (same pattern as connect())
|
|
20405
20446
|
var visualAssistant = this.config.visualAssistant || ((_this$config$agentSet = this.config.agentSettingsOverride) === null || _this$config$agentSet === void 0 ? void 0 : _this$config$agentSet.visualAssistant);
|
|
20406
20447
|
var tempSDK = new _index_js__WEBPACK_IMPORTED_MODULE_0__.VoiceSDK_v2({
|
|
20407
|
-
signedUrl: 'wss://placeholder',
|
|
20408
|
-
// Placeholder, won't be used
|
|
20409
20448
|
autoReconnect: false,
|
|
20410
20449
|
agentId: this.config.agentId,
|
|
20411
20450
|
appId: this.config.appId,
|
|
@@ -20435,19 +20474,13 @@ var AgentSDK = /*#__PURE__*/function () {
|
|
|
20435
20474
|
}, {
|
|
20436
20475
|
key: "connect",
|
|
20437
20476
|
value: function () {
|
|
20438
|
-
var _connect = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(
|
|
20477
|
+
var _connect = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
20439
20478
|
var _this = this;
|
|
20440
20479
|
var _this$config$agentSet2, visualAssistant, _iterator, _step, _step$value, name, handler, _t;
|
|
20441
20480
|
return _regenerator().w(function (_context) {
|
|
20442
20481
|
while (1) switch (_context.p = _context.n) {
|
|
20443
20482
|
case 0:
|
|
20444
20483
|
_context.p = 0;
|
|
20445
|
-
if (signedUrl) {
|
|
20446
|
-
_context.n = 1;
|
|
20447
|
-
break;
|
|
20448
|
-
}
|
|
20449
|
-
throw new Error('signedUrl is required');
|
|
20450
|
-
case 1:
|
|
20451
20484
|
// Clean up existing connection if any
|
|
20452
20485
|
if (this.voiceSDK) {
|
|
20453
20486
|
console.log('🔌 AgentSDK: Cleaning up existing connection');
|
|
@@ -20455,13 +20488,10 @@ var AgentSDK = /*#__PURE__*/function () {
|
|
|
20455
20488
|
this.voiceSDK = null;
|
|
20456
20489
|
}
|
|
20457
20490
|
|
|
20458
|
-
// Create VoiceSDK v2 instance
|
|
20459
|
-
// Allow configurable output format, with defaults optimized for widget
|
|
20460
20491
|
// Get visualAssistant from config or agentSettingsOverride (same pattern as VoiceSDK)
|
|
20461
20492
|
visualAssistant = this.config.visualAssistant || ((_this$config$agentSet2 = this.config.agentSettingsOverride) === null || _this$config$agentSet2 === void 0 ? void 0 : _this$config$agentSet2.visualAssistant);
|
|
20462
20493
|
this.voiceSDK = new _index_js__WEBPACK_IMPORTED_MODULE_0__.VoiceSDK_v2({
|
|
20463
|
-
|
|
20464
|
-
// Use signedUrl parameter (VoiceSDK_v2 supports both signedUrl and websocketUrl)
|
|
20494
|
+
websocketUrl: this.config.websocketUrl,
|
|
20465
20495
|
autoReconnect: false,
|
|
20466
20496
|
agentId: this.config.agentId,
|
|
20467
20497
|
appId: this.config.appId,
|
|
@@ -20620,22 +20650,22 @@ var AgentSDK = /*#__PURE__*/function () {
|
|
|
20620
20650
|
}
|
|
20621
20651
|
|
|
20622
20652
|
// Connect using VoiceSDK
|
|
20623
|
-
_context.n =
|
|
20653
|
+
_context.n = 1;
|
|
20624
20654
|
return this.voiceSDK.connect();
|
|
20625
|
-
case
|
|
20626
|
-
_context.n =
|
|
20655
|
+
case 1:
|
|
20656
|
+
_context.n = 3;
|
|
20627
20657
|
break;
|
|
20628
|
-
case
|
|
20629
|
-
_context.p =
|
|
20658
|
+
case 2:
|
|
20659
|
+
_context.p = 2;
|
|
20630
20660
|
_t = _context.v;
|
|
20631
20661
|
this.onError(_t);
|
|
20632
20662
|
throw _t;
|
|
20633
|
-
case
|
|
20663
|
+
case 3:
|
|
20634
20664
|
return _context.a(2);
|
|
20635
20665
|
}
|
|
20636
|
-
}, _callee, this, [[0,
|
|
20666
|
+
}, _callee, this, [[0, 2]]);
|
|
20637
20667
|
}));
|
|
20638
|
-
function connect(
|
|
20668
|
+
function connect() {
|
|
20639
20669
|
return _connect.apply(this, arguments);
|
|
20640
20670
|
}
|
|
20641
20671
|
return connect;
|
|
@@ -21025,6 +21055,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
21025
21055
|
_classCallCheck(this, TTPChatWidget);
|
|
21026
21056
|
// Merge user config with defaults (backward compatible with simple config)
|
|
21027
21057
|
this.config = this.mergeWithDefaults(config);
|
|
21058
|
+
|
|
21059
|
+
// Backward compat: signedUrl → websocketUrl with deprecation warning
|
|
21060
|
+
if (config.signedUrl && !config.websocketUrl) {
|
|
21061
|
+
console.warn('⚠️ TTPChatWidget: signedUrl is deprecated — use websocketUrl for custom backend URLs, or just provide agentId + appId');
|
|
21062
|
+
}
|
|
21063
|
+
// Silently ignore allowOverride (now server-side only)
|
|
21064
|
+
|
|
21028
21065
|
this.sdk = new _core_TextChatSDK_js__WEBPACK_IMPORTED_MODULE_0__["default"](this.config);
|
|
21029
21066
|
this.isOpen = false;
|
|
21030
21067
|
this.isActive = false;
|
|
@@ -21059,17 +21096,12 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
21059
21096
|
// Pass through send button color for voice send button
|
|
21060
21097
|
sendButtonColor: ((_this$config$text2 = this.config.text) === null || _this$config$text2 === void 0 ? void 0 : _this$config$text2.sendButtonColor) || this.config.sendButtonColor || '#7C3AED',
|
|
21061
21098
|
language: ((_this$config$voice = this.config.voice) === null || _this$config$voice === void 0 ? void 0 : _this$config$voice.language) || this.config.language || 'en',
|
|
21062
|
-
|
|
21063
|
-
// Pass through signedUrl if provided
|
|
21099
|
+
websocketUrl: this.config.websocketUrl,
|
|
21064
21100
|
agentSettingsOverride: this.config.agentSettingsOverride,
|
|
21065
|
-
// Pass through agentSettingsOverride if provided
|
|
21066
21101
|
visualAssistant: this.config.visualAssistant,
|
|
21067
|
-
// Pass through visualAssistant config
|
|
21068
21102
|
translations: this.translations,
|
|
21069
21103
|
shadowRoot: this.shadowRoot,
|
|
21070
|
-
// Pass shadow root reference
|
|
21071
21104
|
textSDK: this.sdk,
|
|
21072
|
-
// Pass TextChatSDK reference for sending text messages during voice calls
|
|
21073
21105
|
// Output format defaults for widget: 44100 Hz, 16-bit, PCM, raw
|
|
21074
21106
|
outputContainer: ((_this$config$voice2 = this.config.voice) === null || _this$config$voice2 === void 0 ? void 0 : _this$config$voice2.outputContainer) || 'raw',
|
|
21075
21107
|
outputEncoding: ((_this$config$voice3 = this.config.voice) === null || _this$config$voice3 === void 0 ? void 0 : _this$config$voice3.outputEncoding) || 'pcm',
|
|
@@ -21268,12 +21300,10 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
21268
21300
|
// Required (agentId is required, appId is optional)
|
|
21269
21301
|
agentId: userConfig.agentId,
|
|
21270
21302
|
appId: userConfig.appId,
|
|
21271
|
-
|
|
21272
|
-
//
|
|
21303
|
+
websocketUrl: userConfig.websocketUrl || userConfig.signedUrl,
|
|
21304
|
+
// signedUrl accepted as backward-compat alias
|
|
21273
21305
|
agentSettingsOverride: userConfig.agentSettingsOverride,
|
|
21274
|
-
// Optional - agent settings override (requires signed URL with allowOverride=true)
|
|
21275
21306
|
demo: userConfig.demo !== false,
|
|
21276
|
-
// Optional - defaults to true
|
|
21277
21307
|
direction: userConfig.direction || 'ltr',
|
|
21278
21308
|
// Optional - text direction: 'ltr' or 'rtl'
|
|
21279
21309
|
language: userConfig.language || 'en',
|
|
@@ -22772,51 +22802,34 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
22772
22802
|
}
|
|
22773
22803
|
}
|
|
22774
22804
|
}, {
|
|
22775
|
-
key: "
|
|
22776
|
-
value: function () {
|
|
22777
|
-
|
|
22778
|
-
|
|
22779
|
-
|
|
22780
|
-
|
|
22781
|
-
|
|
22782
|
-
|
|
22783
|
-
_context4.n = 1;
|
|
22784
|
-
break;
|
|
22785
|
-
}
|
|
22786
|
-
return _context4.a(2, this.config.signedUrl);
|
|
22787
|
-
case 1:
|
|
22788
|
-
if (this.config.agentId) {
|
|
22789
|
-
_context4.n = 2;
|
|
22790
|
-
break;
|
|
22791
|
-
}
|
|
22792
|
-
throw new Error('agentId is required when signedUrl is not provided');
|
|
22793
|
-
case 2:
|
|
22794
|
-
// Build WebSocket URL directly
|
|
22795
|
-
// Default uses backend.talktopc.com for text chat (path may need adjustment)
|
|
22796
|
-
baseUrl = this.config.websocketUrl || 'wss://backend.talktopc.com/ws/conv';
|
|
22797
|
-
params = new URLSearchParams();
|
|
22798
|
-
params.append('agentId', this.config.agentId);
|
|
22799
|
-
if (this.config.appId) {
|
|
22800
|
-
params.append('appId', this.config.appId);
|
|
22801
|
-
}
|
|
22805
|
+
key: "buildWebSocketUrl",
|
|
22806
|
+
value: function buildWebSocketUrl() {
|
|
22807
|
+
if (!this.config.agentId) {
|
|
22808
|
+
throw new Error('agentId is required');
|
|
22809
|
+
}
|
|
22810
|
+
var baseUrl = this.config.websocketUrl || 'wss://backend.talktopc.com/ws/conv';
|
|
22811
|
+
var url = new URL(baseUrl, 'wss://placeholder.com');
|
|
22812
|
+
var params = url.searchParams;
|
|
22802
22813
|
|
|
22803
|
-
|
|
22804
|
-
|
|
22805
|
-
|
|
22806
|
-
|
|
22807
|
-
|
|
22808
|
-
|
|
22809
|
-
|
|
22810
|
-
}
|
|
22811
|
-
return _context4.a(2, wsUrl);
|
|
22812
|
-
}
|
|
22813
|
-
}, _callee4, this);
|
|
22814
|
-
}));
|
|
22815
|
-
function getSignedUrl() {
|
|
22816
|
-
return _getSignedUrl.apply(this, arguments);
|
|
22814
|
+
// Strip any legacy signed_token param
|
|
22815
|
+
params.delete('signed_token');
|
|
22816
|
+
if (!params.has('agentId')) {
|
|
22817
|
+
params.append('agentId', this.config.agentId);
|
|
22818
|
+
}
|
|
22819
|
+
if (this.config.appId && !params.has('appId')) {
|
|
22820
|
+
params.append('appId', this.config.appId);
|
|
22817
22821
|
}
|
|
22818
|
-
|
|
22819
|
-
|
|
22822
|
+
if (this.config.demo !== false) {
|
|
22823
|
+
params.append('demo', 'true');
|
|
22824
|
+
}
|
|
22825
|
+
var wsUrl = "".concat(url.origin).concat(url.pathname, "?").concat(params.toString());
|
|
22826
|
+
if (true) {
|
|
22827
|
+
console.log('[TTPAgentSDK] WebSocket URL:', wsUrl);
|
|
22828
|
+
}
|
|
22829
|
+
return wsUrl;
|
|
22830
|
+
}
|
|
22831
|
+
|
|
22832
|
+
// Delegated to TextInterface
|
|
22820
22833
|
}, {
|
|
22821
22834
|
key: "addMessage",
|
|
22822
22835
|
value: function addMessage(type, text) {
|
|
@@ -23057,12 +23070,9 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
23057
23070
|
translations: this.translations,
|
|
23058
23071
|
shadowRoot: this.shadowRoot,
|
|
23059
23072
|
// Pass shadow root reference
|
|
23060
|
-
|
|
23061
|
-
// Pass through signedUrl if provided
|
|
23073
|
+
websocketUrl: this.config.websocketUrl,
|
|
23062
23074
|
agentSettingsOverride: this.config.agentSettingsOverride,
|
|
23063
|
-
// Pass through agentSettingsOverride if provided
|
|
23064
23075
|
visualAssistant: this.config.visualAssistant,
|
|
23065
|
-
// Pass through visualAssistant config
|
|
23066
23076
|
// Output format defaults for widget: 44100 Hz, 16-bit, PCM, raw
|
|
23067
23077
|
outputContainer: ((_this$config$voice8 = this.config.voice) === null || _this$config$voice8 === void 0 ? void 0 : _this$config$voice8.outputContainer) || 'raw',
|
|
23068
23078
|
outputEncoding: ((_this$config$voice9 = this.config.voice) === null || _this$config$voice9 === void 0 ? void 0 : _this$config$voice9.outputEncoding) || 'pcm',
|
|
@@ -23143,19 +23153,19 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
23143
23153
|
}, {
|
|
23144
23154
|
key: "startVoiceCall",
|
|
23145
23155
|
value: function () {
|
|
23146
|
-
var _startVoiceCall = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
23147
|
-
return _regenerator().w(function (
|
|
23148
|
-
while (1) switch (
|
|
23156
|
+
var _startVoiceCall = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
|
|
23157
|
+
return _regenerator().w(function (_context4) {
|
|
23158
|
+
while (1) switch (_context4.n) {
|
|
23149
23159
|
case 0:
|
|
23150
|
-
|
|
23160
|
+
_context4.n = 1;
|
|
23151
23161
|
return this.voiceInterface.startVoiceCall();
|
|
23152
23162
|
case 1:
|
|
23153
23163
|
// Flush pending tools after SDK connects
|
|
23154
23164
|
this._flushPendingClientTools();
|
|
23155
23165
|
case 2:
|
|
23156
|
-
return
|
|
23166
|
+
return _context4.a(2);
|
|
23157
23167
|
}
|
|
23158
|
-
},
|
|
23168
|
+
}, _callee4, this);
|
|
23159
23169
|
}));
|
|
23160
23170
|
function startVoiceCall() {
|
|
23161
23171
|
return _startVoiceCall.apply(this, arguments);
|
|
@@ -23208,26 +23218,26 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
23208
23218
|
}, {
|
|
23209
23219
|
key: "injectData",
|
|
23210
23220
|
value: (function () {
|
|
23211
|
-
var _injectData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
23221
|
+
var _injectData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(data) {
|
|
23212
23222
|
var _this$voiceInterface6;
|
|
23213
23223
|
var options,
|
|
23214
23224
|
voiceSDK,
|
|
23215
23225
|
ack,
|
|
23216
|
-
|
|
23226
|
+
_args5 = arguments,
|
|
23217
23227
|
_t2;
|
|
23218
|
-
return _regenerator().w(function (
|
|
23219
|
-
while (1) switch (
|
|
23228
|
+
return _regenerator().w(function (_context5) {
|
|
23229
|
+
while (1) switch (_context5.p = _context5.n) {
|
|
23220
23230
|
case 0:
|
|
23221
|
-
options =
|
|
23231
|
+
options = _args5.length > 1 && _args5[1] !== undefined ? _args5[1] : {};
|
|
23222
23232
|
if (!(!data || !data.trim())) {
|
|
23223
|
-
|
|
23233
|
+
_context5.n = 1;
|
|
23224
23234
|
break;
|
|
23225
23235
|
}
|
|
23226
23236
|
console.warn('TTPChatWidget: Cannot inject empty data');
|
|
23227
23237
|
throw new Error('Cannot inject empty data');
|
|
23228
23238
|
case 1:
|
|
23229
23239
|
if (!(!this.voiceInterface || !this.voiceInterface.isActive)) {
|
|
23230
|
-
|
|
23240
|
+
_context5.n = 2;
|
|
23231
23241
|
break;
|
|
23232
23242
|
}
|
|
23233
23243
|
console.warn('TTPChatWidget: Cannot inject data - voice call is not active');
|
|
@@ -23236,28 +23246,28 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
23236
23246
|
// Check if SDK is available
|
|
23237
23247
|
voiceSDK = (_this$voiceInterface6 = this.voiceInterface) === null || _this$voiceInterface6 === void 0 ? void 0 : _this$voiceInterface6.getVoiceSDK();
|
|
23238
23248
|
if (voiceSDK) {
|
|
23239
|
-
|
|
23249
|
+
_context5.n = 3;
|
|
23240
23250
|
break;
|
|
23241
23251
|
}
|
|
23242
23252
|
console.warn('TTPChatWidget: VoiceSDK not available');
|
|
23243
23253
|
throw new Error('VoiceSDK not available');
|
|
23244
23254
|
case 3:
|
|
23245
|
-
|
|
23246
|
-
|
|
23255
|
+
_context5.p = 3;
|
|
23256
|
+
_context5.n = 4;
|
|
23247
23257
|
return voiceSDK.injectData(data, _objectSpread(_objectSpread({}, options), {}, {
|
|
23248
23258
|
source: options.source || 'widget_programmatic'
|
|
23249
23259
|
}));
|
|
23250
23260
|
case 4:
|
|
23251
|
-
ack =
|
|
23252
|
-
return
|
|
23261
|
+
ack = _context5.v;
|
|
23262
|
+
return _context5.a(2, ack);
|
|
23253
23263
|
case 5:
|
|
23254
|
-
|
|
23255
|
-
_t2 =
|
|
23264
|
+
_context5.p = 5;
|
|
23265
|
+
_t2 = _context5.v;
|
|
23256
23266
|
throw _t2;
|
|
23257
23267
|
case 6:
|
|
23258
|
-
return
|
|
23268
|
+
return _context5.a(2);
|
|
23259
23269
|
}
|
|
23260
|
-
},
|
|
23270
|
+
}, _callee5, this, [[3, 5]]);
|
|
23261
23271
|
}));
|
|
23262
23272
|
function injectData(_x) {
|
|
23263
23273
|
return _injectData.apply(this, arguments);
|
|
@@ -23986,12 +23996,9 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
23986
23996
|
this.sdk = new _index_js__WEBPACK_IMPORTED_MODULE_0__.AgentSDK({
|
|
23987
23997
|
agentId: config.agentId,
|
|
23988
23998
|
appId: config.appId,
|
|
23989
|
-
|
|
23990
|
-
// Pass through signedUrl if provided
|
|
23999
|
+
websocketUrl: config.websocketUrl,
|
|
23991
24000
|
agentSettingsOverride: config.agentSettingsOverride,
|
|
23992
|
-
// Pass through agentSettingsOverride if provided
|
|
23993
24001
|
visualAssistant: visualAssistant,
|
|
23994
|
-
// Pass through visualAssistant config (with fallback to agentSettingsOverride)
|
|
23995
24002
|
variables: config.variables || {},
|
|
23996
24003
|
language: config.language || 'en',
|
|
23997
24004
|
// Output format configuration (defaults to 44100 Hz, 16-bit, PCM, raw)
|
|
@@ -24553,7 +24560,7 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
24553
24560
|
value: (function () {
|
|
24554
24561
|
var _proceedWithVoiceCall = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
|
|
24555
24562
|
var _this3 = this;
|
|
24556
|
-
var isResumeCall, panel, header, toggleText, _voiceInterface, originalSection, compactSection, idleState, _panel, fallbackPanel, sampleRate, mediaStream, floatingButton, fallbackButton, existingBar, _floatingButton, _fallbackButton, _idleState, _panel2, _fallbackPanel, deviceInfo, _idleState2, activeState, voiceInterface,
|
|
24563
|
+
var isResumeCall, panel, header, toggleText, _voiceInterface, originalSection, compactSection, idleState, _panel, fallbackPanel, sampleRate, mediaStream, floatingButton, fallbackButton, existingBar, _floatingButton, _fallbackButton, _idleState, _panel2, _fallbackPanel, deviceInfo, _idleState2, activeState, voiceInterface, connected, serverRejected, originalOnError, originalOnDisconnected, attempts, _this$sdk$voiceSDK, error, _existingBar, _existingBar2, _idleState3, _panel3, _fallbackPanel2, _floatingButton2, _fallbackButton2, updateTimer, _existingBar3, _existingBar4, _idleState4, _panel4, _fallbackPanel3, _floatingButton3, _fallbackButton3, _updateTimer, _deviceInfo, _t2, _t3, _t4, _t5, _t6, _t7;
|
|
24557
24564
|
return _regenerator().w(function (_context5) {
|
|
24558
24565
|
while (1) switch (_context5.p = _context5.n) {
|
|
24559
24566
|
case 0:
|
|
@@ -24730,20 +24737,13 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
24730
24737
|
voiceInterface.scrollTop = 0;
|
|
24731
24738
|
}
|
|
24732
24739
|
|
|
24733
|
-
//
|
|
24734
|
-
|
|
24735
|
-
// Get signed URL from config or construct it
|
|
24736
|
-
signedUrl = this.config.signedUrl || (this.config.agentId && this.config.appId ? "wss://speech.talktopc.com/ws/conv?agentId=".concat(this.config.agentId, "&appId=").concat(this.config.appId) : null);
|
|
24737
|
-
if (signedUrl) {
|
|
24740
|
+
// Connect using agentId + appId (URL built internally by SDK)
|
|
24741
|
+
if (this.config.agentId) {
|
|
24738
24742
|
_context5.n = 7;
|
|
24739
24743
|
break;
|
|
24740
24744
|
}
|
|
24741
|
-
throw new Error('
|
|
24745
|
+
throw new Error('agentId is required for voice calls');
|
|
24742
24746
|
case 7:
|
|
24743
|
-
console.log('🔗 Got signed URL:', signedUrl);
|
|
24744
|
-
|
|
24745
|
-
// If SDK is already connected, disconnect first to ensure clean state
|
|
24746
|
-
// This is important for retrying after permission errors
|
|
24747
24747
|
if (!(this.sdk && this.sdk.isConnected)) {
|
|
24748
24748
|
_context5.n = 11;
|
|
24749
24749
|
break;
|
|
@@ -24751,7 +24751,6 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
24751
24751
|
console.log('🔄 SDK already connected, disconnecting for clean retry...');
|
|
24752
24752
|
_context5.p = 8;
|
|
24753
24753
|
this.sdk.disconnect();
|
|
24754
|
-
// Wait a bit for disconnect to complete
|
|
24755
24754
|
_context5.n = 9;
|
|
24756
24755
|
return new Promise(function (resolve) {
|
|
24757
24756
|
return setTimeout(resolve, 100);
|
|
@@ -24765,7 +24764,7 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
24765
24764
|
console.warn('Warning: Error disconnecting existing connection:', _t3);
|
|
24766
24765
|
case 11:
|
|
24767
24766
|
_context5.n = 12;
|
|
24768
|
-
return this.sdk.connect(
|
|
24767
|
+
return this.sdk.connect();
|
|
24769
24768
|
case 12:
|
|
24770
24769
|
connected = _context5.v;
|
|
24771
24770
|
console.log('✅ Connected to WebSocket, connected:', connected);
|
|
@@ -24893,6 +24892,7 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
24893
24892
|
case 26:
|
|
24894
24893
|
console.log('🎤 Started listening - permission granted');
|
|
24895
24894
|
this.isActive = true;
|
|
24895
|
+
this.resetMuteState();
|
|
24896
24896
|
|
|
24897
24897
|
// Update mobile bar if it already exists (created early), otherwise create it
|
|
24898
24898
|
if (this.isMobile) {
|
|
@@ -25026,6 +25026,7 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
25026
25026
|
case 34:
|
|
25027
25027
|
console.log('🎤 Started listening - permission granted');
|
|
25028
25028
|
this.isActive = true;
|
|
25029
|
+
this.resetMuteState();
|
|
25029
25030
|
|
|
25030
25031
|
// Update mobile bar if it already exists (created early), otherwise create it
|
|
25031
25032
|
if (this.isMobile) {
|
|
@@ -25518,10 +25519,56 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
25518
25519
|
}, {
|
|
25519
25520
|
key: "endVoiceCall",
|
|
25520
25521
|
value: function endVoiceCall() {
|
|
25521
|
-
var
|
|
25522
|
-
|
|
25522
|
+
var _this4 = this,
|
|
25523
|
+
_this$sdk2;
|
|
25523
25524
|
console.log('🔴 Ending voice call...');
|
|
25524
25525
|
|
|
25526
|
+
// Reset mic/speaker state + UI immediately so next call never flashes muted UI
|
|
25527
|
+
this.isMicMuted = false;
|
|
25528
|
+
this.isSpeakerMuted = false;
|
|
25529
|
+
|
|
25530
|
+
// Reset mute button DOM state (desktop original + compact)
|
|
25531
|
+
['desktopMuteBtn', 'desktopMuteBtnCompact'].forEach(function (id) {
|
|
25532
|
+
var btn = _this4.shadowRoot.getElementById(id);
|
|
25533
|
+
if (!btn) return;
|
|
25534
|
+
btn.classList.remove('muted');
|
|
25535
|
+
var micIcon = btn.querySelector('.desktop-mic-icon');
|
|
25536
|
+
var micOffIcon = btn.querySelector('.desktop-mic-off-icon');
|
|
25537
|
+
if (micIcon) micIcon.style.display = 'block';
|
|
25538
|
+
if (micOffIcon) micOffIcon.style.display = 'none';
|
|
25539
|
+
});
|
|
25540
|
+
|
|
25541
|
+
// Reset speaker button DOM state (desktop original + compact)
|
|
25542
|
+
['desktopSpeakerBtn', 'desktopSpeakerBtnCompact'].forEach(function (id) {
|
|
25543
|
+
var btn = _this4.shadowRoot.getElementById(id);
|
|
25544
|
+
if (!btn) return;
|
|
25545
|
+
btn.classList.remove('muted');
|
|
25546
|
+
var speakerIcon = btn.querySelector('.desktop-speaker-icon');
|
|
25547
|
+
var speakerOffIcon = btn.querySelector('.desktop-speaker-off-icon');
|
|
25548
|
+
if (speakerIcon) speakerIcon.style.display = 'block';
|
|
25549
|
+
if (speakerOffIcon) speakerOffIcon.style.display = 'none';
|
|
25550
|
+
});
|
|
25551
|
+
|
|
25552
|
+
// Reset mobile mute button
|
|
25553
|
+
var mobileMuteBtn = document.getElementById('mobileMuteBtn');
|
|
25554
|
+
if (mobileMuteBtn) {
|
|
25555
|
+
mobileMuteBtn.classList.remove('muted');
|
|
25556
|
+
var mobileMicIcon = mobileMuteBtn.querySelector('.mobile-mic-icon');
|
|
25557
|
+
var mobileMicOffIcon = mobileMuteBtn.querySelector('.mobile-mic-off-icon');
|
|
25558
|
+
if (mobileMicIcon) mobileMicIcon.style.cssText = 'display: block !important; visibility: visible !important; opacity: 1 !important; width: 15px !important; height: 15px !important; margin: 0 !important; padding: 0 !important;';
|
|
25559
|
+
if (mobileMicOffIcon) mobileMicOffIcon.style.cssText = 'display: none !important; visibility: hidden !important; opacity: 0 !important;';
|
|
25560
|
+
}
|
|
25561
|
+
|
|
25562
|
+
// Reset mobile speaker button
|
|
25563
|
+
var mobileSpeakerBtn = document.getElementById('mobileSpeakerBtn');
|
|
25564
|
+
if (mobileSpeakerBtn) {
|
|
25565
|
+
mobileSpeakerBtn.classList.remove('muted');
|
|
25566
|
+
var mobileSpeakerIcon = mobileSpeakerBtn.querySelector('.mobile-speaker-icon');
|
|
25567
|
+
var mobileSpeakerOffIcon = mobileSpeakerBtn.querySelector('.mobile-speaker-off-icon');
|
|
25568
|
+
if (mobileSpeakerIcon) mobileSpeakerIcon.style.cssText = 'display: block !important; visibility: visible !important; opacity: 1 !important; width: 15px !important; height: 15px !important; margin: 0 !important; padding: 0 !important;';
|
|
25569
|
+
if (mobileSpeakerOffIcon) mobileSpeakerOffIcon.style.cssText = 'display: none !important; visibility: hidden !important; opacity: 0 !important;';
|
|
25570
|
+
}
|
|
25571
|
+
|
|
25525
25572
|
// Reset resume info so next call is treated as a new call (not resume)
|
|
25526
25573
|
// Resume info is only valid for the first call after page load/refresh
|
|
25527
25574
|
this._resumeInfo = null;
|
|
@@ -26093,6 +26140,73 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
26093
26140
|
return this.mobile.stopWaveformAnimation();
|
|
26094
26141
|
}
|
|
26095
26142
|
|
|
26143
|
+
/**
|
|
26144
|
+
* Reset mic and speaker mute state + UI for a fresh call
|
|
26145
|
+
*/
|
|
26146
|
+
}, {
|
|
26147
|
+
key: "resetMuteState",
|
|
26148
|
+
value: function resetMuteState() {
|
|
26149
|
+
var _this$sdk3,
|
|
26150
|
+
_this$sdk4,
|
|
26151
|
+
_this5 = this;
|
|
26152
|
+
this.isMicMuted = false;
|
|
26153
|
+
this.isSpeakerMuted = false;
|
|
26154
|
+
console.log('%c🎤 MIC/SPEAKER RESET - New call starting unmuted', 'background: #10b981; color: white; font-size: 14px; font-weight: bold; padding: 4px 8px; border-radius: 4px;');
|
|
26155
|
+
|
|
26156
|
+
// Ensure audio track is enabled
|
|
26157
|
+
if ((_this$sdk3 = this.sdk) !== null && _this$sdk3 !== void 0 && (_this$sdk3 = _this$sdk3.voiceSDK) !== null && _this$sdk3 !== void 0 && (_this$sdk3 = _this$sdk3.audioRecorder) !== null && _this$sdk3 !== void 0 && _this$sdk3.mediaStream) {
|
|
26158
|
+
var track = this.sdk.voiceSDK.audioRecorder.mediaStream.getAudioTracks()[0];
|
|
26159
|
+
if (track) track.enabled = true;
|
|
26160
|
+
}
|
|
26161
|
+
|
|
26162
|
+
// Ensure speaker is unmuted
|
|
26163
|
+
if ((_this$sdk4 = this.sdk) !== null && _this$sdk4 !== void 0 && (_this$sdk4 = _this$sdk4.voiceSDK) !== null && _this$sdk4 !== void 0 && _this$sdk4.audioPlayer) {
|
|
26164
|
+
this.sdk.voiceSDK.audioPlayer.setMuted(false);
|
|
26165
|
+
}
|
|
26166
|
+
|
|
26167
|
+
// Reset desktop mute buttons (original + compact)
|
|
26168
|
+
['desktopMuteBtn', 'desktopMuteBtnCompact'].forEach(function (id) {
|
|
26169
|
+
var btn = _this5.shadowRoot.getElementById(id);
|
|
26170
|
+
if (!btn) return;
|
|
26171
|
+
btn.classList.remove('muted');
|
|
26172
|
+
var micIcon = btn.querySelector('.desktop-mic-icon');
|
|
26173
|
+
var micOffIcon = btn.querySelector('.desktop-mic-off-icon');
|
|
26174
|
+
if (micIcon) micIcon.style.display = 'block';
|
|
26175
|
+
if (micOffIcon) micOffIcon.style.display = 'none';
|
|
26176
|
+
});
|
|
26177
|
+
|
|
26178
|
+
// Reset desktop speaker buttons (original + compact)
|
|
26179
|
+
['desktopSpeakerBtn', 'desktopSpeakerBtnCompact'].forEach(function (id) {
|
|
26180
|
+
var btn = _this5.shadowRoot.getElementById(id);
|
|
26181
|
+
if (!btn) return;
|
|
26182
|
+
btn.classList.remove('muted');
|
|
26183
|
+
var speakerIcon = btn.querySelector('.desktop-speaker-icon');
|
|
26184
|
+
var speakerOffIcon = btn.querySelector('.desktop-speaker-off-icon');
|
|
26185
|
+
if (speakerIcon) speakerIcon.style.display = 'block';
|
|
26186
|
+
if (speakerOffIcon) speakerOffIcon.style.display = 'none';
|
|
26187
|
+
});
|
|
26188
|
+
|
|
26189
|
+
// Reset mobile mute button
|
|
26190
|
+
var mobileMuteBtn = document.getElementById('mobileMuteBtn');
|
|
26191
|
+
if (mobileMuteBtn) {
|
|
26192
|
+
mobileMuteBtn.classList.remove('muted');
|
|
26193
|
+
var mobileMicIcon = mobileMuteBtn.querySelector('.mobile-mic-icon');
|
|
26194
|
+
var mobileMicOffIcon = mobileMuteBtn.querySelector('.mobile-mic-off-icon');
|
|
26195
|
+
if (mobileMicIcon) mobileMicIcon.style.cssText = 'display: block !important; visibility: visible !important; opacity: 1 !important; width: 15px !important; height: 15px !important; margin: 0 !important; padding: 0 !important;';
|
|
26196
|
+
if (mobileMicOffIcon) mobileMicOffIcon.style.cssText = 'display: none !important; visibility: hidden !important; opacity: 0 !important;';
|
|
26197
|
+
}
|
|
26198
|
+
|
|
26199
|
+
// Reset mobile speaker button
|
|
26200
|
+
var mobileSpeakerBtn = document.getElementById('mobileSpeakerBtn');
|
|
26201
|
+
if (mobileSpeakerBtn) {
|
|
26202
|
+
mobileSpeakerBtn.classList.remove('muted');
|
|
26203
|
+
var mobileSpeakerIcon = mobileSpeakerBtn.querySelector('.mobile-speaker-icon');
|
|
26204
|
+
var mobileSpeakerOffIcon = mobileSpeakerBtn.querySelector('.mobile-speaker-off-icon');
|
|
26205
|
+
if (mobileSpeakerIcon) mobileSpeakerIcon.style.cssText = 'display: block !important; visibility: visible !important; opacity: 1 !important; width: 15px !important; height: 15px !important; margin: 0 !important; padding: 0 !important;';
|
|
26206
|
+
if (mobileSpeakerOffIcon) mobileSpeakerOffIcon.style.cssText = 'display: none !important; visibility: hidden !important; opacity: 0 !important;';
|
|
26207
|
+
}
|
|
26208
|
+
}
|
|
26209
|
+
|
|
26096
26210
|
/**
|
|
26097
26211
|
* Cleanup resources
|
|
26098
26212
|
*/
|
|
@@ -27230,7 +27344,7 @@ var Styles = /*#__PURE__*/function () {
|
|
|
27230
27344
|
var endCallBtnColor = this.config.endCallButtonColor || '#ef4444';
|
|
27231
27345
|
var voiceSendButtonColor = this.config.sendButtonColor || ((_this$config$text = this.config.text) === null || _this$config$text === void 0 ? void 0 : _this$config$text.sendButtonColor) || this.config.voiceSendButtonColor || '#7C3AED';
|
|
27232
27346
|
var important = ' !important';
|
|
27233
|
-
return "\n /* Voice Interface Styles - Ultra-compact for Wix iframes */\n .voice-interface { \n display: none".concat(important, "; \n flex: 1; \n flex-direction: column;\n align-items: stretch; \n justify-content: flex-start; \n padding: 0; \n background: linear-gradient(180deg, #f8fafc 0%, #e0e7ff 100%);\n overflow: hidden;\n min-height: 0;\n height: 100%;\n width: 100%;\n box-sizing: border-box;\n }\n .voice-interface.active { display: flex").concat(important, "; }\n \n /* Voice States - Better scaling gaps */\n #voiceIdleState {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n height: 100%;\n min-height: 0;\n justify-content: center;\n overflow: hidden;\n flex: 1;\n box-sizing: border-box;\n gap: clamp(6px, 1.5vh, 12px);\n }\n \n #voiceActiveState {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n height: 100%;\n min-height: 0;\n justify-content: flex-start;\n overflow: hidden;\n flex: 1;\n box-sizing: border-box;\n gap: 0;\n padding: 0;\n }\n \n #voiceActiveState[style*=\"display: none\"] {\n display: none !important;\n }\n \n /* Voice Avatar - Scales better from small to large */\n .voice-avatar,\n .voice-avatar-active {\n width: clamp(80px, 18vh, 160px);\n height: clamp(80px, 18vh, 160px);\n aspect-ratio: 1;\n border-radius: 50%;\n background: linear-gradient(135deg, ").concat(avatarBg, " 0%, ").concat(avatarActiveBg, " 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: clamp(40px, 9vh, 80px);\n margin: 0;\n box-shadow: 0 8px 30px rgba(102, 126, 234, 0.3);\n transition: all 0.3s ease;\n flex-shrink: 0;\n position: relative;\n }\n \n .voice-avatar-active {\n animation: avatarPulse 2s ease-in-out infinite;\n }\n \n @keyframes avatarPulse {\n 0%, 100% { \n transform: scale(1);\n }\n 50% { \n transform: scale(1.05);\n }\n }\n \n .voice-avatar-active.speaking {\n animation: avatarSpeak 0.5s ease-in-out infinite;\n }\n \n @keyframes avatarSpeak {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.08); }\n }\n \n /* Voice Rings Animation */\n .voice-rings {\n position: absolute;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n }\n \n .voice-ring {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n border: 2px solid rgba(102, 126, 234, 0.3);\n border-radius: 50%;\n opacity: 0;\n animation: ringExpand 2s ease-out infinite;\n }\n \n .voice-ring:nth-child(2) { animation-delay: 0.5s; }\n .voice-ring:nth-child(3) { animation-delay: 1s; }\n \n @keyframes ringExpand {\n 0% {\n width: 100%;\n height: 100%;\n opacity: 0.6;\n }\n 100% {\n width: 160%;\n height: 160%;\n opacity: 0;\n }\n }\n \n /* Voice Status - Scales with container */\n .voice-status {\n text-align: center;\n margin: 0;\n flex-shrink: 0;\n min-height: 0;\n }\n \n .voice-status-title {\n font-size: clamp(12px, 3vh, 20px);\n font-weight: 600;\n color: ").concat(statusTitleColor, ";\n margin-bottom: clamp(2px, 0.5vh, 4px);\n line-height: 1.2;\n }\n \n .voice-status-subtitle {\n font-size: clamp(10px, 2vh, 14px);\n color: ").concat(statusSubtitleColor, ";\n line-height: 1.2;\n }\n \n /* Start Call Button - Scales with container */\n .start-call-btn {\n margin: 0;\n width: min(280px, 70vw)").concat(important, ";\n height: clamp(48px, 8vh, 64px)").concat(important, ";\n border-radius: clamp(24px, 4vh, 32px)").concat(important, ";\n border: none").concat(important, ";\n background: ").concat(startCallBtnColor).concat(important, ";\n color: ").concat(startCallBtnTextColor).concat(important, ";\n font-size: clamp(14px, 2.5vh, 18px)").concat(important, ";\n font-weight: 600").concat(important, ";\n cursor: pointer").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n gap: clamp(8px, 1.5vh, 12px);\n box-shadow: 0 12px 30px rgba(102, 126, 234, 0.4);\n transition: all 0.3s ease;\n flex-shrink: 0;\n }\n \n .start-call-btn svg {\n display: block").concat(important, ";\n visibility: visible").concat(important, ";\n opacity: 1").concat(important, ";\n width: auto").concat(important, ";\n height: auto").concat(important, ";\n }\n \n .start-call-btn svg {\n width: clamp(22px, 4vh, 32px);\n height: clamp(22px, 4vh, 32px);\n }\n \n .start-call-btn:hover {\n transform: translateY(-2px);\n box-shadow: 0 12px 28px rgba(102, 126, 234, 0.5);\n }\n \n .start-call-btn:active {\n transform: translateY(-1px);\n }\n .start-call-btn:disabled {\n cursor: not-allowed").concat(important, ";\n opacity: 0.6").concat(important, ";\n }\n \n /* Connecting Spinner */\n .connecting-spinner {\n display: inline-block;\n width: 16px;\n height: 16px;\n border: 2px solid rgba(255, 255, 255, 0.3);\n border-top-color: ").concat(startCallBtnTextColor, ";\n border-radius: 50%;\n animation: spin 1s linear infinite;\n margin-right: 8px;\n vertical-align: middle;\n }\n \n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n \n /* Voice Transcript - Scales with container */\n .voice-transcript {\n background: ").concat(transcriptBg, ";\n padding: clamp(6px, 1.5vh, 12px);\n border-radius: 10px;\n width: min(360px, calc(100% - 40px));\n margin: 0;\n min-height: clamp(80px, 15vh, 120px);\n max-height: clamp(100px, 18vh, 140px);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n flex-shrink: 1;\n overflow-y: auto;\n overflow-x: hidden;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n }\n \n .transcript-label {\n font-size: clamp(8px, 1.4vh, 11px);\n color: ").concat(transcriptLabelColor, ";\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: clamp(3px, 0.6vh, 6px);\n flex-shrink: 0;\n word-wrap: break-word;\n }\n \n .transcript-text {\n font-size: clamp(11px, 2vh, 15px);\n color: ").concat(transcriptTextColor, ";\n line-height: 1.4;\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n word-wrap: break-word;\n overflow-wrap: break-word;\n }\n \n .transcript-text.empty {\n color: #cbd5e1;\n font-style: italic;\n }\n \n /* Voice Text Input Area - Type while on voice call */\n .voice-text-input-area {\n width: 100%;\n padding: 14px 16px;\n margin: 0;\n flex-shrink: 0;\n background: #ffffff;\n border-top: 1px solid rgba(0, 0, 0, 0.06);\n box-sizing: border-box;\n }\n \n .voice-input-wrapper {\n display: flex;\n align-items: center;\n gap: 10px;\n background: #f1f5f9;\n border-radius: 12px;\n padding: 4px 4px 4px 14px;\n border: 1px solid transparent;\n transition: all 0.2s ease;\n }\n \n .voice-input-wrapper:focus-within {\n background: #fff;\n border-color: #a855f7;\n box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.1);\n }\n \n .voice-text-input {\n flex: 1;\n border: none;\n outline: none;\n font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 14px;\n color: ").concat(liveTranscriptTextColor).concat(important, ";\n background: transparent;\n padding: 10px 0;\n }\n \n .voice-text-input::placeholder {\n color: #94a3b8;\n }\n \n .voice-send-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n height: 38px;\n border-radius: 10px;\n border: none;\n background: ").concat(voiceSendButtonColor).concat(important, ";\n color: #fff;\n cursor: pointer;\n transition: transform 0.2s ease;\n flex-shrink: 0;\n }\n \n .voice-send-btn:hover:not(:disabled) {\n transform: scale(1.05);\n }\n \n .voice-send-btn:active:not(:disabled) {\n transform: scale(0.95);\n }\n \n .voice-send-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n }\n \n .voice-send-btn svg {\n width: 16px;\n height: 16px;\n }\n \n .voice-input-hint {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n margin-top: 10px;\n font-size: 11px;\n color: #64748b;\n transition: color 0.2s ease;\n }\n \n .voice-input-hint svg {\n width: 12px;\n height: 12px;\n color: #10b981;\n }\n \n /* Text input status states */\n .voice-input-hint--sending {\n color: #666;\n }\n \n .voice-input-hint--success {\n color: #28a745;\n }\n \n .voice-input-hint--queued {\n color: #ffc107;\n }\n \n .voice-input-hint--error {\n color: #dc3545;\n }\n \n /* Disabled input styling */\n .voice-text-input:disabled,\n #mobileTextInput:disabled {\n background-color: #f5f5f5;\n cursor: not-allowed;\n }\n \n .voice-send-btn:disabled,\n #mobileSendBtn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n \n /* Voice Controls - Scales with container */\n .voice-controls {\n display: flex;\n gap: clamp(8px, 1.8vh, 14px);\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin: 0;\n padding-top: 0;\n }\n \n .voice-control-btn {\n width: clamp(48px, 9vh, 72px)").concat(important, ";\n height: clamp(48px, 9vh, 72px)").concat(important, ";\n min-width: clamp(48px, 9vh, 72px)").concat(important, ";\n min-height: clamp(48px, 9vh, 72px)").concat(important, ";\n max-width: clamp(48px, 9vh, 72px)").concat(important, ";\n max-height: clamp(48px, 9vh, 72px)").concat(important, ";\n aspect-ratio: 1").concat(important, ";\n border-radius: 50%").concat(important, ";\n border: none").concat(important, ";\n cursor: pointer").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n transition: all 0.2s;\n position: relative").concat(important, ";\n flex-shrink: 0;\n overflow: hidden").concat(important, ";\n padding: 0").concat(important, ";\n margin: 0").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n \n .voice-control-btn svg {\n width: 48%").concat(important, ";\n height: 48%").concat(important, ";\n min-width: 48%").concat(important, ";\n min-height: 48%").concat(important, ";\n max-width: 48%").concat(important, ";\n max-height: 48%").concat(important, ";\n display: block").concat(important, ";\n visibility: visible").concat(important, ";\n opacity: 1").concat(important, ";\n margin: 0").concat(important, ";\n padding: 0").concat(important, ";\n position: relative").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n \n .voice-control-btn.primary {\n width: clamp(54px, 10vh, 80px)").concat(important, ";\n height: clamp(54px, 10vh, 80px)").concat(important, ";\n min-width: clamp(54px, 10vh, 80px)").concat(important, ";\n min-height: clamp(54px, 10vh, 80px)").concat(important, ";\n max-width: clamp(54px, 10vh, 80px)").concat(important, ";\n max-height: clamp(54px, 10vh, 80px)").concat(important, ";\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)").concat(important, ";\n color: white").concat(important, ";\n box-shadow: 0 6px 18px rgba(102, 126, 234, 0.4);\n }\n \n .voice-control-btn.primary:hover {\n transform: scale(1.05);\n }\n \n .voice-control-btn.primary.active {\n background: ").concat(endCallBtnColor).concat(important, ";\n animation: recordingPulse 1.5s ease-in-out infinite;\n }\n .voice-control-btn.primary.active svg {\n fill: white").concat(important, ";\n }\n \n /* More specific selectors for WordPress compatibility */\n #endCallBtn.voice-control-btn.primary.active,\n #muteBtn.voice-control-btn.secondary,\n #speakerBtn.voice-control-btn.secondary {\n border-radius: 50% !important;\n width: clamp(48px, 9vh, 72px) !important;\n height: clamp(48px, 9vh, 72px) !important;\n min-width: clamp(48px, 9vh, 72px) !important;\n min-height: clamp(48px, 9vh, 72px) !important;\n max-width: clamp(48px, 9vh, 72px) !important;\n max-height: clamp(48px, 9vh, 72px) !important;\n aspect-ratio: 1 !important;\n overflow: hidden !important;\n }\n \n #endCallBtn.voice-control-btn.primary.active {\n width: clamp(54px, 10vh, 80px) !important;\n height: clamp(54px, 10vh, 80px) !important;\n min-width: clamp(54px, 10vh, 80px) !important;\n min-height: clamp(54px, 10vh, 80px) !important;\n max-width: clamp(54px, 10vh, 80px) !important;\n max-height: clamp(54px, 10vh, 80px) !important;\n }\n \n \n /* Microphone button specific background color */\n #muteBtn.voice-control-btn.secondary {\n background: ").concat(micButtonColor).concat(important, ";\n }\n \n /* Speaker button specific background color */\n #speakerBtn.voice-control-btn.secondary {\n background: ").concat(speakerButtonColor).concat(important, ";\n }\n \n #endCallBtn.voice-control-btn.primary.active svg,\n #muteBtn.voice-control-btn.secondary svg,\n #speakerBtn.voice-control-btn.secondary svg {\n display: block !important;\n visibility: visible !important;\n opacity: 1 !important;\n width: 48% !important;\n height: 48% !important;\n margin: 0 !important;\n padding: 0 !important;\n position: relative !important;\n }\n \n @keyframes recordingPulse {\n 0%, 100% { \n box-shadow: 0 6px 16px rgba(239, 68, 68, 0.4);\n }\n 50% { \n box-shadow: 0 6px 24px rgba(239, 68, 68, 0.7);\n }\n }\n \n .voice-control-btn.secondary {\n background: ").concat(controlBtnColor).concat(important, ";\n color: ").concat(controlBtnSecondaryColor).concat(important, ";\n box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);\n width: clamp(48px, 9vh, 72px)").concat(important, ";\n height: clamp(48px, 9vh, 72px)").concat(important, ";\n min-width: clamp(48px, 9vh, 72px)").concat(important, ";\n min-height: clamp(48px, 9vh, 72px)").concat(important, ";\n max-width: clamp(48px, 9vh, 72px)").concat(important, ";\n max-height: clamp(48px, 9vh, 72px)").concat(important, ";\n }\n \n .voice-control-btn.secondary:hover {\n background: #f8fafc").concat(important, ";\n transform: scale(1.05);\n }\n \n .voice-control-btn.secondary.muted {\n background: #f3f4f6").concat(important, ";\n }\n \n .voice-control-btn.secondary.muted .mute-icon {\n stroke: #9ca3af !important;\n }\n \n .voice-control-btn.secondary svg {\n width: 48%").concat(important, ";\n height: 48%").concat(important, ";\n display: block").concat(important, ";\n visibility: visible").concat(important, ";\n opacity: 1").concat(important, ";\n margin: 0").concat(important, ";\n padding: 0").concat(important, ";\n position: relative").concat(important, ";\n }\n \n .voice-timer {\n position: absolute;\n bottom: clamp(-18px, -3vh, -24px);\n font-size: clamp(9px, 1.6vh, 12px);\n color: #64748b;\n font-weight: 500;\n white-space: nowrap;\n }\n \n /* ===== DESKTOP VOICE SECTION - New Design ===== */\n .desktop-voice-section {\n padding: 16px 20px;\n background: linear-gradient(180deg, #ffffff 0%, rgba(168, 85, 247, 0.04) 100%);\n width: 100%;\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n box-sizing: border-box;\n text-align: center;\n }\n \n /* Ensure all children are centered */\n .desktop-voice-section > * {\n margin-left: auto;\n margin-right: auto;\n }\n \n .desktop-timer {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 6px !important;\n padding: 5px 10px !important;\n background: rgba(0, 0, 0, 0.05) !important;\n border-radius: 20px !important;\n font-family: 'JetBrains Mono', 'Courier New', monospace;\n font-size: 11px !important;\n color: #64748b !important;\n margin: 0 auto !important;\n }\n \n .desktop-timer .timer-dot {\n width: 5px").concat(important, ";\n height: 5px").concat(important, ";\n background: #ef4444").concat(important, ";\n border-radius: 50%").concat(important, ";\n animation: timerPulse 1s ease-in-out infinite").concat(important, ";\n }\n \n @keyframes timerPulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n }\n \n .desktop-avatar-container {\n margin-bottom: 12px;\n }\n \n .desktop-avatar-large {\n width: 80px !important;\n height: 80px !important;\n border-radius: 20px !important;\n margin: 0 auto 12px !important;\n box-shadow: 0 8px 24px rgba(168, 85, 247, 0.35) !important;\n background: linear-gradient(135deg, ").concat(avatarBg, " 0%, ").concat(avatarActiveBg, " 100%) !important;\n }\n \n .desktop-waveform {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 4px !important;\n height: 36px !important;\n width: 100% !important;\n }\n \n .desktop-waveform-bar {\n width: 4px !important;\n background: rgba(255, 255, 255, 0.9) !important;\n border-radius: 2px !important;\n animation: waveformAnimation 0.8s ease-in-out infinite !important;\n }\n \n .desktop-waveform-bar[data-index=\"0\"] { height: 14px !important; animation-delay: 0s !important; }\n .desktop-waveform-bar[data-index=\"1\"] { height: 26px !important; animation-delay: 0.1s !important; }\n .desktop-waveform-bar[data-index=\"2\"] { height: 36px !important; animation-delay: 0.2s !important; }\n .desktop-waveform-bar[data-index=\"3\"] { height: 22px !important; animation-delay: 0.3s !important; }\n .desktop-waveform-bar[data-index=\"4\"] { height: 16px !important; animation-delay: 0.4s !important; }\n \n @keyframes waveformAnimation {\n 0%, 100% { transform: scaleY(0.5); }\n 50% { transform: scaleY(1); }\n }\n \n .desktop-waveform.paused .desktop-waveform-bar {\n animation-play-state: paused;\n }\n\n /* New main waveform (used in updated template) */\n .desktop-main-waveform {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 3px !important;\n height: 48px !important;\n width: 100% !important;\n max-width: 200px !important;\n margin: 0 auto !important;\n padding: 0 20px !important;\n }\n\n .desktop-main-waveform .waveform-bar {\n width: 3px !important;\n background: #a855f7 !important;\n border-radius: 2px !important;\n height: 8px !important;\n animation: waveformAnimation 0.8s ease-in-out infinite !important;\n }\n\n .desktop-main-waveform .waveform-bar:nth-child(1) { height: 12px !important; animation-delay: 0s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(2) { height: 20px !important; animation-delay: 0.05s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(3) { height: 28px !important; animation-delay: 0.1s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(4) { height: 36px !important; animation-delay: 0.15s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(5) { height: 44px !important; animation-delay: 0.2s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(6) { height: 50px !important; animation-delay: 0.25s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(7) { height: 54px !important; animation-delay: 0.3s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(8) { height: 56px !important; animation-delay: 0.35s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(9) { height: 54px !important; animation-delay: 0.4s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(10) { height: 50px !important; animation-delay: 0.45s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(11) { height: 44px !important; animation-delay: 0.5s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(12) { height: 36px !important; animation-delay: 0.55s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(13) { height: 28px !important; animation-delay: 0.6s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(14) { height: 20px !important; animation-delay: 0.65s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(15) { height: 12px !important; animation-delay: 0.7s !important; }\n\n .desktop-status {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 5px !important;\n font-size: 12px !important;\n color: ").concat(statusTitleColor, ";\n font-weight: 500;\n width: 100%;\n text-align: center;\n margin: 0 auto;\n }\n \n .desktop-status .status-dot {\n width: 5px !important;\n height: 5px !important;\n background: ").concat(statusDotColor, " !important;\n border-radius: 50% !important;\n animation: statusPulse 1.5s ease-in-out infinite !important;\n }\n \n @keyframes statusPulse {\n 0%, 100% { transform: scale(1); opacity: 1; }\n 50% { transform: scale(1.15); opacity: 0.8; }\n }\n \n .desktop-live-waveform {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 3px;\n height: 48px;\n margin-bottom: 20px;\n }\n \n .desktop-live-bar {\n width: 3px;\n background: linear-gradient(180deg, ").concat(avatarBg, ", ").concat(avatarActiveBg, ");\n border-radius: 2px;\n transition: height 0.1s ease;\n height: 8px;\n }\n \n .desktop-controls {\n display: flex;\n gap: 8px;\n align-items: center;\n justify-content: center;\n width: 100%;\n margin: 0 auto;\n }\n \n .desktop-control-btn {\n width: 46px;\n height: 46px;\n border-radius: 50%;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n .desktop-control-btn svg {\n width: 20px;\n height: 20px;\n }\n \n .desktop-mic-icon,\n .desktop-speaker-icon {\n width: 20px !important;\n height: 20px !important;\n display: block;\n flex-shrink: 0;\n }\n \n .desktop-control-btn.secondary.muted .desktop-mic-icon,\n .desktop-control-btn.secondary.muted .desktop-speaker-icon {\n width: 20px !important;\n height: 20px !important;\n }\n \n \n .desktop-control-btn.secondary:hover {\n background: rgba(0, 0, 0, 0.1);\n color: #1e293b;\n transform: scale(1.05);\n }\n .desktop-control-btn.secondary.muted {\n background: #f3f4f6;\n color: #9ca3af;\n }\n \n .desktop-control-btn.secondary.muted .desktop-mic-icon,\n .desktop-control-btn.secondary.muted .desktop-speaker-icon {\n stroke: #9ca3af;\n }\n \n .desktop-control-btn.secondary {\n position: relative;\n }\n \n \n /* Desktop microphone button background color */\n #desktopMuteBtn.desktop-control-btn.secondary,\n #desktopMuteBtnCompact.compact-control-btn.secondary {\n background: ").concat(micButtonColor).concat(important, ";\n }\n \n /* Desktop speaker button background color */\n #desktopSpeakerBtn.desktop-control-btn.secondary,\n #desktopSpeakerBtnCompact.compact-control-btn.secondary {\n background: ").concat(speakerButtonColor).concat(important, ";\n }\n .desktop-mic-off-icon,\n .desktop-speaker-off-icon {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 46px;\n height: 46px;\n transform: translate(-50%, -50%);\n z-index: 10;\n }\n .desktop-control-btn.danger {\n width: 50px;\n height: 50px;\n background: ").concat(endCallBtnColor).concat(important, ";\n color: #ffffff;\n box-shadow: 0 4px 14px rgba(239, 68, 68, 0.4);\n overflow: visible;\n }\n \n .desktop-control-btn.danger svg {\n width: 20px;\n height: 20px;\n overflow: visible;\n }\n \n .desktop-control-btn.danger:hover {\n transform: scale(1.06);\n box-shadow: 0 6px 20px rgba(239, 68, 68, 0.5);\n }\n \n .desktop-control-btn.danger:hover {\n transform: scale(1.06);\n box-shadow: 0 6px 20px rgba(239, 68, 68, 0.5);\n }\n \n \n /* ===== COMPACT VOICE SECTION (Single-row layout) ===== */\n .compact-voice-section {\n padding: 10px 14px;\n background: linear-gradient(180deg, #ffffff, rgba(168, 85, 247, 0.04));\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n border-bottom: 1px solid rgba(0, 0, 0, 0.06);\n min-height: 62px;\n flex-shrink: 0;\n }\n \n .compact-left {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n \n .compact-avatar {\n width: 42px;\n height: 42px;\n min-width: 42px;\n min-height: 42px;\n border-radius: 12px;\n background: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n overflow: visible;\n position: relative;\n }\n \n /* Waveform container in compact avatar - ensure it's visible */\n .compact-avatar .desktop-main-waveform {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 2px !important;\n height: 100% !important;\n width: 100% !important;\n padding: 4px !important;\n transform: scale(0.75) !important;\n transform-origin: center !important;\n }\n \n /* Ensure waveform bars are visible and animated in compact mode */\n .compact-avatar .desktop-main-waveform .waveform-bar {\n width: 2px !important;\n min-width: 2px !important;\n background: #a855f7 !important;\n border-radius: 1px !important;\n flex-shrink: 0 !important;\n animation: waveformAnimation 0.8s ease-in-out infinite !important;\n }\n \n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(1) { height: 6px !important; animation-delay: 0s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(2) { height: 10px !important; animation-delay: 0.05s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(3) { height: 14px !important; animation-delay: 0.1s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(4) { height: 18px !important; animation-delay: 0.15s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(5) { height: 22px !important; animation-delay: 0.2s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(6) { height: 26px !important; animation-delay: 0.25s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(7) { height: 28px !important; animation-delay: 0.3s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(8) { height: 30px !important; animation-delay: 0.35s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(9) { height: 28px !important; animation-delay: 0.4s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(10) { height: 26px !important; animation-delay: 0.45s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(11) { height: 22px !important; animation-delay: 0.5s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(12) { height: 18px !important; animation-delay: 0.55s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(13) { height: 14px !important; animation-delay: 0.6s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(14) { height: 10px !important; animation-delay: 0.65s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(15) { height: 6px !important; animation-delay: 0.7s !important; }\n\n }\n \n .compact-info {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n \n .compact-timer {\n display: flex;\n align-items: center;\n gap: 5px;\n font-family: 'JetBrains Mono', 'Courier New', monospace;\n font-size: 13px;\n font-weight: 600;\n color: ").concat(liveTranscriptTextColor).concat(important, ";\n }\n \n .compact-timer .timer-dot {\n width: 6px").concat(important, ";\n height: 6px").concat(important, ";\n background: #ef4444").concat(important, ";\n border-radius: 50%").concat(important, ";\n animation: timerPulse 1s ease-in-out infinite").concat(important, ";\n }\n \n .compact-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(statusTitleColor).concat(important, ";\n }\n \n .compact-status .status-dot {\n width: 5px").concat(important, ";\n height: 5px").concat(important, ";\n background: ").concat(statusDotColor).concat(important, ";\n border-radius: 50%").concat(important, ";\n animation: statusPulse 1.5s ease-in-out infinite").concat(important, ";\n }\n \n @keyframes statusPulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.7; transform: scale(1.1); }\n }\n \n .compact-controls {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n \n .compact-control-btn {\n width: 36px;\n height: 36px;\n min-width: 36px;\n min-height: 36px;\n border-radius: 50%;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n padding: 0;\n position: relative;\n }\n \n .compact-control-btn svg {\n width: 16px;\n height: 16px;\n }\n \n .compact-control-btn.secondary {\n background: #f1f5f9;\n color: #64748b;\n }\n \n \n /* Compact speaker button background color */\n #desktopSpeakerBtnCompact.compact-control-btn.secondary {\n background: ").concat(speakerButtonColor).concat(important, ";\n }\n /* Compact microphone button background color */\n #desktopMuteBtnCompact.compact-control-btn.secondary {\n background: ").concat(micButtonColor).concat(important, ";\n }\n \n .compact-control-btn.secondary:hover {\n background: #e2e8f0;\n color: #475569;\n }\n \n .compact-control-btn.secondary.muted {\n background: rgba(239, 68, 68, 0.1);\n color: #ef4444;\n }\n \n \n .compact-control-btn.secondary.muted .desktop-mic-icon,\n .compact-control-btn.secondary.muted .desktop-speaker-icon {\n stroke: #ef4444;\n }\n \n .compact-control-btn.secondary.muted .desktop-mic-off-icon,\n .compact-control-btn.secondary.muted .desktop-speaker-off-icon {\n width: 46px;\n height: 46px;\n }\n\n .compact-control-btn.danger {\n width: 40px;\n height: 40px;\n min-width: 40px;\n min-height: 40px;\n background: ").concat(endCallBtnColor).concat(important, ";\n color: white;\n box-shadow: 0 3px 10px rgba(239, 68, 68, 0.35);\n }\n \n .compact-control-btn.danger:hover {\n transform: scale(1.05);\n box-shadow: 0 4px 14px rgba(239, 68, 68, 0.45);\n }\n \n .compact-control-btn.danger svg {\n width: 18px;\n height: 18px;\n overflow: visible;\n }\n \n/* ===== CONVERSATION PANEL ===== */\n .desktop-conversation-panel {\n border-top: 1px solid rgba(0, 0, 0, 0.06);\n width: 100%;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n flex: 1;\n }\n \n .conversation-header {\n padding: 10px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: #fafafa;\n cursor: pointer;\n flex-shrink: 0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.04);\n transition: background 0.2s ease;\n }\n \n .conversation-header:hover {\n background: #f5f5f5;\n }\n \n .conversation-label {\n font-size: 11px;\n font-weight: 600;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n \n .conversation-toggle {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: #94a3b8;\n font-weight: 500;\n }\n \n .conversation-toggle svg {\n transition: transform 0.2s ease;\n }\n \n .conversation-header.expanded .conversation-toggle svg {\n transform: rotate(180deg);\n }\n \n /* ===== COLLAPSED: Live Transcript Only (2 lines) ===== */\n .live-transcript-collapsed {\n padding: 12px 16px;\n background: #fafafa;\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex-shrink: 0;\n min-height: 50px;\n }\n \n .live-indicator {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 9px;\n font-weight: 700;\n color: ").concat(liveIndicatorTextColor).concat(important, ";\n text-transform: uppercase;\n letter-spacing: 0.08em;\n }\n \n .live-indicator .live-dot {\n height: 5px;\n width: 5px;\n background: ").concat(liveIndicatorDotColor).concat(important, ";\n border-radius: 50%;\n animation: statusPulse 1.5s ease-in-out infinite;\n }\n \n .live-text-collapsed {\n font-size: ").concat(liveTranscriptFontSize).concat(important, ";\n color: ").concat(liveTranscriptTextColor).concat(important, ";\n line-height: 1.5;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n \n .live-text-collapsed.muted {\n color: #94a3b8;\n font-style: italic;\n }\n \n .typing-cursor {\n display: inline-block;\n width: 2px;\n height: 14px;\n background: #a855f7;\n margin-left: 2px;\n animation: blink 1s step-end infinite;\n vertical-align: middle;\n }\n \n @keyframes blink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0; }\n }\n \n /* ===== EXPANDED: Full Conversation History ===== */\n .conversation-history {\n flex: 1;\n flex-direction: column;\n gap: 10px;\n overflow-y: auto;\n padding: 14px 16px;\n min-height: 0;\n }\n .conversation-history.visible {\n display: flex;\n }\n\n .conversation-messages {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n /* Message Rows */\n .message-row {\n display: flex;\n gap: 8px;\n animation: msgIn 0.25s ease;\n }\n \n @keyframes msgIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n @keyframes slideIn {\n from { opacity: 0; transform: translateY(-10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n \n @keyframes slideOut {\n from { opacity: 1; transform: translateY(0); }\n to { opacity: 0; transform: translateY(-10px); }\n }\n \n .message-row.user {\n flex-direction: row-reverse;\n }\n \n .message-avatar {\n width: 28px;\n height: 28px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n\n .message-avatar.assistant {\n background: linear-gradient(135deg, #c084fc, #a855f7);\n }\n\n .message-avatar.assistant .orb {\n width: 12px;\n height: 12px;\n background: rgba(255, 255, 255, 0.9);\n border-radius: 50%;\n }\n\n .message-avatar.user {\n background: linear-gradient(135deg, #64748b, #475569);\n color: #fff;\n font-size: 11px;\n font-weight: 600;\n }\n\n .message-bubble {\n max-width: 80%;\n padding: 9px 13px;\n border-radius: 12px;\n font-size: 13px;\n line-height: 1.5;\n }\n \n .message-row.assistant .message-bubble {\n background: #fff;\n color: ").concat(liveTranscriptTextColor).concat(important, ";\n border: 1px solid rgba(0, 0, 0, 0.06);\n border-bottom-left-radius: 4px;\n }\n \n .message-row.user .message-bubble {\n background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);\n color: #fff;\n border-bottom-right-radius: 4px;\n }\n \n /* Live message at bottom of history */\n .live-message-row {\n display: flex;\n gap: 8px;\n padding-top: 8px;\n border-top: 1px dashed rgba(0, 0, 0, 0.08);\n margin-top: auto;\n }\n \n .live-message-row .message-bubble {\n background: #fff;\n border: 1px solid rgba(16, 185, 129, 0.3);\n color: ").concat(liveTranscriptTextColor).concat(important, ";\n position: relative;\n border-radius: 14px;\n border-bottom-left-radius: 4px;\n }\n \n .live-message-row .live-badge {\n position: absolute;\n top: -8px;\n left: 10px;\n background: #10b981;\n color: #fff;\n font-size: 8px;\n font-weight: 700;\n padding: 2px 6px;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n \n /* Hide/show based on expanded state */\n .desktop-conversation-panel.collapsed .conversation-history {\n display: none;\n }\n \n .desktop-conversation-panel.collapsed .live-transcript-collapsed {\n display: flex;\n }\n \n .desktop-conversation-panel.expanded .conversation-history {\n display: flex;\n max-height: 400px;\n }\n \n .desktop-conversation-panel.expanded .live-transcript-collapsed {\n display: none;\n }\n \n /* ===== DARK MODE SUPPORT ===== */\n @media (prefers-color-scheme: dark) {\n .desktop-voice-section {\n background: linear-gradient(180deg, #1e1e2e 0%, rgba(168, 85, 247, 0.08) 100%);\n }\n\n .desktop-timer {\n color: #94a3b8;\n }\n\n .desktop-status {\n color: #34d399;\n }\n\n .desktop-status .status-dot {\n \n .desktop-control-btn.secondary.muted {\n background: rgba(255, 255, 255, 0.1);\n color: #9ca3af;\n \n .compact-voice-section {\n background: linear-gradient(180deg, #1e1e2e 0%, rgba(168, 85, 247, 0.08) 100%);\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n }\n \n .compact-timer {\n color: #e2e8f0;\n }\n \n .compact-status {\n color: #34d399;\n }\n \n .compact-status .status-dot {\n background: #34d399;\n }\n \n .compact-control-btn.secondary {\n background: rgba(255, 255, 255, 0.08);\n color: #94a3b8;\n }\n \n .compact-control-btn.secondary:hover {\n background: rgba(255, 255, 255, 0.15);\n color: #e2e8f0;\n }\n \n .compact-control-btn.secondary.muted {\n background: rgba(239, 68, 68, 0.2);\n color: #f87171;\n }\n\n }\n \n .desktop-control-btn.secondary.muted svg {\n \n .desktop-control-btn.secondary {\n position: relative;\n }\n \n /* Desktop microphone button background color */\n #desktopMuteBtn.desktop-control-btn.secondary,\n #desktopMuteBtnCompact.compact-control-btn.secondary {\n background: ").concat(micButtonColor).concat(important, ";\n }\n \n .desktop-mic-off-icon,\n .desktop-speaker-off-icon {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 20px;\n height: 20px;\n }\n \n .desktop-control-btn.secondary.muted {\n background: #f3f4f6;\n color: #9ca3af;\n }\n \n .desktop-control-btn.secondary.muted svg {\n \n .desktop-control-btn.secondary {\n position: relative;\n }\n \n /* Desktop microphone button background color */\n #desktopMuteBtn.desktop-control-btn.secondary,\n #desktopMuteBtnCompact.compact-control-btn.secondary {\n background: ").concat(micButtonColor).concat(important, ";\n }\n \n .desktop-mic-off-icon,\n .desktop-speaker-off-icon {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 20px;\n height: 20px;\n }\n stroke: #9ca3af;\n }\n stroke: #9ca3af;\n }\n background: #34d399;\n }\n\n .desktop-control-btn.secondary {\n background: rgba(255, 255, 255, 0.08);\n color: #94a3b8;\n }\n\n .desktop-control-btn.secondary:hover {\n background: rgba(255, 255, 255, 0.15);\n color: #e2e8f0;\n }\n\n .desktop-conversation-panel {\n border-top: 1px solid rgba(255, 255, 255, 0.08);\n }\n\n .conversation-header {\n background: #1a1a2e;\n }\n\n .conversation-header:hover {\n background: #252540;\n }\n\n .conversation-label {\n color: #94a3b8;\n }\n\n .conversation-toggle {\n color: #64748b;\n }\n\n .live-transcript-preview {\n background: #1a1a2e;\n }\n .live-indicator {\n color: ").concat(liveIndicatorTextColor).concat(important, ";\n }\n .live-indicator .live-dot {\n background: ").concat(liveIndicatorDotColor).concat(important, ";\n }\n\n .live-text {\n color: #e2e8f0;\n }\n\n .live-text.muted {\n color: #64748b;\n }\n\n .conversation-history {\n background: #1a1a2e;\n }\n\n .conversation-msg.assistant .conversation-msg-bubble {\n background: #252540;\n color: #e2e8f0;\n border: 1px solid rgba(255, 255, 255, 0.08);\n }\n\n .voice-text-input-area {\n background: #1a1a2e;\n }\n\n .voice-text-input {\n background: #252540 !important;\n color: #e2e8f0 !important;\n border-color: rgba(255, 255, 255, 0.1) !important;\n }\n\n .voice-text-input::placeholder {\n color: #64748b !important;\n }\n\n .voice-text-input:focus {\n border-color: ").concat(avatarBg, " !important;\n box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.2) !important;\n }\n\n .voice-input-hint {\n color: #64748b !important;\n }\n\n .voice-send-btn {\n background: ").concat(voiceSendButtonColor, " !important;\n }\n\n .voice-send-btn:disabled {\n background: #374151 !important;\n color: #4b5563 !important;\n }\n }\n\n /* Mobile optimization */\n @media (max-width: 768px) {\n .voice-interface {\n padding: 6px 10px;\n }\n }\n \n @media (max-width: 480px) {\n .voice-interface {\n padding: 5px 8px;\n }\n }\n \n /* Mobile Voice Call UI - Shared styles (also used in generateMobileCSS) */\n ").concat(this._getSharedMobileCSS(important), "\n\n ");
|
|
27347
|
+
return "\n /* Voice Interface Styles - Ultra-compact for Wix iframes */\n .voice-interface { \n display: none".concat(important, "; \n flex: 1; \n flex-direction: column;\n align-items: stretch; \n justify-content: flex-start; \n padding: 0; \n background: linear-gradient(180deg, #f8fafc 0%, #e0e7ff 100%);\n overflow: hidden;\n min-height: 0;\n height: 100%;\n width: 100%;\n box-sizing: border-box;\n }\n .voice-interface.active { display: flex").concat(important, "; }\n \n /* Voice States - Better scaling gaps */\n #voiceIdleState {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n height: 100%;\n min-height: 0;\n justify-content: center;\n overflow: hidden;\n flex: 1;\n box-sizing: border-box;\n gap: clamp(6px, 1.5vh, 12px);\n }\n \n #voiceActiveState {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n height: 100%;\n min-height: 0;\n justify-content: flex-start;\n overflow: hidden;\n flex: 1;\n box-sizing: border-box;\n gap: 0;\n padding: 0;\n }\n \n #voiceActiveState[style*=\"display: none\"] {\n display: none !important;\n }\n \n /* Voice Avatar - Scales better from small to large */\n .voice-avatar,\n .voice-avatar-active {\n width: clamp(80px, 18vh, 160px);\n height: clamp(80px, 18vh, 160px);\n aspect-ratio: 1;\n border-radius: 50%;\n background: linear-gradient(135deg, ").concat(avatarBg, " 0%, ").concat(avatarActiveBg, " 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: clamp(40px, 9vh, 80px);\n margin: 0;\n box-shadow: 0 8px 30px rgba(102, 126, 234, 0.3);\n transition: all 0.3s ease;\n flex-shrink: 0;\n position: relative;\n }\n \n .voice-avatar-active {\n animation: avatarPulse 2s ease-in-out infinite;\n }\n \n @keyframes avatarPulse {\n 0%, 100% { \n transform: scale(1);\n }\n 50% { \n transform: scale(1.05);\n }\n }\n \n .voice-avatar-active.speaking {\n animation: avatarSpeak 0.5s ease-in-out infinite;\n }\n \n @keyframes avatarSpeak {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.08); }\n }\n \n /* Voice Rings Animation */\n .voice-rings {\n position: absolute;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n }\n \n .voice-ring {\ndisplay: block !important;\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n border: 2px solid rgba(102, 126, 234, 0.3);\n border-radius: 50%;\n opacity: 0;\n animation: ringExpand 2s ease-out infinite;\n }\n \n .voice-ring:nth-child(2) { animation-delay: 0.5s; }\n .voice-ring:nth-child(3) { animation-delay: 1s; }\n \n @keyframes ringExpand {\n 0% {\n width: 100%;\n height: 100%;\n opacity: 0.6;\n }\n 100% {\n width: 160%;\n height: 160%;\n opacity: 0;\n }\n }\n \n /* Voice Status - Scales with container */\n .voice-status {\n text-align: center;\n margin: 0;\n flex-shrink: 0;\n min-height: 0;\n }\n \n .voice-status-title {\n font-size: clamp(12px, 3vh, 20px);\n font-weight: 600;\n color: ").concat(statusTitleColor, ";\n margin-bottom: clamp(2px, 0.5vh, 4px);\n line-height: 1.2;\n }\n \n .voice-status-subtitle {\n font-size: clamp(10px, 2vh, 14px);\n color: ").concat(statusSubtitleColor, ";\n line-height: 1.2;\n }\n \n /* Start Call Button - Scales with container */\n .start-call-btn {\n margin: 0;\n width: min(280px, 70vw)").concat(important, ";\n height: clamp(48px, 8vh, 64px)").concat(important, ";\n border-radius: clamp(24px, 4vh, 32px)").concat(important, ";\n border: none").concat(important, ";\n background: ").concat(startCallBtnColor).concat(important, ";\n color: ").concat(startCallBtnTextColor).concat(important, ";\n font-size: clamp(14px, 2.5vh, 18px)").concat(important, ";\n font-weight: 600").concat(important, ";\n cursor: pointer").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n gap: clamp(8px, 1.5vh, 12px);\n box-shadow: 0 12px 30px rgba(102, 126, 234, 0.4);\n transition: all 0.3s ease;\n flex-shrink: 0;\n }\n \n .start-call-btn svg {\n display: block").concat(important, ";\n visibility: visible").concat(important, ";\n opacity: 1").concat(important, ";\n width: auto").concat(important, ";\n height: auto").concat(important, ";\n }\n \n .start-call-btn svg {\n width: clamp(22px, 4vh, 32px);\n height: clamp(22px, 4vh, 32px);\n }\n \n .start-call-btn:hover {\n transform: translateY(-2px);\n box-shadow: 0 12px 28px rgba(102, 126, 234, 0.5);\n }\n \n .start-call-btn:active {\n transform: translateY(-1px);\n }\n .start-call-btn:disabled {\n cursor: not-allowed").concat(important, ";\n opacity: 0.6").concat(important, ";\n }\n \n /* Connecting Spinner */\n .connecting-spinner {\n display: inline-block;\n width: 16px;\n height: 16px;\n border: 2px solid rgba(255, 255, 255, 0.3);\n border-top-color: ").concat(startCallBtnTextColor, ";\n border-radius: 50%;\n animation: spin 1s linear infinite;\n margin-right: 8px;\n vertical-align: middle;\n }\n \n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n \n /* Voice Transcript - Scales with container */\n .voice-transcript {\n background: ").concat(transcriptBg, ";\n padding: clamp(6px, 1.5vh, 12px);\n border-radius: 10px;\n width: min(360px, calc(100% - 40px));\n margin: 0;\n min-height: clamp(80px, 15vh, 120px);\n max-height: clamp(100px, 18vh, 140px);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n flex-shrink: 1;\n overflow-y: auto;\n overflow-x: hidden;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n }\n \n .transcript-label {\n font-size: clamp(8px, 1.4vh, 11px);\n color: ").concat(transcriptLabelColor, ";\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: clamp(3px, 0.6vh, 6px);\n flex-shrink: 0;\n word-wrap: break-word;\n }\n \n .transcript-text {\n font-size: clamp(11px, 2vh, 15px);\n color: ").concat(transcriptTextColor, ";\n line-height: 1.4;\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n word-wrap: break-word;\n overflow-wrap: break-word;\n }\n \n .transcript-text.empty {\n color: #cbd5e1;\n font-style: italic;\n }\n \n /* Voice Text Input Area - Type while on voice call */\n .voice-text-input-area {\n width: 100%;\n padding: 14px 16px;\n margin: 0;\n flex-shrink: 0;\n background: #ffffff;\n border-top: 1px solid rgba(0, 0, 0, 0.06);\n box-sizing: border-box;\n }\n \n .voice-input-wrapper {\n display: flex;\n align-items: center;\n gap: 10px;\n background: #f1f5f9;\n border-radius: 12px;\n padding: 4px 4px 4px 14px;\n border: 1px solid transparent;\n transition: all 0.2s ease;\n }\n \n .voice-input-wrapper:focus-within {\n background: #fff;\n border-color: #a855f7;\n box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.1);\n }\n \n .voice-text-input {\n flex: 1;\n border: none;\n outline: none;\n font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 14px;\n color: ").concat(liveTranscriptTextColor).concat(important, ";\n background: transparent;\n padding: 10px 0;\n }\n \n .voice-text-input::placeholder {\n color: #94a3b8;\n }\n \n .voice-send-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n height: 38px;\n border-radius: 10px;\n border: none;\n background: ").concat(voiceSendButtonColor).concat(important, ";\n color: #fff;\n cursor: pointer;\n transition: transform 0.2s ease;\n flex-shrink: 0;\n }\n \n .voice-send-btn:hover:not(:disabled) {\n transform: scale(1.05);\n }\n \n .voice-send-btn:active:not(:disabled) {\n transform: scale(0.95);\n }\n \n .voice-send-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n }\n \n .voice-send-btn svg {\n width: 16px;\n height: 16px;\n }\n \n .voice-input-hint {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n margin-top: 10px;\n font-size: 11px;\n color: #64748b;\n transition: color 0.2s ease;\n }\n \n .voice-input-hint svg {\n width: 12px;\n height: 12px;\n color: #10b981;\n }\n \n /* Text input status states */\n .voice-input-hint--sending {\n color: #666;\n }\n \n .voice-input-hint--success {\n color: #28a745;\n }\n \n .voice-input-hint--queued {\n color: #ffc107;\n }\n \n .voice-input-hint--error {\n color: #dc3545;\n }\n \n /* Disabled input styling */\n .voice-text-input:disabled,\n #mobileTextInput:disabled {\n background-color: #f5f5f5;\n cursor: not-allowed;\n }\n \n .voice-send-btn:disabled,\n #mobileSendBtn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n \n /* Voice Controls - Scales with container */\n .voice-controls {\n display: flex;\n gap: clamp(8px, 1.8vh, 14px);\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin: 0;\n padding-top: 0;\n }\n \n .voice-control-btn {\n width: clamp(48px, 9vh, 72px)").concat(important, ";\n height: clamp(48px, 9vh, 72px)").concat(important, ";\n min-width: clamp(48px, 9vh, 72px)").concat(important, ";\n min-height: clamp(48px, 9vh, 72px)").concat(important, ";\n max-width: clamp(48px, 9vh, 72px)").concat(important, ";\n max-height: clamp(48px, 9vh, 72px)").concat(important, ";\n aspect-ratio: 1").concat(important, ";\n border-radius: 50%").concat(important, ";\n border: none").concat(important, ";\n cursor: pointer").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n transition: all 0.2s;\n position: relative").concat(important, ";\n flex-shrink: 0;\n overflow: hidden").concat(important, ";\n padding: 0").concat(important, ";\n margin: 0").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n \n .voice-control-btn svg {\n width: 48%").concat(important, ";\n height: 48%").concat(important, ";\n min-width: 48%").concat(important, ";\n min-height: 48%").concat(important, ";\n max-width: 48%").concat(important, ";\n max-height: 48%").concat(important, ";\n display: block").concat(important, ";\n visibility: visible").concat(important, ";\n opacity: 1").concat(important, ";\n margin: 0").concat(important, ";\n padding: 0").concat(important, ";\n position: relative").concat(important, ";\n flex-shrink: 0").concat(important, ";\n }\n \n .voice-control-btn.primary {\n width: clamp(54px, 10vh, 80px)").concat(important, ";\n height: clamp(54px, 10vh, 80px)").concat(important, ";\n min-width: clamp(54px, 10vh, 80px)").concat(important, ";\n min-height: clamp(54px, 10vh, 80px)").concat(important, ";\n max-width: clamp(54px, 10vh, 80px)").concat(important, ";\n max-height: clamp(54px, 10vh, 80px)").concat(important, ";\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)").concat(important, ";\n color: white").concat(important, ";\n box-shadow: 0 6px 18px rgba(102, 126, 234, 0.4);\n }\n \n .voice-control-btn.primary:hover {\n transform: scale(1.05);\n }\n \n .voice-control-btn.primary.active {\n background: ").concat(endCallBtnColor).concat(important, ";\n animation: recordingPulse 1.5s ease-in-out infinite;\n }\n .voice-control-btn.primary.active svg {\n fill: white").concat(important, ";\n }\n \n /* More specific selectors for WordPress compatibility */\n #endCallBtn.voice-control-btn.primary.active,\n #muteBtn.voice-control-btn.secondary,\n #speakerBtn.voice-control-btn.secondary {\n border-radius: 50% !important;\n width: clamp(48px, 9vh, 72px) !important;\n height: clamp(48px, 9vh, 72px) !important;\n min-width: clamp(48px, 9vh, 72px) !important;\n min-height: clamp(48px, 9vh, 72px) !important;\n max-width: clamp(48px, 9vh, 72px) !important;\n max-height: clamp(48px, 9vh, 72px) !important;\n aspect-ratio: 1 !important;\n overflow: hidden !important;\n }\n \n #endCallBtn.voice-control-btn.primary.active {\n width: clamp(54px, 10vh, 80px) !important;\n height: clamp(54px, 10vh, 80px) !important;\n min-width: clamp(54px, 10vh, 80px) !important;\n min-height: clamp(54px, 10vh, 80px) !important;\n max-width: clamp(54px, 10vh, 80px) !important;\n max-height: clamp(54px, 10vh, 80px) !important;\n }\n \n \n /* Microphone button specific background color */\n #muteBtn.voice-control-btn.secondary {\n background: ").concat(micButtonColor).concat(important, ";\n }\n \n /* Speaker button specific background color */\n #speakerBtn.voice-control-btn.secondary {\n background: ").concat(speakerButtonColor).concat(important, ";\n }\n \n #endCallBtn.voice-control-btn.primary.active svg,\n #muteBtn.voice-control-btn.secondary svg,\n #speakerBtn.voice-control-btn.secondary svg {\n display: block !important;\n visibility: visible !important;\n opacity: 1 !important;\n width: 48% !important;\n height: 48% !important;\n margin: 0 !important;\n padding: 0 !important;\n position: relative !important;\n }\n \n @keyframes recordingPulse {\n 0%, 100% { \n box-shadow: 0 6px 16px rgba(239, 68, 68, 0.4);\n }\n 50% { \n box-shadow: 0 6px 24px rgba(239, 68, 68, 0.7);\n }\n }\n \n .voice-control-btn.secondary {\n background: ").concat(controlBtnColor).concat(important, ";\n color: ").concat(controlBtnSecondaryColor).concat(important, ";\n box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);\n width: clamp(48px, 9vh, 72px)").concat(important, ";\n height: clamp(48px, 9vh, 72px)").concat(important, ";\n min-width: clamp(48px, 9vh, 72px)").concat(important, ";\n min-height: clamp(48px, 9vh, 72px)").concat(important, ";\n max-width: clamp(48px, 9vh, 72px)").concat(important, ";\n max-height: clamp(48px, 9vh, 72px)").concat(important, ";\n }\n \n .voice-control-btn.secondary:hover {\n background: #f8fafc").concat(important, ";\n transform: scale(1.05);\n }\n \n .voice-control-btn.secondary.muted {\n background: #f3f4f6").concat(important, ";\n }\n \n .voice-control-btn.secondary.muted .mute-icon {\n stroke: #9ca3af !important;\n }\n \n .voice-control-btn.secondary svg {\n width: 48%").concat(important, ";\n height: 48%").concat(important, ";\n display: block").concat(important, ";\n visibility: visible").concat(important, ";\n opacity: 1").concat(important, ";\n margin: 0").concat(important, ";\n padding: 0").concat(important, ";\n position: relative").concat(important, ";\n }\n \n .voice-timer {\n position: absolute;\n bottom: clamp(-18px, -3vh, -24px);\n font-size: clamp(9px, 1.6vh, 12px);\n color: #64748b;\n font-weight: 500;\n white-space: nowrap;\n }\n \n /* ===== DESKTOP VOICE SECTION - New Design ===== */\n .desktop-voice-section {\n padding: 16px 20px;\n background: linear-gradient(180deg, #ffffff 0%, rgba(168, 85, 247, 0.04) 100%);\n width: 100%;\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n box-sizing: border-box;\n text-align: center;\n }\n \n /* Ensure all children are centered */\n .desktop-voice-section > * {\n margin-left: auto;\n margin-right: auto;\n }\n \n .desktop-timer {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 6px !important;\n padding: 5px 10px !important;\n background: rgba(0, 0, 0, 0.05) !important;\n border-radius: 20px !important;\n font-family: 'JetBrains Mono', 'Courier New', monospace;\n font-size: 11px !important;\n color: #64748b !important;\n margin: 0 auto !important;\n }\n \n .desktop-timer .timer-dot {\n display: block !important;\n width: 5px").concat(important, ";\n height: 5px").concat(important, ";\n background: #ef4444").concat(important, ";\n border-radius: 50%").concat(important, ";\n animation: timerPulse 1s ease-in-out infinite").concat(important, ";\n }\n \n @keyframes timerPulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n }\n \n .desktop-avatar-container {\n margin-bottom: 12px;\n }\n \n .desktop-avatar-large {\n width: 80px !important;\n height: 80px !important;\n border-radius: 20px !important;\n margin: 0 auto 12px !important;\n box-shadow: 0 8px 24px rgba(168, 85, 247, 0.35) !important;\n background: linear-gradient(135deg, ").concat(avatarBg, " 0%, ").concat(avatarActiveBg, " 100%) !important;\n }\n \n .desktop-waveform {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 4px !important;\n height: 36px !important;\n width: 100% !important;\n }\n \n .desktop-waveform-bar {\n display: block !important;\n width: 4px !important;\n background: rgba(255, 255, 255, 0.9) !important;\n border-radius: 2px !important;\n animation: waveformAnimation 0.8s ease-in-out infinite !important;\n }\n \n .desktop-waveform-bar[data-index=\"0\"] { height: 14px !important; animation-delay: 0s !important; }\n .desktop-waveform-bar[data-index=\"1\"] { height: 26px !important; animation-delay: 0.1s !important; }\n .desktop-waveform-bar[data-index=\"2\"] { height: 36px !important; animation-delay: 0.2s !important; }\n .desktop-waveform-bar[data-index=\"3\"] { height: 22px !important; animation-delay: 0.3s !important; }\n .desktop-waveform-bar[data-index=\"4\"] { height: 16px !important; animation-delay: 0.4s !important; }\n \n @keyframes waveformAnimation {\n 0%, 100% { transform: scaleY(0.5); }\n 50% { transform: scaleY(1); }\n }\n \n .desktop-waveform.paused .desktop-waveform-bar {\n animation-play-state: paused;\n }\n\n /* New main waveform (used in updated template) */\n .desktop-main-waveform {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 3px !important;\n height: 48px !important;\n width: 100% !important;\n max-width: 200px !important;\n margin: 0 auto !important;\n padding: 0 20px !important;\n }\n\n .desktop-main-waveform .waveform-bar {\n display: block !important;\n width: 3px !important;\n background: #a855f7 !important;\n border-radius: 2px !important;\n height: 8px !important;\n animation: waveformAnimation 0.8s ease-in-out infinite !important;\n }\n\n .desktop-main-waveform .waveform-bar:nth-child(1) { height: 12px !important; animation-delay: 0s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(2) { height: 20px !important; animation-delay: 0.05s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(3) { height: 28px !important; animation-delay: 0.1s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(4) { height: 36px !important; animation-delay: 0.15s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(5) { height: 44px !important; animation-delay: 0.2s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(6) { height: 50px !important; animation-delay: 0.25s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(7) { height: 54px !important; animation-delay: 0.3s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(8) { height: 56px !important; animation-delay: 0.35s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(9) { height: 54px !important; animation-delay: 0.4s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(10) { height: 50px !important; animation-delay: 0.45s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(11) { height: 44px !important; animation-delay: 0.5s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(12) { height: 36px !important; animation-delay: 0.55s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(13) { height: 28px !important; animation-delay: 0.6s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(14) { height: 20px !important; animation-delay: 0.65s !important; }\n .desktop-main-waveform .waveform-bar:nth-child(15) { height: 12px !important; animation-delay: 0.7s !important; }\n\n .desktop-status {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 5px !important;\n font-size: 12px !important;\n color: ").concat(statusTitleColor, ";\n font-weight: 500;\n width: 100%;\n text-align: center;\n margin: 0 auto;\n }\n \n .desktop-status .status-dot {\n display: block !important;\n width: 5px !important;\n height: 5px !important;\n background: ").concat(statusDotColor, " !important;\n border-radius: 50% !important;\n animation: statusPulse 1.5s ease-in-out infinite !important;\n }\n \n @keyframes statusPulse {\n 0%, 100% { transform: scale(1); opacity: 1; }\n 50% { transform: scale(1.15); opacity: 0.8; }\n }\n \n .desktop-live-waveform {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 3px;\n height: 48px;\n margin-bottom: 20px;\n }\n \n .desktop-live-bar {\ndisplay: block !important;\n width: 3px;\n background: linear-gradient(180deg, ").concat(avatarBg, ", ").concat(avatarActiveBg, ");\n border-radius: 2px;\n transition: height 0.1s ease;\n height: 8px;\n }\n \n .desktop-controls {\n display: flex;\n gap: 8px;\n align-items: center;\n justify-content: center;\n width: 100%;\n margin: 0 auto;\n }\n \n .desktop-control-btn {\n width: 46px;\n height: 46px;\n border-radius: 50%;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n .desktop-control-btn svg {\n width: 20px;\n height: 20px;\n }\n \n .desktop-mic-icon,\n .desktop-speaker-icon {\n width: 20px !important;\n height: 20px !important;\n display: block;\n flex-shrink: 0;\n }\n \n .desktop-control-btn.secondary.muted .desktop-mic-icon,\n .desktop-control-btn.secondary.muted .desktop-speaker-icon {\n width: 20px !important;\n height: 20px !important;\n }\n \n \n .desktop-control-btn.secondary:hover {\n background: rgba(0, 0, 0, 0.1);\n color: #1e293b;\n transform: scale(1.05);\n }\n .desktop-control-btn.secondary.muted {\n background: #f3f4f6;\n color: #9ca3af;\n }\n \n .desktop-control-btn.secondary.muted .desktop-mic-icon,\n .desktop-control-btn.secondary.muted .desktop-speaker-icon {\n stroke: #9ca3af;\n }\n \n .desktop-control-btn.secondary {\n position: relative;\n }\n \n \n /* Desktop microphone button background color */\n #desktopMuteBtn.desktop-control-btn.secondary,\n #desktopMuteBtnCompact.compact-control-btn.secondary {\n background: ").concat(micButtonColor).concat(important, ";\n }\n \n /* Desktop speaker button background color */\n #desktopSpeakerBtn.desktop-control-btn.secondary,\n #desktopSpeakerBtnCompact.compact-control-btn.secondary {\n background: ").concat(speakerButtonColor).concat(important, ";\n }\n .desktop-mic-off-icon,\n .desktop-speaker-off-icon {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 46px;\n height: 46px;\n transform: translate(-50%, -50%);\n z-index: 10;\n }\n .desktop-control-btn.danger {\n width: 50px;\n height: 50px;\n background: ").concat(endCallBtnColor).concat(important, ";\n color: #ffffff;\n box-shadow: 0 4px 14px rgba(239, 68, 68, 0.4);\n overflow: visible;\n }\n \n .desktop-control-btn.danger svg {\n width: 20px;\n height: 20px;\n overflow: visible;\n }\n \n .desktop-control-btn.danger:hover {\n transform: scale(1.06);\n box-shadow: 0 6px 20px rgba(239, 68, 68, 0.5);\n }\n \n .desktop-control-btn.danger:hover {\n transform: scale(1.06);\n box-shadow: 0 6px 20px rgba(239, 68, 68, 0.5);\n }\n \n \n /* ===== COMPACT VOICE SECTION (Single-row layout) ===== */\n .compact-voice-section {\n padding: 10px 14px;\n background: linear-gradient(180deg, #ffffff, rgba(168, 85, 247, 0.04));\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n border-bottom: 1px solid rgba(0, 0, 0, 0.06);\n min-height: 62px;\n flex-shrink: 0;\n }\n \n .compact-left {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n \n .compact-avatar {\n width: 42px;\n height: 42px;\n min-width: 42px;\n min-height: 42px;\n border-radius: 12px;\n background: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n overflow: visible;\n position: relative;\n }\n \n /* Waveform container in compact avatar - ensure it's visible */\n .compact-avatar .desktop-main-waveform {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 2px !important;\n height: 100% !important;\n width: 100% !important;\n padding: 4px !important;\n transform: scale(0.75) !important;\n transform-origin: center !important;\n }\n \n /* Ensure waveform bars are visible and animated in compact mode */\n .compact-avatar .desktop-main-waveform .waveform-bar {\n display: block !important;\n width: 2px !important;\n min-width: 2px !important;\n background: #a855f7 !important;\n border-radius: 1px !important;\n flex-shrink: 0 !important;\n animation: waveformAnimation 0.8s ease-in-out infinite !important;\n }\n \n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(1) { height: 6px !important; animation-delay: 0s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(2) { height: 10px !important; animation-delay: 0.05s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(3) { height: 14px !important; animation-delay: 0.1s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(4) { height: 18px !important; animation-delay: 0.15s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(5) { height: 22px !important; animation-delay: 0.2s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(6) { height: 26px !important; animation-delay: 0.25s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(7) { height: 28px !important; animation-delay: 0.3s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(8) { height: 30px !important; animation-delay: 0.35s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(9) { height: 28px !important; animation-delay: 0.4s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(10) { height: 26px !important; animation-delay: 0.45s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(11) { height: 22px !important; animation-delay: 0.5s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(12) { height: 18px !important; animation-delay: 0.55s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(13) { height: 14px !important; animation-delay: 0.6s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(14) { height: 10px !important; animation-delay: 0.65s !important; }\n .compact-avatar .desktop-main-waveform .waveform-bar:nth-child(15) { height: 6px !important; animation-delay: 0.7s !important; }\n\n }\n \n .compact-info {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n \n .compact-timer {\n display: flex;\n align-items: center;\n gap: 5px;\n font-family: 'JetBrains Mono', 'Courier New', monospace;\n font-size: 13px;\n font-weight: 600;\n color: ").concat(liveTranscriptTextColor).concat(important, ";\n }\n \n .compact-timer .timer-dot {\n display: block !important;\n width: 6px").concat(important, ";\n height: 6px").concat(important, ";\n background: #ef4444").concat(important, ";\n border-radius: 50%").concat(important, ";\n animation: timerPulse 1s ease-in-out infinite").concat(important, ";\n }\n \n .compact-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(statusTitleColor).concat(important, ";\n }\n \n .compact-status .status-dot {\n display: block !important;\n width: 5px").concat(important, ";\n height: 5px").concat(important, ";\n background: ").concat(statusDotColor).concat(important, ";\n border-radius: 50%").concat(important, ";\n animation: statusPulse 1.5s ease-in-out infinite").concat(important, ";\n }\n \n @keyframes statusPulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.7; transform: scale(1.1); }\n }\n \n .compact-controls {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n \n .compact-control-btn {\n width: 36px;\n height: 36px;\n min-width: 36px;\n min-height: 36px;\n border-radius: 50%;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n padding: 0;\n position: relative;\n overflow: hidden;\n }\n \n .compact-control-btn svg {\n width: 16px;\n height: 16px;\n }\n \n .compact-control-btn .desktop-mic-off-icon,\n .compact-control-btn .desktop-speaker-off-icon {\n width: 34px;\n height: 34px;\n }\n \n .compact-control-btn.secondary {\n background: #f1f5f9;\n color: #64748b;\n }\n \n \n /* Compact speaker button background color */\n #desktopSpeakerBtnCompact.compact-control-btn.secondary {\n background: ").concat(speakerButtonColor).concat(important, ";\n }\n /* Compact microphone button background color */\n #desktopMuteBtnCompact.compact-control-btn.secondary {\n background: ").concat(micButtonColor).concat(important, ";\n }\n \n .compact-control-btn.secondary:hover {\n background: #e2e8f0;\n color: #475569;\n }\n \n .compact-control-btn.secondary.muted {\n background: rgba(239, 68, 68, 0.1);\n color: #ef4444;\n }\n \n \n .compact-control-btn.secondary.muted .desktop-mic-icon,\n .compact-control-btn.secondary.muted .desktop-speaker-icon {\n stroke: #ef4444;\n }\n \n .compact-control-btn.secondary.muted .desktop-mic-off-icon,\n .compact-control-btn.secondary.muted .desktop-speaker-off-icon {\n width: 34px;\n height: 34px;\n }\n\n .compact-control-btn.danger {\n width: 40px;\n height: 40px;\n min-width: 40px;\n min-height: 40px;\n background: ").concat(endCallBtnColor).concat(important, ";\n color: white;\n box-shadow: 0 3px 10px rgba(239, 68, 68, 0.35);\n }\n \n .compact-control-btn.danger:hover {\n transform: scale(1.05);\n box-shadow: 0 4px 14px rgba(239, 68, 68, 0.45);\n }\n \n .compact-control-btn.danger svg {\n width: 18px;\n height: 18px;\n overflow: visible;\n }\n \n/* ===== CONVERSATION PANEL ===== */\n .desktop-conversation-panel {\n border-top: 1px solid rgba(0, 0, 0, 0.06);\n width: 100%;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n flex: 1;\n }\n \n .conversation-header {\n padding: 10px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: #fafafa;\n cursor: pointer;\n flex-shrink: 0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.04);\n transition: background 0.2s ease;\n }\n \n .conversation-header:hover {\n background: #f5f5f5;\n }\n \n .conversation-label {\n font-size: 11px;\n font-weight: 600;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n \n .conversation-toggle {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: #94a3b8;\n font-weight: 500;\n }\n \n .conversation-toggle svg {\n transition: transform 0.2s ease;\n }\n \n .conversation-header.expanded .conversation-toggle svg {\n transform: rotate(180deg);\n }\n \n /* ===== COLLAPSED: Live Transcript Only (2 lines) ===== */\n .live-transcript-collapsed {\n padding: 12px 16px;\n background: #fafafa;\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex-shrink: 0;\n min-height: 50px;\n }\n \n .live-indicator {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 9px;\n font-weight: 700;\n color: ").concat(liveIndicatorTextColor).concat(important, ";\n text-transform: uppercase;\n letter-spacing: 0.08em;\n }\n \n .live-indicator .live-dot {\ndisplay: block !important;\n height: 5px;\n width: 5px;\n background: ").concat(liveIndicatorDotColor).concat(important, ";\n border-radius: 50%;\n animation: statusPulse 1.5s ease-in-out infinite;\n }\n \n .live-text-collapsed {\n font-size: ").concat(liveTranscriptFontSize).concat(important, ";\n color: ").concat(liveTranscriptTextColor).concat(important, ";\n line-height: 1.5;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n \n .live-text-collapsed.muted {\n color: #94a3b8;\n font-style: italic;\n }\n \n .typing-cursor {\n display: inline-block;\n width: 2px;\n height: 14px;\n background: #a855f7;\n margin-left: 2px;\n animation: blink 1s step-end infinite;\n vertical-align: middle;\n }\n \n @keyframes blink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0; }\n }\n \n /* ===== EXPANDED: Full Conversation History ===== */\n .conversation-history {\n flex: 1;\n flex-direction: column;\n gap: 10px;\n overflow-y: auto;\n padding: 14px 16px;\n min-height: 0;\n }\n .conversation-history.visible {\n display: flex;\n }\n\n .conversation-messages {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n /* Message Rows */\n .message-row {\n display: flex;\n gap: 8px;\n animation: msgIn 0.25s ease;\n }\n \n @keyframes msgIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n @keyframes slideIn {\n from { opacity: 0; transform: translateY(-10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n \n @keyframes slideOut {\n from { opacity: 1; transform: translateY(0); }\n to { opacity: 0; transform: translateY(-10px); }\n }\n \n .message-row.user {\n flex-direction: row-reverse;\n }\n \n .message-avatar {\n width: 28px;\n height: 28px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n\n .message-avatar.assistant {\n background: linear-gradient(135deg, #c084fc, #a855f7);\n }\n\n .message-avatar.assistant .orb {\n width: 12px;\n height: 12px;\n background: rgba(255, 255, 255, 0.9);\n border-radius: 50%;\n }\n\n .message-avatar.user {\n background: linear-gradient(135deg, #64748b, #475569);\n color: #fff;\n font-size: 11px;\n font-weight: 600;\n }\n\n .message-bubble {\n max-width: 80%;\n padding: 9px 13px;\n border-radius: 12px;\n font-size: 13px;\n line-height: 1.5;\n }\n \n .message-row.assistant .message-bubble {\n background: #fff;\n color: ").concat(liveTranscriptTextColor).concat(important, ";\n border: 1px solid rgba(0, 0, 0, 0.06);\n border-bottom-left-radius: 4px;\n }\n \n .message-row.user .message-bubble {\n background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);\n color: #fff;\n border-bottom-right-radius: 4px;\n }\n \n /* Live message at bottom of history */\n .live-message-row {\n display: flex;\n gap: 8px;\n padding-top: 8px;\n border-top: 1px dashed rgba(0, 0, 0, 0.08);\n margin-top: auto;\n }\n \n .live-message-row .message-bubble {\n background: #fff;\n border: 1px solid rgba(16, 185, 129, 0.3);\n color: ").concat(liveTranscriptTextColor).concat(important, ";\n position: relative;\n border-radius: 14px;\n border-bottom-left-radius: 4px;\n }\n \n .live-message-row .live-badge {\ndisplay: block !important;\n position: absolute;\n top: -8px;\n left: 10px;\n background: #10b981;\n color: #fff;\n font-size: 8px;\n font-weight: 700;\n padding: 2px 6px;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n \n /* Hide/show based on expanded state */\n .desktop-conversation-panel.collapsed .conversation-history {\n display: none;\n }\n \n .desktop-conversation-panel.collapsed .live-transcript-collapsed {\n display: flex;\n }\n \n .desktop-conversation-panel.expanded .conversation-history {\n display: flex;\n max-height: 400px;\n }\n \n .desktop-conversation-panel.expanded .live-transcript-collapsed {\n display: none;\n }\n \n /* ===== DARK MODE SUPPORT ===== */\n @media (prefers-color-scheme: dark) {\n .desktop-voice-section {\n background: linear-gradient(180deg, #1e1e2e 0%, rgba(168, 85, 247, 0.08) 100%);\n }\n\n .desktop-timer {\n color: #94a3b8;\n }\n\n .desktop-status {\n color: #34d399;\n }\n\n .desktop-status .status-dot {\n \n .desktop-control-btn.secondary.muted {\n background: rgba(255, 255, 255, 0.1);\n color: #9ca3af;\n \n .compact-voice-section {\n background: linear-gradient(180deg, #1e1e2e 0%, rgba(168, 85, 247, 0.08) 100%);\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n }\n \n .compact-timer {\n color: #e2e8f0;\n }\n \n .compact-status {\n color: #34d399;\n }\n \n .compact-status .status-dot {\n background: #34d399;\n }\n \n .compact-control-btn.secondary {\n background: rgba(255, 255, 255, 0.08);\n color: #94a3b8;\n }\n \n .compact-control-btn.secondary:hover {\n background: rgba(255, 255, 255, 0.15);\n color: #e2e8f0;\n }\n \n .compact-control-btn.secondary.muted {\n background: rgba(239, 68, 68, 0.2);\n color: #f87171;\n }\n\n }\n \n .desktop-control-btn.secondary.muted svg {\n \n .desktop-control-btn.secondary {\n position: relative;\n }\n \n /* Desktop microphone button background color */\n #desktopMuteBtn.desktop-control-btn.secondary,\n #desktopMuteBtnCompact.compact-control-btn.secondary {\n background: ").concat(micButtonColor).concat(important, ";\n }\n \n .desktop-mic-off-icon,\n .desktop-speaker-off-icon {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 20px;\n height: 20px;\n }\n \n .desktop-control-btn.secondary.muted {\n background: #f3f4f6;\n color: #9ca3af;\n }\n \n .desktop-control-btn.secondary.muted svg {\n \n .desktop-control-btn.secondary {\n position: relative;\n }\n \n /* Desktop microphone button background color */\n #desktopMuteBtn.desktop-control-btn.secondary,\n #desktopMuteBtnCompact.compact-control-btn.secondary {\n background: ").concat(micButtonColor).concat(important, ";\n }\n \n .desktop-mic-off-icon,\n .desktop-speaker-off-icon {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 20px;\n height: 20px;\n }\n stroke: #9ca3af;\n }\n stroke: #9ca3af;\n }\n background: #34d399;\n }\n\n .desktop-control-btn.secondary {\n background: rgba(255, 255, 255, 0.08);\n color: #94a3b8;\n }\n\n .desktop-control-btn.secondary:hover {\n background: rgba(255, 255, 255, 0.15);\n color: #e2e8f0;\n }\n\n .desktop-conversation-panel {\n border-top: 1px solid rgba(255, 255, 255, 0.08);\n }\n\n .conversation-header {\n background: #1a1a2e;\n }\n\n .conversation-header:hover {\n background: #252540;\n }\n\n .conversation-label {\n color: #94a3b8;\n }\n\n .conversation-toggle {\n color: #64748b;\n }\n\n .live-transcript-preview {\n background: #1a1a2e;\n }\n .live-indicator {\n color: ").concat(liveIndicatorTextColor).concat(important, ";\n }\n .live-indicator .live-dot {\n background: ").concat(liveIndicatorDotColor).concat(important, ";\n }\n\n .live-text {\n color: #e2e8f0;\n }\n\n .live-text.muted {\n color: #64748b;\n }\n\n .conversation-history {\n background: #1a1a2e;\n }\n\n .conversation-msg.assistant .conversation-msg-bubble {\n background: #252540;\n color: #e2e8f0;\n border: 1px solid rgba(255, 255, 255, 0.08);\n }\n\n .voice-text-input-area {\n background: #1a1a2e;\n }\n\n .voice-text-input {\n background: #252540 !important;\n color: #e2e8f0 !important;\n border-color: rgba(255, 255, 255, 0.1) !important;\n }\n\n .voice-text-input::placeholder {\n color: #64748b !important;\n }\n\n .voice-text-input:focus {\n border-color: ").concat(avatarBg, " !important;\n box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.2) !important;\n }\n\n .voice-input-hint {\n color: #64748b !important;\n }\n\n .voice-send-btn {\n background: ").concat(voiceSendButtonColor, " !important;\n }\n\n .voice-send-btn:disabled {\n background: #374151 !important;\n color: #4b5563 !important;\n }\n }\n\n /* Mobile optimization */\n @media (max-width: 768px) {\n .voice-interface {\n padding: 6px 10px;\n }\n }\n \n @media (max-width: 480px) {\n .voice-interface {\n padding: 5px 8px;\n }\n }\n \n /* Mobile Voice Call UI - Shared styles (also used in generateMobileCSS) */\n ").concat(this._getSharedMobileCSS(important), "\n\n ");
|
|
27234
27348
|
}
|
|
27235
27349
|
|
|
27236
27350
|
/**
|
|
@@ -27240,7 +27354,7 @@ var Styles = /*#__PURE__*/function () {
|
|
|
27240
27354
|
}, {
|
|
27241
27355
|
key: "_getSharedMobileCSS",
|
|
27242
27356
|
value: function _getSharedMobileCSS(important) {
|
|
27243
|
-
return "\n .mobile-duration-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background-color: #ef4444;\n animation: mobilePulse 1.5s ease-in-out infinite;\n }\n\n @keyframes mobilePulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.95); }\n }\n\n .mobile-voice-bar {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 14px;\n background: linear-gradient(135deg, #7c3aed 0%, #a855f7 50%, #c084fc 100%);\n border-radius: 24px 24px 0 0;\n box-shadow: 0 -8px 32px rgba(124, 58, 237, 0.5), 0 -2px 8px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.2);\n width: 100%;\n max-width: 100%;\n pointer-events: auto;\n }\n\n .mobile-top-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n position: relative;\n }\n\n .mobile-status-indicator {\n display: flex;\n align-items: center;\n gap: 5px;\n min-width: 85px;\n }\n\n .mobile-status-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background-color: #22c55e;\n box-shadow: 0 0 8px #22c55e;\n transition: all 0.3s ease;\n }\n\n .mobile-status-text {\n font-size: 11px;\n font-weight: 700;\n color: rgba(255,255,255,0.95);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n }\n\n .mobile-waveform-center {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 3px;\n height: 24px;\n }\n\n .mobile-waveform-bar {\n width: 4px;\n height: 4px;\n background-color: #fff;\n border-radius: 2px;\n transition: height 0.15s ease;\n box-shadow: 0 0 8px rgba(255,255,255,0.5);\n }\n\n .mobile-controls {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .mobile-control-btn {\n display: flex".concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n width: 32px").concat(important, ";\n height: 32px").concat(important, ";\n min-width: 32px").concat(important, ";\n min-height: 32px").concat(important, ";\n max-width: 32px").concat(important, ";\n max-height: 32px").concat(important, ";\n border-radius: 50%").concat(important, ";\n border: none").concat(important, ";\n cursor: pointer").concat(important, ";\n transition: all 0.2s ease;\n background-color: rgba(255,255,255,0.15)").concat(important, ";\n position: relative").concat(important, ";\n overflow: hidden").concat(important, ";\n padding: 0").concat(important, ";\n margin: 0").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n\n .mobile-control-btn:hover {\n background-color: rgba(255,255,255,0.25)").concat(important, ";\n }\n\n .mobile-control-btn.muted {\n background-color: rgba(239, 68, 68, 0.3)").concat(important, ";\n }\n\n .mobile-control-btn svg {\n position: absolute").concat(important, ";\n top: 50%").concat(important, ";\n left: 50%").concat(important, ";\n transform: translate(-50%, -50%)").concat(important, ";\n display: block").concat(important, ";\n visibility: visible").concat(important, ";\n opacity: 1").concat(important, ";\n width: 15px").concat(important, ";\n height: 15px").concat(important, ";\n margin: 0").concat(important, ";\n padding: 0").concat(important, ";\n }\n\n .mobile-mic-off-icon,\n .mobile-speaker-off-icon {\n display: none !important;\n }\n\n .mobile-control-btn.muted .mobile-mic-icon,\n .mobile-control-btn.muted .mobile-speaker-icon {\n display: none !important;\n }\n\n .mobile-control-btn.muted .mobile-mic-off-icon,\n .mobile-control-btn.muted .mobile-speaker-off-icon {\n display: block !important;\n }\n\n .mobile-end-call-btn {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n width: 36px").concat(important, ";\n height: 36px").concat(important, ";\n min-width: 36px").concat(important, ";\n min-height: 36px").concat(important, ";\n max-width: 36px").concat(important, ";\n max-height: 36px").concat(important, ";\n border-radius: 50%").concat(important, ";\n border: none").concat(important, ";\n cursor: pointer").concat(important, ";\n background-color: #ef4444").concat(important, ";\n box-shadow: 0 4px 14px rgba(239, 68, 68, 0.5);\n transition: all 0.2s ease;\n overflow: hidden").concat(important, ";\n padding: 0").concat(important, ";\n margin: 0").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n\n .mobile-end-call-btn svg {\n display: block").concat(important, ";\n visibility: visible").concat(important, ";\n opacity: 1").concat(important, ";\n width: 15px").concat(important, ";\n height: 15px").concat(important, ";\n margin: 0").concat(important, ";\n padding: 0").concat(important, ";\n position: relative").concat(important, ";\n }\n\n /* ID-specific selectors for WordPress compatibility */\n #mobileMuteBtn.mobile-control-btn,\n #mobileSpeakerBtn.mobile-control-btn,\n #mobileEndCallBtn.mobile-end-call-btn {\n border-radius: 50% !important;\n overflow: hidden !important;\n }\n\n #mobileMuteBtn.mobile-control-btn,\n #mobileSpeakerBtn.mobile-control-btn {\n width: 32px !important;\n height: 32px !important;\n min-width: 32px !important;\n min-height: 32px !important;\n max-width: 32px !important;\n max-height: 32px !important;\n }\n\n #mobileEndCallBtn.mobile-end-call-btn {\n width: 36px !important;\n height: 36px !important;\n min-width: 36px !important;\n min-height: 36px !important;\n max-width: 36px !important;\n max-height: 36px !important;\n }\n\n #mobileMuteBtn.mobile-control-btn svg,\n #mobileSpeakerBtn.mobile-control-btn svg,\n #mobileEndCallBtn.mobile-end-call-btn svg {\n display: block !important;\n visibility: visible !important;\n opacity: 1 !important;\n width: 15px !important;\n height: 15px !important;\n margin: 0 !important;\n padding: 0 !important;\n }\n\n .mobile-end-call-btn:hover {\n transform: scale(1.05);\n }\n\n .mobile-transcript-row {\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 12px;\n background: rgba(255,255,255,0.18);\n border-radius: 14px;\n border: none;\n cursor: pointer;\n text-align: left;\n backdrop-filter: blur(4px);\n transition: background 0.2s ease;\n }\n\n .mobile-transcript-row:hover {\n background: rgba(255,255,255,0.25);\n }\n\n .mobile-transcript-text {\n margin: 0;\n font-size: 13px;\n color: #fff;\n line-height: 1.4;\n font-weight: 500;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .mobile-transcript-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .mobile-expand-hint {\n font-size: 10px;\n color: rgba(255,255,255,0.6);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n font-weight: 600;\n }\n\n .mobile-transcript-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0,0,0,0.6);\n display: flex;\n align-items: flex-end;\n padding: 12px;\n z-index: 100000;\n pointer-events: auto;\n }\n\n .mobile-expanded-transcript {\n width: 100%;\n max-height: 75%;\n background: #fff;\n border-radius: 24px 24px 16px 16px;\n overflow: hidden;\n box-shadow: 0 -8px 40px rgba(0,0,0,0.3);\n display: flex;\n flex-direction: column;\n }\n\n .mobile-transcript-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 14px 16px;\n background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);\n flex-shrink: 0;\n }\n\n .mobile-header-left {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .mobile-header-status {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .mobile-header-status-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background-color: #22c55e;\n box-shadow: 0 0 6px #22c55e;\n }\n\n .mobile-header-status-text {\n font-size: 10px;\n font-weight: 700;\n color: rgba(255,255,255,0.9);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .mobile-header-duration {\n font-size: 10px;\n font-weight: 600;\n color: rgba(255,255,255,0.7);\n margin-left: 8px;\n }\n\n .mobile-transcript-label {\n font-size: 11px;\n font-weight: 800;\n color: rgba(255,255,255,0.7);\n letter-spacing: 1px;\n }\n\n .mobile-close-transcript-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n border: none;\n background: rgba(255,255,255,0.2);\n color: #fff;\n cursor: pointer;\n }\n\n .mobile-close-transcript-btn:hover {\n background: rgba(255,255,255,0.3);\n }\n\n .mobile-messages-container {\n flex: 1;\n padding: 16px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .mobile-message-bubble {\n max-width: 85%;\n padding: 12px 16px;\n border-radius: 18px;\n font-size: 14px;\n line-height: 1.5;\n word-wrap: break-word;\n }\n\n .mobile-message-bubble.assistant {\n align-self: flex-start;\n background-color: #f3f4f6;\n color: #374151;\n border-bottom-left-radius: 4px;\n }\n\n .mobile-message-bubble.user {\n align-self: flex-end;\n background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);\n color: #fff;\n border-bottom-right-radius: 4px;\n }\n\n .mobile-input-area {\n padding: 12px 16px 16px;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n flex-shrink: 0;\n }\n\n .mobile-input-wrapper {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 4px 4px 16px;\n background: #fff;\n border-radius: 24px;\n border: 2px solid #e5e7eb;\n }\n\n .mobile-text-input {\n flex: 1;\n border: none;\n outline: none;\n font-size: 14px;\n color: #374151;\n background: transparent;\n padding: 10px 0;\n }\n\n .mobile-text-input::placeholder {\n color: #9ca3af;\n }\n\n .mobile-send-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);\n color: #fff;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .mobile-send-btn:hover:not(:disabled) {\n transform: scale(1.05);\n }\n\n .mobile-send-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .mobile-input-hint {\n margin: 8px 0 0;\n font-size: 11px;\n color: #9ca3af;\n text-align: center;\n transition: color 0.2s ease;\n }\n\n /* Mobile text input status states */\n .mobile-input-hint--sending {\n color: #666;\n }\n\n .mobile-input-hint--success {\n color: #28a745;\n }\n\n .mobile-input-hint--queued {\n color: #ffc107;\n }\n\n .mobile-input-hint--error {\n color: #dc3545;\n }\n\n /* Disabled mobile input styling */\n #mobileTextInput:disabled {\n background-color: #f5f5f5;\n cursor: not-allowed;\n }\n\n #mobileSendBtn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n ");
|
|
27357
|
+
return "\n .mobile-duration-dot {\ndisplay: block !important;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background-color: #ef4444;\n animation: mobilePulse 1.5s ease-in-out infinite;\n }\n\n @keyframes mobilePulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.95); }\n }\n\n .mobile-voice-bar {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 14px;\n background: linear-gradient(135deg, #7c3aed 0%, #a855f7 50%, #c084fc 100%);\n border-radius: 24px 24px 0 0;\n box-shadow: 0 -8px 32px rgba(124, 58, 237, 0.5), 0 -2px 8px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.2);\n width: 100%;\n max-width: 100%;\n pointer-events: auto;\n }\n\n .mobile-top-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n position: relative;\n }\n\n .mobile-status-indicator {\n display: flex;\n align-items: center;\n gap: 5px;\n min-width: 85px;\n }\n\n .mobile-status-dot {\ndisplay: block !important;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background-color: #22c55e;\n box-shadow: 0 0 8px #22c55e;\n transition: all 0.3s ease;\n }\n\n .mobile-status-text {\n font-size: 11px;\n font-weight: 700;\n color: rgba(255,255,255,0.95);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n }\n\n .mobile-waveform-center {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 3px;\n height: 24px;\n }\n\n .mobile-waveform-bar {\ndisplay: block !important;\n width: 4px;\n height: 4px;\n background-color: #fff;\n border-radius: 2px;\n transition: height 0.15s ease;\n box-shadow: 0 0 8px rgba(255,255,255,0.5);\n }\n\n .mobile-controls {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .mobile-control-btn {\n display: flex".concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n width: 32px").concat(important, ";\n height: 32px").concat(important, ";\n min-width: 32px").concat(important, ";\n min-height: 32px").concat(important, ";\n max-width: 32px").concat(important, ";\n max-height: 32px").concat(important, ";\n border-radius: 50%").concat(important, ";\n border: none").concat(important, ";\n cursor: pointer").concat(important, ";\n transition: all 0.2s ease;\n background-color: rgba(255,255,255,0.15)").concat(important, ";\n position: relative").concat(important, ";\n overflow: hidden").concat(important, ";\n padding: 0").concat(important, ";\n margin: 0").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n\n .mobile-control-btn:hover {\n background-color: rgba(255,255,255,0.25)").concat(important, ";\n }\n\n .mobile-control-btn.muted {\n background-color: rgba(239, 68, 68, 0.3)").concat(important, ";\n }\n\n .mobile-control-btn svg {\n position: absolute").concat(important, ";\n top: 50%").concat(important, ";\n left: 50%").concat(important, ";\n transform: translate(-50%, -50%)").concat(important, ";\n display: block").concat(important, ";\n visibility: visible").concat(important, ";\n opacity: 1").concat(important, ";\n width: 15px").concat(important, ";\n height: 15px").concat(important, ";\n margin: 0").concat(important, ";\n padding: 0").concat(important, ";\n }\n\n .mobile-mic-off-icon,\n .mobile-speaker-off-icon {\n display: none !important;\n }\n\n .mobile-control-btn.muted .mobile-mic-icon,\n .mobile-control-btn.muted .mobile-speaker-icon {\n display: none !important;\n }\n\n .mobile-control-btn.muted .mobile-mic-off-icon,\n .mobile-control-btn.muted .mobile-speaker-off-icon {\n display: block !important;\n }\n\n .mobile-end-call-btn {\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n width: 36px").concat(important, ";\n height: 36px").concat(important, ";\n min-width: 36px").concat(important, ";\n min-height: 36px").concat(important, ";\n max-width: 36px").concat(important, ";\n max-height: 36px").concat(important, ";\n border-radius: 50%").concat(important, ";\n border: none").concat(important, ";\n cursor: pointer").concat(important, ";\n background-color: #ef4444").concat(important, ";\n box-shadow: 0 4px 14px rgba(239, 68, 68, 0.5);\n transition: all 0.2s ease;\n overflow: hidden").concat(important, ";\n padding: 0").concat(important, ";\n margin: 0").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n\n .mobile-end-call-btn svg {\n display: block").concat(important, ";\n visibility: visible").concat(important, ";\n opacity: 1").concat(important, ";\n width: 15px").concat(important, ";\n height: 15px").concat(important, ";\n margin: 0").concat(important, ";\n padding: 0").concat(important, ";\n position: relative").concat(important, ";\n }\n\n /* ID-specific selectors for WordPress compatibility */\n #mobileMuteBtn.mobile-control-btn,\n #mobileSpeakerBtn.mobile-control-btn,\n #mobileEndCallBtn.mobile-end-call-btn {\n border-radius: 50% !important;\n overflow: hidden !important;\n }\n\n #mobileMuteBtn.mobile-control-btn,\n #mobileSpeakerBtn.mobile-control-btn {\n width: 32px !important;\n height: 32px !important;\n min-width: 32px !important;\n min-height: 32px !important;\n max-width: 32px !important;\n max-height: 32px !important;\n }\n\n #mobileEndCallBtn.mobile-end-call-btn {\n width: 36px !important;\n height: 36px !important;\n min-width: 36px !important;\n min-height: 36px !important;\n max-width: 36px !important;\n max-height: 36px !important;\n }\n\n #mobileMuteBtn.mobile-control-btn svg,\n #mobileSpeakerBtn.mobile-control-btn svg,\n #mobileEndCallBtn.mobile-end-call-btn svg {\n display: block !important;\n visibility: visible !important;\n opacity: 1 !important;\n width: 15px !important;\n height: 15px !important;\n margin: 0 !important;\n padding: 0 !important;\n }\n\n .mobile-end-call-btn:hover {\n transform: scale(1.05);\n }\n\n .mobile-transcript-row {\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 12px;\n background: rgba(255,255,255,0.18);\n border-radius: 14px;\n border: none;\n cursor: pointer;\n text-align: left;\n backdrop-filter: blur(4px);\n transition: background 0.2s ease;\n }\n\n .mobile-transcript-row:hover {\n background: rgba(255,255,255,0.25);\n }\n\n .mobile-transcript-text {\n margin: 0;\n font-size: 13px;\n color: #fff;\n line-height: 1.4;\n font-weight: 500;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .mobile-transcript-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .mobile-expand-hint {\n font-size: 10px;\n color: rgba(255,255,255,0.6);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n font-weight: 600;\n }\n\n .mobile-transcript-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0,0,0,0.6);\n display: flex;\n align-items: flex-end;\n padding: 12px;\n z-index: 100000;\n pointer-events: auto;\n }\n\n .mobile-expanded-transcript {\n width: 100%;\n max-height: 75%;\n background: #fff;\n border-radius: 24px 24px 16px 16px;\n overflow: hidden;\n box-shadow: 0 -8px 40px rgba(0,0,0,0.3);\n display: flex;\n flex-direction: column;\n }\n\n .mobile-transcript-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 14px 16px;\n background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);\n flex-shrink: 0;\n }\n\n .mobile-header-left {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .mobile-header-status {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .mobile-header-status-dot {\ndisplay: block !important;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background-color: #22c55e;\n box-shadow: 0 0 6px #22c55e;\n }\n\n .mobile-header-status-text {\n font-size: 10px;\n font-weight: 700;\n color: rgba(255,255,255,0.9);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .mobile-header-duration {\n font-size: 10px;\n font-weight: 600;\n color: rgba(255,255,255,0.7);\n margin-left: 8px;\n }\n\n .mobile-transcript-label {\n font-size: 11px;\n font-weight: 800;\n color: rgba(255,255,255,0.7);\n letter-spacing: 1px;\n }\n\n .mobile-close-transcript-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n border: none;\n background: rgba(255,255,255,0.2);\n color: #fff;\n cursor: pointer;\n }\n\n .mobile-close-transcript-btn:hover {\n background: rgba(255,255,255,0.3);\n }\n\n .mobile-messages-container {\n flex: 1;\n padding: 16px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .mobile-message-bubble {\n max-width: 85%;\n padding: 12px 16px;\n border-radius: 18px;\n font-size: 14px;\n line-height: 1.5;\n word-wrap: break-word;\n }\n\n .mobile-message-bubble.assistant {\n align-self: flex-start;\n background-color: #f3f4f6;\n color: #374151;\n border-bottom-left-radius: 4px;\n }\n\n .mobile-message-bubble.user {\n align-self: flex-end;\n background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);\n color: #fff;\n border-bottom-right-radius: 4px;\n }\n\n .mobile-input-area {\n padding: 12px 16px 16px;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n flex-shrink: 0;\n }\n\n .mobile-input-wrapper {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 4px 4px 16px;\n background: #fff;\n border-radius: 24px;\n border: 2px solid #e5e7eb;\n }\n\n .mobile-text-input {\n flex: 1;\n border: none;\n outline: none;\n font-size: 14px;\n color: #374151;\n background: transparent;\n padding: 10px 0;\n }\n\n .mobile-text-input::placeholder {\n color: #9ca3af;\n }\n\n .mobile-send-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);\n color: #fff;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .mobile-send-btn:hover:not(:disabled) {\n transform: scale(1.05);\n }\n\n .mobile-send-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .mobile-input-hint {\n margin: 8px 0 0;\n font-size: 11px;\n color: #9ca3af;\n text-align: center;\n transition: color 0.2s ease;\n }\n\n /* Mobile text input status states */\n .mobile-input-hint--sending {\n color: #666;\n }\n\n .mobile-input-hint--success {\n color: #28a745;\n }\n\n .mobile-input-hint--queued {\n color: #ffc107;\n }\n\n .mobile-input-hint--error {\n color: #dc3545;\n }\n\n /* Disabled mobile input styling */\n #mobileTextInput:disabled {\n background-color: #f5f5f5;\n cursor: not-allowed;\n }\n\n #mobileSendBtn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n ");
|
|
27244
27358
|
}
|
|
27245
27359
|
|
|
27246
27360
|
/**
|