@tradecanvas/chart 1.26.0 → 1.27.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/dist/Chart.d.ts +6 -0
- package/dist/Chart.d.ts.map +1 -1
- package/dist/{LayoutSession-BE7ZZGLi.js → LayoutSession-CUS33zmB.js} +9 -3
- package/dist/LayoutSession-CUS33zmB.js.map +1 -0
- package/dist/LayoutSession-CYdvbLA3.cjs +2 -0
- package/dist/LayoutSession-CYdvbLA3.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/widget/ChartWidget.d.ts +26 -2
- package/dist/widget/ChartWidget.d.ts.map +1 -1
- package/dist/widget/WidgetCommandPalette.d.ts.map +1 -1
- package/dist/widget/WidgetDrawingSidebar.d.ts.map +1 -1
- package/dist/widget/WidgetHotkeySheet.d.ts.map +1 -1
- package/dist/widget/WidgetReplayBar.d.ts.map +1 -1
- package/dist/widget/WidgetSymbolSearch.d.ts.map +1 -1
- package/dist/widget/WidgetWatchlist.d.ts.map +1 -1
- package/dist/widget/footerHints.d.ts +7 -0
- package/dist/widget/footerHints.d.ts.map +1 -0
- package/dist/widget/iconSet.d.ts +1 -25
- package/dist/widget/iconSet.d.ts.map +1 -1
- package/dist/widget/index.cjs +37 -17
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.js +666 -1136
- package/dist/widget/index.js.map +1 -1
- package/dist/widget/widgetFeatures.d.ts +2 -2
- package/dist/widget/widgetFeatures.d.ts.map +1 -1
- package/dist/widget/widgetTimeframes.d.ts +28 -0
- package/dist/widget/widgetTimeframes.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/LayoutSession-BE7ZZGLi.js.map +0 -1
- package/dist/LayoutSession-BnRz0zSL.cjs +0 -2
- package/dist/LayoutSession-BnRz0zSL.cjs.map +0 -1
package/dist/widget/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { C as e, a as t, c as n, i as r, n as i, o as a, r as o, t as s } from "../LayoutSession-
|
|
1
|
+
import { C as e, a as t, c as n, i as r, n as i, o as a, r as o, t as s } from "../LayoutSession-CUS33zmB.js";
|
|
2
2
|
import { a as c, c as l, i as u, n as d, o as f, r as p, s as m, t as h } from "../i18n-FG3D2x5m.js";
|
|
3
|
-
import { CHART_STYLE_KEYS as g,
|
|
4
|
-
import { ChartStateManager as
|
|
3
|
+
import { CHART_STYLE_KEYS as g, CHART_TYPE_ICONS as _, DARK_THEME as v, DEFAULT_SIGNAL_STYLE as y, DEFAULT_TRADE_ZONE_STYLE as b, DEFAULT_TRADING_CONFIG as x, DRAWING_TOOL_ICONS as ee, LIGHT_THEME as te, PRICE_SOURCES as ne, UI_ICONS as re, barTimeUnit as S, formatPrice as ie, iconSvg as ae, indicatorSource as oe, isTimeFrame as se, isValidTimeZone as ce, marketStatus as le, offsetAt as ue, parseIndicatorSource as de, readChartTypeOptions as fe, readNews as pe, readQuote as me, sanitizeDrawingOptions as he, sanitizeDrawingStyle as ge, tickBarCount as C, timeParts as _e, timeframeBucketStart as ve, timeframeToMs as w, tzLabel as ye, wallToUtc as be, zoneOffsetMinutes as xe } from "@tradecanvas/commons";
|
|
4
|
+
import { ChartStateManager as Se, MAX_ALERT_BARS as Ce, MIN_ALERT_BARS as we, RANGE_PRESETS as Te, indicatorValuePrecision as Ee, plotColor as De, plotShown as Oe, rangePresetStart as ke, servesTimeframe as Ae, sourceParam as je, withResampling as Me } from "@tradecanvas/core";
|
|
5
5
|
//#region src/io/resampleOHLCV.ts
|
|
6
|
-
function
|
|
6
|
+
function Ne(e, t, n = {}) {
|
|
7
7
|
if (e.length === 0) return [];
|
|
8
8
|
let r = n.weekStartsOn ?? 1, i = [], a = null, o = NaN;
|
|
9
9
|
for (let n of e) {
|
|
10
|
-
let e =
|
|
10
|
+
let e = ve(n.time, t, r);
|
|
11
11
|
a === null || e !== o ? (a !== null && i.push(a), a = {
|
|
12
12
|
time: e,
|
|
13
13
|
open: n.open,
|
|
@@ -26,7 +26,7 @@ function Oe(e, t, n = {}) {
|
|
|
26
26
|
}
|
|
27
27
|
return a !== null && i.push(a), i;
|
|
28
28
|
}
|
|
29
|
-
function
|
|
29
|
+
function Pe(e) {
|
|
30
30
|
if (e.length < 2) return 0;
|
|
31
31
|
let t = [];
|
|
32
32
|
for (let n = 1; n < e.length; n++) {
|
|
@@ -37,7 +37,7 @@ function ke(e) {
|
|
|
37
37
|
}
|
|
38
38
|
//#endregion
|
|
39
39
|
//#region src/widget/widgetTimezones.ts
|
|
40
|
-
var
|
|
40
|
+
var Fe = [
|
|
41
41
|
{
|
|
42
42
|
zone: "Pacific/Honolulu",
|
|
43
43
|
city: "Honolulu"
|
|
@@ -151,36 +151,36 @@ var Ae = [
|
|
|
151
151
|
city: "Auckland"
|
|
152
152
|
}
|
|
153
153
|
];
|
|
154
|
-
function
|
|
155
|
-
return !e || e === "local" ? null : e === "exchange" ? "exchange" : /^-?\d+$/.test(e) ? Number(e) :
|
|
154
|
+
function Ie(e) {
|
|
155
|
+
return !e || e === "local" ? null : e === "exchange" ? "exchange" : /^-?\d+$/.test(e) ? Number(e) : ce(e) ? e : null;
|
|
156
156
|
}
|
|
157
|
-
function
|
|
157
|
+
function Le(e) {
|
|
158
158
|
return e === null ? "local" : String(e);
|
|
159
159
|
}
|
|
160
|
-
function
|
|
161
|
-
let i =
|
|
162
|
-
let r =
|
|
160
|
+
function Re(e, t, n, r) {
|
|
161
|
+
let i = ue(null, t), a = Fe.filter(({ zone: e }) => ce(e)).map(({ zone: e, city: n }) => {
|
|
162
|
+
let r = ue(e, t);
|
|
163
163
|
return {
|
|
164
164
|
value: e,
|
|
165
|
-
label: e === "UTC" ? "UTC" : `(${
|
|
165
|
+
label: e === "UTC" ? "UTC" : `(${ye(r)}) ${n}`,
|
|
166
166
|
offset: r
|
|
167
167
|
};
|
|
168
|
-
}), o =
|
|
168
|
+
}), o = Ie(e);
|
|
169
169
|
typeof o == "number" && a.push({
|
|
170
170
|
value: e,
|
|
171
|
-
label:
|
|
171
|
+
label: ye(o),
|
|
172
172
|
offset: o
|
|
173
173
|
}), a.sort((e, t) => e.offset - t.offset);
|
|
174
174
|
let s = [{
|
|
175
175
|
value: "local",
|
|
176
|
-
label: `${n} (${
|
|
176
|
+
label: `${n} (${ye(i)})`,
|
|
177
177
|
offset: i
|
|
178
178
|
}];
|
|
179
179
|
if (r) {
|
|
180
|
-
let e =
|
|
180
|
+
let e = ue(r.zone && ce(r.zone) ? r.zone : "UTC", t);
|
|
181
181
|
s.push({
|
|
182
182
|
value: "exchange",
|
|
183
|
-
label: `${r.label} (${
|
|
183
|
+
label: `${r.label} (${ye(e)})`,
|
|
184
184
|
offset: e
|
|
185
185
|
});
|
|
186
186
|
}
|
|
@@ -188,7 +188,7 @@ function Ne(e, t, n, r) {
|
|
|
188
188
|
}
|
|
189
189
|
//#endregion
|
|
190
190
|
//#region src/widget/widgetConfig.ts
|
|
191
|
-
var
|
|
191
|
+
var ze = [
|
|
192
192
|
{
|
|
193
193
|
label: "Candlestick",
|
|
194
194
|
value: "candlestick"
|
|
@@ -261,7 +261,7 @@ var Pe = [
|
|
|
261
261
|
label: "Range Bars",
|
|
262
262
|
value: "rangeBars"
|
|
263
263
|
}
|
|
264
|
-
],
|
|
264
|
+
], Be = [
|
|
265
265
|
{
|
|
266
266
|
label: "Lines",
|
|
267
267
|
section: "lines",
|
|
@@ -613,7 +613,7 @@ var Pe = [
|
|
|
613
613
|
}
|
|
614
614
|
]
|
|
615
615
|
}
|
|
616
|
-
],
|
|
616
|
+
], Ve = [
|
|
617
617
|
{
|
|
618
618
|
id: "sma",
|
|
619
619
|
name: "SMA",
|
|
@@ -1284,7 +1284,7 @@ var Pe = [
|
|
|
1284
1284
|
name: "Candlestick Patterns",
|
|
1285
1285
|
type: "overlay"
|
|
1286
1286
|
}
|
|
1287
|
-
],
|
|
1287
|
+
], He = [
|
|
1288
1288
|
"sma",
|
|
1289
1289
|
"ema",
|
|
1290
1290
|
"bb",
|
|
@@ -1295,12 +1295,12 @@ var Pe = [
|
|
|
1295
1295
|
"atr",
|
|
1296
1296
|
"obv",
|
|
1297
1297
|
"ichimoku"
|
|
1298
|
-
],
|
|
1298
|
+
], Ue = [
|
|
1299
1299
|
"BTCUSDT",
|
|
1300
1300
|
"ETHUSDT",
|
|
1301
1301
|
"SOLUSDT",
|
|
1302
1302
|
"BNBUSDT"
|
|
1303
|
-
],
|
|
1303
|
+
], We = {
|
|
1304
1304
|
gridVisible: !0,
|
|
1305
1305
|
volumeVisible: !0,
|
|
1306
1306
|
volumeProfileVisible: !1,
|
|
@@ -1339,7 +1339,7 @@ var Pe = [
|
|
|
1339
1339
|
label: e,
|
|
1340
1340
|
keys: [t],
|
|
1341
1341
|
auto: n
|
|
1342
|
-
}), D = (e) => ({ hint: e }),
|
|
1342
|
+
}), D = (e) => ({ hint: e }), Ge = { from: "panes.titleColor" }, Ke = [
|
|
1343
1343
|
{
|
|
1344
1344
|
title: "settings.section.background",
|
|
1345
1345
|
rows: [
|
|
@@ -1349,7 +1349,7 @@ var Pe = [
|
|
|
1349
1349
|
T("settings.paneTitles", "panes.titleColor"),
|
|
1350
1350
|
T("settings.legendText", "legend.textColor"),
|
|
1351
1351
|
T("settings.legendLabels", "legend.labelColor"),
|
|
1352
|
-
E("settings.watermark", "watermark.color",
|
|
1352
|
+
E("settings.watermark", "watermark.color", Ge)
|
|
1353
1353
|
]
|
|
1354
1354
|
},
|
|
1355
1355
|
{
|
|
@@ -1402,41 +1402,41 @@ var Pe = [
|
|
|
1402
1402
|
},
|
|
1403
1403
|
{
|
|
1404
1404
|
title: "settings.highLowLines",
|
|
1405
|
-
rows: [E("drawingSettings.color", "highLow.color",
|
|
1405
|
+
rows: [E("drawingSettings.color", "highLow.color", Ge)]
|
|
1406
1406
|
},
|
|
1407
1407
|
{
|
|
1408
1408
|
title: "objects.drawings",
|
|
1409
1409
|
rows: [E("settings.handles", "drawings.handleColor", D("#ffffff"))]
|
|
1410
1410
|
}
|
|
1411
|
-
],
|
|
1411
|
+
], qe = [
|
|
1412
1412
|
{
|
|
1413
1413
|
title: "settings.section.orders",
|
|
1414
1414
|
trading: !0,
|
|
1415
1415
|
rows: [
|
|
1416
|
-
E("ticket.buy", "trading.buyColor", D(
|
|
1417
|
-
E("ticket.sell", "trading.sellColor", D(
|
|
1418
|
-
E("settings.profit", "trading.profitColor", D(
|
|
1419
|
-
E("settings.loss", "trading.lossColor", D(
|
|
1420
|
-
E("account.entry", "trading.entryColor", D(
|
|
1416
|
+
E("ticket.buy", "trading.buyColor", D(x.orderColors?.buy)),
|
|
1417
|
+
E("ticket.sell", "trading.sellColor", D(x.orderColors?.sell)),
|
|
1418
|
+
E("settings.profit", "trading.profitColor", D(x.positionColors?.profit)),
|
|
1419
|
+
E("settings.loss", "trading.lossColor", D(x.positionColors?.loss)),
|
|
1420
|
+
E("account.entry", "trading.entryColor", D(x.positionColors?.entry))
|
|
1421
1421
|
]
|
|
1422
1422
|
},
|
|
1423
1423
|
{
|
|
1424
1424
|
title: "settings.section.signals",
|
|
1425
1425
|
rows: [
|
|
1426
|
-
E("account.long", "markers.longColor", D(
|
|
1427
|
-
E("account.short", "markers.shortColor", D(
|
|
1428
|
-
E("markers.neutral", "markers.neutralColor", D(
|
|
1426
|
+
E("account.long", "markers.longColor", D(y.longColor)),
|
|
1427
|
+
E("account.short", "markers.shortColor", D(y.shortColor)),
|
|
1428
|
+
E("markers.neutral", "markers.neutralColor", D(y.neutralColor))
|
|
1429
1429
|
]
|
|
1430
1430
|
},
|
|
1431
1431
|
{
|
|
1432
1432
|
title: "settings.section.tradeZones",
|
|
1433
1433
|
rows: [
|
|
1434
|
-
E("settings.profit", "tradeZones.profitColor", D(
|
|
1435
|
-
E("settings.loss", "tradeZones.lossColor", D(
|
|
1436
|
-
E("settings.openTrade", "tradeZones.activeColor", D(
|
|
1434
|
+
E("settings.profit", "tradeZones.profitColor", D(b.profitColor)),
|
|
1435
|
+
E("settings.loss", "tradeZones.lossColor", D(b.lossColor)),
|
|
1436
|
+
E("settings.openTrade", "tradeZones.activeColor", D(b.activeColor))
|
|
1437
1437
|
]
|
|
1438
1438
|
}
|
|
1439
|
-
],
|
|
1439
|
+
], Je = {
|
|
1440
1440
|
upColor: "settings.up",
|
|
1441
1441
|
downColor: "settings.down",
|
|
1442
1442
|
wickUpColor: "settings.upWick",
|
|
@@ -1446,20 +1446,20 @@ var Pe = [
|
|
|
1446
1446
|
lineWidth: "drawingSettings.lineWidth",
|
|
1447
1447
|
topColor: "settings.areaTop",
|
|
1448
1448
|
bottomColor: "settings.areaBottom"
|
|
1449
|
-
},
|
|
1449
|
+
}, Ye = new Set([
|
|
1450
1450
|
"candlestick",
|
|
1451
1451
|
"heikinAshi",
|
|
1452
1452
|
"volumeCandles",
|
|
1453
1453
|
"equivolume"
|
|
1454
1454
|
]);
|
|
1455
|
-
function
|
|
1455
|
+
function Xe(e) {
|
|
1456
1456
|
let t = `series.${e}.`;
|
|
1457
1457
|
return Object.keys(g).filter((e) => e.startsWith(t)).map((n) => {
|
|
1458
|
-
let r = n.slice(t.length), i =
|
|
1459
|
-
return
|
|
1458
|
+
let r = n.slice(t.length), i = Je[r] ?? "drawingSettings.color";
|
|
1459
|
+
return Ye.has(e) && r === "upColor" && (i = "settings.upBody"), Ye.has(e) && r === "downColor" && (i = "settings.downBody"), e === "baseline" && r === "upColor" && (i = "settings.aboveBase"), e === "baseline" && r === "downColor" && (i = "settings.belowBase"), T(i, n);
|
|
1460
1460
|
});
|
|
1461
1461
|
}
|
|
1462
|
-
var Ke = [...new Set([...Object.keys(g).filter((e) => e.startsWith("series.")), ...[...Ve, ...He].flatMap((e) => e.rows.flatMap((e) => e.keys))])], qe = "/* === TradeCanvas Widget — Premium Styles === */\n\n/*\n * The HTML `hidden` attribute only sets `display: none` via the UA stylesheet,\n * which any author `display` rule (e.g. `.tcw-alerts-panel { display: flex }`)\n * silently overrides — leaving panels stuck open when JS sets `el.hidden = true`.\n * Force `hidden` to win for every namespaced widget element. Scoped to `tcw-`\n * so it never touches the host page.\n */\n[class^=\"tcw-\"][hidden],\n[class*=\" tcw-\"][hidden] {\n display: none !important;\n}\n\n/* Control tooltips (WidgetTooltip): quick to appear, slide in from the control. */\n.tcw-tooltip {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 60;\n max-width: 240px;\n padding: 5px 8px;\n border-radius: var(--tcw-tooltip-radius);\n background: var(--tcw-tooltip-bg);\n color: var(--tcw-tooltip-fg);\n box-shadow: var(--tcw-tooltip-shadow);\n width: max-content;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight);\n line-height: 1.35;\n overflow-wrap: anywhere;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transform: translate(var(--tcw-tip-dx, 0), var(--tcw-tip-dy, 0));\n transition:\n opacity 110ms var(--tcw-ease-out),\n transform 110ms var(--tcw-ease-out),\n visibility 0s linear 110ms;\n}\n\n.tcw-tooltip--visible {\n opacity: 1;\n visibility: visible;\n transform: none;\n transition:\n opacity 110ms var(--tcw-ease-out),\n transform 110ms var(--tcw-ease-out),\n visibility 0s;\n}\n\n/* The modal portal: carries the tokens and fonts, but no box of its own. */\n.tcw-root.tcw-portal {\n display: contents;\n}\n\n/* Fullscreen: the root fills the screen; the chart resizes with it. */\n.tcw-root:fullscreen {\n width: 100vw;\n height: 100vh;\n}\n\n.tcw-root {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n font-family: var(--tcw-font);\n font-feature-settings: 'cv11', 'ss01', 'ss03';\n font-size: var(--tcw-font-size);\n line-height: 1.4;\n color: #d9dde4;\n background: #080b10;\n position: relative;\n overflow: hidden;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n /* --- Dark theme tokens (default) --- */\n --tcw-bg: #080b10;\n --tcw-bg-surface: #0c1016;\n --tcw-bg-elevated: #141922;\n --tcw-bg-overlay: rgba(20, 25, 34, 0.5);\n --tcw-border: #1f2630;\n --tcw-border-strong: #2a323e;\n --tcw-tooltip-bg: #262e3a;\n --tcw-tooltip-fg: #eef0f4;\n --tcw-text: #e7e9ee;\n --tcw-text-dim: #aab1bd;\n --tcw-text-muted: #758091;\n\n /* TradeCanvas amber. --tcw-accent-ink is the text colour on an accent fill. */\n --tcw-accent: #f2a93b;\n --tcw-accent-hover: #f5b95c;\n --tcw-accent-ink: #1a1204;\n --tcw-accent-soft: rgba(242, 169, 59, 0.14);\n --tcw-accent-glow: rgba(242, 169, 59, 0.22);\n --tcw-accent-line: rgba(242, 169, 59, 0.55);\n\n --tcw-red: #e8505b;\n --tcw-red-soft: rgba(232, 80, 91, 0.12);\n --tcw-green: #1fa874;\n --tcw-green-soft: rgba(31, 168, 116, 0.12);\n --tcw-amber: #ff9f43;\n\n --tcw-hover-bg: rgba(255, 255, 255, 0.05);\n --tcw-active-bg: rgba(255, 255, 255, 0.08);\n --tcw-divider: rgba(255, 255, 255, 0.06);\n\n /* Motion */\n --tcw-ease: cubic-bezier(0.2, 0, 0, 1);\n --tcw-ease-out: cubic-bezier(0.16, 1, 0.3, 1);\n --tcw-dur-fast: 120ms;\n --tcw-dur-normal: 180ms;\n --tcw-dur-slow: 260ms;\n\n /* The look (UI system): Studio's values. The `ui` option sets them inline. */\n --tcw-radius-xs: 3px;\n --tcw-radius-sm: 5px;\n --tcw-radius: 7px;\n --tcw-radius-lg: 11px;\n --tcw-radius-xl: 16px;\n --tcw-control-radius: var(--tcw-radius);\n --tcw-input-radius: var(--tcw-radius);\n --tcw-menu-radius: var(--tcw-radius-lg);\n --tcw-dialog-radius: var(--tcw-radius-xl);\n --tcw-panel-radius: var(--tcw-radius-lg);\n --tcw-tooltip-radius: var(--tcw-radius-sm);\n --tcw-tag-radius: var(--tcw-radius-sm);\n --tcw-toast-radius: var(--tcw-radius-lg);\n --tcw-toolbar-radius: 0px;\n --tcw-sidebar-radius: 0px;\n --tcw-toolbar-h: 46px;\n --tcw-control-h: 30px;\n --tcw-control-h-sm: 24px;\n --tcw-icon: 18px;\n --tcw-sidebar-w: 48px;\n --tcw-menu-item-h: 30px;\n --tcw-font: 'Manrope', 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n --tcw-font-size: 13px;\n --tcw-font-size-sm: 12px;\n --tcw-font-size-xs: 11px;\n --tcw-font-size-lg: 15px;\n --tcw-weight: 500;\n --tcw-weight-strong: 600;\n --tcw-label-case: none;\n --tcw-label-tracking: 0em;\n --tcw-border-w: 1px;\n --tcw-sep-w: 0px;\n --tcw-menu-shadow: var(--tcw-shadow-lg);\n --tcw-dialog-shadow: var(--tcw-shadow-xl);\n --tcw-tooltip-shadow: var(--tcw-shadow-md);\n --tcw-blur: 0px;\n --tcw-surface-opacity: 100%;\n\n /* Elevation */\n --tcw-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);\n --tcw-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35), 0 1px 3px rgba(0, 0, 0, 0.2);\n --tcw-shadow-lg: 0 12px 36px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.3);\n --tcw-shadow-xl: 0 24px 64px rgba(0, 0, 0, 0.55), 0 12px 24px rgba(0, 0, 0, 0.35);\n --tcw-ring: 0 0 0 2px rgba(242, 169, 59, 0.45);\n\n /* Type */\n --tcw-font-mono: 'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', 'Consolas', ui-monospace, monospace;\n}\n\n.tcw-root[data-tcw-theme='light'] {\n color: #0c1016;\n background: #fcfcfd;\n\n --tcw-bg: #fcfcfd;\n --tcw-bg-surface: #ffffff;\n --tcw-bg-elevated: #ffffff;\n --tcw-bg-overlay: rgba(255, 255, 255, 0.75);\n --tcw-border: #e3e6eb;\n --tcw-border-strong: #d2d6dd;\n --tcw-tooltip-bg: #1f2630;\n --tcw-tooltip-fg: #f4f5f8;\n --tcw-text: #0c1016;\n --tcw-text-dim: #3f4754;\n --tcw-text-muted: #626a77;\n\n /* Deeper amber: readable as text on the light ground, white text readable on it. */\n --tcw-accent: #a0610a;\n --tcw-accent-hover: #874f07;\n --tcw-accent-ink: #ffffff;\n --tcw-accent-soft: rgba(160, 97, 10, 0.10);\n --tcw-accent-glow: rgba(160, 97, 10, 0.16);\n --tcw-accent-line: rgba(160, 97, 10, 0.45);\n --tcw-ring: 0 0 0 2px rgba(160, 97, 10, 0.4);\n\n /* Darker semantic colours: used as text on white. */\n --tcw-red: #c42f3e;\n --tcw-red-soft: rgba(196, 47, 62, 0.10);\n --tcw-green: #0b7d50;\n --tcw-green-soft: rgba(11, 125, 80, 0.10);\n\n --tcw-hover-bg: rgba(0, 0, 0, 0.04);\n --tcw-active-bg: rgba(160, 97, 10, 0.08);\n --tcw-divider: rgba(0, 0, 0, 0.06);\n\n --tcw-shadow-sm: 0 1px 2px rgba(20, 28, 56, 0.05);\n --tcw-shadow-md: 0 4px 12px rgba(20, 28, 56, 0.08), 0 1px 3px rgba(20, 28, 56, 0.04);\n --tcw-shadow-lg: 0 12px 36px rgba(20, 28, 56, 0.14), 0 4px 12px rgba(20, 28, 56, 0.08);\n --tcw-shadow-xl: 0 24px 64px rgba(20, 28, 56, 0.18), 0 12px 24px rgba(20, 28, 56, 0.1);\n}\n\n/* === Toolbar === */\n\n.tcw-toolbar {\n display: flex;\n align-items: center;\n gap: 0;\n padding: 0 10px;\n height: var(--tcw-toolbar-h);\n border-bottom: var(--tcw-border-w) solid var(--tcw-border);\n background:\n linear-gradient(180deg, var(--tcw-bg-elevated) 0%, var(--tcw-bg-surface) 100%);\n flex-shrink: 0;\n position: relative;\n z-index: 20;\n box-shadow: var(--tcw-shadow-sm);\n}\n\n.tcw-toolbar-symbol {\n font-size: calc(var(--tcw-font-size) + 1px);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n display: inline-flex;\n align-items: center;\n height: var(--tcw-control-h);\n padding: 0 12px;\n white-space: nowrap;\n letter-spacing: -0.015em;\n cursor: pointer;\n border: none;\n background: transparent;\n font-family: inherit;\n border-radius: var(--tcw-control-radius);\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-toolbar-symbol:hover {\n background: var(--tcw-hover-bg);\n}\n\n/* With the symbol search switched off, the button only names the symbol. */\n.tcw-toolbar-symbol[aria-disabled=\"true\"] {\n cursor: default;\n}\n\n.tcw-toolbar-symbol[aria-disabled=\"true\"]:hover {\n background: transparent;\n}\n\n.tcw-toolbar-sep {\n width: var(--tcw-sep-w);\n height: 22px;\n background: var(--tcw-border);\n flex-shrink: 0;\n margin: 0 4px;\n}\n\n.tcw-toolbar-group {\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 0 4px;\n}\n\n.tcw-toolbar-spacer {\n flex: 1;\n}\n\n.tcw-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--tcw-control-h);\n padding: 0 10px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n cursor: pointer;\n transition:\n background var(--tcw-dur-fast) var(--tcw-ease),\n color var(--tcw-dur-fast) var(--tcw-ease),\n transform var(--tcw-dur-fast) var(--tcw-ease);\n white-space: nowrap;\n line-height: 1;\n letter-spacing: -0.005em;\n}\n\n.tcw-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-btn:active {\n transform: translateY(0.5px);\n}\n\n.tcw-btn.tcw-active {\n background: var(--tcw-on-bg);\n color: var(--tcw-on-fg);\n font-weight: var(--tcw-weight-strong);\n box-shadow: var(--tcw-on-ring);\n}\n\n.tcw-btn:focus-visible,\n.tcw-btn-icon:focus-visible,\n.tcw-sidebar-btn:focus-visible,\n.tcw-dropdown-trigger:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-btn-icon {\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n transition:\n background var(--tcw-dur-fast) var(--tcw-ease),\n color var(--tcw-dur-fast) var(--tcw-ease);\n line-height: 1;\n position: relative;\n}\n\n.tcw-btn-icon:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-btn-icon svg {\n display: block;\n width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n\n.tcw-badge-count {\n font-size: calc(var(--tcw-font-size) - 3px);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n padding: 1px 5px;\n border-radius: var(--tcw-tag-radius);\n font-family: var(--tcw-font-mono);\n}\n\n/* === Dropdown === */\n\n.tcw-dropdown-trigger {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: var(--tcw-control-h);\n padding: 0 10px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n white-space: nowrap;\n line-height: 1;\n}\n\n.tcw-dropdown-trigger:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-dropdown {\n position: absolute;\n top: 100%;\n margin-top: 6px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n z-index: 50;\n width: max-content;\n max-width: min(340px, calc(100vw - 16px));\n padding: 6px;\n max-height: 420px;\n overflow-y: auto;\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n animation: tcw-pop-in var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n@keyframes tcw-pop-in {\n from { opacity: 0; transform: translateY(-4px) scale(0.98); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n}\n\n.tcw-dropdown-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: var(--tcw-menu-item-h);\n padding: 4px 10px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n width: 100%;\n border: none;\n background: transparent;\n font-family: inherit;\n text-align: start;\n border-radius: var(--tcw-radius-sm);\n gap: 12px;\n}\n\n.tcw-dropdown-item:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n/* A menu row led by an icon (chart types): icon then label, not spread apart. */\n.tcw-dropdown-item--icon {\n justify-content: flex-start;\n gap: 10px;\n}\n\n.tcw-dropdown-item svg,\n.tcw-flyout-item svg {\n flex-shrink: 0;\n}\n\n/* The drawing-group button's icon holder: a plain box for the swapped SVG. */\n.tcw-sidebar-icon {\n display: inline-flex;\n}\n\n.tcw-dropdown-item.tcw-active {\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n font-weight: var(--tcw-weight-strong);\n}\n\n/* Timeframe menu: pick on the left, pin (star) on the right. */\n.tcw-tf-more {\n padding: 0 5px;\n}\n\n.tcw-tf-more svg {\n display: block;\n}\n\n.tcw-tf-row {\n display: flex;\n align-items: center;\n gap: 2px;\n}\n\n.tcw-tf-row .tcw-dropdown-item {\n flex: 1;\n min-width: 0;\n}\n\n.tcw-tf-star {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-tf-star:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-tf-star.tcw-active {\n color: var(--tcw-accent);\n}\n\n.tcw-tf-star.tcw-active svg {\n fill: currentColor;\n}\n\n.tcw-tf-star:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-tf-remove {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-tf-row:hover .tcw-tf-remove,\n.tcw-tf-remove:focus-visible {\n opacity: 1;\n}\n\n/* No hover on touch screens: keep it visible rather than a hidden tap target. */\n@media (hover: none) {\n .tcw-tf-remove { opacity: 1; }\n}\n\n.tcw-tf-remove:hover {\n color: var(--tcw-red);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-tf-remove:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n/* Typed interval, under the list: stays in view while the list scrolls. */\n.tcw-tf-custom {\n position: sticky;\n bottom: -6px;\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin: 4px -6px -6px;\n padding: 6px 10px 8px;\n border-top: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-elevated);\n}\n\n.tcw-tf-custom-hint:empty {\n display: none;\n}\n\n.tcw-tf-custom-hint {\n flex-basis: 100%;\n width: 0;\n min-width: 100%;\n color: var(--tcw-red);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.35;\n}\n\n.tcw-tf-custom-input {\n flex: 1;\n min-width: 0;\n height: 26px;\n padding: 0 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text);\n font: inherit;\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-tf-custom-input::placeholder {\n color: var(--tcw-text-dim);\n}\n\n.tcw-tf-custom-input:focus {\n outline: none;\n border-color: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n\n.tcw-tf-custom-input[aria-invalid='true'] {\n border-color: var(--tcw-red);\n box-shadow: 0 0 0 2px var(--tcw-red-soft);\n}\n\n.tcw-tf-custom-add {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n cursor: pointer;\n}\n\n.tcw-tf-custom-add:hover {\n border-color: var(--tcw-accent);\n color: var(--tcw-accent);\n}\n\n.tcw-tf-custom-add:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: 1px;\n}\n\n.tcw-dropdown-label {\n text-transform: var(--tcw-label-case);\n font-size: calc(var(--tcw-font-size) - 3px);\n color: var(--tcw-text-muted);\n letter-spacing: var(--tcw-label-tracking);\n padding: 8px 10px 4px;\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-dropdown-divider {\n border-top: 1px solid var(--tcw-divider);\n margin: 6px 4px;\n}\n\n.tcw-tag {\n font-size: calc(var(--tcw-font-size) - 3px);\n font-family: var(--tcw-font-mono);\n color: var(--tcw-text-muted);\n padding: 2px 6px;\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-hover-bg);\n letter-spacing: 0.02em;\n}\n\n/* === Body === */\n\n.tcw-body {\n position: relative;\n display: flex;\n flex: 1;\n min-height: 0;\n background: var(--tcw-bg);\n}\n\n.tcw-chart-container {\n flex: 1;\n min-width: 0;\n min-height: 0;\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n/* === Symbol search results: name and exchange === */\n\n.tcw-cmd-item-desc {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-cmd-item-meta {\n flex-shrink: 0;\n color: var(--tcw-text-dim);\n font-size: var(--tcw-font-size-xs);\n letter-spacing: 0.02em;\n}\n\n/* === History pill (older bars loading at the left edge) === */\n\n.tcw-history-pill {\n position: absolute;\n top: 50%;\n left: 10px;\n z-index: 4;\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 5px 10px 5px 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-shadow-sm);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n line-height: 1;\n white-space: nowrap;\n transform: translateY(-50%);\n opacity: 1;\n transition: opacity var(--tcw-dur-normal) var(--tcw-ease-out);\n pointer-events: none;\n}\n\n.tcw-history-pill--hidden {\n opacity: 0;\n}\n\n.tcw-history-pill--error {\n border-color: color-mix(in srgb, var(--tcw-red) 45%, var(--tcw-border));\n color: var(--tcw-red);\n}\n\n.tcw-history-spinner {\n width: 10px;\n height: 10px;\n border: 1.5px solid var(--tcw-accent-soft);\n border-top-color: var(--tcw-accent);\n border-radius: 50%;\n animation: tcw-history-spin 0.8s linear infinite;\n}\n\n.tcw-history-pill--error .tcw-history-spinner {\n border-color: currentColor;\n animation: none;\n}\n\n@keyframes tcw-history-spin {\n to { transform: rotate(360deg); }\n}\n\n/* === Loading overlay (candle skeleton) === */\n\n.tcw-loading-overlay {\n /* Uses a modifier class rather than the `hidden` attribute — the global\n `[hidden] { display: none !important }` rule above would cut the\n opacity transition off before it can play. */\n position: absolute;\n inset: 0;\n z-index: 5;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--tcw-bg);\n opacity: 1;\n transition: opacity var(--tcw-dur-slow) var(--tcw-ease-out);\n pointer-events: none;\n}\n\n.tcw-loading-overlay--hidden {\n opacity: 0;\n}\n\n.tcw-loading-card {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 14px;\n padding: 22px 26px 20px;\n border: 1px solid transparent;\n border-radius: var(--tcw-panel-radius);\n}\n\n/* A slow switch: the previous chart stays readable underneath, dimmed, so the\n click visibly registered without blanking the screen. */\n.tcw-loading-overlay--veil {\n background: color-mix(in srgb, var(--tcw-bg) 55%, transparent);\n}\n\n.tcw-loading-overlay--veil .tcw-loading-card {\n background: var(--tcw-bg-elevated);\n border-color: var(--tcw-border);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n.tcw-loading-candles {\n position: relative;\n display: flex;\n gap: 7px;\n height: 64px;\n}\n\n/* One candle: the element is the wick's column, ::before the wick, ::after the body. */\n.tcw-loading-candle {\n position: relative;\n width: 8px;\n height: 100%;\n color: var(--tcw-red);\n opacity: 0.28;\n animation: tcw-candle-light 1.6s var(--tcw-ease) infinite;\n animation-delay: var(--tcw-delay, 0ms);\n}\n\n.tcw-loading-candle--up { color: var(--tcw-green); }\n\n.tcw-loading-candle::before,\n.tcw-loading-candle::after {\n content: '';\n position: absolute;\n left: 50%;\n background: currentColor;\n transform: translateX(-50%);\n}\n\n.tcw-loading-candle::before {\n top: var(--tcw-wick-top);\n width: 1.5px;\n height: var(--tcw-wick-h);\n}\n\n.tcw-loading-candle::after {\n top: var(--tcw-body-top);\n width: 8px;\n height: var(--tcw-body-h);\n border-radius: 1.5px;\n}\n\n/* Each candle brightens and lifts slightly in turn, left to right. */\n@keyframes tcw-candle-light {\n 0%, 55%, 100% { opacity: 0.28; transform: translateY(0); }\n 20% { opacity: 1; transform: translateY(-2px); }\n}\n\n.tcw-loading-track {\n position: relative;\n width: 100%;\n min-width: 88px;\n height: 2px;\n border-radius: 1px;\n background: var(--tcw-border);\n overflow: hidden;\n}\n\n.tcw-loading-track > span {\n position: absolute;\n inset: 0;\n width: 40%;\n border-radius: 1px;\n background: linear-gradient(90deg, transparent, var(--tcw-accent), transparent);\n animation: tcw-loading-sweep 1.6s var(--tcw-ease) infinite;\n}\n\n@keyframes tcw-loading-sweep {\n from { transform: translateX(-100%); }\n to { transform: translateX(250%); }\n}\n\n/* The status text is announced, not shown — the candles say \"loading\". */\n.tcw-loading-label {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n.tcw-loading-overlay--error .tcw-loading-candles,\n.tcw-loading-overlay--error .tcw-loading-track {\n display: none;\n}\n\n/* A failure is shown: why the chart is empty and that a retry is running. */\n.tcw-loading-overlay--error .tcw-loading-label {\n position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip-path: none;\n white-space: normal;\n max-width: 320px;\n text-align: center;\n color: var(--tcw-red);\n font-size: var(--tcw-font-size);\n}\n\n/* Reduced motion: nothing slides or lifts, but the candles still glow in\n turn and the track breathes, so the wait never looks frozen. */\n@media (prefers-reduced-motion: reduce) {\n .tcw-loading-candle {\n animation: tcw-candle-glow 2.4s ease-in-out infinite;\n animation-delay: var(--tcw-delay, 0ms);\n }\n .tcw-loading-track > span {\n width: 100%;\n background: var(--tcw-accent);\n animation: tcw-loading-breathe 2.4s ease-in-out infinite;\n }\n}\n\n@keyframes tcw-candle-glow {\n 0%, 60%, 100% { opacity: 0.28; }\n 25% { opacity: 0.9; }\n}\n\n@keyframes tcw-loading-breathe {\n 0%, 100% { opacity: 0.15; }\n 50% { opacity: 0.7; }\n}\n\n/* === On-chart indicator legend (WidgetIndicatorLegend) === */\n\n.tcw-ind-legend {\n position: absolute;\n z-index: 3;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 1px;\n max-width: calc(100% - 140px);\n pointer-events: none;\n}\n\n.tcw-ind-legend--collapsed > .tcw-ind-legend-row {\n display: none;\n}\n\n.tcw-ind-legend-row {\n display: flex;\n align-items: center;\n gap: 8px;\n max-width: 100%;\n padding: 0 4px;\n border-radius: var(--tcw-radius-sm);\n font-size: var(--tcw-font-size-xs);\n line-height: 19px;\n font-feature-settings: 'tnum';\n white-space: nowrap;\n color: var(--tcw-text-dim);\n pointer-events: auto;\n cursor: default;\n /* A narrow pane: the values shrink first, then the row is clipped. */\n overflow: hidden;\n}\n\n/* A pane's indicator: at the top of its pane, where the canvas title was,\n short enough to sit in the pane's header below the divider's grab zone. */\n.tcw-ind-legend-row--pane {\n position: absolute;\n z-index: 3;\n line-height: 15px;\n}\n\n.tcw-ind-legend-row:hover,\n.tcw-ind-legend-row:focus-within {\n background: color-mix(in srgb, var(--tcw-bg-elevated) 90%, transparent);\n box-shadow: 0 0 0 1px var(--tcw-border);\n}\n\n.tcw-ind-legend-name {\n padding: 0;\n border: none;\n background: none;\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n cursor: pointer;\n}\n\n.tcw-ind-legend-name:hover {\n color: var(--tcw-accent);\n}\n\n.tcw-ind-legend-values {\n display: inline-flex;\n gap: 7px;\n min-width: 0;\n overflow: hidden;\n}\n\n.tcw-ind-legend-row--hidden .tcw-ind-legend-name,\n.tcw-ind-legend-row--hidden .tcw-ind-legend-values {\n opacity: 0.45;\n}\n\n/* Show / settings / remove: on hover or keyboard focus (always on touch). */\n.tcw-ind-legend-actions {\n display: none;\n gap: 1px;\n margin-left: -2px;\n}\n\n.tcw-ind-legend-row:hover .tcw-ind-legend-actions,\n.tcw-ind-legend-row:focus-within .tcw-ind-legend-actions {\n display: inline-flex;\n}\n\n@media (hover: none) {\n .tcw-ind-legend-actions {\n display: inline-flex;\n }\n\n /* Finger-sized targets. */\n .tcw-ind-legend-act,\n .tcw-ind-legend-toggle {\n min-width: 28px;\n min-height: 24px;\n }\n}\n\n.tcw-ind-legend-act {\n display: inline-grid;\n place-items: center;\n width: 20px;\n height: 18px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n\n.tcw-ind-legend-act:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ind-legend-act[data-act='remove']:hover {\n color: var(--tcw-red);\n}\n\n.tcw-ind-legend-toggle {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n margin-top: 1px;\n padding: 1px 5px;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n cursor: pointer;\n pointer-events: auto;\n}\n\n.tcw-ind-legend-toggle[hidden] {\n display: none;\n}\n\n.tcw-ind-legend-toggle:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ind-legend-name:focus-visible,\n.tcw-ind-legend-act:focus-visible,\n.tcw-ind-legend-toggle:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n/* === Sidebar === */\n\n.tcw-sidebar {\n width: var(--tcw-sidebar-w);\n flex-shrink: 0;\n background: linear-gradient(180deg, var(--tcw-bg-elevated) 0%, var(--tcw-bg-surface) 100%);\n border-inline-end: var(--tcw-border-w) solid var(--tcw-border);\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 6px 0;\n /* On a short screen the tools scroll; the menus sit outside it. */\n overflow-x: hidden;\n overflow-y: auto;\n scrollbar-width: none;\n box-shadow: var(--tcw-shadow-sm);\n}\n.tcw-sidebar::-webkit-scrollbar {\n display: none;\n}\n.tcw-sidebar > * {\n flex-shrink: 0;\n}\n\n.tcw-tool-group-wrap {\n position: relative;\n}\n\n.tcw-sidebar-btn {\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n margin: 1px 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n font-family: inherit;\n transition:\n background var(--tcw-dur-fast) var(--tcw-ease),\n color var(--tcw-dur-fast) var(--tcw-ease);\n position: relative;\n flex-shrink: 0;\n line-height: 1;\n border-radius: var(--tcw-control-radius);\n}\n\n.tcw-sidebar-btn svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n\n.tcw-sidebar-btn:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-sidebar-btn.tcw-active {\n color: var(--tcw-on-icon-fg);\n background: var(--tcw-on-icon-bg);\n box-shadow: var(--tcw-on-icon-ring);\n}\n\n.tcw-sidebar-btn.tcw-danger:hover {\n color: var(--tcw-red);\n background: var(--tcw-red-soft);\n}\n\n.tcw-multi-dot {\n position: absolute;\n bottom: 3px;\n right: 3px;\n width: 4px;\n height: 4px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n opacity: 0.7;\n}\n\n/* The drawing tools' sections: always a hairline (it groups the tools), even in\n looks that drop the rules between toolbar groups. */\n.tcw-sidebar-divider {\n width: 20px;\n height: max(1px, var(--tcw-sep-w));\n background: var(--tcw-divider);\n margin: 5px 0;\n flex-shrink: 0;\n}\n\n.tcw-sidebar-spacer {\n flex: 1;\n}\n\n/* === Flyout === */\n\n.tcw-flyout {\n position: absolute;\n margin-inline-start: 6px;\n overflow-y: auto;\n overscroll-behavior: contain;\n min-width: 180px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n z-index: 30;\n padding: 6px;\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n animation: tcw-slide-right var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n/* Spans the gap to the toolbar button: crossing it stays inside the menu. */\n.tcw-flyout::before {\n content: '';\n position: absolute;\n top: -1px;\n bottom: -1px;\n right: 100%;\n width: 8px;\n}\n\n@keyframes tcw-slide-right {\n from { opacity: 0; transform: translateX(-4px); }\n to { opacity: 1; transform: translateX(0); }\n}\n\n.tcw-flyout-header {\n text-transform: var(--tcw-label-case);\n font-size: calc(var(--tcw-font-size) - 3px);\n color: var(--tcw-text-muted);\n letter-spacing: var(--tcw-label-tracking);\n padding: 6px 10px 4px;\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-flyout-hint {\n padding: 6px 10px 2px;\n border-top: 1px solid var(--tcw-border);\n margin-top: 4px;\n font-size: calc(var(--tcw-font-size) - 2.5px);\n color: var(--tcw-text-muted);\n}\n\n.tcw-flyout-item {\n min-height: var(--tcw-menu-item-h);\n padding: 4px 10px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n cursor: pointer;\n width: 100%;\n display: flex;\n align-items: center;\n gap: 10px;\n border: none;\n background: transparent;\n text-align: start;\n font-family: inherit;\n border-radius: var(--tcw-radius-sm);\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-flyout-item:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n.tcw-flyout-item:focus-visible {\n outline: none;\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n box-shadow: inset 0 0 0 1px var(--tcw-accent);\n}\n\n.tcw-flyout-item.tcw-active {\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n font-weight: var(--tcw-weight-strong);\n}\n\n/* Pinned (favorited) flyout item — a star marker on the right. */\n.tcw-flyout-item.tcw-flyout-faved::after {\n content: '★';\n float: right;\n color: var(--tcw-accent);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.4;\n}\n\n/* Favorites strip — pinned drawing tools above the tool groups. */\n.tcw-sidebar-favorites {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.tcw-sidebar-favorites .tcw-sidebar-btn {\n position: relative;\n}\n.tcw-sidebar-favorites .tcw-sidebar-btn::before {\n content: '';\n position: absolute;\n top: 3px;\n right: 3px;\n width: 4px;\n height: 4px;\n border-radius: 50%;\n background: var(--tcw-accent);\n opacity: 0.7;\n}\n\n/* === Modal === */\n\n.tcw-modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(8, 10, 18, 0.55);\n backdrop-filter: blur(6px) saturate(140%);\n -webkit-backdrop-filter: blur(6px) saturate(140%);\n z-index: 100;\n animation: tcw-fade-in var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n@keyframes tcw-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.tcw-modal {\n position: fixed;\n z-index: 101;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-dialog-radius);\n width: 520px;\n max-width: 92vw;\n max-height: 82vh;\n display: flex;\n flex-direction: column;\n box-shadow: var(--tcw-dialog-shadow);\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\n}\n\n@keyframes tcw-modal-in {\n from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }\n to { opacity: 1; transform: translate(-50%, -50%) scale(1); }\n}\n\n.tcw-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 18px 22px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n.tcw-modal-header h3 {\n font-size: var(--tcw-font-size-lg);\n font-weight: var(--tcw-weight-strong);\n margin: 0;\n color: var(--tcw-text);\n letter-spacing: -0.015em;\n}\n\n.tcw-modal-close {\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n border-radius: var(--tcw-control-radius);\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-modal-close:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-modal-tabs {\n display: flex;\n /* Four tabs in a long language on a phone: they wrap rather than clip. No overflow here: in the\n dialog's column it would let a long body squash the tabs, and clip the underline of the active one. */\n flex-wrap: wrap;\n flex-shrink: 0;\n gap: 4px;\n padding: var(--tcw-tabs-pad-block) 18px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n.tcw-modal-tab {\n flex-shrink: 0;\n white-space: nowrap;\n height: var(--tcw-tab-h);\n padding: var(--tcw-tab-pad);\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n color: var(--tcw-text-muted);\n border: none;\n background: transparent;\n cursor: pointer;\n border-bottom: var(--tcw-tab-line) solid transparent;\n border-radius: var(--tcw-tab-radius);\n margin-bottom: calc(var(--tcw-tab-line) / -2);\n transition: color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n font-family: inherit;\n text-transform: capitalize;\n letter-spacing: -0.005em;\n}\n\n.tcw-modal-tab:hover {\n color: var(--tcw-text-dim);\n background: var(--tcw-tab-hover);\n}\n\n.tcw-modal-tab.tcw-active {\n color: var(--tcw-tab-on-fg);\n background: var(--tcw-tab-on-bg);\n border-bottom-color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-modal-body {\n padding: 20px 22px;\n overflow-y: auto;\n flex: 1;\n}\n\n.tcw-settings-section {\n margin-bottom: 22px;\n}\n\n.tcw-settings-section:last-child {\n margin-bottom: 0;\n}\n\n.tcw-settings-section-title {\n font-size: calc(var(--tcw-font-size) - 2.5px);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n margin-bottom: 12px;\n}\n\n.tcw-settings-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 0;\n}\n\n.tcw-settings-row + .tcw-settings-row {\n border-top: 1px solid var(--tcw-divider);\n}\n\n.tcw-settings-label {\n font-size: var(--tcw-font-size);\n color: var(--tcw-text-dim);\n letter-spacing: -0.005em;\n}\n\n.tcw-color-picker-wrap {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.tcw-color-picker-wrap input[type='color'] {\n width: 28px;\n height: 28px;\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n cursor: pointer;\n padding: 2px;\n}\n\n.tcw-color-picker-wrap input[type='color']::-webkit-color-swatch-wrapper {\n padding: 0;\n}\n\n.tcw-color-picker-wrap input[type='color']::-webkit-color-swatch {\n border: none;\n border-radius: var(--tcw-radius-xs);\n}\n\n.tcw-color-hex {\n font-size: var(--tcw-font-size-xs);\n font-family: var(--tcw-font-mono);\n color: var(--tcw-text-muted);\n min-width: 64px;\n letter-spacing: 0.01em;\n}\n\n/* A colour left to the part itself: the swatch shows where the picker starts, faded. */\n.tcw-color-auto input[type='color'] {\n opacity: 0.45;\n border-style: dashed;\n}\n\n.tcw-color-auto .tcw-color-hex {\n font-family: inherit;\n font-style: italic;\n}\n\n.tcw-color-auto-btn {\n height: 24px;\n padding: 0 8px;\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n background: transparent;\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-radius-sm);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-color-auto-btn:hover,\n.tcw-color-auto-btn:focus-visible {\n color: var(--tcw-text);\n border-color: var(--tcw-accent);\n}\n\n.tcw-toggle {\n width: 36px;\n height: 20px;\n background: rgba(255, 255, 255, 0.12);\n border-radius: 10px;\n position: relative;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n border: none;\n padding: 0;\n flex-shrink: 0;\n}\n\n.tcw-toggle::after {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n transition:\n left var(--tcw-dur-normal) var(--tcw-ease-out),\n background var(--tcw-dur-fast) var(--tcw-ease);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.tcw-toggle.tcw-on {\n background: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-glow);\n}\n\n.tcw-toggle.tcw-on::after {\n left: 18px;\n background: #fff;\n}\n\n.tcw-root[data-tcw-theme='light'] .tcw-toggle {\n background: rgba(0, 0, 0, 0.12);\n}\n\n.tcw-root[data-tcw-theme='light'] .tcw-toggle::after {\n background: #999;\n}\n\n.tcw-root[data-tcw-theme='light'] .tcw-toggle.tcw-on {\n background: var(--tcw-accent);\n}\n\n.tcw-root[data-tcw-theme='light'] .tcw-toggle.tcw-on::after {\n background: #fff;\n}\n\n.tcw-settings-select {\n padding: 6px 10px;\n font-size: var(--tcw-font-size-sm);\n font-family: inherit;\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n color: var(--tcw-text);\n cursor: pointer;\n transition: border-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-settings-select:hover {\n border-color: var(--tcw-border-strong);\n}\n\n.tcw-settings-select:focus-visible {\n outline: none;\n border-color: var(--tcw-accent);\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-modal-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 22px;\n border-top: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-surface);\n border-radius: 0 0 var(--tcw-dialog-radius) var(--tcw-dialog-radius);\n}\n\n.tcw-reset-link {\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-muted);\n cursor: pointer;\n border: none;\n background: transparent;\n font-family: inherit;\n text-decoration: underline;\n text-underline-offset: 2px;\n text-decoration-color: var(--tcw-border-strong);\n transition: color var(--tcw-dur-fast) var(--tcw-ease), text-decoration-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-reset-link:hover {\n color: var(--tcw-text-dim);\n text-decoration-color: currentColor;\n}\n\n.tcw-done-btn {\n padding: 8px 18px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n font-family: inherit;\n transition:\n background var(--tcw-dur-fast) var(--tcw-ease),\n transform var(--tcw-dur-fast) var(--tcw-ease),\n box-shadow var(--tcw-dur-fast) var(--tcw-ease);\n letter-spacing: -0.005em;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.15);\n}\n\n.tcw-done-btn:hover {\n background: var(--tcw-accent-hover);\n box-shadow: var(--tcw-shadow-md), 0 0 0 3px var(--tcw-accent-glow);\n}\n\n.tcw-done-btn:active {\n transform: translateY(0.5px);\n}\n\n/* === Status Bar === */\n\n.tcw-statusbar {\n /* Above sidebar buttons that overflow a short chart; menus (z 30+) stay on top. */\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 7px 16px;\n border-top: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n flex-shrink: 0;\n font-feature-settings: 'tnum';\n}\n\n.tcw-status-right {\n display: flex;\n align-items: center;\n gap: 14px;\n margin-inline-start: auto;\n min-width: 0;\n white-space: nowrap;\n}\n\n/* Narrow screens: the toolbar already names the symbol and timeframe, so the\n range bar gets the room. */\n@media (max-width: 640px) {\n .tcw-status-info {\n display: none;\n }\n\n .tcw-range-btn {\n padding: 4px 5px;\n }\n}\n\n/* Range presets + go to date, bottom left */\n.tcw-range-bar {\n display: flex;\n align-items: center;\n gap: 1px;\n margin: -4px 12px -4px -8px;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n}\n\n.tcw-range-bar::-webkit-scrollbar {\n display: none;\n}\n\n.tcw-range-btn {\n flex-shrink: 0;\n padding: 4px 7px;\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n letter-spacing: 0.02em;\n color: var(--tcw-text-muted);\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-range-btn:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-range-btn:active {\n color: var(--tcw-accent);\n}\n\n.tcw-range-btn:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-range-goto {\n display: inline-grid;\n place-items: center;\n margin-inline-start: 6px;\n padding: 4px 6px;\n}\n\n.tcw-range-goto svg {\n display: block;\n}\n\n/* Go-to-date popover, anchored above the range bar */\n.tcw-goto {\n position: absolute;\n left: 10px;\n bottom: 40px;\n z-index: 40;\n display: grid;\n gap: 10px;\n width: 232px;\n padding: 14px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-goto-title {\n font-weight: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size);\n}\n\n.tcw-goto-field {\n display: grid;\n gap: 4px;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n}\n\n.tcw-goto-input {\n height: 30px;\n padding: 0 8px;\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n color-scheme: dark;\n}\n\n.tcw-root[data-tcw-theme='light'] .tcw-goto-input {\n color-scheme: light;\n}\n\n.tcw-goto-input:focus {\n outline: none;\n border-color: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n\n.tcw-goto-actions {\n display: flex;\n justify-content: flex-end;\n gap: 6px;\n}\n\n.tcw-goto-submit {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-goto-submit:hover {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n filter: brightness(1.08);\n}\n\n.tcw-status-indicator {\n display: flex;\n align-items: center;\n gap: 7px;\n font-weight: var(--tcw-weight);\n}\n\n.tcw-status-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n transition: background var(--tcw-dur-normal) var(--tcw-ease), box-shadow var(--tcw-dur-normal) var(--tcw-ease);\n position: relative;\n}\n\n.tcw-status-dot.tcw-connected {\n background: var(--tcw-green);\n box-shadow: 0 0 0 3px rgba(31, 168, 116, 0.18);\n}\n\n.tcw-status-dot.tcw-connected::after {\n content: '';\n position: absolute;\n inset: -3px;\n border-radius: 50%;\n border: 2px solid var(--tcw-green);\n opacity: 0;\n animation: tcw-pulse 2.2s ease-out infinite;\n}\n\n@keyframes tcw-pulse {\n 0% { opacity: 0.6; transform: scale(0.6); }\n 100% { opacity: 0; transform: scale(2.2); }\n}\n\n.tcw-status-dot.tcw-error {\n background: var(--tcw-red);\n box-shadow: 0 0 0 3px rgba(232, 80, 91, 0.2);\n}\n\n/* === Command Palette === */\n\n.tcw-cmd-palette {\n position: fixed;\n z-index: 102;\n top: 18%;\n left: 50%;\n transform: translateX(-50%);\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-dialog-radius);\n width: 560px;\n max-width: 92vw;\n max-height: 62vh;\n display: flex;\n flex-direction: column;\n box-shadow: var(--tcw-dialog-shadow);\n overflow: hidden;\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\n}\n\n.tcw-cmd-header {\n display: flex;\n align-items: center;\n padding: 14px 18px;\n border-bottom: 1px solid var(--tcw-divider);\n gap: 12px;\n}\n\n.tcw-cmd-icon {\n font-size: calc(var(--tcw-font-size) + 5px);\n color: var(--tcw-text-muted);\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n}\n\n.tcw-cmd-input {\n flex: 1;\n background: transparent;\n border: none;\n outline: none;\n font-size: calc(var(--tcw-font-size) + 1.5px);\n font-family: inherit;\n color: var(--tcw-text);\n caret-color: var(--tcw-accent);\n letter-spacing: -0.005em;\n}\n\n.tcw-cmd-input::placeholder {\n color: var(--tcw-text-muted);\n}\n\n.tcw-cmd-hint {\n font-size: calc(var(--tcw-font-size) - 3px);\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n border: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n padding: 3px 7px;\n border-radius: 4px;\n flex-shrink: 0;\n box-shadow: inset 0 -1px 0 var(--tcw-border);\n}\n\n.tcw-cmd-list {\n overflow-y: auto;\n flex: 1;\n padding: 6px;\n max-height: 380px;\n}\n\n.tcw-cmd-category {\n text-transform: var(--tcw-label-case);\n font-size: calc(var(--tcw-font-size) - 3px);\n color: var(--tcw-text-muted);\n letter-spacing: var(--tcw-label-tracking);\n padding: 10px 10px 4px;\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-cmd-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 9px 12px;\n font-size: var(--tcw-font-size);\n color: var(--tcw-text-dim);\n cursor: pointer;\n width: 100%;\n border: none;\n background: transparent;\n font-family: inherit;\n text-align: start;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n gap: 10px;\n border-radius: var(--tcw-radius);\n letter-spacing: -0.005em;\n}\n\n.tcw-cmd-item:hover,\n.tcw-cmd-item.tcw-selected {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-cmd-item.tcw-selected {\n box-shadow: inset 2px 0 0 var(--tcw-accent);\n}\n\n.tcw-cmd-item.tcw-active .tcw-cmd-item-label {\n color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-cmd-item-label {\n flex: 1;\n}\n\n.tcw-cmd-check {\n color: var(--tcw-accent);\n font-size: calc(var(--tcw-font-size) + 1px);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n}\n\n.tcw-cmd-kbd {\n font-size: calc(var(--tcw-font-size) - 3px);\n font-family: var(--tcw-font-mono);\n color: var(--tcw-text-muted);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n padding: 2px 6px;\n border-radius: var(--tcw-tag-radius);\n box-shadow: inset 0 -1px 0 var(--tcw-border);\n}\n\n.tcw-cmd-empty {\n padding: 32px 16px;\n text-align: center;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size);\n}\n\n.tcw-cmd-footer {\n display: flex;\n align-items: center;\n gap: 18px;\n padding: 10px 18px;\n border-top: 1px solid var(--tcw-divider);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n background: var(--tcw-bg-surface);\n}\n\n/* === Watchlist === */\n\n.tcw-watchlist {\n width: 220px;\n flex-shrink: 0;\n background: var(--tcw-bg-surface);\n border-inline-start: 1px solid var(--tcw-border);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n box-shadow: var(--tcw-shadow-sm);\n}\n\n.tcw-watchlist-header {\n position: relative;\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 6px 8px 6px 8px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n/* The shown list's name: opens the lists menu. */\n.tcw-watchlist-name {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 6px;\n height: var(--tcw-control-h-sm);\n padding: 0 6px;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n text-align: start;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n}\n.tcw-watchlist-name::after {\n content: '';\n flex: none;\n width: 0;\n height: 0;\n margin-inline-start: auto;\n border: 4px solid transparent;\n border-top-color: currentColor;\n border-bottom-width: 0;\n opacity: 0.7;\n}\n\n.tcw-watchlist-add {\n flex: none;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-lg);\n line-height: 1;\n cursor: pointer;\n}\n\n.tcw-watchlist-name:hover,\n.tcw-watchlist-add:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n.tcw-watchlist-name:focus-visible,\n.tcw-watchlist-add:focus-visible,\n.tcw-watchlist-input:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* The lists menu, under the header. */\n.tcw-watchlist-menu {\n top: calc(100% - 2px);\n left: 6px;\n right: 6px;\n margin-top: 0;\n}\n.tcw-watchlist-count {\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n}\n.tcw-watchlist-menu .tcw-danger {\n color: var(--tcw-red);\n}\n\n/* Naming a list in place. */\n.tcw-watchlist-input {\n flex: 1;\n min-width: 0;\n height: var(--tcw-control-h-sm);\n padding: 0 8px;\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-watchlist-empty {\n padding: 16px 14px;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.5;\n}\n\n/* A row's remove button shows on hover or focus, over its numbers. */\n.tcw-watchlist-remove {\n position: absolute;\n top: 50%;\n right: 6px;\n display: grid;\n place-items: center;\n width: 20px;\n height: 20px;\n border: 0;\n border-radius: var(--tcw-radius-sm);\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size);\n line-height: 1;\n opacity: 0;\n transform: translateY(-50%);\n cursor: pointer;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-watchlist-row:hover .tcw-watchlist-remove,\n.tcw-watchlist-row:focus-within .tcw-watchlist-remove {\n opacity: 1;\n}\n.tcw-watchlist-remove:hover {\n color: var(--tcw-red);\n}\n.tcw-watchlist-row.tcw-watchlist-dragging {\n opacity: 0.45;\n}\n\n.tcw-watchlist-list {\n flex: 1;\n overflow-y: auto;\n padding: 4px 0;\n}\n\n.tcw-watchlist-row {\n position: relative;\n display: grid;\n grid-template-columns: 1fr auto auto;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n border-inline-start: 2px solid transparent;\n outline: none;\n}\n\n.tcw-watchlist-row:hover {\n background: var(--tcw-hover-bg);\n}\n\n.tcw-watchlist-row:focus-visible {\n background: var(--tcw-hover-bg);\n border-inline-start-color: var(--tcw-accent);\n}\n\n.tcw-watchlist-row.tcw-watchlist-active {\n background: var(--tcw-accent-soft);\n border-inline-start-color: var(--tcw-accent);\n}\n\n.tcw-watchlist-symbol {\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n letter-spacing: -0.005em;\n white-space: nowrap;\n}\n\n.tcw-watchlist-spark {\n width: 56px;\n height: 22px;\n align-self: center;\n}\n\n.tcw-watchlist-stats {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 1px;\n font-variant-numeric: tabular-nums;\n font-family: var(--tcw-font-mono);\n}\n\n.tcw-watchlist-price {\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n font-weight: var(--tcw-weight);\n}\n\n.tcw-watchlist-change {\n font-size: calc(var(--tcw-font-size) - 2.5px);\n color: var(--tcw-text-muted);\n font-weight: var(--tcw-weight);\n}\n\n.tcw-watchlist-change.tcw-up {\n color: var(--tcw-green);\n}\n\n.tcw-watchlist-change.tcw-down {\n color: var(--tcw-red);\n}\n\n@media (max-width: 768px) {\n .tcw-watchlist {\n display: none;\n }\n}\n\n/* === Toast === */\n\n.tcw-toast {\n position: absolute;\n bottom: 60px;\n left: 50%;\n transform: translate(-50%, 12px);\n z-index: 40;\n padding: 9px 14px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-toast-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n color: var(--tcw-text);\n opacity: 0;\n transition: opacity var(--tcw-dur-normal) var(--tcw-ease-out), transform var(--tcw-dur-normal) var(--tcw-ease-out);\n pointer-events: none;\n max-width: calc(100% - 32px);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n letter-spacing: -0.005em;\n}\n\n.tcw-toast.tcw-toast-in {\n opacity: 1;\n transform: translate(-50%, 0);\n}\n\n.tcw-toast-error {\n border-color: var(--tcw-red);\n color: var(--tcw-red);\n}\n\n/* === Replay scrubber === */\n\n/* Picking the replay start: the bars right of the pointer would be hidden. */\n.tcw-replay-shade {\n position: absolute;\n z-index: 4;\n pointer-events: none;\n background: color-mix(in srgb, var(--tcw-bg) 62%, transparent);\n border-inline-start: 1.5px dashed var(--tcw-accent);\n}\n\n.tcw-replay-group {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n\n.tcw-replay-group[hidden] { display: none; }\n\n.tcw-replay-hint {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 0 4px;\n color: var(--tcw-text-dim);\n white-space: nowrap;\n}\n\n.tcw-replay-text-btn {\n height: 26px;\n padding: 0 10px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-weight: var(--tcw-weight);\n white-space: nowrap;\n cursor: pointer;\n transition: background var(--tcw-dur-fast), border-color var(--tcw-dur-fast), color var(--tcw-dur-fast);\n}\n\n.tcw-replay-text-btn:hover { background: var(--tcw-hover-bg); border-color: var(--tcw-border-strong); }\n.tcw-replay-text-btn:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n\n/* At the last bar: the way out is the next thing to do. */\n.tcw-replay-bar--ended .tcw-replay-realtime {\n background: var(--tcw-accent);\n border-color: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n}\n\n.tcw-replay-btn:disabled { opacity: 0.4; cursor: default; }\n\n@media (max-width: 640px) {\n .tcw-replay-bar {\n flex-wrap: wrap;\n justify-content: center;\n max-width: calc(100% - 24px);\n border-radius: var(--tcw-panel-radius);\n }\n .tcw-replay-hint { white-space: normal; }\n}\n\n.tcw-replay-bar {\n position: absolute;\n left: 50%;\n /* Above the 30px time axis, so its dates stay readable. */\n bottom: 40px;\n transform: translateX(-50%);\n z-index: 25;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n animation: tcw-pop-in var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n.tcw-replay-btn {\n width: 28px;\n height: 28px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: transparent;\n color: var(--tcw-text-dim);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n font-family: inherit;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-replay-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-replay-btn.tcw-replay-play {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n width: 32px;\n height: 32px;\n box-shadow: 0 0 0 3px var(--tcw-accent-glow);\n}\n\n.tcw-replay-btn.tcw-replay-play:hover {\n background: var(--tcw-accent-hover);\n}\n\n.tcw-replay-scrubber {\n appearance: none;\n -webkit-appearance: none;\n width: 220px;\n height: 4px;\n background: var(--tcw-border-strong);\n border-radius: 2px;\n outline: none;\n cursor: pointer;\n}\n\n.tcw-replay-scrubber::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n}\n\n.tcw-replay-scrubber::-moz-range-thumb {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n}\n\n.tcw-replay-progress {\n font-size: var(--tcw-font-size-xs);\n font-family: var(--tcw-font-mono);\n color: var(--tcw-text-muted);\n min-width: 64px;\n text-align: center;\n font-feature-settings: 'tnum';\n}\n\n.tcw-replay-speed {\n padding: 4px 8px;\n font-size: var(--tcw-font-size-xs);\n font-family: var(--tcw-font-mono);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n color: var(--tcw-text-dim);\n cursor: pointer;\n}\n\n.tcw-replay-speed:hover {\n border-color: var(--tcw-border-strong);\n}\n\n@media (max-width: 640px) {\n .tcw-replay-scrubber {\n width: 140px;\n }\n .tcw-replay-progress {\n display: none;\n }\n}\n\n/* === Hotkey sheet === */\n\n.tcw-hotkey-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 24px 32px;\n}\n\n.tcw-hotkey-section .tcw-settings-section-title {\n margin-bottom: 8px;\n}\n\n.tcw-hotkey-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 6px 0;\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n.tcw-hotkey-row:last-child {\n border-bottom: none;\n}\n\n.tcw-hotkey-keys {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-shrink: 0;\n}\n\n.tcw-hotkey-sep {\n font-size: calc(var(--tcw-font-size) - 3px);\n color: var(--tcw-text-muted);\n}\n\n.tcw-hotkey-label {\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n text-align: end;\n letter-spacing: -0.005em;\n}\n\n@media (max-width: 640px) {\n .tcw-hotkey-grid {\n grid-template-columns: 1fr;\n gap: 18px;\n }\n}\n\n/* === Scrollbar (subtle, premium feel) === */\n\n.tcw-dropdown::-webkit-scrollbar,\n.tcw-modal-body::-webkit-scrollbar,\n.tcw-cmd-list::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n.tcw-dropdown::-webkit-scrollbar-track,\n.tcw-modal-body::-webkit-scrollbar-track,\n.tcw-cmd-list::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.tcw-dropdown::-webkit-scrollbar-thumb,\n.tcw-modal-body::-webkit-scrollbar-thumb,\n.tcw-cmd-list::-webkit-scrollbar-thumb {\n background: var(--tcw-border-strong);\n border-radius: 4px;\n border: 2px solid transparent;\n background-clip: padding-box;\n}\n\n.tcw-dropdown::-webkit-scrollbar-thumb:hover,\n.tcw-modal-body::-webkit-scrollbar-thumb:hover,\n.tcw-cmd-list::-webkit-scrollbar-thumb:hover {\n background: var(--tcw-text-muted);\n background-clip: padding-box;\n border: 2px solid transparent;\n}\n\n/* === Responsive === */\n\n@media (max-width: 768px) {\n .tcw-toolbar {\n padding: 0 4px;\n height: max(44px, var(--tcw-toolbar-h)); /* Apple HIG minimum touch target */\n }\n .tcw-toolbar-sep {\n display: none;\n }\n .tcw-btn,\n .tcw-dropdown-trigger {\n height: max(40px, var(--tcw-control-h)); /* fatter tap target */\n padding: 0 12px;\n font-size: var(--tcw-font-size);\n }\n .tcw-btn-icon {\n width: max(40px, var(--tcw-control-h));\n height: max(40px, var(--tcw-control-h));\n }\n .tcw-sidebar {\n width: max(44px, var(--tcw-sidebar-w));\n }\n .tcw-sidebar-btn {\n width: max(40px, var(--tcw-control-h));\n height: max(40px, var(--tcw-control-h));\n }\n .tcw-modal,\n .tcw-cmd-palette {\n width: 94vw;\n border-radius: var(--tcw-dialog-radius);\n }\n\n /* Hide the right-side watchlist on tablets too — already declared but\n * grouped here for clarity. */\n .tcw-watchlist {\n display: none;\n }\n\n /* Replay scrubber compact mode */\n .tcw-replay-scrubber {\n width: 120px;\n }\n .tcw-replay-progress {\n display: none;\n }\n}\n\n/* === Mobile bottom-sheet pattern ===\n * On phones, swap floating-centered modals for full-width sheets that slide\n * up from the bottom. Bigger hit targets, no awkward off-screen clipping,\n * matches how every modern iOS/Android app handles overflow UI.\n */\n@media (max-width: 640px) {\n .tcw-modal,\n .tcw-cmd-palette {\n top: auto;\n bottom: 0;\n left: 0;\n right: 0;\n transform: none;\n width: 100vw;\n max-width: 100vw;\n max-height: 92vh;\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 0 0;\n border-bottom: none;\n /* Grab handle */\n padding-top: 8px;\n }\n\n /* Visual \"grab handle\" affordance — a short pill at the top of every sheet */\n .tcw-modal::before,\n .tcw-cmd-palette::before {\n content: '';\n display: block;\n width: 36px;\n height: 4px;\n border-radius: 2px;\n background: var(--tcw-border-strong);\n margin: 0 auto 8px;\n opacity: 0.7;\n }\n\n /* Reuse the existing modal-in animation but slide from below instead of\n * popping from center, so the entrance reads as a sheet, not a dialog. */\n @keyframes tcw-modal-in {\n from { opacity: 0; transform: translateY(20px); }\n to { opacity: 1; transform: translateY(0); }\n }\n\n .tcw-modal,\n .tcw-cmd-palette {\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\n }\n\n /* Safe-area-aware footer padding for iPhone notch / home indicator */\n .tcw-modal-footer,\n .tcw-cmd-footer {\n padding-bottom: max(14px, env(safe-area-inset-bottom));\n }\n\n /* Larger tap targets inside sheets */\n .tcw-modal-tab {\n padding: 14px 16px;\n }\n .tcw-cmd-item {\n padding: 12px 14px;\n font-size: calc(var(--tcw-font-size) + 1px);\n }\n .tcw-dropdown-item {\n padding: 12px 12px;\n font-size: calc(var(--tcw-font-size) + 1px);\n }\n\n /* Hotkey sheet — single column on phones */\n .tcw-hotkey-grid {\n grid-template-columns: 1fr;\n }\n}\n\n/* === Price alerts panel === */\n\n.tcw-alerts-panel {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-end: 12px;\n z-index: 40;\n width: 300px;\n max-width: calc(100vw - 24px);\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n\n@keyframes tcw-alerts-in {\n from { opacity: 0; transform: translateY(-6px) scale(0.98); }\n to { opacity: 1; transform: none; }\n}\n\n.tcw-alerts-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 12px;\n font-weight: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n\n.tcw-alerts-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-alerts-close:hover {\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n}\n\n.tcw-alerts-form {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 8px;\n padding: 12px;\n border-bottom: 1px solid var(--tcw-border);\n}\n\n.tcw-alerts-form input,\n.tcw-alerts-form select {\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n height: 32px;\n padding: 0 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-sm);\n outline: none;\n}\n.tcw-alerts-form input:focus,\n.tcw-alerts-form select:focus {\n border-color: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n.tcw-alerts-message,\n.tcw-alerts-source {\n grid-column: 1 / -1;\n}\n\n.tcw-alerts-add {\n grid-column: 1 / -1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 34px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent-ink);\n background: var(--tcw-accent);\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-alerts-add:hover {\n background: var(--tcw-accent-hover);\n}\n\n.tcw-alerts-list {\n max-height: 260px;\n overflow-y: auto;\n padding: 6px;\n}\n\n.tcw-alerts-empty {\n padding: 18px 12px;\n text-align: center;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-muted);\n line-height: 1.5;\n}\n\n.tcw-alerts-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 8px 8px;\n border-radius: var(--tcw-radius-sm);\n}\n.tcw-alerts-row:hover {\n background: var(--tcw-bg-surface);\n}\n.tcw-alerts-triggered {\n background: var(--tcw-accent-soft);\n}\n\n.tcw-alerts-info {\n min-width: 0;\n}\n.tcw-alerts-row-main {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n font-variant-numeric: tabular-nums;\n}\n.tcw-alerts-row-note {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.tcw-alerts-badge {\n font-size: calc(var(--tcw-font-size) - 4px);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n padding: 2px 5px;\n border-radius: var(--tcw-tag-radius);\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n}\n\n.tcw-alerts-del {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-alerts-del:hover {\n background: var(--tcw-red-soft);\n color: var(--tcw-red);\n}\n\n@media (max-width: 640px) {\n .tcw-alerts-panel {\n top: auto;\n bottom: 0;\n left: 0;\n right: 0;\n width: 100vw;\n max-width: 100vw;\n border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;\n }\n .tcw-alerts-list {\n max-height: 40vh;\n padding-bottom: max(8px, env(safe-area-inset-bottom));\n }\n}\n\n/* === Data Window === */\n\n.tcw-datawin {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-end: 12px;\n z-index: 38;\n width: 200px;\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-datawin-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 9px 12px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-datawin-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-datawin-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\n.tcw-datawin-body { padding: 6px 4px; max-height: 360px; overflow-y: auto; }\n.tcw-datawin-empty { padding: 14px; text-align: center; font-size: var(--tcw-font-size-sm); color: var(--tcw-text-muted); }\n.tcw-datawin-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n padding: 3px 8px;\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-datawin-label { color: var(--tcw-text-muted); }\n.tcw-datawin-value { color: var(--tcw-text); font-variant-numeric: tabular-nums; font-weight: var(--tcw-weight-strong); }\n.tcw-datawin-value.tcw-up { color: var(--tcw-green); }\n.tcw-datawin-value.tcw-down { color: var(--tcw-red); }\n.tcw-datawin-sub {\n margin: 6px 8px 2px;\n font-size: calc(var(--tcw-font-size) - 3px);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n border-top: 1px solid var(--tcw-border);\n padding-top: 6px;\n}\n\n@media (max-width: 640px) {\n .tcw-datawin { top: auto; bottom: 0; left: 0; right: 0; width: 100vw; border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0; }\n}\n\n/* === Depth-of-market ladder === */\n\n.tcw-ladder {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-end: 12px;\n z-index: 41;\n width: 240px;\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-ladder-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 12px;\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-ladder-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-ladder-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\n.tcw-ladder-cols {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n padding: 4px 0;\n font-size: calc(var(--tcw-font-size) - 3px);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-ladder-cols span { text-align: center; }\n.tcw-ladder-body { max-height: 360px; overflow-y: auto; }\n.tcw-ladder-empty { padding: 18px; text-align: center; font-size: var(--tcw-font-size-sm); color: var(--tcw-text-muted); }\n\n.tcw-ladder-row {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n height: 22px;\n font-variant-numeric: tabular-nums;\n}\n.tcw-ladder-cell {\n position: relative;\n display: flex;\n align-items: center;\n border: none;\n background: transparent;\n font-size: var(--tcw-font-size-xs);\n cursor: pointer;\n font-variant-numeric: tabular-nums;\n overflow: hidden;\n}\n.tcw-ladder-cell:disabled { cursor: default; }\n/* Depth bar grows from the centre column outward. */\n.tcw-ladder-cell::before {\n content: '';\n position: absolute;\n top: 1px; bottom: 1px;\n width: var(--w, 0%);\n}\n.tcw-ladder-bid { justify-content: flex-end; padding-right: 8px; color: var(--tcw-green); }\n.tcw-ladder-bid::before { right: 0; background: var(--tcw-green-soft); }\n.tcw-ladder-bid span, .tcw-ladder-bid { position: relative; }\n.tcw-ladder-ask { justify-content: flex-start; padding-left: 8px; color: var(--tcw-red); }\n.tcw-ladder-ask::before { left: 0; background: var(--tcw-red-soft); }\n.tcw-ladder-cell:not(:disabled):hover::before { opacity: 0.7; filter: brightness(1.4); }\n.tcw-ladder-cell > * { position: relative; }\n.tcw-ladder-price {\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text-dim);\n border-inline-start: 1px solid var(--tcw-border);\n border-inline-end: 1px solid var(--tcw-border);\n}\n.tcw-ladder-price.tcw-ask { color: var(--tcw-red); }\n.tcw-ladder-price.tcw-bid { color: var(--tcw-green); }\n\n@media (max-width: 640px) {\n .tcw-ladder { top: auto; bottom: 0; left: 0; right: 0; width: 100vw; border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0; }\n .tcw-ladder-body { max-height: 45vh; padding-bottom: max(0px, env(safe-area-inset-bottom)); }\n}\n\n/* === Bracket order placement === */\n\n.tcw-btn-long:hover { color: var(--tcw-green) !important; }\n.tcw-btn-short:hover { color: var(--tcw-red) !important; }\n\n.tcw-bracket-bar {\n position: absolute;\n top: calc(var(--tcw-panel-top) + 2px);\n left: 50%;\n transform: translateX(-50%);\n z-index: 45;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 7px 8px 7px 14px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-bracket-label {\n font-size: var(--tcw-font-size-sm);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n}\n.tcw-bracket-label[data-side='buy'] { color: var(--tcw-green); }\n.tcw-bracket-label[data-side='sell'] { color: var(--tcw-red); }\n.tcw-bracket-hint {\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n.tcw-bracket-cancel, .tcw-bracket-confirm {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n height: 30px;\n padding: 0 12px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-bracket-cancel {\n color: var(--tcw-text-dim);\n background: var(--tcw-bg-surface);\n}\n.tcw-bracket-cancel:hover { color: var(--tcw-text); }\n.tcw-bracket-confirm {\n color: var(--tcw-accent-ink);\n background: var(--tcw-accent);\n}\n.tcw-bracket-confirm:hover { background: var(--tcw-accent-hover); }\n\n@media (max-width: 640px) {\n .tcw-bracket-bar { width: calc(100vw - 24px); justify-content: space-between; }\n .tcw-bracket-hint { display: none; }\n}\n\n/* === Drawing style + templates popover === */\n\n.tcw-style-panel {\n position: absolute;\n bottom: 12px;\n inset-inline-start: var(--tcw-panel-left);\n z-index: 40;\n width: 220px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-style-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-style-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-style-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\n\n.tcw-style-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.tcw-style-swatch {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 1px solid var(--tcw-border-strong);\n cursor: pointer;\n padding: 0;\n}\n.tcw-style-swatch.tcw-on { outline: 2px solid var(--tcw-accent); outline-offset: 1px; }\n.tcw-style-picker {\n width: 22px;\n height: 22px;\n padding: 0;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n cursor: pointer;\n}\n.tcw-style-width, .tcw-style-dash {\n flex: 1;\n min-width: 0;\n height: 26px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n color: var(--tcw-text-dim);\n cursor: pointer;\n font-size: var(--tcw-font-size-xs);\n}\n.tcw-style-width span { width: 16px; background: currentColor; border-radius: var(--tcw-radius-xs); }\n.tcw-style-width.tcw-on, .tcw-style-dash.tcw-on {\n border-color: var(--tcw-accent);\n color: var(--tcw-accent);\n}\n\n.tcw-style-subhead {\n font-size: calc(var(--tcw-font-size) - 3px);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n margin-top: 2px;\n}\n.tcw-style-save { display: flex; gap: 6px; }\n.tcw-style-name {\n flex: 1;\n min-width: 0;\n height: 28px;\n padding: 0 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n outline: none;\n}\n.tcw-style-name:focus { border-color: var(--tcw-accent); }\n.tcw-style-savebtn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 0 10px;\n height: 28px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent-ink);\n background: var(--tcw-accent);\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-style-savebtn:hover { background: var(--tcw-accent-hover); }\n\n.tcw-style-templates { display: flex; flex-direction: column; gap: 2px; max-height: 140px; overflow-y: auto; }\n.tcw-style-empty { font-size: var(--tcw-font-size-xs); color: var(--tcw-text-muted); padding: 4px 0; }\n.tcw-style-template { display: flex; align-items: center; gap: 4px; }\n.tcw-style-apply {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 5px 7px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n text-align: start;\n}\n.tcw-style-apply:hover { background: var(--tcw-bg-surface); }\n.tcw-style-tdot { flex-shrink: 0; width: 9px; height: 9px; border-radius: 50%; }\n.tcw-style-tdel {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-style-tdel:hover { background: var(--tcw-red-soft); color: var(--tcw-red); }\n\n/* === Settings range slider === */\n\n.tcw-settings-range {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.tcw-settings-range input[type='range'] {\n width: 110px;\n accent-color: var(--tcw-accent);\n cursor: pointer;\n}\n.tcw-settings-range-val {\n min-width: 38px;\n text-align: end;\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text-dim);\n}\n\n/* === Indicator settings dialog === */\n\n/* Narrow on a desktop; on a phone a sheet across the screen like every dialog. */\n@media (min-width: 641px) {\n .tcw-modal-narrow {\n max-width: 360px;\n }\n}\n.tcw-indi-input {\n width: 110px;\n height: 30px;\n padding: 0 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n outline: none;\n font-variant-numeric: tabular-nums;\n}\n.tcw-indi-input:focus {\n border-color: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n.tcw-indi-select {\n width: 150px;\n padding-right: 4px;\n cursor: pointer;\n}\n/* A level: its value and a remove button. */\n.tcw-indi-level {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n.tcw-indi-remove {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-indi-remove:hover {\n color: var(--tcw-red);\n background: var(--tcw-hover-bg);\n}\n.tcw-indi-remove:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n.tcw-indi-add {\n margin-top: 8px;\n}\n.tcw-indi-color {\n width: 36px;\n height: 28px;\n padding: 2px;\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-sm);\n cursor: pointer;\n}\n\n/* === Object tree panel === */\n\n.tcw-tree-panel {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-end: 12px;\n z-index: 39;\n width: 280px;\n max-width: calc(100vw - 24px);\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n\n.tcw-tree-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 12px;\n font-weight: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-tree-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-tree-close:hover {\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n}\n\n.tcw-tree-section {\n padding: 6px;\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-tree-section:last-child {\n border-bottom: none;\n}\n.tcw-tree-section-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 8px 4px;\n font-size: calc(var(--tcw-font-size) - 3px);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n}\n.tcw-tree-add {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-tree-add:hover {\n background: var(--tcw-accent-soft);\n color: var(--tcw-accent);\n}\n.tcw-tree-dot {\n flex-shrink: 0;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n.tcw-tree-list {\n max-height: 200px;\n overflow-y: auto;\n}\n\n.tcw-tree-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 6px 8px;\n border-radius: var(--tcw-radius-sm);\n}\n.tcw-tree-row:hover {\n background: var(--tcw-bg-surface);\n}\n.tcw-tree-hidden .tcw-tree-name {\n opacity: 0.5;\n}\n.tcw-tree-name {\n min-width: 0;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.tcw-tree-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-shrink: 0;\n}\n.tcw-tree-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-tree-btn:hover {\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text);\n}\n.tcw-tree-btn.tcw-tree-on {\n color: var(--tcw-accent);\n}\n.tcw-tree-btn.tcw-tree-del:hover {\n background: var(--tcw-red-soft);\n color: var(--tcw-red);\n}\n.tcw-tree-group .tcw-tree-name {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: var(--tcw-weight-strong);\n}\n.tcw-tree-group .tcw-tree-name svg {\n flex: none;\n color: var(--tcw-text-muted);\n}\n.tcw-tree-member {\n margin-left: 14px;\n padding-left: 10px;\n border-inline-start: 1px solid var(--tcw-border-strong);\n border-radius: 0 var(--tcw-radius-sm) var(--tcw-radius-sm) 0;\n}\n.tcw-tree-rename {\n flex: 1;\n min-width: 0;\n padding: 3px 6px;\n border: 1px solid var(--tcw-accent-line);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-tree-rename:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n.tcw-tree-empty {\n padding: 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-muted);\n}\n\n@media (max-width: 640px) {\n .tcw-tree-panel {\n top: auto;\n bottom: 0;\n left: 0;\n right: 0;\n width: 100vw;\n max-width: 100vw;\n border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;\n }\n .tcw-tree-list {\n max-height: 30vh;\n }\n .tcw-tree-section:last-child {\n padding-bottom: max(6px, env(safe-area-inset-bottom));\n }\n}\n\n/* === Reduced motion === */\n\n@media (prefers-reduced-motion: reduce) {\n .tcw-root *,\n .tcw-root *::before,\n .tcw-root *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n\n /* Except the loader's slow glow (opacity only): without it a long wait\n looks frozen. */\n .tcw-root .tcw-loading-candle,\n .tcw-root .tcw-loading-track > span {\n animation-duration: 2.4s !important;\n animation-iteration-count: infinite !important;\n animation-delay: var(--tcw-delay, 0ms) !important;\n }\n}\n\n/* --- Drawing settings dialog --- */\n.tcw-drawing-settings .tcw-modal-footer { gap: 12px; }\n.tcw-drawing-settings-tools {\n display: flex;\n gap: 14px;\n margin-inline-end: auto;\n}\n.tcw-drawing-text {\n min-height: 56px;\n resize: vertical;\n font-family: inherit;\n}\n.tcw-levels-editor { display: grid; gap: 6px; margin-bottom: 10px; }\n.tcw-levels-grid {\n display: grid;\n gap: 4px;\n max-height: 260px;\n overflow-y: auto;\n padding-right: 2px;\n}\n.tcw-level-row {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) 32px 24px;\n align-items: center;\n gap: 8px;\n}\n.tcw-level-row input[type='checkbox'] { accent-color: var(--tcw-accent); }\n.tcw-level-remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: 0;\n border-radius: var(--tcw-radius-sm, 4px);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-level-remove:hover { color: var(--tcw-text); background: var(--tcw-bg-elevated); }\n.tcw-level-remove:focus-visible { outline: 2px solid var(--tcw-accent); outline-offset: 1px; }\n.tcw-level-add { justify-self: start; }\n.tcw-drawing-templates { display: grid; gap: 2px; margin-bottom: 8px; }\n.tcw-drawing-alert { display: inline-flex; align-items: center; gap: 6px; }\n\n/* --- Context menu (right-click on a drawing) --- */\n.tcw-context-menu {\n position: absolute;\n z-index: 70;\n min-width: 200px;\n padding: 4px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-divider);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n}\n.tcw-context-item {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n min-height: var(--tcw-menu-item-h);\n padding: 4px 10px;\n border: 0;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size);\n text-align: start;\n cursor: pointer;\n}\n.tcw-context-item svg, .tcw-context-icon { flex: none; width: 14px; height: 14px; color: var(--tcw-text-muted); }\n.tcw-context-item:hover, .tcw-context-item:focus-visible { background: var(--tcw-bg-surface); outline: none; }\n.tcw-context-item:focus-visible { box-shadow: inset 0 0 0 1px var(--tcw-accent); }\n.tcw-context-danger, .tcw-context-danger svg { color: var(--tcw-red); }\n.tcw-context-sep { height: 1px; margin: 4px 6px; background: var(--tcw-divider); }\n/* --- Toolbar over a selected drawing --- */\n.tcw-sel-toolbar {\n position: absolute;\n z-index: 65;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 3px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-divider);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-family: var(--tcw-font);\n white-space: nowrap;\n animation: tcw-sel-in var(--tcw-dur-fast) var(--tcw-ease-out);\n}\n@keyframes tcw-sel-in { from { opacity: 0; transform: translateY(3px); } }\n.tcw-sel-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n min-width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n padding: 0 6px;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-sel-btn svg { flex: none; }\n.tcw-sel-btn:hover, .tcw-sel-btn[aria-expanded=\"true\"] { background: var(--tcw-hover-bg); color: var(--tcw-text); }\n.tcw-sel-btn:focus-visible, .tcw-sel-swatch:focus-visible, .tcw-sel-option:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--tcw-accent); }\n.tcw-sel-btn.tcw-sel-on { color: var(--tcw-accent); background: var(--tcw-accent-soft); }\n.tcw-sel-danger:hover { color: var(--tcw-red); background: var(--tcw-red-soft); }\n.tcw-sel-color {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tcw-text) 25%, transparent);\n}\n.tcw-sel-width {\n display: inline-block;\n width: 16px;\n height: var(--w, 1px);\n max-height: 6px;\n border-radius: 1px;\n background: currentColor;\n}\n.tcw-sel-sep { flex: none; width: 1px; height: 18px; margin: 0 3px; background: var(--tcw-divider); }\n.tcw-sel-pop {\n position: absolute;\n z-index: 66;\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 120px;\n padding: 4px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-divider);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-family: var(--tcw-font);\n}\n.tcw-sel-pop--color {\n display: grid;\n grid-template-columns: repeat(4, 24px);\n gap: 6px;\n min-width: 0;\n padding: 8px;\n}\n.tcw-sel-swatch {\n width: 24px;\n height: 24px;\n padding: 0;\n border: 0;\n border-radius: 50%;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tcw-text) 20%, transparent);\n cursor: pointer;\n transition: transform var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-sel-swatch:hover { transform: scale(1.1); }\n.tcw-sel-swatch.tcw-sel-on { box-shadow: 0 0 0 2px var(--tcw-bg-elevated), 0 0 0 4px var(--tcw-accent); }\n.tcw-sel-option {\n display: flex;\n align-items: center;\n gap: 10px;\n min-height: var(--tcw-menu-item-h);\n padding: 4px 10px;\n border: 0;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n text-align: start;\n cursor: pointer;\n}\n.tcw-sel-option:hover { background: var(--tcw-bg-surface); }\n.tcw-sel-option.tcw-sel-on { color: var(--tcw-accent); }\n@media (prefers-reduced-motion: reduce) {\n .tcw-sel-toolbar { animation: none; }\n .tcw-sel-swatch { transition: none; }\n}\n\n/* --- Account panel (positions, orders, history) --- */\n.tcw-account-dock {\n flex: none;\n}\n.tcw-account {\n display: flex;\n flex-direction: column;\n height: 220px;\n border-top: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n}\n.tcw-account-head {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 8px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n.tcw-account-tabs {\n display: flex;\n gap: 2px;\n flex: 1;\n min-width: 0;\n overflow-x: auto;\n}\n.tcw-account-tab {\n padding: 6px 10px;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n white-space: nowrap;\n cursor: pointer;\n}\n.tcw-account-tab:hover { color: var(--tcw-text); background: var(--tcw-hover-bg); }\n.tcw-account-tab[aria-selected=\"true\"] { color: var(--tcw-text); background: var(--tcw-active-bg); }\n.tcw-account-tab:focus-visible, .tcw-account-new:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--tcw-accent); }\n.tcw-account-new {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 10px;\n border: 1px solid var(--tcw-accent-line);\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-accent-soft);\n color: var(--tcw-accent);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n cursor: pointer;\n}\n.tcw-account-new:hover { background: var(--tcw-accent-glow); }\n.tcw-account-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n}\n.tcw-account-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n}\n.tcw-account-table th {\n position: sticky;\n top: 0;\n padding: 6px 10px;\n background: var(--tcw-bg-surface);\n color: var(--tcw-text-muted);\n font-weight: var(--tcw-weight);\n text-align: start;\n border-bottom: 1px solid var(--tcw-divider);\n}\n.tcw-account-table td {\n padding: 5px 10px;\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-divider);\n white-space: nowrap;\n}\n.tcw-account-table tr:hover td { background: var(--tcw-hover-bg); }\n.tcw-account-side { font-weight: var(--tcw-weight-strong); }\n.tcw-account-buy, .tcw-account-up { color: var(--tcw-green); }\n.tcw-account-sell, .tcw-account-down { color: var(--tcw-red); }\n.tcw-account-actions { display: flex; gap: 2px; }\n.tcw-account-empty, .tcw-account-summary {\n margin: 0;\n padding: 14px 12px;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-account-summary { padding: 8px 12px; color: var(--tcw-text-dim); }\n@media (max-width: 640px) {\n .tcw-account { height: 45vh; }\n}\n\n/* --- Order ticket --- */\n.tcw-ticket-side {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 6px;\n margin-bottom: 12px;\n}\n.tcw-ticket-side-btn {\n padding: 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n}\n.tcw-ticket-buy[aria-pressed=\"true\"] { background: var(--tcw-green-soft); border-color: var(--tcw-green); color: var(--tcw-green); }\n.tcw-ticket-sell[aria-pressed=\"true\"] { background: var(--tcw-red-soft); border-color: var(--tcw-red); color: var(--tcw-red); }\n.tcw-ticket-side-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--tcw-accent-soft); }\n.tcw-ticket-optional { display: flex; align-items: center; gap: 8px; }\n.tcw-ticket-optional > span { flex: 1; }\n.tcw-ticket-optional .tcw-indi-input { width: 110px; }\n.tcw-ticket-problems {\n min-height: 18px;\n padding: 0 22px 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-ticket-problems p { margin: 2px 0; }\n.tcw-ticket-problems.tcw-ticket-bad { color: var(--tcw-red); }\n.tcw-done-btn.tcw-ticket-sell { background: var(--tcw-red); color: #fff; }\n.tcw-done-btn:disabled { opacity: 0.45; cursor: not-allowed; }\n\n/* --- Named layouts --- */\n.tcw-layouts-btn { max-width: 190px; }\n.tcw-layouts-label {\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n.tcw-layouts-dirty {\n width: 6px;\n height: 6px;\n flex: none;\n border-radius: 50%;\n background: var(--tcw-accent);\n}\n.tcw-name-field { display: flex; flex-direction: column; gap: 6px; font-size: var(--tcw-font-size-sm); color: var(--tcw-text-dim); }\n.tcw-name-field .tcw-indi-input { width: 100%; height: 34px; font-size: var(--tcw-font-size); }\n.tcw-layouts-body { display: flex; flex-direction: column; gap: 10px; }\n.tcw-layouts-search { width: 100%; height: 32px; }\n.tcw-layouts-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n max-height: 50vh;\n overflow-y: auto;\n}\n.tcw-layouts-row {\n display: flex;\n align-items: center;\n gap: 6px;\n border-radius: var(--tcw-radius);\n}\n.tcw-layouts-row:hover { background: var(--tcw-hover-bg); }\n.tcw-layouts-open {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n padding: 7px 8px;\n border: none;\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n text-align: start;\n cursor: pointer;\n border-radius: var(--tcw-radius);\n}\n.tcw-layouts-open:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--tcw-accent-soft); }\n.tcw-layouts-name {\n display: flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.tcw-layouts-open[aria-current=\"true\"] .tcw-layouts-name { color: var(--tcw-accent); }\n.tcw-layouts-meta {\n max-width: 100%;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n font-variant-numeric: tabular-nums;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.tcw-layouts-confirm {\n padding: 4px 10px;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-red);\n color: #fff;\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n}\n.tcw-layouts-confirm:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--tcw-red-soft); }\n\n/* --- Chart grid --- */\n.tcw-grid { background: var(--tcw-bg); }\n.tcw-grid-bar {\n display: flex;\n align-items: center;\n gap: 6px;\n min-height: calc(var(--tcw-control-h) + 8px);\n padding: 0 8px;\n border-bottom: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n overflow-x: auto;\n scrollbar-width: none;\n}\n.tcw-grid-bar::-webkit-scrollbar { display: none; }\n.tcw-grid-group { display: flex; align-items: center; gap: 2px; flex: none; }\n.tcw-grid-label {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-right: 4px;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n letter-spacing: var(--tcw-label-tracking);\n text-transform: var(--tcw-label-case);\n color: var(--tcw-text-muted);\n}\n.tcw-grid-sync[aria-pressed=\"true\"] { color: var(--tcw-accent); }\n.tcw-grid-cells {\n flex: 1;\n min-height: 0;\n display: grid;\n gap: 1px;\n background: var(--tcw-border);\n}\n.tcw-grid-cell {\n position: relative;\n min-width: 0;\n min-height: 0;\n background: var(--tcw-bg);\n}\n.tcw-grid-cell-active::after {\n content: '';\n position: absolute;\n inset: 0;\n border: 1px solid var(--tcw-accent);\n pointer-events: none;\n z-index: 5;\n}\n\n/* --- Host toolbar buttons --- */\n.tcw-toolbar-host { display: inline-flex; align-items: center; gap: 2px; }\n.tcw-toolbar-host:empty { display: none; }\n.tcw-host-btn { display: inline-flex; align-items: center; gap: 4px; }\n\n/* --- Host sidebar buttons, status bar items, and the layer over the chart --- */\n.tcw-sidebar-host { display: flex; flex-direction: column; align-items: center; }\n.tcw-sidebar-host:empty { display: none; }\n.tcw-status-host { display: flex; align-items: center; gap: 10px; min-width: 0; }\n.tcw-status-host:empty { display: none; }\n.tcw-status-host-item { white-space: nowrap; }\n.tcw-status-host-btn {\n margin: -4px -6px;\n padding: 4px 6px;\n font: inherit;\n color: inherit;\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-status-host-btn:hover { color: var(--tcw-text); background: var(--tcw-hover-bg); }\n.tcw-status-host-btn:focus-visible { outline: 2px solid var(--tcw-accent); outline-offset: -2px; }\n/* Over the plot and under the widget's own overlays; the pointer reaches the chart unless an element of yours takes it. */\n.tcw-host-layer { position: absolute; inset: 0; z-index: 2; pointer-events: none; }\n\n/* --- Pane buttons (move, fold, maximise) --- */\n.tcw-pane-controls {\n position: absolute;\n z-index: 4;\n display: flex;\n gap: 1px;\n transform: translateX(-100%);\n padding: 1px;\n border-radius: var(--tcw-radius-sm);\n background: color-mix(in srgb, var(--tcw-bg) 80%, transparent);\n opacity: 0.55;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-pane-controls:hover,\n.tcw-pane-controls:focus-within { opacity: 1; }\n.tcw-pane-btn {\n display: inline-grid;\n place-items: center;\n width: 18px;\n height: 16px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-pane-btn:hover { color: var(--tcw-text); background: var(--tcw-hover-bg); }\n.tcw-pane-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--tcw-accent-soft); }\n\n/* --- Typed interval --- */\n.tcw-interval-input {\n position: absolute;\n z-index: 20;\n left: 50%;\n top: 40%;\n transform: translate(-50%, -50%);\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 12px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-lg, 10px);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n.tcw-interval-field {\n width: 150px;\n height: 36px;\n padding: 0 10px;\n font: inherit;\n font-size: calc(var(--tcw-font-size) + 5px);\n font-weight: var(--tcw-weight-strong);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-accent);\n border-radius: var(--tcw-input-radius);\n outline: none;\n}\n.tcw-interval-field[aria-invalid] { border-color: var(--tcw-red); }\n.tcw-interval-hint { font-size: var(--tcw-font-size-xs); color: var(--tcw-text-muted); max-width: 170px; }\n\n/* --- Alerts: lines, moves, bar close, expiry --- */\n.tcw-alerts-source { grid-column: auto; }\n.tcw-alerts-row-fields {\n grid-column: 1 / -1;\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 8px;\n}\n.tcw-alerts-row-fields[hidden] { display: none; }\n.tcw-alerts-row-fields > input[hidden] { display: none; }\n.tcw-alerts-row-fields:has(> input[hidden]) { grid-template-columns: 1fr; }\n.tcw-alerts-options { align-items: center; }\n.tcw-alerts-form .tcw-alerts-check {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-alerts-form .tcw-alerts-check input { width: auto; height: auto; }\n.tcw-alerts-form input[aria-invalid=\"true\"] { border-color: var(--tcw-red); }\n.tcw-alerts-row-meta { margin-top: 2px; font-size: var(--tcw-font-size-xs); color: var(--tcw-text-muted); }\n.tcw-alerts-expired { opacity: 0.6; }\n\n/* --- Signal marker note --- */\n.tcw-marker-tip {\n position: absolute;\n z-index: 12;\n pointer-events: none;\n padding: 6px 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-tooltip-radius);\n background: var(--tcw-tooltip-bg);\n color: var(--tcw-tooltip-fg);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.45;\n font-variant-numeric: tabular-nums;\n box-shadow: var(--tcw-menu-shadow);\n max-width: 240px;\n}\n.tcw-marker-tip strong { display: block; font-size: var(--tcw-font-size-sm); }\n\n/* === Navigation over the chart ===\n * Centred on the plot's bottom edge, shown while a mouse is over the chart. */\n.tcw-nav {\n position: absolute;\n z-index: 15;\n display: flex;\n gap: 2px;\n padding: 3px;\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: calc(var(--tcw-control-radius) + 3px);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n opacity: 0;\n pointer-events: none;\n transform: translate(-50%, calc(-100% - 12px));\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-nav.tcw-nav-shown {\n opacity: 1;\n pointer-events: auto;\n}\n.tcw-nav-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n cursor: pointer;\n touch-action: none;\n}\n.tcw-nav-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n.tcw-nav-btn:active {\n background: var(--tcw-active-bg);\n}\n.tcw-nav-btn:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n.tcw-nav-btn svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n@media (hover: none) {\n .tcw-nav { display: none; }\n}\n\n/* === Symbol info ===\n * Top left, beside the drawing tools: the panels on the right stay clear. */\n.tcw-syminfo {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-start: var(--tcw-panel-left);\n z-index: 38;\n width: 288px;\n max-height: calc(100% - var(--tcw-panel-top) - 12px);\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-syminfo-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 9px 12px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-syminfo-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-syminfo-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\n.tcw-syminfo-body,\n.tcw-syminfo-news {\n padding: 12px 14px;\n overflow-y: auto;\n}\n.tcw-syminfo-body {\n display: grid;\n gap: 10px;\n}\n.tcw-syminfo-symbol {\n font-size: var(--tcw-font-size-lg);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-syminfo-desc {\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-syminfo-meta {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n.tcw-syminfo-quote {\n display: flex;\n align-items: baseline;\n gap: 10px;\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n}\n.tcw-syminfo-price {\n font-size: calc(var(--tcw-font-size) + 7px);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-syminfo-change { font-size: var(--tcw-font-size-sm); }\n.tcw-syminfo-change.tcw-up { color: var(--tcw-green); }\n.tcw-syminfo-change.tcw-down { color: var(--tcw-red); }\n.tcw-syminfo-status {\n display: flex;\n align-items: center;\n gap: 7px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-syminfo-status::before,\n.tcw-status-market::before {\n content: '';\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n}\n.tcw-syminfo-status[data-state='open']::before,\n.tcw-syminfo-status[data-state='always']::before,\n.tcw-status-market[data-state='open']::before {\n background: var(--tcw-green);\n}\n.tcw-syminfo-stats {\n display: grid;\n gap: 4px;\n margin: 0;\n padding-top: 10px;\n border-top: 1px solid var(--tcw-divider);\n}\n.tcw-syminfo-stat {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-syminfo-stat dt { color: var(--tcw-text-muted); }\n.tcw-syminfo-stat dd {\n margin: 0;\n color: var(--tcw-text);\n text-align: end;\n font-variant-numeric: tabular-nums;\n overflow-wrap: anywhere;\n}\n.tcw-syminfo-news {\n border-top: 1px solid var(--tcw-divider);\n}\n.tcw-syminfo-news-title {\n margin-bottom: 8px;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text-muted);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n.tcw-syminfo-news-list {\n display: grid;\n gap: 10px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.tcw-syminfo-news-item {\n font-size: var(--tcw-font-size-sm);\n line-height: 1.4;\n color: var(--tcw-text);\n}\n.tcw-syminfo-news-item a {\n color: var(--tcw-text);\n text-decoration: none;\n}\n.tcw-syminfo-news-item a:hover { color: var(--tcw-accent); text-decoration: underline; }\n.tcw-syminfo-news-item a:focus-visible { outline: none; box-shadow: var(--tcw-ring); border-radius: var(--tcw-radius-xs); }\n.tcw-syminfo-news-meta,\n.tcw-syminfo-news-note {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n\n/* Numbers keep their sign on the left, and mixed text its own order, in a right-to-left widget too. */\n.tcw-watchlist-price,\n.tcw-watchlist-change,\n.tcw-syminfo-price,\n.tcw-syminfo-change {\n unicode-bidi: isolate;\n direction: ltr;\n}\n.tcw-syminfo-desc,\n.tcw-syminfo-meta,\n.tcw-syminfo-status,\n.tcw-syminfo-stat dd,\n.tcw-syminfo-news-meta {\n unicode-bidi: plaintext;\n}\n\n/* The market's status in the status bar. */\n.tcw-status-market {\n display: flex;\n align-items: center;\n gap: 7px;\n color: var(--tcw-text-muted);\n}\n\n@media (max-width: 640px) {\n .tcw-syminfo {\n top: auto;\n bottom: 0;\n left: 0;\n right: 0;\n width: 100vw;\n max-height: 70%;\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 0 0;\n }\n}\n\n/* === The look: how chosen controls show, floating bars, segmented intervals ===\n * Each switch sets variables on its own root, which its parts read: a grid's\n * look never reaches into a chart that has one of its own. */\n\n/* A chosen button (`ui.active`): a tinted fill (default), a solid pill, or an underline.\n * Dialog tabs are chips, or underlined in the underline look. Panels sit below the\n * toolbar and beside the drawing tools. */\n.tcw-root {\n --tcw-on-bg: var(--tcw-accent-soft);\n --tcw-on-fg: var(--tcw-accent);\n --tcw-on-ring: none;\n --tcw-on-icon-bg: var(--tcw-accent-soft);\n --tcw-on-icon-fg: var(--tcw-accent);\n --tcw-on-icon-ring: none;\n --tcw-tabs-pad-block: 8px;\n --tcw-tab-h: var(--tcw-control-h);\n --tcw-tab-pad: 0 12px;\n --tcw-tab-line: 0px;\n --tcw-tab-radius: var(--tcw-control-radius);\n --tcw-tab-hover: var(--tcw-hover-bg);\n --tcw-tab-on-bg: var(--tcw-on-bg);\n --tcw-tab-on-fg: var(--tcw-on-fg);\n --tcw-panel-top: calc(var(--tcw-toolbar-h) + 6px);\n --tcw-panel-left: calc(var(--tcw-sidebar-w) + 12px);\n}\n.tcw-root[data-tcw-active='solid'] {\n --tcw-on-bg: var(--tcw-text);\n --tcw-on-fg: var(--tcw-bg);\n --tcw-on-icon-bg: var(--tcw-text);\n --tcw-on-icon-fg: var(--tcw-bg);\n}\n.tcw-root[data-tcw-active='underline'] {\n --tcw-on-bg: var(--tcw-active-bg);\n --tcw-on-fg: var(--tcw-text);\n --tcw-on-ring: inset 0 -2px 0 var(--tcw-accent);\n --tcw-on-icon-bg: var(--tcw-active-bg);\n --tcw-on-icon-fg: var(--tcw-accent);\n --tcw-on-icon-ring: inset 2px 0 0 var(--tcw-accent);\n --tcw-tabs-pad-block: 0px;\n --tcw-tab-h: auto;\n --tcw-tab-pad: 11px 14px;\n --tcw-tab-line: 2px;\n --tcw-tab-radius: 0px;\n --tcw-tab-hover: transparent;\n --tcw-tab-on-bg: transparent;\n --tcw-tab-on-fg: var(--tcw-accent);\n}\n.tcw-root[data-tcw-toolbar='floating'] {\n --tcw-panel-top: calc(var(--tcw-toolbar-h) + 2 * var(--tcw-border-w) + 14px);\n}\n.tcw-root[data-tcw-sidebar='floating'] {\n --tcw-panel-left: calc(var(--tcw-sidebar-w) + 2 * var(--tcw-border-w) + 22px);\n}\n\n/* The toolbar as an island (`ui.toolbar: 'floating'`). */\n.tcw-root[data-tcw-toolbar='floating'] > .tcw-toolbar {\n margin: 8px 10px 0;\n padding-inline: calc(min(var(--tcw-toolbar-radius), var(--tcw-toolbar-h) / 2) / 2 + 8px);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-toolbar-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n/* The drawing tools as an island (`ui.sidebar: 'floating'`). */\n.tcw-root[data-tcw-sidebar='floating'] > .tcw-body > .tcw-sidebar {\n align-self: flex-start;\n max-height: calc(100% - 20px);\n margin: 10px 6px 10px 10px;\n padding-block: calc(min(var(--tcw-sidebar-radius), var(--tcw-sidebar-w) / 2) / 2 + 6px);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-sidebar-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n/* Frosted menus (`ui.blur` above 0): the chart shows through, blurred. */\n@supports (background: color-mix(in srgb, red 50%, transparent)) {\n .tcw-dropdown,\n .tcw-flyout,\n .tcw-context-menu {\n background: color-mix(in srgb, var(--tcw-bg-elevated) var(--tcw-surface-opacity), transparent);\n }\n}\n\n/* The interval buttons in one track (`ui.intervals: 'segmented'`). */\n.tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group {\n gap: 2px;\n margin: 0 4px;\n padding: 3px;\n border-radius: calc(var(--tcw-control-radius) + 3px);\n background: var(--tcw-hover-bg);\n}\n.tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group .tcw-btn {\n height: calc(var(--tcw-control-h) - 6px);\n padding: 0 9px;\n}\n\n/* Phones: the variants keep comfortable tap targets and room for the bar. */\n@media (max-width: 768px) {\n .tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group .tcw-btn {\n height: max(34px, calc(var(--tcw-control-h) - 6px));\n padding: 0 10px;\n }\n .tcw-root[data-tcw-toolbar='floating'] > .tcw-toolbar {\n margin: 6px 6px 0;\n padding-inline: 4px;\n }\n .tcw-root[data-tcw-sidebar='floating'] > .tcw-body > .tcw-sidebar {\n margin: 6px 4px 6px 6px;\n }\n}\n", O = /* @__PURE__ */ "toolbar,sidebar,statusBar,alerts,objectTree,symbolInfo,symbolSearch,settings,indicatorSettings,drawingSettings,dataWindow,commandPalette,hotkeySheet,goToDate,replay,screenshot,copyImage,shareView,autoFib,themeToggle,fullscreen,accountPanel,orderTicket,bracketOrders,depthLadder,layouts,indicatorTemplates,compare,indicatorLegend,navigation,customTimeframes,intervalTyping,dragDropImport,hotkeys,toasts,toolbar.symbol,toolbar.symbolInfo,toolbar.timeframes,toolbar.timeframeMenu,toolbar.chartType,toolbar.indicators,toolbar.layouts,toolbar.replay,toolbar.bracketOrders,toolbar.depthLadder,toolbar.accountPanel,toolbar.objectTree,toolbar.alerts,toolbar.screenshot,toolbar.settings,toolbar.themeToggle,toolbar.fullscreen,sidebar.cursor,sidebar.favorites,sidebar.lines,sidebar.fibonacci,sidebar.patterns,sidebar.forecasting,sidebar.annotation,sidebar.style,sidebar.magnet,sidebar.eraser,sidebar.zoomArea,sidebar.stayInDrawing,sidebar.undo,sidebar.redo,sidebar.clear,statusBar.range,statusBar.goToDate,statusBar.market,statusBar.connection,statusBar.symbol,indicatorLegend.values,indicatorLegend.visibility,indicatorLegend.settings,indicatorLegend.remove,indicatorLegend.more,pane.move,pane.collapse,pane.maximize,navigation.zoom,navigation.scroll,navigation.reset,menu.chart,menu.chart.alert,menu.chart.order,menu.chart.orderTicket,menu.chart.horizontalLine,menu.chart.resetView,menu.chart.drawings,menu.chart.exportData,menu.chart.settings,menu.chart.scale,menu.chart.goToDate,menu.chart.paneScale,menu.priceAxisAdd,menu.drawing,menu.drawing.settings,menu.drawing.alert,menu.drawing.order,menu.drawing.group,menu.drawing.lock,menu.drawing.hide,menu.drawing.duplicate,menu.drawing.delete,selectionToolbar,hotkeys.commandPalette,hotkeys.symbolSearch,hotkeys.save,hotkeys.tools,hotkeys.invertScale,hotkeys.goToDate,hotkeys.help".split(","), Je = new Set(O), Ye = {
|
|
1462
|
+
var Ze = [...new Set([...Object.keys(g).filter((e) => e.startsWith("series.")), ...[...Ke, ...qe].flatMap((e) => e.rows.flatMap((e) => e.keys))])], Qe = "/* === TradeCanvas Widget — Premium Styles === */\n\n/*\n * The HTML `hidden` attribute only sets `display: none` via the UA stylesheet,\n * which any author `display` rule (e.g. `.tcw-alerts-panel { display: flex }`)\n * silently overrides — leaving panels stuck open when JS sets `el.hidden = true`.\n * Force `hidden` to win for every namespaced widget element. Scoped to `tcw-`\n * so it never touches the host page.\n */\n[class^=\"tcw-\"][hidden],\n[class*=\" tcw-\"][hidden] {\n display: none !important;\n}\n\n/* Control tooltips (WidgetTooltip): quick to appear, slide in from the control. */\n.tcw-tooltip {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 60;\n max-width: 240px;\n padding: 5px 8px;\n border-radius: var(--tcw-tooltip-radius);\n background: var(--tcw-tooltip-bg);\n color: var(--tcw-tooltip-fg);\n box-shadow: var(--tcw-tooltip-shadow);\n width: max-content;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight);\n line-height: 1.35;\n overflow-wrap: anywhere;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transform: translate(var(--tcw-tip-dx, 0), var(--tcw-tip-dy, 0));\n transition:\n opacity 110ms var(--tcw-ease-out),\n transform 110ms var(--tcw-ease-out),\n visibility 0s linear 110ms;\n}\n\n.tcw-tooltip--visible {\n opacity: 1;\n visibility: visible;\n transform: none;\n transition:\n opacity 110ms var(--tcw-ease-out),\n transform 110ms var(--tcw-ease-out),\n visibility 0s;\n}\n\n/* The modal portal: carries the tokens and fonts, but no box of its own. */\n.tcw-root.tcw-portal {\n display: contents;\n}\n\n/* Fullscreen: the root fills the screen; the chart resizes with it. */\n.tcw-root:fullscreen {\n width: 100vw;\n height: 100vh;\n}\n\n.tcw-root {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n font-family: var(--tcw-font);\n font-feature-settings: 'cv11', 'ss01', 'ss03';\n font-size: var(--tcw-font-size);\n line-height: 1.4;\n color: #d9dde4;\n background: #080b10;\n position: relative;\n overflow: hidden;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n /* --- Dark theme tokens (default) --- */\n --tcw-bg: #080b10;\n --tcw-bg-surface: #0c1016;\n --tcw-bg-elevated: #141922;\n --tcw-bg-overlay: rgba(20, 25, 34, 0.5);\n --tcw-border: #1f2630;\n --tcw-border-strong: #2a323e;\n --tcw-tooltip-bg: #262e3a;\n --tcw-tooltip-fg: #eef0f4;\n --tcw-text: #e7e9ee;\n --tcw-text-dim: #aab1bd;\n --tcw-text-muted: #758091;\n\n /* TradeCanvas amber. --tcw-accent-ink is the text colour on an accent fill. */\n --tcw-accent: #f2a93b;\n --tcw-accent-hover: #f5b95c;\n --tcw-accent-ink: #1a1204;\n --tcw-accent-soft: rgba(242, 169, 59, 0.14);\n --tcw-accent-glow: rgba(242, 169, 59, 0.22);\n --tcw-accent-line: rgba(242, 169, 59, 0.55);\n\n --tcw-red: #e8505b;\n --tcw-red-soft: rgba(232, 80, 91, 0.12);\n --tcw-green: #1fa874;\n --tcw-green-soft: rgba(31, 168, 116, 0.12);\n --tcw-amber: #ff9f43;\n\n --tcw-hover-bg: rgba(255, 255, 255, 0.05);\n --tcw-active-bg: rgba(255, 255, 255, 0.08);\n --tcw-divider: rgba(255, 255, 255, 0.06);\n\n /* Motion */\n --tcw-ease: cubic-bezier(0.2, 0, 0, 1);\n --tcw-ease-out: cubic-bezier(0.16, 1, 0.3, 1);\n --tcw-dur-fast: 120ms;\n --tcw-dur-normal: 180ms;\n --tcw-dur-slow: 260ms;\n\n /* The look (UI system): Studio's values. The `ui` option sets them inline. */\n --tcw-radius-xs: 3px;\n --tcw-radius-sm: 5px;\n --tcw-radius: 7px;\n --tcw-radius-lg: 11px;\n --tcw-radius-xl: 16px;\n --tcw-control-radius: var(--tcw-radius);\n --tcw-input-radius: var(--tcw-radius);\n --tcw-menu-radius: var(--tcw-radius-lg);\n --tcw-dialog-radius: var(--tcw-radius-xl);\n --tcw-panel-radius: var(--tcw-radius-lg);\n --tcw-tooltip-radius: var(--tcw-radius-sm);\n --tcw-tag-radius: var(--tcw-radius-sm);\n --tcw-toast-radius: var(--tcw-radius-lg);\n --tcw-toolbar-radius: 0px;\n --tcw-sidebar-radius: 0px;\n --tcw-toolbar-h: 46px;\n --tcw-control-h: 30px;\n --tcw-control-h-sm: 24px;\n --tcw-icon: 18px;\n --tcw-sidebar-w: 48px;\n --tcw-menu-item-h: 30px;\n --tcw-font: 'Manrope', 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n --tcw-font-size: 13px;\n --tcw-font-size-sm: 12px;\n --tcw-font-size-xs: 11px;\n --tcw-font-size-lg: 15px;\n --tcw-weight: 500;\n --tcw-weight-strong: 600;\n --tcw-label-case: none;\n --tcw-label-tracking: 0em;\n --tcw-border-w: 1px;\n --tcw-sep-w: 0px;\n --tcw-menu-shadow: var(--tcw-shadow-lg);\n --tcw-dialog-shadow: var(--tcw-shadow-xl);\n --tcw-tooltip-shadow: var(--tcw-shadow-md);\n --tcw-blur: 0px;\n --tcw-surface-opacity: 100%;\n\n /* Elevation */\n --tcw-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);\n --tcw-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35), 0 1px 3px rgba(0, 0, 0, 0.2);\n --tcw-shadow-lg: 0 12px 36px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.3);\n --tcw-shadow-xl: 0 24px 64px rgba(0, 0, 0, 0.55), 0 12px 24px rgba(0, 0, 0, 0.35);\n --tcw-ring: 0 0 0 2px rgba(242, 169, 59, 0.45);\n\n /* Type */\n --tcw-font-mono: 'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', 'Consolas', ui-monospace, monospace;\n}\n\n.tcw-root[data-tcw-theme='light'] {\n color: #0c1016;\n background: #fcfcfd;\n\n --tcw-bg: #fcfcfd;\n --tcw-bg-surface: #ffffff;\n --tcw-bg-elevated: #ffffff;\n --tcw-bg-overlay: rgba(255, 255, 255, 0.75);\n --tcw-border: #e3e6eb;\n --tcw-border-strong: #d2d6dd;\n --tcw-tooltip-bg: #1f2630;\n --tcw-tooltip-fg: #f4f5f8;\n --tcw-text: #0c1016;\n --tcw-text-dim: #3f4754;\n --tcw-text-muted: #626a77;\n\n /* Deeper amber: readable as text on the light ground, white text readable on it. */\n --tcw-accent: #a0610a;\n --tcw-accent-hover: #874f07;\n --tcw-accent-ink: #ffffff;\n --tcw-accent-soft: rgba(160, 97, 10, 0.10);\n --tcw-accent-glow: rgba(160, 97, 10, 0.16);\n --tcw-accent-line: rgba(160, 97, 10, 0.45);\n --tcw-ring: 0 0 0 2px rgba(160, 97, 10, 0.4);\n\n /* Darker semantic colours: used as text on white. */\n --tcw-red: #c42f3e;\n --tcw-red-soft: rgba(196, 47, 62, 0.10);\n --tcw-green: #0b7d50;\n --tcw-green-soft: rgba(11, 125, 80, 0.10);\n\n --tcw-hover-bg: rgba(0, 0, 0, 0.04);\n --tcw-active-bg: rgba(160, 97, 10, 0.08);\n --tcw-divider: rgba(0, 0, 0, 0.06);\n\n --tcw-shadow-sm: 0 1px 2px rgba(20, 28, 56, 0.05);\n --tcw-shadow-md: 0 4px 12px rgba(20, 28, 56, 0.08), 0 1px 3px rgba(20, 28, 56, 0.04);\n --tcw-shadow-lg: 0 12px 36px rgba(20, 28, 56, 0.14), 0 4px 12px rgba(20, 28, 56, 0.08);\n --tcw-shadow-xl: 0 24px 64px rgba(20, 28, 56, 0.18), 0 12px 24px rgba(20, 28, 56, 0.1);\n}\n\n/* === Toolbar === */\n\n.tcw-toolbar {\n display: flex;\n align-items: center;\n gap: 0;\n padding: 0 10px;\n height: var(--tcw-toolbar-h);\n border-bottom: var(--tcw-border-w) solid var(--tcw-border);\n background:\n linear-gradient(180deg, var(--tcw-bg-elevated) 0%, var(--tcw-bg-surface) 100%);\n flex-shrink: 0;\n position: relative;\n z-index: 20;\n box-shadow: var(--tcw-shadow-sm);\n}\n\n.tcw-toolbar-symbol {\n font-size: calc(var(--tcw-font-size) + 1px);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n display: inline-flex;\n align-items: center;\n height: var(--tcw-control-h);\n padding: 0 12px;\n white-space: nowrap;\n letter-spacing: -0.015em;\n cursor: pointer;\n border: none;\n background: transparent;\n font-family: inherit;\n border-radius: var(--tcw-control-radius);\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-toolbar-symbol:hover {\n background: var(--tcw-hover-bg);\n}\n\n/* With the symbol search switched off, the button only names the symbol. */\n.tcw-toolbar-symbol[aria-disabled=\"true\"] {\n cursor: default;\n}\n\n.tcw-toolbar-symbol[aria-disabled=\"true\"]:hover {\n background: transparent;\n}\n\n.tcw-toolbar-sep {\n width: var(--tcw-sep-w);\n height: 22px;\n background: var(--tcw-border);\n flex-shrink: 0;\n margin: 0 4px;\n}\n\n.tcw-toolbar-group {\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 0 4px;\n}\n\n.tcw-toolbar-spacer {\n flex: 1;\n}\n\n.tcw-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--tcw-control-h);\n padding: 0 10px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n cursor: pointer;\n transition:\n background var(--tcw-dur-fast) var(--tcw-ease),\n color var(--tcw-dur-fast) var(--tcw-ease),\n transform var(--tcw-dur-fast) var(--tcw-ease);\n white-space: nowrap;\n line-height: 1;\n letter-spacing: -0.005em;\n}\n\n.tcw-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-btn:active {\n transform: translateY(0.5px);\n}\n\n.tcw-btn.tcw-active {\n background: var(--tcw-on-bg);\n color: var(--tcw-on-fg);\n font-weight: var(--tcw-weight-strong);\n box-shadow: var(--tcw-on-ring);\n}\n\n.tcw-btn:focus-visible,\n.tcw-btn-icon:focus-visible,\n.tcw-sidebar-btn:focus-visible,\n.tcw-dropdown-trigger:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-btn-icon {\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n transition:\n background var(--tcw-dur-fast) var(--tcw-ease),\n color var(--tcw-dur-fast) var(--tcw-ease);\n line-height: 1;\n position: relative;\n}\n\n.tcw-btn-icon:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-btn-icon svg {\n display: block;\n width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n\n.tcw-badge-count {\n font-size: calc(var(--tcw-font-size) - 3px);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n padding: 1px 5px;\n border-radius: var(--tcw-tag-radius);\n font-family: var(--tcw-font-mono);\n}\n\n/* === Dropdown === */\n\n.tcw-dropdown-trigger {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: var(--tcw-control-h);\n padding: 0 10px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n white-space: nowrap;\n line-height: 1;\n}\n\n.tcw-dropdown-trigger:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-dropdown {\n position: absolute;\n top: 100%;\n margin-top: 6px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n z-index: 50;\n width: max-content;\n max-width: min(340px, calc(100vw - 16px));\n padding: 6px;\n max-height: 420px;\n overflow-y: auto;\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n animation: tcw-pop-in var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n@keyframes tcw-pop-in {\n from { opacity: 0; transform: translateY(-4px) scale(0.98); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n}\n\n.tcw-dropdown-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: var(--tcw-menu-item-h);\n padding: 4px 10px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n width: 100%;\n border: none;\n background: transparent;\n font-family: inherit;\n text-align: start;\n border-radius: var(--tcw-radius-sm);\n gap: 12px;\n}\n\n.tcw-dropdown-item:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n/* A menu row led by an icon (chart types): icon then label, not spread apart. */\n.tcw-dropdown-item--icon {\n justify-content: flex-start;\n gap: 10px;\n}\n\n.tcw-dropdown-item svg,\n.tcw-flyout-item svg {\n flex-shrink: 0;\n}\n\n/* The drawing-group button's icon holder: a plain box for the swapped SVG. */\n.tcw-sidebar-icon {\n display: inline-flex;\n}\n\n.tcw-dropdown-item.tcw-active {\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n font-weight: var(--tcw-weight-strong);\n}\n\n/* Timeframe menu: pick on the left, pin (star) on the right. */\n.tcw-tf-more {\n padding: 0 5px;\n}\n\n.tcw-tf-more svg {\n display: block;\n}\n\n.tcw-tf-row {\n display: flex;\n align-items: center;\n gap: 2px;\n}\n\n.tcw-tf-row .tcw-dropdown-item {\n flex: 1;\n min-width: 0;\n}\n\n.tcw-tf-star {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-tf-star:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-tf-star.tcw-active {\n color: var(--tcw-accent);\n}\n\n.tcw-tf-star.tcw-active svg {\n fill: currentColor;\n}\n\n.tcw-tf-star:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-tf-remove {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-tf-row:hover .tcw-tf-remove,\n.tcw-tf-remove:focus-visible {\n opacity: 1;\n}\n\n/* No hover on touch screens: keep it visible rather than a hidden tap target. */\n@media (hover: none) {\n .tcw-tf-remove { opacity: 1; }\n}\n\n.tcw-tf-remove:hover {\n color: var(--tcw-red);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-tf-remove:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n/* Typed interval, under the list: stays in view while the list scrolls. */\n.tcw-tf-custom {\n position: sticky;\n bottom: -6px;\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin: 4px -6px -6px;\n padding: 6px 10px 8px;\n border-top: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-elevated);\n}\n\n.tcw-tf-custom-hint:empty {\n display: none;\n}\n\n.tcw-tf-custom-hint {\n flex-basis: 100%;\n width: 0;\n min-width: 100%;\n color: var(--tcw-red);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.35;\n}\n\n.tcw-tf-custom-input {\n flex: 1;\n min-width: 0;\n height: 26px;\n padding: 0 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text);\n font: inherit;\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-tf-custom-input::placeholder {\n color: var(--tcw-text-dim);\n}\n\n.tcw-tf-custom-input:focus {\n outline: none;\n border-color: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n\n.tcw-tf-custom-input[aria-invalid='true'] {\n border-color: var(--tcw-red);\n box-shadow: 0 0 0 2px var(--tcw-red-soft);\n}\n\n.tcw-tf-custom-add {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n cursor: pointer;\n}\n\n.tcw-tf-custom-add:hover {\n border-color: var(--tcw-accent);\n color: var(--tcw-accent);\n}\n\n.tcw-tf-custom-add:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: 1px;\n}\n\n.tcw-dropdown-label {\n text-transform: var(--tcw-label-case);\n font-size: calc(var(--tcw-font-size) - 3px);\n color: var(--tcw-text-muted);\n letter-spacing: var(--tcw-label-tracking);\n padding: 8px 10px 4px;\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-dropdown-divider {\n border-top: 1px solid var(--tcw-divider);\n margin: 6px 4px;\n}\n\n.tcw-tag {\n font-size: calc(var(--tcw-font-size) - 3px);\n font-family: var(--tcw-font-mono);\n color: var(--tcw-text-muted);\n padding: 2px 6px;\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-hover-bg);\n letter-spacing: 0.02em;\n}\n\n/* === Body === */\n\n.tcw-body {\n position: relative;\n display: flex;\n flex: 1;\n min-height: 0;\n background: var(--tcw-bg);\n}\n\n.tcw-chart-container {\n flex: 1;\n min-width: 0;\n min-height: 0;\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n/* === Symbol search results: name and exchange === */\n\n.tcw-cmd-item-desc {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-cmd-item-meta {\n flex-shrink: 0;\n color: var(--tcw-text-dim);\n font-size: var(--tcw-font-size-xs);\n letter-spacing: 0.02em;\n}\n\n/* === History pill (older bars loading at the left edge) === */\n\n.tcw-history-pill {\n position: absolute;\n top: 50%;\n left: 10px;\n z-index: 4;\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 5px 10px 5px 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-shadow-sm);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n line-height: 1;\n white-space: nowrap;\n transform: translateY(-50%);\n opacity: 1;\n transition: opacity var(--tcw-dur-normal) var(--tcw-ease-out);\n pointer-events: none;\n}\n\n.tcw-history-pill--hidden {\n opacity: 0;\n}\n\n.tcw-history-pill--error {\n border-color: color-mix(in srgb, var(--tcw-red) 45%, var(--tcw-border));\n color: var(--tcw-red);\n}\n\n.tcw-history-spinner {\n width: 10px;\n height: 10px;\n border: 1.5px solid var(--tcw-accent-soft);\n border-top-color: var(--tcw-accent);\n border-radius: 50%;\n animation: tcw-history-spin 0.8s linear infinite;\n}\n\n.tcw-history-pill--error .tcw-history-spinner {\n border-color: currentColor;\n animation: none;\n}\n\n@keyframes tcw-history-spin {\n to { transform: rotate(360deg); }\n}\n\n/* === Loading overlay (candle skeleton) === */\n\n.tcw-loading-overlay {\n /* Uses a modifier class rather than the `hidden` attribute — the global\n `[hidden] { display: none !important }` rule above would cut the\n opacity transition off before it can play. */\n position: absolute;\n inset: 0;\n z-index: 5;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--tcw-bg);\n opacity: 1;\n transition: opacity var(--tcw-dur-slow) var(--tcw-ease-out);\n pointer-events: none;\n}\n\n.tcw-loading-overlay--hidden {\n opacity: 0;\n}\n\n.tcw-loading-card {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 14px;\n padding: 22px 26px 20px;\n border: 1px solid transparent;\n border-radius: var(--tcw-panel-radius);\n}\n\n/* A slow switch: the previous chart stays readable underneath, dimmed, so the\n click visibly registered without blanking the screen. */\n.tcw-loading-overlay--veil {\n background: color-mix(in srgb, var(--tcw-bg) 55%, transparent);\n}\n\n.tcw-loading-overlay--veil .tcw-loading-card {\n background: var(--tcw-bg-elevated);\n border-color: var(--tcw-border);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n.tcw-loading-candles {\n position: relative;\n display: flex;\n gap: 7px;\n height: 64px;\n}\n\n/* One candle: the element is the wick's column, ::before the wick, ::after the body. */\n.tcw-loading-candle {\n position: relative;\n width: 8px;\n height: 100%;\n color: var(--tcw-red);\n opacity: 0.28;\n animation: tcw-candle-light 1.6s var(--tcw-ease) infinite;\n animation-delay: var(--tcw-delay, 0ms);\n}\n\n.tcw-loading-candle--up { color: var(--tcw-green); }\n\n.tcw-loading-candle::before,\n.tcw-loading-candle::after {\n content: '';\n position: absolute;\n left: 50%;\n background: currentColor;\n transform: translateX(-50%);\n}\n\n.tcw-loading-candle::before {\n top: var(--tcw-wick-top);\n width: 1.5px;\n height: var(--tcw-wick-h);\n}\n\n.tcw-loading-candle::after {\n top: var(--tcw-body-top);\n width: 8px;\n height: var(--tcw-body-h);\n border-radius: 1.5px;\n}\n\n/* Each candle brightens and lifts slightly in turn, left to right. */\n@keyframes tcw-candle-light {\n 0%, 55%, 100% { opacity: 0.28; transform: translateY(0); }\n 20% { opacity: 1; transform: translateY(-2px); }\n}\n\n.tcw-loading-track {\n position: relative;\n width: 100%;\n min-width: 88px;\n height: 2px;\n border-radius: 1px;\n background: var(--tcw-border);\n overflow: hidden;\n}\n\n.tcw-loading-track > span {\n position: absolute;\n inset: 0;\n width: 40%;\n border-radius: 1px;\n background: linear-gradient(90deg, transparent, var(--tcw-accent), transparent);\n animation: tcw-loading-sweep 1.6s var(--tcw-ease) infinite;\n}\n\n@keyframes tcw-loading-sweep {\n from { transform: translateX(-100%); }\n to { transform: translateX(250%); }\n}\n\n/* The status text is announced, not shown — the candles say \"loading\". */\n.tcw-loading-label {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n.tcw-loading-overlay--error .tcw-loading-candles,\n.tcw-loading-overlay--error .tcw-loading-track {\n display: none;\n}\n\n/* A failure is shown: why the chart is empty and that a retry is running. */\n.tcw-loading-overlay--error .tcw-loading-label {\n position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip-path: none;\n white-space: normal;\n max-width: 320px;\n text-align: center;\n color: var(--tcw-red);\n font-size: var(--tcw-font-size);\n}\n\n/* Reduced motion: nothing slides or lifts, but the candles still glow in\n turn and the track breathes, so the wait never looks frozen. */\n@media (prefers-reduced-motion: reduce) {\n .tcw-loading-candle {\n animation: tcw-candle-glow 2.4s ease-in-out infinite;\n animation-delay: var(--tcw-delay, 0ms);\n }\n .tcw-loading-track > span {\n width: 100%;\n background: var(--tcw-accent);\n animation: tcw-loading-breathe 2.4s ease-in-out infinite;\n }\n}\n\n@keyframes tcw-candle-glow {\n 0%, 60%, 100% { opacity: 0.28; }\n 25% { opacity: 0.9; }\n}\n\n@keyframes tcw-loading-breathe {\n 0%, 100% { opacity: 0.15; }\n 50% { opacity: 0.7; }\n}\n\n/* === On-chart indicator legend (WidgetIndicatorLegend) === */\n\n.tcw-ind-legend {\n position: absolute;\n z-index: 3;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 1px;\n max-width: calc(100% - 140px);\n pointer-events: none;\n}\n\n.tcw-ind-legend--collapsed > .tcw-ind-legend-row {\n display: none;\n}\n\n.tcw-ind-legend-row {\n display: flex;\n align-items: center;\n gap: 8px;\n max-width: 100%;\n padding: 0 4px;\n border-radius: var(--tcw-radius-sm);\n font-size: var(--tcw-font-size-xs);\n line-height: 19px;\n font-feature-settings: 'tnum';\n white-space: nowrap;\n color: var(--tcw-text-dim);\n pointer-events: auto;\n cursor: default;\n /* A narrow pane: the values shrink first, then the row is clipped. */\n overflow: hidden;\n}\n\n/* A pane's indicator: at the top of its pane, where the canvas title was,\n short enough to sit in the pane's header below the divider's grab zone. */\n.tcw-ind-legend-row--pane {\n position: absolute;\n z-index: 3;\n line-height: 15px;\n}\n\n.tcw-ind-legend-row:hover,\n.tcw-ind-legend-row:focus-within {\n background: color-mix(in srgb, var(--tcw-bg-elevated) 90%, transparent);\n box-shadow: 0 0 0 1px var(--tcw-border);\n}\n\n.tcw-ind-legend-name {\n padding: 0;\n border: none;\n background: none;\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n cursor: pointer;\n}\n\n.tcw-ind-legend-name:hover {\n color: var(--tcw-accent);\n}\n\n.tcw-ind-legend-values {\n display: inline-flex;\n gap: 7px;\n min-width: 0;\n overflow: hidden;\n}\n\n.tcw-ind-legend-row--hidden .tcw-ind-legend-name,\n.tcw-ind-legend-row--hidden .tcw-ind-legend-values {\n opacity: 0.45;\n}\n\n/* Show / settings / remove: on hover or keyboard focus (always on touch). */\n.tcw-ind-legend-actions {\n display: none;\n gap: 1px;\n margin-left: -2px;\n}\n\n.tcw-ind-legend-row:hover .tcw-ind-legend-actions,\n.tcw-ind-legend-row:focus-within .tcw-ind-legend-actions {\n display: inline-flex;\n}\n\n@media (hover: none) {\n .tcw-ind-legend-actions {\n display: inline-flex;\n }\n\n /* Finger-sized targets. */\n .tcw-ind-legend-act,\n .tcw-ind-legend-toggle {\n min-width: 28px;\n min-height: 24px;\n }\n}\n\n.tcw-ind-legend-act {\n display: inline-grid;\n place-items: center;\n width: 20px;\n height: 18px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n\n.tcw-ind-legend-act:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ind-legend-act[data-act='remove']:hover {\n color: var(--tcw-red);\n}\n\n.tcw-ind-legend-toggle {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n margin-top: 1px;\n padding: 1px 5px;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n cursor: pointer;\n pointer-events: auto;\n}\n\n.tcw-ind-legend-toggle[hidden] {\n display: none;\n}\n\n.tcw-ind-legend-toggle:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ind-legend-name:focus-visible,\n.tcw-ind-legend-act:focus-visible,\n.tcw-ind-legend-toggle:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n/* === Sidebar === */\n\n.tcw-sidebar {\n width: var(--tcw-sidebar-w);\n flex-shrink: 0;\n background: linear-gradient(180deg, var(--tcw-bg-elevated) 0%, var(--tcw-bg-surface) 100%);\n border-inline-end: var(--tcw-border-w) solid var(--tcw-border);\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 6px 0;\n /* On a short screen the tools scroll; the menus sit outside it. */\n overflow-x: hidden;\n overflow-y: auto;\n scrollbar-width: none;\n box-shadow: var(--tcw-shadow-sm);\n}\n.tcw-sidebar::-webkit-scrollbar {\n display: none;\n}\n.tcw-sidebar > * {\n flex-shrink: 0;\n}\n\n.tcw-tool-group-wrap {\n position: relative;\n}\n\n.tcw-sidebar-btn {\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n margin: 1px 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n font-family: inherit;\n transition:\n background var(--tcw-dur-fast) var(--tcw-ease),\n color var(--tcw-dur-fast) var(--tcw-ease);\n position: relative;\n flex-shrink: 0;\n line-height: 1;\n border-radius: var(--tcw-control-radius);\n}\n\n.tcw-sidebar-btn svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n\n.tcw-sidebar-btn:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-sidebar-btn.tcw-active {\n color: var(--tcw-on-icon-fg);\n background: var(--tcw-on-icon-bg);\n box-shadow: var(--tcw-on-icon-ring);\n}\n\n.tcw-sidebar-btn.tcw-danger:hover {\n color: var(--tcw-red);\n background: var(--tcw-red-soft);\n}\n\n.tcw-multi-dot {\n position: absolute;\n bottom: 3px;\n right: 3px;\n width: 4px;\n height: 4px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n opacity: 0.7;\n}\n\n/* The drawing tools' sections: always a hairline (it groups the tools), even in\n looks that drop the rules between toolbar groups. */\n.tcw-sidebar-divider {\n width: 20px;\n height: max(1px, var(--tcw-sep-w));\n background: var(--tcw-divider);\n margin: 5px 0;\n flex-shrink: 0;\n}\n\n.tcw-sidebar-spacer {\n flex: 1;\n}\n\n/* === Flyout === */\n\n.tcw-flyout {\n position: absolute;\n margin-inline-start: 6px;\n overflow-y: auto;\n overscroll-behavior: contain;\n min-width: 180px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n z-index: 30;\n padding: 6px;\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n animation: tcw-slide-right var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n/* Spans the gap to the toolbar button: crossing it stays inside the menu. */\n.tcw-flyout::before {\n content: '';\n position: absolute;\n top: -1px;\n bottom: -1px;\n right: 100%;\n width: 8px;\n}\n\n@keyframes tcw-slide-right {\n from { opacity: 0; transform: translateX(-4px); }\n to { opacity: 1; transform: translateX(0); }\n}\n\n.tcw-flyout-header {\n text-transform: var(--tcw-label-case);\n font-size: calc(var(--tcw-font-size) - 3px);\n color: var(--tcw-text-muted);\n letter-spacing: var(--tcw-label-tracking);\n padding: 6px 10px 4px;\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-flyout-hint {\n padding: 6px 10px 2px;\n border-top: 1px solid var(--tcw-border);\n margin-top: 4px;\n font-size: calc(var(--tcw-font-size) - 2.5px);\n color: var(--tcw-text-muted);\n}\n\n.tcw-flyout-item {\n min-height: var(--tcw-menu-item-h);\n padding: 4px 10px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n cursor: pointer;\n width: 100%;\n display: flex;\n align-items: center;\n gap: 10px;\n border: none;\n background: transparent;\n text-align: start;\n font-family: inherit;\n border-radius: var(--tcw-radius-sm);\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-flyout-item:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n.tcw-flyout-item:focus-visible {\n outline: none;\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n box-shadow: inset 0 0 0 1px var(--tcw-accent);\n}\n\n.tcw-flyout-item.tcw-active {\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n font-weight: var(--tcw-weight-strong);\n}\n\n/* Pinned (favorited) flyout item — the icon set's star, filled, on the right. */\n.tcw-flyout-star {\n display: inline-flex;\n margin-inline-start: auto;\n color: var(--tcw-accent);\n}\n.tcw-flyout-star svg path { fill: currentColor; }\n\n/* Favorites strip — pinned drawing tools above the tool groups. */\n.tcw-sidebar-favorites {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.tcw-sidebar-favorites .tcw-sidebar-btn {\n position: relative;\n}\n.tcw-sidebar-favorites .tcw-sidebar-btn::before {\n content: '';\n position: absolute;\n top: 3px;\n right: 3px;\n width: 4px;\n height: 4px;\n border-radius: 50%;\n background: var(--tcw-accent);\n opacity: 0.7;\n}\n\n/* === Modal === */\n\n.tcw-modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(8, 10, 18, 0.55);\n backdrop-filter: blur(6px) saturate(140%);\n -webkit-backdrop-filter: blur(6px) saturate(140%);\n z-index: 100;\n animation: tcw-fade-in var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n@keyframes tcw-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.tcw-modal {\n position: fixed;\n z-index: 101;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-dialog-radius);\n width: 520px;\n max-width: 92vw;\n max-height: 82vh;\n display: flex;\n flex-direction: column;\n box-shadow: var(--tcw-dialog-shadow);\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\n}\n\n@keyframes tcw-modal-in {\n from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }\n to { opacity: 1; transform: translate(-50%, -50%) scale(1); }\n}\n\n.tcw-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 18px 22px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n.tcw-modal-header h3 {\n font-size: var(--tcw-font-size-lg);\n font-weight: var(--tcw-weight-strong);\n margin: 0;\n color: var(--tcw-text);\n letter-spacing: -0.015em;\n}\n\n.tcw-modal-close {\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n border-radius: var(--tcw-control-radius);\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-modal-close:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-modal-tabs {\n display: flex;\n /* Four tabs in a long language on a phone: they wrap rather than clip. No overflow here: in the\n dialog's column it would let a long body squash the tabs, and clip the underline of the active one. */\n flex-wrap: wrap;\n flex-shrink: 0;\n gap: 4px;\n padding: var(--tcw-tabs-pad-block) 18px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n.tcw-modal-tab {\n flex-shrink: 0;\n white-space: nowrap;\n height: var(--tcw-tab-h);\n padding: var(--tcw-tab-pad);\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n color: var(--tcw-text-muted);\n border: none;\n background: transparent;\n cursor: pointer;\n border-bottom: var(--tcw-tab-line) solid transparent;\n border-radius: var(--tcw-tab-radius);\n margin-bottom: calc(var(--tcw-tab-line) / -2);\n transition: color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n font-family: inherit;\n text-transform: capitalize;\n letter-spacing: -0.005em;\n}\n\n.tcw-modal-tab:hover {\n color: var(--tcw-text-dim);\n background: var(--tcw-tab-hover);\n}\n\n.tcw-modal-tab.tcw-active {\n color: var(--tcw-tab-on-fg);\n background: var(--tcw-tab-on-bg);\n border-bottom-color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-modal-body {\n padding: 20px 22px;\n overflow-y: auto;\n flex: 1;\n}\n\n.tcw-settings-section {\n margin-bottom: 22px;\n}\n\n.tcw-settings-section:last-child {\n margin-bottom: 0;\n}\n\n.tcw-settings-section-title {\n font-size: calc(var(--tcw-font-size) - 2.5px);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n margin-bottom: 12px;\n}\n\n.tcw-settings-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 0;\n}\n\n.tcw-settings-row + .tcw-settings-row {\n border-top: 1px solid var(--tcw-divider);\n}\n\n.tcw-settings-label {\n font-size: var(--tcw-font-size);\n color: var(--tcw-text-dim);\n letter-spacing: -0.005em;\n}\n\n.tcw-color-picker-wrap {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.tcw-color-picker-wrap input[type='color'] {\n width: 28px;\n height: 28px;\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n cursor: pointer;\n padding: 2px;\n}\n\n.tcw-color-picker-wrap input[type='color']::-webkit-color-swatch-wrapper {\n padding: 0;\n}\n\n.tcw-color-picker-wrap input[type='color']::-webkit-color-swatch {\n border: none;\n border-radius: var(--tcw-radius-xs);\n}\n\n.tcw-color-hex {\n font-size: var(--tcw-font-size-xs);\n font-family: var(--tcw-font-mono);\n color: var(--tcw-text-muted);\n min-width: 64px;\n letter-spacing: 0.01em;\n}\n\n/* A colour left to the part itself: the swatch shows where the picker starts, faded. */\n.tcw-color-auto input[type='color'] {\n opacity: 0.45;\n border-style: dashed;\n}\n\n.tcw-color-auto .tcw-color-hex {\n font-family: inherit;\n font-style: italic;\n}\n\n.tcw-color-auto-btn {\n height: 24px;\n padding: 0 8px;\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n background: transparent;\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-radius-sm);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-color-auto-btn:hover,\n.tcw-color-auto-btn:focus-visible {\n color: var(--tcw-text);\n border-color: var(--tcw-accent);\n}\n\n.tcw-toggle {\n width: 36px;\n height: 20px;\n background: rgba(255, 255, 255, 0.12);\n border-radius: 10px;\n position: relative;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n border: none;\n padding: 0;\n flex-shrink: 0;\n}\n\n.tcw-toggle::after {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n transition:\n left var(--tcw-dur-normal) var(--tcw-ease-out),\n background var(--tcw-dur-fast) var(--tcw-ease);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.tcw-toggle.tcw-on {\n background: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-glow);\n}\n\n.tcw-toggle.tcw-on::after {\n left: 18px;\n background: #fff;\n}\n\n.tcw-root[data-tcw-theme='light'] .tcw-toggle {\n background: rgba(0, 0, 0, 0.12);\n}\n\n.tcw-root[data-tcw-theme='light'] .tcw-toggle::after {\n background: #999;\n}\n\n.tcw-root[data-tcw-theme='light'] .tcw-toggle.tcw-on {\n background: var(--tcw-accent);\n}\n\n.tcw-root[data-tcw-theme='light'] .tcw-toggle.tcw-on::after {\n background: #fff;\n}\n\n.tcw-settings-select {\n padding: 6px 10px;\n font-size: var(--tcw-font-size-sm);\n font-family: inherit;\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n color: var(--tcw-text);\n cursor: pointer;\n transition: border-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-settings-select:hover {\n border-color: var(--tcw-border-strong);\n}\n\n.tcw-settings-select:focus-visible {\n outline: none;\n border-color: var(--tcw-accent);\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-modal-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 22px;\n border-top: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-surface);\n border-radius: 0 0 var(--tcw-dialog-radius) var(--tcw-dialog-radius);\n}\n\n.tcw-reset-link {\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-muted);\n cursor: pointer;\n border: none;\n background: transparent;\n font-family: inherit;\n text-decoration: underline;\n text-underline-offset: 2px;\n text-decoration-color: var(--tcw-border-strong);\n transition: color var(--tcw-dur-fast) var(--tcw-ease), text-decoration-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-reset-link:hover {\n color: var(--tcw-text-dim);\n text-decoration-color: currentColor;\n}\n\n.tcw-done-btn {\n padding: 8px 18px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n font-family: inherit;\n transition:\n background var(--tcw-dur-fast) var(--tcw-ease),\n transform var(--tcw-dur-fast) var(--tcw-ease),\n box-shadow var(--tcw-dur-fast) var(--tcw-ease);\n letter-spacing: -0.005em;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.15);\n}\n\n.tcw-done-btn:hover {\n background: var(--tcw-accent-hover);\n box-shadow: var(--tcw-shadow-md), 0 0 0 3px var(--tcw-accent-glow);\n}\n\n.tcw-done-btn:active {\n transform: translateY(0.5px);\n}\n\n/* === Status Bar === */\n\n.tcw-statusbar {\n /* Above sidebar buttons that overflow a short chart; menus (z 30+) stay on top. */\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 7px 16px;\n border-top: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n flex-shrink: 0;\n font-feature-settings: 'tnum';\n}\n\n.tcw-status-right {\n display: flex;\n align-items: center;\n gap: 14px;\n margin-inline-start: auto;\n min-width: 0;\n white-space: nowrap;\n}\n\n/* Narrow screens: the toolbar already names the symbol and timeframe, so the\n range bar gets the room. */\n@media (max-width: 640px) {\n .tcw-status-info {\n display: none;\n }\n\n .tcw-range-btn {\n padding: 4px 5px;\n }\n}\n\n/* Range presets + go to date, bottom left */\n.tcw-range-bar {\n display: flex;\n align-items: center;\n gap: 1px;\n margin: -4px 12px -4px -8px;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n}\n\n.tcw-range-bar::-webkit-scrollbar {\n display: none;\n}\n\n.tcw-range-btn {\n flex-shrink: 0;\n padding: 4px 7px;\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n letter-spacing: 0.02em;\n color: var(--tcw-text-muted);\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-range-btn:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-range-btn:active {\n color: var(--tcw-accent);\n}\n\n.tcw-range-btn:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-range-goto {\n display: inline-grid;\n place-items: center;\n margin-inline-start: 6px;\n padding: 4px 6px;\n}\n\n.tcw-range-goto svg {\n display: block;\n}\n\n/* Go-to-date popover, anchored above the range bar */\n.tcw-goto {\n position: absolute;\n left: 10px;\n bottom: 40px;\n z-index: 40;\n display: grid;\n gap: 10px;\n width: 232px;\n padding: 14px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-goto-title {\n font-weight: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size);\n}\n\n.tcw-goto-field {\n display: grid;\n gap: 4px;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n}\n\n.tcw-goto-input {\n height: 30px;\n padding: 0 8px;\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n color-scheme: dark;\n}\n\n.tcw-root[data-tcw-theme='light'] .tcw-goto-input {\n color-scheme: light;\n}\n\n.tcw-goto-input:focus {\n outline: none;\n border-color: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n\n.tcw-goto-actions {\n display: flex;\n justify-content: flex-end;\n gap: 6px;\n}\n\n.tcw-goto-submit {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-goto-submit:hover {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n filter: brightness(1.08);\n}\n\n.tcw-status-indicator {\n display: flex;\n align-items: center;\n gap: 7px;\n font-weight: var(--tcw-weight);\n}\n\n.tcw-status-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n transition: background var(--tcw-dur-normal) var(--tcw-ease), box-shadow var(--tcw-dur-normal) var(--tcw-ease);\n position: relative;\n}\n\n.tcw-status-dot.tcw-connected {\n background: var(--tcw-green);\n box-shadow: 0 0 0 3px rgba(31, 168, 116, 0.18);\n}\n\n.tcw-status-dot.tcw-connected::after {\n content: '';\n position: absolute;\n inset: -3px;\n border-radius: 50%;\n border: 2px solid var(--tcw-green);\n opacity: 0;\n animation: tcw-pulse 2.2s ease-out infinite;\n}\n\n@keyframes tcw-pulse {\n 0% { opacity: 0.6; transform: scale(0.6); }\n 100% { opacity: 0; transform: scale(2.2); }\n}\n\n.tcw-status-dot.tcw-error {\n background: var(--tcw-red);\n box-shadow: 0 0 0 3px rgba(232, 80, 91, 0.2);\n}\n\n/* === Command Palette === */\n\n.tcw-cmd-palette {\n position: fixed;\n z-index: 102;\n top: 18%;\n left: 50%;\n transform: translateX(-50%);\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-dialog-radius);\n width: 560px;\n max-width: 92vw;\n max-height: 62vh;\n display: flex;\n flex-direction: column;\n box-shadow: var(--tcw-dialog-shadow);\n overflow: hidden;\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\n}\n\n.tcw-cmd-header {\n display: flex;\n align-items: center;\n padding: 14px 18px;\n border-bottom: 1px solid var(--tcw-divider);\n gap: 12px;\n}\n\n.tcw-cmd-icon {\n color: var(--tcw-text-muted);\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n}\n\n.tcw-cmd-input {\n flex: 1;\n background: transparent;\n border: none;\n outline: none;\n font-size: calc(var(--tcw-font-size) + 1.5px);\n font-family: inherit;\n color: var(--tcw-text);\n caret-color: var(--tcw-accent);\n letter-spacing: -0.005em;\n}\n\n.tcw-cmd-input::placeholder {\n color: var(--tcw-text-muted);\n}\n\n.tcw-cmd-hint {\n font-size: calc(var(--tcw-font-size) - 3px);\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n border: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n padding: 3px 7px;\n border-radius: 4px;\n flex-shrink: 0;\n box-shadow: inset 0 -1px 0 var(--tcw-border);\n}\n\n.tcw-cmd-list {\n overflow-y: auto;\n flex: 1;\n padding: 6px;\n max-height: 380px;\n}\n\n.tcw-cmd-category {\n text-transform: var(--tcw-label-case);\n font-size: calc(var(--tcw-font-size) - 3px);\n color: var(--tcw-text-muted);\n letter-spacing: var(--tcw-label-tracking);\n padding: 10px 10px 4px;\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-cmd-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 9px 12px;\n font-size: var(--tcw-font-size);\n color: var(--tcw-text-dim);\n cursor: pointer;\n width: 100%;\n border: none;\n background: transparent;\n font-family: inherit;\n text-align: start;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n gap: 10px;\n border-radius: var(--tcw-radius);\n letter-spacing: -0.005em;\n}\n\n.tcw-cmd-item:hover,\n.tcw-cmd-item.tcw-selected {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-cmd-item.tcw-selected {\n box-shadow: inset 2px 0 0 var(--tcw-accent);\n}\n\n.tcw-cmd-item.tcw-active .tcw-cmd-item-label {\n color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-cmd-item-label {\n flex: 1;\n}\n\n.tcw-cmd-check {\n display: inline-flex;\n color: var(--tcw-accent);\n}\n\n.tcw-cmd-kbd {\n font-size: calc(var(--tcw-font-size) - 3px);\n font-family: var(--tcw-font-mono);\n color: var(--tcw-text-muted);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n padding: 2px 6px;\n border-radius: var(--tcw-tag-radius);\n box-shadow: inset 0 -1px 0 var(--tcw-border);\n}\n\n.tcw-cmd-empty {\n padding: 32px 16px;\n text-align: center;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size);\n}\n\n/* A key and what it does, in a list dialog's footer: keys in the shortcut chips (.tcw-cmd-kbd). */\n.tcw-cmd-help {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n}\n.tcw-cmd-help-text { margin-inline-start: 3px; }\n.tcw-cmd-key {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n font-style: normal;\n}\n\n.tcw-cmd-footer {\n display: flex;\n align-items: center;\n gap: 18px;\n padding: 10px 18px;\n border-top: 1px solid var(--tcw-divider);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n background: var(--tcw-bg-surface);\n}\n\n/* === Watchlist === */\n\n.tcw-watchlist {\n width: 220px;\n flex-shrink: 0;\n background: var(--tcw-bg-surface);\n border-inline-start: 1px solid var(--tcw-border);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n box-shadow: var(--tcw-shadow-sm);\n}\n\n.tcw-watchlist-header {\n position: relative;\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 6px 8px 6px 8px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n/* The shown list's name: opens the lists menu. */\n.tcw-watchlist-name {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 6px;\n height: var(--tcw-control-h-sm);\n padding: 0 6px;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n text-align: start;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n}\n.tcw-watchlist-name::after {\n content: '';\n flex: none;\n width: 0;\n height: 0;\n margin-inline-start: auto;\n border: 4px solid transparent;\n border-top-color: currentColor;\n border-bottom-width: 0;\n opacity: 0.7;\n}\n\n.tcw-watchlist-add {\n flex: none;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-lg);\n line-height: 1;\n cursor: pointer;\n}\n\n.tcw-watchlist-name:hover,\n.tcw-watchlist-add:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n.tcw-watchlist-name:focus-visible,\n.tcw-watchlist-add:focus-visible,\n.tcw-watchlist-input:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* The lists menu, under the header. */\n.tcw-watchlist-menu {\n top: calc(100% - 2px);\n left: 6px;\n right: 6px;\n margin-top: 0;\n}\n.tcw-watchlist-count {\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n}\n.tcw-watchlist-menu .tcw-danger {\n color: var(--tcw-red);\n}\n\n/* Naming a list in place. */\n.tcw-watchlist-input {\n flex: 1;\n min-width: 0;\n height: var(--tcw-control-h-sm);\n padding: 0 8px;\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-watchlist-empty {\n padding: 16px 14px;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.5;\n}\n\n/* A row's remove button shows on hover or focus, over its numbers. */\n.tcw-watchlist-remove {\n position: absolute;\n top: 50%;\n right: 6px;\n display: grid;\n place-items: center;\n width: 20px;\n height: 20px;\n border: 0;\n border-radius: var(--tcw-radius-sm);\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size);\n line-height: 1;\n opacity: 0;\n transform: translateY(-50%);\n cursor: pointer;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-watchlist-row:hover .tcw-watchlist-remove,\n.tcw-watchlist-row:focus-within .tcw-watchlist-remove {\n opacity: 1;\n}\n.tcw-watchlist-remove:hover {\n color: var(--tcw-red);\n}\n.tcw-watchlist-row.tcw-watchlist-dragging {\n opacity: 0.45;\n}\n\n.tcw-watchlist-list {\n flex: 1;\n overflow-y: auto;\n padding: 4px 0;\n}\n\n.tcw-watchlist-row {\n position: relative;\n display: grid;\n grid-template-columns: 1fr auto auto;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n border-inline-start: 2px solid transparent;\n outline: none;\n}\n\n.tcw-watchlist-row:hover {\n background: var(--tcw-hover-bg);\n}\n\n.tcw-watchlist-row:focus-visible {\n background: var(--tcw-hover-bg);\n border-inline-start-color: var(--tcw-accent);\n}\n\n.tcw-watchlist-row.tcw-watchlist-active {\n background: var(--tcw-accent-soft);\n border-inline-start-color: var(--tcw-accent);\n}\n\n.tcw-watchlist-symbol {\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n letter-spacing: -0.005em;\n white-space: nowrap;\n}\n\n.tcw-watchlist-spark {\n width: 56px;\n height: 22px;\n align-self: center;\n}\n\n.tcw-watchlist-stats {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 1px;\n font-variant-numeric: tabular-nums;\n font-family: var(--tcw-font-mono);\n}\n\n.tcw-watchlist-price {\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n font-weight: var(--tcw-weight);\n}\n\n.tcw-watchlist-change {\n font-size: calc(var(--tcw-font-size) - 2.5px);\n color: var(--tcw-text-muted);\n font-weight: var(--tcw-weight);\n}\n\n.tcw-watchlist-change.tcw-up {\n color: var(--tcw-green);\n}\n\n.tcw-watchlist-change.tcw-down {\n color: var(--tcw-red);\n}\n\n@media (max-width: 768px) {\n .tcw-watchlist {\n display: none;\n }\n}\n\n/* === Toast === */\n\n.tcw-toast-icon {\n display: inline-flex;\n vertical-align: -2px;\n margin-inline-end: 7px;\n color: var(--tcw-accent);\n}\n.tcw-toast-error .tcw-toast-icon { color: var(--tcw-red); }\n\n.tcw-toast {\n position: absolute;\n bottom: 60px;\n left: 50%;\n transform: translate(-50%, 12px);\n z-index: 40;\n padding: 9px 14px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-toast-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n color: var(--tcw-text);\n opacity: 0;\n transition: opacity var(--tcw-dur-normal) var(--tcw-ease-out), transform var(--tcw-dur-normal) var(--tcw-ease-out);\n pointer-events: none;\n max-width: calc(100% - 32px);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n letter-spacing: -0.005em;\n}\n\n.tcw-toast.tcw-toast-in {\n opacity: 1;\n transform: translate(-50%, 0);\n}\n\n.tcw-toast-error {\n border-color: var(--tcw-red);\n color: var(--tcw-red);\n}\n\n/* === Replay scrubber === */\n\n/* Picking the replay start: the bars right of the pointer would be hidden. */\n.tcw-replay-shade {\n position: absolute;\n z-index: 4;\n pointer-events: none;\n background: color-mix(in srgb, var(--tcw-bg) 62%, transparent);\n border-inline-start: 1.5px dashed var(--tcw-accent);\n}\n\n.tcw-replay-group {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n\n.tcw-replay-group[hidden] { display: none; }\n\n.tcw-replay-hint {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 0 4px;\n color: var(--tcw-text-dim);\n white-space: nowrap;\n}\n\n.tcw-replay-text-btn {\n height: 26px;\n padding: 0 10px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-weight: var(--tcw-weight);\n white-space: nowrap;\n cursor: pointer;\n transition: background var(--tcw-dur-fast), border-color var(--tcw-dur-fast), color var(--tcw-dur-fast);\n}\n\n.tcw-replay-text-btn:hover { background: var(--tcw-hover-bg); border-color: var(--tcw-border-strong); }\n.tcw-replay-text-btn:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n\n/* At the last bar: the way out is the next thing to do. */\n.tcw-replay-bar--ended .tcw-replay-realtime {\n background: var(--tcw-accent);\n border-color: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n}\n\n.tcw-replay-btn:disabled { opacity: 0.4; cursor: default; }\n\n@media (max-width: 640px) {\n .tcw-replay-bar {\n flex-wrap: wrap;\n justify-content: center;\n max-width: calc(100% - 24px);\n border-radius: var(--tcw-panel-radius);\n }\n .tcw-replay-hint { white-space: normal; }\n}\n\n.tcw-replay-bar {\n position: absolute;\n left: 50%;\n /* Above the 30px time axis, so its dates stay readable. */\n bottom: 40px;\n transform: translateX(-50%);\n z-index: 25;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n animation: tcw-pop-in var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n.tcw-replay-btn {\n width: 28px;\n height: 28px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: transparent;\n color: var(--tcw-text-dim);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n font-family: inherit;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-replay-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-replay-btn.tcw-replay-play {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n width: 32px;\n height: 32px;\n box-shadow: 0 0 0 3px var(--tcw-accent-glow);\n}\n\n.tcw-replay-btn.tcw-replay-play:hover {\n background: var(--tcw-accent-hover);\n}\n\n.tcw-replay-scrubber {\n appearance: none;\n -webkit-appearance: none;\n width: 220px;\n height: 4px;\n background: var(--tcw-border-strong);\n border-radius: 2px;\n outline: none;\n cursor: pointer;\n}\n\n.tcw-replay-scrubber::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n}\n\n.tcw-replay-scrubber::-moz-range-thumb {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n}\n\n.tcw-replay-progress {\n font-size: var(--tcw-font-size-xs);\n font-family: var(--tcw-font-mono);\n color: var(--tcw-text-muted);\n min-width: 64px;\n text-align: center;\n font-feature-settings: 'tnum';\n}\n\n.tcw-replay-speed {\n padding: 4px 8px;\n font-size: var(--tcw-font-size-xs);\n font-family: var(--tcw-font-mono);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n color: var(--tcw-text-dim);\n cursor: pointer;\n}\n\n.tcw-replay-speed:hover {\n border-color: var(--tcw-border-strong);\n}\n\n@media (max-width: 640px) {\n .tcw-replay-scrubber {\n width: 140px;\n }\n .tcw-replay-progress {\n display: none;\n }\n}\n\n/* === Hotkey sheet === */\n\n.tcw-hotkey-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 24px 32px;\n}\n\n.tcw-hotkey-section .tcw-settings-section-title {\n margin-bottom: 8px;\n}\n\n.tcw-hotkey-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 6px 0;\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n.tcw-hotkey-row:last-child {\n border-bottom: none;\n}\n\n.tcw-hotkey-keys {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-shrink: 0;\n}\n\n.tcw-hotkey-sep {\n font-size: calc(var(--tcw-font-size) - 3px);\n color: var(--tcw-text-muted);\n}\n\n.tcw-hotkey-label {\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n text-align: end;\n letter-spacing: -0.005em;\n}\n\n@media (max-width: 640px) {\n .tcw-hotkey-grid {\n grid-template-columns: 1fr;\n gap: 18px;\n }\n}\n\n/* === Scrollbar (subtle, premium feel) === */\n\n.tcw-dropdown::-webkit-scrollbar,\n.tcw-modal-body::-webkit-scrollbar,\n.tcw-cmd-list::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n.tcw-dropdown::-webkit-scrollbar-track,\n.tcw-modal-body::-webkit-scrollbar-track,\n.tcw-cmd-list::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.tcw-dropdown::-webkit-scrollbar-thumb,\n.tcw-modal-body::-webkit-scrollbar-thumb,\n.tcw-cmd-list::-webkit-scrollbar-thumb {\n background: var(--tcw-border-strong);\n border-radius: 4px;\n border: 2px solid transparent;\n background-clip: padding-box;\n}\n\n.tcw-dropdown::-webkit-scrollbar-thumb:hover,\n.tcw-modal-body::-webkit-scrollbar-thumb:hover,\n.tcw-cmd-list::-webkit-scrollbar-thumb:hover {\n background: var(--tcw-text-muted);\n background-clip: padding-box;\n border: 2px solid transparent;\n}\n\n/* === Responsive === */\n\n@media (max-width: 768px) {\n .tcw-toolbar {\n padding: 0 4px;\n height: max(44px, var(--tcw-toolbar-h)); /* Apple HIG minimum touch target */\n }\n .tcw-toolbar-sep {\n display: none;\n }\n .tcw-btn,\n .tcw-dropdown-trigger {\n height: max(40px, var(--tcw-control-h)); /* fatter tap target */\n padding: 0 12px;\n font-size: var(--tcw-font-size);\n }\n .tcw-btn-icon {\n width: max(40px, var(--tcw-control-h));\n height: max(40px, var(--tcw-control-h));\n }\n .tcw-sidebar {\n width: max(44px, var(--tcw-sidebar-w));\n }\n .tcw-sidebar-btn {\n width: max(40px, var(--tcw-control-h));\n height: max(40px, var(--tcw-control-h));\n }\n .tcw-modal,\n .tcw-cmd-palette {\n width: 94vw;\n border-radius: var(--tcw-dialog-radius);\n }\n\n /* Hide the right-side watchlist on tablets too — already declared but\n * grouped here for clarity. */\n .tcw-watchlist {\n display: none;\n }\n\n /* Replay scrubber compact mode */\n .tcw-replay-scrubber {\n width: 120px;\n }\n .tcw-replay-progress {\n display: none;\n }\n}\n\n/* === Mobile bottom-sheet pattern ===\n * On phones, swap floating-centered modals for full-width sheets that slide\n * up from the bottom. Bigger hit targets, no awkward off-screen clipping,\n * matches how every modern iOS/Android app handles overflow UI.\n */\n@media (max-width: 640px) {\n .tcw-modal,\n .tcw-cmd-palette {\n top: auto;\n bottom: 0;\n left: 0;\n right: 0;\n transform: none;\n width: 100vw;\n max-width: 100vw;\n max-height: 92vh;\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 0 0;\n border-bottom: none;\n /* Grab handle */\n padding-top: 8px;\n }\n\n /* Visual \"grab handle\" affordance — a short pill at the top of every sheet */\n .tcw-modal::before,\n .tcw-cmd-palette::before {\n content: '';\n display: block;\n width: 36px;\n height: 4px;\n border-radius: 2px;\n background: var(--tcw-border-strong);\n margin: 0 auto 8px;\n opacity: 0.7;\n }\n\n /* Reuse the existing modal-in animation but slide from below instead of\n * popping from center, so the entrance reads as a sheet, not a dialog. */\n @keyframes tcw-modal-in {\n from { opacity: 0; transform: translateY(20px); }\n to { opacity: 1; transform: translateY(0); }\n }\n\n .tcw-modal,\n .tcw-cmd-palette {\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\n }\n\n /* Safe-area-aware footer padding for iPhone notch / home indicator */\n .tcw-modal-footer,\n .tcw-cmd-footer {\n padding-bottom: max(14px, env(safe-area-inset-bottom));\n }\n\n /* Larger tap targets inside sheets */\n .tcw-modal-tab {\n padding: 14px 16px;\n }\n .tcw-cmd-item {\n padding: 12px 14px;\n font-size: calc(var(--tcw-font-size) + 1px);\n }\n .tcw-dropdown-item {\n padding: 12px 12px;\n font-size: calc(var(--tcw-font-size) + 1px);\n }\n\n /* Hotkey sheet — single column on phones */\n .tcw-hotkey-grid {\n grid-template-columns: 1fr;\n }\n}\n\n/* === Price alerts panel === */\n\n.tcw-alerts-panel {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-end: 12px;\n z-index: 40;\n width: 300px;\n max-width: calc(100vw - 24px);\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n\n@keyframes tcw-alerts-in {\n from { opacity: 0; transform: translateY(-6px) scale(0.98); }\n to { opacity: 1; transform: none; }\n}\n\n.tcw-alerts-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 12px;\n font-weight: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n\n.tcw-alerts-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-alerts-close:hover {\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n}\n\n.tcw-alerts-form {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 8px;\n padding: 12px;\n border-bottom: 1px solid var(--tcw-border);\n}\n\n.tcw-alerts-form input,\n.tcw-alerts-form select {\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n height: 32px;\n padding: 0 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-sm);\n outline: none;\n}\n.tcw-alerts-form input:focus,\n.tcw-alerts-form select:focus {\n border-color: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n.tcw-alerts-message,\n.tcw-alerts-source {\n grid-column: 1 / -1;\n}\n\n.tcw-alerts-add {\n grid-column: 1 / -1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 34px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent-ink);\n background: var(--tcw-accent);\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-alerts-add:hover {\n background: var(--tcw-accent-hover);\n}\n\n.tcw-alerts-list {\n max-height: 260px;\n overflow-y: auto;\n padding: 6px;\n}\n\n.tcw-alerts-empty {\n padding: 18px 12px;\n text-align: center;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-muted);\n line-height: 1.5;\n}\n\n.tcw-alerts-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 8px 8px;\n border-radius: var(--tcw-radius-sm);\n}\n.tcw-alerts-row:hover {\n background: var(--tcw-bg-surface);\n}\n.tcw-alerts-triggered {\n background: var(--tcw-accent-soft);\n}\n\n.tcw-alerts-info {\n min-width: 0;\n}\n.tcw-alerts-row-main {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n font-variant-numeric: tabular-nums;\n}\n.tcw-alerts-row-note {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.tcw-alerts-badge {\n font-size: calc(var(--tcw-font-size) - 4px);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n padding: 2px 5px;\n border-radius: var(--tcw-tag-radius);\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n}\n\n.tcw-alerts-del {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-alerts-del:hover {\n background: var(--tcw-red-soft);\n color: var(--tcw-red);\n}\n\n@media (max-width: 640px) {\n .tcw-alerts-panel {\n top: auto;\n bottom: 0;\n left: 0;\n right: 0;\n width: 100vw;\n max-width: 100vw;\n border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;\n }\n .tcw-alerts-list {\n max-height: 40vh;\n padding-bottom: max(8px, env(safe-area-inset-bottom));\n }\n}\n\n/* === Data Window === */\n\n.tcw-datawin {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-end: 12px;\n z-index: 38;\n width: 200px;\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-datawin-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 9px 12px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-datawin-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-datawin-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\n.tcw-datawin-body { padding: 6px 4px; max-height: 360px; overflow-y: auto; }\n.tcw-datawin-empty { padding: 14px; text-align: center; font-size: var(--tcw-font-size-sm); color: var(--tcw-text-muted); }\n.tcw-datawin-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n padding: 3px 8px;\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-datawin-label { color: var(--tcw-text-muted); }\n.tcw-datawin-value { color: var(--tcw-text); font-variant-numeric: tabular-nums; font-weight: var(--tcw-weight-strong); }\n.tcw-datawin-value.tcw-up { color: var(--tcw-green); }\n.tcw-datawin-value.tcw-down { color: var(--tcw-red); }\n.tcw-datawin-sub {\n margin: 6px 8px 2px;\n font-size: calc(var(--tcw-font-size) - 3px);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n border-top: 1px solid var(--tcw-border);\n padding-top: 6px;\n}\n\n@media (max-width: 640px) {\n .tcw-datawin { top: auto; bottom: 0; left: 0; right: 0; width: 100vw; border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0; }\n}\n\n/* === Depth-of-market ladder === */\n\n.tcw-ladder {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-end: 12px;\n z-index: 41;\n width: 240px;\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-ladder-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 12px;\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-ladder-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-ladder-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\n.tcw-ladder-cols {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n padding: 4px 0;\n font-size: calc(var(--tcw-font-size) - 3px);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-ladder-cols span { text-align: center; }\n.tcw-ladder-body { max-height: 360px; overflow-y: auto; }\n.tcw-ladder-empty { padding: 18px; text-align: center; font-size: var(--tcw-font-size-sm); color: var(--tcw-text-muted); }\n\n.tcw-ladder-row {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n height: 22px;\n font-variant-numeric: tabular-nums;\n}\n.tcw-ladder-cell {\n position: relative;\n display: flex;\n align-items: center;\n border: none;\n background: transparent;\n font-size: var(--tcw-font-size-xs);\n cursor: pointer;\n font-variant-numeric: tabular-nums;\n overflow: hidden;\n}\n.tcw-ladder-cell:disabled { cursor: default; }\n/* Depth bar grows from the centre column outward. */\n.tcw-ladder-cell::before {\n content: '';\n position: absolute;\n top: 1px; bottom: 1px;\n width: var(--w, 0%);\n}\n.tcw-ladder-bid { justify-content: flex-end; padding-right: 8px; color: var(--tcw-green); }\n.tcw-ladder-bid::before { right: 0; background: var(--tcw-green-soft); }\n.tcw-ladder-bid span, .tcw-ladder-bid { position: relative; }\n.tcw-ladder-ask { justify-content: flex-start; padding-left: 8px; color: var(--tcw-red); }\n.tcw-ladder-ask::before { left: 0; background: var(--tcw-red-soft); }\n.tcw-ladder-cell:not(:disabled):hover::before { opacity: 0.7; filter: brightness(1.4); }\n.tcw-ladder-cell > * { position: relative; }\n.tcw-ladder-price {\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text-dim);\n border-inline-start: 1px solid var(--tcw-border);\n border-inline-end: 1px solid var(--tcw-border);\n}\n.tcw-ladder-price.tcw-ask { color: var(--tcw-red); }\n.tcw-ladder-price.tcw-bid { color: var(--tcw-green); }\n\n@media (max-width: 640px) {\n .tcw-ladder { top: auto; bottom: 0; left: 0; right: 0; width: 100vw; border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0; }\n .tcw-ladder-body { max-height: 45vh; padding-bottom: max(0px, env(safe-area-inset-bottom)); }\n}\n\n/* === Bracket order placement === */\n\n.tcw-btn-long:hover { color: var(--tcw-green) !important; }\n.tcw-btn-short:hover { color: var(--tcw-red) !important; }\n\n.tcw-bracket-bar {\n position: absolute;\n top: calc(var(--tcw-panel-top) + 2px);\n left: 50%;\n transform: translateX(-50%);\n z-index: 45;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 7px 8px 7px 14px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-bracket-label {\n font-size: var(--tcw-font-size-sm);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n}\n.tcw-bracket-label[data-side='buy'] { color: var(--tcw-green); }\n.tcw-bracket-label[data-side='sell'] { color: var(--tcw-red); }\n.tcw-bracket-hint {\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n.tcw-bracket-cancel, .tcw-bracket-confirm {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n height: 30px;\n padding: 0 12px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-bracket-cancel {\n color: var(--tcw-text-dim);\n background: var(--tcw-bg-surface);\n}\n.tcw-bracket-cancel:hover { color: var(--tcw-text); }\n.tcw-bracket-confirm {\n color: var(--tcw-accent-ink);\n background: var(--tcw-accent);\n}\n.tcw-bracket-confirm:hover { background: var(--tcw-accent-hover); }\n\n@media (max-width: 640px) {\n .tcw-bracket-bar { width: calc(100vw - 24px); justify-content: space-between; }\n .tcw-bracket-hint { display: none; }\n}\n\n/* === Drawing style + templates popover === */\n\n.tcw-style-panel {\n position: absolute;\n bottom: 12px;\n inset-inline-start: var(--tcw-panel-left);\n z-index: 40;\n width: 220px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-style-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-style-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-style-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\n\n.tcw-style-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.tcw-style-swatch {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 1px solid var(--tcw-border-strong);\n cursor: pointer;\n padding: 0;\n}\n.tcw-style-swatch.tcw-on { outline: 2px solid var(--tcw-accent); outline-offset: 1px; }\n.tcw-style-picker {\n width: 22px;\n height: 22px;\n padding: 0;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n cursor: pointer;\n}\n.tcw-style-width, .tcw-style-dash {\n flex: 1;\n min-width: 0;\n height: 26px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n color: var(--tcw-text-dim);\n cursor: pointer;\n font-size: var(--tcw-font-size-xs);\n}\n.tcw-style-width span { width: 16px; background: currentColor; border-radius: var(--tcw-radius-xs); }\n.tcw-style-width.tcw-on, .tcw-style-dash.tcw-on {\n border-color: var(--tcw-accent);\n color: var(--tcw-accent);\n}\n\n.tcw-style-subhead {\n font-size: calc(var(--tcw-font-size) - 3px);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n margin-top: 2px;\n}\n.tcw-style-save { display: flex; gap: 6px; }\n.tcw-style-name {\n flex: 1;\n min-width: 0;\n height: 28px;\n padding: 0 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n outline: none;\n}\n.tcw-style-name:focus { border-color: var(--tcw-accent); }\n.tcw-style-savebtn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 0 10px;\n height: 28px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent-ink);\n background: var(--tcw-accent);\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-style-savebtn:hover { background: var(--tcw-accent-hover); }\n\n.tcw-style-templates { display: flex; flex-direction: column; gap: 2px; max-height: 140px; overflow-y: auto; }\n.tcw-style-empty { font-size: var(--tcw-font-size-xs); color: var(--tcw-text-muted); padding: 4px 0; }\n.tcw-style-template { display: flex; align-items: center; gap: 4px; }\n.tcw-style-apply {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 5px 7px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n text-align: start;\n}\n.tcw-style-apply:hover { background: var(--tcw-bg-surface); }\n.tcw-style-tdot { flex-shrink: 0; width: 9px; height: 9px; border-radius: 50%; }\n.tcw-style-tdel {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-style-tdel:hover { background: var(--tcw-red-soft); color: var(--tcw-red); }\n\n/* === Settings range slider === */\n\n.tcw-settings-range {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.tcw-settings-range input[type='range'] {\n width: 110px;\n accent-color: var(--tcw-accent);\n cursor: pointer;\n}\n.tcw-settings-range-val {\n min-width: 38px;\n text-align: end;\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text-dim);\n}\n\n/* === Indicator settings dialog === */\n\n/* Narrow on a desktop; on a phone a sheet across the screen like every dialog. */\n@media (min-width: 641px) {\n .tcw-modal-narrow {\n max-width: 360px;\n }\n}\n.tcw-indi-input {\n width: 110px;\n height: 30px;\n padding: 0 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n outline: none;\n font-variant-numeric: tabular-nums;\n}\n.tcw-indi-input:focus {\n border-color: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n.tcw-indi-select {\n width: 150px;\n padding-right: 4px;\n cursor: pointer;\n}\n/* A level: its value and a remove button. */\n.tcw-indi-level {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n.tcw-indi-remove {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-indi-remove:hover {\n color: var(--tcw-red);\n background: var(--tcw-hover-bg);\n}\n.tcw-indi-remove:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n.tcw-indi-add {\n margin-top: 8px;\n}\n.tcw-indi-color {\n width: 36px;\n height: 28px;\n padding: 2px;\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-sm);\n cursor: pointer;\n}\n\n/* === Object tree panel === */\n\n.tcw-tree-panel {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-end: 12px;\n z-index: 39;\n width: 280px;\n max-width: calc(100vw - 24px);\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n\n.tcw-tree-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 12px;\n font-weight: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-tree-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-tree-close:hover {\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n}\n\n.tcw-tree-section {\n padding: 6px;\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-tree-section:last-child {\n border-bottom: none;\n}\n.tcw-tree-section-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 8px 4px;\n font-size: calc(var(--tcw-font-size) - 3px);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n}\n.tcw-tree-add {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-tree-add:hover {\n background: var(--tcw-accent-soft);\n color: var(--tcw-accent);\n}\n.tcw-tree-dot {\n flex-shrink: 0;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n.tcw-tree-list {\n max-height: 200px;\n overflow-y: auto;\n}\n\n.tcw-tree-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 6px 8px;\n border-radius: var(--tcw-radius-sm);\n}\n.tcw-tree-row:hover {\n background: var(--tcw-bg-surface);\n}\n.tcw-tree-hidden .tcw-tree-name {\n opacity: 0.5;\n}\n.tcw-tree-name {\n min-width: 0;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.tcw-tree-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-shrink: 0;\n}\n.tcw-tree-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n.tcw-tree-btn:hover {\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text);\n}\n.tcw-tree-btn.tcw-tree-on {\n color: var(--tcw-accent);\n}\n.tcw-tree-btn.tcw-tree-del:hover {\n background: var(--tcw-red-soft);\n color: var(--tcw-red);\n}\n.tcw-tree-group .tcw-tree-name {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: var(--tcw-weight-strong);\n}\n.tcw-tree-group .tcw-tree-name svg {\n flex: none;\n color: var(--tcw-text-muted);\n}\n.tcw-tree-member {\n margin-left: 14px;\n padding-left: 10px;\n border-inline-start: 1px solid var(--tcw-border-strong);\n border-radius: 0 var(--tcw-radius-sm) var(--tcw-radius-sm) 0;\n}\n.tcw-tree-rename {\n flex: 1;\n min-width: 0;\n padding: 3px 6px;\n border: 1px solid var(--tcw-accent-line);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-tree-rename:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n.tcw-tree-empty {\n padding: 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-muted);\n}\n\n@media (max-width: 640px) {\n .tcw-tree-panel {\n top: auto;\n bottom: 0;\n left: 0;\n right: 0;\n width: 100vw;\n max-width: 100vw;\n border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;\n }\n .tcw-tree-list {\n max-height: 30vh;\n }\n .tcw-tree-section:last-child {\n padding-bottom: max(6px, env(safe-area-inset-bottom));\n }\n}\n\n/* === Reduced motion === */\n\n@media (prefers-reduced-motion: reduce) {\n .tcw-root *,\n .tcw-root *::before,\n .tcw-root *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n\n /* Except the loader's slow glow (opacity only): without it a long wait\n looks frozen. */\n .tcw-root .tcw-loading-candle,\n .tcw-root .tcw-loading-track > span {\n animation-duration: 2.4s !important;\n animation-iteration-count: infinite !important;\n animation-delay: var(--tcw-delay, 0ms) !important;\n }\n}\n\n/* --- Drawing settings dialog --- */\n.tcw-drawing-settings .tcw-modal-footer { gap: 12px; }\n.tcw-drawing-settings-tools {\n display: flex;\n gap: 14px;\n margin-inline-end: auto;\n}\n.tcw-drawing-text {\n min-height: 56px;\n resize: vertical;\n font-family: inherit;\n}\n.tcw-levels-editor { display: grid; gap: 6px; margin-bottom: 10px; }\n.tcw-levels-grid {\n display: grid;\n gap: 4px;\n max-height: 260px;\n overflow-y: auto;\n padding-right: 2px;\n}\n.tcw-level-row {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) 32px 24px;\n align-items: center;\n gap: 8px;\n}\n.tcw-level-row input[type='checkbox'] { accent-color: var(--tcw-accent); }\n.tcw-level-remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: 0;\n border-radius: var(--tcw-radius-sm, 4px);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-level-remove:hover { color: var(--tcw-text); background: var(--tcw-bg-elevated); }\n.tcw-level-remove:focus-visible { outline: 2px solid var(--tcw-accent); outline-offset: 1px; }\n.tcw-level-add { justify-self: start; }\n.tcw-drawing-templates { display: grid; gap: 2px; margin-bottom: 8px; }\n.tcw-drawing-alert { display: inline-flex; align-items: center; gap: 6px; }\n\n/* --- Context menu (right-click on a drawing) --- */\n.tcw-context-menu {\n position: absolute;\n z-index: 70;\n min-width: 200px;\n padding: 4px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-divider);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n}\n.tcw-context-item {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n min-height: var(--tcw-menu-item-h);\n padding: 4px 10px;\n border: 0;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size);\n text-align: start;\n cursor: pointer;\n}\n.tcw-context-item svg, .tcw-context-icon { flex: none; width: 14px; height: 14px; color: var(--tcw-text-muted); }\n.tcw-context-item:hover, .tcw-context-item:focus-visible { background: var(--tcw-bg-surface); outline: none; }\n.tcw-context-item:focus-visible { box-shadow: inset 0 0 0 1px var(--tcw-accent); }\n.tcw-context-danger, .tcw-context-danger svg { color: var(--tcw-red); }\n.tcw-context-sep { height: 1px; margin: 4px 6px; background: var(--tcw-divider); }\n/* --- Toolbar over a selected drawing --- */\n.tcw-sel-toolbar {\n position: absolute;\n z-index: 65;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 3px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-divider);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-family: var(--tcw-font);\n white-space: nowrap;\n animation: tcw-sel-in var(--tcw-dur-fast) var(--tcw-ease-out);\n}\n@keyframes tcw-sel-in { from { opacity: 0; transform: translateY(3px); } }\n.tcw-sel-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n min-width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n padding: 0 6px;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-sel-btn svg { flex: none; }\n.tcw-sel-btn:hover, .tcw-sel-btn[aria-expanded=\"true\"] { background: var(--tcw-hover-bg); color: var(--tcw-text); }\n.tcw-sel-btn:focus-visible, .tcw-sel-swatch:focus-visible, .tcw-sel-option:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--tcw-accent); }\n.tcw-sel-btn.tcw-sel-on { color: var(--tcw-accent); background: var(--tcw-accent-soft); }\n.tcw-sel-danger:hover { color: var(--tcw-red); background: var(--tcw-red-soft); }\n.tcw-sel-color {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tcw-text) 25%, transparent);\n}\n.tcw-sel-width {\n display: inline-block;\n width: 16px;\n height: var(--w, 1px);\n max-height: 6px;\n border-radius: 1px;\n background: currentColor;\n}\n.tcw-sel-sep { flex: none; width: 1px; height: 18px; margin: 0 3px; background: var(--tcw-divider); }\n.tcw-sel-pop {\n position: absolute;\n z-index: 66;\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 120px;\n padding: 4px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-divider);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-family: var(--tcw-font);\n}\n.tcw-sel-pop--color {\n display: grid;\n grid-template-columns: repeat(4, 24px);\n gap: 6px;\n min-width: 0;\n padding: 8px;\n}\n.tcw-sel-swatch {\n width: 24px;\n height: 24px;\n padding: 0;\n border: 0;\n border-radius: 50%;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tcw-text) 20%, transparent);\n cursor: pointer;\n transition: transform var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-sel-swatch:hover { transform: scale(1.1); }\n.tcw-sel-swatch.tcw-sel-on { box-shadow: 0 0 0 2px var(--tcw-bg-elevated), 0 0 0 4px var(--tcw-accent); }\n.tcw-sel-option {\n display: flex;\n align-items: center;\n gap: 10px;\n min-height: var(--tcw-menu-item-h);\n padding: 4px 10px;\n border: 0;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n text-align: start;\n cursor: pointer;\n}\n.tcw-sel-option:hover { background: var(--tcw-bg-surface); }\n.tcw-sel-option.tcw-sel-on { color: var(--tcw-accent); }\n@media (prefers-reduced-motion: reduce) {\n .tcw-sel-toolbar { animation: none; }\n .tcw-sel-swatch { transition: none; }\n}\n\n/* --- Account panel (positions, orders, history) --- */\n.tcw-account-dock {\n flex: none;\n}\n.tcw-account {\n display: flex;\n flex-direction: column;\n height: 220px;\n border-top: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n}\n.tcw-account-head {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 8px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n.tcw-account-tabs {\n display: flex;\n gap: 2px;\n flex: 1;\n min-width: 0;\n overflow-x: auto;\n}\n.tcw-account-tab {\n padding: 6px 10px;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n white-space: nowrap;\n cursor: pointer;\n}\n.tcw-account-tab:hover { color: var(--tcw-text); background: var(--tcw-hover-bg); }\n.tcw-account-tab[aria-selected=\"true\"] { color: var(--tcw-text); background: var(--tcw-active-bg); }\n.tcw-account-tab:focus-visible, .tcw-account-new:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--tcw-accent); }\n.tcw-account-new {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 10px;\n border: 1px solid var(--tcw-accent-line);\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-accent-soft);\n color: var(--tcw-accent);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n cursor: pointer;\n}\n.tcw-account-new:hover { background: var(--tcw-accent-glow); }\n.tcw-account-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n}\n.tcw-account-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n}\n.tcw-account-table th {\n position: sticky;\n top: 0;\n padding: 6px 10px;\n background: var(--tcw-bg-surface);\n color: var(--tcw-text-muted);\n font-weight: var(--tcw-weight);\n text-align: start;\n border-bottom: 1px solid var(--tcw-divider);\n}\n.tcw-account-table td {\n padding: 5px 10px;\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-divider);\n white-space: nowrap;\n}\n.tcw-account-table tr:hover td { background: var(--tcw-hover-bg); }\n.tcw-account-side { font-weight: var(--tcw-weight-strong); }\n.tcw-account-buy, .tcw-account-up { color: var(--tcw-green); }\n.tcw-account-sell, .tcw-account-down { color: var(--tcw-red); }\n.tcw-account-actions { display: flex; gap: 2px; }\n.tcw-account-empty, .tcw-account-summary {\n margin: 0;\n padding: 14px 12px;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-account-summary { padding: 8px 12px; color: var(--tcw-text-dim); }\n@media (max-width: 640px) {\n .tcw-account { height: 45vh; }\n}\n\n/* --- Order ticket --- */\n.tcw-ticket-side {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 6px;\n margin-bottom: 12px;\n}\n.tcw-ticket-side-btn {\n padding: 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n}\n.tcw-ticket-buy[aria-pressed=\"true\"] { background: var(--tcw-green-soft); border-color: var(--tcw-green); color: var(--tcw-green); }\n.tcw-ticket-sell[aria-pressed=\"true\"] { background: var(--tcw-red-soft); border-color: var(--tcw-red); color: var(--tcw-red); }\n.tcw-ticket-side-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--tcw-accent-soft); }\n.tcw-ticket-optional { display: flex; align-items: center; gap: 8px; }\n.tcw-ticket-optional > span { flex: 1; }\n.tcw-ticket-optional .tcw-indi-input { width: 110px; }\n.tcw-ticket-problems {\n min-height: 18px;\n padding: 0 22px 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-ticket-problems p { margin: 2px 0; }\n.tcw-ticket-problems.tcw-ticket-bad { color: var(--tcw-red); }\n.tcw-done-btn.tcw-ticket-sell { background: var(--tcw-red); color: #fff; }\n.tcw-done-btn:disabled { opacity: 0.45; cursor: not-allowed; }\n\n/* --- Named layouts --- */\n.tcw-layouts-btn { max-width: 190px; }\n.tcw-layouts-label {\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n.tcw-layouts-dirty {\n width: 6px;\n height: 6px;\n flex: none;\n border-radius: 50%;\n background: var(--tcw-accent);\n}\n.tcw-name-field { display: flex; flex-direction: column; gap: 6px; font-size: var(--tcw-font-size-sm); color: var(--tcw-text-dim); }\n.tcw-name-field .tcw-indi-input { width: 100%; height: 34px; font-size: var(--tcw-font-size); }\n.tcw-layouts-body { display: flex; flex-direction: column; gap: 10px; }\n.tcw-layouts-search { width: 100%; height: 32px; }\n.tcw-layouts-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n max-height: 50vh;\n overflow-y: auto;\n}\n.tcw-layouts-row {\n display: flex;\n align-items: center;\n gap: 6px;\n border-radius: var(--tcw-radius);\n}\n.tcw-layouts-row:hover { background: var(--tcw-hover-bg); }\n.tcw-layouts-open {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n padding: 7px 8px;\n border: none;\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n text-align: start;\n cursor: pointer;\n border-radius: var(--tcw-radius);\n}\n.tcw-layouts-open:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--tcw-accent-soft); }\n.tcw-layouts-name {\n display: flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.tcw-layouts-open[aria-current=\"true\"] .tcw-layouts-name { color: var(--tcw-accent); }\n.tcw-layouts-meta {\n max-width: 100%;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n font-variant-numeric: tabular-nums;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.tcw-layouts-confirm {\n padding: 4px 10px;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-red);\n color: #fff;\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n}\n.tcw-layouts-confirm:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--tcw-red-soft); }\n\n/* --- Chart grid --- */\n.tcw-grid { background: var(--tcw-bg); }\n.tcw-grid-bar {\n display: flex;\n align-items: center;\n gap: 6px;\n min-height: calc(var(--tcw-control-h) + 8px);\n padding: 0 8px;\n border-bottom: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n overflow-x: auto;\n scrollbar-width: none;\n}\n.tcw-grid-bar::-webkit-scrollbar { display: none; }\n.tcw-grid-group { display: flex; align-items: center; gap: 2px; flex: none; }\n.tcw-grid-label {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-right: 4px;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n letter-spacing: var(--tcw-label-tracking);\n text-transform: var(--tcw-label-case);\n color: var(--tcw-text-muted);\n}\n.tcw-grid-sync[aria-pressed=\"true\"] { color: var(--tcw-accent); }\n.tcw-grid-cells {\n flex: 1;\n min-height: 0;\n display: grid;\n gap: 1px;\n background: var(--tcw-border);\n}\n.tcw-grid-cell {\n position: relative;\n min-width: 0;\n min-height: 0;\n background: var(--tcw-bg);\n}\n.tcw-grid-cell-active::after {\n content: '';\n position: absolute;\n inset: 0;\n border: 1px solid var(--tcw-accent);\n pointer-events: none;\n z-index: 5;\n}\n\n/* --- Host toolbar buttons --- */\n.tcw-toolbar-host { display: inline-flex; align-items: center; gap: 2px; }\n.tcw-toolbar-host:empty { display: none; }\n.tcw-host-btn { display: inline-flex; align-items: center; gap: 4px; }\n\n/* --- Host sidebar buttons, status bar items, and the layer over the chart --- */\n.tcw-sidebar-host { display: flex; flex-direction: column; align-items: center; }\n.tcw-sidebar-host:empty { display: none; }\n.tcw-status-host { display: flex; align-items: center; gap: 10px; min-width: 0; }\n.tcw-status-host:empty { display: none; }\n.tcw-status-host-item { white-space: nowrap; }\n.tcw-status-host-btn {\n margin: -4px -6px;\n padding: 4px 6px;\n font: inherit;\n color: inherit;\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-status-host-btn:hover { color: var(--tcw-text); background: var(--tcw-hover-bg); }\n.tcw-status-host-btn:focus-visible { outline: 2px solid var(--tcw-accent); outline-offset: -2px; }\n/* Over the plot and under the widget's own overlays; the pointer reaches the chart unless an element of yours takes it. */\n.tcw-host-layer { position: absolute; inset: 0; z-index: 2; pointer-events: none; }\n\n/* --- Pane buttons (move, fold, maximise) --- */\n.tcw-pane-controls {\n position: absolute;\n z-index: 4;\n display: flex;\n gap: 1px;\n transform: translateX(-100%);\n padding: 1px;\n border-radius: var(--tcw-radius-sm);\n background: color-mix(in srgb, var(--tcw-bg) 80%, transparent);\n opacity: 0.55;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-pane-controls:hover,\n.tcw-pane-controls:focus-within { opacity: 1; }\n.tcw-pane-btn {\n display: inline-grid;\n place-items: center;\n width: 18px;\n height: 16px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-pane-btn:hover { color: var(--tcw-text); background: var(--tcw-hover-bg); }\n.tcw-pane-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--tcw-accent-soft); }\n\n/* --- Typed interval --- */\n.tcw-interval-input {\n position: absolute;\n z-index: 20;\n left: 50%;\n top: 40%;\n transform: translate(-50%, -50%);\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 12px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-lg, 10px);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n.tcw-interval-field {\n width: 150px;\n height: 36px;\n padding: 0 10px;\n font: inherit;\n font-size: calc(var(--tcw-font-size) + 5px);\n font-weight: var(--tcw-weight-strong);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-accent);\n border-radius: var(--tcw-input-radius);\n outline: none;\n}\n.tcw-interval-field[aria-invalid] { border-color: var(--tcw-red); }\n.tcw-interval-hint { font-size: var(--tcw-font-size-xs); color: var(--tcw-text-muted); max-width: 170px; }\n\n/* --- Alerts: lines, moves, bar close, expiry --- */\n.tcw-alerts-source { grid-column: auto; }\n.tcw-alerts-row-fields {\n grid-column: 1 / -1;\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 8px;\n}\n.tcw-alerts-row-fields[hidden] { display: none; }\n.tcw-alerts-row-fields > input[hidden] { display: none; }\n.tcw-alerts-row-fields:has(> input[hidden]) { grid-template-columns: 1fr; }\n.tcw-alerts-options { align-items: center; }\n.tcw-alerts-form .tcw-alerts-check {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-alerts-form .tcw-alerts-check input { width: auto; height: auto; }\n.tcw-alerts-form input[aria-invalid=\"true\"] { border-color: var(--tcw-red); }\n.tcw-alerts-row-meta { margin-top: 2px; font-size: var(--tcw-font-size-xs); color: var(--tcw-text-muted); }\n.tcw-alerts-expired { opacity: 0.6; }\n\n/* --- Signal marker note --- */\n.tcw-marker-tip {\n position: absolute;\n z-index: 12;\n pointer-events: none;\n padding: 6px 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-tooltip-radius);\n background: var(--tcw-tooltip-bg);\n color: var(--tcw-tooltip-fg);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.45;\n font-variant-numeric: tabular-nums;\n box-shadow: var(--tcw-menu-shadow);\n max-width: 240px;\n}\n.tcw-marker-tip strong { display: block; font-size: var(--tcw-font-size-sm); }\n\n/* === Navigation over the chart ===\n * Centred on the plot's bottom edge, shown while a mouse is over the chart. */\n.tcw-nav {\n position: absolute;\n z-index: 15;\n display: flex;\n gap: 2px;\n padding: 3px;\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: calc(var(--tcw-control-radius) + 3px);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n opacity: 0;\n pointer-events: none;\n transform: translate(-50%, calc(-100% - 12px));\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-nav.tcw-nav-shown {\n opacity: 1;\n pointer-events: auto;\n}\n.tcw-nav-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n cursor: pointer;\n touch-action: none;\n}\n.tcw-nav-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n.tcw-nav-btn:active {\n background: var(--tcw-active-bg);\n}\n.tcw-nav-btn:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n.tcw-nav-btn svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n@media (hover: none) {\n .tcw-nav { display: none; }\n}\n\n/* === Symbol info ===\n * Top left, beside the drawing tools: the panels on the right stay clear. */\n.tcw-syminfo {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-start: var(--tcw-panel-left);\n z-index: 38;\n width: 288px;\n max-height: calc(100% - var(--tcw-panel-top) - 12px);\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-syminfo-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 9px 12px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-syminfo-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-syminfo-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\n.tcw-syminfo-body,\n.tcw-syminfo-news {\n padding: 12px 14px;\n overflow-y: auto;\n}\n.tcw-syminfo-body {\n display: grid;\n gap: 10px;\n}\n.tcw-syminfo-symbol {\n font-size: var(--tcw-font-size-lg);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-syminfo-desc {\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-syminfo-meta {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n.tcw-syminfo-quote {\n display: flex;\n align-items: baseline;\n gap: 10px;\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n}\n.tcw-syminfo-price {\n font-size: calc(var(--tcw-font-size) + 7px);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-syminfo-change { font-size: var(--tcw-font-size-sm); }\n.tcw-syminfo-change.tcw-up { color: var(--tcw-green); }\n.tcw-syminfo-change.tcw-down { color: var(--tcw-red); }\n.tcw-syminfo-status {\n display: flex;\n align-items: center;\n gap: 7px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-syminfo-status::before,\n.tcw-status-market::before {\n content: '';\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n}\n.tcw-syminfo-status[data-state='open']::before,\n.tcw-syminfo-status[data-state='always']::before,\n.tcw-status-market[data-state='open']::before {\n background: var(--tcw-green);\n}\n.tcw-syminfo-stats {\n display: grid;\n gap: 4px;\n margin: 0;\n padding-top: 10px;\n border-top: 1px solid var(--tcw-divider);\n}\n.tcw-syminfo-stat {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-syminfo-stat dt { color: var(--tcw-text-muted); }\n.tcw-syminfo-stat dd {\n margin: 0;\n color: var(--tcw-text);\n text-align: end;\n font-variant-numeric: tabular-nums;\n overflow-wrap: anywhere;\n}\n.tcw-syminfo-news {\n border-top: 1px solid var(--tcw-divider);\n}\n.tcw-syminfo-news-title {\n margin-bottom: 8px;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text-muted);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n.tcw-syminfo-news-list {\n display: grid;\n gap: 10px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.tcw-syminfo-news-item {\n font-size: var(--tcw-font-size-sm);\n line-height: 1.4;\n color: var(--tcw-text);\n}\n.tcw-syminfo-news-item a {\n color: var(--tcw-text);\n text-decoration: none;\n}\n.tcw-syminfo-news-item a:hover { color: var(--tcw-accent); text-decoration: underline; }\n.tcw-syminfo-news-item a:focus-visible { outline: none; box-shadow: var(--tcw-ring); border-radius: var(--tcw-radius-xs); }\n.tcw-syminfo-news-meta,\n.tcw-syminfo-news-note {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n\n/* Numbers keep their sign on the left, and mixed text its own order, in a right-to-left widget too. */\n.tcw-watchlist-price,\n.tcw-watchlist-change,\n.tcw-syminfo-price,\n.tcw-syminfo-change {\n unicode-bidi: isolate;\n direction: ltr;\n}\n.tcw-syminfo-desc,\n.tcw-syminfo-meta,\n.tcw-syminfo-status,\n.tcw-syminfo-stat dd,\n.tcw-syminfo-news-meta {\n unicode-bidi: plaintext;\n}\n\n/* The market's status in the status bar. */\n.tcw-status-market {\n display: flex;\n align-items: center;\n gap: 7px;\n color: var(--tcw-text-muted);\n}\n\n@media (max-width: 640px) {\n .tcw-syminfo {\n top: auto;\n bottom: 0;\n left: 0;\n right: 0;\n width: 100vw;\n max-height: 70%;\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 0 0;\n }\n}\n\n/* === The look: how chosen controls show, floating bars, segmented intervals ===\n * Each switch sets variables on its own root, which its parts read: a grid's\n * look never reaches into a chart that has one of its own. */\n\n/* A chosen button (`ui.active`): a tinted fill (default), a solid pill, or an underline.\n * Dialog tabs are chips, or underlined in the underline look. Panels sit below the\n * toolbar and beside the drawing tools. */\n.tcw-root {\n --tcw-on-bg: var(--tcw-accent-soft);\n --tcw-on-fg: var(--tcw-accent);\n --tcw-on-ring: none;\n --tcw-on-icon-bg: var(--tcw-accent-soft);\n --tcw-on-icon-fg: var(--tcw-accent);\n --tcw-on-icon-ring: none;\n --tcw-tabs-pad-block: 8px;\n --tcw-tab-h: var(--tcw-control-h);\n --tcw-tab-pad: 0 12px;\n --tcw-tab-line: 0px;\n --tcw-tab-radius: var(--tcw-control-radius);\n --tcw-tab-hover: var(--tcw-hover-bg);\n --tcw-tab-on-bg: var(--tcw-on-bg);\n --tcw-tab-on-fg: var(--tcw-on-fg);\n --tcw-panel-top: calc(var(--tcw-toolbar-h) + 6px);\n --tcw-panel-left: calc(var(--tcw-sidebar-w) + 12px);\n}\n.tcw-root[data-tcw-active='solid'] {\n --tcw-on-bg: var(--tcw-text);\n --tcw-on-fg: var(--tcw-bg);\n --tcw-on-icon-bg: var(--tcw-text);\n --tcw-on-icon-fg: var(--tcw-bg);\n}\n.tcw-root[data-tcw-active='underline'] {\n --tcw-on-bg: var(--tcw-active-bg);\n --tcw-on-fg: var(--tcw-text);\n --tcw-on-ring: inset 0 -2px 0 var(--tcw-accent);\n --tcw-on-icon-bg: var(--tcw-active-bg);\n --tcw-on-icon-fg: var(--tcw-accent);\n --tcw-on-icon-ring: inset 2px 0 0 var(--tcw-accent);\n --tcw-tabs-pad-block: 0px;\n --tcw-tab-h: auto;\n --tcw-tab-pad: 11px 14px;\n --tcw-tab-line: 2px;\n --tcw-tab-radius: 0px;\n --tcw-tab-hover: transparent;\n --tcw-tab-on-bg: transparent;\n --tcw-tab-on-fg: var(--tcw-accent);\n}\n.tcw-root[data-tcw-toolbar='floating'] {\n --tcw-panel-top: calc(var(--tcw-toolbar-h) + 2 * var(--tcw-border-w) + 14px);\n}\n.tcw-root[data-tcw-sidebar='floating'] {\n --tcw-panel-left: calc(var(--tcw-sidebar-w) + 2 * var(--tcw-border-w) + 22px);\n}\n\n/* The toolbar as an island (`ui.toolbar: 'floating'`). */\n.tcw-root[data-tcw-toolbar='floating'] > .tcw-toolbar {\n margin: 8px 10px 0;\n padding-inline: calc(min(var(--tcw-toolbar-radius), var(--tcw-toolbar-h) / 2) / 2 + 8px);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-toolbar-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n/* The drawing tools as an island (`ui.sidebar: 'floating'`). */\n.tcw-root[data-tcw-sidebar='floating'] > .tcw-body > .tcw-sidebar {\n align-self: flex-start;\n max-height: calc(100% - 20px);\n margin: 10px 6px 10px 10px;\n padding-block: calc(min(var(--tcw-sidebar-radius), var(--tcw-sidebar-w) / 2) / 2 + 6px);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-sidebar-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n/* Frosted menus (`ui.blur` above 0): the chart shows through, blurred. */\n@supports (background: color-mix(in srgb, red 50%, transparent)) {\n .tcw-dropdown,\n .tcw-flyout,\n .tcw-context-menu {\n background: color-mix(in srgb, var(--tcw-bg-elevated) var(--tcw-surface-opacity), transparent);\n }\n}\n\n/* The interval buttons in one track (`ui.intervals: 'segmented'`). */\n.tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group {\n gap: 2px;\n margin: 0 4px;\n padding: 3px;\n border-radius: calc(var(--tcw-control-radius) + 3px);\n background: var(--tcw-hover-bg);\n}\n.tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group .tcw-btn {\n height: calc(var(--tcw-control-h) - 6px);\n padding: 0 9px;\n}\n\n/* Phones: the variants keep comfortable tap targets and room for the bar. */\n@media (max-width: 768px) {\n .tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group .tcw-btn {\n height: max(34px, calc(var(--tcw-control-h) - 6px));\n padding: 0 10px;\n }\n .tcw-root[data-tcw-toolbar='floating'] > .tcw-toolbar {\n margin: 6px 6px 0;\n padding-inline: 4px;\n }\n .tcw-root[data-tcw-sidebar='floating'] > .tcw-body > .tcw-sidebar {\n margin: 6px 4px 6px 6px;\n }\n}\n", O = /* @__PURE__ */ "toolbar,sidebar,statusBar,alerts,objectTree,symbolInfo,symbolSearch,settings,indicatorSettings,drawingSettings,dataWindow,commandPalette,hotkeySheet,goToDate,replay,screenshot,copyImage,shareView,autoFib,themeToggle,fullscreen,accountPanel,orderTicket,bracketOrders,depthLadder,layouts,indicatorTemplates,compare,indicatorLegend,navigation,customTimeframes,intervalTyping,dragDropImport,hotkeys,toasts,toolbar.symbol,toolbar.symbolInfo,toolbar.timeframes,toolbar.timeframeMenu,toolbar.chartType,toolbar.indicators,toolbar.layouts,toolbar.replay,toolbar.bracketOrders,toolbar.depthLadder,toolbar.accountPanel,toolbar.objectTree,toolbar.alerts,toolbar.screenshot,toolbar.settings,toolbar.themeToggle,toolbar.fullscreen,sidebar.cursor,sidebar.favorites,sidebar.lines,sidebar.fibonacci,sidebar.patterns,sidebar.forecasting,sidebar.annotation,sidebar.style,sidebar.magnet,sidebar.eraser,sidebar.zoomArea,sidebar.stayInDrawing,sidebar.undo,sidebar.redo,sidebar.clear,statusBar.range,statusBar.goToDate,statusBar.market,statusBar.connection,statusBar.symbol,statusBar.rangeTimeframe,indicatorLegend.values,indicatorLegend.visibility,indicatorLegend.settings,indicatorLegend.remove,indicatorLegend.more,pane.move,pane.collapse,pane.maximize,navigation.zoom,navigation.scroll,navigation.reset,menu.chart,menu.chart.alert,menu.chart.order,menu.chart.orderTicket,menu.chart.horizontalLine,menu.chart.resetView,menu.chart.drawings,menu.chart.exportData,menu.chart.settings,menu.chart.scale,menu.chart.goToDate,menu.chart.paneScale,menu.priceAxisAdd,menu.drawing,menu.drawing.settings,menu.drawing.alert,menu.drawing.order,menu.drawing.group,menu.drawing.lock,menu.drawing.hide,menu.drawing.duplicate,menu.drawing.delete,selectionToolbar,hotkeys.commandPalette,hotkeys.symbolSearch,hotkeys.save,hotkeys.tools,hotkeys.invertScale,hotkeys.goToDate,hotkeys.help".split(","), $e = new Set(O), et = {
|
|
1463
1463
|
toolbar: ["toolbar"],
|
|
1464
1464
|
drawingTools: [
|
|
1465
1465
|
"sidebar",
|
|
@@ -1469,7 +1469,11 @@ var Ke = [...new Set([...Object.keys(g).filter((e) => e.startsWith("series.")),
|
|
|
1469
1469
|
],
|
|
1470
1470
|
settings: ["settings"],
|
|
1471
1471
|
statusBar: ["statusBar", "goToDate"],
|
|
1472
|
-
rangeBar: [
|
|
1472
|
+
rangeBar: [
|
|
1473
|
+
"statusBar.range",
|
|
1474
|
+
"statusBar.rangeTimeframe",
|
|
1475
|
+
"goToDate"
|
|
1476
|
+
],
|
|
1473
1477
|
indicatorLegend: ["indicatorLegend"],
|
|
1474
1478
|
fullscreen: ["fullscreen"],
|
|
1475
1479
|
alerts: ["alerts"],
|
|
@@ -1481,7 +1485,7 @@ var Ke = [...new Set([...Object.keys(g).filter((e) => e.startsWith("series.")),
|
|
|
1481
1485
|
navigation: ["navigation"],
|
|
1482
1486
|
dragDropImport: ["dragDropImport"],
|
|
1483
1487
|
customTimeframes: ["customTimeframes"]
|
|
1484
|
-
},
|
|
1488
|
+
}, tt = {
|
|
1485
1489
|
alert: ["alerts", "menu.chart.alert"],
|
|
1486
1490
|
buyLimit: ["menu.chart.order"],
|
|
1487
1491
|
buyStop: ["menu.chart.order"],
|
|
@@ -1503,7 +1507,7 @@ var Ke = [...new Set([...Object.keys(g).filter((e) => e.startsWith("series.")),
|
|
|
1503
1507
|
paneLog: ["menu.chart.paneScale"],
|
|
1504
1508
|
paneInvert: ["menu.chart.paneScale"],
|
|
1505
1509
|
panePercent: ["menu.chart.paneScale"]
|
|
1506
|
-
},
|
|
1510
|
+
}, nt = {
|
|
1507
1511
|
settings: ["drawingSettings", "menu.drawing.settings"],
|
|
1508
1512
|
alert: ["alerts", "menu.drawing.alert"],
|
|
1509
1513
|
front: ["menu.drawing.order"],
|
|
@@ -1517,7 +1521,7 @@ var Ke = [...new Set([...Object.keys(g).filter((e) => e.startsWith("series.")),
|
|
|
1517
1521
|
hide: ["menu.drawing.hide"],
|
|
1518
1522
|
duplicate: ["menu.drawing.duplicate"],
|
|
1519
1523
|
delete: ["menu.drawing.delete"]
|
|
1520
|
-
},
|
|
1524
|
+
}, rt = {
|
|
1521
1525
|
screenshot: "screenshot",
|
|
1522
1526
|
copyImage: "copyImage",
|
|
1523
1527
|
toggleTheme: "themeToggle",
|
|
@@ -1527,24 +1531,24 @@ var Ke = [...new Set([...Object.keys(g).filter((e) => e.startsWith("series.")),
|
|
|
1527
1531
|
dataWindow: "dataWindow",
|
|
1528
1532
|
symbolInfo: "symbolInfo"
|
|
1529
1533
|
};
|
|
1530
|
-
function
|
|
1534
|
+
function it(e) {
|
|
1531
1535
|
if (typeof e != "object" || !e || Array.isArray(e)) return {};
|
|
1532
1536
|
let t = {}, n = [];
|
|
1533
|
-
for (let [r, i] of Object.entries(e))
|
|
1537
|
+
for (let [r, i] of Object.entries(e)) $e.has(r) && typeof i == "boolean" ? t[r] = i : n.push(r);
|
|
1534
1538
|
return n.length > 0 && console.warn(`[ChartWidget] Unknown or non-boolean feature switches left out: ${n.join(", ")}.`), t;
|
|
1535
1539
|
}
|
|
1536
|
-
function
|
|
1540
|
+
function at(e) {
|
|
1537
1541
|
let t = Object.fromEntries(O.map((e) => [e, !0]));
|
|
1538
|
-
for (let [n, r] of Object.entries(
|
|
1542
|
+
for (let [n, r] of Object.entries(et)) if (e[n] === !1) for (let e of r) t[e] = !1;
|
|
1539
1543
|
return {
|
|
1540
1544
|
...t,
|
|
1541
|
-
|
|
1545
|
+
...it(e.features)
|
|
1542
1546
|
};
|
|
1543
1547
|
}
|
|
1544
|
-
function
|
|
1548
|
+
function ot(e) {
|
|
1545
1549
|
return O.filter((t) => !e[t]).join(" ");
|
|
1546
1550
|
}
|
|
1547
|
-
var k = "tcw-divider-off",
|
|
1551
|
+
var k = "tcw-divider-off", st = [
|
|
1548
1552
|
{
|
|
1549
1553
|
names: [
|
|
1550
1554
|
"navigation.zoom",
|
|
@@ -1571,23 +1575,23 @@ var k = "tcw-divider-off", nt = [
|
|
|
1571
1575
|
selector: ".tcw-ind-legend-actions"
|
|
1572
1576
|
}
|
|
1573
1577
|
];
|
|
1574
|
-
function
|
|
1578
|
+
function ct() {
|
|
1575
1579
|
return [
|
|
1576
1580
|
...O.map((e) => `.tcw-root[data-tcw-off~="${e}"] [data-tcw-part~="${e}"]{display:none!important}`),
|
|
1577
|
-
...
|
|
1581
|
+
...st.map(({ names: e, selector: t }) => `.tcw-root${e.map((e) => `[data-tcw-off~="${e}"]`).join("")} ${t}{display:none!important}`),
|
|
1578
1582
|
`.${k}{display:none!important}`
|
|
1579
1583
|
].join("\n");
|
|
1580
1584
|
}
|
|
1581
1585
|
function A(e, ...t) {
|
|
1582
1586
|
e.dataset.tcwPart = t.join(" ");
|
|
1583
1587
|
}
|
|
1584
|
-
function
|
|
1588
|
+
function lt(...e) {
|
|
1585
1589
|
return `data-tcw-part="${e.join(" ")}"`;
|
|
1586
1590
|
}
|
|
1587
|
-
function
|
|
1588
|
-
return Object.prototype.hasOwnProperty.call(
|
|
1591
|
+
function ut(e) {
|
|
1592
|
+
return Object.prototype.hasOwnProperty.call(rt, e) ? rt[e] : void 0;
|
|
1589
1593
|
}
|
|
1590
|
-
function
|
|
1594
|
+
function dt(e, t, n) {
|
|
1591
1595
|
let r = [...e.children], i = (e) => e.classList.contains(t);
|
|
1592
1596
|
for (let e of r) i(e) && e.classList.remove(k);
|
|
1593
1597
|
let a = (e) => !e.hidden && getComputedStyle(e).display !== "none", o = (e) => a(e) && (e instanceof HTMLButtonElement || e.childElementCount > 0 || e.textContent !== ""), s = !1, c = null;
|
|
@@ -1598,7 +1602,7 @@ function ot(e, t, n) {
|
|
|
1598
1602
|
} else o(e) && (s = !0, c = null);
|
|
1599
1603
|
c?.classList.add(k);
|
|
1600
1604
|
}
|
|
1601
|
-
function
|
|
1605
|
+
function ft(e, t, n) {
|
|
1602
1606
|
let r = e.filter((e) => e === "separator" ? !0 : (t[e.id] ?? []).every((e) => n[e]));
|
|
1603
1607
|
return r.filter((e, t) => {
|
|
1604
1608
|
if (e !== "separator") return !0;
|
|
@@ -1608,568 +1612,30 @@ function st(e, t, n) {
|
|
|
1608
1612
|
}
|
|
1609
1613
|
//#endregion
|
|
1610
1614
|
//#region src/widget/WidgetStyles.ts
|
|
1611
|
-
var
|
|
1612
|
-
function
|
|
1613
|
-
if (
|
|
1615
|
+
var pt = 0, mt = "tcw-styles";
|
|
1616
|
+
function ht() {
|
|
1617
|
+
if (pt++, pt > 1 || document.getElementById(mt)) return;
|
|
1614
1618
|
let e = document.createElement("style");
|
|
1615
|
-
e.id =
|
|
1616
|
-
${
|
|
1619
|
+
e.id = mt, e.textContent = `${Qe}
|
|
1620
|
+
${ct()}`, document.head.insertBefore(e, document.head.firstChild);
|
|
1617
1621
|
}
|
|
1618
|
-
function
|
|
1619
|
-
if (
|
|
1620
|
-
let e = document.getElementById(
|
|
1622
|
+
function gt() {
|
|
1623
|
+
if (pt--, pt > 0) return;
|
|
1624
|
+
let e = document.getElementById(mt);
|
|
1621
1625
|
e && e.remove();
|
|
1622
1626
|
}
|
|
1623
1627
|
//#endregion
|
|
1624
|
-
//#region src/widget/iconSet.ts
|
|
1625
|
-
var ft = {
|
|
1626
|
-
cursor: { d: "M6 3.5L18.5 12.5L12.6 13.6L9.7 19.4z" },
|
|
1627
|
-
trendingUp: { d: "M3 17L9 11L13 14.5L21 6.5M15 6.5H21V12.5" },
|
|
1628
|
-
trendingDown: { d: "M3 7L9 13L13 9.5L21 17.5M15 17.5H21V11.5" },
|
|
1629
|
-
minus: { d: "M5 12H19" },
|
|
1630
|
-
plus: { d: "M12 5V19M5 12H19" },
|
|
1631
|
-
penLine: { d: "M14.5 5.5L18.5 9.5M4 20L5 15.5L15.8 4.7a2 2 0 0 1 2.83 0l.67.67a2 2 0 0 1 0 2.83L8.5 19z" },
|
|
1632
|
-
zigzag: { d: "M3 17L8 9L13 15L21 6" },
|
|
1633
|
-
hash: { d: "M5 9H19M5 15H19M10 4L8.5 20M15.5 4L14 20" },
|
|
1634
|
-
square: { d: "M6.5 4.5h11a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2h-11a2 2 0 0 1-2-2v-11a2 2 0 0 1 2-2z" },
|
|
1635
|
-
gitBranch: { d: "M6 3V15M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM18 9a9 9 0 0 1-9 9" },
|
|
1636
|
-
ruler: { d: "M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9" },
|
|
1637
|
-
type: { d: "M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5" },
|
|
1638
|
-
magnet: { d: "M6 4V11a6 6 0 0 0 12 0V4M6 4h3.5v7a2.5 2.5 0 0 0 5 0V4H18M6 8h3.5M14.5 8H18" },
|
|
1639
|
-
magnetStrong: {
|
|
1640
|
-
d: "M6 4V11a6 6 0 0 0 12 0V4M6 4h3.5v7a2.5 2.5 0 0 0 5 0V4H18",
|
|
1641
|
-
fills: ["M6 4h3.5v4H6z", "M14.5 4H18v4h-3.5z"]
|
|
1642
|
-
},
|
|
1643
|
-
eraser: { d: "M8.5 19.5L3.9 14.9a1.5 1.5 0 0 1 0-2.1l8.5-8.5a1.5 1.5 0 0 1 2.1 0l5.2 5.2a1.5 1.5 0 0 1 0 2.1L12 19.5zM8 9l7 7M12 19.5H20" },
|
|
1644
|
-
zoomIn: { d: "M16.5 10.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0zM15 15L20.5 20.5M10.5 7.5V13.5M7.5 10.5H13.5" },
|
|
1645
|
-
undo: { d: "M9 14L4 9L9 4M4 9H14.5a5.5 5.5 0 0 1 0 11H11" },
|
|
1646
|
-
redo: { d: "M15 14L20 9L15 4M20 9H9.5a5.5 5.5 0 0 0 0 11H13" },
|
|
1647
|
-
trash: { d: "M4 7H20M9.5 7V4.5h5V7M6.5 7l.8 12.2A1.5 1.5 0 0 0 8.8 20.6h6.4a1.5 1.5 0 0 0 1.5-1.4L17.5 7M10 11v6M14 11v6" },
|
|
1648
|
-
camera: { d: "M4.5 7.5h3L9 5h6l1.5 2.5h3A1.5 1.5 0 0 1 21 9v9.5a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 18.5V9a1.5 1.5 0 0 1 1.5-1.5zM15.5 13.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0z" },
|
|
1649
|
-
settings: { d: "M4 7H14M18 7H20M4 17H8M12 17H20M18 7a2 2 0 1 1-4 0 2 2 0 0 1 4 0zM12 17a2 2 0 1 1-4 0 2 2 0 0 1 4 0z" },
|
|
1650
|
-
moon: { d: "M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z" },
|
|
1651
|
-
sun: { d: "M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0zM12 2.5v2M12 19.5v2M4.6 4.6l1.4 1.4M18 18l1.4 1.4M2.5 12h2M19.5 12h2M4.6 19.4L6 18M18 6l1.4-1.4" },
|
|
1652
|
-
chevronDown: { d: "M6 9L12 15L18 9" },
|
|
1653
|
-
chevronUp: { d: "M6 15L12 9L18 15" },
|
|
1654
|
-
barChart: { d: "M5 20V13M12 20V5M19 20V10" },
|
|
1655
|
-
x: { d: "M6 6L18 18M18 6L6 18" },
|
|
1656
|
-
play: { d: "M7 4.5v15L19.5 12z" },
|
|
1657
|
-
pause: { d: "M8 5V19M16 5V19" },
|
|
1658
|
-
stop: { d: "M7.5 6h9A1.5 1.5 0 0 1 18 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 6 16.5v-9A1.5 1.5 0 0 1 7.5 6z" },
|
|
1659
|
-
receipt: { d: "M6 3.5h12v17l-2-1.25-2 1.25-2-1.25-2 1.25-2-1.25-2 1.25zM9 8h6M9 12h6M9 16h3" },
|
|
1660
|
-
bell: { d: "M6 16.5V11a6 6 0 0 1 12 0v5.5l1.5 2H4.5zM10 20.5a2.2 2.2 0 0 0 4 0" },
|
|
1661
|
-
layers: { d: "M12 3.5L21 8.5L12 13.5L3 8.5zM3 12.5L12 17.5L21 12.5M3 16.5L12 21.5L21 16.5" },
|
|
1662
|
-
eye: { d: "M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12zM15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0z" },
|
|
1663
|
-
eyeOff: { d: "M4 4L20 20M9.9 5.8A9.6 9.6 0 0 1 12 5.5c6 0 9.5 6.5 9.5 6.5a16 16 0 0 1-2.3 3.1M6.6 7.1C3.9 8.9 2.5 12 2.5 12S6 18.5 12 18.5a9.3 9.3 0 0 0 4.7-1.3M10 10.1a3 3 0 0 0 4 4" },
|
|
1664
|
-
lock: { d: "M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 8 0v3" },
|
|
1665
|
-
unlock: { d: "M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 7.7-1.5" },
|
|
1666
|
-
palette: {
|
|
1667
|
-
d: "M12 3.5a8.5 8.5 0 0 0 0 17c1.1 0 1.6-.8 1.6-1.6 0-.5-.2-.9-.5-1.2a1.6 1.6 0 0 1 1.2-2.7h1.9a4.3 4.3 0 0 0 4.3-4.3C20.5 6.9 16.7 3.5 12 3.5z",
|
|
1668
|
-
dots: [
|
|
1669
|
-
[
|
|
1670
|
-
7.5,
|
|
1671
|
-
11.5,
|
|
1672
|
-
1.25
|
|
1673
|
-
],
|
|
1674
|
-
[
|
|
1675
|
-
9.5,
|
|
1676
|
-
7.75,
|
|
1677
|
-
1.25
|
|
1678
|
-
],
|
|
1679
|
-
[
|
|
1680
|
-
14,
|
|
1681
|
-
7.25,
|
|
1682
|
-
1.25
|
|
1683
|
-
]
|
|
1684
|
-
]
|
|
1685
|
-
},
|
|
1686
|
-
check: { d: "M5 12.5L10 17.5L19 7" },
|
|
1687
|
-
maximize: { d: "M8 4H5a1 1 0 0 0-1 1v3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3" },
|
|
1688
|
-
minimize: { d: "M4 8h3a1 1 0 0 0 1-1V4M16 4v3a1 1 0 0 0 1 1h3M20 16h-3a1 1 0 0 0-1 1v3M8 20v-3a1 1 0 0 0-1-1H4" },
|
|
1689
|
-
repeat: { d: "M17 3.5L20.5 7L17 10.5M3.5 11.5V10a3 3 0 0 1 3-3h14M7 20.5L3.5 17L7 13.5M20.5 12.5V14a3 3 0 0 1-3 3h-14" },
|
|
1690
|
-
info: {
|
|
1691
|
-
d: "M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0zM12 11V16.5",
|
|
1692
|
-
dots: [[
|
|
1693
|
-
12,
|
|
1694
|
-
7.75,
|
|
1695
|
-
1.25
|
|
1696
|
-
]]
|
|
1697
|
-
},
|
|
1698
|
-
chevronLeft: { d: "M15 5L8 12L15 19" },
|
|
1699
|
-
chevronRight: { d: "M9 5L16 12L9 19" },
|
|
1700
|
-
reset: { d: "M4.5 12a7.5 7.5 0 1 0 2.2-5.3M4.5 4v4.5H9" },
|
|
1701
|
-
calendar: { d: "M5.5 5h13a2 2 0 0 1 2 2v11.5a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2zM3.5 10H20.5M8 3V7M16 3V7" },
|
|
1702
|
-
star: { d: "M12 3.5L14.6 9L20.5 9.6L16 13.6L17.3 19.5L12 16.5L6.7 19.5L8 13.6L3.5 9.6L9.4 9z" },
|
|
1703
|
-
ladder: { d: "M4 6H11M13 6H17M6 10H11M13 10H20M8 14H11M13 14H15M5 18H11M13 18H19" },
|
|
1704
|
-
save: { d: "M5.5 3.5h10.5l4.5 4.5v10.5a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2v-13a2 2 0 0 1 2-2zM8 3.5v5h7v-5M7.5 20.5v-6h9v6" },
|
|
1705
|
-
folder: { d: "M3.5 7a2 2 0 0 1 2-2h4l2 2.5h7a2 2 0 0 1 2 2V17a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2z" },
|
|
1706
|
-
link: { d: "M10 14a4 4 0 0 0 5.66 0l3-3a4 4 0 0 0-5.66-5.66l-1.2 1.2M14 10a4 4 0 0 0-5.66 0l-3 3a4 4 0 0 0 5.66 5.66l1.2-1.2" },
|
|
1707
|
-
arrowUp: { d: "M12 19V5M6 11L12 5L18 11" },
|
|
1708
|
-
arrowDown: { d: "M12 5V19M6 13L12 19L18 13" },
|
|
1709
|
-
more: { dots: [
|
|
1710
|
-
[
|
|
1711
|
-
6,
|
|
1712
|
-
12,
|
|
1713
|
-
1.6
|
|
1714
|
-
],
|
|
1715
|
-
[
|
|
1716
|
-
12,
|
|
1717
|
-
12,
|
|
1718
|
-
1.6
|
|
1719
|
-
],
|
|
1720
|
-
[
|
|
1721
|
-
18,
|
|
1722
|
-
12,
|
|
1723
|
-
1.6
|
|
1724
|
-
]
|
|
1725
|
-
] },
|
|
1726
|
-
layoutGrid: { d: "M5 4.5h4.5a.5.5 0 0 1 .5.5v4.5a.5.5 0 0 1-.5.5H5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5zM14.5 4.5H19a.5.5 0 0 1 .5.5v4.5a.5.5 0 0 1-.5.5h-4.5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5zM5 14h4.5a.5.5 0 0 1 .5.5V19a.5.5 0 0 1-.5.5H5a.5.5 0 0 1-.5-.5v-4.5A.5.5 0 0 1 5 14zM14.5 14H19a.5.5 0 0 1 .5.5V19a.5.5 0 0 1-.5.5h-4.5a.5.5 0 0 1-.5-.5v-4.5a.5.5 0 0 1 .5-.5z" }
|
|
1727
|
-
}, pt = {
|
|
1728
|
-
trendLine: {
|
|
1729
|
-
d: "M5 18L19 6",
|
|
1730
|
-
dots: [[5, 18], [19, 6]]
|
|
1731
|
-
},
|
|
1732
|
-
ray: {
|
|
1733
|
-
d: "M5 17L21 5M17.5 4.81L21 5L20.2 8.41",
|
|
1734
|
-
dots: [[5, 17], [11, 12.5]]
|
|
1735
|
-
},
|
|
1736
|
-
extendedLine: {
|
|
1737
|
-
d: "M3 18.5L21 5M17.5 4.81L21 5L20.2 8.41M6.5 18.69L3 18.5L3.8 15.09",
|
|
1738
|
-
dots: [[9, 14], [15, 9.5]]
|
|
1739
|
-
},
|
|
1740
|
-
infoLine: {
|
|
1741
|
-
d: "M5 20L19 10M4.5 3.5h9a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1zM6.5 6.5h5",
|
|
1742
|
-
dots: [[5, 20], [19, 10]]
|
|
1743
|
-
},
|
|
1744
|
-
trendAngle: {
|
|
1745
|
-
d: "M5 18L19 7M5 18H20M11 18A6 6 0 0 0 9.71 14.29",
|
|
1746
|
-
dots: [[5, 18], [19, 7]]
|
|
1747
|
-
},
|
|
1748
|
-
horizontalLine: {
|
|
1749
|
-
d: "M3 12H21",
|
|
1750
|
-
dots: [[12, 12]]
|
|
1751
|
-
},
|
|
1752
|
-
horizontalRay: {
|
|
1753
|
-
d: "M7 12H21M18.5 9.5L21 12L18.5 14.5",
|
|
1754
|
-
dots: [[7, 12]]
|
|
1755
|
-
},
|
|
1756
|
-
verticalLine: {
|
|
1757
|
-
d: "M12 3V21",
|
|
1758
|
-
dots: [[12, 12]]
|
|
1759
|
-
},
|
|
1760
|
-
crossLine: {
|
|
1761
|
-
d: "M3 12H21M12 3V21",
|
|
1762
|
-
dots: [[12, 12]]
|
|
1763
|
-
},
|
|
1764
|
-
parallelChannel: {
|
|
1765
|
-
d: "M3 15L15 5M9 19L21 9",
|
|
1766
|
-
dots: [
|
|
1767
|
-
[3, 15],
|
|
1768
|
-
[15, 5],
|
|
1769
|
-
[9, 19]
|
|
1770
|
-
]
|
|
1771
|
-
},
|
|
1772
|
-
regressionChannel: {
|
|
1773
|
-
d: "M3 12L21 4M3 20L21 12",
|
|
1774
|
-
dash: "M3 16L21 8",
|
|
1775
|
-
dots: [[3, 16], [21, 8]]
|
|
1776
|
-
},
|
|
1777
|
-
fibRetracement: {
|
|
1778
|
-
d: "M3 4H21M3 9H21M3 13H21M3 20H21",
|
|
1779
|
-
dots: [[5, 20], [19, 4]]
|
|
1780
|
-
},
|
|
1781
|
-
fibExtension: {
|
|
1782
|
-
d: "M3 20L8 10L12 16M14 4H21M14 8H21M14 12H21",
|
|
1783
|
-
dots: [
|
|
1784
|
-
[3, 20],
|
|
1785
|
-
[8, 10],
|
|
1786
|
-
[12, 16]
|
|
1787
|
-
]
|
|
1788
|
-
},
|
|
1789
|
-
fibChannel: {
|
|
1790
|
-
d: "M3 9L21 3M3 13L21 7M3 16L21 10M3 21L21 15",
|
|
1791
|
-
dots: [
|
|
1792
|
-
[3, 21],
|
|
1793
|
-
[21, 15],
|
|
1794
|
-
[3, 9]
|
|
1795
|
-
]
|
|
1796
|
-
},
|
|
1797
|
-
fibTimeZones: {
|
|
1798
|
-
d: "M3 4V20M6 4V20M9.5 4V20M14 4V20M20.5 4V20",
|
|
1799
|
-
dots: [[3, 20], [6, 20]]
|
|
1800
|
-
},
|
|
1801
|
-
fibSpeedResistanceFan: {
|
|
1802
|
-
d: "M4 20L20 4M4 20L20 11M4 20L20 16M4 20L11 4",
|
|
1803
|
-
dash: "M4 4H20V20",
|
|
1804
|
-
dots: [[4, 20], [20, 4]]
|
|
1805
|
-
},
|
|
1806
|
-
rectangle: {
|
|
1807
|
-
d: "M5.5 6h13A1.5 1.5 0 0 1 20 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 4 16.5v-9A1.5 1.5 0 0 1 5.5 6z",
|
|
1808
|
-
dots: [[4, 6], [20, 18]]
|
|
1809
|
-
},
|
|
1810
|
-
circle: {
|
|
1811
|
-
d: "M19.5 12a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0z",
|
|
1812
|
-
dots: [[12, 12], [19.5, 12]]
|
|
1813
|
-
},
|
|
1814
|
-
ellipse: {
|
|
1815
|
-
d: "M20.5 12c0 3-3.8 5.5-8.5 5.5S3.5 15 3.5 12 7.3 6.5 12 6.5s8.5 2.5 8.5 5.5z",
|
|
1816
|
-
dots: [[3.5, 12], [20.5, 12]]
|
|
1817
|
-
},
|
|
1818
|
-
triangle: {
|
|
1819
|
-
d: "M12 4.5L20 19H4z",
|
|
1820
|
-
dots: [
|
|
1821
|
-
[12, 4.5],
|
|
1822
|
-
[20, 19],
|
|
1823
|
-
[4, 19]
|
|
1824
|
-
]
|
|
1825
|
-
},
|
|
1826
|
-
pitchfork: {
|
|
1827
|
-
d: "M4 20L16.75 3M7 9L11.5 3M13 15L21 4.33M7 9L13 15",
|
|
1828
|
-
dots: [
|
|
1829
|
-
[4, 20],
|
|
1830
|
-
[7, 9],
|
|
1831
|
-
[13, 15]
|
|
1832
|
-
]
|
|
1833
|
-
},
|
|
1834
|
-
schiffPitchfork: {
|
|
1835
|
-
d: "M4 14.5L21 7.42M7 9L21 3.17M13 15L21 11.67M7 9L13 15",
|
|
1836
|
-
dash: "M4 20V14.5",
|
|
1837
|
-
dots: [
|
|
1838
|
-
[4, 14.5],
|
|
1839
|
-
[7, 9],
|
|
1840
|
-
[13, 15]
|
|
1841
|
-
]
|
|
1842
|
-
},
|
|
1843
|
-
modifiedSchiffPitchfork: {
|
|
1844
|
-
d: "M5.5 14.5L21 5.89M7 9L17.8 3M13 15L21 10.56M7 9L13 15",
|
|
1845
|
-
dash: "M4 20L5.5 14.5",
|
|
1846
|
-
dots: [
|
|
1847
|
-
[5.5, 14.5],
|
|
1848
|
-
[7, 9],
|
|
1849
|
-
[13, 15]
|
|
1850
|
-
]
|
|
1851
|
-
},
|
|
1852
|
-
gannFan: {
|
|
1853
|
-
d: "M4 20L20 4M4 20L20 12M4 20L12 4M4 20L20 16.5M4 20L7.5 4",
|
|
1854
|
-
dots: [[4, 20], [20, 4]]
|
|
1855
|
-
},
|
|
1856
|
-
gannBox: {
|
|
1857
|
-
d: "M4 4H20V20H4zM4 20L20 4M4 4L20 20M12 4V20",
|
|
1858
|
-
dots: [[4, 20], [20, 4]]
|
|
1859
|
-
},
|
|
1860
|
-
cyclicLines: {
|
|
1861
|
-
d: "M4 4V20M9 4V20M14 4V20M19 4V20",
|
|
1862
|
-
dots: [[4, 20], [9, 20]]
|
|
1863
|
-
},
|
|
1864
|
-
xabcdPattern: {
|
|
1865
|
-
d: "M3 18L7 6L11 13L15 8L21 19",
|
|
1866
|
-
dash: "M3 18L11 13L21 19",
|
|
1867
|
-
dots: [
|
|
1868
|
-
[3, 18],
|
|
1869
|
-
[7, 6],
|
|
1870
|
-
[11, 13],
|
|
1871
|
-
[15, 8],
|
|
1872
|
-
[21, 19]
|
|
1873
|
-
]
|
|
1874
|
-
},
|
|
1875
|
-
abcdPattern: {
|
|
1876
|
-
d: "M4 19L9 8L13 14L20 4",
|
|
1877
|
-
dots: [
|
|
1878
|
-
[4, 19],
|
|
1879
|
-
[9, 8],
|
|
1880
|
-
[13, 14],
|
|
1881
|
-
[20, 4]
|
|
1882
|
-
]
|
|
1883
|
-
},
|
|
1884
|
-
headAndShoulders: {
|
|
1885
|
-
d: "M3 19L6 11L8.5 15L12 5L15.5 15L18 11L21 19",
|
|
1886
|
-
dash: "M4.5 15H19.5",
|
|
1887
|
-
dots: [
|
|
1888
|
-
[6, 11],
|
|
1889
|
-
[12, 5],
|
|
1890
|
-
[18, 11]
|
|
1891
|
-
]
|
|
1892
|
-
},
|
|
1893
|
-
elliottWave: {
|
|
1894
|
-
d: "M3 19L6 13L8.5 16L14 6L16 10L21 4",
|
|
1895
|
-
dots: [[3, 19], [21, 4]]
|
|
1896
|
-
},
|
|
1897
|
-
priceRange: { d: "M5 4H19M5 20H19M12 6.5V17.5M9 9.5L12 6.5L15 9.5M9 14.5L12 17.5L15 14.5" },
|
|
1898
|
-
dateRange: { d: "M4 5V19M20 5V19M6.5 12H17.5M9.5 9L6.5 12L9.5 15M14.5 9L17.5 12L14.5 15" },
|
|
1899
|
-
dateAndPriceRange: {
|
|
1900
|
-
d: "M6 18V4M3 7L6 4L9 7M6 18H20M17 15L20 18L17 21",
|
|
1901
|
-
dash: "M6 4H20V18"
|
|
1902
|
-
},
|
|
1903
|
-
measure: { d: "M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9" },
|
|
1904
|
-
text: { d: "M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5" },
|
|
1905
|
-
priceLabel: { d: "M9 5H19a1.5 1.5 0 0 1 1.5 1.5v11A1.5 1.5 0 0 1 19 19H9L3.5 12zM11 12H17" },
|
|
1906
|
-
arrow: { d: "M5 19L19 5M10 5H19V14" },
|
|
1907
|
-
riskReward: {
|
|
1908
|
-
d: "M5 12V4H19V12M3 12H21",
|
|
1909
|
-
dash: "M5 12V18H19V12",
|
|
1910
|
-
dots: [[5, 12]]
|
|
1911
|
-
},
|
|
1912
|
-
anchoredVWAP: {
|
|
1913
|
-
d: "M4 18C9 17 12 10 20 7M4 20.5V18",
|
|
1914
|
-
dots: [[4, 18]]
|
|
1915
|
-
},
|
|
1916
|
-
volumeProfileRange: {
|
|
1917
|
-
d: "M6 7H12M6 10.5H17M6 14H15M6 17.5H10",
|
|
1918
|
-
dash: "M3.5 4V20M20.5 4V20",
|
|
1919
|
-
dots: [[3.5, 20], [20.5, 20]]
|
|
1920
|
-
},
|
|
1921
|
-
note: { d: "M5.5 4.5h13v9l-5 5h-8zM13.5 18.5v-5h5M8.5 8.5h7M8.5 11.5h4" },
|
|
1922
|
-
callout: {
|
|
1923
|
-
d: "M10.5 4h9a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1zM12 12L5 19M12.5 8h5",
|
|
1924
|
-
dots: [[5, 19]]
|
|
1925
|
-
},
|
|
1926
|
-
flag: {
|
|
1927
|
-
d: "M6 21V4M6 4.5h11l-2.5 3.75L17 12H6",
|
|
1928
|
-
soft: "M6 4.5h11l-2.5 3.75L17 12H6z",
|
|
1929
|
-
dots: [[6, 21]]
|
|
1930
|
-
},
|
|
1931
|
-
arrowMark: { d: "M12 4L18 11H14.5V20H9.5V11H6z" },
|
|
1932
|
-
icon: { d: "M12 3.5l2.6 5.3 5.9.85-4.25 4.15 1 5.85L12 16.9l-5.25 2.75 1-5.85L3.5 9.65l5.9-.85z" },
|
|
1933
|
-
brush: { d: "M3.5 17c2.5 0 3-5 6-5s2.5 5 5.5 5 3.5-6 5.5-9" },
|
|
1934
|
-
highlighter: { d: "M14.5 4.5l5 5L11 18H6v-5zM12 7l5 5M4 21h8" },
|
|
1935
|
-
path: {
|
|
1936
|
-
d: "M4 18L9 10L14 14L20 6M16.2 6.6L20 6L19.6 9.8",
|
|
1937
|
-
dots: [
|
|
1938
|
-
[4, 18],
|
|
1939
|
-
[9, 10],
|
|
1940
|
-
[14, 14]
|
|
1941
|
-
]
|
|
1942
|
-
},
|
|
1943
|
-
polyline: {
|
|
1944
|
-
d: "M5 17L8 6L16 4L20 14L12 20z",
|
|
1945
|
-
soft: "M5 17L8 6L16 4L20 14L12 20z",
|
|
1946
|
-
dots: [
|
|
1947
|
-
[5, 17],
|
|
1948
|
-
[8, 6],
|
|
1949
|
-
[16, 4],
|
|
1950
|
-
[20, 14],
|
|
1951
|
-
[12, 20]
|
|
1952
|
-
]
|
|
1953
|
-
},
|
|
1954
|
-
curve: {
|
|
1955
|
-
d: "M4 18C8 4 16 4 20 18",
|
|
1956
|
-
dots: [
|
|
1957
|
-
[4, 18],
|
|
1958
|
-
[20, 18],
|
|
1959
|
-
[12, 7.5]
|
|
1960
|
-
]
|
|
1961
|
-
},
|
|
1962
|
-
arc: {
|
|
1963
|
-
d: "M4 17a8 8 0 0 1 16 0",
|
|
1964
|
-
dots: [
|
|
1965
|
-
[4, 17],
|
|
1966
|
-
[20, 17],
|
|
1967
|
-
[12, 9]
|
|
1968
|
-
]
|
|
1969
|
-
},
|
|
1970
|
-
fibCircles: {
|
|
1971
|
-
d: "M14 12a2 2 0 1 1-4 0 2 2 0 0 1 4 0zM16.5 12a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0zM20 12a8 8 0 1 1-16 0 8 8 0 0 1 16 0z",
|
|
1972
|
-
dots: [[12, 12], [20, 12]]
|
|
1973
|
-
},
|
|
1974
|
-
fibSpiral: {
|
|
1975
|
-
d: "M12 12a1.5 1.5 0 0 1 1.5 1.5 3 3 0 0 1-3 3A4.5 4.5 0 0 1 6 12a6 6 0 0 1 6-6 8 8 0 0 1 8 8",
|
|
1976
|
-
dots: [[12, 12]]
|
|
1977
|
-
},
|
|
1978
|
-
fibArcs: {
|
|
1979
|
-
d: "M10 20a6 6 0 0 0-6-6M14 20a10 10 0 0 0-10-10M18 20a14 14 0 0 0-14-14",
|
|
1980
|
-
dash: "M4 20L18 6",
|
|
1981
|
-
dots: [[4, 20], [18, 6]]
|
|
1982
|
-
},
|
|
1983
|
-
fibWedge: {
|
|
1984
|
-
d: "M4 19L20 7M4 19L20 16M10.4 14.2A8 8 0 0 1 11.86 17.53M14.4 11.2A13 13 0 0 1 16.78 16.6",
|
|
1985
|
-
dots: [
|
|
1986
|
-
[4, 19],
|
|
1987
|
-
[20, 7],
|
|
1988
|
-
[20, 16]
|
|
1989
|
-
]
|
|
1990
|
-
},
|
|
1991
|
-
pitchfan: {
|
|
1992
|
-
d: "M4 20L14 4M4 20L20 14M4 20L17 9",
|
|
1993
|
-
dash: "M14 4L20 14",
|
|
1994
|
-
dots: [
|
|
1995
|
-
[4, 20],
|
|
1996
|
-
[14, 4],
|
|
1997
|
-
[20, 14]
|
|
1998
|
-
]
|
|
1999
|
-
},
|
|
2000
|
-
gannSquare: {
|
|
2001
|
-
d: "M4 4H20V20H4zM4 20L20 4M4 12H20M12 4V20M4 12a8 8 0 0 1 8 8",
|
|
2002
|
-
dots: [[4, 20], [20, 4]]
|
|
2003
|
-
},
|
|
2004
|
-
elliottImpulse: {
|
|
2005
|
-
d: "M3 19L7 12L10 15L15 5L17.5 9L21 3",
|
|
2006
|
-
dots: [[3, 19], [21, 3]]
|
|
2007
|
-
},
|
|
2008
|
-
elliottCorrection: {
|
|
2009
|
-
d: "M4 5L10 17L14 11L20 20",
|
|
2010
|
-
dots: [[4, 5], [20, 20]]
|
|
2011
|
-
},
|
|
2012
|
-
elliottTriangle: {
|
|
2013
|
-
d: "M3 6L7 17L11 9L15 15L18 11L21 13",
|
|
2014
|
-
dots: [[3, 6], [21, 13]]
|
|
2015
|
-
},
|
|
2016
|
-
elliottDoubleCombo: {
|
|
2017
|
-
d: "M4 5L9 14L13 9L20 19",
|
|
2018
|
-
dots: [
|
|
2019
|
-
[4, 5],
|
|
2020
|
-
[9, 14],
|
|
2021
|
-
[13, 9],
|
|
2022
|
-
[20, 19]
|
|
2023
|
-
]
|
|
2024
|
-
},
|
|
2025
|
-
elliottTripleCombo: {
|
|
2026
|
-
d: "M3 5L7 13L10 9L14 16L17 12L21 20",
|
|
2027
|
-
dots: [[3, 5], [21, 20]]
|
|
2028
|
-
},
|
|
2029
|
-
threeDrives: {
|
|
2030
|
-
d: "M3 20L7 12L9.5 15L14 7L16.5 10L21 3",
|
|
2031
|
-
dash: "M7 12L14 7L21 3",
|
|
2032
|
-
dots: [
|
|
2033
|
-
[7, 12],
|
|
2034
|
-
[14, 7],
|
|
2035
|
-
[21, 3]
|
|
2036
|
-
]
|
|
2037
|
-
},
|
|
2038
|
-
cypherPattern: {
|
|
2039
|
-
d: "M3 19L7 9L10 14L15 5L20 16",
|
|
2040
|
-
dash: "M3 19L10 14L20 16",
|
|
2041
|
-
dots: [
|
|
2042
|
-
[3, 19],
|
|
2043
|
-
[7, 9],
|
|
2044
|
-
[10, 14],
|
|
2045
|
-
[15, 5],
|
|
2046
|
-
[20, 16]
|
|
2047
|
-
]
|
|
2048
|
-
},
|
|
2049
|
-
timeCycles: {
|
|
2050
|
-
d: "M3 18a4.5 4.5 0 0 1 9 0a4.5 4.5 0 0 1 9 0",
|
|
2051
|
-
dots: [[3, 18], [12, 18]]
|
|
2052
|
-
},
|
|
2053
|
-
sineLine: {
|
|
2054
|
-
d: "M3 12C5 5 7.5 5 9 12S13 19 15 12 19.5 5 21 12",
|
|
2055
|
-
dots: [[6, 6.75], [12, 17.25]]
|
|
2056
|
-
},
|
|
2057
|
-
forecast: {
|
|
2058
|
-
d: "M4 18L15.2 7.8M19.5 6a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z",
|
|
2059
|
-
dots: [[4, 18]]
|
|
2060
|
-
},
|
|
2061
|
-
projection: {
|
|
2062
|
-
d: "M12 19L18 11M15.2 11.3L18 11L17.8 13.8",
|
|
2063
|
-
dash: "M3 17L9 9",
|
|
2064
|
-
dots: [
|
|
2065
|
-
[3, 17],
|
|
2066
|
-
[9, 9],
|
|
2067
|
-
[12, 19]
|
|
2068
|
-
]
|
|
2069
|
-
},
|
|
2070
|
-
barsPattern: {
|
|
2071
|
-
d: "M5 6V14M9 9V18M15 4V12M19 7V16",
|
|
2072
|
-
fills: [
|
|
2073
|
-
"M4 8h2v4H4z",
|
|
2074
|
-
"M8 11h2v5H8z",
|
|
2075
|
-
"M14 6h2v4h-2z",
|
|
2076
|
-
"M18 9h2v5h-2z"
|
|
2077
|
-
],
|
|
2078
|
-
dash: "M12 3V21"
|
|
2079
|
-
}
|
|
2080
|
-
}, mt = {
|
|
2081
|
-
candlestick: {
|
|
2082
|
-
d: "M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19",
|
|
2083
|
-
fills: ["M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1z", "M14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z"]
|
|
2084
|
-
},
|
|
2085
|
-
hollowCandle: { d: "M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1zM14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z" },
|
|
2086
|
-
heikinAshi: {
|
|
2087
|
-
d: "M5.5 9.5V12M5.5 18V20M12 5.5V8M12 14V16M18.5 3V4.5M18.5 10.5V12.5",
|
|
2088
|
-
fills: [
|
|
2089
|
-
"M4 12h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5H4a.5.5 0 0 1-.5-.5v-5A.5.5 0 0 1 4 12z",
|
|
2090
|
-
"M10.5 8h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-5a.5.5 0 0 1 .5-.5z",
|
|
2091
|
-
"M17 4.5h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5z"
|
|
2092
|
-
]
|
|
2093
|
-
},
|
|
2094
|
-
bar: { d: "M8 4V20M5 8H8M8 16H11M16 6V18M13 15H16M16 9H19" },
|
|
2095
|
-
volumeCandles: {
|
|
2096
|
-
d: "M6.5 5V8M6.5 16V19M15.5 3.5V6M15.5 16V20",
|
|
2097
|
-
fills: ["M5.5 8h2a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-7a.5.5 0 0 1 .5-.5z", "M11.5 6h8a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5z"]
|
|
2098
|
-
},
|
|
2099
|
-
equivolume: { d: "M4.5 10h2a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1zM10 6h5a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zM18.5 4h1a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z" },
|
|
2100
|
-
line: { d: "M3 17L8 11L12 14L21 5" },
|
|
2101
|
-
area: {
|
|
2102
|
-
d: "M3 17L8 11L12 14L21 5",
|
|
2103
|
-
soft: "M3 17L8 11L12 14L21 5V20H3z"
|
|
2104
|
-
},
|
|
2105
|
-
baseline: {
|
|
2106
|
-
d: "M3 16L7 9L11 14L15 7L21 15",
|
|
2107
|
-
dash: "M3 12H21"
|
|
2108
|
-
},
|
|
2109
|
-
hlcArea: {
|
|
2110
|
-
d: "M3 9L8 6L13 9L21 4M3 15L8 13L13 16L21 11",
|
|
2111
|
-
dash: "M3 12L8 9.5L13 12.5L21 7.5",
|
|
2112
|
-
soft: "M3 9L8 6L13 9L21 4V11L13 16L8 13L3 15z"
|
|
2113
|
-
},
|
|
2114
|
-
stepLine: { d: "M3 18H8V12H12V15H16V7H21" },
|
|
2115
|
-
lineWithMarkers: {
|
|
2116
|
-
d: "M4 17L9 10L14 14L20 6",
|
|
2117
|
-
dots: [
|
|
2118
|
-
[4, 17],
|
|
2119
|
-
[9, 10],
|
|
2120
|
-
[14, 14],
|
|
2121
|
-
[20, 6]
|
|
2122
|
-
]
|
|
2123
|
-
},
|
|
2124
|
-
hiLo: {
|
|
2125
|
-
d: "M6 7V17M12 4V14M18 9V20",
|
|
2126
|
-
fills: [
|
|
2127
|
-
"M5 7h2v10H5z",
|
|
2128
|
-
"M11 4h2v10h-2z",
|
|
2129
|
-
"M17 9h2v11h-2z"
|
|
2130
|
-
]
|
|
2131
|
-
},
|
|
2132
|
-
renko: { d: "M3.5 15.5h4v4h-4zM7.5 11.5h4v4h-4zM11.5 7.5h4v4h-4zM15.5 11.5h4v4h-4z" },
|
|
2133
|
-
lineBreak: {
|
|
2134
|
-
d: "M4 14h4v5H4zM8 10h4v4H8zM16 9h4v8h-4z",
|
|
2135
|
-
fills: ["M12 5h4v5h-4z"]
|
|
2136
|
-
},
|
|
2137
|
-
kagi: { d: "M4 19V11H9V16H14V5H20V13" },
|
|
2138
|
-
pointAndFigure: { d: "M5.5 5.5l3 3M8.5 5.5l-3 3M5.5 10.5l3 3M8.5 10.5l-3 3M5.5 15.5l3 3M8.5 15.5l-3 3M14.5 9a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0M14.5 14a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0" },
|
|
2139
|
-
rangeBars: {
|
|
2140
|
-
d: "M6.5 11V12M6.5 18V19M12 7V8M12 14V15M17.5 3.5V4.5M17.5 10.5V11.5",
|
|
2141
|
-
fills: [
|
|
2142
|
-
"M5 12h3v6H5z",
|
|
2143
|
-
"M10.5 8h3v6h-3z",
|
|
2144
|
-
"M16 4.5h3v6h-3z"
|
|
2145
|
-
]
|
|
2146
|
-
}
|
|
2147
|
-
}, ht = 1.75, gt = .22, _t = /* @__PURE__ */ new WeakMap();
|
|
2148
|
-
function vt(e) {
|
|
2149
|
-
let t = _t.get(e);
|
|
2150
|
-
if (t) return t;
|
|
2151
|
-
let n = "";
|
|
2152
|
-
e.soft && (n += `<path d="${e.soft}" fill="currentColor" fill-opacity="${gt}" stroke="none"/>`);
|
|
2153
|
-
for (let t of e.fills ?? []) n += `<path d="${t}" fill="currentColor" stroke="none"/>`;
|
|
2154
|
-
e.d && (n += `<path d="${e.d}"/>`), e.dash && (n += `<path d="${e.dash}" stroke-dasharray="2 2.5"/>`);
|
|
2155
|
-
for (let [t, r, i = ht] of e.dots ?? []) n += `<circle cx="${t}" cy="${r}" r="${i}" fill="currentColor" stroke="none"/>`;
|
|
2156
|
-
return _t.set(e, n), n;
|
|
2157
|
-
}
|
|
2158
|
-
function yt(e, t) {
|
|
2159
|
-
return `<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${vt(e)}</svg>`;
|
|
2160
|
-
}
|
|
2161
|
-
//#endregion
|
|
2162
1628
|
//#region src/widget/icons.ts
|
|
2163
|
-
var
|
|
1629
|
+
var _t = (e, t) => Object.prototype.hasOwnProperty.call(e, t) ? e[t] : void 0;
|
|
2164
1630
|
function j(e, t = 14) {
|
|
2165
|
-
let n =
|
|
2166
|
-
return n ?
|
|
1631
|
+
let n = _t(re, e);
|
|
1632
|
+
return n ? ae(n, t) : "";
|
|
2167
1633
|
}
|
|
2168
1634
|
function M(e, t = 16) {
|
|
2169
|
-
return
|
|
1635
|
+
return ae(_t(ee, e) ?? re.penLine, t);
|
|
2170
1636
|
}
|
|
2171
|
-
function
|
|
2172
|
-
return
|
|
1637
|
+
function vt(e, t = 14) {
|
|
1638
|
+
return ae(_t(_, e) ?? re.barChart, t);
|
|
2173
1639
|
}
|
|
2174
1640
|
//#endregion
|
|
2175
1641
|
//#region src/widget/escapeHtml.ts
|
|
@@ -2184,7 +1650,7 @@ function N(e) {
|
|
|
2184
1650
|
}
|
|
2185
1651
|
//#endregion
|
|
2186
1652
|
//#region src/widget/WidgetDropdown.ts
|
|
2187
|
-
var
|
|
1653
|
+
var yt = class {
|
|
2188
1654
|
trigger;
|
|
2189
1655
|
panel;
|
|
2190
1656
|
_isOpen = !1;
|
|
@@ -2215,7 +1681,7 @@ var St = class {
|
|
|
2215
1681
|
destroy() {
|
|
2216
1682
|
this.trigger.removeEventListener("click", this.onTriggerClick), document.removeEventListener("mousedown", this.onOutsideClick), document.removeEventListener("keydown", this.onEscapeKey), this.panel.remove();
|
|
2217
1683
|
}
|
|
2218
|
-
},
|
|
1684
|
+
}, bt = [
|
|
2219
1685
|
"en-US",
|
|
2220
1686
|
"en-GB",
|
|
2221
1687
|
"en-IN",
|
|
@@ -2233,15 +1699,15 @@ var St = class {
|
|
|
2233
1699
|
"zh-TW",
|
|
2234
1700
|
"ja-JP",
|
|
2235
1701
|
"ko-KR"
|
|
2236
|
-
],
|
|
2237
|
-
function
|
|
2238
|
-
return (e && !
|
|
1702
|
+
], xt = 65234;
|
|
1703
|
+
function St(e) {
|
|
1704
|
+
return (e && !bt.includes(e) ? [e, ...bt] : bt).map((e) => {
|
|
2239
1705
|
let t;
|
|
2240
1706
|
try {
|
|
2241
1707
|
t = new Intl.NumberFormat(e, {
|
|
2242
1708
|
minimumFractionDigits: 2,
|
|
2243
1709
|
maximumFractionDigits: 2
|
|
2244
|
-
}).format(
|
|
1710
|
+
}).format(xt);
|
|
2245
1711
|
} catch {
|
|
2246
1712
|
t = "";
|
|
2247
1713
|
}
|
|
@@ -2251,7 +1717,7 @@ function Tt(e) {
|
|
|
2251
1717
|
};
|
|
2252
1718
|
});
|
|
2253
1719
|
}
|
|
2254
|
-
var
|
|
1720
|
+
var Ct = {
|
|
2255
1721
|
Lines: "toolGroup.lines",
|
|
2256
1722
|
"Horizontal/Vertical": "toolGroup.horizontalVertical",
|
|
2257
1723
|
Channels: "toolGroup.channels",
|
|
@@ -2266,14 +1732,14 @@ var Et = {
|
|
|
2266
1732
|
Cycles: "toolGroup.cycles",
|
|
2267
1733
|
"Elliott Waves": "toolGroup.elliott"
|
|
2268
1734
|
};
|
|
2269
|
-
function
|
|
1735
|
+
function wt(e, t) {
|
|
2270
1736
|
let n = `chartType.${e.value}`, r = t(n);
|
|
2271
1737
|
return r === n ? e.label : r;
|
|
2272
1738
|
}
|
|
2273
|
-
function
|
|
1739
|
+
function Tt(e, t) {
|
|
2274
1740
|
return e.map((e) => ({
|
|
2275
1741
|
...e,
|
|
2276
|
-
label:
|
|
1742
|
+
label: Ct[e.label] ? t(Ct[e.label]) : e.label,
|
|
2277
1743
|
tools: e.tools.map((e) => {
|
|
2278
1744
|
let n = `tool.${e.value}`, r = t(n);
|
|
2279
1745
|
return {
|
|
@@ -2285,12 +1751,12 @@ function Ot(e, t) {
|
|
|
2285
1751
|
}
|
|
2286
1752
|
//#endregion
|
|
2287
1753
|
//#region src/widget/WidgetToolbar.ts
|
|
2288
|
-
var
|
|
2289
|
-
function
|
|
1754
|
+
var Et = 0;
|
|
1755
|
+
function Dt(e, t) {
|
|
2290
1756
|
let n = e.querySelector(".tcw-host-btn-text")?.textContent ?? "";
|
|
2291
1757
|
n === t ? e.removeAttribute("aria-label") : e.setAttribute("aria-label", n ? `${t}: ${n}` : t);
|
|
2292
1758
|
}
|
|
2293
|
-
var
|
|
1759
|
+
var Ot = class {
|
|
2294
1760
|
config;
|
|
2295
1761
|
callbacks;
|
|
2296
1762
|
t;
|
|
@@ -2300,7 +1766,7 @@ var jt = class {
|
|
|
2300
1766
|
tfGroup = null;
|
|
2301
1767
|
tfDropdown = null;
|
|
2302
1768
|
tfFavorites = [];
|
|
2303
|
-
uid = (
|
|
1769
|
+
uid = (Et++).toString(36);
|
|
2304
1770
|
tfRendered = "";
|
|
2305
1771
|
themeBtn = null;
|
|
2306
1772
|
indicatorTemplates = [];
|
|
@@ -2320,17 +1786,17 @@ var jt = class {
|
|
|
2320
1786
|
let e = document.createElement("div");
|
|
2321
1787
|
e.style.position = "relative", e.style.display = "inline-flex", A(e, "toolbar.timeframeMenu");
|
|
2322
1788
|
let t = document.createElement("button");
|
|
2323
|
-
t.className = "tcw-btn tcw-tf-more", t.dataset.role = "timeframes", t.title = this.t("toolbar.timeframes"), t.setAttribute("aria-label", this.t("toolbar.timeframes")), t.innerHTML = j("chevronDown", 12), e.appendChild(t), n.appendChild(e), this.tfDropdown = new
|
|
1789
|
+
t.className = "tcw-btn tcw-tf-more", t.dataset.role = "timeframes", t.title = this.t("toolbar.timeframes"), t.setAttribute("aria-label", this.t("toolbar.timeframes")), t.innerHTML = j("chevronDown", 12), e.appendChild(t), n.appendChild(e), this.tfDropdown = new yt(e, { width: "150px" }), this.buildTimeframeMenu();
|
|
2324
1790
|
}
|
|
2325
1791
|
n.appendChild(this.sep());
|
|
2326
1792
|
let i = document.createElement("div");
|
|
2327
1793
|
i.style.position = "relative", i.style.display = "inline-flex", A(i, "toolbar.chartType");
|
|
2328
1794
|
let a = document.createElement("button");
|
|
2329
|
-
a.className = "tcw-dropdown-trigger", a.dataset.role = "charttype", i.appendChild(a), n.appendChild(i), this.chartTypeDropdown = new
|
|
1795
|
+
a.className = "tcw-dropdown-trigger", a.dataset.role = "charttype", i.appendChild(a), n.appendChild(i), this.chartTypeDropdown = new yt(i, { width: "160px" }), this.buildChartTypeMenu(), n.appendChild(this.sep());
|
|
2330
1796
|
let o = document.createElement("div");
|
|
2331
1797
|
o.style.position = "relative", o.style.display = "inline-flex", A(o, "toolbar.indicators");
|
|
2332
1798
|
let s = document.createElement("button");
|
|
2333
|
-
if (s.className = "tcw-dropdown-trigger", s.dataset.role = "indicators", o.appendChild(s), n.appendChild(o), this.indicatorDropdown = new
|
|
1799
|
+
if (s.className = "tcw-dropdown-trigger", s.dataset.role = "indicators", o.appendChild(s), n.appendChild(o), this.indicatorDropdown = new yt(o, { width: "280px" }), this.buildIndicatorMenu(), this.hostLeft = this.hostGroup(), n.appendChild(this.hostLeft), n.appendChild(this.spacer()), t.onLayouts) {
|
|
2334
1800
|
let e = t.onLayouts, r = document.createElement("button");
|
|
2335
1801
|
r.type = "button", r.className = "tcw-dropdown-trigger tcw-layouts-btn", r.dataset.role = "layouts", A(r, "layouts", "toolbar.layouts"), r.setAttribute("aria-haspopup", "menu"), r.addEventListener("click", () => e(r)), n.appendChild(r), this.setLayout(null, !1);
|
|
2336
1802
|
}
|
|
@@ -2373,7 +1839,7 @@ var jt = class {
|
|
|
2373
1839
|
let e = document.createElement("span");
|
|
2374
1840
|
e.className = "tcw-host-btn-text", e.textContent = n, t.appendChild(e);
|
|
2375
1841
|
}
|
|
2376
|
-
return
|
|
1842
|
+
return Dt(t, e.label), t.addEventListener("click", () => e.onClick(t)), (e.side === "left" ? this.hostLeft : this.hostRight)?.appendChild(t), t;
|
|
2377
1843
|
}
|
|
2378
1844
|
hostSlot(e) {
|
|
2379
1845
|
return e === "left" ? this.hostLeft : this.hostRight;
|
|
@@ -2387,7 +1853,7 @@ var jt = class {
|
|
|
2387
1853
|
t && (e ? t.removeAttribute("aria-disabled") : t.setAttribute("aria-disabled", "true"));
|
|
2388
1854
|
}
|
|
2389
1855
|
tidy() {
|
|
2390
|
-
|
|
1856
|
+
dt(this.el, "tcw-toolbar-sep", "tcw-toolbar-spacer");
|
|
2391
1857
|
}
|
|
2392
1858
|
setActive(e, t) {
|
|
2393
1859
|
let n = this.el.querySelector(`[data-role="${e}"]`);
|
|
@@ -2405,11 +1871,11 @@ var jt = class {
|
|
|
2405
1871
|
this.fullscreenBtn.innerHTML = j(e ? "minimize" : "maximize", 14), this.fullscreenBtn.title = t, this.fullscreenBtn.setAttribute("aria-pressed", String(e));
|
|
2406
1872
|
}
|
|
2407
1873
|
chartTypeLabel(e) {
|
|
2408
|
-
return
|
|
1874
|
+
return wt(e, this.t);
|
|
2409
1875
|
}
|
|
2410
1876
|
buildChartTypeMenu() {
|
|
2411
1877
|
if (!this.chartTypeDropdown) return;
|
|
2412
|
-
let e = this.config.chartTypes.map((e) => `<button class="tcw-dropdown-item tcw-dropdown-item--icon" data-ct="${N(e.value)}">${
|
|
1878
|
+
let e = this.config.chartTypes.map((e) => `<button class="tcw-dropdown-item tcw-dropdown-item--icon" data-ct="${N(e.value)}">${vt(e.value, 16)}<span>${N(this.chartTypeLabel(e))}</span></button>`).join("");
|
|
2413
1879
|
this.chartTypeDropdown.setContent(e), this.chartTypeDropdown.panel.querySelectorAll(".tcw-dropdown-item").forEach((e) => {
|
|
2414
1880
|
e.addEventListener("click", (e) => {
|
|
2415
1881
|
let t = e.currentTarget.dataset.ct;
|
|
@@ -2439,7 +1905,7 @@ var jt = class {
|
|
|
2439
1905
|
}
|
|
2440
1906
|
if (this.callbacks.onAddTimeframe) {
|
|
2441
1907
|
let e = N(this.t("toolbar.timeframes.custom")), t = N(this.t("toolbar.timeframes.add"));
|
|
2442
|
-
n += `<form class="tcw-tf-custom" ${
|
|
1908
|
+
n += `<form class="tcw-tf-custom" ${lt("customTimeframes")} novalidate><input class="tcw-tf-custom-input" type="text" autocomplete="off" spellcheck="false" maxlength="6" placeholder="7m, 90m, 2h…" aria-label="${e}" aria-describedby="tcw-tf-hint-${this.uid}"><button type="submit" class="tcw-tf-custom-add" title="${t}" aria-label="${t}">${j("plus", 12)}</button><div class="tcw-tf-custom-hint" id="tcw-tf-hint-${this.uid}" role="status"></div></form>`;
|
|
2443
1909
|
}
|
|
2444
1910
|
this.tfDropdown.setContent(n);
|
|
2445
1911
|
let r = this.tfDropdown.panel;
|
|
@@ -2480,7 +1946,7 @@ var jt = class {
|
|
|
2480
1946
|
}
|
|
2481
1947
|
templatesMenuHtml() {
|
|
2482
1948
|
if (!this.callbacks.onSaveIndicatorTemplate) return "";
|
|
2483
|
-
let e = this.t("templates.delete"), t = `<div ${
|
|
1949
|
+
let e = this.t("templates.delete"), t = `<div ${lt("indicatorTemplates")}><div class="tcw-dropdown-label">${N(this.t("toolbar.indicators.templates"))}</div>`;
|
|
2484
1950
|
for (let n of this.indicatorTemplates) {
|
|
2485
1951
|
let r = N(n);
|
|
2486
1952
|
t += `<div class="tcw-tf-row"><button class="tcw-dropdown-item" data-tpl-apply="${r}">${j("layers", 14)}<span>${r}</span></button><button class="tcw-tf-remove" data-tpl-delete="${r}" title="${N(p(e, { name: n }))}" aria-label="${N(p(e, { name: n }))}">${j("x", 12)}</button></div>`;
|
|
@@ -2519,7 +1985,7 @@ var jt = class {
|
|
|
2519
1985
|
let n = this.el.querySelector("[data-role=\"charttype\"]");
|
|
2520
1986
|
if (n) {
|
|
2521
1987
|
let t = this.config.chartTypes.find((t) => t.value === e.chartType), r = t ? this.chartTypeLabel(t) : e.chartType;
|
|
2522
|
-
n.innerHTML = `${
|
|
1988
|
+
n.innerHTML = `${vt(e.chartType, 14)} ${N(r)} ${j("chevronDown", 12)}`;
|
|
2523
1989
|
}
|
|
2524
1990
|
let r = this.el.querySelector("[data-role=\"indicators\"]");
|
|
2525
1991
|
if (r) {
|
|
@@ -2546,28 +2012,28 @@ var jt = class {
|
|
|
2546
2012
|
};
|
|
2547
2013
|
//#endregion
|
|
2548
2014
|
//#region src/widget/hostButtons.ts
|
|
2549
|
-
function
|
|
2015
|
+
function kt(e, t, n) {
|
|
2550
2016
|
e.classList.toggle("tcw-active", t), n && e.setAttribute("aria-pressed", String(t));
|
|
2551
2017
|
}
|
|
2552
|
-
function
|
|
2018
|
+
function At(e, t, n) {
|
|
2553
2019
|
let r = e.querySelector(".tcw-host-btn-text");
|
|
2554
|
-
r || (r = document.createElement("span"), r.className = "tcw-host-btn-text", e.appendChild(r)), r.textContent = n,
|
|
2020
|
+
r || (r = document.createElement("span"), r.className = "tcw-host-btn-text", e.appendChild(r)), r.textContent = n, Dt(e, t);
|
|
2555
2021
|
}
|
|
2556
2022
|
//#endregion
|
|
2557
2023
|
//#region src/widget/WidgetDrawingSidebar.ts
|
|
2558
|
-
var
|
|
2559
|
-
function
|
|
2024
|
+
var jt = 16, Mt = 150, Nt = 4;
|
|
2025
|
+
function Pt(e) {
|
|
2560
2026
|
let t = `sidebar.${e}`;
|
|
2561
2027
|
return O.includes(t) ? t : null;
|
|
2562
2028
|
}
|
|
2563
|
-
function
|
|
2029
|
+
function Ft(e, t) {
|
|
2564
2030
|
for (let n of e) {
|
|
2565
2031
|
let e = n.tools.find((e) => e.value === t);
|
|
2566
2032
|
if (e) return e.label;
|
|
2567
2033
|
}
|
|
2568
2034
|
return t;
|
|
2569
2035
|
}
|
|
2570
|
-
var
|
|
2036
|
+
var It = class {
|
|
2571
2037
|
config;
|
|
2572
2038
|
callbacks;
|
|
2573
2039
|
el;
|
|
@@ -2599,14 +2065,14 @@ var zt = class {
|
|
|
2599
2065
|
e.section !== void 0 && r !== void 0 && e.section !== r && this.appendDivider(), r = e.section;
|
|
2600
2066
|
let a = document.createElement("div");
|
|
2601
2067
|
a.className = "tcw-tool-group-wrap";
|
|
2602
|
-
let o =
|
|
2068
|
+
let o = Pt(e.section);
|
|
2603
2069
|
o && A(a, o);
|
|
2604
2070
|
let s = document.createElement("button");
|
|
2605
2071
|
s.className = "tcw-sidebar-btn";
|
|
2606
2072
|
let c = e.tools[0].value;
|
|
2607
2073
|
e.tools.length > 1 ? s.setAttribute("aria-label", `${e.label}: ${e.tools[0].label}`) : s.title = e.label;
|
|
2608
2074
|
let l = document.createElement("span");
|
|
2609
|
-
if (l.className = "tcw-sidebar-icon", l.innerHTML = M(c,
|
|
2075
|
+
if (l.className = "tcw-sidebar-icon", l.innerHTML = M(c, jt), s.appendChild(l), this.groupIcons.push(l), this.groupTools.push(c), e.tools.length > 1) {
|
|
2610
2076
|
let e = document.createElement("span");
|
|
2611
2077
|
e.className = "tcw-multi-dot", s.appendChild(e);
|
|
2612
2078
|
}
|
|
@@ -2640,7 +2106,7 @@ var zt = class {
|
|
|
2640
2106
|
this.favoritesEl.style.display = e ? "" : "none", this.favoritesDivider && (this.favoritesDivider.style.display = e ? "" : "none");
|
|
2641
2107
|
for (let e of this.favorites) {
|
|
2642
2108
|
let t = document.createElement("button");
|
|
2643
|
-
t.className = "tcw-sidebar-btn", t.title = p(this.t("sidebar.unpinHint"), { tool:
|
|
2109
|
+
t.className = "tcw-sidebar-btn", t.title = p(this.t("sidebar.unpinHint"), { tool: Ft(this.config.drawingToolGroups, e) }), t.dataset.toolValue = e, t.innerHTML = M(e, jt), t.addEventListener("click", () => this.callbacks.onDrawingTool(e)), t.addEventListener("contextmenu", (t) => {
|
|
2644
2110
|
t.preventDefault(), this.callbacks.onToggleFavorite?.(e);
|
|
2645
2111
|
}), this.favoritesEl.appendChild(t);
|
|
2646
2112
|
}
|
|
@@ -2659,13 +2125,21 @@ var zt = class {
|
|
|
2659
2125
|
r.className = "tcw-flyout-header", r.textContent = t.label, n.appendChild(r);
|
|
2660
2126
|
for (let e of t.tools) {
|
|
2661
2127
|
let t = document.createElement("button");
|
|
2662
|
-
t.className = "tcw-flyout-item", t.setAttribute("role", "menuitem"), t.tabIndex = -1, t.innerHTML = M(e.value,
|
|
2128
|
+
t.className = "tcw-flyout-item", t.setAttribute("role", "menuitem"), t.tabIndex = -1, t.innerHTML = M(e.value, jt);
|
|
2663
2129
|
let r = document.createElement("span");
|
|
2664
|
-
r.textContent = e.label, t.appendChild(r), t.dataset.toolValue = e.value, t.addEventListener("click", () => {
|
|
2130
|
+
if (r.textContent = e.label, t.appendChild(r), t.dataset.toolValue = e.value, t.addEventListener("click", () => {
|
|
2665
2131
|
this.callbacks.onDrawingTool(e.value), this.hideFlyout();
|
|
2666
|
-
}), this.callbacks.onToggleFavorite
|
|
2667
|
-
|
|
2668
|
-
|
|
2132
|
+
}), this.callbacks.onToggleFavorite) {
|
|
2133
|
+
if (this.favorites.includes(e.value)) {
|
|
2134
|
+
t.classList.add("tcw-flyout-faved");
|
|
2135
|
+
let e = document.createElement("span");
|
|
2136
|
+
e.className = "tcw-flyout-star", e.innerHTML = j("star", 12), t.appendChild(e);
|
|
2137
|
+
}
|
|
2138
|
+
t.addEventListener("contextmenu", (t) => {
|
|
2139
|
+
t.preventDefault(), this.callbacks.onToggleFavorite?.(e.value);
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2142
|
+
n.appendChild(t);
|
|
2669
2143
|
}
|
|
2670
2144
|
if (this.callbacks.onToggleFavorite) {
|
|
2671
2145
|
let e = document.createElement("div");
|
|
@@ -2711,14 +2185,14 @@ var zt = class {
|
|
|
2711
2185
|
}
|
|
2712
2186
|
placeFlyout(e, t) {
|
|
2713
2187
|
let n = this.host.getBoundingClientRect(), r = t.getBoundingClientRect();
|
|
2714
|
-
e.style.maxHeight = `${Math.max(0, this.host.clientHeight -
|
|
2715
|
-
let i = this.host.clientHeight - e.offsetHeight -
|
|
2188
|
+
e.style.maxHeight = `${Math.max(0, this.host.clientHeight - Nt * 2)}px`;
|
|
2189
|
+
let i = this.host.clientHeight - e.offsetHeight - Nt;
|
|
2716
2190
|
this.host.closest("[dir]")?.getAttribute("dir") === "rtl" ? (e.style.left = "", e.style.right = `${n.right - r.left}px`) : (e.style.right = "", e.style.left = `${r.right - n.left}px`), e.style.top = `${Math.max(0, Math.min(r.top - n.top, i))}px`;
|
|
2717
2191
|
}
|
|
2718
2192
|
scheduleHideFlyout() {
|
|
2719
2193
|
this.cancelHideFlyout(), this.flyoutHideTimer = setTimeout(() => {
|
|
2720
2194
|
this.flyoutHideTimer = null, this.hideFlyout();
|
|
2721
|
-
},
|
|
2195
|
+
}, Mt);
|
|
2722
2196
|
}
|
|
2723
2197
|
cancelHideFlyout() {
|
|
2724
2198
|
this.flyoutHideTimer !== null && (clearTimeout(this.flyoutHideTimer), this.flyoutHideTimer = null);
|
|
@@ -2731,7 +2205,7 @@ var zt = class {
|
|
|
2731
2205
|
let { drawingToolGroups: t } = this.config;
|
|
2732
2206
|
for (let n = 0; n < t.length; n++) {
|
|
2733
2207
|
let r = t[n].tools.some((t) => t.value === e.activeTool);
|
|
2734
|
-
this.groupButtons[n].classList.toggle("tcw-active", r), r && e.activeTool && e.activeTool !== this.groupTools[n] && (this.groupTools[n] = e.activeTool, this.groupIcons[n].innerHTML = M(e.activeTool,
|
|
2208
|
+
this.groupButtons[n].classList.toggle("tcw-active", r), r && e.activeTool && e.activeTool !== this.groupTools[n] && (this.groupTools[n] = e.activeTool, this.groupIcons[n].innerHTML = M(e.activeTool, jt), t[n].tools.length > 1 && this.groupButtons[n].setAttribute("aria-label", `${t[n].label}: ${Ft(t, e.activeTool)}`));
|
|
2735
2209
|
}
|
|
2736
2210
|
if (this.flyoutEl && this.flyoutEl.querySelectorAll(".tcw-flyout-item").forEach((t) => {
|
|
2737
2211
|
let n = t;
|
|
@@ -2751,7 +2225,7 @@ var zt = class {
|
|
|
2751
2225
|
return this.hostEl;
|
|
2752
2226
|
}
|
|
2753
2227
|
tidy() {
|
|
2754
|
-
|
|
2228
|
+
dt(this.el, "tcw-sidebar-divider", "tcw-sidebar-spacer");
|
|
2755
2229
|
}
|
|
2756
2230
|
toggleButton(e, t, n) {
|
|
2757
2231
|
let r = document.createElement("button");
|
|
@@ -2776,14 +2250,14 @@ function P(e, t) {
|
|
|
2776
2250
|
let r = document.createElement("span");
|
|
2777
2251
|
return r.className = "tcw-settings-label", r.textContent = e, n.append(r, t), n;
|
|
2778
2252
|
}
|
|
2779
|
-
function
|
|
2253
|
+
function Lt(e, t) {
|
|
2780
2254
|
let n = document.createElement("button");
|
|
2781
2255
|
return n.type = "button", n.className = `tcw-toggle${e ? " tcw-on" : ""}`, n.setAttribute("role", "switch"), n.setAttribute("aria-checked", String(e)), n.addEventListener("click", () => {
|
|
2782
2256
|
let e = !n.classList.contains("tcw-on");
|
|
2783
2257
|
n.classList.toggle("tcw-on", e), n.setAttribute("aria-checked", String(e)), t(e);
|
|
2784
2258
|
}), n;
|
|
2785
2259
|
}
|
|
2786
|
-
function
|
|
2260
|
+
function Rt(e, t, n) {
|
|
2787
2261
|
let r = document.createElement("input");
|
|
2788
2262
|
return r.type = "number", r.className = "tcw-indi-input", r.value = String(e), r.step = String(t.step ?? (Number.isInteger(e) ? 1 : .001)), t.min !== void 0 && (r.min = String(t.min)), t.max !== void 0 && (r.max = String(t.max)), r.addEventListener("change", () => {
|
|
2789
2263
|
if (r.value.trim() === "") return;
|
|
@@ -2791,7 +2265,7 @@ function Vt(e, t, n) {
|
|
|
2791
2265
|
Number.isFinite(e) && (t.min !== void 0 && (e = Math.max(t.min, e)), t.max !== void 0 && (e = Math.min(t.max, e)), r.value = String(e), n(e));
|
|
2792
2266
|
}), r;
|
|
2793
2267
|
}
|
|
2794
|
-
function
|
|
2268
|
+
function zt(e, t) {
|
|
2795
2269
|
let n = document.createElement("input");
|
|
2796
2270
|
return n.type = "color", n.className = "tcw-indi-color", n.value = I(e), n.addEventListener("input", () => t(n.value)), n;
|
|
2797
2271
|
}
|
|
@@ -2816,11 +2290,11 @@ function I(e) {
|
|
|
2816
2290
|
n[2],
|
|
2817
2291
|
n[3]
|
|
2818
2292
|
].map((e) => Math.min(255, Number(e)).toString(16).padStart(2, "0")).join("")}`;
|
|
2819
|
-
let r =
|
|
2293
|
+
let r = Bt(t);
|
|
2820
2294
|
return r !== null && r !== t ? I(r) : "#000000";
|
|
2821
2295
|
}
|
|
2822
2296
|
var L;
|
|
2823
|
-
function
|
|
2297
|
+
function Bt(e) {
|
|
2824
2298
|
if (L === void 0) try {
|
|
2825
2299
|
L = typeof document < "u" ? document.createElement("canvas").getContext("2d") : null;
|
|
2826
2300
|
} catch {
|
|
@@ -2831,12 +2305,12 @@ function Ut(e) {
|
|
|
2831
2305
|
let t = String(L.fillStyle);
|
|
2832
2306
|
return t === "#010203" ? null : t;
|
|
2833
2307
|
}
|
|
2834
|
-
function
|
|
2308
|
+
function Vt(e) {
|
|
2835
2309
|
if (typeof e != "string") return 1;
|
|
2836
2310
|
let t = /^rgba\([^)]*,\s*([\d.]+)\s*\)$/i.exec(e.trim());
|
|
2837
2311
|
return t ? Math.max(0, Math.min(1, Number(t[1]))) : 1;
|
|
2838
2312
|
}
|
|
2839
|
-
function
|
|
2313
|
+
function Ht(e, t) {
|
|
2840
2314
|
let n = I(e), [r, i, a] = [
|
|
2841
2315
|
1,
|
|
2842
2316
|
3,
|
|
@@ -2846,17 +2320,17 @@ function Gt(e, t) {
|
|
|
2846
2320
|
}
|
|
2847
2321
|
//#endregion
|
|
2848
2322
|
//#region src/widget/WidgetSettings.ts
|
|
2849
|
-
var
|
|
2323
|
+
var Ut = [
|
|
2850
2324
|
"style",
|
|
2851
2325
|
"display",
|
|
2852
2326
|
"scale",
|
|
2853
2327
|
"trading"
|
|
2854
|
-
],
|
|
2328
|
+
], Wt = [
|
|
2855
2329
|
1,
|
|
2856
2330
|
2,
|
|
2857
2331
|
3,
|
|
2858
2332
|
4
|
|
2859
|
-
],
|
|
2333
|
+
], Gt = class {
|
|
2860
2334
|
callbacks;
|
|
2861
2335
|
t;
|
|
2862
2336
|
backdrop = null;
|
|
@@ -2896,7 +2370,7 @@ var Kt = [
|
|
|
2896
2370
|
}), e.appendChild(n), this.modal.appendChild(e);
|
|
2897
2371
|
let r = document.createElement("div");
|
|
2898
2372
|
r.className = "tcw-modal-tabs", r.setAttribute("role", "tablist"), this.tabButtons = [];
|
|
2899
|
-
for (let e of
|
|
2373
|
+
for (let e of Ut) {
|
|
2900
2374
|
let t = document.createElement("button");
|
|
2901
2375
|
t.type = "button", t.className = "tcw-modal-tab", t.setAttribute("role", "tab"), t.textContent = this.t(`settings.tab.${e}`), t.dataset.tab = e, t.setAttribute("aria-selected", String(e === this.currentTab)), e === this.currentTab && t.classList.add("tcw-active"), t.addEventListener("click", () => {
|
|
2902
2376
|
this.currentTab = e, this.tabButtons.forEach((t) => {
|
|
@@ -2930,14 +2404,14 @@ var Kt = [
|
|
|
2930
2404
|
this.renderScaleTab();
|
|
2931
2405
|
break;
|
|
2932
2406
|
case "trading":
|
|
2933
|
-
for (let e of
|
|
2407
|
+
for (let e of qe) (!e.trading || this.available.trading !== !1) && this.renderLookSection(e);
|
|
2934
2408
|
break;
|
|
2935
2409
|
}
|
|
2936
2410
|
}
|
|
2937
2411
|
renderStyleTab() {
|
|
2938
2412
|
if (!(!this.bodyEl || !this.currentSettings)) {
|
|
2939
2413
|
this.renderChartTypeSection();
|
|
2940
|
-
for (let e of
|
|
2414
|
+
for (let e of Ke) this.renderLookSection(e);
|
|
2941
2415
|
}
|
|
2942
2416
|
}
|
|
2943
2417
|
renderLookSection(e) {
|
|
@@ -2968,12 +2442,12 @@ var Kt = [
|
|
|
2968
2442
|
break;
|
|
2969
2443
|
}
|
|
2970
2444
|
case "lineStyle":
|
|
2971
|
-
i = this.selectRow(t, r(), [...o, ...this.lineStyles()], (e) => a(e === "" ? null :
|
|
2445
|
+
i = this.selectRow(t, r(), [...o, ...this.lineStyles()], (e) => a(e === "" ? null : Jt(e))), s = () => {
|
|
2972
2446
|
i.querySelector("select").value = r();
|
|
2973
2447
|
};
|
|
2974
2448
|
break;
|
|
2975
2449
|
case "width": {
|
|
2976
|
-
let e = n(), c = typeof e == "number" && !
|
|
2450
|
+
let e = n(), c = typeof e == "number" && !Wt.includes(e) ? [...Wt, e].sort((e, t) => e - t) : Wt;
|
|
2977
2451
|
i = this.selectRow(t, r(), [...o, ...c.map((e) => ({
|
|
2978
2452
|
value: String(e),
|
|
2979
2453
|
label: `${e}px`
|
|
@@ -3036,10 +2510,10 @@ var Kt = [
|
|
|
3036
2510
|
label: this.t("settings.crosshair.hidden"),
|
|
3037
2511
|
value: "hidden"
|
|
3038
2512
|
}
|
|
3039
|
-
], (e) => this.patch({ crosshairMode: e }))), t.appendChild(this.selectRow(this.t("settings.timezone"), e.timezone,
|
|
2513
|
+
], (e) => this.patch({ crosshairMode: e }))), t.appendChild(this.selectRow(this.t("settings.timezone"), e.timezone, Re(e.timezone, Date.now(), this.t("settings.timezone.local"), this.available.exchangeZone ? {
|
|
3040
2514
|
label: this.t("settings.timezone.exchange"),
|
|
3041
2515
|
zone: this.available.exchangeZone()
|
|
3042
|
-
} : void 0), (e) => this.patch({ timezone: e }))), t.appendChild(this.selectRow(this.t("settings.numberLocale"), e.numberLocale,
|
|
2516
|
+
} : void 0), (e) => this.patch({ timezone: e }))), t.appendChild(this.selectRow(this.t("settings.numberLocale"), e.numberLocale, St(e.numberLocale), (e) => this.patch({ numberLocale: e }))), this.bodyEl.appendChild(t);
|
|
3043
2517
|
}
|
|
3044
2518
|
renderScaleTab() {
|
|
3045
2519
|
if (!this.bodyEl || !this.currentSettings) return;
|
|
@@ -3067,7 +2541,7 @@ var Kt = [
|
|
|
3067
2541
|
}
|
|
3068
2542
|
renderChartTypeSection() {
|
|
3069
2543
|
if (!this.bodyEl || !this.currentSettings || !this.chartType) return;
|
|
3070
|
-
let e = this.chartType, t = this.currentSettings.chartTypeOptions ?? {}, n =
|
|
2544
|
+
let e = this.chartType, t = this.currentSettings.chartTypeOptions ?? {}, n = ze.find((t) => t.value === e), r = this.section(n ? wt(n, this.t) : e), i = (e, t) => this.patch({ chartTypeOptions: {
|
|
3071
2545
|
...this.currentSettings?.chartTypeOptions ?? {},
|
|
3072
2546
|
[e]: t
|
|
3073
2547
|
} });
|
|
@@ -3077,14 +2551,14 @@ var Kt = [
|
|
|
3077
2551
|
r.appendChild(this.numberRow(this.t("settings.boxSize"), typeof e.boxSize == "number" ? e.boxSize : null, "any", Infinity, (e) => i("renko", {
|
|
3078
2552
|
...this.currentSettings?.chartTypeOptions?.renko ?? {},
|
|
3079
2553
|
boxSize: e ?? "atr"
|
|
3080
|
-
}))), r.appendChild(this.numberRow(this.t("settings.atrPeriod"), e.atrPeriod ?? null, "1", 500, (e) => i("renko",
|
|
2554
|
+
}))), r.appendChild(this.numberRow(this.t("settings.atrPeriod"), e.atrPeriod ?? null, "1", 500, (e) => i("renko", Kt(this.currentSettings?.chartTypeOptions?.renko, "atrPeriod", e))));
|
|
3081
2555
|
break;
|
|
3082
2556
|
}
|
|
3083
2557
|
case "lineBreak":
|
|
3084
|
-
r.appendChild(this.numberRow(this.t("settings.lineBreakLines"), t.lineBreak?.lines ?? null, "1", 10, (e) => i("lineBreak",
|
|
2558
|
+
r.appendChild(this.numberRow(this.t("settings.lineBreakLines"), t.lineBreak?.lines ?? null, "1", 10, (e) => i("lineBreak", Kt(this.currentSettings?.chartTypeOptions?.lineBreak, "lines", e))));
|
|
3085
2559
|
break;
|
|
3086
2560
|
case "kagi":
|
|
3087
|
-
r.appendChild(this.numberRow(this.t("settings.reversal"), t.kagi?.reversal ?? null, "any", Infinity, (e) => i("kagi",
|
|
2561
|
+
r.appendChild(this.numberRow(this.t("settings.reversal"), t.kagi?.reversal ?? null, "any", Infinity, (e) => i("kagi", Kt(this.currentSettings?.chartTypeOptions?.kagi, "reversal", e)))), r.appendChild(this.selectRow(this.t("settings.reversalType"), t.kagi?.reversalType ?? "percent", [{
|
|
3088
2562
|
value: "percent",
|
|
3089
2563
|
label: this.t("settings.reversalType.percent")
|
|
3090
2564
|
}, {
|
|
@@ -3099,14 +2573,14 @@ var Kt = [
|
|
|
3099
2573
|
r.appendChild(this.numberRow(this.t("settings.boxSize"), typeof t.pointAndFigure?.boxSize == "number" ? t.pointAndFigure.boxSize : null, "any", Infinity, (e) => i("pointAndFigure", {
|
|
3100
2574
|
...this.currentSettings?.chartTypeOptions?.pointAndFigure ?? {},
|
|
3101
2575
|
boxSize: e ?? "auto"
|
|
3102
|
-
}))), r.appendChild(this.numberRow(this.t("settings.reversalBoxes"), t.pointAndFigure?.reversal ?? null, "1", 10, (e) => i("pointAndFigure",
|
|
2576
|
+
}))), r.appendChild(this.numberRow(this.t("settings.reversalBoxes"), t.pointAndFigure?.reversal ?? null, "1", 10, (e) => i("pointAndFigure", Kt(this.currentSettings?.chartTypeOptions?.pointAndFigure, "reversal", e))));
|
|
3103
2577
|
break;
|
|
3104
2578
|
case "rangeBars":
|
|
3105
2579
|
r.appendChild(this.numberRow(this.t("settings.barRange"), typeof t.rangeBars?.range == "number" ? t.rangeBars.range : null, "any", Infinity, (e) => i("rangeBars", { range: e ?? "auto" })));
|
|
3106
2580
|
break;
|
|
3107
2581
|
default: break;
|
|
3108
2582
|
}
|
|
3109
|
-
for (let t of
|
|
2583
|
+
for (let t of Xe(e)) r.appendChild(this.lookRow(t));
|
|
3110
2584
|
this.bodyEl.appendChild(r);
|
|
3111
2585
|
}
|
|
3112
2586
|
numberRow(e, t, n, r, i) {
|
|
@@ -3145,7 +2619,7 @@ var Kt = [
|
|
|
3145
2619
|
let s = document.createElement("input");
|
|
3146
2620
|
s.type = "color", s.setAttribute("aria-label", e);
|
|
3147
2621
|
let c = document.createElement("span");
|
|
3148
|
-
c.className = "tcw-color-hex", c.id = `tcw-color-${++
|
|
2622
|
+
c.className = "tcw-color-hex", c.id = `tcw-color-${++qt}`, s.setAttribute("aria-describedby", c.id);
|
|
3149
2623
|
let l = null, u = (t) => {
|
|
3150
2624
|
s.value = I(t ?? r.start?.()), c.textContent = t ?? this.t("settings.auto"), i.classList.toggle("tcw-color-auto", t === null), t !== null && r.start && !l ? (l = document.createElement("button"), l.type = "button", l.className = "tcw-color-auto-btn", l.textContent = this.t("settings.auto"), l.setAttribute("aria-label", `${e}: ${this.t("settings.auto")}`), l.addEventListener("click", () => {
|
|
3151
2625
|
n(null), s.focus(), u(r.read());
|
|
@@ -3201,17 +2675,17 @@ var Kt = [
|
|
|
3201
2675
|
this.close();
|
|
3202
2676
|
}
|
|
3203
2677
|
};
|
|
3204
|
-
function
|
|
2678
|
+
function Kt(e, t, n) {
|
|
3205
2679
|
let r = { ...e ?? {} };
|
|
3206
2680
|
return n === null ? delete r[t] : r[t] = n, r;
|
|
3207
2681
|
}
|
|
3208
|
-
var
|
|
3209
|
-
function
|
|
2682
|
+
var qt = 0;
|
|
2683
|
+
function Jt(e) {
|
|
3210
2684
|
return e === "dashed" || e === "dotted" ? e : "solid";
|
|
3211
2685
|
}
|
|
3212
2686
|
//#endregion
|
|
3213
2687
|
//#region src/widget/WidgetStatusBar.ts
|
|
3214
|
-
var
|
|
2688
|
+
var Yt = class {
|
|
3215
2689
|
el;
|
|
3216
2690
|
dotEl;
|
|
3217
2691
|
messageEl;
|
|
@@ -3256,7 +2730,16 @@ var Qt = class {
|
|
|
3256
2730
|
let n = document.createElement("button");
|
|
3257
2731
|
return n.type = "button", n.className = "tcw-range-btn tcw-range-goto", n.dataset.role = "goto", A(n, "goToDate", "statusBar.goToDate"), n.title = `${e.goToLabel} (Alt+G)`, n.setAttribute("aria-label", e.goToLabel), n.innerHTML = j("calendar", 13), n.addEventListener("click", e.onGoTo), t.appendChild(n), t;
|
|
3258
2732
|
}
|
|
3259
|
-
}
|
|
2733
|
+
};
|
|
2734
|
+
//#endregion
|
|
2735
|
+
//#region src/widget/footerHints.ts
|
|
2736
|
+
function Xt(e, t, n) {
|
|
2737
|
+
let r = (...e) => e.map((e) => `<kbd class="tcw-cmd-kbd tcw-cmd-key">${e}</kbd>`).join(""), i = (e, t) => `<span class="tcw-cmd-help">${e}<span class="tcw-cmd-help-text">${N(t)}</span></span>`;
|
|
2738
|
+
return i(r(j("arrowUp", 11), j("arrowDown", 11)), e) + i(r(j("enter", 11)), t) + i(r("Esc"), n);
|
|
2739
|
+
}
|
|
2740
|
+
//#endregion
|
|
2741
|
+
//#region src/widget/WidgetCommandPalette.ts
|
|
2742
|
+
var Zt = class {
|
|
3260
2743
|
backdrop = null;
|
|
3261
2744
|
modal = null;
|
|
3262
2745
|
input = null;
|
|
@@ -3275,11 +2758,11 @@ var Qt = class {
|
|
|
3275
2758
|
let t = document.createElement("div");
|
|
3276
2759
|
t.className = "tcw-cmd-header";
|
|
3277
2760
|
let n = document.createElement("span");
|
|
3278
|
-
n.className = "tcw-cmd-icon", n.
|
|
2761
|
+
n.className = "tcw-cmd-icon", n.innerHTML = j("search", 16), t.appendChild(n), this.input = document.createElement("input"), this.input.className = "tcw-cmd-input", this.input.type = "text", this.input.placeholder = this.t("palette.placeholder"), this.input.addEventListener("input", () => this.filter()), t.appendChild(this.input);
|
|
3279
2762
|
let r = document.createElement("span");
|
|
3280
2763
|
r.className = "tcw-cmd-hint", r.textContent = "ESC", t.appendChild(r), this.modal.appendChild(t), this.list = document.createElement("div"), this.list.className = "tcw-cmd-list", this.modal.appendChild(this.list);
|
|
3281
2764
|
let i = document.createElement("div");
|
|
3282
|
-
i.className = "tcw-cmd-footer", i.innerHTML =
|
|
2765
|
+
i.className = "tcw-cmd-footer", i.innerHTML = Xt(this.t("common.navigate"), this.t("common.select"), this.t("common.close")), this.modal.appendChild(i), this.host().append(this.backdrop, this.modal), this.renderList(), this.input.focus(), document.addEventListener("keydown", this.boundKeydown);
|
|
3283
2766
|
}
|
|
3284
2767
|
close() {
|
|
3285
2768
|
document.removeEventListener("keydown", this.boundKeydown), this.backdrop?.remove(), this.modal?.remove(), this.backdrop = null, this.modal = null, this.input = null, this.list = null, this.callbacks.onClose();
|
|
@@ -3311,7 +2794,7 @@ var Qt = class {
|
|
|
3311
2794
|
let i = document.createElement("span");
|
|
3312
2795
|
if (i.className = "tcw-cmd-item-label", i.textContent = n.label, r.appendChild(i), n.active) {
|
|
3313
2796
|
let e = document.createElement("span");
|
|
3314
|
-
e.className = "tcw-cmd-check", e.
|
|
2797
|
+
e.className = "tcw-cmd-check", e.innerHTML = j("check", 14), r.appendChild(e);
|
|
3315
2798
|
}
|
|
3316
2799
|
if (n.shortcut) {
|
|
3317
2800
|
let e = document.createElement("kbd");
|
|
@@ -3381,7 +2864,7 @@ var Qt = class {
|
|
|
3381
2864
|
destroy() {
|
|
3382
2865
|
this.close();
|
|
3383
2866
|
}
|
|
3384
|
-
},
|
|
2867
|
+
}, Qt = class {
|
|
3385
2868
|
backdrop = null;
|
|
3386
2869
|
modal = null;
|
|
3387
2870
|
input = null;
|
|
@@ -3410,11 +2893,11 @@ var Qt = class {
|
|
|
3410
2893
|
let i = document.createElement("div");
|
|
3411
2894
|
i.className = "tcw-cmd-header";
|
|
3412
2895
|
let a = document.createElement("span");
|
|
3413
|
-
a.className = "tcw-cmd-icon", a.innerHTML =
|
|
2896
|
+
a.className = "tcw-cmd-icon", a.innerHTML = j("search", 16), i.appendChild(a), this.input = document.createElement("input"), this.input.className = "tcw-cmd-input", this.input.type = "text", this.input.placeholder = this.t("symbolSearch.placeholder"), this.input.autocomplete = "off", this.input.spellcheck = !1, this.input.addEventListener("input", () => this.filter()), i.appendChild(this.input);
|
|
3414
2897
|
let o = document.createElement("span");
|
|
3415
2898
|
o.className = "tcw-cmd-hint", o.textContent = "ESC", i.appendChild(o), this.modal.appendChild(i), this.list = document.createElement("div"), this.list.className = "tcw-cmd-list", this.modal.appendChild(this.list);
|
|
3416
2899
|
let s = document.createElement("div");
|
|
3417
|
-
s.className = "tcw-cmd-footer", s.innerHTML =
|
|
2900
|
+
s.className = "tcw-cmd-footer", s.innerHTML = Xt(this.t("common.navigate"), this.t("common.open"), this.t("common.close")), this.modal.appendChild(s), this.host().append(this.backdrop, this.modal), this.renderList(), this.input.focus(), document.addEventListener("keydown", this.boundKeydown);
|
|
3418
2901
|
}
|
|
3419
2902
|
close() {
|
|
3420
2903
|
document.removeEventListener("keydown", this.boundKeydown), this.cancelSearch(), this.pickOnResults = !1, this.searchFn = null, this.backdrop?.remove(), this.modal?.remove(), this.backdrop = null, this.modal = null, this.input = null, this.list = null, this.pickOverride = null, this.callbacks.onClose();
|
|
@@ -3434,7 +2917,7 @@ var Qt = class {
|
|
|
3434
2917
|
}
|
|
3435
2918
|
this.cancelSearch(), this.status = "idle", e ? this.filtered = this.symbols.map((t) => ({
|
|
3436
2919
|
symbol: t,
|
|
3437
|
-
score:
|
|
2920
|
+
score: $t(t.toUpperCase(), e)
|
|
3438
2921
|
})).filter((e) => e.score > 0).sort((e, t) => t.score - e.score) : this.filtered = this.symbols.map((e) => ({
|
|
3439
2922
|
symbol: e,
|
|
3440
2923
|
score: 0
|
|
@@ -3484,7 +2967,7 @@ var Qt = class {
|
|
|
3484
2967
|
let { symbol: n, description: r, meta: i } = this.filtered[t], a = document.createElement("button");
|
|
3485
2968
|
a.className = "tcw-cmd-item", t === this.selectedIndex && a.classList.add("tcw-selected"), n === this.current && a.classList.add("tcw-active");
|
|
3486
2969
|
let o = document.createElement("span");
|
|
3487
|
-
if (o.className = "tcw-cmd-item-label", o.innerHTML =
|
|
2970
|
+
if (o.className = "tcw-cmd-item-label", o.innerHTML = en(n, e), a.appendChild(o), r && r !== n) {
|
|
3488
2971
|
let e = document.createElement("span");
|
|
3489
2972
|
e.className = "tcw-cmd-item-desc", e.textContent = r, a.appendChild(e);
|
|
3490
2973
|
}
|
|
@@ -3494,7 +2977,7 @@ var Qt = class {
|
|
|
3494
2977
|
}
|
|
3495
2978
|
if (n === this.current) {
|
|
3496
2979
|
let e = document.createElement("span");
|
|
3497
|
-
e.className = "tcw-cmd-check", e.
|
|
2980
|
+
e.className = "tcw-cmd-check", e.innerHTML = j("check", 14), a.appendChild(e);
|
|
3498
2981
|
}
|
|
3499
2982
|
a.addEventListener("click", () => this.pick(t)), a.addEventListener("mouseenter", () => {
|
|
3500
2983
|
this.selectedIndex = t, this.updateSelection();
|
|
@@ -3533,7 +3016,7 @@ var Qt = class {
|
|
|
3533
3016
|
}
|
|
3534
3017
|
}
|
|
3535
3018
|
};
|
|
3536
|
-
function
|
|
3019
|
+
function $t(e, t) {
|
|
3537
3020
|
if (e === t) return 1e3;
|
|
3538
3021
|
if (e.startsWith(t)) return 500 + (50 - Math.min(50, e.length - t.length));
|
|
3539
3022
|
if (e.includes(t)) return 200 + (50 - Math.min(50, e.length - t.length));
|
|
@@ -3541,25 +3024,22 @@ function tn(e, t) {
|
|
|
3541
3024
|
for (let a = 0; a < e.length && n < t.length; a++) e[a] === t[n] && (r >= 0 && (i += a - r - 1), r = a, n++);
|
|
3542
3025
|
return n < t.length ? 0 : 100 - Math.min(99, i);
|
|
3543
3026
|
}
|
|
3544
|
-
function
|
|
3027
|
+
function en(e, t) {
|
|
3545
3028
|
if (!t) return N(e);
|
|
3546
3029
|
let n = e.toUpperCase(), r = "", i = 0;
|
|
3547
3030
|
for (let a = 0; a < e.length; a++) i < t.length && n[a] === t[i] ? (r += `<mark style="background:transparent;color:var(--tcw-accent);font-weight:700">${N(e[a])}</mark>`, i++) : r += N(e[a]);
|
|
3548
3031
|
return r;
|
|
3549
3032
|
}
|
|
3550
|
-
function rn() {
|
|
3551
|
-
return "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"m21 21-4.3-4.3\"/></svg>";
|
|
3552
|
-
}
|
|
3553
3033
|
//#endregion
|
|
3554
3034
|
//#region src/widget/WidgetHotkeySheet.ts
|
|
3555
|
-
var
|
|
3035
|
+
var tn = {
|
|
3556
3036
|
"Search & navigation": "hotkeys.group.searchNavigation",
|
|
3557
3037
|
"Chart manipulation": "hotkeys.group.chartManipulation",
|
|
3558
3038
|
"Touch (mobile / tablet)": "hotkeys.group.touch",
|
|
3559
3039
|
Keyboard: "hotkeys.group.keyboard",
|
|
3560
3040
|
Drawing: "hotkeys.group.drawing",
|
|
3561
3041
|
More: "hotkeys.group.more"
|
|
3562
|
-
}, R = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent) ? "⌘" : "Ctrl",
|
|
3042
|
+
}, R = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent) ? "⌘" : "Ctrl", nn = [
|
|
3563
3043
|
{
|
|
3564
3044
|
title: "Search & navigation",
|
|
3565
3045
|
entries: [
|
|
@@ -3787,7 +3267,7 @@ var an = {
|
|
|
3787
3267
|
}
|
|
3788
3268
|
]
|
|
3789
3269
|
}
|
|
3790
|
-
],
|
|
3270
|
+
], rn = class {
|
|
3791
3271
|
backdrop = null;
|
|
3792
3272
|
modal = null;
|
|
3793
3273
|
callbacks;
|
|
@@ -3800,7 +3280,7 @@ var an = {
|
|
|
3800
3280
|
}
|
|
3801
3281
|
open(e = {}) {
|
|
3802
3282
|
if (this.backdrop) return;
|
|
3803
|
-
let t = e.isOn ?? (() => !0), n = new Set((e.extra ?? []).map((e) => e.keys.join("+").toLowerCase())), r =
|
|
3283
|
+
let t = e.isOn ?? (() => !0), n = new Set((e.extra ?? []).map((e) => e.keys.join("+").toLowerCase())), r = nn.map((e) => ({
|
|
3804
3284
|
title: e.title,
|
|
3805
3285
|
entries: e.entries.filter((e) => (!e.feature || t(e.feature)) && !n.has(e.keys.join("+").toLowerCase()))
|
|
3806
3286
|
})).filter((e) => e.entries.length > 0);
|
|
@@ -3813,7 +3293,7 @@ var an = {
|
|
|
3813
3293
|
let a = document.createElement("h3");
|
|
3814
3294
|
a.textContent = this.t("hotkeys.title"), i.appendChild(a);
|
|
3815
3295
|
let o = document.createElement("button");
|
|
3816
|
-
o.className = "tcw-modal-close", o.setAttribute("aria-label", this.t("hotkeys.close")), o.innerHTML = "
|
|
3296
|
+
o.className = "tcw-modal-close", o.setAttribute("aria-label", this.t("hotkeys.close")), o.innerHTML = j("x", 14), o.addEventListener("click", () => this.close()), i.appendChild(o), this.modal.appendChild(i);
|
|
3817
3297
|
let s = document.createElement("div");
|
|
3818
3298
|
s.className = "tcw-modal-body";
|
|
3819
3299
|
let c = document.createElement("div");
|
|
@@ -3823,7 +3303,7 @@ var an = {
|
|
|
3823
3303
|
t.className = "tcw-hotkey-section";
|
|
3824
3304
|
let n = document.createElement("div");
|
|
3825
3305
|
n.className = "tcw-settings-section-title";
|
|
3826
|
-
let r =
|
|
3306
|
+
let r = tn[e.title];
|
|
3827
3307
|
n.textContent = r ? this.t(r) : e.title, t.appendChild(n);
|
|
3828
3308
|
for (let n of e.entries) {
|
|
3829
3309
|
let e = document.createElement("div");
|
|
@@ -3863,7 +3343,7 @@ var an = {
|
|
|
3863
3343
|
destroy() {
|
|
3864
3344
|
this.close();
|
|
3865
3345
|
}
|
|
3866
|
-
},
|
|
3346
|
+
}, an = {
|
|
3867
3347
|
selectHint: "Click a bar to start the replay",
|
|
3868
3348
|
random: "Random bar",
|
|
3869
3349
|
realtime: "Back to realtime",
|
|
@@ -3876,7 +3356,7 @@ var an = {
|
|
|
3876
3356
|
position: "Replay position",
|
|
3877
3357
|
speed: "Speed",
|
|
3878
3358
|
step: "Step"
|
|
3879
|
-
},
|
|
3359
|
+
}, on = [
|
|
3880
3360
|
1,
|
|
3881
3361
|
2,
|
|
3882
3362
|
3,
|
|
@@ -3884,7 +3364,7 @@ var an = {
|
|
|
3884
3364
|
10,
|
|
3885
3365
|
25,
|
|
3886
3366
|
50
|
|
3887
|
-
],
|
|
3367
|
+
], sn = class {
|
|
3888
3368
|
root = null;
|
|
3889
3369
|
scrubber = null;
|
|
3890
3370
|
progressLabel = null;
|
|
@@ -3900,7 +3380,7 @@ var an = {
|
|
|
3900
3380
|
labels;
|
|
3901
3381
|
constructor(e, t = {}) {
|
|
3902
3382
|
this.callbacks = e, this.labels = {
|
|
3903
|
-
...
|
|
3383
|
+
...an,
|
|
3904
3384
|
...t
|
|
3905
3385
|
};
|
|
3906
3386
|
}
|
|
@@ -3933,16 +3413,16 @@ var an = {
|
|
|
3933
3413
|
this.unmount();
|
|
3934
3414
|
}
|
|
3935
3415
|
markup() {
|
|
3936
|
-
let e = this.labels, t =
|
|
3416
|
+
let e = this.labels, t = on.map((t) => `<option value="${t}"${t === this.speed ? " selected" : ""}>${t} ${N(e.barsPerSecond)}</option>`).join("");
|
|
3937
3417
|
return `
|
|
3938
3418
|
<span class="tcw-replay-group" data-mode="select">
|
|
3939
|
-
<span class="tcw-replay-hint" role="status">${
|
|
3419
|
+
<span class="tcw-replay-hint" role="status">${fn()}${N(e.selectHint)}</span>
|
|
3940
3420
|
<button class="tcw-replay-text-btn" data-act="random">${N(e.random)}</button>
|
|
3941
3421
|
</span>
|
|
3942
3422
|
<span class="tcw-replay-group" data-mode="replay">
|
|
3943
|
-
<button class="tcw-replay-btn" data-act="stepBack" title="${N(e.stepBack)}" aria-label="${N(e.stepBack)}">${
|
|
3944
|
-
<button class="tcw-replay-btn tcw-replay-play" data-act="play" title="${N(e.play)}" aria-label="${N(e.play)}">${
|
|
3945
|
-
<button class="tcw-replay-btn" data-act="stepForward" title="${N(e.stepForward)}" aria-label="${N(e.stepForward)}">${
|
|
3423
|
+
<button class="tcw-replay-btn" data-act="stepBack" title="${N(e.stepBack)}" aria-label="${N(e.stepBack)}">${un()}</button>
|
|
3424
|
+
<button class="tcw-replay-btn tcw-replay-play" data-act="play" title="${N(e.play)}" aria-label="${N(e.play)}">${cn()}</button>
|
|
3425
|
+
<button class="tcw-replay-btn" data-act="stepForward" title="${N(e.stepForward)}" aria-label="${N(e.stepForward)}">${dn()}</button>
|
|
3946
3426
|
<input type="range" class="tcw-replay-scrubber" data-act="seek" min="0" max="${Math.max(0, this.total - 1)}" value="0" step="1" aria-label="${N(this.labels.position)}" />
|
|
3947
3427
|
<span class="tcw-replay-progress" data-tcw="progress">1 / ${this.total}</span>
|
|
3948
3428
|
<select class="tcw-replay-speed" data-act="speed" aria-label="${N(this.labels.speed)}">${t}</select>
|
|
@@ -3968,31 +3448,13 @@ var an = {
|
|
|
3968
3448
|
for (let t of e.querySelectorAll(".tcw-replay-group")) t.hidden = t.dataset.mode !== this.mode;
|
|
3969
3449
|
if (e.classList.toggle("tcw-replay-bar--ended", this.ended), this.playBtn) {
|
|
3970
3450
|
let e = this.state === "playing";
|
|
3971
|
-
this.playBtn.innerHTML = e ?
|
|
3451
|
+
this.playBtn.innerHTML = e ? ln() : cn(), this.playBtn.title = e ? this.labels.pause : this.labels.play, this.playBtn.setAttribute("aria-label", this.playBtn.title);
|
|
3972
3452
|
let t = this.ended && !e;
|
|
3973
3453
|
t && document.activeElement === this.playBtn && this.realtimeBtn?.focus(), this.playBtn.disabled = t;
|
|
3974
3454
|
}
|
|
3975
3455
|
}
|
|
3976
3456
|
}
|
|
3977
|
-
}
|
|
3978
|
-
function dn() {
|
|
3979
|
-
return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M8 5v14l11-7L8 5z\"/></svg>";
|
|
3980
|
-
}
|
|
3981
|
-
function fn() {
|
|
3982
|
-
return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/></svg>";
|
|
3983
|
-
}
|
|
3984
|
-
function pn() {
|
|
3985
|
-
return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M6 6h2v12H6zM20 6L9 12l11 6V6z\"/></svg>";
|
|
3986
|
-
}
|
|
3987
|
-
function mn() {
|
|
3988
|
-
return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M4 6l11 6L4 18V6zM16 6h2v12h-2z\"/></svg>";
|
|
3989
|
-
}
|
|
3990
|
-
function hn() {
|
|
3991
|
-
return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M12 3v18M8 7l4-4 4 4M8 17l4 4 4-4\"/></svg>";
|
|
3992
|
-
}
|
|
3993
|
-
//#endregion
|
|
3994
|
-
//#region src/widget/WidgetWatchlist.ts
|
|
3995
|
-
var gn = class {
|
|
3457
|
+
}, cn = () => j("play", 14), ln = () => j("pause", 14), un = () => j("stepBack", 14), dn = () => j("stepForward", 14), fn = () => j("cursor", 14), pn = class {
|
|
3996
3458
|
el;
|
|
3997
3459
|
headerEl;
|
|
3998
3460
|
nameBtn;
|
|
@@ -4059,7 +3521,7 @@ var gn = class {
|
|
|
4059
3521
|
let t = document.createElement("div");
|
|
4060
3522
|
t.className = "tcw-watchlist-row", t.setAttribute("role", "listitem"), t.dataset.symbol = e, t.tabIndex = 0, t.draggable = !!this.callbacks.onMove;
|
|
4061
3523
|
let n = document.createElement("div");
|
|
4062
|
-
n.className = "tcw-watchlist-symbol", n.textContent =
|
|
3524
|
+
n.className = "tcw-watchlist-symbol", n.textContent = mn(e);
|
|
4063
3525
|
let r = document.createElement("canvas");
|
|
4064
3526
|
r.className = "tcw-watchlist-spark", r.width = 64, r.height = 22;
|
|
4065
3527
|
let i = document.createElement("div");
|
|
@@ -4069,7 +3531,7 @@ var gn = class {
|
|
|
4069
3531
|
let o = document.createElement("span");
|
|
4070
3532
|
if (o.className = "tcw-watchlist-change", i.append(a, o), t.append(n, r, i), this.callbacks.onRemove) {
|
|
4071
3533
|
let n = document.createElement("button");
|
|
4072
|
-
n.type = "button", n.className = "tcw-watchlist-remove", n.
|
|
3534
|
+
n.type = "button", n.className = "tcw-watchlist-remove", n.innerHTML = j("x", 12), n.tabIndex = -1;
|
|
4073
3535
|
let r = p(this.labels.remove, { symbol: e });
|
|
4074
3536
|
n.title = r, n.setAttribute("aria-label", r), n.addEventListener("click", (t) => {
|
|
4075
3537
|
t.stopPropagation(), this.callbacks.onRemove?.(e);
|
|
@@ -4118,14 +3580,14 @@ var gn = class {
|
|
|
4118
3580
|
renderRow(e) {
|
|
4119
3581
|
let t = this.rowMap.get(e), n = this.entries.get(e);
|
|
4120
3582
|
if (!(!t || !n)) {
|
|
4121
|
-
if (n.lastPrice !== void 0 && (t.priceEl.textContent =
|
|
3583
|
+
if (n.lastPrice !== void 0 && (t.priceEl.textContent = hn(n.lastPrice, this.locale)), n.lastPrice !== void 0 && n.refPrice !== void 0 && n.refPrice !== 0) {
|
|
4122
3584
|
let e = n.lastPrice - n.refPrice, r = e / n.refPrice * 100, i = e >= 0 ? "+" : "-", a = Math.abs(r).toLocaleString(this.locale, {
|
|
4123
3585
|
minimumFractionDigits: 2,
|
|
4124
3586
|
maximumFractionDigits: 2
|
|
4125
3587
|
});
|
|
4126
3588
|
t.changeEl.textContent = `${i}${a}%`, t.changeEl.className = `tcw-watchlist-change ${e >= 0 ? "tcw-up" : "tcw-down"}`;
|
|
4127
3589
|
} else t.changeEl.textContent = "";
|
|
4128
|
-
n.sparkline && n.sparkline.length >= 2 &&
|
|
3590
|
+
n.sparkline && n.sparkline.length >= 2 && gn(t.sparkCanvas, n.sparkline, n.refPrice ?? n.sparkline[0]);
|
|
4129
3591
|
}
|
|
4130
3592
|
}
|
|
4131
3593
|
openMenu() {
|
|
@@ -4184,7 +3646,7 @@ var gn = class {
|
|
|
4184
3646
|
}), n.addEventListener("blur", () => i(!1)), n.focus();
|
|
4185
3647
|
}
|
|
4186
3648
|
};
|
|
4187
|
-
function
|
|
3649
|
+
function mn(e) {
|
|
4188
3650
|
for (let t of [
|
|
4189
3651
|
"USDT",
|
|
4190
3652
|
"USD",
|
|
@@ -4194,7 +3656,7 @@ function _n(e) {
|
|
|
4194
3656
|
]) if (e.length > t.length && e.endsWith(t)) return e.slice(0, -t.length) + "/" + t;
|
|
4195
3657
|
return e;
|
|
4196
3658
|
}
|
|
4197
|
-
function
|
|
3659
|
+
function hn(e, t) {
|
|
4198
3660
|
if (e === 0) return "0";
|
|
4199
3661
|
let n = Math.abs(e);
|
|
4200
3662
|
return n >= 1e3 ? e.toLocaleString(t, {
|
|
@@ -4205,7 +3667,7 @@ function vn(e, t) {
|
|
|
4205
3667
|
maximumFractionDigits: 4
|
|
4206
3668
|
}) : Number(e.toPrecision(4)).toLocaleString(t, { maximumFractionDigits: 10 });
|
|
4207
3669
|
}
|
|
4208
|
-
function
|
|
3670
|
+
function gn(e, t, n) {
|
|
4209
3671
|
let r = e.getContext("2d");
|
|
4210
3672
|
if (!r) return;
|
|
4211
3673
|
let i = window.devicePixelRatio || 1;
|
|
@@ -4223,32 +3685,32 @@ function yn(e, t, n) {
|
|
|
4223
3685
|
}
|
|
4224
3686
|
//#endregion
|
|
4225
3687
|
//#region src/widget/WatchlistStore.ts
|
|
4226
|
-
var
|
|
3688
|
+
var _n = 50, vn = 500, yn = 60, bn = 64, xn = (e) => typeof e == "string" && e.trim().slice(0, yn) || null, Sn = (e) => {
|
|
4227
3689
|
if (typeof e != "string") return null;
|
|
4228
3690
|
let t = e.trim();
|
|
4229
|
-
return t && t.length <=
|
|
3691
|
+
return t && t.length <= bn ? t : null;
|
|
4230
3692
|
};
|
|
4231
|
-
function
|
|
3693
|
+
function Cn(e) {
|
|
4232
3694
|
let t = [];
|
|
4233
3695
|
for (let n of e) {
|
|
4234
|
-
let e =
|
|
4235
|
-
if (e && !t.includes(e) && t.push(e), t.length ===
|
|
3696
|
+
let e = Sn(n);
|
|
3697
|
+
if (e && !t.includes(e) && t.push(e), t.length === vn) break;
|
|
4236
3698
|
}
|
|
4237
3699
|
return t;
|
|
4238
3700
|
}
|
|
4239
|
-
function
|
|
3701
|
+
function wn(e) {
|
|
4240
3702
|
if (!e || typeof e != "object") return null;
|
|
4241
3703
|
let t = e;
|
|
4242
3704
|
if (!Array.isArray(t.lists)) return null;
|
|
4243
3705
|
let n = [];
|
|
4244
3706
|
for (let e of t.lists) {
|
|
4245
|
-
if (n.length ===
|
|
3707
|
+
if (n.length === _n) break;
|
|
4246
3708
|
if (!e || typeof e != "object") continue;
|
|
4247
|
-
let t = e, r = typeof t.id == "string" && t.id && t.id.length <=
|
|
3709
|
+
let t = e, r = typeof t.id == "string" && t.id && t.id.length <= bn ? t.id : null, i = xn(t.name);
|
|
4248
3710
|
!r || !i || n.some((e) => e.id === r) || n.push({
|
|
4249
3711
|
id: r,
|
|
4250
3712
|
name: i,
|
|
4251
|
-
symbols: Array.isArray(t.symbols) ?
|
|
3713
|
+
symbols: Array.isArray(t.symbols) ? Cn(t.symbols) : []
|
|
4252
3714
|
});
|
|
4253
3715
|
}
|
|
4254
3716
|
return n.length === 0 ? null : {
|
|
@@ -4256,10 +3718,10 @@ function Dn(e) {
|
|
|
4256
3718
|
active: typeof t.active == "string" && n.some((e) => e.id === t.active) ? t.active : n[0].id
|
|
4257
3719
|
};
|
|
4258
3720
|
}
|
|
4259
|
-
var
|
|
3721
|
+
var Tn = (e) => ({
|
|
4260
3722
|
...e,
|
|
4261
3723
|
symbols: [...e.symbols]
|
|
4262
|
-
}),
|
|
3724
|
+
}), En = class {
|
|
4263
3725
|
lists;
|
|
4264
3726
|
active;
|
|
4265
3727
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -4267,38 +3729,38 @@ var On = (e) => ({
|
|
|
4267
3729
|
storageKey;
|
|
4268
3730
|
constructor(e) {
|
|
4269
3731
|
this.storage = e.storage ?? null, this.storageKey = e.storageKey ?? "tcw:watchlists";
|
|
4270
|
-
let t = this.load(), n = e.lists ?
|
|
3732
|
+
let t = this.load(), n = e.lists ? wn({
|
|
4271
3733
|
lists: e.lists,
|
|
4272
3734
|
active: e.activeList
|
|
4273
3735
|
}) : null, r = t ?? n ?? {
|
|
4274
3736
|
lists: [{
|
|
4275
3737
|
id: "default",
|
|
4276
|
-
name:
|
|
4277
|
-
symbols:
|
|
3738
|
+
name: xn(e.defaultName) ?? "Watchlist",
|
|
3739
|
+
symbols: Cn(e.symbols ?? [])
|
|
4278
3740
|
}],
|
|
4279
3741
|
active: "default"
|
|
4280
3742
|
};
|
|
4281
3743
|
this.lists = r.lists, this.active = r.active;
|
|
4282
3744
|
}
|
|
4283
3745
|
getLists() {
|
|
4284
|
-
return this.lists.map(
|
|
3746
|
+
return this.lists.map(Tn);
|
|
4285
3747
|
}
|
|
4286
3748
|
getActive() {
|
|
4287
|
-
return
|
|
3749
|
+
return Tn(this.activeList());
|
|
4288
3750
|
}
|
|
4289
3751
|
setActive(e) {
|
|
4290
3752
|
e === this.active || !this.lists.some((t) => t.id === e) || (this.active = e, this.changed());
|
|
4291
3753
|
}
|
|
4292
3754
|
replace(e, t) {
|
|
4293
|
-
let n =
|
|
3755
|
+
let n = wn({
|
|
4294
3756
|
lists: e,
|
|
4295
3757
|
active: t ?? this.active
|
|
4296
3758
|
});
|
|
4297
3759
|
n && (this.lists = n.lists, this.active = n.active, this.changed());
|
|
4298
3760
|
}
|
|
4299
3761
|
create(e) {
|
|
4300
|
-
let t =
|
|
4301
|
-
if (!t || this.lists.length >=
|
|
3762
|
+
let t = xn(e);
|
|
3763
|
+
if (!t || this.lists.length >= _n) return null;
|
|
4302
3764
|
let n = this.lists.length + 1;
|
|
4303
3765
|
for (; this.lists.some((e) => e.id === `list-${n}`);) n++;
|
|
4304
3766
|
let r = {
|
|
@@ -4306,10 +3768,10 @@ var On = (e) => ({
|
|
|
4306
3768
|
name: t,
|
|
4307
3769
|
symbols: []
|
|
4308
3770
|
};
|
|
4309
|
-
return this.lists = [...this.lists, r], this.active = r.id, this.changed(),
|
|
3771
|
+
return this.lists = [...this.lists, r], this.active = r.id, this.changed(), Tn(r);
|
|
4310
3772
|
}
|
|
4311
3773
|
rename(e, t) {
|
|
4312
|
-
let n =
|
|
3774
|
+
let n = xn(t);
|
|
4313
3775
|
n && this.update(e, (e) => ({
|
|
4314
3776
|
...e,
|
|
4315
3777
|
name: n
|
|
@@ -4319,8 +3781,8 @@ var On = (e) => ({
|
|
|
4319
3781
|
this.lists.length <= 1 || !this.lists.some((t) => t.id === e) || (this.lists = this.lists.filter((t) => t.id !== e), this.active === e && (this.active = this.lists[0].id), this.changed());
|
|
4320
3782
|
}
|
|
4321
3783
|
add(e, t = this.active) {
|
|
4322
|
-
let n =
|
|
4323
|
-
return !n || !r || r.symbols.includes(n) || r.symbols.length >=
|
|
3784
|
+
let n = Sn(e), r = this.lists.find((e) => e.id === t);
|
|
3785
|
+
return !n || !r || r.symbols.includes(n) || r.symbols.length >= vn ? !1 : (this.update(t, (e) => ({
|
|
4324
3786
|
...e,
|
|
4325
3787
|
symbols: [...e.symbols, n]
|
|
4326
3788
|
})), !0);
|
|
@@ -4363,7 +3825,7 @@ var On = (e) => ({
|
|
|
4363
3825
|
if (!this.storage) return null;
|
|
4364
3826
|
try {
|
|
4365
3827
|
let e = this.storage.getItem(this.storageKey);
|
|
4366
|
-
return e ?
|
|
3828
|
+
return e ? wn(JSON.parse(e)) : null;
|
|
4367
3829
|
} catch {
|
|
4368
3830
|
return null;
|
|
4369
3831
|
}
|
|
@@ -4376,7 +3838,7 @@ var On = (e) => ({
|
|
|
4376
3838
|
}));
|
|
4377
3839
|
} catch {}
|
|
4378
3840
|
}
|
|
4379
|
-
},
|
|
3841
|
+
}, Dn = class {
|
|
4380
3842
|
el;
|
|
4381
3843
|
bodyEl;
|
|
4382
3844
|
newsEl;
|
|
@@ -4453,7 +3915,7 @@ function z(e, t, n) {
|
|
|
4453
3915
|
}
|
|
4454
3916
|
//#endregion
|
|
4455
3917
|
//#region src/widget/WidgetChartNav.ts
|
|
4456
|
-
var
|
|
3918
|
+
var On = 300, kn = 80, An = class {
|
|
4457
3919
|
el;
|
|
4458
3920
|
holdTimer = null;
|
|
4459
3921
|
repeatTimer = null;
|
|
@@ -4544,8 +4006,8 @@ var jn = 300, Mn = 80, Nn = class {
|
|
|
4544
4006
|
}
|
|
4545
4007
|
startHold(e) {
|
|
4546
4008
|
this.stopHold(), this.actions.scroll(e), this.holdTimer = setTimeout(() => {
|
|
4547
|
-
this.repeatTimer = setInterval(() => this.actions.scroll(e),
|
|
4548
|
-
},
|
|
4009
|
+
this.repeatTimer = setInterval(() => this.actions.scroll(e), kn);
|
|
4010
|
+
}, On);
|
|
4549
4011
|
}
|
|
4550
4012
|
stopHold() {
|
|
4551
4013
|
this.holdTimer && clearTimeout(this.holdTimer), this.repeatTimer && clearInterval(this.repeatTimer), this.holdTimer = null, this.repeatTimer = null;
|
|
@@ -4553,17 +4015,17 @@ var jn = 300, Mn = 80, Nn = class {
|
|
|
4553
4015
|
};
|
|
4554
4016
|
//#endregion
|
|
4555
4017
|
//#region src/widget/WidgetAlertsPanel.ts
|
|
4556
|
-
function
|
|
4557
|
-
let i = e.label ?? t("alerts.source.price"), a =
|
|
4558
|
-
if (
|
|
4018
|
+
function jn(e, t, n, r = !1) {
|
|
4019
|
+
let i = e.label ?? t("alerts.source.price"), a = In.get(e.condition), o = a ? t(a) : e.condition;
|
|
4020
|
+
if (Nn.includes(e.condition)) return `${i} ${o} ${p(t("alerts.moveSummary"), {
|
|
4559
4021
|
percent: e.percent ?? 0,
|
|
4560
4022
|
bars: e.bars ?? 0
|
|
4561
4023
|
})}`;
|
|
4562
4024
|
if (e.target) return `${i} ${o} ${e.targetLabel ?? e.target}`;
|
|
4563
|
-
let s = e.channel && e.channel !== "price", c = Number.isFinite(e.price) ? s ?
|
|
4025
|
+
let s = e.channel && e.channel !== "price", c = Number.isFinite(e.price) ? s ? Rn(e.price) : n(e.price) : "—";
|
|
4564
4026
|
return `${(s || e.drawingId) && e.label ? `${e.label} ` : r ? `${i} ` : ""}${o} ${c}`;
|
|
4565
4027
|
}
|
|
4566
|
-
var
|
|
4028
|
+
var Mn = [
|
|
4567
4029
|
{
|
|
4568
4030
|
value: "crossing",
|
|
4569
4031
|
key: "alerts.condition.crossing"
|
|
@@ -4592,20 +4054,20 @@ var Fn = [
|
|
|
4592
4054
|
value: "movesDown",
|
|
4593
4055
|
key: "alerts.condition.movesDown"
|
|
4594
4056
|
}
|
|
4595
|
-
],
|
|
4057
|
+
], Nn = ["movesUp", "movesDown"], Pn = {
|
|
4596
4058
|
hour: 36e5,
|
|
4597
4059
|
day: 864e5,
|
|
4598
4060
|
week: 7 * 864e5,
|
|
4599
4061
|
month: 30 * 864e5
|
|
4600
|
-
},
|
|
4601
|
-
function
|
|
4062
|
+
}, Fn = "", In = new Map(Mn.map((e) => [e.value, e.key]));
|
|
4063
|
+
function Ln(e) {
|
|
4602
4064
|
return Math.round(e * 1e6) / 1e6;
|
|
4603
4065
|
}
|
|
4604
|
-
function
|
|
4066
|
+
function Rn(e) {
|
|
4605
4067
|
let t = Math.abs(e);
|
|
4606
4068
|
return t >= 1e3 || t >= 1 ? e.toFixed(2) : e.toPrecision(4);
|
|
4607
4069
|
}
|
|
4608
|
-
var
|
|
4070
|
+
var zn = class {
|
|
4609
4071
|
el;
|
|
4610
4072
|
listEl;
|
|
4611
4073
|
priceInput;
|
|
@@ -4639,11 +4101,11 @@ var Hn = class {
|
|
|
4639
4101
|
o.className = "tcw-alerts-form", o.noValidate = !0, this.sourceSelect = document.createElement("select"), this.sourceSelect.className = "tcw-alerts-source", this.sourceSelect.setAttribute("aria-label", this.t("alerts.source")), this.sourceSelect.addEventListener("change", () => {
|
|
4640
4102
|
this.renderTargets(), this.prefillPrice();
|
|
4641
4103
|
}), this.conditionSelect = document.createElement("select"), this.conditionSelect.className = "tcw-alerts-condition", this.conditionSelect.setAttribute("aria-label", this.t("alerts.conditionLabel"));
|
|
4642
|
-
for (let e of
|
|
4104
|
+
for (let e of Mn) {
|
|
4643
4105
|
let t = document.createElement("option");
|
|
4644
4106
|
t.value = e.value, t.textContent = this.t(e.key), this.conditionSelect.appendChild(t);
|
|
4645
4107
|
}
|
|
4646
|
-
this.conditionSelect.addEventListener("change", () => this.showFields()), this.levelRow = document.createElement("div"), this.levelRow.className = "tcw-alerts-row-fields", this.targetSelect = document.createElement("select"), this.targetSelect.className = "tcw-alerts-target", this.targetSelect.setAttribute("aria-label", this.t("alerts.compareWith")), this.targetSelect.addEventListener("change", () => this.showFields()), this.priceInput = document.createElement("input"), this.priceInput.type = "number", this.priceInput.step = "any", this.priceInput.placeholder = this.t("alerts.value"), this.priceInput.setAttribute("aria-label", this.t("alerts.value")), this.priceInput.className = "tcw-alerts-price", this.levelRow.append(this.targetSelect, this.priceInput), this.moveRow = document.createElement("div"), this.moveRow.className = "tcw-alerts-row-fields", this.percentInput = this.numberField("tcw-alerts-percent", this.t("alerts.percent"), "1", "0.01"), this.barsInput = this.numberField("tcw-alerts-bars", this.t("alerts.bars"), "10", "1"), this.barsInput.min = String(
|
|
4108
|
+
this.conditionSelect.addEventListener("change", () => this.showFields()), this.levelRow = document.createElement("div"), this.levelRow.className = "tcw-alerts-row-fields", this.targetSelect = document.createElement("select"), this.targetSelect.className = "tcw-alerts-target", this.targetSelect.setAttribute("aria-label", this.t("alerts.compareWith")), this.targetSelect.addEventListener("change", () => this.showFields()), this.priceInput = document.createElement("input"), this.priceInput.type = "number", this.priceInput.step = "any", this.priceInput.placeholder = this.t("alerts.value"), this.priceInput.setAttribute("aria-label", this.t("alerts.value")), this.priceInput.className = "tcw-alerts-price", this.levelRow.append(this.targetSelect, this.priceInput), this.moveRow = document.createElement("div"), this.moveRow.className = "tcw-alerts-row-fields", this.percentInput = this.numberField("tcw-alerts-percent", this.t("alerts.percent"), "1", "0.01"), this.barsInput = this.numberField("tcw-alerts-bars", this.t("alerts.bars"), "10", "1"), this.barsInput.min = String(we), this.barsInput.max = String(Ce), this.moveRow.append(this.percentInput, this.barsInput);
|
|
4647
4109
|
let s = document.createElement("div");
|
|
4648
4110
|
s.className = "tcw-alerts-row-fields tcw-alerts-options";
|
|
4649
4111
|
let c = document.createElement("label");
|
|
@@ -4669,20 +4131,20 @@ var Hn = class {
|
|
|
4669
4131
|
return i.type = "number", i.step = r, i.min = "0", i.value = n, i.className = e, i.placeholder = t, i.setAttribute("aria-label", t), i;
|
|
4670
4132
|
}
|
|
4671
4133
|
showFields() {
|
|
4672
|
-
let e =
|
|
4673
|
-
this.moveRow.hidden = !e, this.levelRow.hidden = e, this.priceInput.hidden = this.targetSelect.value !==
|
|
4134
|
+
let e = Nn.includes(this.conditionSelect.value);
|
|
4135
|
+
this.moveRow.hidden = !e, this.levelRow.hidden = e, this.priceInput.hidden = this.targetSelect.value !== Fn;
|
|
4674
4136
|
}
|
|
4675
4137
|
renderTargets() {
|
|
4676
4138
|
let e = this.targetSelect.value, t = this.sourceSelect.value || "price";
|
|
4677
4139
|
this.targetSelect.replaceChildren();
|
|
4678
4140
|
let n = document.createElement("option");
|
|
4679
|
-
n.value =
|
|
4141
|
+
n.value = Fn, n.textContent = this.t("alerts.compare.value"), this.targetSelect.appendChild(n);
|
|
4680
4142
|
for (let e of this.sources) {
|
|
4681
4143
|
if (e.channel === t) continue;
|
|
4682
4144
|
let n = document.createElement("option");
|
|
4683
4145
|
n.value = e.channel, n.textContent = e.label, this.targetSelect.appendChild(n);
|
|
4684
4146
|
}
|
|
4685
|
-
this.targetSelect.value = [...this.targetSelect.options].some((t) => t.value === e) ? e :
|
|
4147
|
+
this.targetSelect.value = [...this.targetSelect.options].some((t) => t.value === e) ? e : Fn, this.showFields();
|
|
4686
4148
|
}
|
|
4687
4149
|
setSources(e) {
|
|
4688
4150
|
this.sources = e.length > 0 ? e : [{
|
|
@@ -4710,7 +4172,7 @@ var Hn = class {
|
|
|
4710
4172
|
}
|
|
4711
4173
|
prefillPrice() {
|
|
4712
4174
|
let e = this.callbacks.getChannelValue(this.sourceSelect.value || "price");
|
|
4713
|
-
this.priceInput.value = e === null ? "" : String(
|
|
4175
|
+
this.priceInput.value = e === null ? "" : String(Ln(e));
|
|
4714
4176
|
}
|
|
4715
4177
|
close() {
|
|
4716
4178
|
this.open = !1, this.el.hidden = !0;
|
|
@@ -4723,20 +4185,20 @@ var Hn = class {
|
|
|
4723
4185
|
}
|
|
4724
4186
|
submitForm() {
|
|
4725
4187
|
let e = this.conditionSelect.value, t = this.messageInput.value.trim() || void 0, n = this.sourceSelect.value || "price", r = this.sources.find((e) => e.channel === n)?.label ?? this.t("alerts.source.price"), i = {}, a = NaN;
|
|
4726
|
-
if (
|
|
4188
|
+
if (Nn.includes(e)) {
|
|
4727
4189
|
i.percent = Number(this.percentInput.value), i.bars = Number(this.barsInput.value);
|
|
4728
|
-
let e = Number.isInteger(i.bars) && i.bars >=
|
|
4190
|
+
let e = Number.isInteger(i.bars) && i.bars >= we && i.bars <= Ce;
|
|
4729
4191
|
if (!(i.percent > 0) || !e) {
|
|
4730
4192
|
this.markInvalid(i.percent > 0 ? this.barsInput : this.percentInput);
|
|
4731
4193
|
return;
|
|
4732
4194
|
}
|
|
4733
|
-
} else if (this.targetSelect.value !==
|
|
4195
|
+
} else if (this.targetSelect.value !== Fn) i.target = this.targetSelect.value;
|
|
4734
4196
|
else if (a = Number(this.priceInput.value), this.priceInput.value.trim() === "" || !Number.isFinite(a)) {
|
|
4735
4197
|
this.markInvalid(this.priceInput);
|
|
4736
4198
|
return;
|
|
4737
4199
|
}
|
|
4738
4200
|
this.closeCheck.checked && (i.onBarClose = !0);
|
|
4739
|
-
let o =
|
|
4201
|
+
let o = Pn[this.expirySelect.value];
|
|
4740
4202
|
o && (i.expiresAt = (this.callbacks.now ?? Date.now)() + o), this.callbacks.onAdd({
|
|
4741
4203
|
price: a,
|
|
4742
4204
|
condition: e,
|
|
@@ -4750,7 +4212,7 @@ var Hn = class {
|
|
|
4750
4212
|
e.setAttribute("aria-invalid", "true"), e.focus(), e.addEventListener("input", () => e.removeAttribute("aria-invalid"), { once: !0 });
|
|
4751
4213
|
}
|
|
4752
4214
|
describe(e) {
|
|
4753
|
-
return
|
|
4215
|
+
return jn(e, this.t, this.callbacks.formatPrice);
|
|
4754
4216
|
}
|
|
4755
4217
|
renderList() {
|
|
4756
4218
|
if (this.listEl.replaceChildren(), this.alerts.length === 0) {
|
|
@@ -4785,7 +4247,7 @@ var Hn = class {
|
|
|
4785
4247
|
a.type = "button", a.className = "tcw-alerts-del", a.setAttribute("aria-label", this.t("alerts.delete")), a.innerHTML = j("trash", 14), a.addEventListener("click", () => this.callbacks.onRemove(e.id)), t.appendChild(n), t.appendChild(a), this.listEl.appendChild(t);
|
|
4786
4248
|
}
|
|
4787
4249
|
}
|
|
4788
|
-
},
|
|
4250
|
+
}, Bn = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", Vn = "'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', 'Consolas', ui-monospace, monospace", Hn = {
|
|
4789
4251
|
studio: {
|
|
4790
4252
|
radius: {
|
|
4791
4253
|
xs: 3,
|
|
@@ -4807,8 +4269,8 @@ var Hn = class {
|
|
|
4807
4269
|
menuItem: 30
|
|
4808
4270
|
},
|
|
4809
4271
|
font: {
|
|
4810
|
-
family: `'Manrope', 'Inter', ${
|
|
4811
|
-
mono:
|
|
4272
|
+
family: `'Manrope', 'Inter', ${Bn}`,
|
|
4273
|
+
mono: Vn,
|
|
4812
4274
|
size: 13,
|
|
4813
4275
|
weight: 500,
|
|
4814
4276
|
strongWeight: 600,
|
|
@@ -4853,7 +4315,7 @@ var Hn = class {
|
|
|
4853
4315
|
menuItem: 26
|
|
4854
4316
|
},
|
|
4855
4317
|
font: {
|
|
4856
|
-
family: `'IBM Plex Sans Condensed', 'Roboto Condensed', 'Arial Narrow', ${
|
|
4318
|
+
family: `'IBM Plex Sans Condensed', 'Roboto Condensed', 'Arial Narrow', ${Bn}`,
|
|
4857
4319
|
mono: "'IBM Plex Mono', ui-monospace, monospace",
|
|
4858
4320
|
size: 12,
|
|
4859
4321
|
weight: 500,
|
|
@@ -4901,8 +4363,8 @@ var Hn = class {
|
|
|
4901
4363
|
menuItem: 34
|
|
4902
4364
|
},
|
|
4903
4365
|
font: {
|
|
4904
|
-
family: `'Sora', 'Manrope', ${
|
|
4905
|
-
mono:
|
|
4366
|
+
family: `'Sora', 'Manrope', ${Bn}`,
|
|
4367
|
+
mono: Vn,
|
|
4906
4368
|
size: 13,
|
|
4907
4369
|
weight: 500,
|
|
4908
4370
|
strongWeight: 600,
|
|
@@ -4925,7 +4387,7 @@ var Hn = class {
|
|
|
4925
4387
|
intervals: "segmented",
|
|
4926
4388
|
tagRadius: 999
|
|
4927
4389
|
}
|
|
4928
|
-
},
|
|
4390
|
+
}, Un = {
|
|
4929
4391
|
compact: {
|
|
4930
4392
|
toolbar: 38,
|
|
4931
4393
|
control: 26,
|
|
@@ -4943,7 +4405,7 @@ var Hn = class {
|
|
|
4943
4405
|
menuItem: 34
|
|
4944
4406
|
}
|
|
4945
4407
|
};
|
|
4946
|
-
function
|
|
4408
|
+
function Wn(e, t) {
|
|
4947
4409
|
return {
|
|
4948
4410
|
control: e.md,
|
|
4949
4411
|
input: e.md,
|
|
@@ -4958,26 +4420,26 @@ function qn(e, t) {
|
|
|
4958
4420
|
...t
|
|
4959
4421
|
};
|
|
4960
4422
|
}
|
|
4961
|
-
var
|
|
4962
|
-
function
|
|
4963
|
-
let t =
|
|
4423
|
+
var Gn = Object.freeze(Object.fromEntries(Object.keys(Hn).map((e) => [e, qn(Kn(e))])));
|
|
4424
|
+
function Kn(e) {
|
|
4425
|
+
let t = Hn[e];
|
|
4964
4426
|
return {
|
|
4965
4427
|
...t,
|
|
4966
4428
|
preset: e,
|
|
4967
4429
|
radius: { ...t.radius },
|
|
4968
|
-
components:
|
|
4430
|
+
components: Wn(t.radius, t.components),
|
|
4969
4431
|
sizes: { ...t.sizes },
|
|
4970
4432
|
font: { ...t.font },
|
|
4971
4433
|
borders: { ...t.borders },
|
|
4972
4434
|
shadows: { ...t.shadows }
|
|
4973
4435
|
};
|
|
4974
4436
|
}
|
|
4975
|
-
function
|
|
4976
|
-
for (let t of Object.values(e)) t && typeof t == "object" &&
|
|
4437
|
+
function qn(e) {
|
|
4438
|
+
for (let t of Object.values(e)) t && typeof t == "object" && qn(t);
|
|
4977
4439
|
return Object.freeze(e);
|
|
4978
4440
|
}
|
|
4979
|
-
var
|
|
4980
|
-
function
|
|
4441
|
+
var Jn = (e) => e === "studio" || e === "terminal" || e === "capsule", B = (e, t, n) => typeof e == "number" && Number.isFinite(e) && e >= t && e <= n, Yn = (e) => typeof e == "string" && e.trim().length > 0 && e.length <= 300 && !/[;{}<>\\]|url\s*\(|expression\s*\(|\/\*/i.test(e) && Xn(e);
|
|
4442
|
+
function Xn(e) {
|
|
4981
4443
|
let t = 0, n = "";
|
|
4982
4444
|
for (let r of e) if (n) r === n && (n = "");
|
|
4983
4445
|
else if (r === "\"" || r === "'") n = r;
|
|
@@ -4985,7 +4447,7 @@ function $n(e) {
|
|
|
4985
4447
|
else if (r === ")" && --t < 0) return !1;
|
|
4986
4448
|
return t === 0 && !n;
|
|
4987
4449
|
}
|
|
4988
|
-
var
|
|
4450
|
+
var Zn = (e, t) => typeof e == "string" && t.includes(e);
|
|
4989
4451
|
function V(e, t, n) {
|
|
4990
4452
|
let r = { ...e };
|
|
4991
4453
|
if (!t || typeof t != "object") return r;
|
|
@@ -4996,28 +4458,28 @@ function V(e, t, n) {
|
|
|
4996
4458
|
return r;
|
|
4997
4459
|
}
|
|
4998
4460
|
function H(e) {
|
|
4999
|
-
let t = typeof e == "string" ? { preset: e } : e ?? {}, n =
|
|
4461
|
+
let t = typeof e == "string" ? { preset: e } : e ?? {}, n = Jn(t.preset) ? t.preset : "studio", r = Hn[n], i = V(r.radius, t.radius, (e, t) => B(t, 0, 999)), a = V(t.density === "compact" || t.density === "spacious" ? Un[t.density] : r.sizes, t.sizes, (e, t) => e === "icon" ? B(t, 10, 32) : B(t, 16, 80)), o = V(r.font, t.font, (e, t) => e === "family" || e === "mono" ? Yn(t) : e === "size" ? B(t, 11, 20) : e === "weight" || e === "strongWeight" ? B(t, 100, 900) : e === "labelCase" ? t === "none" || t === "uppercase" : B(t, 0, .5));
|
|
5000
4462
|
return {
|
|
5001
4463
|
preset: n,
|
|
5002
4464
|
radius: i,
|
|
5003
|
-
components: V(
|
|
4465
|
+
components: V(Wn(i, r.components), t.components, (e, t) => B(t, 0, 999)),
|
|
5004
4466
|
sizes: a,
|
|
5005
4467
|
font: o,
|
|
5006
4468
|
borders: V(r.borders, t.borders, (e, t) => e === "width" ? B(t, 0, 4) : typeof t == "boolean"),
|
|
5007
|
-
shadows: V(r.shadows, t.shadows, (e, t) =>
|
|
4469
|
+
shadows: V(r.shadows, t.shadows, (e, t) => Yn(t)),
|
|
5008
4470
|
blur: B(t.blur, 0, 40) ? t.blur : r.blur,
|
|
5009
|
-
active:
|
|
4471
|
+
active: Zn(t.active, [
|
|
5010
4472
|
"tint",
|
|
5011
4473
|
"solid",
|
|
5012
4474
|
"underline"
|
|
5013
4475
|
]) ? t.active : r.active,
|
|
5014
|
-
toolbar:
|
|
5015
|
-
sidebar:
|
|
5016
|
-
intervals:
|
|
4476
|
+
toolbar: Zn(t.toolbar, ["docked", "floating"]) ? t.toolbar : r.toolbar,
|
|
4477
|
+
sidebar: Zn(t.sidebar, ["docked", "floating"]) ? t.sidebar : r.sidebar,
|
|
4478
|
+
intervals: Zn(t.intervals, ["plain", "segmented"]) ? t.intervals : r.intervals,
|
|
5017
4479
|
tagRadius: B(t.tagRadius, 0, 999) ? t.tagRadius : r.tagRadius
|
|
5018
4480
|
};
|
|
5019
4481
|
}
|
|
5020
|
-
function
|
|
4482
|
+
function Qn(e) {
|
|
5021
4483
|
let t = (e) => `${e}px`, n = e.radius, r = e.components, i = e.sizes, a = e.font;
|
|
5022
4484
|
return {
|
|
5023
4485
|
"--tcw-radius-xs": t(n.xs),
|
|
@@ -5062,12 +4524,12 @@ function tr(e) {
|
|
|
5062
4524
|
}
|
|
5063
4525
|
function U(e, t, n = {}) {
|
|
5064
4526
|
let r = n.variables !== !1;
|
|
5065
|
-
for (let [n, i] of Object.entries(
|
|
4527
|
+
for (let [n, i] of Object.entries(Qn(t))) r ? e.style.setProperty(n, i) : e.style.removeProperty(n);
|
|
5066
4528
|
e.dataset.tcwUi = t.preset, e.dataset.tcwActive = t.active, e.dataset.tcwToolbar = t.toolbar, e.dataset.tcwSidebar = t.sidebar, e.dataset.tcwIntervals = t.intervals, e.dataset.tcwSeparators = t.borders.separators ? "on" : "off";
|
|
5067
4529
|
}
|
|
5068
4530
|
//#endregion
|
|
5069
4531
|
//#region src/widget/WidgetObjectTree.ts
|
|
5070
|
-
var
|
|
4532
|
+
var $n = class {
|
|
5071
4533
|
el;
|
|
5072
4534
|
indicatorsEl;
|
|
5073
4535
|
drawingsEl;
|
|
@@ -5219,7 +4681,7 @@ var nr = class {
|
|
|
5219
4681
|
let i = document.createElement("button");
|
|
5220
4682
|
return i.type = "button", i.className = `tcw-tree-btn ${n}`.trim(), i.setAttribute("aria-label", t), i.title = t, i.innerHTML = j(e, 14), i.addEventListener("click", r), i;
|
|
5221
4683
|
}
|
|
5222
|
-
},
|
|
4684
|
+
}, er = {
|
|
5223
4685
|
trendLine: "Trend Line",
|
|
5224
4686
|
ray: "Ray",
|
|
5225
4687
|
extendedLine: "Extended Line",
|
|
@@ -5262,33 +4724,33 @@ var nr = class {
|
|
|
5262
4724
|
volumeProfileRange: "Volume Profile",
|
|
5263
4725
|
riskReward: "Long/Short Position"
|
|
5264
4726
|
};
|
|
5265
|
-
function
|
|
4727
|
+
function tr(e, t) {
|
|
5266
4728
|
let n = `tool.${e}`, r = t?.(n);
|
|
5267
|
-
return r && r !== n ? r :
|
|
4729
|
+
return r && r !== n ? r : er[e] ?? e;
|
|
5268
4730
|
}
|
|
5269
4731
|
//#endregion
|
|
5270
4732
|
//#region src/widget/focusTrap.ts
|
|
5271
|
-
var
|
|
4733
|
+
var nr = "button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])";
|
|
5272
4734
|
function W(e, t) {
|
|
5273
4735
|
if (e.key !== "Tab") return;
|
|
5274
|
-
let n = [...t.querySelectorAll(
|
|
4736
|
+
let n = [...t.querySelectorAll(nr)].filter((e) => e.getClientRects().length > 0 || e === document.activeElement);
|
|
5275
4737
|
if (n.length === 0) return;
|
|
5276
4738
|
let r = n[0], i = n[n.length - 1], a = document.activeElement;
|
|
5277
4739
|
e.shiftKey && (a === r || !t.contains(a)) ? (e.preventDefault(), i.focus()) : !e.shiftKey && (a === i || !t.contains(a)) && (e.preventDefault(), r.focus());
|
|
5278
4740
|
}
|
|
5279
4741
|
//#endregion
|
|
5280
4742
|
//#region src/widget/WidgetIndicatorSettings.ts
|
|
5281
|
-
var
|
|
4743
|
+
var rr = 1, ir = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/, ar = [
|
|
5282
4744
|
1,
|
|
5283
4745
|
1.5,
|
|
5284
4746
|
2,
|
|
5285
4747
|
3,
|
|
5286
4748
|
4
|
|
5287
4749
|
];
|
|
5288
|
-
function
|
|
4750
|
+
function or(e) {
|
|
5289
4751
|
return e.replace(/_/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (e) => e.toUpperCase());
|
|
5290
4752
|
}
|
|
5291
|
-
var
|
|
4753
|
+
var sr = class {
|
|
5292
4754
|
backdrop;
|
|
5293
4755
|
modal;
|
|
5294
4756
|
bodyEl;
|
|
@@ -5303,7 +4765,7 @@ var ur = class {
|
|
|
5303
4765
|
tab = "inputs";
|
|
5304
4766
|
tabButtons = [];
|
|
5305
4767
|
returnFocus = null;
|
|
5306
|
-
uid =
|
|
4768
|
+
uid = rr++;
|
|
5307
4769
|
t;
|
|
5308
4770
|
constructor(e, t, n) {
|
|
5309
4771
|
this.callbacks = t, this.t = n ?? ((e) => l[e]), this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.hidden = !0, this.backdrop.addEventListener("click", (e) => {
|
|
@@ -5389,14 +4851,14 @@ var ur = class {
|
|
|
5389
4851
|
}
|
|
5390
4852
|
fieldRow(e) {
|
|
5391
4853
|
let t = this.target?.inputs?.[e], n = this.currentValue(e), r = typeof (this.target?.defaults[e] ?? n), i;
|
|
5392
|
-
return i = t?.source ? this.sourceControl(e, String(n ?? "close")) : t?.options ? this.choiceControl(e, t.options, n) : r === "boolean" ? this.toggleControl(e, !!n) : r === "number" ? this.numberControl(e, Number(n), t) : typeof n == "string" &&
|
|
4854
|
+
return i = t?.source ? this.sourceControl(e, String(n ?? "close")) : t?.options ? this.choiceControl(e, t.options, n) : r === "boolean" ? this.toggleControl(e, !!n) : r === "number" ? this.numberControl(e, Number(n), t) : typeof n == "string" && ir.test(n) ? this.colorInput(n, (t) => this.setValue(e, t)) : this.textControl(e, String(n ?? "")), this.row(t?.label ?? or(e), i);
|
|
5393
4855
|
}
|
|
5394
4856
|
sourceControl(e, t) {
|
|
5395
4857
|
let n = document.createElement("select");
|
|
5396
4858
|
n.className = "tcw-indi-input tcw-indi-select";
|
|
5397
4859
|
let r = document.createElement("optgroup");
|
|
5398
4860
|
r.label = this.t("indicatorSettings.source.prices");
|
|
5399
|
-
for (let e of
|
|
4861
|
+
for (let e of ne) r.appendChild(this.option(e, e));
|
|
5400
4862
|
n.appendChild(r);
|
|
5401
4863
|
let i = this.target?.lineSources ?? [];
|
|
5402
4864
|
if (i.length) {
|
|
@@ -5453,7 +4915,7 @@ var ur = class {
|
|
|
5453
4915
|
}
|
|
5454
4916
|
let i = document.createElement("select");
|
|
5455
4917
|
i.className = "tcw-indi-input tcw-indi-select";
|
|
5456
|
-
for (let e of
|
|
4918
|
+
for (let e of ar) i.appendChild(this.option(String(e), `${e} px`));
|
|
5457
4919
|
if (i.value = String(t.lineWidth ?? 1.5), i.addEventListener("change", () => this.callbacks.onStyle?.(t.instanceId, { lineWidths: [Number(i.value)] })), e.appendChild(this.row(this.t("indicatorSettings.lineWidth"), i)), t.scale && this.callbacks.onScale) {
|
|
5458
4920
|
let n = document.createElement("select");
|
|
5459
4921
|
n.className = "tcw-indi-input tcw-indi-select", n.appendChild(this.option("right", this.t("indicatorSettings.scale.right"))), n.appendChild(this.option("left", this.t("indicatorSettings.scale.left"))), n.value = t.scale, n.addEventListener("change", () => {
|
|
@@ -5524,10 +4986,10 @@ var ur = class {
|
|
|
5524
4986
|
}
|
|
5525
4987
|
colorInput(e, t) {
|
|
5526
4988
|
let n = document.createElement("input");
|
|
5527
|
-
return n.type = "color", n.className = "tcw-indi-color", n.value =
|
|
4989
|
+
return n.type = "color", n.className = "tcw-indi-color", n.value = cr(e), n.addEventListener("input", () => t(n.value)), n;
|
|
5528
4990
|
}
|
|
5529
4991
|
};
|
|
5530
|
-
function
|
|
4992
|
+
function cr(e) {
|
|
5531
4993
|
let t = e.trim();
|
|
5532
4994
|
if (/^#[0-9a-f]{6}$/i.test(t)) return t.toLowerCase();
|
|
5533
4995
|
if (/^#[0-9a-f]{3}$/i.test(t)) return `#${t[1]}${t[1]}${t[2]}${t[2]}${t[3]}${t[3]}`.toLowerCase();
|
|
@@ -5540,43 +5002,43 @@ function dr(e) {
|
|
|
5540
5002
|
}
|
|
5541
5003
|
//#endregion
|
|
5542
5004
|
//#region src/widget/DrawingTemplateStore.ts
|
|
5543
|
-
function
|
|
5005
|
+
function lr() {
|
|
5544
5006
|
try {
|
|
5545
5007
|
return typeof localStorage < "u" ? localStorage : null;
|
|
5546
5008
|
} catch {
|
|
5547
5009
|
return null;
|
|
5548
5010
|
}
|
|
5549
5011
|
}
|
|
5550
|
-
var
|
|
5551
|
-
function
|
|
5552
|
-
let { text: t, ...n } =
|
|
5012
|
+
var ur = 80;
|
|
5013
|
+
function dr(e) {
|
|
5014
|
+
let { text: t, ...n } = ge(e);
|
|
5553
5015
|
return n;
|
|
5554
5016
|
}
|
|
5555
|
-
function
|
|
5017
|
+
function fr(e) {
|
|
5556
5018
|
let t = {
|
|
5557
5019
|
name: e.name,
|
|
5558
5020
|
style: { ...e.style }
|
|
5559
5021
|
};
|
|
5560
5022
|
return e.type && (t.type = e.type), e.options && (t.options = structuredClone(e.options)), t;
|
|
5561
5023
|
}
|
|
5562
|
-
var
|
|
5024
|
+
var pr = class {
|
|
5563
5025
|
templates = [];
|
|
5564
|
-
constructor(e = "tcw:draw-templates", t =
|
|
5026
|
+
constructor(e = "tcw:draw-templates", t = lr()) {
|
|
5565
5027
|
this.storageKey = e, this.storage = t, this.load();
|
|
5566
5028
|
}
|
|
5567
5029
|
list(e) {
|
|
5568
|
-
return this.templates.filter((t) => !t.type || t.type === e).map(
|
|
5030
|
+
return this.templates.filter((t) => !t.type || t.type === e).map(fr);
|
|
5569
5031
|
}
|
|
5570
5032
|
get(e, t) {
|
|
5571
5033
|
let n = this.templates.find((n) => n.name === e && n.type === t);
|
|
5572
|
-
return n ?
|
|
5034
|
+
return n ? fr(n) : null;
|
|
5573
5035
|
}
|
|
5574
5036
|
save(e, t, n) {
|
|
5575
|
-
let r = e.trim().slice(0,
|
|
5037
|
+
let r = e.trim().slice(0, ur);
|
|
5576
5038
|
if (!r) return;
|
|
5577
5039
|
let i = {
|
|
5578
5040
|
name: r,
|
|
5579
|
-
style:
|
|
5041
|
+
style: dr(t)
|
|
5580
5042
|
};
|
|
5581
5043
|
n && (i.type = n.type, i.options = structuredClone(n.options)), this.templates = this.templates.filter((e) => !(e.name === r && e.type === i.type)), this.templates.push(i), this.persist();
|
|
5582
5044
|
}
|
|
@@ -5594,8 +5056,8 @@ var gr = class {
|
|
|
5594
5056
|
if (!Array.isArray(t)) return;
|
|
5595
5057
|
this.templates = t.filter((e) => e && typeof e.name == "string" && e.name.trim() !== "").map((e) => {
|
|
5596
5058
|
let t = {
|
|
5597
|
-
name: e.name.trim().slice(0,
|
|
5598
|
-
style:
|
|
5059
|
+
name: e.name.trim().slice(0, ur),
|
|
5060
|
+
style: dr(e.style)
|
|
5599
5061
|
};
|
|
5600
5062
|
return typeof e.type == "string" && (t.type = e.type), e.options && typeof e.options == "object" && !Array.isArray(e.options) && (t.options = e.options), t;
|
|
5601
5063
|
});
|
|
@@ -5606,9 +5068,9 @@ var gr = class {
|
|
|
5606
5068
|
this.storage.setItem(this.storageKey, JSON.stringify(this.templates));
|
|
5607
5069
|
} catch {}
|
|
5608
5070
|
}
|
|
5609
|
-
},
|
|
5071
|
+
}, mr = class {
|
|
5610
5072
|
defaults = {};
|
|
5611
|
-
constructor(e = "tcw:drawing-defaults", t =
|
|
5073
|
+
constructor(e = "tcw:drawing-defaults", t = lr()) {
|
|
5612
5074
|
this.storageKey = e, this.storage = t;
|
|
5613
5075
|
try {
|
|
5614
5076
|
let e = this.storage?.getItem(this.storageKey), t = e ? JSON.parse(e) : null;
|
|
@@ -5624,7 +5086,7 @@ var gr = class {
|
|
|
5624
5086
|
this.storage?.setItem(this.storageKey, JSON.stringify(this.defaults));
|
|
5625
5087
|
} catch {}
|
|
5626
5088
|
}
|
|
5627
|
-
},
|
|
5089
|
+
}, hr = [
|
|
5628
5090
|
"#4c8dff",
|
|
5629
5091
|
"#1fa874",
|
|
5630
5092
|
"#e8505b",
|
|
@@ -5633,16 +5095,16 @@ var gr = class {
|
|
|
5633
5095
|
"#1398a8",
|
|
5634
5096
|
"#ffffff",
|
|
5635
5097
|
"#7d8696"
|
|
5636
|
-
],
|
|
5098
|
+
], gr = [
|
|
5637
5099
|
1,
|
|
5638
5100
|
2,
|
|
5639
5101
|
3,
|
|
5640
5102
|
4
|
|
5641
|
-
],
|
|
5103
|
+
], _r = [
|
|
5642
5104
|
"solid",
|
|
5643
5105
|
"dashed",
|
|
5644
5106
|
"dotted"
|
|
5645
|
-
],
|
|
5107
|
+
], vr = class {
|
|
5646
5108
|
el;
|
|
5647
5109
|
templatesEl;
|
|
5648
5110
|
nameInput;
|
|
@@ -5682,7 +5144,7 @@ var gr = class {
|
|
|
5682
5144
|
colorRow() {
|
|
5683
5145
|
let e = document.createElement("div");
|
|
5684
5146
|
e.className = "tcw-style-row tcw-style-colors";
|
|
5685
|
-
for (let t of
|
|
5147
|
+
for (let t of hr) {
|
|
5686
5148
|
let n = document.createElement("button");
|
|
5687
5149
|
n.type = "button", n.className = "tcw-style-swatch", n.style.background = t, n.dataset.color = t, n.setAttribute("aria-label", t), n.addEventListener("click", () => this.applyStyle({ color: t })), e.appendChild(n);
|
|
5688
5150
|
}
|
|
@@ -5692,7 +5154,7 @@ var gr = class {
|
|
|
5692
5154
|
widthRow() {
|
|
5693
5155
|
let e = document.createElement("div");
|
|
5694
5156
|
e.className = "tcw-style-row tcw-style-widths";
|
|
5695
|
-
for (let t of
|
|
5157
|
+
for (let t of gr) {
|
|
5696
5158
|
let n = document.createElement("button");
|
|
5697
5159
|
n.type = "button", n.className = "tcw-style-width", n.dataset.width = String(t);
|
|
5698
5160
|
let r = document.createElement("span");
|
|
@@ -5703,7 +5165,7 @@ var gr = class {
|
|
|
5703
5165
|
lineStyleRow() {
|
|
5704
5166
|
let e = document.createElement("div");
|
|
5705
5167
|
e.className = "tcw-style-row tcw-style-dashes";
|
|
5706
|
-
for (let t of
|
|
5168
|
+
for (let t of _r) {
|
|
5707
5169
|
let n = document.createElement("button");
|
|
5708
5170
|
n.type = "button", n.className = "tcw-style-dash", n.dataset.linestyle = t, n.textContent = t === "solid" ? "──" : t === "dashed" ? "╌╌" : "┄┄", n.title = t, n.addEventListener("click", () => this.applyStyle({ lineStyle: t })), e.appendChild(n);
|
|
5709
5171
|
}
|
|
@@ -5751,18 +5213,18 @@ var gr = class {
|
|
|
5751
5213
|
}), e.appendChild(n), e.appendChild(a), this.templatesEl.appendChild(e);
|
|
5752
5214
|
}
|
|
5753
5215
|
}
|
|
5754
|
-
},
|
|
5755
|
-
function
|
|
5756
|
-
return typeof e == "string" &&
|
|
5216
|
+
}, yr = 10, G = 4, br = 4, xr = 20, Sr = /^(#[0-9a-f]{3,8}|(rgb|hsl)a?\([\d\s.,%/+-]+\)|[a-z]+)$/i;
|
|
5217
|
+
function Cr(e) {
|
|
5218
|
+
return typeof e == "string" && Sr.test(e.trim()) ? e.trim() : "#7d8696";
|
|
5757
5219
|
}
|
|
5758
|
-
function
|
|
5220
|
+
function wr(e) {
|
|
5759
5221
|
let t = Number(e);
|
|
5760
|
-
return Number.isFinite(t) && t > 0 ? Math.min(t,
|
|
5222
|
+
return Number.isFinite(t) && t > 0 ? Math.min(t, xr) : 1;
|
|
5761
5223
|
}
|
|
5762
|
-
function
|
|
5763
|
-
return
|
|
5224
|
+
function Tr(e) {
|
|
5225
|
+
return _r.includes(e) ? e : "solid";
|
|
5764
5226
|
}
|
|
5765
|
-
var
|
|
5227
|
+
var Er = class {
|
|
5766
5228
|
el;
|
|
5767
5229
|
pop;
|
|
5768
5230
|
target = null;
|
|
@@ -5783,9 +5245,9 @@ var kr = class {
|
|
|
5783
5245
|
show(e) {
|
|
5784
5246
|
this.target = e;
|
|
5785
5247
|
let t = e.style, n = [
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5248
|
+
Cr(t.color),
|
|
5249
|
+
wr(t.lineWidth),
|
|
5250
|
+
Tr(t.lineStyle),
|
|
5789
5251
|
e.locked,
|
|
5790
5252
|
e.canDelete,
|
|
5791
5253
|
e.canSettings,
|
|
@@ -5803,11 +5265,11 @@ var kr = class {
|
|
|
5803
5265
|
document.removeEventListener("pointerdown", this.onDocDown, !0), this.el.remove(), this.pop.remove();
|
|
5804
5266
|
}
|
|
5805
5267
|
render(e) {
|
|
5806
|
-
let t = this.t, n =
|
|
5268
|
+
let t = this.t, n = Cr(e.style.color), r = wr(e.style.lineWidth), i = Tr(e.style.lineStyle), a = e.locked, o = this.el.contains(document.activeElement) ? document.activeElement.dataset.action : void 0, s = (e, t, n, r = "") => `<button type="button" class="tcw-sel-btn${r}" data-action="${e}" aria-label="${N(t)}" title="${N(t)}">${n}</button>`, c = (e, t, n) => s(e, t, n, " tcw-sel-has-pop").replace("<button ", "<button aria-haspopup=\"dialog\" aria-expanded=\"false\" ");
|
|
5807
5269
|
this.el.innerHTML = [
|
|
5808
5270
|
c("color", t("drawingSettings.color"), `<span class="tcw-sel-color" style="background:${N(n)}"></span>`),
|
|
5809
5271
|
c("width", t("drawingSettings.lineWidth"), `<span class="tcw-sel-width" style="--w:${r}px"></span><span class="tcw-sel-num">${r}px</span>`),
|
|
5810
|
-
c("lineStyle", t("drawingSettings.lineStyle"),
|
|
5272
|
+
c("lineStyle", t("drawingSettings.lineStyle"), Dr(i)),
|
|
5811
5273
|
"<span class=\"tcw-sel-sep\" aria-hidden=\"true\"></span>",
|
|
5812
5274
|
e.canSettings ? s("settings", t("legend.settings"), j("settings", 15)) : "",
|
|
5813
5275
|
e.canAlert ? s("alert", t("drawingSettings.addAlert"), j("bell", 15)) : "",
|
|
@@ -5828,8 +5290,8 @@ var kr = class {
|
|
|
5828
5290
|
place(e) {
|
|
5829
5291
|
let { rect: t, bounds: n } = e, { w: r, h: i } = this.size, a = t.x + t.width / 2 - r / 2;
|
|
5830
5292
|
a = Math.max(n.x + G, Math.min(a, n.x + n.width - r - G));
|
|
5831
|
-
let o = t.y - i -
|
|
5832
|
-
o < n.y + G && (o = Math.min(t.y + t.height +
|
|
5293
|
+
let o = t.y - i - yr;
|
|
5294
|
+
o < n.y + G && (o = Math.min(t.y + t.height + yr, n.y + n.height - i - G)), o = Math.max(o, n.y + G), this.el.style.left = `${Math.round(a)}px`, this.el.style.top = `${Math.round(o)}px`;
|
|
5833
5295
|
}
|
|
5834
5296
|
onClick(e) {
|
|
5835
5297
|
let t = e.target.closest("[data-action]");
|
|
@@ -5860,8 +5322,8 @@ var kr = class {
|
|
|
5860
5322
|
r < 0 || (e.preventDefault(), this.rove(t[r], !0));
|
|
5861
5323
|
}
|
|
5862
5324
|
openPopover(e, t) {
|
|
5863
|
-
let n = this.target.style, r =
|
|
5864
|
-
this.openPop = e, e === "color" ? this.pop.innerHTML =
|
|
5325
|
+
let n = this.target.style, r = Cr(n.color).toLowerCase(), i = wr(n.lineWidth), a = Tr(n.lineStyle), o = (e, t, n, r = "") => `<button type="button" class="${e}${t ? " tcw-sel-on" : ""}" aria-pressed="${t}" ${n}>${r}</button>`;
|
|
5326
|
+
this.openPop = e, e === "color" ? this.pop.innerHTML = hr.map((e) => o("tcw-sel-swatch", e.toLowerCase() === r, `data-color="${e}" style="background:${e}" aria-label="${e}"`)).join("") : e === "width" ? this.pop.innerHTML = gr.map((e) => o("tcw-sel-option", e === i, `data-width="${e}"`, `<span class="tcw-sel-width" style="--w:${e}px"></span>${e}px`)).join("") : this.pop.innerHTML = _r.map((e) => o("tcw-sel-option", e === a, `data-style="${e}"`, Dr(e) + N(this.t(`drawingSettings.lineStyle.${e}`)))).join(""), this.pop.className = `tcw-sel-pop tcw-sel-pop--${e}`, this.pop.setAttribute("aria-label", t.getAttribute("aria-label") ?? ""), this.pop.hidden = !1;
|
|
5865
5327
|
for (let e of this.el.querySelectorAll("[aria-expanded=\"true\"]")) e.setAttribute("aria-expanded", "false");
|
|
5866
5328
|
t.setAttribute("aria-expanded", "true"), this.placePop(), this.pop.querySelector(".tcw-sel-on, button")?.focus();
|
|
5867
5329
|
}
|
|
@@ -5872,7 +5334,7 @@ var kr = class {
|
|
|
5872
5334
|
}
|
|
5873
5335
|
let t = [...this.pop.querySelectorAll("button")], n = t.indexOf(document.activeElement);
|
|
5874
5336
|
if (n < 0) return;
|
|
5875
|
-
let r = this.openPop === "color" ?
|
|
5337
|
+
let r = this.openPop === "color" ? br : 1, i = e.key === "ArrowRight" ? 1 : e.key === "ArrowLeft" ? -1 : e.key === "ArrowDown" ? r : e.key === "ArrowUp" ? -r : 0;
|
|
5876
5338
|
i && (e.preventDefault(), t[(n + i + t.length) % t.length].focus());
|
|
5877
5339
|
}
|
|
5878
5340
|
placePop() {
|
|
@@ -5881,7 +5343,7 @@ var kr = class {
|
|
|
5881
5343
|
}
|
|
5882
5344
|
onPick(e) {
|
|
5883
5345
|
let t = e.target.closest("button");
|
|
5884
|
-
t && (t.dataset.color ? this.callbacks.onStyle({ color: t.dataset.color }) : t.dataset.width ? this.callbacks.onStyle({ lineWidth: Number(t.dataset.width) }) : t.dataset.style && this.callbacks.onStyle({ lineStyle:
|
|
5346
|
+
t && (t.dataset.color ? this.callbacks.onStyle({ color: t.dataset.color }) : t.dataset.width ? this.callbacks.onStyle({ lineWidth: Number(t.dataset.width) }) : t.dataset.style && this.callbacks.onStyle({ lineStyle: Tr(t.dataset.style) }), this.closePop(!0));
|
|
5885
5347
|
}
|
|
5886
5348
|
closePop(e = !1) {
|
|
5887
5349
|
if (!this.openPop) return;
|
|
@@ -5889,21 +5351,21 @@ var kr = class {
|
|
|
5889
5351
|
t?.setAttribute("aria-expanded", "false"), this.openPop = null, this.pop.hidden = !0, e && t?.focus();
|
|
5890
5352
|
}
|
|
5891
5353
|
};
|
|
5892
|
-
function
|
|
5354
|
+
function Dr(e) {
|
|
5893
5355
|
return `<svg class="tcw-sel-line" width="22" height="10" viewBox="0 0 22 10" aria-hidden="true"><line x1="1" y1="5" x2="21" y2="5" stroke="currentColor" stroke-width="2"${e === "dashed" ? " stroke-dasharray=\"4 3\"" : e === "dotted" ? " stroke-dasharray=\"1 3\" stroke-linecap=\"round\"" : ""}/></svg>`;
|
|
5894
5356
|
}
|
|
5895
5357
|
//#endregion
|
|
5896
5358
|
//#region src/widget/WidgetDrawingSettings.ts
|
|
5897
|
-
var
|
|
5359
|
+
var Or = 12, kr = [
|
|
5898
5360
|
1,
|
|
5899
5361
|
2,
|
|
5900
5362
|
3,
|
|
5901
5363
|
4
|
|
5902
|
-
],
|
|
5364
|
+
], Ar = [
|
|
5903
5365
|
"solid",
|
|
5904
5366
|
"dashed",
|
|
5905
5367
|
"dotted"
|
|
5906
|
-
],
|
|
5368
|
+
], jr = [
|
|
5907
5369
|
10,
|
|
5908
5370
|
11,
|
|
5909
5371
|
12,
|
|
@@ -5914,7 +5376,7 @@ var jr = 12, Mr = [
|
|
|
5914
5376
|
24,
|
|
5915
5377
|
28,
|
|
5916
5378
|
32
|
|
5917
|
-
],
|
|
5379
|
+
], Mr = 48, Nr = 1, Pr = class {
|
|
5918
5380
|
backdrop;
|
|
5919
5381
|
modal;
|
|
5920
5382
|
titleEl;
|
|
@@ -5928,7 +5390,7 @@ var jr = 12, Mr = [
|
|
|
5928
5390
|
anchors = [];
|
|
5929
5391
|
tab = "style";
|
|
5930
5392
|
returnFocus = null;
|
|
5931
|
-
uid =
|
|
5393
|
+
uid = Nr++;
|
|
5932
5394
|
constructor(e, t, n = h) {
|
|
5933
5395
|
this.callbacks = t, this.t = n, this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.hidden = !0;
|
|
5934
5396
|
let r = !1;
|
|
@@ -5974,7 +5436,7 @@ var jr = 12, Mr = [
|
|
|
5974
5436
|
}
|
|
5975
5437
|
tabs() {
|
|
5976
5438
|
let e = ["style"];
|
|
5977
|
-
return this.target && Object.keys(this.target.defs).length > 0 && e.push("options"), this.target && this.target.anchors.length <=
|
|
5439
|
+
return this.target && Object.keys(this.target.defs).length > 0 && e.push("options"), this.target && this.target.anchors.length <= Or && e.push("coordinates"), e;
|
|
5978
5440
|
}
|
|
5979
5441
|
renderTabs() {
|
|
5980
5442
|
this.tabButtons = this.tabs().map((e) => {
|
|
@@ -6028,22 +5490,22 @@ var jr = 12, Mr = [
|
|
|
6028
5490
|
}
|
|
6029
5491
|
renderStyle(e) {
|
|
6030
5492
|
let t = this.target;
|
|
6031
|
-
e.appendChild(P(this.t("drawingSettings.color"),
|
|
5493
|
+
e.appendChild(P(this.t("drawingSettings.color"), zt(this.style.color, (e) => this.setStyle({ color: e })))), e.appendChild(P(this.t("drawingSettings.lineWidth"), F(kr.map((e) => ({
|
|
6032
5494
|
value: String(e),
|
|
6033
5495
|
label: `${e} px`
|
|
6034
|
-
})), String(this.style.lineWidth), (e) => this.setStyle({ lineWidth: Number(e) })))), e.appendChild(P(this.t("drawingSettings.lineStyle"), F(
|
|
5496
|
+
})), String(this.style.lineWidth), (e) => this.setStyle({ lineWidth: Number(e) })))), e.appendChild(P(this.t("drawingSettings.lineStyle"), F(Ar.map((e) => ({
|
|
6035
5497
|
value: e,
|
|
6036
5498
|
label: this.t(`drawingSettings.lineStyle.${e}`)
|
|
6037
5499
|
})), this.style.lineStyle, (e) => this.setStyle({ lineStyle: e })))), t.fill && this.renderFill(e), t.text && this.renderText(e), this.callbacks.templates && this.renderTemplates(e);
|
|
6038
5500
|
}
|
|
6039
5501
|
renderFill(e) {
|
|
6040
|
-
let t = this.style.fillColor ??
|
|
6041
|
-
fillColor:
|
|
5502
|
+
let t = this.style.fillColor ?? Ht(this.style.color, .1), n = I(t), r = Vt(t), i = () => this.setStyle({
|
|
5503
|
+
fillColor: Ht(n, r),
|
|
6042
5504
|
fillOpacity: r
|
|
6043
5505
|
});
|
|
6044
|
-
e.appendChild(P(this.t("drawingSettings.fill"),
|
|
5506
|
+
e.appendChild(P(this.t("drawingSettings.fill"), zt(n, (e) => {
|
|
6045
5507
|
n = e, i();
|
|
6046
|
-
}))), e.appendChild(P(this.t("drawingSettings.opacity"),
|
|
5508
|
+
}))), e.appendChild(P(this.t("drawingSettings.opacity"), Rt(Math.round(r * 100), {
|
|
6047
5509
|
min: 0,
|
|
6048
5510
|
max: 100,
|
|
6049
5511
|
step: 5
|
|
@@ -6053,7 +5515,7 @@ var jr = 12, Mr = [
|
|
|
6053
5515
|
}
|
|
6054
5516
|
renderText(e) {
|
|
6055
5517
|
let t = document.createElement("textarea");
|
|
6056
|
-
t.className = "tcw-indi-input tcw-drawing-text", t.rows = 3, t.value = this.style.text ?? "", t.addEventListener("input", () => this.setStyle({ text: t.value })), e.appendChild(P(this.t("drawingSettings.text"), t)), e.appendChild(P(this.t("drawingSettings.fontSize"), F(
|
|
5518
|
+
t.className = "tcw-indi-input tcw-drawing-text", t.rows = 3, t.value = this.style.text ?? "", t.addEventListener("input", () => this.setStyle({ text: t.value })), e.appendChild(P(this.t("drawingSettings.text"), t)), e.appendChild(P(this.t("drawingSettings.fontSize"), F(jr.map((e) => ({
|
|
6057
5519
|
value: String(e),
|
|
6058
5520
|
label: `${e} px`
|
|
6059
5521
|
})), String(this.style.fontSize ?? 12), (e) => this.setStyle({ fontSize: Number(e) }))));
|
|
@@ -6073,7 +5535,7 @@ var jr = 12, Mr = [
|
|
|
6073
5535
|
r.className = "tcw-style-tmpl";
|
|
6074
5536
|
let a = document.createElement("button");
|
|
6075
5537
|
a.type = "button", a.className = "tcw-style-tmpl-apply", a.textContent = e.name, a.addEventListener("click", () => {
|
|
6076
|
-
this.setStyle(e.style), e.options && this.setOptions(
|
|
5538
|
+
this.setStyle(e.style), e.options && this.setOptions(he(n.defs, e.options)), this.renderBody();
|
|
6077
5539
|
});
|
|
6078
5540
|
let o = document.createElement("button");
|
|
6079
5541
|
o.type = "button", o.className = "tcw-style-tmpl-del", o.setAttribute("aria-label", this.t("drawingStyle.deleteTemplate")), o.innerHTML = j("x", 12), o.addEventListener("click", () => {
|
|
@@ -6113,8 +5575,8 @@ var jr = 12, Mr = [
|
|
|
6113
5575
|
optionControl(e, t) {
|
|
6114
5576
|
let n = this.options[e];
|
|
6115
5577
|
switch (t.kind) {
|
|
6116
|
-
case "boolean": return
|
|
6117
|
-
case "number": return
|
|
5578
|
+
case "boolean": return Lt(!!n, (t) => this.setOptions({ [e]: t }));
|
|
5579
|
+
case "number": return Rt(Number(n), {
|
|
6118
5580
|
min: t.min,
|
|
6119
5581
|
max: t.max,
|
|
6120
5582
|
step: t.step
|
|
@@ -6148,12 +5610,12 @@ var jr = 12, Mr = [
|
|
|
6148
5610
|
...e,
|
|
6149
5611
|
visible: r.checked
|
|
6150
5612
|
} : e)));
|
|
6151
|
-
let c =
|
|
5613
|
+
let c = Rt(e.value, { step: .001 }, (e) => a(i().map((n, r) => r === t ? {
|
|
6152
5614
|
...n,
|
|
6153
5615
|
value: e
|
|
6154
5616
|
} : n)));
|
|
6155
5617
|
c.setAttribute("aria-label", this.t("drawingSettings.levelValue") + s);
|
|
6156
|
-
let l =
|
|
5618
|
+
let l = zt(e.color ?? this.style.color, (e) => a(i().map((n, r) => r === t ? {
|
|
6157
5619
|
...n,
|
|
6158
5620
|
color: e
|
|
6159
5621
|
} : n)));
|
|
@@ -6164,7 +5626,7 @@ var jr = 12, Mr = [
|
|
|
6164
5626
|
}), n.append(r, c, l, u), o.appendChild(n);
|
|
6165
5627
|
}), n.appendChild(o);
|
|
6166
5628
|
let s = document.createElement("button");
|
|
6167
|
-
return s.type = "button", s.className = "tcw-reset-link tcw-level-add", s.textContent = this.t("drawingSettings.addLevel"), s.disabled = i().length >=
|
|
5629
|
+
return s.type = "button", s.className = "tcw-reset-link tcw-level-add", s.textContent = this.t("drawingSettings.addLevel"), s.disabled = i().length >= Mr, s.addEventListener("click", () => {
|
|
6168
5630
|
let e = i().at(-1)?.value ?? 0;
|
|
6169
5631
|
a([...i(), {
|
|
6170
5632
|
value: Math.round((e + .5) * 1e3) / 1e3,
|
|
@@ -6188,7 +5650,7 @@ var jr = 12, Mr = [
|
|
|
6188
5650
|
});
|
|
6189
5651
|
}
|
|
6190
5652
|
priceInput(e, t) {
|
|
6191
|
-
let n = this.callbacks.roundPrice ?? ((e) => e), r = this.callbacks.priceStep?.(), i =
|
|
5653
|
+
let n = this.callbacks.roundPrice ?? ((e) => e), r = this.callbacks.priceStep?.(), i = Rt(n(e), { step: r !== void 0 && r > 0 ? r : "any" }, (e) => {
|
|
6192
5654
|
let r = n(e);
|
|
6193
5655
|
i.value = String(r), t(r);
|
|
6194
5656
|
});
|
|
@@ -6200,8 +5662,8 @@ var jr = 12, Mr = [
|
|
|
6200
5662
|
...t
|
|
6201
5663
|
} : n), this.change({ anchors: this.anchors.map((e) => ({ ...e })) });
|
|
6202
5664
|
}
|
|
6203
|
-
},
|
|
6204
|
-
function
|
|
5665
|
+
}, Fr = 4;
|
|
5666
|
+
function Ir(e, t, n) {
|
|
6205
5667
|
let r = e + t > n ? e - t : e;
|
|
6206
5668
|
return Math.max(0, Math.min(r, n - t));
|
|
6207
5669
|
}
|
|
@@ -6220,8 +5682,8 @@ var K = class {
|
|
|
6220
5682
|
}
|
|
6221
5683
|
open(e, t, n, r, i) {
|
|
6222
5684
|
this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null, this.onPick = r, this.anchor = i ?? null, this.anchor?.setAttribute("aria-expanded", "true"), this.el.replaceChildren(...e.map((e) => this.entry(e))), this.el.hidden = !1;
|
|
6223
|
-
let a = this.host.getBoundingClientRect(), o = Math.min(this.host.clientWidth, window.innerWidth - a.left) -
|
|
6224
|
-
this.el.style.left = `${
|
|
5685
|
+
let a = this.host.getBoundingClientRect(), o = Math.min(this.host.clientWidth, window.innerWidth - a.left) - Fr, s = Math.min(this.host.clientHeight, window.innerHeight - a.top) - Fr;
|
|
5686
|
+
this.el.style.left = `${Ir(t, this.el.offsetWidth, o)}px`, this.el.style.top = `${Ir(n, this.el.offsetHeight, s)}px`, document.addEventListener("pointerdown", this.onDocPointer, !0), document.addEventListener("wheel", this.onAway, {
|
|
6225
5687
|
capture: !0,
|
|
6226
5688
|
passive: !0
|
|
6227
5689
|
}), window.addEventListener("resize", this.onAway), window.addEventListener("blur", this.onAway), this.items()[0]?.focus({ preventScroll: !0 });
|
|
@@ -6269,7 +5731,7 @@ var K = class {
|
|
|
6269
5731
|
};
|
|
6270
5732
|
//#endregion
|
|
6271
5733
|
//#region src/widget/drawingMenu.ts
|
|
6272
|
-
function
|
|
5734
|
+
function Lr(e, t) {
|
|
6273
5735
|
let { selected: n } = e, r = n.length === 1, i = new Set(n.map((e) => e.groupId)), a = i.size === 1 && !i.has(null), o = [];
|
|
6274
5736
|
e.canConfigure && r && o.push({
|
|
6275
5737
|
id: "settings",
|
|
@@ -6326,7 +5788,7 @@ function Br(e, t) {
|
|
|
6326
5788
|
}
|
|
6327
5789
|
//#endregion
|
|
6328
5790
|
//#region src/widget/chartMenu.ts
|
|
6329
|
-
function
|
|
5791
|
+
function Rr(e, t) {
|
|
6330
5792
|
if (e.price === void 0 || !Number.isFinite(e.price)) return [];
|
|
6331
5793
|
let n = e.formatPrice(e.price), r = [];
|
|
6332
5794
|
if (e.canAlert && r.push({
|
|
@@ -6363,9 +5825,9 @@ function Vr(e, t) {
|
|
|
6363
5825
|
icon: "minus"
|
|
6364
5826
|
}), r;
|
|
6365
5827
|
}
|
|
6366
|
-
function
|
|
5828
|
+
function zr(e, t, n) {
|
|
6367
5829
|
let r = (e) => {
|
|
6368
|
-
let r =
|
|
5830
|
+
let r = Rr(t, n);
|
|
6369
5831
|
return r.length > 0 ? [
|
|
6370
5832
|
...r,
|
|
6371
5833
|
"separator",
|
|
@@ -6378,7 +5840,7 @@ function Hr(e, t, n) {
|
|
|
6378
5840
|
};
|
|
6379
5841
|
switch (e) {
|
|
6380
5842
|
case "priceAxis": {
|
|
6381
|
-
let e =
|
|
5843
|
+
let e = Rr({
|
|
6382
5844
|
...t,
|
|
6383
5845
|
canTrade: !1,
|
|
6384
5846
|
canDraw: !1
|
|
@@ -6479,24 +5941,24 @@ var q = [
|
|
|
6479
5941
|
"positions",
|
|
6480
5942
|
"orders",
|
|
6481
5943
|
"history"
|
|
6482
|
-
],
|
|
5944
|
+
], Br = [
|
|
6483
5945
|
"order",
|
|
6484
5946
|
"close",
|
|
6485
5947
|
"reverse",
|
|
6486
5948
|
"stopLoss",
|
|
6487
5949
|
"takeProfit"
|
|
6488
|
-
],
|
|
5950
|
+
], Vr = [
|
|
6489
5951
|
"market",
|
|
6490
5952
|
"limit",
|
|
6491
5953
|
"stop"
|
|
6492
|
-
],
|
|
6493
|
-
function
|
|
5954
|
+
], Hr = ["gtc", "day"];
|
|
5955
|
+
function Ur(e, t, n) {
|
|
6494
5956
|
return e.includes(t ?? "") ? t : n;
|
|
6495
5957
|
}
|
|
6496
|
-
function
|
|
5958
|
+
function Wr(e, t) {
|
|
6497
5959
|
return e.length === t.length && e.every((e, n) => e === t[n]);
|
|
6498
5960
|
}
|
|
6499
|
-
function
|
|
5961
|
+
function Gr(e, t) {
|
|
6500
5962
|
if (t === null) return null;
|
|
6501
5963
|
let n = e.quantity - (e.closedQuantity ?? 0), r = e.side === "buy" ? 1 : -1;
|
|
6502
5964
|
return {
|
|
@@ -6504,10 +5966,10 @@ function Jr(e, t) {
|
|
|
6504
5966
|
pct: e.entryPrice === 0 ? 0 : (t - e.entryPrice) / e.entryPrice * 100 * r
|
|
6505
5967
|
};
|
|
6506
5968
|
}
|
|
6507
|
-
function
|
|
5969
|
+
function Kr(e, t = 2) {
|
|
6508
5970
|
return `${e > 0 ? "+" : ""}${e.toFixed(t)}`;
|
|
6509
5971
|
}
|
|
6510
|
-
var
|
|
5972
|
+
var qr = class {
|
|
6511
5973
|
el;
|
|
6512
5974
|
tabButtons = /* @__PURE__ */ new Map();
|
|
6513
5975
|
content;
|
|
@@ -6549,7 +6011,7 @@ var Xr = class {
|
|
|
6549
6011
|
}
|
|
6550
6012
|
update(e) {
|
|
6551
6013
|
let t = this.snapshot;
|
|
6552
|
-
if (this.snapshot = e,
|
|
6014
|
+
if (this.snapshot = e, Wr(t.positions, e.positions) && Wr(t.orders, e.orders) && Wr(t.fills, e.fills) && t.realisedPnl === e.realisedPnl) {
|
|
6553
6015
|
this.open && this.tab === "positions" && t.price !== e.price && this.patchPrices();
|
|
6554
6016
|
return;
|
|
6555
6017
|
}
|
|
@@ -6585,10 +6047,10 @@ var Xr = class {
|
|
|
6585
6047
|
}
|
|
6586
6048
|
patchPrices() {
|
|
6587
6049
|
let { price: e } = this.snapshot;
|
|
6588
|
-
for (let t of this.live) t.price.textContent = e === null ? "—" : this.callbacks.formatPrice(e), this.writePnl(t.pnl,
|
|
6050
|
+
for (let t of this.live) t.price.textContent = e === null ? "—" : this.callbacks.formatPrice(e), this.writePnl(t.pnl, Gr(t.position, e));
|
|
6589
6051
|
}
|
|
6590
6052
|
writePnl(e, t) {
|
|
6591
|
-
e.className = t === null ? "" : t.pnl >= 0 ? "tcw-account-up" : "tcw-account-down", e.textContent = t === null ? "—" : `${
|
|
6053
|
+
e.className = t === null ? "" : t.pnl >= 0 ? "tcw-account-up" : "tcw-account-down", e.textContent = t === null ? "—" : `${Kr(t.pnl)} (${Kr(t.pct)}%)`;
|
|
6592
6054
|
}
|
|
6593
6055
|
table(e, t, n) {
|
|
6594
6056
|
if (t.length === 0) {
|
|
@@ -6633,7 +6095,7 @@ var Xr = class {
|
|
|
6633
6095
|
renderPositions() {
|
|
6634
6096
|
let { formatPrice: e } = this.callbacks, { price: t } = this.snapshot, n = this.snapshot.positions.map((n) => {
|
|
6635
6097
|
let r = n.quantity - (n.closedQuantity ?? 0), i = document.createElement("span");
|
|
6636
|
-
this.writePnl(i,
|
|
6098
|
+
this.writePnl(i, Gr(n, t));
|
|
6637
6099
|
let a = `${this.sideText(n.side, "position")} ${r} @ ${e(n.entryPrice)}`, o = this.row([
|
|
6638
6100
|
this.sideCell(n.side),
|
|
6639
6101
|
String(r),
|
|
@@ -6674,7 +6136,7 @@ var Xr = class {
|
|
|
6674
6136
|
}
|
|
6675
6137
|
renderOrders() {
|
|
6676
6138
|
let { formatPrice: e } = this.callbacks, t = this.snapshot.orders.map((t) => {
|
|
6677
|
-
let n =
|
|
6139
|
+
let n = Ur(Vr, t.type === "stopLimit" ? "stop" : t.type, "limit"), r = `${this.sideText(t.side, "trade")} ${t.quantity} @ ${e(t.price)}`;
|
|
6678
6140
|
return this.row([
|
|
6679
6141
|
this.sideCell(t.side, "trade"),
|
|
6680
6142
|
this.t(`ticket.type.${n}`),
|
|
@@ -6682,7 +6144,7 @@ var Xr = class {
|
|
|
6682
6144
|
e(t.price),
|
|
6683
6145
|
t.stopLoss === void 0 ? "—" : e(t.stopLoss),
|
|
6684
6146
|
t.takeProfit === void 0 ? "—" : e(t.takeProfit),
|
|
6685
|
-
t.timeInForce ? this.t(`ticket.tif.${
|
|
6147
|
+
t.timeInForce ? this.t(`ticket.tif.${Ur(Hr, t.timeInForce, "gtc")}`) : "—",
|
|
6686
6148
|
this.actions({
|
|
6687
6149
|
icon: "x",
|
|
6688
6150
|
label: `${this.t("account.cancelOrder")}: ${r}`,
|
|
@@ -6706,12 +6168,12 @@ var Xr = class {
|
|
|
6706
6168
|
renderHistory() {
|
|
6707
6169
|
let { formatPrice: e, formatTime: t } = this.callbacks, n = [...this.snapshot.fills].reverse().map((n) => {
|
|
6708
6170
|
let r = document.createElement("span");
|
|
6709
|
-
return n.pnl === void 0 ? r.textContent = "—" : (r.className = n.pnl >= 0 ? "tcw-account-up" : "tcw-account-down", r.textContent =
|
|
6171
|
+
return n.pnl === void 0 ? r.textContent = "—" : (r.className = n.pnl >= 0 ? "tcw-account-up" : "tcw-account-down", r.textContent = Kr(n.pnl)), this.row([
|
|
6710
6172
|
t(n.time),
|
|
6711
6173
|
this.sideCell(n.side, "trade"),
|
|
6712
6174
|
String(n.quantity),
|
|
6713
6175
|
e(n.price),
|
|
6714
|
-
this.t(`account.reason.${
|
|
6176
|
+
this.t(`account.reason.${Ur(Br, n.reason, "order")}`),
|
|
6715
6177
|
r
|
|
6716
6178
|
]);
|
|
6717
6179
|
});
|
|
@@ -6726,14 +6188,14 @@ var Xr = class {
|
|
|
6726
6188
|
let r = this.snapshot.realisedPnl ?? this.snapshot.fills.reduce((e, t) => e + (t.pnl ?? 0), 0);
|
|
6727
6189
|
if (n.length > 0) {
|
|
6728
6190
|
let e = document.createElement("p");
|
|
6729
|
-
e.className = "tcw-account-summary", e.textContent = p(this.t("account.realised"), { pnl:
|
|
6191
|
+
e.className = "tcw-account-summary", e.textContent = p(this.t("account.realised"), { pnl: Kr(r) }), this.content.appendChild(e);
|
|
6730
6192
|
}
|
|
6731
6193
|
}
|
|
6732
|
-
},
|
|
6733
|
-
function
|
|
6194
|
+
}, Jr = 1e-9;
|
|
6195
|
+
function Yr(e, t) {
|
|
6734
6196
|
return e.type === "market" ? t : e.price;
|
|
6735
6197
|
}
|
|
6736
|
-
function
|
|
6198
|
+
function Xr(e, t, n = {}) {
|
|
6737
6199
|
let r = [];
|
|
6738
6200
|
(!(e.quantity > 0) || !Number.isFinite(e.quantity)) && r.push("quantity"), e.type !== "market" && (!(e.price > 0) || !Number.isFinite(e.price)) && r.push("price"), e.type === "market" && !((t ?? e.price) > 0) && r.push("market");
|
|
6739
6201
|
let i = e.side === "buy";
|
|
@@ -6743,18 +6205,18 @@ function $r(e, t, n = {}) {
|
|
|
6743
6205
|
}
|
|
6744
6206
|
let a = (e) => e === null || Number.isFinite(e) && e > 0;
|
|
6745
6207
|
a(e.stopLoss) || r.push("stopLoss"), a(e.takeProfit) || r.push("takeProfit");
|
|
6746
|
-
let o =
|
|
6747
|
-
return o !== null && o > 0 && (e.stopLoss !== null && a(e.stopLoss) && (i ? e.stopLoss >= o : e.stopLoss <= o) && r.push("stopLossSide"), e.takeProfit !== null && a(e.takeProfit) && (i ? e.takeProfit <= o : e.takeProfit >= o) && r.push("takeProfitSide")), [...r, ...
|
|
6208
|
+
let o = Yr(e, t);
|
|
6209
|
+
return o !== null && o > 0 && (e.stopLoss !== null && a(e.stopLoss) && (i ? e.stopLoss >= o : e.stopLoss <= o) && r.push("stopLossSide"), e.takeProfit !== null && a(e.takeProfit) && (i ? e.takeProfit <= o : e.takeProfit >= o) && r.push("takeProfitSide")), [...r, ...Zr(e, n)];
|
|
6748
6210
|
}
|
|
6749
|
-
function
|
|
6211
|
+
function Zr(e, t) {
|
|
6750
6212
|
let n = [], r = e.type === "market" ? null : e.price, i = [
|
|
6751
6213
|
r,
|
|
6752
6214
|
e.stopLoss,
|
|
6753
6215
|
e.takeProfit
|
|
6754
6216
|
].filter((e) => e !== null && Number.isFinite(e) && e > 0), { roundPrice: a, limits: o, lot: s } = t;
|
|
6755
|
-
return a && i.some((e) => Math.abs(a(e) - e) >
|
|
6217
|
+
return a && i.some((e) => Math.abs(a(e) - e) > Jr) && n.push("priceStep"), o && r !== null && r > 0 && (r > o.ceiling + Jr || r < o.floor - Jr) && n.push("priceLimits"), s !== void 0 && s > 1 && e.quantity > s && e.quantity % s !== 0 && n.push("lot"), n;
|
|
6756
6218
|
}
|
|
6757
|
-
function
|
|
6219
|
+
function Qr(e, t) {
|
|
6758
6220
|
let n = {
|
|
6759
6221
|
side: e.side,
|
|
6760
6222
|
type: e.type,
|
|
@@ -6763,15 +6225,15 @@ function ti(e, t) {
|
|
|
6763
6225
|
};
|
|
6764
6226
|
return e.type === "stop" && (n.stopPrice = e.price), e.type !== "market" && (n.timeInForce = e.timeInForce), e.stopLoss !== null && (n.stopLoss = e.stopLoss), e.takeProfit !== null && (n.takeProfit = e.takeProfit), n;
|
|
6765
6227
|
}
|
|
6766
|
-
function
|
|
6767
|
-
let n =
|
|
6228
|
+
function $r(e, t) {
|
|
6229
|
+
let n = Yr(e, t);
|
|
6768
6230
|
if (n === null || e.stopLoss === null || e.takeProfit === null) return null;
|
|
6769
6231
|
let r = Math.abs(n - e.stopLoss);
|
|
6770
6232
|
return r > 0 ? Math.abs(e.takeProfit - n) / r : null;
|
|
6771
6233
|
}
|
|
6772
6234
|
//#endregion
|
|
6773
6235
|
//#region src/widget/WidgetOrderTicket.ts
|
|
6774
|
-
var
|
|
6236
|
+
var ei = 0, ti = class {
|
|
6775
6237
|
backdrop;
|
|
6776
6238
|
modal;
|
|
6777
6239
|
body;
|
|
@@ -6781,7 +6243,7 @@ var ri = 0, ii = class {
|
|
|
6781
6243
|
lastPrice = null;
|
|
6782
6244
|
rules = {};
|
|
6783
6245
|
returnFocus = null;
|
|
6784
|
-
uid = ++
|
|
6246
|
+
uid = ++ei;
|
|
6785
6247
|
constructor(e, t, n = h) {
|
|
6786
6248
|
this.callbacks = t, this.t = n, this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.hidden = !0;
|
|
6787
6249
|
let r = !1;
|
|
@@ -6836,7 +6298,7 @@ var ri = 0, ii = class {
|
|
|
6836
6298
|
}
|
|
6837
6299
|
place() {
|
|
6838
6300
|
let e = this.draft;
|
|
6839
|
-
!e ||
|
|
6301
|
+
!e || Xr(e, this.lastPrice, this.rules).length > 0 || (this.callbacks.onSubmit(Qr(e, this.lastPrice)), this.close());
|
|
6840
6302
|
}
|
|
6841
6303
|
set(e, t = !1) {
|
|
6842
6304
|
this.draft && (this.draft = {
|
|
@@ -6848,18 +6310,18 @@ var ri = 0, ii = class {
|
|
|
6848
6310
|
let e = this.draft;
|
|
6849
6311
|
if (!e) return;
|
|
6850
6312
|
let t = document.activeElement, n = t instanceof HTMLElement && this.body.contains(t) ? t.dataset.ticketField : void 0;
|
|
6851
|
-
this.body.replaceChildren(this.sideToggle(e.side), P(this.t("ticket.type"),
|
|
6313
|
+
this.body.replaceChildren(this.sideToggle(e.side), P(this.t("ticket.type"), ni("type", F([
|
|
6852
6314
|
"market",
|
|
6853
6315
|
"limit",
|
|
6854
6316
|
"stop"
|
|
6855
6317
|
].map((e) => ({
|
|
6856
6318
|
value: e,
|
|
6857
6319
|
label: this.t(`ticket.type.${e}`)
|
|
6858
|
-
})), e.type, (e) => this.set({ type: e }, !0)))), P(this.t("ticket.quantity"),
|
|
6320
|
+
})), e.type, (e) => this.set({ type: e }, !0)))), P(this.t("ticket.quantity"), ni("quantity", this.number(e.quantity, (e) => this.set({ quantity: e }))))), e.type !== "market" && this.body.append(P(this.t("ticket.price"), ni("price", this.number(e.price, (e) => this.set({ price: e })))), P(this.t("ticket.timeInForce"), ni("timeInForce", F(["gtc", "day"].map((e) => ({
|
|
6859
6321
|
value: e,
|
|
6860
6322
|
label: this.t(`ticket.tif.${e}`)
|
|
6861
6323
|
})), e.timeInForce, (e) => this.set({ timeInForce: e })))));
|
|
6862
|
-
let r = e.type === "market" ? this.lastPrice ?? e.price : e.price, i = (t) =>
|
|
6324
|
+
let r = e.type === "market" ? this.lastPrice ?? e.price : e.price, i = (t) => ri(r * (1 + (e.side === "buy" ? t : -t) / 100), r);
|
|
6863
6325
|
this.body.append(this.optionalPrice("ticket.stopLoss", e.stopLoss, i(-1), (t) => this.set({ stopLoss: t }, t === null || e.stopLoss === null)), this.optionalPrice("ticket.takeProfit", e.takeProfit, i(2), (t) => this.set({ takeProfit: t }, t === null || e.takeProfit === null))), n && this.body.querySelector(`[data-ticket-field="${n}"]`)?.focus(), this.check();
|
|
6864
6326
|
}
|
|
6865
6327
|
sideToggle(e) {
|
|
@@ -6880,7 +6342,7 @@ var ri = 0, ii = class {
|
|
|
6880
6342
|
i.className = "tcw-settings-row tcw-ticket-optional";
|
|
6881
6343
|
let a = document.createElement("span");
|
|
6882
6344
|
a.textContent = this.t(e);
|
|
6883
|
-
let o =
|
|
6345
|
+
let o = Lt(t !== null, (e) => r(e ? n : null));
|
|
6884
6346
|
if (o.setAttribute("aria-label", this.t(e)), o.dataset.ticketField = `${e}-switch`, i.append(a, o), t !== null) {
|
|
6885
6347
|
let n = this.number(t, (e) => r(Number.isFinite(e) ? e : NaN));
|
|
6886
6348
|
n.setAttribute("aria-label", this.t(e)), n.dataset.ticketField = e, i.appendChild(n);
|
|
@@ -6890,7 +6352,7 @@ var ri = 0, ii = class {
|
|
|
6890
6352
|
check() {
|
|
6891
6353
|
let e = this.draft;
|
|
6892
6354
|
if (!e) return;
|
|
6893
|
-
let t =
|
|
6355
|
+
let t = Xr(e, this.lastPrice, this.rules), n = t.map((e) => this.problemText(e)), r = $r(e, this.lastPrice);
|
|
6894
6356
|
t.length === 0 && r !== null && n.push(p(this.t("ticket.riskReward"), { rr: r.toFixed(2) })), this.problemsEl.replaceChildren(...n.map((e) => {
|
|
6895
6357
|
let t = document.createElement("p");
|
|
6896
6358
|
return t.textContent = e, t;
|
|
@@ -6904,16 +6366,16 @@ var ri = 0, ii = class {
|
|
|
6904
6366
|
}) : e === "lot" ? p(t, { lot: r ?? 1 }) : t;
|
|
6905
6367
|
}
|
|
6906
6368
|
};
|
|
6907
|
-
function
|
|
6369
|
+
function ni(e, t) {
|
|
6908
6370
|
return t.dataset.ticketField = e, t;
|
|
6909
6371
|
}
|
|
6910
|
-
function
|
|
6372
|
+
function ri(e, t) {
|
|
6911
6373
|
let n = Math.abs(t), r = n >= 10 || n === 0 ? 2 : n >= 1 ? 4 : Math.min(10, Math.ceil(-Math.log10(n)) + 3);
|
|
6912
6374
|
return Number(e.toFixed(r));
|
|
6913
6375
|
}
|
|
6914
6376
|
//#endregion
|
|
6915
6377
|
//#region src/widget/WidgetNamePrompt.ts
|
|
6916
|
-
var
|
|
6378
|
+
var ii = 0, ai = class {
|
|
6917
6379
|
backdrop;
|
|
6918
6380
|
titleEl;
|
|
6919
6381
|
input;
|
|
@@ -6921,7 +6383,7 @@ var si = 0, ci = class {
|
|
|
6921
6383
|
request = null;
|
|
6922
6384
|
returnFocus = null;
|
|
6923
6385
|
busy = !1;
|
|
6924
|
-
uid = ++
|
|
6386
|
+
uid = ++ii;
|
|
6925
6387
|
constructor(e, t = h) {
|
|
6926
6388
|
this.t = t, this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.hidden = !0;
|
|
6927
6389
|
let n = !1;
|
|
@@ -6981,7 +6443,7 @@ var si = 0, ci = class {
|
|
|
6981
6443
|
}
|
|
6982
6444
|
}
|
|
6983
6445
|
}
|
|
6984
|
-
},
|
|
6446
|
+
}, oi = 0, si = class {
|
|
6985
6447
|
backdrop;
|
|
6986
6448
|
search;
|
|
6987
6449
|
listEl;
|
|
@@ -6989,7 +6451,7 @@ var si = 0, ci = class {
|
|
|
6989
6451
|
confirming = null;
|
|
6990
6452
|
returnFocus = null;
|
|
6991
6453
|
loadSeq = 0;
|
|
6992
|
-
uid = ++
|
|
6454
|
+
uid = ++oi;
|
|
6993
6455
|
constructor(e, t, n = h) {
|
|
6994
6456
|
this.callbacks = t, this.t = n, this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.hidden = !0;
|
|
6995
6457
|
let r = !1;
|
|
@@ -7091,7 +6553,7 @@ var si = 0, ci = class {
|
|
|
7091
6553
|
this.confirming = null, await this.refresh(), this.isOpen() && this.search.focus();
|
|
7092
6554
|
}
|
|
7093
6555
|
}
|
|
7094
|
-
},
|
|
6556
|
+
}, ci = 5, li = class {
|
|
7095
6557
|
menu;
|
|
7096
6558
|
prompt;
|
|
7097
6559
|
dialog;
|
|
@@ -7099,7 +6561,7 @@ var si = 0, ci = class {
|
|
|
7099
6561
|
constructor(e, t) {
|
|
7100
6562
|
this.session = e, this.host = t;
|
|
7101
6563
|
let { root: n, t: r } = t;
|
|
7102
|
-
this.menu = new K(n, r("toolbar.layouts")), this.prompt = new
|
|
6564
|
+
this.menu = new K(n, r("toolbar.layouts")), this.prompt = new ai(n, r), this.dialog = new si(n, {
|
|
7103
6565
|
list: () => e.list(),
|
|
7104
6566
|
currentId: () => e.current()?.id ?? null,
|
|
7105
6567
|
onOpen: (e) => void this.open(e),
|
|
@@ -7177,7 +6639,7 @@ var si = 0, ci = class {
|
|
|
7177
6639
|
}
|
|
7178
6640
|
let { session: t } = this, { t: n, root: r } = this.host, i = [];
|
|
7179
6641
|
try {
|
|
7180
|
-
i = (await t.list()).slice(0,
|
|
6642
|
+
i = (await t.list()).slice(0, ci);
|
|
7181
6643
|
} catch {}
|
|
7182
6644
|
if (this.destroyed) return;
|
|
7183
6645
|
let a = t.current(), o = [{
|
|
@@ -7214,7 +6676,7 @@ var si = 0, ci = class {
|
|
|
7214
6676
|
destroy() {
|
|
7215
6677
|
this.destroyed = !0, this.menu.destroy(), this.prompt.destroy(), this.dialog.destroy();
|
|
7216
6678
|
}
|
|
7217
|
-
},
|
|
6679
|
+
}, ui = [
|
|
7218
6680
|
"1m",
|
|
7219
6681
|
"3m",
|
|
7220
6682
|
"5m",
|
|
@@ -7226,33 +6688,33 @@ var si = 0, ci = class {
|
|
|
7226
6688
|
"1d",
|
|
7227
6689
|
"1w",
|
|
7228
6690
|
"1M"
|
|
7229
|
-
],
|
|
6691
|
+
], di = [
|
|
7230
6692
|
"1m",
|
|
7231
6693
|
"5m",
|
|
7232
6694
|
"15m",
|
|
7233
6695
|
"1h",
|
|
7234
6696
|
"4h",
|
|
7235
6697
|
"1d"
|
|
7236
|
-
],
|
|
7237
|
-
function
|
|
6698
|
+
], fi = 6;
|
|
6699
|
+
function pi(e) {
|
|
7238
6700
|
let t = e.slice(-1);
|
|
7239
6701
|
return t === "h" || t === "d" || t === "w" ? e.slice(0, -1) + t.toUpperCase() : e;
|
|
7240
6702
|
}
|
|
7241
|
-
var
|
|
6703
|
+
var mi = (e) => Number.isFinite(w(e)) || C(e) !== null, hi = (e, t) => {
|
|
7242
6704
|
let n = C(e), r = C(t);
|
|
7243
6705
|
return n !== null || r !== null ? n === null ? 1 : r === null ? -1 : n - r : w(e) - w(t);
|
|
7244
6706
|
};
|
|
7245
|
-
function
|
|
7246
|
-
let n = t?.length ? t : null, r = e?.length ? e : n ??
|
|
7247
|
-
return [...new Set(r)].filter((e) =>
|
|
6707
|
+
function gi(e, t) {
|
|
6708
|
+
let n = t?.length ? t : null, r = e?.length ? e : n ?? ui;
|
|
6709
|
+
return [...new Set(r)].filter((e) => mi(e) && (!n || n.includes(e))).sort(hi);
|
|
7248
6710
|
}
|
|
7249
|
-
function
|
|
6711
|
+
function _i(e, t, n = !1) {
|
|
7250
6712
|
if (t?.length) return e.filter((e) => t.includes(e));
|
|
7251
6713
|
if (n) return [...e];
|
|
7252
|
-
let r = e.filter((e) =>
|
|
7253
|
-
return r.length > 0 ? r : e.slice(0,
|
|
6714
|
+
let r = e.filter((e) => di.includes(e));
|
|
6715
|
+
return r.length > 0 ? r : e.slice(0, fi);
|
|
7254
6716
|
}
|
|
7255
|
-
var
|
|
6717
|
+
var vi = 9999, yi = {
|
|
7256
6718
|
"": "m",
|
|
7257
6719
|
s: "s",
|
|
7258
6720
|
S: "s",
|
|
@@ -7264,28 +6726,44 @@ var xi = 9999, Si = {
|
|
|
7264
6726
|
w: "w",
|
|
7265
6727
|
W: "w",
|
|
7266
6728
|
M: "M"
|
|
7267
|
-
},
|
|
6729
|
+
}, bi = {
|
|
7268
6730
|
s: ["m", 60],
|
|
7269
6731
|
m: ["h", 60],
|
|
7270
6732
|
h: ["d", 24]
|
|
7271
6733
|
};
|
|
7272
|
-
function
|
|
6734
|
+
function xi(e) {
|
|
7273
6735
|
let t = /^(\d+)([a-zA-Z]?)$/.exec(e.trim());
|
|
7274
6736
|
if (!t) return null;
|
|
7275
6737
|
if (t[2] === "T" || t[2] === "t") {
|
|
7276
6738
|
let e = `${Number(t[1])}T`;
|
|
7277
|
-
return Number(t[1]) <=
|
|
6739
|
+
return Number(t[1]) <= vi && C(e) !== null ? e : null;
|
|
7278
6740
|
}
|
|
7279
|
-
let n = Number(t[1]), r =
|
|
6741
|
+
let n = Number(t[1]), r = yi[t[2]];
|
|
7280
6742
|
if (!r || !Number.isSafeInteger(n) || n < 1) return null;
|
|
7281
|
-
for (let e =
|
|
7282
|
-
if (n >
|
|
6743
|
+
for (let e = bi[r]; e && n % e[1] === 0; e = bi[r]) n /= e[1], r = e[0];
|
|
6744
|
+
if (n > vi) return null;
|
|
7283
6745
|
let i = `${n}${r}`;
|
|
7284
|
-
return
|
|
7285
|
-
}
|
|
7286
|
-
function
|
|
7287
|
-
let r = n?.length ? n : null, i = t.filter((e) =>
|
|
7288
|
-
return [...new Set([...e, ...i])].sort(
|
|
6746
|
+
return se(i) ? i : null;
|
|
6747
|
+
}
|
|
6748
|
+
function Si(e, t, n) {
|
|
6749
|
+
let r = n?.length ? n : null, i = t.filter((e) => mi(e) && (!r || r.includes(e)));
|
|
6750
|
+
return [...new Set([...e, ...i])].sort(hi);
|
|
6751
|
+
}
|
|
6752
|
+
var Ci = 864e5, wi = 5 / 7;
|
|
6753
|
+
function Ti(e) {
|
|
6754
|
+
let t = w(e.current), n = w(e.chosen);
|
|
6755
|
+
if (!Number.isFinite(t) || !Number.isFinite(n) || !(e.width > 0) || !(e.spanMs > 0)) return e.current;
|
|
6756
|
+
let r = (n) => {
|
|
6757
|
+
if (n === t) return e.barsInSpan;
|
|
6758
|
+
if (n < Ci) return e.barsInSpan * t / n;
|
|
6759
|
+
let r = e.spanMs / n;
|
|
6760
|
+
return n === Ci ? r * (e.dayShare ?? wi) : r;
|
|
6761
|
+
}, i = [...new Set([...e.available, e.current])].filter((e) => {
|
|
6762
|
+
let t = w(e);
|
|
6763
|
+
return Number.isFinite(t) && t >= n;
|
|
6764
|
+
}).sort(hi);
|
|
6765
|
+
for (let t of i) if (r(w(t)) * 2 <= e.width) return t;
|
|
6766
|
+
return i[i.length - 1] ?? e.current;
|
|
7289
6767
|
}
|
|
7290
6768
|
//#endregion
|
|
7291
6769
|
//#region src/widget/WidgetIntervalInput.ts
|
|
@@ -7315,11 +6793,11 @@ var Ei = 0, Di = class {
|
|
|
7315
6793
|
this.el.remove();
|
|
7316
6794
|
}
|
|
7317
6795
|
check() {
|
|
7318
|
-
let e =
|
|
6796
|
+
let e = xi(this.input.value) !== null;
|
|
7319
6797
|
!e && this.input.value.trim() !== "" ? this.input.setAttribute("aria-invalid", "true") : this.input.removeAttribute("aria-invalid"), this.hint.textContent = e || this.input.value.trim() === "" ? this.labels.hint : this.labels.invalid;
|
|
7320
6798
|
}
|
|
7321
6799
|
apply() {
|
|
7322
|
-
let e =
|
|
6800
|
+
let e = xi(this.input.value);
|
|
7323
6801
|
if (e && this.onApply(e)) {
|
|
7324
6802
|
this.close();
|
|
7325
6803
|
return;
|
|
@@ -7343,7 +6821,7 @@ var Ei = 0, Di = class {
|
|
|
7343
6821
|
if (typeof n != "object" || !n) continue;
|
|
7344
6822
|
let { name: e, indicators: r } = n;
|
|
7345
6823
|
if (typeof e != "string" || !e.trim() || !Array.isArray(r)) continue;
|
|
7346
|
-
let i =
|
|
6824
|
+
let i = Se.deserialize(JSON.stringify({
|
|
7347
6825
|
version: 2,
|
|
7348
6826
|
indicators: r
|
|
7349
6827
|
})).indicators;
|
|
@@ -7407,7 +6885,7 @@ function Pi(e) {
|
|
|
7407
6885
|
return r;
|
|
7408
6886
|
}
|
|
7409
6887
|
function Fi(e) {
|
|
7410
|
-
return !Ni(e) || e.v !== 1 || typeof e.symbol != "string" || !e.symbol || typeof e.timeframe != "string" || !(
|
|
6888
|
+
return !Ni(e) || e.v !== 1 || typeof e.symbol != "string" || !e.symbol || typeof e.timeframe != "string" || !(se(e.timeframe) || C(e.timeframe) !== null) ? null : {
|
|
7411
6889
|
v: 1,
|
|
7412
6890
|
symbol: e.symbol,
|
|
7413
6891
|
timeframe: e.timeframe,
|
|
@@ -7485,10 +6963,10 @@ function Vi(e, t, n) {
|
|
|
7485
6963
|
];
|
|
7486
6964
|
if (o < 1 || o > 12 || s < 1 || s > 31 || c > 23 || l > 59) return null;
|
|
7487
6965
|
let u = Date.UTC(a, o - 1, s, c, l);
|
|
7488
|
-
return new Date(u).getUTCDate() === s ?
|
|
6966
|
+
return new Date(u).getUTCDate() === s ? be(u, n) : null;
|
|
7489
6967
|
}
|
|
7490
6968
|
function X(e, t) {
|
|
7491
|
-
let n = (e) => String(e).padStart(2, "0"), r =
|
|
6969
|
+
let n = (e) => String(e).padStart(2, "0"), r = _e(e, t);
|
|
7492
6970
|
return {
|
|
7493
6971
|
date: `${r.year}-${n(r.month)}-${n(r.day)}`,
|
|
7494
6972
|
time: `${n(r.hours)}:${n(r.minutes)}`
|
|
@@ -7830,11 +7308,11 @@ function ta(e, t, n, r) {
|
|
|
7830
7308
|
opacity: 1
|
|
7831
7309
|
}, o = [];
|
|
7832
7310
|
for (let e of i) {
|
|
7833
|
-
if (!
|
|
7311
|
+
if (!Oe(e, { plots: r })) continue;
|
|
7834
7312
|
let i = t[e.key];
|
|
7835
7313
|
typeof i != "number" || !Number.isFinite(i) || o.push({
|
|
7836
7314
|
value: i,
|
|
7837
|
-
color: n.length ?
|
|
7315
|
+
color: n.length ? De(e, a, t) : null
|
|
7838
7316
|
});
|
|
7839
7317
|
}
|
|
7840
7318
|
return o;
|
|
@@ -7848,7 +7326,7 @@ function ra(e) {
|
|
|
7848
7326
|
}), na.set(e, t)), t;
|
|
7849
7327
|
}
|
|
7850
7328
|
function ia(e, t = "en-US") {
|
|
7851
|
-
return Math.abs(e) >= 1e6 ? ra(t).format(e) :
|
|
7329
|
+
return Math.abs(e) >= 1e6 ? ra(t).format(e) : ie(e, Ee(e), t);
|
|
7852
7330
|
}
|
|
7853
7331
|
//#endregion
|
|
7854
7332
|
//#region src/widget/WidgetBracketBar.ts
|
|
@@ -8408,12 +7886,12 @@ var Ha = [
|
|
|
8408
7886
|
KeyV: "verticalLine",
|
|
8409
7887
|
KeyC: "crossLine",
|
|
8410
7888
|
KeyF: "fibRetracement"
|
|
8411
|
-
}, Za = 229, Qa =
|
|
7889
|
+
}, Za = 229, Qa = Ze.filter((e) => g[e] !== "color"), $a = 200, eo = class {
|
|
8412
7890
|
chart;
|
|
8413
7891
|
state;
|
|
8414
7892
|
themeOf = {
|
|
8415
|
-
dark:
|
|
8416
|
-
light:
|
|
7893
|
+
dark: v,
|
|
7894
|
+
light: te
|
|
8417
7895
|
};
|
|
8418
7896
|
toolbar = null;
|
|
8419
7897
|
sidebar = null;
|
|
@@ -8513,6 +7991,9 @@ var Ha = [
|
|
|
8513
7991
|
boundGlobalKeydown = null;
|
|
8514
7992
|
baseSeries = null;
|
|
8515
7993
|
baseTimeframeMs = 0;
|
|
7994
|
+
chosenTimeframe = null;
|
|
7995
|
+
rangeSeq = 0;
|
|
7996
|
+
rangeQueue = Promise.resolve();
|
|
8516
7997
|
compares = [];
|
|
8517
7998
|
featureState;
|
|
8518
7999
|
hostHotkeys = [];
|
|
@@ -8520,17 +8001,17 @@ var Ha = [
|
|
|
8520
8001
|
hostLayer = null;
|
|
8521
8002
|
priceAxisAddDefault = !1;
|
|
8522
8003
|
constructor(e, t = {}) {
|
|
8523
|
-
this.options = t, this.symbols = t.symbols ??
|
|
8004
|
+
this.options = t, this.symbols = t.symbols ?? Ue;
|
|
8524
8005
|
let r = t.chartOptions;
|
|
8525
8006
|
if (this.settingsState = {
|
|
8526
|
-
...
|
|
8007
|
+
...We,
|
|
8527
8008
|
...r?.numberLocale ? { numberLocale: r.numberLocale } : {},
|
|
8528
|
-
...r?.timeZone == null ? {} : { timezone:
|
|
8009
|
+
...r?.timeZone == null ? {} : { timezone: Le(r.timeZone) },
|
|
8529
8010
|
...r?.leftPriceScale === void 0 ? {} : { leftPriceScale: r.leftPriceScale },
|
|
8530
8011
|
...r?.highLowLines === void 0 ? {} : { highLowLines: r.highLowLines },
|
|
8531
8012
|
...r?.extendedHours === void 0 ? {} : { extendedHours: r.extendedHours },
|
|
8532
|
-
...r?.chartTypeOptions ? { chartTypeOptions:
|
|
8533
|
-
}, this.t = d(f(t.locale, t.messages)), this.featureState =
|
|
8013
|
+
...r?.chartTypeOptions ? { chartTypeOptions: fe(r.chartTypeOptions) } : {}
|
|
8014
|
+
}, this.t = d(f(t.locale, t.messages)), this.featureState = at(t), t.persistLayouts) {
|
|
8534
8015
|
let e = t.persistLayouts === !0 ? {} : t.persistLayouts;
|
|
8535
8016
|
this.layoutKeyPrefix = e.keyPrefix ?? "tcw:layout:", this.layoutDebounceMs = e.debounceMs ?? 1500;
|
|
8536
8017
|
}
|
|
@@ -8569,8 +8050,8 @@ var Ha = [
|
|
|
8569
8050
|
legendVisible: s.legend !== !1,
|
|
8570
8051
|
barCountdown: s.barCountdown !== !1,
|
|
8571
8052
|
indicatorValueLabels: s.indicatorValueLabels !== !1
|
|
8572
|
-
}, this.settingsState = { ...this.settingsDefaults }, this.timeframes =
|
|
8573
|
-
let e =
|
|
8053
|
+
}, this.settingsState = { ...this.settingsDefaults }, this.timeframes = Si(gi(t.timeframes, s.timeframes), this.customTimeframes.list(), s.timeframes), !this.timeframes.some((e) => this.timeframeFavorites.has(e))) {
|
|
8054
|
+
let e = _i(this.timeframes, s.defaultTimeframeFavorites, !!t.timeframes?.length);
|
|
8574
8055
|
for (let t of e) this.timeframeFavorites.add(t);
|
|
8575
8056
|
}
|
|
8576
8057
|
let l = t.timeframe ?? "5m", u = !s.timeframes?.length || s.timeframes.includes(l) ? l : this.timeframes[0] ?? l;
|
|
@@ -8588,17 +8069,17 @@ var Ha = [
|
|
|
8588
8069
|
stayInDrawing: !1,
|
|
8589
8070
|
connectionState: t.adapter ? "connecting" : "disconnected",
|
|
8590
8071
|
connectionMessage: t.adapter ? this.t("status.connecting") : ""
|
|
8591
|
-
},
|
|
8592
|
-
let m = t.dir === "ltr" || t.dir === "rtl" ? t.dir :
|
|
8072
|
+
}, ht(), this.root = document.createElement("div"), this.root.className = "tcw-root", this.root.dataset.tcwTheme = i ? "dark" : "light";
|
|
8073
|
+
let m = t.dir === "ltr" || t.dir === "rtl" ? t.dir : fo(t.locale) ? "rtl" : "ltr";
|
|
8593
8074
|
this.root.dir = m, this.portal.dir = m, e.appendChild(this.root), this.tooltip = new Ki(this.root), this.portal.className = "tcw-root tcw-portal", this.portal.dataset.tcwTheme = this.root.dataset.tcwTheme, this.ui = H(t.ui);
|
|
8594
8075
|
let h = t.ui !== void 0;
|
|
8595
|
-
U(this.root, this.ui, { variables: h }), U(this.portal, this.ui, { variables: h }), this.markSwitchedOff(), this.toolbar = new
|
|
8076
|
+
U(this.root, this.ui, { variables: h }), U(this.portal, this.ui, { variables: h }), this.markSwitchedOff(), this.toolbar = new Ot(this.root, {
|
|
8596
8077
|
symbols: this.symbols,
|
|
8597
8078
|
timeframes: this.timeframeMenu(),
|
|
8598
8079
|
timeframeFavorites: this.pinnedTimeframes(),
|
|
8599
|
-
chartTypes: t.chartTypes ?
|
|
8600
|
-
indicators:
|
|
8601
|
-
popularIndicatorIds:
|
|
8080
|
+
chartTypes: t.chartTypes ? ze.filter((e) => t.chartTypes.includes(e.value)) : ze,
|
|
8081
|
+
indicators: Ve,
|
|
8082
|
+
popularIndicatorIds: He
|
|
8602
8083
|
}, {
|
|
8603
8084
|
onSymbolClick: () => this.handleSymbolClick(),
|
|
8604
8085
|
onSymbolInfo: () => this.toggleSymbolInfo(),
|
|
@@ -8626,8 +8107,8 @@ var Ha = [
|
|
|
8626
8107
|
onToggleFullscreen: typeof document < "u" && document.fullscreenEnabled ? () => this.toggleFullscreen() : void 0
|
|
8627
8108
|
}, this.t);
|
|
8628
8109
|
let g = document.createElement("div");
|
|
8629
|
-
g.className = "tcw-body", t.drawingFavorites && this.favoritesStore.seedDefaults(t.drawingFavorites), this.sidebar = new
|
|
8630
|
-
drawingToolGroups:
|
|
8110
|
+
g.className = "tcw-body", t.drawingFavorites && this.favoritesStore.seedDefaults(t.drawingFavorites), this.sidebar = new It(g, {
|
|
8111
|
+
drawingToolGroups: Tt(Be, this.t),
|
|
8631
8112
|
favorites: this.favoritesStore.list()
|
|
8632
8113
|
}, {
|
|
8633
8114
|
onDrawingTool: (e) => this.handleDrawingTool(e),
|
|
@@ -8673,7 +8154,7 @@ var Ha = [
|
|
|
8673
8154
|
}), t.chartOptions?.shapes || this.applyChartShapes(), this.applyLegendFont(), this.chart.on("visibleRangeChange", (e) => {
|
|
8674
8155
|
let { from: t, to: n } = e.payload;
|
|
8675
8156
|
Number.isFinite(t) && Number.isFinite(n) && (this.visibleBarCount = Math.max(1, n - t));
|
|
8676
|
-
}), this.chartNav = new
|
|
8157
|
+
}), this.chartNav = new An(this.chartContainer, {
|
|
8677
8158
|
zoomIn: () => this.chart.zoomIn(),
|
|
8678
8159
|
zoomOut: () => this.chart.zoomOut(),
|
|
8679
8160
|
scroll: (e) => this.chart.scrollBars(e * Math.max(1, Math.round(this.visibleBarCount / 10))),
|
|
@@ -8684,7 +8165,7 @@ var Ha = [
|
|
|
8684
8165
|
}, this.t), this.chart.on("dataUpdate", (e) => this.handleDataUpdate(e.payload)), this.chart.on("historyLoad", (e) => this.historyPill.update(e.payload)), this.chart.on("symbolInfoChange", (e) => {
|
|
8685
8166
|
let t = e.payload.info, n = t ? [t.description, t.exchange].filter(Boolean).join(" · ") : "";
|
|
8686
8167
|
this.toolbar?.setSymbolDescription(n || null), this.refreshMarket();
|
|
8687
|
-
}), this.symbolInfoPanel = new
|
|
8168
|
+
}), this.symbolInfoPanel = new Dn(this.root, this.t, { onToggle: (e) => {
|
|
8688
8169
|
this.toolbar?.setActive("symbolInfo", e), e && (this.refreshSymbolInfo(), this.loadNews());
|
|
8689
8170
|
} }), this.marketTimer = setInterval(() => this.refreshMarket(), 3e4), this.dragDrop = new a(this.chartContainer, {
|
|
8690
8171
|
onData: (e, t, n) => {
|
|
@@ -8698,12 +8179,12 @@ var Ha = [
|
|
|
8698
8179
|
onError: (e, t) => {
|
|
8699
8180
|
this.say(`${t.name}: ${e.message}`, "error");
|
|
8700
8181
|
}
|
|
8701
|
-
}), this.featureState.dragDropImport && this.dragDrop.attach(), this.statusBar = new
|
|
8702
|
-
presets:
|
|
8182
|
+
}), this.featureState.dragDropImport && this.dragDrop.attach(), this.statusBar = new Yt(this.root, {
|
|
8183
|
+
presets: Te,
|
|
8703
8184
|
presetLabels: { All: this.t("range.all") },
|
|
8704
8185
|
groupLabel: this.t("range.presets"),
|
|
8705
8186
|
goToLabel: this.t("range.goTo"),
|
|
8706
|
-
onPreset: (e) => this.
|
|
8187
|
+
onPreset: (e) => void this.applyRangePreset(e),
|
|
8707
8188
|
onGoTo: () => this.toggleGoToDate()
|
|
8708
8189
|
}), this.goToDate = new Hi(this.root, {
|
|
8709
8190
|
title: this.t("range.goTo"),
|
|
@@ -8711,7 +8192,7 @@ var Ha = [
|
|
|
8711
8192
|
time: this.t("range.time"),
|
|
8712
8193
|
submit: this.t("range.goToSubmit"),
|
|
8713
8194
|
cancel: this.t("range.cancel")
|
|
8714
|
-
}, ({ date: e, time: t }) => this.goToWallTime(e, t)), this.settings = new
|
|
8195
|
+
}, ({ date: e, time: t }) => this.goToWallTime(e, t)), this.settings = new Gt({
|
|
8715
8196
|
onChange: (e) => this.changeSettings(e),
|
|
8716
8197
|
onReset: () => this.resetSettings(),
|
|
8717
8198
|
onClose: () => {},
|
|
@@ -8722,12 +8203,12 @@ var Ha = [
|
|
|
8722
8203
|
logScale: s.logScale,
|
|
8723
8204
|
trading: s.trading !== !1,
|
|
8724
8205
|
exchangeZone: this.adapter?.resolveSymbol ? () => this.chart.getSymbolInfo()?.timezone ?? null : void 0
|
|
8725
|
-
}, this.overlayHost), this.symbolSearch = new
|
|
8206
|
+
}, this.overlayHost), this.symbolSearch = new Qt({
|
|
8726
8207
|
onPick: (e) => {
|
|
8727
8208
|
this.setSymbol(e);
|
|
8728
8209
|
},
|
|
8729
8210
|
onClose: () => {}
|
|
8730
|
-
}, this.overlayHost, this.t), this.hotkeySheet = new
|
|
8211
|
+
}, this.overlayHost, this.t), this.hotkeySheet = new rn({ onClose: () => {} }, this.t, this.overlayHost), this.chart.on("drawingToolChange", (e) => {
|
|
8731
8212
|
let t = e.payload.tool;
|
|
8732
8213
|
t !== this.state.activeTool && (this.state = {
|
|
8733
8214
|
...this.state,
|
|
@@ -8797,9 +8278,9 @@ var Ha = [
|
|
|
8797
8278
|
let t = e.payload;
|
|
8798
8279
|
this.lastHoverIndex = typeof t.barIndex == "number" ? t.barIndex : null, this.dataWindow?.isOpen() && this.dataWindow.render(this.buildDataWindowModel());
|
|
8799
8280
|
});
|
|
8800
|
-
let v = new
|
|
8281
|
+
let v = new pr(), y = new mr();
|
|
8801
8282
|
for (let [e, t] of Object.entries(y.all())) this.chart.setDrawingToolDefaults(e, t ?? null);
|
|
8802
|
-
this.drawingSettings = new
|
|
8283
|
+
this.drawingSettings = new Pr(this.root, {
|
|
8803
8284
|
onBegin: (e) => this.chart.beginDrawingEdit(e),
|
|
8804
8285
|
onChange: (e, t) => this.chart.updateDrawing(e, t),
|
|
8805
8286
|
onEnd: (e, t) => {
|
|
@@ -8817,7 +8298,7 @@ var Ha = [
|
|
|
8817
8298
|
this.chart.setDrawingToolDefaults(e, t), y.set(e, this.chart.getDrawingToolDefaults(e)), this.say(p(this.t("drawingSettings.defaultSaved"), { name: this.drawingToolName(e) }));
|
|
8818
8299
|
},
|
|
8819
8300
|
templates: v
|
|
8820
|
-
}, this.t), this.chart.on("drawingDoubleClick", (e) => this.openDrawingSettings(e.payload.id)), this.drawingStyle = new
|
|
8301
|
+
}, this.t), this.chart.on("drawingDoubleClick", (e) => this.openDrawingSettings(e.payload.id)), this.drawingStyle = new vr(this.root, {
|
|
8821
8302
|
onStyleChange: (e) => {
|
|
8822
8303
|
this.chart.setDrawingStyle(e), this.chart.setSelectedDrawingStyle(e);
|
|
8823
8304
|
},
|
|
@@ -8825,7 +8306,7 @@ var Ha = [
|
|
|
8825
8306
|
}, v, this.t), this.drawingMenu = new K(this.root, this.t("drawingMenu.label")), this.chart.on("drawingContextMenu", (e) => {
|
|
8826
8307
|
let { id: t, x: n, y: r } = e.payload;
|
|
8827
8308
|
this.openDrawingMenu(t, n, r);
|
|
8828
|
-
}), this.selectionToolbar = new
|
|
8309
|
+
}), this.selectionToolbar = new Er(this.root, {
|
|
8829
8310
|
onStyle: (e) => {
|
|
8830
8311
|
for (let t of this.chart.getSelectedDrawingIds()) this.chart.setSelectedDrawingStyle(e, t);
|
|
8831
8312
|
this.updateSelectionToolbar();
|
|
@@ -8876,14 +8357,14 @@ var Ha = [
|
|
|
8876
8357
|
...this.chartMenuContext(s),
|
|
8877
8358
|
...o ? { pane: this.chart.getPaneScale(o) } : {}
|
|
8878
8359
|
};
|
|
8879
|
-
this.menuPane = o ?? null, this.openChartMenu(
|
|
8360
|
+
this.menuPane = o ?? null, this.openChartMenu(ft(zr(t, c, this.t), tt, this.featureState), n, r, {
|
|
8880
8361
|
area: t,
|
|
8881
8362
|
price: s,
|
|
8882
8363
|
time: a
|
|
8883
8364
|
});
|
|
8884
8365
|
}), this.chart.on("priceAxisAdd", (e) => {
|
|
8885
8366
|
if (!this.featureState["menu.priceAxisAdd"]) return;
|
|
8886
|
-
let { price: t, x: n, y: r } = e.payload, i = this.chart.roundPrice(t), a =
|
|
8367
|
+
let { price: t, x: n, y: r } = e.payload, i = this.chart.roundPrice(t), a = ft(Rr(this.chartMenuContext(i), this.t), tt, this.featureState);
|
|
8887
8368
|
this.openChartMenu(a, n, r, {
|
|
8888
8369
|
area: "priceAxisAdd",
|
|
8889
8370
|
price: i
|
|
@@ -8893,7 +8374,7 @@ var Ha = [
|
|
|
8893
8374
|
hint: this.t("interval.hint"),
|
|
8894
8375
|
invalid: this.t("interval.invalid")
|
|
8895
8376
|
}, (e) => this.selectTypedTimeframe(e)), this.toolbar?.setIndicatorTemplates(this.templates.list().map((e) => e.name)), t.layouts !== !1 && this.setupLayouts(t.layouts === !0 || t.layouts === void 0 ? {} : t.layouts), t.trading !== !1) {
|
|
8896
|
-
this.orderTicket = new
|
|
8377
|
+
this.orderTicket = new ti(this.root, {
|
|
8897
8378
|
onSubmit: (e) => {
|
|
8898
8379
|
this.chart.placeOrderIntent(e), this.say(p(this.t("ticket.sent"), {
|
|
8899
8380
|
side: this.t(e.side === "buy" ? "ticket.buy" : "ticket.sell"),
|
|
@@ -8902,7 +8383,7 @@ var Ha = [
|
|
|
8902
8383
|
}));
|
|
8903
8384
|
},
|
|
8904
8385
|
formatPrice: (e) => this.formatAlertPrice(e)
|
|
8905
|
-
}, this.t), this.accountPanel = new
|
|
8386
|
+
}, this.t), this.accountPanel = new qr(_, {
|
|
8906
8387
|
onClosePosition: (e) => this.chart.closePositionIntent(e),
|
|
8907
8388
|
onReversePosition: (e) => this.chart.reversePositionIntent(e),
|
|
8908
8389
|
onCancelOrder: (e) => this.chart.cancelOrderIntent(e),
|
|
@@ -8944,7 +8425,7 @@ var Ha = [
|
|
|
8944
8425
|
}, void 0, this.t)), this.chart.on("dataUpdate", (e) => {
|
|
8945
8426
|
let t = e.payload;
|
|
8946
8427
|
t && t.bracket === "cancelled" && this.bracketBar?.hide();
|
|
8947
|
-
})), this.alertsPanel = new
|
|
8428
|
+
})), this.alertsPanel = new zn(this.root, {
|
|
8948
8429
|
onAdd: ({ price: e, condition: t, message: n, channel: r, label: i, options: a }) => {
|
|
8949
8430
|
try {
|
|
8950
8431
|
return this.chart.addAlert(e, t, n, r, i, a), !0;
|
|
@@ -8967,8 +8448,8 @@ var Ha = [
|
|
|
8967
8448
|
let t = e.payload;
|
|
8968
8449
|
if (this.refreshAlerts(), !this.featureState.alerts) return;
|
|
8969
8450
|
let n = `${this.alertText(t)}${t.message ? ` — ${t.message}` : ""}`;
|
|
8970
|
-
this.say(
|
|
8971
|
-
}), this.indicatorSettings = new
|
|
8451
|
+
this.say(p(this.t("alerts.fired"), { text: n }), "info", "bell"), this.alertNotifier?.notify(n);
|
|
8452
|
+
}), this.indicatorSettings = new sr(this.root, {
|
|
8972
8453
|
onApply: (e, t) => {
|
|
8973
8454
|
this.chart.updateIndicator(e, t), this.syncIndicatorsFromChart();
|
|
8974
8455
|
},
|
|
@@ -8976,7 +8457,7 @@ var Ha = [
|
|
|
8976
8457
|
onLevels: (e, t) => this.chart.setIndicatorLevels(e, t),
|
|
8977
8458
|
onScale: (e, t) => this.chart.setIndicatorScale(e, t),
|
|
8978
8459
|
onClose: () => {}
|
|
8979
|
-
}, this.t), this.objectTree = new
|
|
8460
|
+
}, this.t), this.objectTree = new $n(this.root, {
|
|
8980
8461
|
onRemoveIndicator: (e) => this.handleRemoveIndicator(e),
|
|
8981
8462
|
onConfigureIndicator: (e) => this.openIndicatorSettings(e),
|
|
8982
8463
|
onToggleIndicatorVisible: (e, t) => {
|
|
@@ -9014,7 +8495,7 @@ var Ha = [
|
|
|
9014
8495
|
x || !this.objectTree?.isOpen() || (x = requestAnimationFrame(() => {
|
|
9015
8496
|
x = 0, this.destroyed || b();
|
|
9016
8497
|
}));
|
|
9017
|
-
}), this.chart.on("indicatorAdd", b), this.chart.on("indicatorRemove", b), this.chart.on("indicatorChange", b), this.commandPalette = new
|
|
8498
|
+
}), this.chart.on("indicatorAdd", b), this.chart.on("indicatorRemove", b), this.chart.on("indicatorChange", b), this.commandPalette = new Zt({
|
|
9018
8499
|
onIndicator: (e) => this.handleAddIndicator(e),
|
|
9019
8500
|
onChartType: (e) => this.handleChartType(e),
|
|
9020
8501
|
onDrawingTool: (e) => this.handleDrawingTool(e),
|
|
@@ -9091,7 +8572,7 @@ var Ha = [
|
|
|
9091
8572
|
this.watchlistStore?.removeSymbol(e, t);
|
|
9092
8573
|
}
|
|
9093
8574
|
setQuotes(e) {
|
|
9094
|
-
let t = e.map(
|
|
8575
|
+
let t = e.map(me).filter((e) => e !== null);
|
|
9095
8576
|
t.length > 0 && this.takeQuotes(t);
|
|
9096
8577
|
}
|
|
9097
8578
|
getQuote(e) {
|
|
@@ -9105,7 +8586,7 @@ var Ha = [
|
|
|
9105
8586
|
n && !this.featureState.symbolInfo || (n ? t.open() : t.close());
|
|
9106
8587
|
}
|
|
9107
8588
|
refreshMarket() {
|
|
9108
|
-
let e =
|
|
8589
|
+
let e = le(this.chart.getSymbolInfo(), Date.now());
|
|
9109
8590
|
this.statusBar?.setMarket(e.state, this.t(e.state === "open" ? "symbolInfo.open" : "symbolInfo.closed")), this.refreshSymbolInfo();
|
|
9110
8591
|
}
|
|
9111
8592
|
refreshSymbolInfo() {
|
|
@@ -9113,9 +8594,9 @@ var Ha = [
|
|
|
9113
8594
|
!e?.isOpen() || this.destroyed || e.render(this.symbolInfoView());
|
|
9114
8595
|
}
|
|
9115
8596
|
symbolInfoView() {
|
|
9116
|
-
let e = this.chart.getSymbolInfo(), t = this.state.symbol, n = this.quotes.get(t), r =
|
|
8597
|
+
let e = this.chart.getSymbolInfo(), t = this.state.symbol, n = this.quotes.get(t), r = oo(this.chart.getData(), e?.timezone), i = (e) => this.formatAlertPrice(e), a = this.textLocale(), o = n?.last ?? r?.close, s = n?.prevClose ?? r?.prevClose, c = n?.change ?? (o !== void 0 && s !== void 0 ? o - s : void 0), l = o !== void 0 && c !== void 0 ? o - c : void 0, u = n?.changePercent ?? (c !== void 0 && l ? c / l * 100 : void 0), d = le(e, Date.now()), f = this.t(d.state === "open" ? "symbolInfo.open" : d.state === "closed" ? "symbolInfo.closed" : "symbolInfo.always");
|
|
9117
8598
|
if (d.state !== "always" && d.next !== null) {
|
|
9118
|
-
let e =
|
|
8599
|
+
let e = so(d.next - Date.now(), a);
|
|
9119
8600
|
f += ` · ${p(this.t(d.state === "open" ? "symbolInfo.closesIn" : "symbolInfo.opensIn"), { when: e })}`;
|
|
9120
8601
|
}
|
|
9121
8602
|
let m = [], h = (e, t) => {
|
|
@@ -9126,7 +8607,7 @@ var Ha = [
|
|
|
9126
8607
|
}, g = (e) => e === void 0 ? void 0 : i(e);
|
|
9127
8608
|
h(this.t("dataWindow.open"), g(n?.open ?? r?.open)), h(this.t("dataWindow.high"), g(n?.high ?? r?.high)), h(this.t("dataWindow.low"), g(n?.low ?? r?.low)), h(this.t("symbolInfo.prevClose"), g(s));
|
|
9128
8609
|
let _ = n?.volume ?? r?.volume;
|
|
9129
|
-
h(this.t("dataWindow.volume"), _ === void 0 ? void 0 :
|
|
8610
|
+
h(this.t("dataWindow.volume"), _ === void 0 ? void 0 : co(_, this.intlLocale())), h(this.t("symbolInfo.bid"), g(n?.bid)), h(this.t("symbolInfo.ask"), g(n?.ask)), h(this.t("symbolInfo.tick"), e?.minTick === void 0 ? void 0 : String(e.minTick)), h(this.t("symbolInfo.currency"), e?.currency), h(this.t("symbolInfo.timezone"), e?.timezone), h(this.t("symbolInfo.hours"), lo(e, a));
|
|
9130
8611
|
let v = (c ?? 0) >= 0 ? "+" : "-";
|
|
9131
8612
|
return {
|
|
9132
8613
|
symbol: t,
|
|
@@ -9159,17 +8640,17 @@ var Ha = [
|
|
|
9159
8640
|
items: t.map((e) => ({
|
|
9160
8641
|
title: e.title,
|
|
9161
8642
|
url: e.url,
|
|
9162
|
-
meta: [e.source,
|
|
8643
|
+
meta: [e.source, so(e.time - Date.now(), n)].filter(Boolean).join(" · ")
|
|
9163
8644
|
}))
|
|
9164
8645
|
});
|
|
9165
8646
|
}, o = this.newsCache.get(r);
|
|
9166
|
-
if (o && Date.now() - o.at <
|
|
8647
|
+
if (o && Date.now() - o.at < io) {
|
|
9167
8648
|
a(o.items);
|
|
9168
8649
|
return;
|
|
9169
8650
|
}
|
|
9170
|
-
e.renderNews({ kind: "loading" }), Promise.resolve().then(() => n(r,
|
|
8651
|
+
e.renderNews({ kind: "loading" }), Promise.resolve().then(() => n(r, ro)).then((e) => {
|
|
9171
8652
|
if (i !== this.newsRequest || this.destroyed) return;
|
|
9172
|
-
let t =
|
|
8653
|
+
let t = pe(e, ro);
|
|
9173
8654
|
this.newsCache.set(r, {
|
|
9174
8655
|
at: Date.now(),
|
|
9175
8656
|
items: t
|
|
@@ -9185,7 +8666,7 @@ var Ha = [
|
|
|
9185
8666
|
return this.options.locale || "en";
|
|
9186
8667
|
}
|
|
9187
8668
|
createWatchlist(e, t) {
|
|
9188
|
-
let n = t.persist ?
|
|
8669
|
+
let n = t.persist ? no() : null, r = new En({
|
|
9189
8670
|
lists: t.lists,
|
|
9190
8671
|
activeList: t.activeList,
|
|
9191
8672
|
symbols: this.symbols,
|
|
@@ -9195,7 +8676,7 @@ var Ha = [
|
|
|
9195
8676
|
});
|
|
9196
8677
|
this.watchlistStore = r, this.watchlistFromSymbols = !t.lists && !t.persist, this.quoteSource = t.quotes === !1 ? null : t.quotes ?? (this.options.adapter?.subscribeQuotes ? this.options.adapter : null);
|
|
9197
8678
|
let i = (e) => this.t(e);
|
|
9198
|
-
this.watchlist = new
|
|
8679
|
+
this.watchlist = new pn(e, {
|
|
9199
8680
|
onSelect: (e) => {
|
|
9200
8681
|
this.setSymbol(e);
|
|
9201
8682
|
},
|
|
@@ -9231,7 +8712,7 @@ var Ha = [
|
|
|
9231
8712
|
if (t !== this.quotedKey && (this.quotedKey = t, this.stopQuotes?.(), this.stopQuotes = null, e.length !== 0)) try {
|
|
9232
8713
|
this.stopQuotes = this.quoteSource.subscribeQuotes(e, (e) => {
|
|
9233
8714
|
if (this.destroyed || !Array.isArray(e)) return;
|
|
9234
|
-
let t = e.map(
|
|
8715
|
+
let t = e.map(me).filter((e) => e !== null);
|
|
9235
8716
|
t.length > 0 && this.takeQuotes(t);
|
|
9236
8717
|
});
|
|
9237
8718
|
} catch {
|
|
@@ -9279,21 +8760,22 @@ var Ha = [
|
|
|
9279
8760
|
});
|
|
9280
8761
|
}
|
|
9281
8762
|
async setTimeframe(e) {
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
|
|
9293
|
-
|
|
9294
|
-
|
|
9295
|
-
|
|
8763
|
+
this.chart.isTimeframeAllowed(e) && (this.chosenTimeframe = e, this.rangeSeq++, await this.switchTimeframe(e));
|
|
8764
|
+
}
|
|
8765
|
+
async switchTimeframe(e) {
|
|
8766
|
+
if (this.state = {
|
|
8767
|
+
...this.state,
|
|
8768
|
+
timeframe: e
|
|
8769
|
+
}, this.options.onTimeframeChange?.(e), this.updateUI(), this.layoutSession?.changed(), this.adapter) {
|
|
8770
|
+
await this.connectStream();
|
|
8771
|
+
return;
|
|
8772
|
+
}
|
|
8773
|
+
if (this.options.resampleTimeframes !== !1) {
|
|
8774
|
+
if (!this.baseSeries) {
|
|
8775
|
+
let e = this.chart.getData();
|
|
8776
|
+
e.length > 0 && (this.baseSeries = e, this.baseTimeframeMs = Pe(e));
|
|
9296
8777
|
}
|
|
8778
|
+
await this.switchLocalTimeframe();
|
|
9297
8779
|
}
|
|
9298
8780
|
}
|
|
9299
8781
|
setTheme(e) {
|
|
@@ -9328,7 +8810,7 @@ var Ha = [
|
|
|
9328
8810
|
if (!this.destroyed) {
|
|
9329
8811
|
this.destroyed = !0, this.boundGlobalKeydown && document.removeEventListener("keydown", this.boundGlobalKeydown), document.removeEventListener("fullscreenchange", this.onFullscreenChange), this.unregisterKeys(), this.tooltip.destroy(), this.legendFrame && cancelAnimationFrame(this.legendFrame), this.indicatorLegend?.destroy(), this.portal.remove(), document.fullscreenElement === this.root && document.exitFullscreen().catch(() => {}), this.flushActiveLayout(), this.commandPalette?.destroy(), this.symbolSearch?.destroy(), this.hotkeySheet?.destroy(), this.replayPollInterval && clearInterval(this.replayPollInterval), this.replayShade?.remove(), this.replayBar?.destroy(), this.dragDrop?.detach(), this.alertsPanel?.destroy(), this.objectTree?.destroy(), this.indicatorSettings?.destroy(), this.drawingStyle?.destroy(), this.drawingSettings?.destroy(), this.drawingMenu?.destroy(), this.selectionToolbar?.destroy(), this.selectionToolbarFrame !== null && cancelAnimationFrame(this.selectionToolbarFrame), this.chartMenu?.destroy(), this.legendMenu?.destroy();
|
|
9330
8812
|
for (let e of this.hostMenus) e.destroy();
|
|
9331
|
-
this.hostMenus.clear(), this.templatePrompt?.destroy(), this.intervalInput?.destroy(), this.markerTip?.remove(), this.layoutSession?.destroy(), this.layoutsUI?.destroy(), this.accountPanel?.destroy(), this.orderTicket?.destroy(), this.accountFrame && cancelAnimationFrame(this.accountFrame), this.bracketBar?.destroy(), this.alertNotifier?.destroy(), this.depthLadder?.destroy(), this.dataWindow?.destroy(), this.watchlistInterval && clearInterval(this.watchlistInterval), this.marketTimer && clearInterval(this.marketTimer), this.chartNav?.destroy(), this.symbolInfoPanel?.destroy(), this.stopQuotes?.(), this.stopQuotes = null, this.watchlist?.destroy(), this.toolbar?.destroy(), this.sidebar?.destroy(), this.settings?.destroy(), this.statusBar?.destroy(), this.goToDate?.destroy(), this.loading.destroy(), this.historyPill.destroy(), this.chart.destroy(), this.root.remove(),
|
|
8813
|
+
this.hostMenus.clear(), this.templatePrompt?.destroy(), this.intervalInput?.destroy(), this.markerTip?.remove(), this.layoutSession?.destroy(), this.layoutsUI?.destroy(), this.accountPanel?.destroy(), this.orderTicket?.destroy(), this.accountFrame && cancelAnimationFrame(this.accountFrame), this.bracketBar?.destroy(), this.alertNotifier?.destroy(), this.depthLadder?.destroy(), this.dataWindow?.destroy(), this.watchlistInterval && clearInterval(this.watchlistInterval), this.marketTimer && clearInterval(this.marketTimer), this.chartNav?.destroy(), this.symbolInfoPanel?.destroy(), this.stopQuotes?.(), this.stopQuotes = null, this.watchlist?.destroy(), this.toolbar?.destroy(), this.sidebar?.destroy(), this.settings?.destroy(), this.statusBar?.destroy(), this.goToDate?.destroy(), this.loading.destroy(), this.historyPill.destroy(), this.chart.destroy(), this.root.remove(), gt();
|
|
9332
8814
|
}
|
|
9333
8815
|
}
|
|
9334
8816
|
handleSymbolClick() {
|
|
@@ -9345,6 +8827,48 @@ var Ha = [
|
|
|
9345
8827
|
handleTimeframe(e) {
|
|
9346
8828
|
this.setTimeframe(e);
|
|
9347
8829
|
}
|
|
8830
|
+
applyRangePreset(e) {
|
|
8831
|
+
let t = ++this.rangeSeq;
|
|
8832
|
+
return this.rangeQueue = this.rangeQueue.then(() => this.runRangePreset(e, t)).catch((e) => {
|
|
8833
|
+
this.say(e instanceof Error ? e.message : String(e), "error");
|
|
8834
|
+
}), this.rangeQueue;
|
|
8835
|
+
}
|
|
8836
|
+
async runRangePreset(e, t) {
|
|
8837
|
+
let n = () => t === this.rangeSeq && !this.destroyed;
|
|
8838
|
+
if (!n()) return;
|
|
8839
|
+
this.chosenTimeframe ??= this.state.timeframe;
|
|
8840
|
+
let r = this.featureState["statusBar.rangeTimeframe"] ? this.timeframeForPreset(e) : this.state.timeframe;
|
|
8841
|
+
r !== this.state.timeframe && (await this.switchTimeframe(r), !n() || this.adapter && this.state.connectionState === "error") || this.chart.setVisibleRangePreset(e);
|
|
8842
|
+
}
|
|
8843
|
+
timeframeForPreset(e) {
|
|
8844
|
+
let t = this.state.timeframe, n = this.chart.getData();
|
|
8845
|
+
if (n.length < 2) return t;
|
|
8846
|
+
let r = S(n), i = n[n.length - 1].time * r, a = e === "All" ? n[0].time * r : ke(e, i, this.displayTimezone());
|
|
8847
|
+
if (a === null) return t;
|
|
8848
|
+
let o = n.length - 1;
|
|
8849
|
+
for (; o > 0 && n[o - 1].time * r >= a;) o--;
|
|
8850
|
+
let s = this.displayTimezone();
|
|
8851
|
+
return Ti({
|
|
8852
|
+
dayShare: n.slice(-$a).some((e) => {
|
|
8853
|
+
let t = e.time * r, n = new Date(t + ue(s, t) * 6e4).getUTCDay();
|
|
8854
|
+
return n === 0 || n === 6;
|
|
8855
|
+
}) ? 1 : 5 / 7,
|
|
8856
|
+
spanMs: i - a,
|
|
8857
|
+
barsInSpan: n.length - o,
|
|
8858
|
+
width: this.chart.getPlotRect().width,
|
|
8859
|
+
current: t,
|
|
8860
|
+
chosen: this.chosenTimeframe ?? t,
|
|
8861
|
+
available: this.timeframes.filter((e) => this.chart.isTimeframeAllowed(e) && this.canShowTimeframe(e))
|
|
8862
|
+
});
|
|
8863
|
+
}
|
|
8864
|
+
canShowTimeframe(e) {
|
|
8865
|
+
if (this.adapter) return Ae(this.adapter, e);
|
|
8866
|
+
if (this.options.resampleTimeframes === !1) return !1;
|
|
8867
|
+
let t = this.chart.getData();
|
|
8868
|
+
if (t.length < 2) return !1;
|
|
8869
|
+
let n = this.baseSeries ? this.baseTimeframeMs : Pe(t);
|
|
8870
|
+
return !(n > 0) || w(e) >= n;
|
|
8871
|
+
}
|
|
9348
8872
|
toggleFullscreen() {
|
|
9349
8873
|
if (document.fullscreenElement === this.root) {
|
|
9350
8874
|
document.exitFullscreen().catch(() => {});
|
|
@@ -9383,7 +8907,7 @@ var Ha = [
|
|
|
9383
8907
|
e.hide();
|
|
9384
8908
|
return;
|
|
9385
8909
|
}
|
|
9386
|
-
let i = this.chartOffset(), a = this.chart.getPlotRect(), o =
|
|
8910
|
+
let i = this.chartOffset(), a = this.chart.getPlotRect(), o = uo(r.map((e) => this.chart.getDrawingRect(e.id))) ?? {
|
|
9387
8911
|
x: a.x + a.width / 2,
|
|
9388
8912
|
y: a.y,
|
|
9389
8913
|
width: 0,
|
|
@@ -9440,11 +8964,11 @@ var Ha = [
|
|
|
9440
8964
|
}] : [];
|
|
9441
8965
|
});
|
|
9442
8966
|
if (i.length === 0) return;
|
|
9443
|
-
let a =
|
|
8967
|
+
let a = ft(Lr({
|
|
9444
8968
|
selected: i,
|
|
9445
8969
|
canConfigure: this.drawingSettings !== null,
|
|
9446
8970
|
canAlert: this.chart.canAddDrawingAlert(e)
|
|
9447
|
-
}, this.t),
|
|
8971
|
+
}, this.t), nt, this.featureState), o = i.map((e) => e.id), s = r.get(e), c = s ? this.options.drawingMenuItems?.({
|
|
9448
8972
|
id: e,
|
|
9449
8973
|
type: s.type,
|
|
9450
8974
|
selected: o
|
|
@@ -9527,7 +9051,7 @@ var Ha = [
|
|
|
9527
9051
|
let t = this.featureState;
|
|
9528
9052
|
this.featureState = {
|
|
9529
9053
|
...t,
|
|
9530
|
-
|
|
9054
|
+
...it(e)
|
|
9531
9055
|
};
|
|
9532
9056
|
let n = (e) => t[e] !== this.featureState[e];
|
|
9533
9057
|
this.markSwitchedOff(), this.closeSwitchedOff((e) => t[e] && !this.featureState[e]), n("selectionToolbar") && this.updateSelectionToolbar(), n("indicatorLegend") && (this.chart.setPaneTitlesVisible(!this.featureState.indicatorLegend), this.scheduleLegend()), n("menu.priceAxisAdd") && this.chart.setFeatures({ priceAxisAddButton: this.priceAxisAddDefault && this.featureState["menu.priceAxisAdd"] }), n("dragDropImport") && (this.featureState.dragDropImport ? this.dragDrop?.attach() : this.dragDrop?.detach()), [
|
|
@@ -9608,7 +9132,7 @@ var Ha = [
|
|
|
9608
9132
|
}
|
|
9609
9133
|
}
|
|
9610
9134
|
markSwitchedOff() {
|
|
9611
|
-
let e =
|
|
9135
|
+
let e = ot(this.featureState);
|
|
9612
9136
|
for (let t of [this.root, this.portal]) e ? t.dataset.tcwOff = e : delete t.dataset.tcwOff;
|
|
9613
9137
|
this.toolbar?.setSymbolSearch(this.featureState.symbolSearch), this.toolbar?.tidy(), this.sidebar?.tidy();
|
|
9614
9138
|
}
|
|
@@ -9617,8 +9141,8 @@ var Ha = [
|
|
|
9617
9141
|
let t = this.toolbar, n = t.addHostButton(e);
|
|
9618
9142
|
return t.tidy(), {
|
|
9619
9143
|
element: n,
|
|
9620
|
-
setActive: (t) =>
|
|
9621
|
-
setText: (t) =>
|
|
9144
|
+
setActive: (t) => kt(n, t, e.toggle === !0),
|
|
9145
|
+
setText: (t) => At(n, e.label, t),
|
|
9622
9146
|
remove: () => {
|
|
9623
9147
|
n.remove(), t.tidy();
|
|
9624
9148
|
}
|
|
@@ -9648,7 +9172,7 @@ var Ha = [
|
|
|
9648
9172
|
});
|
|
9649
9173
|
return r.setAttribute("aria-haspopup", "menu"), r.setAttribute("aria-expanded", "false"), t.tidy(), {
|
|
9650
9174
|
element: r,
|
|
9651
|
-
setText: (t) =>
|
|
9175
|
+
setText: (t) => At(r, e.label, t),
|
|
9652
9176
|
remove: () => {
|
|
9653
9177
|
n.destroy(), this.hostMenus.delete(n), r.remove(), t.tidy();
|
|
9654
9178
|
}
|
|
@@ -9660,7 +9184,7 @@ var Ha = [
|
|
|
9660
9184
|
let n = t.addHostButton(e);
|
|
9661
9185
|
return {
|
|
9662
9186
|
element: n,
|
|
9663
|
-
setActive: (t) =>
|
|
9187
|
+
setActive: (t) => kt(n, t, e.toggle === !0),
|
|
9664
9188
|
remove: () => {
|
|
9665
9189
|
n.remove(), t.tidy();
|
|
9666
9190
|
}
|
|
@@ -9812,7 +9336,7 @@ var Ha = [
|
|
|
9812
9336
|
}), this.say(p(this.t(`order.${e}`), { price: this.formatAlertPrice(t) }));
|
|
9813
9337
|
}
|
|
9814
9338
|
displayTimezone() {
|
|
9815
|
-
let e =
|
|
9339
|
+
let e = Ie(this.settingsState.timezone);
|
|
9816
9340
|
return e === "exchange" ? this.chart.getEffectiveTimezone() : e;
|
|
9817
9341
|
}
|
|
9818
9342
|
toggleGoToDate() {
|
|
@@ -9837,14 +9361,14 @@ var Ha = [
|
|
|
9837
9361
|
timeframeMenu() {
|
|
9838
9362
|
return this.timeframes.map((e) => ({
|
|
9839
9363
|
value: e,
|
|
9840
|
-
label:
|
|
9364
|
+
label: pi(e),
|
|
9841
9365
|
custom: this.customTimeframes.has(e)
|
|
9842
9366
|
}));
|
|
9843
9367
|
}
|
|
9844
9368
|
handleAddTimeframe(e) {
|
|
9845
9369
|
if (!this.featureState.customTimeframes) return !1;
|
|
9846
|
-
let t =
|
|
9847
|
-
return !t || !this.chart.isTimeframeAllowed(t) || this.adapter && !
|
|
9370
|
+
let t = xi(e);
|
|
9371
|
+
return !t || !this.chart.isTimeframeAllowed(t) || this.adapter && !Ae(this.adapter, t) || !this.adapter && C(t) !== null ? !1 : (this.timeframes.includes(t) || (this.customTimeframes.add(t), this.timeframeFavorites.add(t), this.timeframes = Si(this.timeframes, [t]), this.toolbar?.setTimeframes(this.timeframeMenu(), this.pinnedTimeframes())), this.handleTimeframe(t), !0);
|
|
9848
9372
|
}
|
|
9849
9373
|
showMarkerTip(e) {
|
|
9850
9374
|
let { marker: t } = e;
|
|
@@ -9863,7 +9387,7 @@ var Ha = [
|
|
|
9863
9387
|
this.markerTip.style.left = `${l}px`, this.markerTip.style.top = `${u}px`;
|
|
9864
9388
|
}
|
|
9865
9389
|
selectTypedTimeframe(e) {
|
|
9866
|
-
return !this.chart.isTimeframeAllowed(e) || !this.timeframes.includes(e) && !this.featureState.customTimeframes || this.adapter && !
|
|
9390
|
+
return !this.chart.isTimeframeAllowed(e) || !this.timeframes.includes(e) && !this.featureState.customTimeframes || this.adapter && !Ae(this.adapter, e) ? !1 : (this.timeframes.includes(e) || (this.customTimeframes.add(e), this.timeframes = Si(this.timeframes, [e]), this.toolbar?.setTimeframes(this.timeframeMenu(), this.pinnedTimeframes())), this.handleTimeframe(e), !0);
|
|
9867
9391
|
}
|
|
9868
9392
|
applyIndicatorTemplate(e) {
|
|
9869
9393
|
if (!this.featureState.indicatorTemplates) return;
|
|
@@ -9876,7 +9400,7 @@ var Ha = [
|
|
|
9876
9400
|
this.say(this.t("templates.nothing"), "error");
|
|
9877
9401
|
return;
|
|
9878
9402
|
}
|
|
9879
|
-
this.templatePrompt ??= new
|
|
9403
|
+
this.templatePrompt ??= new ai(this.root, this.t), this.templatePrompt.open({
|
|
9880
9404
|
title: this.t("templates.saveTitle"),
|
|
9881
9405
|
submitLabel: this.t("common.save"),
|
|
9882
9406
|
placeholder: this.t("templates.namePlaceholder"),
|
|
@@ -9898,7 +9422,7 @@ var Ha = [
|
|
|
9898
9422
|
this.timeframeFavorites.toggle(e), this.toolbar?.setTimeframeFavorites(this.pinnedTimeframes()), this.updateUI();
|
|
9899
9423
|
}
|
|
9900
9424
|
setData(e) {
|
|
9901
|
-
this.localSeq++, this.baseSeries = e, this.baseTimeframeMs =
|
|
9425
|
+
this.localSeq++, this.baseSeries = e, this.baseTimeframeMs = Pe(e), this.applyTimeframeData(), this.adapter || this.loading.end();
|
|
9902
9426
|
}
|
|
9903
9427
|
async switchLocalTimeframe() {
|
|
9904
9428
|
if (!this.baseSeries) return;
|
|
@@ -9915,7 +9439,7 @@ var Ha = [
|
|
|
9915
9439
|
let e = performance.now(), t = w(this.state.timeframe);
|
|
9916
9440
|
if (this.baseTimeframeMs > 0 && t > this.baseTimeframeMs) {
|
|
9917
9441
|
let e = this.options.weekStartsOn ?? 1;
|
|
9918
|
-
this.chart.setData(
|
|
9442
|
+
this.chart.setData(Ne(this.baseSeries, this.state.timeframe, { weekStartsOn: e }));
|
|
9919
9443
|
} else this.chart.setData(this.baseSeries);
|
|
9920
9444
|
this.lastLocalSwitchMs = performance.now() - e;
|
|
9921
9445
|
}
|
|
@@ -10045,7 +9569,7 @@ var Ha = [
|
|
|
10045
9569
|
defaults: n.descriptor.defaultConfig,
|
|
10046
9570
|
params: n.params,
|
|
10047
9571
|
inputs: n.descriptor.inputs,
|
|
10048
|
-
lineSources:
|
|
9572
|
+
lineSources: to(e, t),
|
|
10049
9573
|
plots: n.descriptor.plots,
|
|
10050
9574
|
colors: r?.colors,
|
|
10051
9575
|
lineWidth: r?.lineWidths[0],
|
|
@@ -10062,7 +9586,7 @@ var Ha = [
|
|
|
10062
9586
|
visible: e.visible
|
|
10063
9587
|
})), t = this.chart.getDrawings().map((e) => ({
|
|
10064
9588
|
id: e.id,
|
|
10065
|
-
label:
|
|
9589
|
+
label: tr(e.type, this.t),
|
|
10066
9590
|
visible: e.visible,
|
|
10067
9591
|
locked: e.locked,
|
|
10068
9592
|
group: e.group
|
|
@@ -10145,7 +9669,7 @@ var Ha = [
|
|
|
10145
9669
|
if (this.compares.some((t) => t.symbol === e)) return;
|
|
10146
9670
|
let n = Ha[this.compares.length % Ha.length], r = `cmp_${e}`;
|
|
10147
9671
|
try {
|
|
10148
|
-
let t = await
|
|
9672
|
+
let t = await Me(this.adapter).fetchHistory(e, this.state.timeframe, this.options.historyLimit ?? 500);
|
|
10149
9673
|
this.compares.length === 0 && this.chart.setCompareMode("percent"), this.chart.addCompareSymbol(r, e, t, n), this.compares = [...this.compares, {
|
|
10150
9674
|
id: r,
|
|
10151
9675
|
symbol: e,
|
|
@@ -10167,7 +9691,7 @@ var Ha = [
|
|
|
10167
9691
|
this.symbolLoads.set(e, n);
|
|
10168
9692
|
let r = () => this.destroyed || t !== this.state.timeframe || this.symbolLoads.get(e) !== n;
|
|
10169
9693
|
try {
|
|
10170
|
-
let n = Math.max(this.chart.getData().length, this.options.historyLimit ?? 500), i = await
|
|
9694
|
+
let n = Math.max(this.chart.getData().length, this.options.historyLimit ?? 500), i = await Me(this.adapter).fetchHistory(e, t, n);
|
|
10171
9695
|
if (r()) return;
|
|
10172
9696
|
this.chart.setSymbolSeries(e, i);
|
|
10173
9697
|
} catch (t) {
|
|
@@ -10181,7 +9705,7 @@ var Ha = [
|
|
|
10181
9705
|
let e = this.compares.filter((e) => e.symbol === this.state.symbol);
|
|
10182
9706
|
for (let t of e) this.handleRemoveCompare(t.id);
|
|
10183
9707
|
for (let e of this.compares) try {
|
|
10184
|
-
let t = await
|
|
9708
|
+
let t = await Me(this.adapter).fetchHistory(e.symbol, this.state.timeframe, this.options.historyLimit ?? 500);
|
|
10185
9709
|
this.chart.updateCompareData(e.id, t);
|
|
10186
9710
|
} catch {}
|
|
10187
9711
|
}
|
|
@@ -10210,7 +9734,7 @@ var Ha = [
|
|
|
10210
9734
|
};
|
|
10211
9735
|
}
|
|
10212
9736
|
alertText(e) {
|
|
10213
|
-
return
|
|
9737
|
+
return jn(this.alertListItem(e, this.buildAlertSources()), this.t, (e) => this.formatAlertPrice(e), !0);
|
|
10214
9738
|
}
|
|
10215
9739
|
buildAlertSources() {
|
|
10216
9740
|
let e = [{
|
|
@@ -10275,19 +9799,19 @@ var Ha = [
|
|
|
10275
9799
|
}
|
|
10276
9800
|
buildCommandItems() {
|
|
10277
9801
|
let e = [];
|
|
10278
|
-
for (let t of
|
|
9802
|
+
for (let t of Ve) e.push({
|
|
10279
9803
|
id: t.id,
|
|
10280
9804
|
label: t.name,
|
|
10281
9805
|
category: "indicator",
|
|
10282
9806
|
active: [...this.state.activeIndicators.values()].some((e) => e.id === t.id)
|
|
10283
9807
|
});
|
|
10284
|
-
for (let t of
|
|
9808
|
+
for (let t of ze) e.push({
|
|
10285
9809
|
id: t.value,
|
|
10286
|
-
label:
|
|
9810
|
+
label: wt(t, this.t),
|
|
10287
9811
|
category: "chartType",
|
|
10288
9812
|
active: this.state.chartType === t.value
|
|
10289
9813
|
});
|
|
10290
|
-
for (let t of
|
|
9814
|
+
for (let t of Tt(Be, this.t)) for (let n of t.tools) e.push({
|
|
10291
9815
|
id: n.value,
|
|
10292
9816
|
label: n.label,
|
|
10293
9817
|
category: "drawing",
|
|
@@ -10295,7 +9819,7 @@ var Ha = [
|
|
|
10295
9819
|
});
|
|
10296
9820
|
for (let t of this.timeframes) e.push({
|
|
10297
9821
|
id: t,
|
|
10298
|
-
label:
|
|
9822
|
+
label: pi(t),
|
|
10299
9823
|
category: "timeframe",
|
|
10300
9824
|
active: this.state.timeframe === t
|
|
10301
9825
|
});
|
|
@@ -10339,7 +9863,7 @@ var Ha = [
|
|
|
10339
9863
|
}), e.filter((e) => e.category !== "action" || this.commandOn(e.id));
|
|
10340
9864
|
}
|
|
10341
9865
|
commandOn(e) {
|
|
10342
|
-
let t =
|
|
9866
|
+
let t = ut(e);
|
|
10343
9867
|
return t === void 0 || this.featureState[t];
|
|
10344
9868
|
}
|
|
10345
9869
|
handleAction(e) {
|
|
@@ -10422,14 +9946,20 @@ var Ha = [
|
|
|
10422
9946
|
chartTypeOptions: this.chart.getChartTypeOptions?.() ?? {}
|
|
10423
9947
|
}, this.settings?.open(this.settingsState, this.state.chartType));
|
|
10424
9948
|
}
|
|
10425
|
-
toast(e, t = "info") {
|
|
10426
|
-
let
|
|
10427
|
-
|
|
10428
|
-
|
|
9949
|
+
toast(e, t = "info", n) {
|
|
9950
|
+
let r = document.createElement("div");
|
|
9951
|
+
r.className = `tcw-toast ${t === "error" ? "tcw-toast-error" : ""}`, r.setAttribute("role", t === "error" ? "alert" : "status");
|
|
9952
|
+
let i = n ? j(n, 14) : "";
|
|
9953
|
+
if (i) {
|
|
9954
|
+
let e = document.createElement("span");
|
|
9955
|
+
e.className = "tcw-toast-icon", e.innerHTML = i, r.appendChild(e);
|
|
9956
|
+
}
|
|
9957
|
+
r.appendChild(document.createTextNode(e)), this.root.appendChild(r), requestAnimationFrame(() => r.classList.add("tcw-toast-in")), setTimeout(() => {
|
|
9958
|
+
r.classList.remove("tcw-toast-in"), r.addEventListener("transitionend", () => r.remove(), { once: !0 }), setTimeout(() => r.remove(), 400);
|
|
10429
9959
|
}, 3500);
|
|
10430
9960
|
}
|
|
10431
|
-
say(e, t = "info") {
|
|
10432
|
-
(this.featureState.toasts || t === "error") && this.toast(e, t);
|
|
9961
|
+
say(e, t = "info", n) {
|
|
9962
|
+
(this.featureState.toasts || t === "error") && this.toast(e, t, n);
|
|
10433
9963
|
}
|
|
10434
9964
|
getLayoutSession() {
|
|
10435
9965
|
return this.layoutSession;
|
|
@@ -10445,7 +9975,7 @@ var Ha = [
|
|
|
10445
9975
|
return {
|
|
10446
9976
|
v: 1,
|
|
10447
9977
|
symbol: this.state.symbol,
|
|
10448
|
-
timeframe: this.state.timeframe,
|
|
9978
|
+
timeframe: this.chosenTimeframe ?? this.state.timeframe,
|
|
10449
9979
|
scaleMode: this.settingsState.scaleMode,
|
|
10450
9980
|
invertScale: this.settingsState.invertScale,
|
|
10451
9981
|
chart: n
|
|
@@ -10479,7 +10009,7 @@ var Ha = [
|
|
|
10479
10009
|
capture: () => ({
|
|
10480
10010
|
content: this.getLayoutContent(),
|
|
10481
10011
|
symbol: this.state.symbol,
|
|
10482
|
-
timeframe: this.state.timeframe
|
|
10012
|
+
timeframe: this.chosenTimeframe ?? this.state.timeframe
|
|
10483
10013
|
}),
|
|
10484
10014
|
apply: async (e) => {
|
|
10485
10015
|
if (!await this.applyLayoutContent(e.content)) throw Error("Not a widget layout");
|
|
@@ -10490,7 +10020,7 @@ var Ha = [
|
|
|
10490
10020
|
onChange: () => this.toolbar?.setLayout(t.current()?.name ?? null, t.isDirty()),
|
|
10491
10021
|
onError: () => this.say(this.t("layouts.saveFailed"), "error")
|
|
10492
10022
|
});
|
|
10493
|
-
this.layoutSession = t, this.layoutsUI = new
|
|
10023
|
+
this.layoutSession = t, this.layoutsUI = new li(t, {
|
|
10494
10024
|
root: this.root,
|
|
10495
10025
|
t: this.t,
|
|
10496
10026
|
toast: (e, t) => this.say(e, t),
|
|
@@ -10547,7 +10077,7 @@ var Ha = [
|
|
|
10547
10077
|
enterReplay() {
|
|
10548
10078
|
if (this.replayTotal() < 2) return;
|
|
10549
10079
|
let e = this.t;
|
|
10550
|
-
this.replayBar = new
|
|
10080
|
+
this.replayBar = new sn({
|
|
10551
10081
|
onPlay: () => {
|
|
10552
10082
|
if (this.replayBar?.getMode() === "select") {
|
|
10553
10083
|
this.startReplayAt(Math.max(1, this.replayTotal() - 100), !0);
|
|
@@ -10636,7 +10166,7 @@ var Ha = [
|
|
|
10636
10166
|
let e = w(this.state.timeframe);
|
|
10637
10167
|
return qa.filter((t) => {
|
|
10638
10168
|
let n = w(t);
|
|
10639
|
-
return !(n < e) || e % n !== 0 ? !1 : this.adapter ?
|
|
10169
|
+
return !(n < e) || e % n !== 0 ? !1 : this.adapter ? Ae(this.adapter, t) : this.baseSeries !== null && this.baseTimeframeMs > 0 && n >= this.baseTimeframeMs && n % this.baseTimeframeMs === 0;
|
|
10640
10170
|
});
|
|
10641
10171
|
}
|
|
10642
10172
|
async replayStepsFor(e) {
|
|
@@ -10646,11 +10176,11 @@ var Ha = [
|
|
|
10646
10176
|
if (this.adapter) {
|
|
10647
10177
|
let t = Math.max(1, Math.round(w(this.state.timeframe) / w(e))), r = Math.min(Ja, Math.max(this.chart.getData().length, 100) * t);
|
|
10648
10178
|
try {
|
|
10649
|
-
n = await
|
|
10179
|
+
n = await Me(this.adapter).fetchHistory(this.state.symbol, e, r);
|
|
10650
10180
|
} catch {
|
|
10651
10181
|
n = null;
|
|
10652
10182
|
}
|
|
10653
|
-
} else this.baseSeries && (n = w(e) === this.baseTimeframeMs ? this.baseSeries :
|
|
10183
|
+
} else this.baseSeries && (n = w(e) === this.baseTimeframeMs ? this.baseSeries : Ne(this.baseSeries, e));
|
|
10654
10184
|
return !n || n.length === 0 ? null : (this.replayStepsCache = {
|
|
10655
10185
|
key: t,
|
|
10656
10186
|
steps: n
|
|
@@ -10708,7 +10238,7 @@ var Ha = [
|
|
|
10708
10238
|
}) : (this.chart.setScaleMode(e.scaleMode), this.settingsState = {
|
|
10709
10239
|
...this.settingsState,
|
|
10710
10240
|
logScale: e.scaleMode === "logarithmic"
|
|
10711
|
-
}), e.numberLocale !== void 0 && (this.chart.setNumberLocale(e.numberLocale), this.watchlist?.setLocale(e.numberLocale || void 0)), e.timezone !== void 0 && this.chart.setTimezone(
|
|
10241
|
+
}), e.numberLocale !== void 0 && (this.chart.setNumberLocale(e.numberLocale), this.watchlist?.setLocale(e.numberLocale || void 0)), e.timezone !== void 0 && this.chart.setTimezone(Ie(e.timezone)), e.highLowLines !== void 0 && this.chart.setHighLowLines(e.highLowLines), e.extendedHours !== void 0 && this.chart.setExtendedHours(e.extendedHours), e.mainSeriesVisible !== void 0 && this.chart.setMainSeriesVisible(e.mainSeriesVisible), e.chartTypeOptions !== void 0 && this.chart.setChartTypeOptions({
|
|
10712
10242
|
renko: {},
|
|
10713
10243
|
lineBreak: {},
|
|
10714
10244
|
kagi: {},
|
|
@@ -10719,7 +10249,7 @@ var Ha = [
|
|
|
10719
10249
|
}
|
|
10720
10250
|
resetSettings() {
|
|
10721
10251
|
let e = { ...this.settingsState }, t = this.settingsStyle(), n = { ...this.settingsDefaults };
|
|
10722
|
-
this.applySettings(n), this.chart.resetOverrides([...
|
|
10252
|
+
this.applySettings(n), this.chart.resetOverrides([...Ze], { layer: "user" });
|
|
10723
10253
|
let r = { ...this.settingsState }, i = this.settingsStyle();
|
|
10724
10254
|
this.settings?.refresh(this.settingsState), JSON.stringify([e, t]) !== JSON.stringify([r, i]) && this.chart.recordUndo({
|
|
10725
10255
|
undo: () => this.restoreSettings(e, t),
|
|
@@ -10748,7 +10278,7 @@ var Ha = [
|
|
|
10748
10278
|
redo: () => this.restoreSettings(i)
|
|
10749
10279
|
});
|
|
10750
10280
|
}
|
|
10751
|
-
settingsStyle(e =
|
|
10281
|
+
settingsStyle(e = Ze) {
|
|
10752
10282
|
let t = this.chart.getOverrides?.({ layer: "user" }) ?? {}, n = Object.fromEntries(e.map((e) => {
|
|
10753
10283
|
let n = t[e];
|
|
10754
10284
|
return [e, typeof n == "string" || typeof n == "boolean" || typeof n == "number" ? n : null];
|
|
@@ -10902,7 +10432,7 @@ var Ha = [
|
|
|
10902
10432
|
return e === void 0 || e === "dark" ? !0 : e === "light" ? !1 : typeof e == "object" && e.background ? this.isColorDark(e.background) : !0;
|
|
10903
10433
|
}
|
|
10904
10434
|
resolveTheme(e) {
|
|
10905
|
-
return e === void 0 || e === "dark" ?
|
|
10435
|
+
return e === void 0 || e === "dark" ? v : e === "light" ? te : typeof e == "object" ? e : v;
|
|
10906
10436
|
}
|
|
10907
10437
|
isColorDark(e) {
|
|
10908
10438
|
if (e.startsWith("#") && e.length >= 7) {
|
|
@@ -10912,10 +10442,10 @@ var Ha = [
|
|
|
10912
10442
|
return !0;
|
|
10913
10443
|
}
|
|
10914
10444
|
};
|
|
10915
|
-
function
|
|
10445
|
+
function to(t, n) {
|
|
10916
10446
|
let r = (e) => {
|
|
10917
|
-
let t =
|
|
10918
|
-
return t &&
|
|
10447
|
+
let t = je(e.descriptor);
|
|
10448
|
+
return t && de(e.params[t])?.instanceId || null;
|
|
10919
10449
|
}, i = new Set([t]);
|
|
10920
10450
|
for (let e = !0; e;) {
|
|
10921
10451
|
e = !1;
|
|
@@ -10929,25 +10459,25 @@ function eo(t, n) {
|
|
|
10929
10459
|
if (i.has(t.instanceId)) continue;
|
|
10930
10460
|
let n = e(t.id, t.params, t.descriptor.defaultConfig, t.descriptor.shortName);
|
|
10931
10461
|
for (let e of t.descriptor.plots ?? []) a.push({
|
|
10932
|
-
value:
|
|
10462
|
+
value: oe(t.instanceId, e.key),
|
|
10933
10463
|
label: `${n}: ${e.title}`
|
|
10934
10464
|
});
|
|
10935
10465
|
}
|
|
10936
10466
|
return a;
|
|
10937
10467
|
}
|
|
10938
|
-
function
|
|
10468
|
+
function no() {
|
|
10939
10469
|
try {
|
|
10940
10470
|
return typeof localStorage < "u" ? localStorage : null;
|
|
10941
10471
|
} catch {
|
|
10942
10472
|
return null;
|
|
10943
10473
|
}
|
|
10944
10474
|
}
|
|
10945
|
-
var
|
|
10946
|
-
function
|
|
10475
|
+
var ro = 10, io = 5 * 6e4, ao = 864e5;
|
|
10476
|
+
function oo(e, t) {
|
|
10947
10477
|
if (e.length === 0) return null;
|
|
10948
|
-
let n = t &&
|
|
10478
|
+
let n = t && ce(t) ? t : null, r = S(e), i = (e) => {
|
|
10949
10479
|
let t = e * r;
|
|
10950
|
-
return Math.floor((t + (n ?
|
|
10480
|
+
return Math.floor((t + (n ? xe(n, t) * 6e4 : 0)) / ao);
|
|
10951
10481
|
}, a = e[e.length - 1], o = i(a.time), s = e.length - 1;
|
|
10952
10482
|
for (; s > 0 && i(e[s - 1].time) === o;) s--;
|
|
10953
10483
|
let c = -Infinity, l = Infinity, u = 0;
|
|
@@ -10961,7 +10491,7 @@ function ao(e, t) {
|
|
|
10961
10491
|
prevClose: s > 0 ? e[s - 1].close : void 0
|
|
10962
10492
|
};
|
|
10963
10493
|
}
|
|
10964
|
-
function
|
|
10494
|
+
function so(e, t) {
|
|
10965
10495
|
let n = e / 6e4, [r, i] = Math.abs(n) < 60 ? [Math.round(n) || Math.sign(n) || 1, "minute"] : Math.abs(n) < 1440 ? [Math.round(n / 60), "hour"] : [Math.round(n / 1440), "day"];
|
|
10966
10496
|
try {
|
|
10967
10497
|
return new Intl.RelativeTimeFormat(t, { numeric: "auto" }).format(r, i);
|
|
@@ -10969,7 +10499,7 @@ function oo(e, t) {
|
|
|
10969
10499
|
return new Intl.RelativeTimeFormat("en", { numeric: "auto" }).format(r, i);
|
|
10970
10500
|
}
|
|
10971
10501
|
}
|
|
10972
|
-
function
|
|
10502
|
+
function co(e, t) {
|
|
10973
10503
|
try {
|
|
10974
10504
|
return new Intl.NumberFormat(t, {
|
|
10975
10505
|
notation: "compact",
|
|
@@ -10979,7 +10509,7 @@ function so(e, t) {
|
|
|
10979
10509
|
return String(e);
|
|
10980
10510
|
}
|
|
10981
10511
|
}
|
|
10982
|
-
function
|
|
10512
|
+
function lo(e, t) {
|
|
10983
10513
|
let n = e?.sessions ?? [];
|
|
10984
10514
|
if (n.length === 0) return;
|
|
10985
10515
|
let r;
|
|
@@ -11006,7 +10536,7 @@ function co(e, t) {
|
|
|
11006
10536
|
};
|
|
11007
10537
|
return n.map((e) => [`${e.start}–${e.end}`, i(e.days)].filter(Boolean).join(" ")).join(", ");
|
|
11008
10538
|
}
|
|
11009
|
-
function
|
|
10539
|
+
function uo(e) {
|
|
11010
10540
|
let t = e.filter((e) => e !== null);
|
|
11011
10541
|
if (t.length === 0) return null;
|
|
11012
10542
|
let n = Math.min(...t.map((e) => e.x)), r = Math.min(...t.map((e) => e.y)), i = Math.max(...t.map((e) => e.x + e.width)), a = Math.max(...t.map((e) => e.y + e.height));
|
|
@@ -11017,19 +10547,19 @@ function lo(e) {
|
|
|
11017
10547
|
height: a - r
|
|
11018
10548
|
};
|
|
11019
10549
|
}
|
|
11020
|
-
function
|
|
10550
|
+
function fo(e) {
|
|
11021
10551
|
return !!e && /^(ar|he|iw|fa|ur|ps|yi|dv|ckb|sd|ug)(-|$)/i.test(e);
|
|
11022
10552
|
}
|
|
11023
10553
|
//#endregion
|
|
11024
10554
|
//#region src/widget/ChartWidgetGrid.ts
|
|
11025
|
-
var
|
|
10555
|
+
var po = {
|
|
11026
10556
|
symbol: !1,
|
|
11027
10557
|
interval: !1,
|
|
11028
10558
|
crosshair: !0,
|
|
11029
10559
|
time: !1,
|
|
11030
10560
|
drawings: !1,
|
|
11031
10561
|
replay: !1
|
|
11032
|
-
},
|
|
10562
|
+
}, mo = [
|
|
11033
10563
|
"symbol",
|
|
11034
10564
|
"interval",
|
|
11035
10565
|
"crosshair",
|
|
@@ -11070,25 +10600,25 @@ var fo = {
|
|
|
11070
10600
|
rows: 3
|
|
11071
10601
|
}
|
|
11072
10602
|
};
|
|
11073
|
-
function
|
|
10603
|
+
function ho(e) {
|
|
11074
10604
|
return typeof e == "string" && Object.prototype.hasOwnProperty.call($, e);
|
|
11075
10605
|
}
|
|
11076
|
-
function
|
|
10606
|
+
function go(e) {
|
|
11077
10607
|
return JSON.parse(JSON.stringify(e));
|
|
11078
10608
|
}
|
|
11079
|
-
function
|
|
10609
|
+
function _o(e, t, n = 16) {
|
|
11080
10610
|
let r = (20 - 2 * (e - 1)) / e, i = (20 - 2 * (t - 1)) / t, a = "";
|
|
11081
10611
|
for (let n = 0; n < t; n++) for (let t = 0; t < e; t++) a += `<rect x="${2 + t * (r + 2)}" y="${2 + n * (i + 2)}" width="${r}" height="${i}" rx="1"/>`;
|
|
11082
10612
|
return `<svg width="${n}" height="${n}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true">${a}</svg>`;
|
|
11083
10613
|
}
|
|
11084
|
-
function
|
|
10614
|
+
function vo(e) {
|
|
11085
10615
|
if (typeof e != "object" || !e) return null;
|
|
11086
10616
|
let t = e;
|
|
11087
|
-
if (t.v !== 1 || t.kind !== "grid" || !
|
|
10617
|
+
if (t.v !== 1 || t.kind !== "grid" || !ho(t.layout) || !Array.isArray(t.cells)) return null;
|
|
11088
10618
|
let n = t.cells.map(Fi);
|
|
11089
10619
|
if (n.some((e) => e === null)) return null;
|
|
11090
|
-
let r = typeof t.sync == "object" && t.sync !== null ? t.sync : {}, i = { ...
|
|
11091
|
-
for (let e of
|
|
10620
|
+
let r = typeof t.sync == "object" && t.sync !== null ? t.sync : {}, i = { ...po };
|
|
10621
|
+
for (let e of mo) typeof r[e] == "boolean" && (i[e] = r[e]);
|
|
11092
10622
|
let a = typeof t.active == "number" && Number.isInteger(t.active) ? t.active : 0;
|
|
11093
10623
|
return {
|
|
11094
10624
|
v: 1,
|
|
@@ -11099,7 +10629,7 @@ function _o(e) {
|
|
|
11099
10629
|
cells: n
|
|
11100
10630
|
};
|
|
11101
10631
|
}
|
|
11102
|
-
var
|
|
10632
|
+
var yo = class {
|
|
11103
10633
|
root;
|
|
11104
10634
|
cellsEl;
|
|
11105
10635
|
cells = [];
|
|
@@ -11126,10 +10656,10 @@ var vo = class {
|
|
|
11126
10656
|
!(e.ctrlKey || e.metaKey) || e.altKey || e.shiftKey || e.key !== "s" && e.key !== "S" || !this.layoutsUI || Y() || !ji(this.root, !0) || (e.preventDefault(), this.layoutsUI.save());
|
|
11127
10657
|
};
|
|
11128
10658
|
constructor(e, t = {}) {
|
|
11129
|
-
this.options = t, this.layout =
|
|
11130
|
-
...
|
|
10659
|
+
this.options = t, this.layout = ho(t.layout) ? t.layout : "1x2", this.sync = {
|
|
10660
|
+
...po,
|
|
11131
10661
|
...t.sync
|
|
11132
|
-
}, this.t = d(f(t.widget?.locale, t.widget?.messages)),
|
|
10662
|
+
}, this.t = d(f(t.widget?.locale, t.widget?.messages)), ht(), this.root = document.createElement("div"), this.root.className = "tcw-root tcw-grid", this.root.dataset.tcwTheme = t.widget?.theme === "light" ? "light" : "dark", U(this.root, H(t.widget?.ui), { variables: t.widget?.ui !== void 0 }), t.bar !== !1 && this.root.appendChild(this.buildBar()), this.cellsEl = document.createElement("div"), this.cellsEl.className = "tcw-grid-cells", this.root.appendChild(this.cellsEl), e.appendChild(this.root), this.applyShape();
|
|
11133
10663
|
for (let e = 0; e < this.shapeCount(); e++) this.cells.push(this.createCell(e));
|
|
11134
10664
|
this.markActive();
|
|
11135
10665
|
let n = this.cells[0]?.el.querySelector(".tcw-root")?.dataset.tcwTheme;
|
|
@@ -11165,7 +10695,7 @@ var vo = class {
|
|
|
11165
10695
|
return this.layout;
|
|
11166
10696
|
}
|
|
11167
10697
|
setLayout(e) {
|
|
11168
|
-
if (e === this.layout || !
|
|
10698
|
+
if (e === this.layout || !ho(e)) return;
|
|
11169
10699
|
this.layout = e;
|
|
11170
10700
|
let t = this.shapeCount();
|
|
11171
10701
|
for (; this.cells.length > t;) {
|
|
@@ -11211,7 +10741,7 @@ var vo = class {
|
|
|
11211
10741
|
this.styleOverrides = t;
|
|
11212
10742
|
}
|
|
11213
10743
|
setFeatures(e) {
|
|
11214
|
-
let t =
|
|
10744
|
+
let t = it(e);
|
|
11215
10745
|
for (let e of this.cells) e.widget.setFeatures(t);
|
|
11216
10746
|
this.featureSwitches = {
|
|
11217
10747
|
...this.featureSwitches,
|
|
@@ -11255,14 +10785,14 @@ var vo = class {
|
|
|
11255
10785
|
return JSON.stringify(this.captureLayout());
|
|
11256
10786
|
}
|
|
11257
10787
|
async applyLayoutContent(e) {
|
|
11258
|
-
let t =
|
|
10788
|
+
let t = vo(Ii(e));
|
|
11259
10789
|
return t ? (await this.restoreLayout(t), !0) : !1;
|
|
11260
10790
|
}
|
|
11261
10791
|
destroy() {
|
|
11262
10792
|
if (!this.destroyed) {
|
|
11263
10793
|
this.destroyed = !0, document.removeEventListener("keydown", this.onKeyDown), this.unregisterKeys(), this.drawingFrame && cancelAnimationFrame(this.drawingFrame), this.session?.destroy(), this.layoutsUI?.destroy();
|
|
11264
10794
|
for (let e of this.cells) this.destroyCell(e);
|
|
11265
|
-
this.cells = [], this.root.remove(),
|
|
10795
|
+
this.cells = [], this.root.remove(), gt();
|
|
11266
10796
|
}
|
|
11267
10797
|
}
|
|
11268
10798
|
shapeCount() {
|
|
@@ -11276,7 +10806,7 @@ var vo = class {
|
|
|
11276
10806
|
createCell(e) {
|
|
11277
10807
|
let t = document.createElement("div");
|
|
11278
10808
|
t.className = "tcw-grid-cell", t.setAttribute("role", "region"), t.setAttribute("aria-label", p(this.t("grid.chart"), { n: e + 1 })), this.cellsEl.appendChild(t);
|
|
11279
|
-
let n = this.options.widget ?? {}, r = this.options.cells?.[e] ?? {}, i = this.cells[this.active]?.widget, a = {}, o = new
|
|
10809
|
+
let n = this.options.widget ?? {}, r = this.options.cells?.[e] ?? {}, i = this.cells[this.active]?.widget, a = {}, o = new eo(t, {
|
|
11280
10810
|
...n,
|
|
11281
10811
|
...r,
|
|
11282
10812
|
...i && this.sync.symbol ? { symbol: i.getSymbol() } : {},
|
|
@@ -11325,7 +10855,7 @@ var vo = class {
|
|
|
11325
10855
|
t.replaySeekToTime(n);
|
|
11326
10856
|
return;
|
|
11327
10857
|
}
|
|
11328
|
-
let r =
|
|
10858
|
+
let r = bo(t.getData(), n);
|
|
11329
10859
|
r >= 0 && t.replayStart({
|
|
11330
10860
|
startIndex: r,
|
|
11331
10861
|
paused: !0
|
|
@@ -11370,7 +10900,7 @@ var vo = class {
|
|
|
11370
10900
|
copyDrawings(e) {
|
|
11371
10901
|
let t = e.widget.getSymbol(), n = e.widget.getChart().getDrawings();
|
|
11372
10902
|
this.quietly(() => {
|
|
11373
|
-
for (let r of this.cells) r !== e && r.widget.getSymbol() === t && r.widget.getChart().setDrawings(
|
|
10903
|
+
for (let r of this.cells) r !== e && r.widget.getSymbol() === t && r.widget.getChart().setDrawings(go(n));
|
|
11374
10904
|
});
|
|
11375
10905
|
}
|
|
11376
10906
|
mergeDrawings() {
|
|
@@ -11382,7 +10912,7 @@ var vo = class {
|
|
|
11382
10912
|
let e = /* @__PURE__ */ new Map();
|
|
11383
10913
|
for (let n of t) for (let t of n.widget.getChart().getDrawings()) e.has(t.id) || e.set(t.id, t);
|
|
11384
10914
|
let n = [...e.values()];
|
|
11385
|
-
for (let e of t) e.widget.getChart().setDrawings(
|
|
10915
|
+
for (let e of t) e.widget.getChart().setDrawings(go(n));
|
|
11386
10916
|
}
|
|
11387
10917
|
});
|
|
11388
10918
|
}
|
|
@@ -11400,20 +10930,20 @@ var vo = class {
|
|
|
11400
10930
|
e.className = "tcw-grid-bar", e.setAttribute("role", "toolbar"), e.setAttribute("aria-label", this.t("grid.bar"));
|
|
11401
10931
|
let t = document.createElement("div");
|
|
11402
10932
|
t.className = "tcw-grid-group", t.setAttribute("role", "group"), t.setAttribute("aria-label", this.t("grid.layout"));
|
|
11403
|
-
let n = this.options.layoutChoices?.filter(
|
|
10933
|
+
let n = this.options.layoutChoices?.filter(ho) ?? Object.keys($);
|
|
11404
10934
|
for (let e of n) {
|
|
11405
10935
|
let { cols: n, rows: r } = $[e], i = n * r === 1 ? this.t("grid.single") : p(this.t("grid.layoutOption"), {
|
|
11406
10936
|
count: n * r,
|
|
11407
10937
|
cols: n,
|
|
11408
10938
|
rows: r
|
|
11409
10939
|
}), a = document.createElement("button");
|
|
11410
|
-
a.type = "button", a.className = "tcw-btn-icon", a.title = i, a.setAttribute("aria-label", i), a.innerHTML =
|
|
10940
|
+
a.type = "button", a.className = "tcw-btn-icon", a.title = i, a.setAttribute("aria-label", i), a.innerHTML = _o(n, r), a.addEventListener("click", () => this.setLayout(e)), this.layoutButtons.set(e, a), t.appendChild(a);
|
|
11411
10941
|
}
|
|
11412
10942
|
let r = document.createElement("div");
|
|
11413
10943
|
r.className = "tcw-grid-group", r.setAttribute("role", "group"), r.setAttribute("aria-label", this.t("grid.sync"));
|
|
11414
10944
|
let i = document.createElement("span");
|
|
11415
10945
|
i.className = "tcw-grid-label", i.innerHTML = `${j("link", 13)}<span>${N(this.t("grid.sync"))}</span>`, r.appendChild(i);
|
|
11416
|
-
for (let e of
|
|
10946
|
+
for (let e of mo) {
|
|
11417
10947
|
let t = document.createElement("button");
|
|
11418
10948
|
t.type = "button", t.className = "tcw-btn tcw-grid-sync", t.textContent = this.t(`grid.sync.${e}`), t.title = this.t(`grid.sync.${e}.hint`), t.addEventListener("click", () => this.setSync({ [e]: !this.sync[e] })), this.syncButtons.set(e, t), r.appendChild(t);
|
|
11419
10949
|
}
|
|
@@ -11460,7 +10990,7 @@ var vo = class {
|
|
|
11460
10990
|
onChange: () => this.renderLayoutsButton(),
|
|
11461
10991
|
onError: () => this.toast(this.t("layouts.saveFailed"), "error")
|
|
11462
10992
|
});
|
|
11463
|
-
this.session = t, this.layoutsUI = new
|
|
10993
|
+
this.session = t, this.layoutsUI = new li(t, {
|
|
11464
10994
|
root: this.root,
|
|
11465
10995
|
t: this.t,
|
|
11466
10996
|
toast: (e, t) => this.toast(e, t),
|
|
@@ -11474,12 +11004,12 @@ var vo = class {
|
|
|
11474
11004
|
this.cells[this.active]?.widget.toast(e, t);
|
|
11475
11005
|
}
|
|
11476
11006
|
};
|
|
11477
|
-
function
|
|
11007
|
+
function bo(e, t) {
|
|
11478
11008
|
let n = -1;
|
|
11479
11009
|
for (let r = 0; r < e.length && e[r].time < t; r++) n = r;
|
|
11480
11010
|
return n;
|
|
11481
11011
|
}
|
|
11482
11012
|
//#endregion
|
|
11483
|
-
export {
|
|
11013
|
+
export { _ as CHART_TYPE_ICONS, eo as ChartWidget, yo as ChartWidgetGrid, po as DEFAULT_GRID_SYNC, ee as DRAWING_TOOL_ICONS, l as EN_MESSAGES, $ as GRID_SHAPES, s as LayoutSession, i as MAX_LAYOUT_NAME, re as UI_ICONS, m as VI_MESSAGES, O as WIDGET_FEATURES, Gn as WIDGET_UI_PRESETS, U as applyWidgetUI, o as cleanLayoutName, vt as createChartTypeIcon, j as createIcon, M as createToolIcon, u as findWidgetLocale, ae as iconSvg, r as localStorageLayouts, t as memoryLayouts, vo as readGridLayout, wn as readWatchlists, Fi as readWidgetLayout, c as registerWidgetLocale, H as resolveWidgetUI, Qn as widgetUIVariables };
|
|
11484
11014
|
|
|
11485
11015
|
//# sourceMappingURL=index.js.map
|