@tradecanvas/chart 1.0.3 → 1.2.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/LICENSE +21 -21
- package/README.md +79 -9
- package/dist/Chart.d.ts +33 -1
- package/dist/Chart.d.ts.map +1 -1
- package/dist/DataManager.d.ts.map +1 -1
- package/dist/{DragDropImporter-BGNGtnk4.js → DragDropImporter-BcTzFeRP.js} +312 -223
- package/dist/DragDropImporter-BcTzFeRP.js.map +1 -0
- package/dist/DragDropImporter-DZBrretS.cjs +2 -0
- package/dist/DragDropImporter-DZBrretS.cjs.map +1 -0
- package/dist/charts/IndicatorPriceRange.d.ts +7 -3
- package/dist/charts/IndicatorPriceRange.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -24
- package/dist/index.js.map +1 -1
- package/dist/layout/LayoutManager.d.ts +3 -0
- package/dist/layout/LayoutManager.d.ts.map +1 -1
- package/dist/layout/priceAxisWidth.d.ts +22 -0
- package/dist/layout/priceAxisWidth.d.ts.map +1 -0
- package/dist/widget/ChartWidget.d.ts +24 -1
- package/dist/widget/ChartWidget.d.ts.map +1 -1
- package/dist/widget/WidgetDrawingSidebar.d.ts.map +1 -1
- package/dist/widget/WidgetHotkeySheet.d.ts +3 -1
- package/dist/widget/WidgetHotkeySheet.d.ts.map +1 -1
- package/dist/widget/WidgetLoadingOverlay.d.ts +41 -0
- package/dist/widget/WidgetLoadingOverlay.d.ts.map +1 -0
- package/dist/widget/WidgetObjectTree.d.ts.map +1 -1
- package/dist/widget/WidgetSettings.d.ts +3 -1
- package/dist/widget/WidgetSettings.d.ts.map +1 -1
- package/dist/widget/WidgetToolbar.d.ts +4 -1
- package/dist/widget/WidgetToolbar.d.ts.map +1 -1
- package/dist/widget/WidgetWatchlist.d.ts +4 -1
- package/dist/widget/WidgetWatchlist.d.ts.map +1 -1
- package/dist/widget/i18n.d.ts +70 -0
- package/dist/widget/i18n.d.ts.map +1 -0
- package/dist/widget/icons.d.ts.map +1 -1
- package/dist/widget/index.cjs +2458 -2380
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.js +635 -237
- package/dist/widget/index.js.map +1 -1
- package/dist/widget/types.d.ts +10 -0
- package/dist/widget/types.d.ts.map +1 -1
- package/dist/widget/widgetConfig.d.ts.map +1 -1
- package/package.json +6 -3
- package/dist/DragDropImporter-BGNGtnk4.js.map +0 -1
- package/dist/DragDropImporter-DvQin-m-.cjs +0 -2
- package/dist/DragDropImporter-DvQin-m-.cjs.map +0 -1
package/dist/widget/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as e, t } from "../DragDropImporter-
|
|
1
|
+
import { r as e, t } from "../DragDropImporter-BcTzFeRP.js";
|
|
2
2
|
import { DARK_THEME as n, LIGHT_THEME as r, timeframeBucketStart as i, timeframeToMs as a } from "@tradecanvas/commons";
|
|
3
3
|
//#region src/io/resampleOHLCV.ts
|
|
4
4
|
function o(e, t, n = {}) {
|
|
@@ -124,18 +124,37 @@ var c = [
|
|
|
124
124
|
{
|
|
125
125
|
label: "Extended Line",
|
|
126
126
|
value: "extendedLine"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
label: "Info Line",
|
|
130
|
+
value: "infoLine"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
label: "Trend Angle",
|
|
134
|
+
value: "trendAngle"
|
|
127
135
|
}
|
|
128
136
|
]
|
|
129
137
|
},
|
|
130
138
|
{
|
|
131
139
|
label: "Horizontal/Vertical",
|
|
132
|
-
tools: [
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
tools: [
|
|
141
|
+
{
|
|
142
|
+
label: "Horizontal Line",
|
|
143
|
+
value: "horizontalLine"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
label: "Horizontal Ray",
|
|
147
|
+
value: "horizontalRay"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
label: "Vertical Line",
|
|
151
|
+
value: "verticalLine"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
label: "Cross Line",
|
|
155
|
+
value: "crossLine"
|
|
156
|
+
}
|
|
157
|
+
]
|
|
139
158
|
},
|
|
140
159
|
{
|
|
141
160
|
label: "Channels",
|
|
@@ -149,13 +168,28 @@ var c = [
|
|
|
149
168
|
},
|
|
150
169
|
{
|
|
151
170
|
label: "Fibonacci",
|
|
152
|
-
tools: [
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
171
|
+
tools: [
|
|
172
|
+
{
|
|
173
|
+
label: "Fib Retracement",
|
|
174
|
+
value: "fibRetracement"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
label: "Fib Extension",
|
|
178
|
+
value: "fibExtension"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
label: "Fib Channel",
|
|
182
|
+
value: "fibChannel"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
label: "Fib Time Zones",
|
|
186
|
+
value: "fibTimeZones"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
label: "Fib Speed Resistance Fan",
|
|
190
|
+
value: "fibSpeedResistanceFan"
|
|
191
|
+
}
|
|
192
|
+
]
|
|
159
193
|
},
|
|
160
194
|
{
|
|
161
195
|
label: "Shapes",
|
|
@@ -164,6 +198,10 @@ var c = [
|
|
|
164
198
|
label: "Rectangle",
|
|
165
199
|
value: "rectangle"
|
|
166
200
|
},
|
|
201
|
+
{
|
|
202
|
+
label: "Circle",
|
|
203
|
+
value: "circle"
|
|
204
|
+
},
|
|
167
205
|
{
|
|
168
206
|
label: "Ellipse",
|
|
169
207
|
value: "ellipse"
|
|
@@ -175,12 +213,20 @@ var c = [
|
|
|
175
213
|
]
|
|
176
214
|
},
|
|
177
215
|
{
|
|
178
|
-
label: "Gann &
|
|
216
|
+
label: "Gann & Pitchforks",
|
|
179
217
|
tools: [
|
|
180
218
|
{
|
|
181
219
|
label: "Pitchfork",
|
|
182
220
|
value: "pitchfork"
|
|
183
221
|
},
|
|
222
|
+
{
|
|
223
|
+
label: "Schiff Pitchfork",
|
|
224
|
+
value: "schiffPitchfork"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
label: "Modified Schiff Pitchfork",
|
|
228
|
+
value: "modifiedSchiffPitchfork"
|
|
229
|
+
},
|
|
184
230
|
{
|
|
185
231
|
label: "Gann Fan",
|
|
186
232
|
value: "gannFan"
|
|
@@ -189,6 +235,27 @@ var c = [
|
|
|
189
235
|
label: "Gann Box",
|
|
190
236
|
value: "gannBox"
|
|
191
237
|
},
|
|
238
|
+
{
|
|
239
|
+
label: "Cyclic Lines",
|
|
240
|
+
value: "cyclicLines"
|
|
241
|
+
}
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
label: "Patterns",
|
|
246
|
+
tools: [
|
|
247
|
+
{
|
|
248
|
+
label: "XABCD Pattern",
|
|
249
|
+
value: "xabcdPattern"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
label: "ABCD Pattern",
|
|
253
|
+
value: "abcdPattern"
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
label: "Head and Shoulders",
|
|
257
|
+
value: "headAndShoulders"
|
|
258
|
+
},
|
|
192
259
|
{
|
|
193
260
|
label: "Elliott Wave",
|
|
194
261
|
value: "elliottWave"
|
|
@@ -206,6 +273,10 @@ var c = [
|
|
|
206
273
|
label: "Date Range",
|
|
207
274
|
value: "dateRange"
|
|
208
275
|
},
|
|
276
|
+
{
|
|
277
|
+
label: "Date and Price Range",
|
|
278
|
+
value: "dateAndPriceRange"
|
|
279
|
+
},
|
|
209
280
|
{
|
|
210
281
|
label: "Measure",
|
|
211
282
|
value: "measure"
|
|
@@ -214,13 +285,37 @@ var c = [
|
|
|
214
285
|
},
|
|
215
286
|
{
|
|
216
287
|
label: "Annotation",
|
|
217
|
-
tools: [
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
288
|
+
tools: [
|
|
289
|
+
{
|
|
290
|
+
label: "Text",
|
|
291
|
+
value: "text"
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
label: "Price Label",
|
|
295
|
+
value: "priceLabel"
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
label: "Arrow",
|
|
299
|
+
value: "arrow"
|
|
300
|
+
}
|
|
301
|
+
]
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
label: "Forecasting",
|
|
305
|
+
tools: [
|
|
306
|
+
{
|
|
307
|
+
label: "Long/Short Position",
|
|
308
|
+
value: "riskReward"
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
label: "Anchored VWAP",
|
|
312
|
+
value: "anchoredVWAP"
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
label: "Fixed Range Volume Profile",
|
|
316
|
+
value: "volumeProfileRange"
|
|
317
|
+
}
|
|
318
|
+
]
|
|
224
319
|
}
|
|
225
320
|
], d = [
|
|
226
321
|
{
|
|
@@ -233,6 +328,21 @@ var c = [
|
|
|
233
328
|
name: "EMA",
|
|
234
329
|
type: "overlay"
|
|
235
330
|
},
|
|
331
|
+
{
|
|
332
|
+
id: "tema",
|
|
333
|
+
name: "Triple EMA",
|
|
334
|
+
type: "overlay"
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
id: "vwma",
|
|
338
|
+
name: "VWMA",
|
|
339
|
+
type: "overlay"
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
id: "wma",
|
|
343
|
+
name: "Weighted MA",
|
|
344
|
+
type: "overlay"
|
|
345
|
+
},
|
|
236
346
|
{
|
|
237
347
|
id: "hma",
|
|
238
348
|
name: "Hull MA",
|
|
@@ -248,6 +358,11 @@ var c = [
|
|
|
248
358
|
name: "Bollinger Bands",
|
|
249
359
|
type: "overlay"
|
|
250
360
|
},
|
|
361
|
+
{
|
|
362
|
+
id: "envelope",
|
|
363
|
+
name: "Envelope",
|
|
364
|
+
type: "overlay"
|
|
365
|
+
},
|
|
251
366
|
{
|
|
252
367
|
id: "vwap",
|
|
253
368
|
name: "VWAP",
|
|
@@ -600,7 +715,7 @@ var c = [
|
|
|
600
715
|
crosshairMode: "magnet",
|
|
601
716
|
numberLocale: "en-US",
|
|
602
717
|
timezone: "local"
|
|
603
|
-
}, te = "/* === 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.tcw-root {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif;\n font-feature-settings: 'cv11', 'ss01', 'ss03';\n font-size: 13px;\n line-height: 1.4;\n color: #d1d4dc;\n background: #0d0f17;\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: #0d0f17;\n --tcw-bg-surface: #131722;\n --tcw-bg-elevated: #1a1e2d;\n --tcw-bg-overlay: #20253480;\n --tcw-border: #2a2e39;\n --tcw-border-strong: #363a45;\n --tcw-text: #e9ebf0;\n --tcw-text-dim: #b2b5be;\n --tcw-text-muted: #6b6f7a;\n\n --tcw-accent: #4f88ff;\n --tcw-accent-hover: #6b9aff;\n --tcw-accent-soft: rgba(79, 136, 255, 0.14);\n --tcw-accent-glow: rgba(79, 136, 255, 0.22);\n --tcw-accent-line: rgba(79, 136, 255, 0.55);\n\n --tcw-red: #f23645;\n --tcw-red-soft: rgba(242, 54, 69, 0.12);\n --tcw-green: #26a17b;\n --tcw-green-soft: rgba(38, 161, 123, 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 /* Shape */\n --tcw-radius-sm: 4px;\n --tcw-radius: 6px;\n --tcw-radius-lg: 10px;\n --tcw-radius-xl: 14px;\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(79, 136, 255, 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: #131722;\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: #e7e9ef;\n --tcw-border-strong: #d4d7e0;\n --tcw-text: #131722;\n --tcw-text-dim: #50545e;\n --tcw-text-muted: #8b8f99;\n\n --tcw-accent: #2962ff;\n --tcw-accent-hover: #1e4fd6;\n --tcw-accent-soft: rgba(41, 98, 255, 0.10);\n --tcw-accent-glow: rgba(41, 98, 255, 0.16);\n --tcw-accent-line: rgba(41, 98, 255, 0.45);\n\n --tcw-hover-bg: rgba(0, 0, 0, 0.04);\n --tcw-active-bg: rgba(41, 98, 255, 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: 44px;\n border-bottom: 1px 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: 14px;\n font-weight: 650;\n color: var(--tcw-text);\n padding: 6px 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-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.tcw-toolbar-sep {\n width: 1px;\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 padding: 6px 10px;\n font-size: 12px;\n font-weight: 500;\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-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-accent-soft);\n color: var(--tcw-accent);\n font-weight: 600;\n box-shadow: inset 0 0 0 1px var(--tcw-accent-line);\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: 32px;\n height: 32px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-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}\n\n.tcw-badge-count {\n font-size: 10px;\n font-weight: 600;\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n padding: 1px 5px;\n border-radius: 9px;\n font-family: var(--tcw-font-mono);\n}\n\n.tcw-indicator-chips {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 0 4px;\n flex-wrap: nowrap;\n overflow: hidden;\n}\n\n.tcw-indicator-chip {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 6px 3px 9px;\n font-size: 11px;\n font-weight: 500;\n background: var(--tcw-accent-soft);\n color: var(--tcw-accent);\n border-radius: 9999px;\n white-space: nowrap;\n line-height: 1.4;\n letter-spacing: -0.005em;\n border: 1px solid transparent;\n transition: border-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-indicator-chip:hover {\n border-color: var(--tcw-accent-line);\n}\n\n.tcw-chip-remove {\n cursor: pointer;\n opacity: 0.55;\n padding: 0 2px;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n border: none;\n background: transparent;\n color: inherit;\n display: inline-flex;\n align-items: center;\n}\n\n.tcw-chip-remove:hover {\n opacity: 1;\n}\n\n/* === Dropdown === */\n\n.tcw-dropdown-trigger {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 6px 10px;\n font-size: 12px;\n font-weight: 500;\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-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: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-lg);\n box-shadow: var(--tcw-shadow-lg);\n z-index: 50;\n padding: 6px;\n max-height: 420px;\n overflow-y: auto;\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\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 padding: 7px 10px;\n font-size: 12.5px;\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: left;\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.tcw-dropdown-item.tcw-active {\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n font-weight: 600;\n}\n\n.tcw-dropdown-label {\n text-transform: uppercase;\n font-size: 10px;\n color: var(--tcw-text-muted);\n letter-spacing: 0.08em;\n padding: 8px 10px 4px;\n font-weight: 600;\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: 10px;\n font-family: var(--tcw-font-mono);\n color: var(--tcw-text-muted);\n padding: 2px 6px;\n border-radius: 4px;\n background: var(--tcw-hover-bg);\n letter-spacing: 0.02em;\n}\n\n/* === Body === */\n\n.tcw-body {\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/* === Sidebar === */\n\n.tcw-sidebar {\n width: 40px;\n flex-shrink: 0;\n background: linear-gradient(180deg, var(--tcw-bg-elevated) 0%, var(--tcw-bg-surface) 100%);\n border-right: 1px solid var(--tcw-border);\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 6px 0;\n overflow: visible;\n box-shadow: var(--tcw-shadow-sm);\n}\n\n.tcw-tool-group-wrap {\n position: relative;\n}\n\n.tcw-sidebar-btn {\n width: 32px;\n height: 32px;\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-radius);\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-accent);\n background: var(--tcw-accent-soft);\n box-shadow: inset 2px 0 0 var(--tcw-accent);\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.tcw-sidebar-divider {\n width: 22px;\n height: 1px;\n background: var(--tcw-divider);\n margin: 6px 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 left: 100%;\n top: 0;\n margin-left: 6px;\n min-width: 180px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-lg);\n box-shadow: var(--tcw-shadow-lg);\n z-index: 30;\n padding: 6px;\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n animation: tcw-slide-right var(--tcw-dur-normal) var(--tcw-ease-out);\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: uppercase;\n font-size: 10px;\n color: var(--tcw-text-muted);\n letter-spacing: 0.08em;\n padding: 6px 10px 4px;\n font-weight: 600;\n}\n\n.tcw-flyout-item {\n padding: 7px 10px;\n font-size: 12.5px;\n color: var(--tcw-text-dim);\n cursor: pointer;\n width: 100%;\n display: block;\n border: none;\n background: transparent;\n text-align: left;\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\n.tcw-flyout-item.tcw-active {\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n font-weight: 600;\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: 11px;\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: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-xl);\n width: 520px;\n max-width: 92vw;\n max-height: 82vh;\n display: flex;\n flex-direction: column;\n box-shadow: var(--tcw-shadow-xl);\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: 15px;\n font-weight: 650;\n margin: 0;\n color: var(--tcw-text);\n letter-spacing: -0.015em;\n}\n\n.tcw-modal-close {\n width: 28px;\n height: 28px;\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-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 gap: 4px;\n padding: 0 18px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n.tcw-modal-tab {\n padding: 11px 14px;\n font-size: 12px;\n font-weight: 500;\n color: var(--tcw-text-muted);\n border: none;\n background: transparent;\n cursor: pointer;\n border-bottom: 2px solid transparent;\n margin-bottom: -1px;\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}\n\n.tcw-modal-tab.tcw-active {\n color: var(--tcw-accent);\n border-bottom-color: var(--tcw-accent);\n font-weight: 600;\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: 10.5px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.09em;\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: 13px;\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: 2px;\n}\n\n.tcw-color-hex {\n font-size: 11px;\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.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: 12px;\n font-family: inherit;\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-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-radius-xl) var(--tcw-radius-xl);\n}\n\n.tcw-reset-link {\n font-size: 12px;\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: 12.5px;\n font-weight: 600;\n background: var(--tcw-accent);\n color: #fff;\n border: none;\n border-radius: var(--tcw-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 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: 11px;\n color: var(--tcw-text-muted);\n flex-shrink: 0;\n font-feature-settings: 'tnum';\n}\n\n.tcw-status-indicator {\n display: flex;\n align-items: center;\n gap: 7px;\n font-weight: 500;\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(38, 161, 123, 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(242, 54, 69, 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: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-xl);\n width: 560px;\n max-width: 92vw;\n max-height: 62vh;\n display: flex;\n flex-direction: column;\n box-shadow: var(--tcw-shadow-xl);\n overflow: hidden;\n backdrop-filter: blur(20px);\n -webkit-backdrop-filter: blur(20px);\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: 18px;\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: 14.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: 10px;\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: uppercase;\n font-size: 10px;\n color: var(--tcw-text-muted);\n letter-spacing: 0.09em;\n padding: 10px 10px 4px;\n font-weight: 600;\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: 13px;\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: left;\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: 600;\n}\n\n.tcw-cmd-item-label {\n flex: 1;\n}\n\n.tcw-cmd-check {\n color: var(--tcw-accent);\n font-size: 14px;\n font-weight: 700;\n}\n\n.tcw-cmd-kbd {\n font-size: 10px;\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: 4px;\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: 13px;\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: 11px;\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-left: 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 padding: 10px 14px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--tcw-text-muted);\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n.tcw-watchlist-list {\n flex: 1;\n overflow-y: auto;\n padding: 4px 0;\n}\n\n.tcw-watchlist-row {\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-left: 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-left-color: var(--tcw-accent);\n}\n\n.tcw-watchlist-row.tcw-watchlist-active {\n background: var(--tcw-accent-soft);\n border-left-color: var(--tcw-accent);\n}\n\n.tcw-watchlist-symbol {\n font-size: 12.5px;\n font-weight: 600;\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: 12px;\n color: var(--tcw-text);\n font-weight: 500;\n}\n\n.tcw-watchlist-change {\n font-size: 10.5px;\n color: var(--tcw-text-muted);\n font-weight: 500;\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: 9999px;\n box-shadow: var(--tcw-shadow-lg);\n font-size: 12.5px;\n font-weight: 500;\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.tcw-replay-bar {\n position: absolute;\n left: 50%;\n bottom: 16px;\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: 9999px;\n box-shadow: var(--tcw-shadow-lg);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n font-size: 12px;\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: 9999px;\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: #fff;\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: 11px;\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: 11px;\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-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: 10px;\n color: var(--tcw-text-muted);\n}\n\n.tcw-hotkey-label {\n font-size: 12.5px;\n color: var(--tcw-text-dim);\n text-align: right;\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: 44px; /* Apple HIG minimum touch target */\n }\n .tcw-toolbar-sep {\n display: none;\n }\n .tcw-indicator-chips {\n display: none;\n }\n .tcw-btn,\n .tcw-dropdown-trigger {\n padding: 10px 12px; /* fatter tap target */\n font-size: 13px;\n }\n .tcw-btn-icon {\n width: 40px;\n height: 40px;\n }\n .tcw-sidebar {\n width: 44px;\n }\n .tcw-sidebar-btn {\n width: 40px;\n height: 40px;\n }\n .tcw-modal,\n .tcw-cmd-palette {\n width: 94vw;\n border-radius: var(--tcw-radius-lg);\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-radius-xl) var(--tcw-radius-xl) 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: 14px;\n }\n .tcw-dropdown-item {\n padding: 12px 12px;\n font-size: 14px;\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: 50px;\n right: 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: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-radius-lg);\n box-shadow: var(--tcw-shadow-lg);\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: 600;\n font-size: 13px;\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: 26px;\n height: 26px;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-radius-sm);\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: 12px;\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: 12px;\n font-weight: 600;\n color: #fff;\n background: var(--tcw-accent);\n border: none;\n border-radius: var(--tcw-radius-sm);\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: 12px;\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: 12px;\n font-weight: 600;\n color: var(--tcw-text);\n font-variant-numeric: tabular-nums;\n}\n.tcw-alerts-row-note {\n margin-top: 2px;\n font-size: 11px;\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: 9px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n padding: 2px 5px;\n border-radius: 999px;\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: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-radius-sm);\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: 50px;\n right: 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-radius-lg);\n box-shadow: var(--tcw-shadow-lg);\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: 12px;\n font-weight: 600;\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: 24px;\n height: 24px;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-radius-sm);\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: 12px; 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: 12px;\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: 600; }\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: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.04em;\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: 50px;\n right: 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-radius-lg);\n box-shadow: var(--tcw-shadow-lg);\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: 13px;\n font-weight: 600;\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: 26px;\n height: 26px;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-radius-sm);\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: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.04em;\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: 12px; 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: 11px;\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: 11px;\n font-weight: 600;\n color: var(--tcw-text-dim);\n border-left: 1px solid var(--tcw-border);\n border-right: 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: 52px;\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: 999px;\n box-shadow: var(--tcw-shadow-lg);\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-bracket-label {\n font-size: 12px;\n font-weight: 700;\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: 11px;\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: 12px;\n font-weight: 600;\n border: none;\n border-radius: 999px;\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: #fff;\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 left: 52px;\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-radius-lg);\n box-shadow: var(--tcw-shadow-lg);\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: 12px;\n font-weight: 600;\n color: var(--tcw-text);\n}\n.tcw-style-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-radius-sm);\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-radius-sm);\n color: var(--tcw-text-dim);\n cursor: pointer;\n font-size: 11px;\n}\n.tcw-style-width span { width: 16px; background: currentColor; border-radius: 2px; }\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: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\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: 12px;\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-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: 12px;\n font-weight: 600;\n color: #fff;\n background: var(--tcw-accent);\n border: none;\n border-radius: var(--tcw-radius-sm);\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: 11px; 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: 12px;\n color: var(--tcw-text);\n background: transparent;\n border: none;\n border-radius: var(--tcw-radius-sm);\n cursor: pointer;\n text-align: left;\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: 26px;\n height: 26px;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-radius-sm);\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: right;\n font-size: 12px;\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text-dim);\n}\n\n/* === Indicator settings dialog === */\n\n.tcw-modal-narrow {\n max-width: 360px;\n}\n.tcw-indi-input {\n width: 110px;\n height: 30px;\n padding: 0 8px;\n font-size: 12px;\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 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-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: 50px;\n right: 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-radius-lg);\n box-shadow: var(--tcw-shadow-lg);\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: 600;\n font-size: 13px;\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: 26px;\n height: 26px;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-radius-sm);\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: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\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: 22px;\n height: 22px;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-radius-sm);\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: 12px;\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: 26px;\n height: 26px;\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-radius-sm);\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-empty {\n padding: 8px;\n font-size: 12px;\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", m = 0, h = "tcw-styles";
|
|
718
|
+
}, te = "/* === TradeCanvas Widget — Premium Styles === */\r\n\r\n/*\r\n * The HTML `hidden` attribute only sets `display: none` via the UA stylesheet,\r\n * which any author `display` rule (e.g. `.tcw-alerts-panel { display: flex }`)\r\n * silently overrides — leaving panels stuck open when JS sets `el.hidden = true`.\r\n * Force `hidden` to win for every namespaced widget element. Scoped to `tcw-`\r\n * so it never touches the host page.\r\n */\r\n[class^=\"tcw-\"][hidden],\r\n[class*=\" tcw-\"][hidden] {\r\n display: none !important;\r\n}\r\n\r\n.tcw-root {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif;\r\n font-feature-settings: 'cv11', 'ss01', 'ss03';\r\n font-size: 13px;\r\n line-height: 1.4;\r\n color: #d1d4dc;\r\n background: #0d0f17;\r\n position: relative;\r\n overflow: hidden;\r\n -webkit-font-smoothing: antialiased;\r\n -moz-osx-font-smoothing: grayscale;\r\n\r\n /* --- Dark theme tokens (default) --- */\r\n --tcw-bg: #0d0f17;\r\n --tcw-bg-surface: #131722;\r\n --tcw-bg-elevated: #1a1e2d;\r\n --tcw-bg-overlay: #20253480;\r\n --tcw-border: #2a2e39;\r\n --tcw-border-strong: #363a45;\r\n --tcw-text: #e9ebf0;\r\n --tcw-text-dim: #b2b5be;\r\n --tcw-text-muted: #6b6f7a;\r\n\r\n --tcw-accent: #4f88ff;\r\n --tcw-accent-hover: #6b9aff;\r\n --tcw-accent-soft: rgba(79, 136, 255, 0.14);\r\n --tcw-accent-glow: rgba(79, 136, 255, 0.22);\r\n --tcw-accent-line: rgba(79, 136, 255, 0.55);\r\n\r\n --tcw-red: #f23645;\r\n --tcw-red-soft: rgba(242, 54, 69, 0.12);\r\n --tcw-green: #26a17b;\r\n --tcw-green-soft: rgba(38, 161, 123, 0.12);\r\n --tcw-amber: #ff9f43;\r\n\r\n --tcw-hover-bg: rgba(255, 255, 255, 0.05);\r\n --tcw-active-bg: rgba(255, 255, 255, 0.08);\r\n --tcw-divider: rgba(255, 255, 255, 0.06);\r\n\r\n /* Motion */\r\n --tcw-ease: cubic-bezier(0.2, 0, 0, 1);\r\n --tcw-ease-out: cubic-bezier(0.16, 1, 0.3, 1);\r\n --tcw-dur-fast: 120ms;\r\n --tcw-dur-normal: 180ms;\r\n --tcw-dur-slow: 260ms;\r\n\r\n /* Shape */\r\n --tcw-radius-sm: 4px;\r\n --tcw-radius: 6px;\r\n --tcw-radius-lg: 10px;\r\n --tcw-radius-xl: 14px;\r\n\r\n /* Elevation */\r\n --tcw-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);\r\n --tcw-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35), 0 1px 3px rgba(0, 0, 0, 0.2);\r\n --tcw-shadow-lg: 0 12px 36px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.3);\r\n --tcw-shadow-xl: 0 24px 64px rgba(0, 0, 0, 0.55), 0 12px 24px rgba(0, 0, 0, 0.35);\r\n --tcw-ring: 0 0 0 2px rgba(79, 136, 255, 0.45);\r\n\r\n /* Type */\r\n --tcw-font-mono: 'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', 'Consolas', ui-monospace, monospace;\r\n}\r\n\r\n.tcw-root[data-tcw-theme='light'] {\r\n color: #131722;\r\n background: #fcfcfd;\r\n\r\n --tcw-bg: #fcfcfd;\r\n --tcw-bg-surface: #ffffff;\r\n --tcw-bg-elevated: #ffffff;\r\n --tcw-bg-overlay: rgba(255, 255, 255, 0.75);\r\n --tcw-border: #e7e9ef;\r\n --tcw-border-strong: #d4d7e0;\r\n --tcw-text: #131722;\r\n --tcw-text-dim: #50545e;\r\n --tcw-text-muted: #8b8f99;\r\n\r\n --tcw-accent: #2962ff;\r\n --tcw-accent-hover: #1e4fd6;\r\n --tcw-accent-soft: rgba(41, 98, 255, 0.10);\r\n --tcw-accent-glow: rgba(41, 98, 255, 0.16);\r\n --tcw-accent-line: rgba(41, 98, 255, 0.45);\r\n\r\n --tcw-hover-bg: rgba(0, 0, 0, 0.04);\r\n --tcw-active-bg: rgba(41, 98, 255, 0.08);\r\n --tcw-divider: rgba(0, 0, 0, 0.06);\r\n\r\n --tcw-shadow-sm: 0 1px 2px rgba(20, 28, 56, 0.05);\r\n --tcw-shadow-md: 0 4px 12px rgba(20, 28, 56, 0.08), 0 1px 3px rgba(20, 28, 56, 0.04);\r\n --tcw-shadow-lg: 0 12px 36px rgba(20, 28, 56, 0.14), 0 4px 12px rgba(20, 28, 56, 0.08);\r\n --tcw-shadow-xl: 0 24px 64px rgba(20, 28, 56, 0.18), 0 12px 24px rgba(20, 28, 56, 0.1);\r\n}\r\n\r\n/* === Toolbar === */\r\n\r\n.tcw-toolbar {\r\n display: flex;\r\n align-items: center;\r\n gap: 0;\r\n padding: 0 10px;\r\n height: 44px;\r\n border-bottom: 1px solid var(--tcw-border);\r\n background:\r\n linear-gradient(180deg, var(--tcw-bg-elevated) 0%, var(--tcw-bg-surface) 100%);\r\n flex-shrink: 0;\r\n position: relative;\r\n z-index: 20;\r\n box-shadow: var(--tcw-shadow-sm);\r\n}\r\n\r\n.tcw-toolbar-symbol {\r\n font-size: 14px;\r\n font-weight: 650;\r\n color: var(--tcw-text);\r\n padding: 6px 12px;\r\n white-space: nowrap;\r\n letter-spacing: -0.015em;\r\n cursor: pointer;\r\n border: none;\r\n background: transparent;\r\n font-family: inherit;\r\n border-radius: var(--tcw-radius);\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-toolbar-symbol:hover {\r\n background: var(--tcw-hover-bg);\r\n}\r\n\r\n.tcw-toolbar-sep {\r\n width: 1px;\r\n height: 22px;\r\n background: var(--tcw-border);\r\n flex-shrink: 0;\r\n margin: 0 4px;\r\n}\r\n\r\n.tcw-toolbar-group {\r\n display: flex;\r\n align-items: center;\r\n gap: 2px;\r\n padding: 0 4px;\r\n}\r\n\r\n.tcw-toolbar-spacer {\r\n flex: 1;\r\n}\r\n\r\n.tcw-btn {\r\n padding: 6px 10px;\r\n font-size: 12px;\r\n font-weight: 500;\r\n font-family: inherit;\r\n border: none;\r\n border-radius: var(--tcw-radius);\r\n background: transparent;\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n transition:\r\n background var(--tcw-dur-fast) var(--tcw-ease),\r\n color var(--tcw-dur-fast) var(--tcw-ease),\r\n transform var(--tcw-dur-fast) var(--tcw-ease);\r\n white-space: nowrap;\r\n line-height: 1;\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-btn:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-btn:active {\r\n transform: translateY(0.5px);\r\n}\r\n\r\n.tcw-btn.tcw-active {\r\n background: var(--tcw-accent-soft);\r\n color: var(--tcw-accent);\r\n font-weight: 600;\r\n box-shadow: inset 0 0 0 1px var(--tcw-accent-line);\r\n}\r\n\r\n.tcw-btn:focus-visible,\r\n.tcw-btn-icon:focus-visible,\r\n.tcw-sidebar-btn:focus-visible,\r\n.tcw-dropdown-trigger:focus-visible {\r\n outline: none;\r\n box-shadow: var(--tcw-ring);\r\n}\r\n\r\n.tcw-btn-icon {\r\n width: 32px;\r\n height: 32px;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-family: inherit;\r\n border: none;\r\n border-radius: var(--tcw-radius);\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n cursor: pointer;\r\n transition:\r\n background var(--tcw-dur-fast) var(--tcw-ease),\r\n color var(--tcw-dur-fast) var(--tcw-ease);\r\n line-height: 1;\r\n position: relative;\r\n}\r\n\r\n.tcw-btn-icon:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-btn-icon svg {\r\n display: block;\r\n}\r\n\r\n.tcw-badge-count {\r\n font-size: 10px;\r\n font-weight: 600;\r\n color: var(--tcw-accent);\r\n background: var(--tcw-accent-soft);\r\n padding: 1px 5px;\r\n border-radius: 9px;\r\n font-family: var(--tcw-font-mono);\r\n}\r\n\r\n.tcw-indicator-chips {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n padding: 0 4px;\r\n flex-wrap: nowrap;\r\n overflow: hidden;\r\n}\r\n\r\n.tcw-indicator-chip {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 4px;\r\n padding: 3px 6px 3px 9px;\r\n font-size: 11px;\r\n font-weight: 500;\r\n background: var(--tcw-accent-soft);\r\n color: var(--tcw-accent);\r\n border-radius: 9999px;\r\n white-space: nowrap;\r\n line-height: 1.4;\r\n letter-spacing: -0.005em;\r\n border: 1px solid transparent;\r\n transition: border-color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-indicator-chip:hover {\r\n border-color: var(--tcw-accent-line);\r\n}\r\n\r\n.tcw-chip-remove {\r\n cursor: pointer;\r\n opacity: 0.55;\r\n padding: 0 2px;\r\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\r\n border: none;\r\n background: transparent;\r\n color: inherit;\r\n display: inline-flex;\r\n align-items: center;\r\n}\r\n\r\n.tcw-chip-remove:hover {\r\n opacity: 1;\r\n}\r\n\r\n/* === Dropdown === */\r\n\r\n.tcw-dropdown-trigger {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 4px;\r\n padding: 6px 10px;\r\n font-size: 12px;\r\n font-weight: 500;\r\n font-family: inherit;\r\n border: none;\r\n border-radius: var(--tcw-radius);\r\n background: transparent;\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n white-space: nowrap;\r\n line-height: 1;\r\n}\r\n\r\n.tcw-dropdown-trigger:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-dropdown {\r\n position: absolute;\r\n top: 100%;\r\n margin-top: 6px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n z-index: 50;\r\n padding: 6px;\r\n max-height: 420px;\r\n overflow-y: auto;\r\n backdrop-filter: blur(12px);\r\n -webkit-backdrop-filter: blur(12px);\r\n animation: tcw-pop-in var(--tcw-dur-normal) var(--tcw-ease-out);\r\n}\r\n\r\n@keyframes tcw-pop-in {\r\n from { opacity: 0; transform: translateY(-4px) scale(0.98); }\r\n to { opacity: 1; transform: translateY(0) scale(1); }\r\n}\r\n\r\n.tcw-dropdown-item {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 7px 10px;\r\n font-size: 12.5px;\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n width: 100%;\r\n border: none;\r\n background: transparent;\r\n font-family: inherit;\r\n text-align: left;\r\n border-radius: var(--tcw-radius-sm);\r\n gap: 12px;\r\n}\r\n\r\n.tcw-dropdown-item:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-dropdown-item.tcw-active {\r\n color: var(--tcw-accent);\r\n background: var(--tcw-accent-soft);\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-dropdown-label {\r\n text-transform: uppercase;\r\n font-size: 10px;\r\n color: var(--tcw-text-muted);\r\n letter-spacing: 0.08em;\r\n padding: 8px 10px 4px;\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-dropdown-divider {\r\n border-top: 1px solid var(--tcw-divider);\r\n margin: 6px 4px;\r\n}\r\n\r\n.tcw-tag {\r\n font-size: 10px;\r\n font-family: var(--tcw-font-mono);\r\n color: var(--tcw-text-muted);\r\n padding: 2px 6px;\r\n border-radius: 4px;\r\n background: var(--tcw-hover-bg);\r\n letter-spacing: 0.02em;\r\n}\r\n\r\n/* === Body === */\r\n\r\n.tcw-body {\r\n display: flex;\r\n flex: 1;\r\n min-height: 0;\r\n background: var(--tcw-bg);\r\n}\r\n\r\n.tcw-chart-container {\r\n flex: 1;\r\n min-width: 0;\r\n min-height: 0;\r\n width: 100%;\r\n height: 100%;\r\n position: relative;\r\n}\r\n\r\n/* === Loading overlay (TradingView-style skeleton bars) === */\r\n\r\n.tcw-loading-overlay {\r\n /* Uses a modifier class rather than the `hidden` attribute — the global\r\n `[hidden] { display: none !important }` rule above would cut the\r\n opacity transition off before it can play. */\r\n position: absolute;\r\n inset: 0;\r\n z-index: 5;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n background: var(--tcw-bg);\r\n opacity: 1;\r\n transition: opacity var(--tcw-dur-slow) var(--tcw-ease-out);\r\n pointer-events: none;\r\n}\r\n\r\n.tcw-loading-overlay--hidden {\r\n opacity: 0;\r\n}\r\n\r\n.tcw-loading-card {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 16px;\r\n padding: 20px 28px 16px;\r\n border: 1px solid transparent;\r\n border-radius: var(--tcw-radius-lg);\r\n}\r\n\r\n/* A slow switch: the previous chart stays readable underneath, dimmed, so the\r\n click visibly registered without blanking the screen. */\r\n.tcw-loading-overlay--veil {\r\n background: color-mix(in srgb, var(--tcw-bg) 55%, transparent);\r\n}\r\n\r\n.tcw-loading-overlay--veil .tcw-loading-card {\r\n background: var(--tcw-bg-elevated);\r\n border-color: var(--tcw-border);\r\n box-shadow: var(--tcw-shadow-lg);\r\n}\r\n\r\n.tcw-loading-overlay--error .tcw-loading-bars {\r\n display: none;\r\n}\r\n\r\n.tcw-loading-overlay--error .tcw-loading-label {\r\n color: var(--tcw-red);\r\n font-size: 13px;\r\n}\r\n\r\n.tcw-loading-bars {\r\n display: flex;\r\n align-items: flex-end;\r\n gap: 3px;\r\n height: 64px;\r\n}\r\n\r\n.tcw-loading-bar {\r\n width: 5px;\r\n border-radius: 2px 2px 0 0;\r\n background: var(--tcw-border-strong);\r\n animation: tcw-skeleton-pulse 1.1s ease-in-out infinite;\r\n}\r\n\r\n@keyframes tcw-skeleton-pulse {\r\n 0%, 100% { opacity: 0.35; transform: scaleY(0.55); }\r\n 50% { opacity: 0.85; transform: scaleY(1); }\r\n}\r\n\r\n.tcw-loading-label {\r\n font-size: 12px;\r\n color: var(--tcw-text-muted);\r\n letter-spacing: 0.02em;\r\n}\r\n\r\n/* === Sidebar === */\r\n\r\n.tcw-sidebar {\r\n width: 40px;\r\n flex-shrink: 0;\r\n background: linear-gradient(180deg, var(--tcw-bg-elevated) 0%, var(--tcw-bg-surface) 100%);\r\n border-right: 1px solid var(--tcw-border);\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n padding: 6px 0;\r\n overflow: visible;\r\n box-shadow: var(--tcw-shadow-sm);\r\n}\r\n\r\n.tcw-tool-group-wrap {\r\n position: relative;\r\n}\r\n\r\n.tcw-sidebar-btn {\r\n width: 32px;\r\n height: 32px;\r\n margin: 1px 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n cursor: pointer;\r\n font-family: inherit;\r\n transition:\r\n background var(--tcw-dur-fast) var(--tcw-ease),\r\n color var(--tcw-dur-fast) var(--tcw-ease);\r\n position: relative;\r\n flex-shrink: 0;\r\n line-height: 1;\r\n border-radius: var(--tcw-radius);\r\n}\r\n\r\n.tcw-sidebar-btn:hover {\r\n color: var(--tcw-text);\r\n background: var(--tcw-hover-bg);\r\n}\r\n\r\n.tcw-sidebar-btn.tcw-active {\r\n color: var(--tcw-accent);\r\n background: var(--tcw-accent-soft);\r\n box-shadow: inset 2px 0 0 var(--tcw-accent);\r\n}\r\n\r\n.tcw-sidebar-btn.tcw-danger:hover {\r\n color: var(--tcw-red);\r\n background: var(--tcw-red-soft);\r\n}\r\n\r\n.tcw-multi-dot {\r\n position: absolute;\r\n bottom: 3px;\r\n right: 3px;\r\n width: 4px;\r\n height: 4px;\r\n border-radius: 50%;\r\n background: var(--tcw-text-muted);\r\n opacity: 0.7;\r\n}\r\n\r\n.tcw-sidebar-divider {\r\n width: 22px;\r\n height: 1px;\r\n background: var(--tcw-divider);\r\n margin: 6px 0;\r\n flex-shrink: 0;\r\n}\r\n\r\n.tcw-sidebar-spacer {\r\n flex: 1;\r\n}\r\n\r\n/* === Flyout === */\r\n\r\n.tcw-flyout {\r\n position: absolute;\r\n left: 100%;\r\n top: 0;\r\n margin-left: 6px;\r\n min-width: 180px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n z-index: 30;\r\n padding: 6px;\r\n backdrop-filter: blur(12px);\r\n -webkit-backdrop-filter: blur(12px);\r\n animation: tcw-slide-right var(--tcw-dur-normal) var(--tcw-ease-out);\r\n}\r\n\r\n@keyframes tcw-slide-right {\r\n from { opacity: 0; transform: translateX(-4px); }\r\n to { opacity: 1; transform: translateX(0); }\r\n}\r\n\r\n.tcw-flyout-header {\r\n text-transform: uppercase;\r\n font-size: 10px;\r\n color: var(--tcw-text-muted);\r\n letter-spacing: 0.08em;\r\n padding: 6px 10px 4px;\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-flyout-item {\r\n padding: 7px 10px;\r\n font-size: 12.5px;\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n width: 100%;\r\n display: block;\r\n border: none;\r\n background: transparent;\r\n text-align: left;\r\n font-family: inherit;\r\n border-radius: var(--tcw-radius-sm);\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-flyout-item:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-flyout-item.tcw-active {\r\n color: var(--tcw-accent);\r\n background: var(--tcw-accent-soft);\r\n font-weight: 600;\r\n}\r\n\r\n/* Pinned (favorited) flyout item — a star marker on the right. */\r\n.tcw-flyout-item.tcw-flyout-faved::after {\r\n content: '★';\r\n float: right;\r\n color: var(--tcw-accent);\r\n font-size: 11px;\r\n line-height: 1.4;\r\n}\r\n\r\n/* Favorites strip — pinned drawing tools above the tool groups. */\r\n.tcw-sidebar-favorites {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n}\r\n.tcw-sidebar-favorites .tcw-sidebar-btn {\r\n position: relative;\r\n}\r\n.tcw-sidebar-favorites .tcw-sidebar-btn::before {\r\n content: '';\r\n position: absolute;\r\n top: 3px;\r\n right: 3px;\r\n width: 4px;\r\n height: 4px;\r\n border-radius: 50%;\r\n background: var(--tcw-accent);\r\n opacity: 0.7;\r\n}\r\n\r\n/* === Modal === */\r\n\r\n.tcw-modal-backdrop {\r\n position: fixed;\r\n inset: 0;\r\n background: rgba(8, 10, 18, 0.55);\r\n backdrop-filter: blur(6px) saturate(140%);\r\n -webkit-backdrop-filter: blur(6px) saturate(140%);\r\n z-index: 100;\r\n animation: tcw-fade-in var(--tcw-dur-normal) var(--tcw-ease-out);\r\n}\r\n\r\n@keyframes tcw-fade-in {\r\n from { opacity: 0; }\r\n to { opacity: 1; }\r\n}\r\n\r\n.tcw-modal {\r\n position: fixed;\r\n z-index: 101;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-xl);\r\n width: 520px;\r\n max-width: 92vw;\r\n max-height: 82vh;\r\n display: flex;\r\n flex-direction: column;\r\n box-shadow: var(--tcw-shadow-xl);\r\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\r\n}\r\n\r\n@keyframes tcw-modal-in {\r\n from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }\r\n to { opacity: 1; transform: translate(-50%, -50%) scale(1); }\r\n}\r\n\r\n.tcw-modal-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 18px 22px;\r\n border-bottom: 1px solid var(--tcw-divider);\r\n}\r\n\r\n.tcw-modal-header h3 {\r\n font-size: 15px;\r\n font-weight: 650;\r\n margin: 0;\r\n color: var(--tcw-text);\r\n letter-spacing: -0.015em;\r\n}\r\n\r\n.tcw-modal-close {\r\n width: 28px;\r\n height: 28px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n cursor: pointer;\r\n border-radius: var(--tcw-radius);\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-modal-close:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-modal-tabs {\r\n display: flex;\r\n gap: 4px;\r\n padding: 0 18px;\r\n border-bottom: 1px solid var(--tcw-divider);\r\n}\r\n\r\n.tcw-modal-tab {\r\n padding: 11px 14px;\r\n font-size: 12px;\r\n font-weight: 500;\r\n color: var(--tcw-text-muted);\r\n border: none;\r\n background: transparent;\r\n cursor: pointer;\r\n border-bottom: 2px solid transparent;\r\n margin-bottom: -1px;\r\n transition: color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\r\n font-family: inherit;\r\n text-transform: capitalize;\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-modal-tab:hover {\r\n color: var(--tcw-text-dim);\r\n}\r\n\r\n.tcw-modal-tab.tcw-active {\r\n color: var(--tcw-accent);\r\n border-bottom-color: var(--tcw-accent);\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-modal-body {\r\n padding: 20px 22px;\r\n overflow-y: auto;\r\n flex: 1;\r\n}\r\n\r\n.tcw-settings-section {\r\n margin-bottom: 22px;\r\n}\r\n\r\n.tcw-settings-section:last-child {\r\n margin-bottom: 0;\r\n}\r\n\r\n.tcw-settings-section-title {\r\n font-size: 10.5px;\r\n font-weight: 600;\r\n text-transform: uppercase;\r\n letter-spacing: 0.09em;\r\n color: var(--tcw-text-muted);\r\n margin-bottom: 12px;\r\n}\r\n\r\n.tcw-settings-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 0;\r\n}\r\n\r\n.tcw-settings-row + .tcw-settings-row {\r\n border-top: 1px solid var(--tcw-divider);\r\n}\r\n\r\n.tcw-settings-label {\r\n font-size: 13px;\r\n color: var(--tcw-text-dim);\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-color-picker-wrap {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n\r\n.tcw-color-picker-wrap input[type='color'] {\r\n width: 28px;\r\n height: 28px;\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-sm);\r\n background: transparent;\r\n cursor: pointer;\r\n padding: 2px;\r\n}\r\n\r\n.tcw-color-picker-wrap input[type='color']::-webkit-color-swatch-wrapper {\r\n padding: 0;\r\n}\r\n\r\n.tcw-color-picker-wrap input[type='color']::-webkit-color-swatch {\r\n border: none;\r\n border-radius: 2px;\r\n}\r\n\r\n.tcw-color-hex {\r\n font-size: 11px;\r\n font-family: var(--tcw-font-mono);\r\n color: var(--tcw-text-muted);\r\n min-width: 64px;\r\n letter-spacing: 0.01em;\r\n}\r\n\r\n.tcw-toggle {\r\n width: 36px;\r\n height: 20px;\r\n background: rgba(255, 255, 255, 0.12);\r\n border-radius: 10px;\r\n position: relative;\r\n cursor: pointer;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\r\n border: none;\r\n padding: 0;\r\n flex-shrink: 0;\r\n}\r\n\r\n.tcw-toggle::after {\r\n content: '';\r\n position: absolute;\r\n top: 2px;\r\n left: 2px;\r\n width: 16px;\r\n height: 16px;\r\n border-radius: 50%;\r\n background: var(--tcw-text-muted);\r\n transition:\r\n left var(--tcw-dur-normal) var(--tcw-ease-out),\r\n background var(--tcw-dur-fast) var(--tcw-ease);\r\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.tcw-toggle.tcw-on {\r\n background: var(--tcw-accent);\r\n box-shadow: 0 0 0 2px var(--tcw-accent-glow);\r\n}\r\n\r\n.tcw-toggle.tcw-on::after {\r\n left: 18px;\r\n background: #fff;\r\n}\r\n\r\n.tcw-root[data-tcw-theme='light'] .tcw-toggle {\r\n background: rgba(0, 0, 0, 0.12);\r\n}\r\n\r\n.tcw-root[data-tcw-theme='light'] .tcw-toggle::after {\r\n background: #999;\r\n}\r\n\r\n.tcw-root[data-tcw-theme='light'] .tcw-toggle.tcw-on {\r\n background: var(--tcw-accent);\r\n}\r\n\r\n.tcw-root[data-tcw-theme='light'] .tcw-toggle.tcw-on::after {\r\n background: #fff;\r\n}\r\n\r\n.tcw-settings-select {\r\n padding: 6px 10px;\r\n font-size: 12px;\r\n font-family: inherit;\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius);\r\n color: var(--tcw-text);\r\n cursor: pointer;\r\n transition: border-color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-settings-select:hover {\r\n border-color: var(--tcw-border-strong);\r\n}\r\n\r\n.tcw-settings-select:focus-visible {\r\n outline: none;\r\n border-color: var(--tcw-accent);\r\n box-shadow: var(--tcw-ring);\r\n}\r\n\r\n.tcw-modal-footer {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 14px 22px;\r\n border-top: 1px solid var(--tcw-divider);\r\n background: var(--tcw-bg-surface);\r\n border-radius: 0 0 var(--tcw-radius-xl) var(--tcw-radius-xl);\r\n}\r\n\r\n.tcw-reset-link {\r\n font-size: 12px;\r\n color: var(--tcw-text-muted);\r\n cursor: pointer;\r\n border: none;\r\n background: transparent;\r\n font-family: inherit;\r\n text-decoration: underline;\r\n text-underline-offset: 2px;\r\n text-decoration-color: var(--tcw-border-strong);\r\n transition: color var(--tcw-dur-fast) var(--tcw-ease), text-decoration-color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-reset-link:hover {\r\n color: var(--tcw-text-dim);\r\n text-decoration-color: currentColor;\r\n}\r\n\r\n.tcw-done-btn {\r\n padding: 8px 18px;\r\n font-size: 12.5px;\r\n font-weight: 600;\r\n background: var(--tcw-accent);\r\n color: #fff;\r\n border: none;\r\n border-radius: var(--tcw-radius);\r\n cursor: pointer;\r\n font-family: inherit;\r\n transition:\r\n background var(--tcw-dur-fast) var(--tcw-ease),\r\n transform var(--tcw-dur-fast) var(--tcw-ease),\r\n box-shadow var(--tcw-dur-fast) var(--tcw-ease);\r\n letter-spacing: -0.005em;\r\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.15);\r\n}\r\n\r\n.tcw-done-btn:hover {\r\n background: var(--tcw-accent-hover);\r\n box-shadow: var(--tcw-shadow-md), 0 0 0 3px var(--tcw-accent-glow);\r\n}\r\n\r\n.tcw-done-btn:active {\r\n transform: translateY(0.5px);\r\n}\r\n\r\n/* === Status Bar === */\r\n\r\n.tcw-statusbar {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 7px 16px;\r\n border-top: 1px solid var(--tcw-border);\r\n background: var(--tcw-bg-surface);\r\n font-size: 11px;\r\n color: var(--tcw-text-muted);\r\n flex-shrink: 0;\r\n font-feature-settings: 'tnum';\r\n}\r\n\r\n.tcw-status-indicator {\r\n display: flex;\r\n align-items: center;\r\n gap: 7px;\r\n font-weight: 500;\r\n}\r\n\r\n.tcw-status-dot {\r\n width: 7px;\r\n height: 7px;\r\n border-radius: 50%;\r\n background: var(--tcw-text-muted);\r\n transition: background var(--tcw-dur-normal) var(--tcw-ease), box-shadow var(--tcw-dur-normal) var(--tcw-ease);\r\n position: relative;\r\n}\r\n\r\n.tcw-status-dot.tcw-connected {\r\n background: var(--tcw-green);\r\n box-shadow: 0 0 0 3px rgba(38, 161, 123, 0.18);\r\n}\r\n\r\n.tcw-status-dot.tcw-connected::after {\r\n content: '';\r\n position: absolute;\r\n inset: -3px;\r\n border-radius: 50%;\r\n border: 2px solid var(--tcw-green);\r\n opacity: 0;\r\n animation: tcw-pulse 2.2s ease-out infinite;\r\n}\r\n\r\n@keyframes tcw-pulse {\r\n 0% { opacity: 0.6; transform: scale(0.6); }\r\n 100% { opacity: 0; transform: scale(2.2); }\r\n}\r\n\r\n.tcw-status-dot.tcw-error {\r\n background: var(--tcw-red);\r\n box-shadow: 0 0 0 3px rgba(242, 54, 69, 0.2);\r\n}\r\n\r\n/* === Command Palette === */\r\n\r\n.tcw-cmd-palette {\r\n position: fixed;\r\n z-index: 102;\r\n top: 18%;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-xl);\r\n width: 560px;\r\n max-width: 92vw;\r\n max-height: 62vh;\r\n display: flex;\r\n flex-direction: column;\r\n box-shadow: var(--tcw-shadow-xl);\r\n overflow: hidden;\r\n backdrop-filter: blur(20px);\r\n -webkit-backdrop-filter: blur(20px);\r\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\r\n}\r\n\r\n.tcw-cmd-header {\r\n display: flex;\r\n align-items: center;\r\n padding: 14px 18px;\r\n border-bottom: 1px solid var(--tcw-divider);\r\n gap: 12px;\r\n}\r\n\r\n.tcw-cmd-icon {\r\n font-size: 18px;\r\n color: var(--tcw-text-muted);\r\n flex-shrink: 0;\r\n display: inline-flex;\r\n align-items: center;\r\n}\r\n\r\n.tcw-cmd-input {\r\n flex: 1;\r\n background: transparent;\r\n border: none;\r\n outline: none;\r\n font-size: 14.5px;\r\n font-family: inherit;\r\n color: var(--tcw-text);\r\n caret-color: var(--tcw-accent);\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-cmd-input::placeholder {\r\n color: var(--tcw-text-muted);\r\n}\r\n\r\n.tcw-cmd-hint {\r\n font-size: 10px;\r\n color: var(--tcw-text-muted);\r\n font-family: var(--tcw-font-mono);\r\n border: 1px solid var(--tcw-border);\r\n background: var(--tcw-bg-surface);\r\n padding: 3px 7px;\r\n border-radius: 4px;\r\n flex-shrink: 0;\r\n box-shadow: inset 0 -1px 0 var(--tcw-border);\r\n}\r\n\r\n.tcw-cmd-list {\r\n overflow-y: auto;\r\n flex: 1;\r\n padding: 6px;\r\n max-height: 380px;\r\n}\r\n\r\n.tcw-cmd-category {\r\n text-transform: uppercase;\r\n font-size: 10px;\r\n color: var(--tcw-text-muted);\r\n letter-spacing: 0.09em;\r\n padding: 10px 10px 4px;\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-cmd-item {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 9px 12px;\r\n font-size: 13px;\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n width: 100%;\r\n border: none;\r\n background: transparent;\r\n font-family: inherit;\r\n text-align: left;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n gap: 10px;\r\n border-radius: var(--tcw-radius);\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-cmd-item:hover,\r\n.tcw-cmd-item.tcw-selected {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-cmd-item.tcw-selected {\r\n box-shadow: inset 2px 0 0 var(--tcw-accent);\r\n}\r\n\r\n.tcw-cmd-item.tcw-active .tcw-cmd-item-label {\r\n color: var(--tcw-accent);\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-cmd-item-label {\r\n flex: 1;\r\n}\r\n\r\n.tcw-cmd-check {\r\n color: var(--tcw-accent);\r\n font-size: 14px;\r\n font-weight: 700;\r\n}\r\n\r\n.tcw-cmd-kbd {\r\n font-size: 10px;\r\n font-family: var(--tcw-font-mono);\r\n color: var(--tcw-text-muted);\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n padding: 2px 6px;\r\n border-radius: 4px;\r\n box-shadow: inset 0 -1px 0 var(--tcw-border);\r\n}\r\n\r\n.tcw-cmd-empty {\r\n padding: 32px 16px;\r\n text-align: center;\r\n color: var(--tcw-text-muted);\r\n font-size: 13px;\r\n}\r\n\r\n.tcw-cmd-footer {\r\n display: flex;\r\n align-items: center;\r\n gap: 18px;\r\n padding: 10px 18px;\r\n border-top: 1px solid var(--tcw-divider);\r\n font-size: 11px;\r\n color: var(--tcw-text-muted);\r\n background: var(--tcw-bg-surface);\r\n}\r\n\r\n/* === Watchlist === */\r\n\r\n.tcw-watchlist {\r\n width: 220px;\r\n flex-shrink: 0;\r\n background: var(--tcw-bg-surface);\r\n border-left: 1px solid var(--tcw-border);\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n box-shadow: var(--tcw-shadow-sm);\r\n}\r\n\r\n.tcw-watchlist-header {\r\n padding: 10px 14px;\r\n font-size: 11px;\r\n font-weight: 600;\r\n text-transform: uppercase;\r\n letter-spacing: 0.08em;\r\n color: var(--tcw-text-muted);\r\n border-bottom: 1px solid var(--tcw-divider);\r\n}\r\n\r\n.tcw-watchlist-list {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 4px 0;\r\n}\r\n\r\n.tcw-watchlist-row {\r\n display: grid;\r\n grid-template-columns: 1fr auto auto;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 8px 12px;\r\n cursor: pointer;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\r\n border-left: 2px solid transparent;\r\n outline: none;\r\n}\r\n\r\n.tcw-watchlist-row:hover {\r\n background: var(--tcw-hover-bg);\r\n}\r\n\r\n.tcw-watchlist-row:focus-visible {\r\n background: var(--tcw-hover-bg);\r\n border-left-color: var(--tcw-accent);\r\n}\r\n\r\n.tcw-watchlist-row.tcw-watchlist-active {\r\n background: var(--tcw-accent-soft);\r\n border-left-color: var(--tcw-accent);\r\n}\r\n\r\n.tcw-watchlist-symbol {\r\n font-size: 12.5px;\r\n font-weight: 600;\r\n color: var(--tcw-text);\r\n letter-spacing: -0.005em;\r\n white-space: nowrap;\r\n}\r\n\r\n.tcw-watchlist-spark {\r\n width: 56px;\r\n height: 22px;\r\n align-self: center;\r\n}\r\n\r\n.tcw-watchlist-stats {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: flex-end;\r\n gap: 1px;\r\n font-variant-numeric: tabular-nums;\r\n font-family: var(--tcw-font-mono);\r\n}\r\n\r\n.tcw-watchlist-price {\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n font-weight: 500;\r\n}\r\n\r\n.tcw-watchlist-change {\r\n font-size: 10.5px;\r\n color: var(--tcw-text-muted);\r\n font-weight: 500;\r\n}\r\n\r\n.tcw-watchlist-change.tcw-up {\r\n color: var(--tcw-green);\r\n}\r\n\r\n.tcw-watchlist-change.tcw-down {\r\n color: var(--tcw-red);\r\n}\r\n\r\n@media (max-width: 768px) {\r\n .tcw-watchlist {\r\n display: none;\r\n }\r\n}\r\n\r\n/* === Toast === */\r\n\r\n.tcw-toast {\r\n position: absolute;\r\n bottom: 60px;\r\n left: 50%;\r\n transform: translate(-50%, 12px);\r\n z-index: 40;\r\n padding: 9px 14px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: 9999px;\r\n box-shadow: var(--tcw-shadow-lg);\r\n font-size: 12.5px;\r\n font-weight: 500;\r\n color: var(--tcw-text);\r\n opacity: 0;\r\n transition: opacity var(--tcw-dur-normal) var(--tcw-ease-out), transform var(--tcw-dur-normal) var(--tcw-ease-out);\r\n pointer-events: none;\r\n max-width: calc(100% - 32px);\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-toast.tcw-toast-in {\r\n opacity: 1;\r\n transform: translate(-50%, 0);\r\n}\r\n\r\n.tcw-toast-error {\r\n border-color: var(--tcw-red);\r\n color: var(--tcw-red);\r\n}\r\n\r\n/* === Replay scrubber === */\r\n\r\n.tcw-replay-bar {\r\n position: absolute;\r\n left: 50%;\r\n bottom: 16px;\r\n transform: translateX(-50%);\r\n z-index: 25;\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 6px 10px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: 9999px;\r\n box-shadow: var(--tcw-shadow-lg);\r\n backdrop-filter: blur(12px);\r\n -webkit-backdrop-filter: blur(12px);\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n animation: tcw-pop-in var(--tcw-dur-normal) var(--tcw-ease-out);\r\n}\r\n\r\n.tcw-replay-btn {\r\n width: 28px;\r\n height: 28px;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-dim);\r\n border-radius: 9999px;\r\n cursor: pointer;\r\n font-family: inherit;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-replay-btn:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-replay-btn.tcw-replay-play {\r\n background: var(--tcw-accent);\r\n color: #fff;\r\n width: 32px;\r\n height: 32px;\r\n box-shadow: 0 0 0 3px var(--tcw-accent-glow);\r\n}\r\n\r\n.tcw-replay-btn.tcw-replay-play:hover {\r\n background: var(--tcw-accent-hover);\r\n}\r\n\r\n.tcw-replay-scrubber {\r\n appearance: none;\r\n -webkit-appearance: none;\r\n width: 220px;\r\n height: 4px;\r\n background: var(--tcw-border-strong);\r\n border-radius: 2px;\r\n outline: none;\r\n cursor: pointer;\r\n}\r\n\r\n.tcw-replay-scrubber::-webkit-slider-thumb {\r\n -webkit-appearance: none;\r\n appearance: none;\r\n width: 14px;\r\n height: 14px;\r\n border-radius: 50%;\r\n background: var(--tcw-accent);\r\n border: 2px solid var(--tcw-bg-elevated);\r\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\r\n cursor: pointer;\r\n}\r\n\r\n.tcw-replay-scrubber::-moz-range-thumb {\r\n width: 14px;\r\n height: 14px;\r\n border-radius: 50%;\r\n background: var(--tcw-accent);\r\n border: 2px solid var(--tcw-bg-elevated);\r\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\r\n cursor: pointer;\r\n}\r\n\r\n.tcw-replay-progress {\r\n font-size: 11px;\r\n font-family: var(--tcw-font-mono);\r\n color: var(--tcw-text-muted);\r\n min-width: 64px;\r\n text-align: center;\r\n font-feature-settings: 'tnum';\r\n}\r\n\r\n.tcw-replay-speed {\r\n padding: 4px 8px;\r\n font-size: 11px;\r\n font-family: var(--tcw-font-mono);\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius);\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n}\r\n\r\n.tcw-replay-speed:hover {\r\n border-color: var(--tcw-border-strong);\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .tcw-replay-scrubber {\r\n width: 140px;\r\n }\r\n .tcw-replay-progress {\r\n display: none;\r\n }\r\n}\r\n\r\n/* === Hotkey sheet === */\r\n\r\n.tcw-hotkey-grid {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr;\r\n gap: 24px 32px;\r\n}\r\n\r\n.tcw-hotkey-section .tcw-settings-section-title {\r\n margin-bottom: 8px;\r\n}\r\n\r\n.tcw-hotkey-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 12px;\r\n padding: 6px 0;\r\n border-bottom: 1px solid var(--tcw-divider);\r\n}\r\n\r\n.tcw-hotkey-row:last-child {\r\n border-bottom: none;\r\n}\r\n\r\n.tcw-hotkey-keys {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n flex-shrink: 0;\r\n}\r\n\r\n.tcw-hotkey-sep {\r\n font-size: 10px;\r\n color: var(--tcw-text-muted);\r\n}\r\n\r\n.tcw-hotkey-label {\r\n font-size: 12.5px;\r\n color: var(--tcw-text-dim);\r\n text-align: right;\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .tcw-hotkey-grid {\r\n grid-template-columns: 1fr;\r\n gap: 18px;\r\n }\r\n}\r\n\r\n/* === Scrollbar (subtle, premium feel) === */\r\n\r\n.tcw-dropdown::-webkit-scrollbar,\r\n.tcw-modal-body::-webkit-scrollbar,\r\n.tcw-cmd-list::-webkit-scrollbar {\r\n width: 8px;\r\n height: 8px;\r\n}\r\n\r\n.tcw-dropdown::-webkit-scrollbar-track,\r\n.tcw-modal-body::-webkit-scrollbar-track,\r\n.tcw-cmd-list::-webkit-scrollbar-track {\r\n background: transparent;\r\n}\r\n\r\n.tcw-dropdown::-webkit-scrollbar-thumb,\r\n.tcw-modal-body::-webkit-scrollbar-thumb,\r\n.tcw-cmd-list::-webkit-scrollbar-thumb {\r\n background: var(--tcw-border-strong);\r\n border-radius: 4px;\r\n border: 2px solid transparent;\r\n background-clip: padding-box;\r\n}\r\n\r\n.tcw-dropdown::-webkit-scrollbar-thumb:hover,\r\n.tcw-modal-body::-webkit-scrollbar-thumb:hover,\r\n.tcw-cmd-list::-webkit-scrollbar-thumb:hover {\r\n background: var(--tcw-text-muted);\r\n background-clip: padding-box;\r\n border: 2px solid transparent;\r\n}\r\n\r\n/* === Responsive === */\r\n\r\n@media (max-width: 768px) {\r\n .tcw-toolbar {\r\n padding: 0 4px;\r\n height: 44px; /* Apple HIG minimum touch target */\r\n }\r\n .tcw-toolbar-sep {\r\n display: none;\r\n }\r\n .tcw-indicator-chips {\r\n display: none;\r\n }\r\n .tcw-btn,\r\n .tcw-dropdown-trigger {\r\n padding: 10px 12px; /* fatter tap target */\r\n font-size: 13px;\r\n }\r\n .tcw-btn-icon {\r\n width: 40px;\r\n height: 40px;\r\n }\r\n .tcw-sidebar {\r\n width: 44px;\r\n }\r\n .tcw-sidebar-btn {\r\n width: 40px;\r\n height: 40px;\r\n }\r\n .tcw-modal,\r\n .tcw-cmd-palette {\r\n width: 94vw;\r\n border-radius: var(--tcw-radius-lg);\r\n }\r\n\r\n /* Hide the right-side watchlist on tablets too — already declared but\r\n * grouped here for clarity. */\r\n .tcw-watchlist {\r\n display: none;\r\n }\r\n\r\n /* Replay scrubber compact mode */\r\n .tcw-replay-scrubber {\r\n width: 120px;\r\n }\r\n .tcw-replay-progress {\r\n display: none;\r\n }\r\n}\r\n\r\n/* === Mobile bottom-sheet pattern ===\r\n * On phones, swap floating-centered modals for full-width sheets that slide\r\n * up from the bottom. Bigger hit targets, no awkward off-screen clipping,\r\n * matches how every modern iOS/Android app handles overflow UI.\r\n */\r\n@media (max-width: 640px) {\r\n .tcw-modal,\r\n .tcw-cmd-palette {\r\n top: auto;\r\n bottom: 0;\r\n left: 0;\r\n right: 0;\r\n transform: none;\r\n width: 100vw;\r\n max-width: 100vw;\r\n max-height: 92vh;\r\n border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;\r\n border-bottom: none;\r\n /* Grab handle */\r\n padding-top: 8px;\r\n }\r\n\r\n /* Visual \"grab handle\" affordance — a short pill at the top of every sheet */\r\n .tcw-modal::before,\r\n .tcw-cmd-palette::before {\r\n content: '';\r\n display: block;\r\n width: 36px;\r\n height: 4px;\r\n border-radius: 2px;\r\n background: var(--tcw-border-strong);\r\n margin: 0 auto 8px;\r\n opacity: 0.7;\r\n }\r\n\r\n /* Reuse the existing modal-in animation but slide from below instead of\r\n * popping from center, so the entrance reads as a sheet, not a dialog. */\r\n @keyframes tcw-modal-in {\r\n from { opacity: 0; transform: translateY(20px); }\r\n to { opacity: 1; transform: translateY(0); }\r\n }\r\n\r\n .tcw-modal,\r\n .tcw-cmd-palette {\r\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\r\n }\r\n\r\n /* Safe-area-aware footer padding for iPhone notch / home indicator */\r\n .tcw-modal-footer,\r\n .tcw-cmd-footer {\r\n padding-bottom: max(14px, env(safe-area-inset-bottom));\r\n }\r\n\r\n /* Larger tap targets inside sheets */\r\n .tcw-modal-tab {\r\n padding: 14px 16px;\r\n }\r\n .tcw-cmd-item {\r\n padding: 12px 14px;\r\n font-size: 14px;\r\n }\r\n .tcw-dropdown-item {\r\n padding: 12px 12px;\r\n font-size: 14px;\r\n }\r\n\r\n /* Hotkey sheet — single column on phones */\r\n .tcw-hotkey-grid {\r\n grid-template-columns: 1fr;\r\n }\r\n}\r\n\r\n/* === Price alerts panel === */\r\n\r\n.tcw-alerts-panel {\r\n position: absolute;\r\n top: 50px;\r\n right: 12px;\r\n z-index: 40;\r\n width: 300px;\r\n max-width: calc(100vw - 24px);\r\n display: flex;\r\n flex-direction: column;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n overflow: hidden;\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n\r\n@keyframes tcw-alerts-in {\r\n from { opacity: 0; transform: translateY(-6px) scale(0.98); }\r\n to { opacity: 1; transform: none; }\r\n}\r\n\r\n.tcw-alerts-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 12px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n color: var(--tcw-text);\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n\r\n.tcw-alerts-close {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-alerts-close:hover {\r\n background: var(--tcw-bg-surface);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-alerts-form {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr;\r\n gap: 8px;\r\n padding: 12px;\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n\r\n.tcw-alerts-form input,\r\n.tcw-alerts-form select {\r\n width: 100%;\r\n min-width: 0;\r\n box-sizing: border-box;\r\n height: 32px;\r\n padding: 0 8px;\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n outline: none;\r\n}\r\n.tcw-alerts-form input:focus,\r\n.tcw-alerts-form select:focus {\r\n border-color: var(--tcw-accent);\r\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\r\n}\r\n.tcw-alerts-message,\r\n.tcw-alerts-source {\r\n grid-column: 1 / -1;\r\n}\r\n\r\n.tcw-alerts-add {\r\n grid-column: 1 / -1;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 6px;\r\n height: 34px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: #fff;\r\n background: var(--tcw-accent);\r\n border: none;\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-alerts-add:hover {\r\n background: var(--tcw-accent-hover);\r\n}\r\n\r\n.tcw-alerts-list {\r\n max-height: 260px;\r\n overflow-y: auto;\r\n padding: 6px;\r\n}\r\n\r\n.tcw-alerts-empty {\r\n padding: 18px 12px;\r\n text-align: center;\r\n font-size: 12px;\r\n color: var(--tcw-text-muted);\r\n line-height: 1.5;\r\n}\r\n\r\n.tcw-alerts-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 8px;\r\n padding: 8px 8px;\r\n border-radius: var(--tcw-radius-sm);\r\n}\r\n.tcw-alerts-row:hover {\r\n background: var(--tcw-bg-surface);\r\n}\r\n.tcw-alerts-triggered {\r\n background: var(--tcw-accent-soft);\r\n}\r\n\r\n.tcw-alerts-info {\r\n min-width: 0;\r\n}\r\n.tcw-alerts-row-main {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--tcw-text);\r\n font-variant-numeric: tabular-nums;\r\n}\r\n.tcw-alerts-row-note {\r\n margin-top: 2px;\r\n font-size: 11px;\r\n color: var(--tcw-text-muted);\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n.tcw-alerts-badge {\r\n font-size: 9px;\r\n font-weight: 700;\r\n text-transform: uppercase;\r\n letter-spacing: 0.04em;\r\n padding: 2px 5px;\r\n border-radius: 999px;\r\n color: var(--tcw-accent);\r\n background: var(--tcw-accent-soft);\r\n}\r\n\r\n.tcw-alerts-del {\r\n flex-shrink: 0;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 28px;\r\n height: 28px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-alerts-del:hover {\r\n background: var(--tcw-red-soft);\r\n color: var(--tcw-red);\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .tcw-alerts-panel {\r\n top: auto;\r\n bottom: 0;\r\n left: 0;\r\n right: 0;\r\n width: 100vw;\r\n max-width: 100vw;\r\n border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;\r\n }\r\n .tcw-alerts-list {\r\n max-height: 40vh;\r\n padding-bottom: max(8px, env(safe-area-inset-bottom));\r\n }\r\n}\r\n\r\n/* === Data Window === */\r\n\r\n.tcw-datawin {\r\n position: absolute;\r\n top: 50px;\r\n right: 12px;\r\n z-index: 38;\r\n width: 200px;\r\n display: flex;\r\n flex-direction: column;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n overflow: hidden;\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n.tcw-datawin-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 9px 12px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--tcw-text);\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n.tcw-datawin-close {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 24px;\r\n height: 24px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-datawin-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\r\n.tcw-datawin-body { padding: 6px 4px; max-height: 360px; overflow-y: auto; }\r\n.tcw-datawin-empty { padding: 14px; text-align: center; font-size: 12px; color: var(--tcw-text-muted); }\r\n.tcw-datawin-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 10px;\r\n padding: 3px 8px;\r\n font-size: 12px;\r\n}\r\n.tcw-datawin-label { color: var(--tcw-text-muted); }\r\n.tcw-datawin-value { color: var(--tcw-text); font-variant-numeric: tabular-nums; font-weight: 600; }\r\n.tcw-datawin-value.tcw-up { color: var(--tcw-green); }\r\n.tcw-datawin-value.tcw-down { color: var(--tcw-red); }\r\n.tcw-datawin-sub {\r\n margin: 6px 8px 2px;\r\n font-size: 10px;\r\n font-weight: 700;\r\n text-transform: uppercase;\r\n letter-spacing: 0.04em;\r\n color: var(--tcw-text-muted);\r\n border-top: 1px solid var(--tcw-border);\r\n padding-top: 6px;\r\n}\r\n\r\n@media (max-width: 640px) {\r\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; }\r\n}\r\n\r\n/* === Depth-of-market ladder === */\r\n\r\n.tcw-ladder {\r\n position: absolute;\r\n top: 50px;\r\n right: 12px;\r\n z-index: 41;\r\n width: 240px;\r\n display: flex;\r\n flex-direction: column;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n overflow: hidden;\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n.tcw-ladder-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 12px;\r\n font-size: 13px;\r\n font-weight: 600;\r\n color: var(--tcw-text);\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n.tcw-ladder-close {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-ladder-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\r\n.tcw-ladder-cols {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr 1fr;\r\n padding: 4px 0;\r\n font-size: 10px;\r\n font-weight: 700;\r\n text-transform: uppercase;\r\n letter-spacing: 0.04em;\r\n color: var(--tcw-text-muted);\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n.tcw-ladder-cols span { text-align: center; }\r\n.tcw-ladder-body { max-height: 360px; overflow-y: auto; }\r\n.tcw-ladder-empty { padding: 18px; text-align: center; font-size: 12px; color: var(--tcw-text-muted); }\r\n\r\n.tcw-ladder-row {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr 1fr;\r\n height: 22px;\r\n font-variant-numeric: tabular-nums;\r\n}\r\n.tcw-ladder-cell {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n border: none;\r\n background: transparent;\r\n font-size: 11px;\r\n cursor: pointer;\r\n font-variant-numeric: tabular-nums;\r\n overflow: hidden;\r\n}\r\n.tcw-ladder-cell:disabled { cursor: default; }\r\n/* Depth bar grows from the centre column outward. */\r\n.tcw-ladder-cell::before {\r\n content: '';\r\n position: absolute;\r\n top: 1px; bottom: 1px;\r\n width: var(--w, 0%);\r\n}\r\n.tcw-ladder-bid { justify-content: flex-end; padding-right: 8px; color: var(--tcw-green); }\r\n.tcw-ladder-bid::before { right: 0; background: var(--tcw-green-soft); }\r\n.tcw-ladder-bid span, .tcw-ladder-bid { position: relative; }\r\n.tcw-ladder-ask { justify-content: flex-start; padding-left: 8px; color: var(--tcw-red); }\r\n.tcw-ladder-ask::before { left: 0; background: var(--tcw-red-soft); }\r\n.tcw-ladder-cell:not(:disabled):hover::before { opacity: 0.7; filter: brightness(1.4); }\r\n.tcw-ladder-cell > * { position: relative; }\r\n.tcw-ladder-price {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--tcw-text-dim);\r\n border-left: 1px solid var(--tcw-border);\r\n border-right: 1px solid var(--tcw-border);\r\n}\r\n.tcw-ladder-price.tcw-ask { color: var(--tcw-red); }\r\n.tcw-ladder-price.tcw-bid { color: var(--tcw-green); }\r\n\r\n@media (max-width: 640px) {\r\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; }\r\n .tcw-ladder-body { max-height: 45vh; padding-bottom: max(0px, env(safe-area-inset-bottom)); }\r\n}\r\n\r\n/* === Bracket order placement === */\r\n\r\n.tcw-btn-long:hover { color: var(--tcw-green) !important; }\r\n.tcw-btn-short:hover { color: var(--tcw-red) !important; }\r\n\r\n.tcw-bracket-bar {\r\n position: absolute;\r\n top: 52px;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n z-index: 45;\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n padding: 7px 8px 7px 14px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: 999px;\r\n box-shadow: var(--tcw-shadow-lg);\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n.tcw-bracket-label {\r\n font-size: 12px;\r\n font-weight: 700;\r\n}\r\n.tcw-bracket-label[data-side='buy'] { color: var(--tcw-green); }\r\n.tcw-bracket-label[data-side='sell'] { color: var(--tcw-red); }\r\n.tcw-bracket-hint {\r\n font-size: 11px;\r\n color: var(--tcw-text-muted);\r\n}\r\n.tcw-bracket-cancel, .tcw-bracket-confirm {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 5px;\r\n height: 30px;\r\n padding: 0 12px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n border: none;\r\n border-radius: 999px;\r\n cursor: pointer;\r\n}\r\n.tcw-bracket-cancel {\r\n color: var(--tcw-text-dim);\r\n background: var(--tcw-bg-surface);\r\n}\r\n.tcw-bracket-cancel:hover { color: var(--tcw-text); }\r\n.tcw-bracket-confirm {\r\n color: #fff;\r\n background: var(--tcw-accent);\r\n}\r\n.tcw-bracket-confirm:hover { background: var(--tcw-accent-hover); }\r\n\r\n@media (max-width: 640px) {\r\n .tcw-bracket-bar { width: calc(100vw - 24px); justify-content: space-between; }\r\n .tcw-bracket-hint { display: none; }\r\n}\r\n\r\n/* === Drawing style + templates popover === */\r\n\r\n.tcw-style-panel {\r\n position: absolute;\r\n bottom: 12px;\r\n left: 52px;\r\n z-index: 40;\r\n width: 220px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n padding: 12px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n.tcw-style-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--tcw-text);\r\n}\r\n.tcw-style-close {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 24px;\r\n height: 24px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-style-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\r\n\r\n.tcw-style-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\r\n.tcw-style-swatch {\r\n width: 18px;\r\n height: 18px;\r\n border-radius: 50%;\r\n border: 1px solid var(--tcw-border-strong);\r\n cursor: pointer;\r\n padding: 0;\r\n}\r\n.tcw-style-swatch.tcw-on { outline: 2px solid var(--tcw-accent); outline-offset: 1px; }\r\n.tcw-style-picker {\r\n width: 22px;\r\n height: 22px;\r\n padding: 0;\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n background: transparent;\r\n cursor: pointer;\r\n}\r\n.tcw-style-width, .tcw-style-dash {\r\n flex: 1;\r\n min-width: 0;\r\n height: 26px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n font-size: 11px;\r\n}\r\n.tcw-style-width span { width: 16px; background: currentColor; border-radius: 2px; }\r\n.tcw-style-width.tcw-on, .tcw-style-dash.tcw-on {\r\n border-color: var(--tcw-accent);\r\n color: var(--tcw-accent);\r\n}\r\n\r\n.tcw-style-subhead {\r\n font-size: 10px;\r\n font-weight: 700;\r\n text-transform: uppercase;\r\n letter-spacing: 0.05em;\r\n color: var(--tcw-text-muted);\r\n margin-top: 2px;\r\n}\r\n.tcw-style-save { display: flex; gap: 6px; }\r\n.tcw-style-name {\r\n flex: 1;\r\n min-width: 0;\r\n height: 28px;\r\n padding: 0 8px;\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n outline: none;\r\n}\r\n.tcw-style-name:focus { border-color: var(--tcw-accent); }\r\n.tcw-style-savebtn {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 4px;\r\n padding: 0 10px;\r\n height: 28px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: #fff;\r\n background: var(--tcw-accent);\r\n border: none;\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-style-savebtn:hover { background: var(--tcw-accent-hover); }\r\n\r\n.tcw-style-templates { display: flex; flex-direction: column; gap: 2px; max-height: 140px; overflow-y: auto; }\r\n.tcw-style-empty { font-size: 11px; color: var(--tcw-text-muted); padding: 4px 0; }\r\n.tcw-style-template { display: flex; align-items: center; gap: 4px; }\r\n.tcw-style-apply {\r\n flex: 1;\r\n min-width: 0;\r\n display: flex;\r\n align-items: center;\r\n gap: 7px;\r\n padding: 5px 7px;\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n background: transparent;\r\n border: none;\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n text-align: left;\r\n}\r\n.tcw-style-apply:hover { background: var(--tcw-bg-surface); }\r\n.tcw-style-tdot { flex-shrink: 0; width: 9px; height: 9px; border-radius: 50%; }\r\n.tcw-style-tdel {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-style-tdel:hover { background: var(--tcw-red-soft); color: var(--tcw-red); }\r\n\r\n/* === Settings range slider === */\r\n\r\n.tcw-settings-range {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n.tcw-settings-range input[type='range'] {\r\n width: 110px;\r\n accent-color: var(--tcw-accent);\r\n cursor: pointer;\r\n}\r\n.tcw-settings-range-val {\r\n min-width: 38px;\r\n text-align: right;\r\n font-size: 12px;\r\n font-variant-numeric: tabular-nums;\r\n color: var(--tcw-text-dim);\r\n}\r\n\r\n/* === Indicator settings dialog === */\r\n\r\n.tcw-modal-narrow {\r\n max-width: 360px;\r\n}\r\n.tcw-indi-input {\r\n width: 110px;\r\n height: 30px;\r\n padding: 0 8px;\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n outline: none;\r\n font-variant-numeric: tabular-nums;\r\n}\r\n.tcw-indi-input:focus {\r\n border-color: var(--tcw-accent);\r\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\r\n}\r\n.tcw-indi-color {\r\n width: 36px;\r\n height: 28px;\r\n padding: 2px;\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n\r\n/* === Object tree panel === */\r\n\r\n.tcw-tree-panel {\r\n position: absolute;\r\n top: 50px;\r\n right: 12px;\r\n z-index: 39;\r\n width: 280px;\r\n max-width: calc(100vw - 24px);\r\n display: flex;\r\n flex-direction: column;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n overflow: hidden;\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n\r\n.tcw-tree-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 12px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n color: var(--tcw-text);\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n.tcw-tree-close {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-tree-close:hover {\r\n background: var(--tcw-bg-surface);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-tree-section {\r\n padding: 6px;\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n.tcw-tree-section:last-child {\r\n border-bottom: none;\r\n}\r\n.tcw-tree-section-head {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 6px 8px 4px;\r\n font-size: 10px;\r\n font-weight: 700;\r\n text-transform: uppercase;\r\n letter-spacing: 0.05em;\r\n color: var(--tcw-text-muted);\r\n}\r\n.tcw-tree-add {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 22px;\r\n height: 22px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-tree-add:hover {\r\n background: var(--tcw-accent-soft);\r\n color: var(--tcw-accent);\r\n}\r\n.tcw-tree-dot {\r\n flex-shrink: 0;\r\n width: 8px;\r\n height: 8px;\r\n border-radius: 50%;\r\n}\r\n.tcw-tree-list {\r\n max-height: 200px;\r\n overflow-y: auto;\r\n}\r\n\r\n.tcw-tree-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 8px;\r\n padding: 6px 8px;\r\n border-radius: var(--tcw-radius-sm);\r\n}\r\n.tcw-tree-row:hover {\r\n background: var(--tcw-bg-surface);\r\n}\r\n.tcw-tree-hidden .tcw-tree-name {\r\n opacity: 0.5;\r\n}\r\n.tcw-tree-name {\r\n min-width: 0;\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n.tcw-tree-actions {\r\n display: flex;\r\n align-items: center;\r\n gap: 2px;\r\n flex-shrink: 0;\r\n}\r\n.tcw-tree-btn {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-tree-btn:hover {\r\n background: var(--tcw-bg-elevated);\r\n color: var(--tcw-text);\r\n}\r\n.tcw-tree-btn.tcw-tree-on {\r\n color: var(--tcw-accent);\r\n}\r\n.tcw-tree-btn.tcw-tree-del:hover {\r\n background: var(--tcw-red-soft);\r\n color: var(--tcw-red);\r\n}\r\n.tcw-tree-empty {\r\n padding: 8px;\r\n font-size: 12px;\r\n color: var(--tcw-text-muted);\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .tcw-tree-panel {\r\n top: auto;\r\n bottom: 0;\r\n left: 0;\r\n right: 0;\r\n width: 100vw;\r\n max-width: 100vw;\r\n border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;\r\n }\r\n .tcw-tree-list {\r\n max-height: 30vh;\r\n }\r\n .tcw-tree-section:last-child {\r\n padding-bottom: max(6px, env(safe-area-inset-bottom));\r\n }\r\n}\r\n\r\n/* === Reduced motion === */\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n .tcw-root *,\r\n .tcw-root *::before,\r\n .tcw-root *::after {\r\n animation-duration: 0.01ms !important;\r\n animation-iteration-count: 1 !important;\r\n transition-duration: 0.01ms !important;\r\n }\r\n}\r\n", m = 0, h = "tcw-styles";
|
|
604
719
|
function g() {
|
|
605
720
|
if (m++, m > 1 || document.getElementById(h)) return;
|
|
606
721
|
let e = document.createElement("style");
|
|
@@ -618,6 +733,7 @@ var v = {
|
|
|
618
733
|
trendingUp: "<polyline points=\"22 7 13.5 15.5 8.5 10.5 2 17\"/><polyline points=\"16 7 22 7 22 13\"/>",
|
|
619
734
|
minus: "<path d=\"M5 12h14\"/>",
|
|
620
735
|
penLine: "<path d=\"M12 20h9\"/><path d=\"M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z\"/>",
|
|
736
|
+
zigzag: "<polyline points=\"2 18 7 8 12 14 17 4 22 12\"/>",
|
|
621
737
|
hash: "<line x1=\"4\" y1=\"9\" x2=\"20\" y2=\"9\"/><line x1=\"4\" y1=\"15\" x2=\"20\" y2=\"15\"/><line x1=\"10\" y1=\"3\" x2=\"8\" y2=\"21\"/><line x1=\"16\" y1=\"3\" x2=\"14\" y2=\"21\"/>",
|
|
622
738
|
square: "<rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\"/>",
|
|
623
739
|
gitBranch: "<line x1=\"6\" y1=\"3\" x2=\"6\" y2=\"15\"/><circle cx=\"18\" cy=\"6\" r=\"3\"/><circle cx=\"6\" cy=\"18\" r=\"3\"/><path d=\"M18 9a9 9 0 0 1-9 9\"/>",
|
|
@@ -691,14 +807,15 @@ var b = class {
|
|
|
691
807
|
}, ne = class {
|
|
692
808
|
config;
|
|
693
809
|
callbacks;
|
|
810
|
+
t;
|
|
694
811
|
el;
|
|
695
812
|
chartTypeDropdown = null;
|
|
696
813
|
indicatorDropdown = null;
|
|
697
814
|
tfButtons = [];
|
|
698
815
|
chipsContainer = null;
|
|
699
816
|
themeBtn = null;
|
|
700
|
-
constructor(e, t, n) {
|
|
701
|
-
this.config = t, this.callbacks = n, this.el = document.createElement("div"), this.el.className = "tcw-toolbar", this.build(), e.appendChild(this.el);
|
|
817
|
+
constructor(e, t, n, r) {
|
|
818
|
+
this.config = t, this.callbacks = n, this.t = r, this.el = document.createElement("div"), this.el.className = "tcw-toolbar", this.build(), e.appendChild(this.el);
|
|
702
819
|
}
|
|
703
820
|
build() {
|
|
704
821
|
let { config: e, callbacks: t, el: n } = this, r = document.createElement("button");
|
|
@@ -718,35 +835,39 @@ var b = class {
|
|
|
718
835
|
s.style.position = "relative", s.style.display = "inline-flex";
|
|
719
836
|
let c = document.createElement("button");
|
|
720
837
|
if (c.className = "tcw-dropdown-trigger", c.dataset.role = "indicators", s.appendChild(c), n.appendChild(s), this.indicatorDropdown = new b(s, { width: "280px" }), this.buildIndicatorMenu(), this.chipsContainer = document.createElement("div"), this.chipsContainer.className = "tcw-indicator-chips", n.appendChild(this.chipsContainer), n.appendChild(this.spacer()), t.onToggleReplay) {
|
|
721
|
-
let e = this.iconBtn("play", "
|
|
838
|
+
let e = this.iconBtn("play", this.t("toolbar.replay"), t.onToggleReplay);
|
|
722
839
|
e.dataset.role = "replay", n.appendChild(e);
|
|
723
840
|
}
|
|
724
841
|
if (t.onBracket) {
|
|
725
|
-
let e = t.onBracket, r = this.iconBtn("trendingUp", "
|
|
842
|
+
let e = t.onBracket, r = this.iconBtn("trendingUp", this.t("toolbar.longBracket"), () => e("buy"));
|
|
726
843
|
r.dataset.role = "long", r.classList.add("tcw-btn-long"), n.appendChild(r);
|
|
727
|
-
let i = this.iconBtn("trendingDown", "
|
|
844
|
+
let i = this.iconBtn("trendingDown", this.t("toolbar.shortBracket"), () => e("sell"));
|
|
728
845
|
i.dataset.role = "short", i.classList.add("tcw-btn-short"), n.appendChild(i);
|
|
729
846
|
}
|
|
730
847
|
if (t.onToggleLadder) {
|
|
731
|
-
let e = this.iconBtn("ladder", "
|
|
848
|
+
let e = this.iconBtn("ladder", this.t("toolbar.depthLadder"), t.onToggleLadder);
|
|
732
849
|
e.dataset.role = "ladder", n.appendChild(e);
|
|
733
850
|
}
|
|
734
851
|
if (t.onToggleObjects) {
|
|
735
|
-
let e = this.iconBtn("layers", "
|
|
852
|
+
let e = this.iconBtn("layers", this.t("toolbar.objects"), t.onToggleObjects);
|
|
736
853
|
e.dataset.role = "objects", n.appendChild(e);
|
|
737
854
|
}
|
|
738
855
|
if (t.onToggleAlerts) {
|
|
739
|
-
let e = this.iconBtn("bell", "
|
|
856
|
+
let e = this.iconBtn("bell", this.t("toolbar.priceAlerts"), t.onToggleAlerts);
|
|
740
857
|
e.dataset.role = "alerts", n.appendChild(e);
|
|
741
858
|
}
|
|
742
|
-
let l = this.iconBtn("camera", "
|
|
859
|
+
let l = this.iconBtn("camera", this.t("toolbar.screenshot"), t.onScreenshot);
|
|
743
860
|
n.appendChild(l);
|
|
744
|
-
let u = this.iconBtn("settings", "
|
|
745
|
-
n.appendChild(u), this.themeBtn = this.iconBtn("moon", "
|
|
861
|
+
let u = this.iconBtn("settings", this.t("toolbar.settings"), t.onSettings);
|
|
862
|
+
n.appendChild(u), this.themeBtn = this.iconBtn("moon", this.t("toolbar.toggleTheme"), t.onToggleTheme), this.themeBtn.dataset.role = "theme", n.appendChild(this.themeBtn);
|
|
863
|
+
}
|
|
864
|
+
chartTypeLabel(e) {
|
|
865
|
+
let t = `chartType.${e.value}`, n = this.t(t);
|
|
866
|
+
return n === t ? e.label : n;
|
|
746
867
|
}
|
|
747
868
|
buildChartTypeMenu() {
|
|
748
869
|
if (!this.chartTypeDropdown) return;
|
|
749
|
-
let e = this.config.chartTypes.map((e) => `<button class="tcw-dropdown-item" data-ct="${e.value}">${e
|
|
870
|
+
let e = this.config.chartTypes.map((e) => `<button class="tcw-dropdown-item" data-ct="${e.value}">${this.chartTypeLabel(e)}</button>`).join("");
|
|
750
871
|
this.chartTypeDropdown.setContent(e), this.chartTypeDropdown.panel.querySelectorAll(".tcw-dropdown-item").forEach((e) => {
|
|
751
872
|
e.addEventListener("click", (e) => {
|
|
752
873
|
let t = e.currentTarget.dataset.ct;
|
|
@@ -756,11 +877,11 @@ var b = class {
|
|
|
756
877
|
}
|
|
757
878
|
buildIndicatorMenu() {
|
|
758
879
|
if (!this.indicatorDropdown) return;
|
|
759
|
-
let { indicators: e, popularIndicatorIds: t } = this.config, n = e.filter((e) => t.includes(e.id)), r = e.filter((e) => !t.includes(e.id)), i =
|
|
760
|
-
for (let e of n)
|
|
761
|
-
|
|
762
|
-
for (let e of r)
|
|
763
|
-
this.indicatorDropdown.setContent(
|
|
880
|
+
let { indicators: e, popularIndicatorIds: t } = this.config, n = e.filter((e) => t.includes(e.id)), r = e.filter((e) => !t.includes(e.id)), i = (e) => this.t(`indicatorType.${e}`), a = `<div class="tcw-dropdown-label">${this.t("toolbar.indicators.popular")}</div>`;
|
|
881
|
+
for (let e of n) a += `<button class="tcw-dropdown-item" data-ind="${e.id}"><span>${e.name}</span><span class="tcw-tag">${i(e.type)}</span></button>`;
|
|
882
|
+
a += "<div class=\"tcw-dropdown-divider\"></div>", a += `<div class="tcw-dropdown-label">${this.t("toolbar.indicators.all")}</div>`;
|
|
883
|
+
for (let e of r) a += `<button class="tcw-dropdown-item" data-ind="${e.id}"><span>${e.name}</span><span class="tcw-tag">${i(e.type)}</span></button>`;
|
|
884
|
+
this.indicatorDropdown.setContent(a), this.indicatorDropdown.panel.querySelectorAll(".tcw-dropdown-item[data-ind]").forEach((e) => {
|
|
764
885
|
e.addEventListener("click", (e) => {
|
|
765
886
|
let t = e.currentTarget.dataset.ind;
|
|
766
887
|
this.callbacks.onAddIndicator(t);
|
|
@@ -773,12 +894,12 @@ var b = class {
|
|
|
773
894
|
for (let t of this.tfButtons) t.classList.toggle("tcw-active", t.dataset.tf === e.timeframe);
|
|
774
895
|
let n = this.el.querySelector("[data-role=\"charttype\"]");
|
|
775
896
|
if (n) {
|
|
776
|
-
let t = this.config.chartTypes.find((t) => t.value === e.chartType)
|
|
777
|
-
n.innerHTML = `${y("barChart", 14)} ${
|
|
897
|
+
let t = this.config.chartTypes.find((t) => t.value === e.chartType), r = t ? this.chartTypeLabel(t) : e.chartType;
|
|
898
|
+
n.innerHTML = `${y("barChart", 14)} ${r} ${y("chevronDown", 12)}`;
|
|
778
899
|
}
|
|
779
900
|
let r = this.el.querySelector("[data-role=\"indicators\"]");
|
|
780
901
|
if (r) {
|
|
781
|
-
let t = e.activeIndicators.size, n = `${y("trendingUp", 14)}
|
|
902
|
+
let t = e.activeIndicators.size, n = `${y("trendingUp", 14)} ${this.t("toolbar.indicators")}`;
|
|
782
903
|
t > 0 && (n += ` <span class="tcw-badge-count">${t}</span>`), r.innerHTML = n;
|
|
783
904
|
}
|
|
784
905
|
if (this.chipsContainer) {
|
|
@@ -826,33 +947,52 @@ var b = class {
|
|
|
826
947
|
"hash",
|
|
827
948
|
"square",
|
|
828
949
|
"gitBranch",
|
|
950
|
+
"zigzag",
|
|
829
951
|
"ruler",
|
|
830
|
-
"type"
|
|
952
|
+
"type",
|
|
953
|
+
"ladder"
|
|
831
954
|
], ie = {
|
|
832
955
|
trendLine: "trendingUp",
|
|
833
956
|
ray: "trendingUp",
|
|
834
957
|
extendedLine: "trendingUp",
|
|
958
|
+
infoLine: "trendingUp",
|
|
959
|
+
trendAngle: "trendingUp",
|
|
835
960
|
horizontalLine: "minus",
|
|
961
|
+
horizontalRay: "minus",
|
|
836
962
|
verticalLine: "penLine",
|
|
963
|
+
crossLine: "plus",
|
|
837
964
|
rectangle: "square",
|
|
965
|
+
circle: "square",
|
|
838
966
|
ellipse: "square",
|
|
839
967
|
triangle: "square",
|
|
840
968
|
arrow: "trendingUp",
|
|
841
969
|
parallelChannel: "gitBranch",
|
|
842
970
|
regressionChannel: "gitBranch",
|
|
843
971
|
pitchfork: "gitBranch",
|
|
972
|
+
schiffPitchfork: "gitBranch",
|
|
973
|
+
modifiedSchiffPitchfork: "gitBranch",
|
|
844
974
|
fibRetracement: "hash",
|
|
845
975
|
fibExtension: "hash",
|
|
846
976
|
fibTimeZones: "hash",
|
|
977
|
+
fibChannel: "hash",
|
|
978
|
+
fibSpeedResistanceFan: "hash",
|
|
847
979
|
gannBox: "hash",
|
|
848
980
|
gannFan: "gitBranch",
|
|
849
|
-
|
|
981
|
+
cyclicLines: "barChart",
|
|
982
|
+
elliottWave: "zigzag",
|
|
983
|
+
xabcdPattern: "zigzag",
|
|
984
|
+
abcdPattern: "zigzag",
|
|
985
|
+
headAndShoulders: "zigzag",
|
|
850
986
|
priceRange: "ruler",
|
|
851
987
|
dateRange: "ruler",
|
|
988
|
+
dateAndPriceRange: "ruler",
|
|
852
989
|
measure: "ruler",
|
|
990
|
+
text: "type",
|
|
853
991
|
textAnnotation: "type",
|
|
992
|
+
priceLabel: "type",
|
|
854
993
|
anchoredVWAP: "trendingUp",
|
|
855
|
-
volumeProfileRange: "barChart"
|
|
994
|
+
volumeProfileRange: "barChart",
|
|
995
|
+
riskReward: "square"
|
|
856
996
|
};
|
|
857
997
|
function ae(e) {
|
|
858
998
|
return ie[e] ?? "penLine";
|
|
@@ -864,7 +1004,7 @@ function oe(e, t) {
|
|
|
864
1004
|
}
|
|
865
1005
|
return t;
|
|
866
1006
|
}
|
|
867
|
-
var
|
|
1007
|
+
var se = class {
|
|
868
1008
|
config;
|
|
869
1009
|
callbacks;
|
|
870
1010
|
el;
|
|
@@ -959,20 +1099,21 @@ var x = class {
|
|
|
959
1099
|
destroy() {
|
|
960
1100
|
this.hideFlyout(), this.el.remove();
|
|
961
1101
|
}
|
|
962
|
-
},
|
|
1102
|
+
}, x = [
|
|
963
1103
|
"style",
|
|
964
1104
|
"display",
|
|
965
1105
|
"scale"
|
|
966
|
-
],
|
|
1106
|
+
], S = class {
|
|
967
1107
|
callbacks;
|
|
1108
|
+
t;
|
|
968
1109
|
backdrop = null;
|
|
969
1110
|
modal = null;
|
|
970
1111
|
currentTab = "style";
|
|
971
1112
|
currentSettings = null;
|
|
972
1113
|
bodyEl = null;
|
|
973
1114
|
tabButtons = [];
|
|
974
|
-
constructor(e) {
|
|
975
|
-
this.callbacks = e;
|
|
1115
|
+
constructor(e, t) {
|
|
1116
|
+
this.callbacks = e, this.t = t;
|
|
976
1117
|
}
|
|
977
1118
|
open(e) {
|
|
978
1119
|
this.currentSettings = { ...e }, this.currentTab = "style", this.buildModal();
|
|
@@ -987,16 +1128,16 @@ var x = class {
|
|
|
987
1128
|
let e = document.createElement("div");
|
|
988
1129
|
e.className = "tcw-modal-header";
|
|
989
1130
|
let t = document.createElement("h3");
|
|
990
|
-
t.textContent = "
|
|
1131
|
+
t.textContent = this.t("settings.title"), e.appendChild(t);
|
|
991
1132
|
let n = document.createElement("button");
|
|
992
1133
|
n.className = "tcw-modal-close", n.innerHTML = y("x", 16), n.addEventListener("click", () => {
|
|
993
1134
|
this.callbacks.onClose(), this.close();
|
|
994
1135
|
}), e.appendChild(n), this.modal.appendChild(e);
|
|
995
1136
|
let r = document.createElement("div");
|
|
996
1137
|
r.className = "tcw-modal-tabs", this.tabButtons = [];
|
|
997
|
-
for (let e of
|
|
1138
|
+
for (let e of x) {
|
|
998
1139
|
let t = document.createElement("button");
|
|
999
|
-
t.className = "tcw-modal-tab", t.textContent = e, t.dataset.tab = e, e === this.currentTab && t.classList.add("tcw-active"), t.addEventListener("click", () => {
|
|
1140
|
+
t.className = "tcw-modal-tab", t.textContent = this.t(`settings.tab.${e}`), t.dataset.tab = e, e === this.currentTab && t.classList.add("tcw-active"), t.addEventListener("click", () => {
|
|
1000
1141
|
this.currentTab = e, this.tabButtons.forEach((t) => t.classList.toggle("tcw-active", t.dataset.tab === e)), this.renderTabContent();
|
|
1001
1142
|
}), r.appendChild(t), this.tabButtons.push(t);
|
|
1002
1143
|
}
|
|
@@ -1004,9 +1145,9 @@ var x = class {
|
|
|
1004
1145
|
let i = document.createElement("div");
|
|
1005
1146
|
i.className = "tcw-modal-footer";
|
|
1006
1147
|
let a = document.createElement("button");
|
|
1007
|
-
a.className = "tcw-reset-link", a.textContent = "
|
|
1148
|
+
a.className = "tcw-reset-link", a.textContent = this.t("settings.resetToDefaults"), a.addEventListener("click", () => this.callbacks.onReset()), i.appendChild(a);
|
|
1008
1149
|
let o = document.createElement("button");
|
|
1009
|
-
o.className = "tcw-done-btn", o.textContent = "
|
|
1150
|
+
o.className = "tcw-done-btn", o.textContent = this.t("settings.done"), o.addEventListener("click", () => {
|
|
1010
1151
|
this.callbacks.onClose(), this.close();
|
|
1011
1152
|
}), i.appendChild(o), this.modal.appendChild(i), document.body.appendChild(this.modal);
|
|
1012
1153
|
let s = (e) => {
|
|
@@ -1029,9 +1170,9 @@ var x = class {
|
|
|
1029
1170
|
}
|
|
1030
1171
|
renderStyleTab() {
|
|
1031
1172
|
if (!this.bodyEl || !this.currentSettings) return;
|
|
1032
|
-
let e = this.currentSettings, t = this.section("
|
|
1173
|
+
let e = this.currentSettings, t = this.section(this.t("settings.section.candleColors"));
|
|
1033
1174
|
t.appendChild(this.colorRow("Up Body", e.candleUpColor, (e) => this.patch({ candleUpColor: e }))), t.appendChild(this.colorRow("Down Body", e.candleDownColor, (e) => this.patch({ candleDownColor: e }))), t.appendChild(this.colorRow("Up Wick", e.candleUpWick, (e) => this.patch({ candleUpWick: e }))), t.appendChild(this.colorRow("Down Wick", e.candleDownWick, (e) => this.patch({ candleDownWick: e }))), this.bodyEl.appendChild(t);
|
|
1034
|
-
let n = this.section("
|
|
1175
|
+
let n = this.section(this.t("settings.section.background"));
|
|
1035
1176
|
n.appendChild(this.colorRow("Background", e.backgroundColor, (e) => this.patch({ backgroundColor: e }))), n.appendChild(this.colorRow("Grid", e.gridColor, (e) => this.patch({ gridColor: e }))), this.bodyEl.appendChild(n);
|
|
1036
1177
|
}
|
|
1037
1178
|
renderDisplayTab() {
|
|
@@ -1205,7 +1346,7 @@ var x = class {
|
|
|
1205
1346
|
destroy() {
|
|
1206
1347
|
this.close();
|
|
1207
1348
|
}
|
|
1208
|
-
},
|
|
1349
|
+
}, C = class {
|
|
1209
1350
|
el;
|
|
1210
1351
|
dotEl;
|
|
1211
1352
|
messageEl;
|
|
@@ -1221,7 +1362,7 @@ var x = class {
|
|
|
1221
1362
|
destroy() {
|
|
1222
1363
|
this.el.remove();
|
|
1223
1364
|
}
|
|
1224
|
-
},
|
|
1365
|
+
}, w = class {
|
|
1225
1366
|
backdrop = null;
|
|
1226
1367
|
modal = null;
|
|
1227
1368
|
input = null;
|
|
@@ -1346,7 +1487,7 @@ var x = class {
|
|
|
1346
1487
|
destroy() {
|
|
1347
1488
|
this.close();
|
|
1348
1489
|
}
|
|
1349
|
-
},
|
|
1490
|
+
}, T = class {
|
|
1350
1491
|
backdrop = null;
|
|
1351
1492
|
modal = null;
|
|
1352
1493
|
input = null;
|
|
@@ -1370,7 +1511,7 @@ var x = class {
|
|
|
1370
1511
|
let r = document.createElement("div");
|
|
1371
1512
|
r.className = "tcw-cmd-header";
|
|
1372
1513
|
let i = document.createElement("span");
|
|
1373
|
-
i.className = "tcw-cmd-icon", i.innerHTML =
|
|
1514
|
+
i.className = "tcw-cmd-icon", i.innerHTML = k(), r.appendChild(i), this.input = document.createElement("input"), this.input.className = "tcw-cmd-input", this.input.type = "text", this.input.placeholder = "Search symbol… (e.g. BTC, ETH, AAPL)", this.input.autocomplete = "off", this.input.spellcheck = !1, this.input.addEventListener("input", () => this.filter()), r.appendChild(this.input);
|
|
1374
1515
|
let a = document.createElement("span");
|
|
1375
1516
|
a.className = "tcw-cmd-hint", a.textContent = "ESC", r.appendChild(a), this.modal.appendChild(r), this.list = document.createElement("div"), this.list.className = "tcw-cmd-list", this.modal.appendChild(this.list);
|
|
1376
1517
|
let o = document.createElement("div");
|
|
@@ -1389,7 +1530,7 @@ var x = class {
|
|
|
1389
1530
|
let e = (this.input?.value ?? "").toUpperCase().trim();
|
|
1390
1531
|
e ? this.filtered = this.symbols.map((t) => ({
|
|
1391
1532
|
symbol: t,
|
|
1392
|
-
score:
|
|
1533
|
+
score: E(t.toUpperCase(), e)
|
|
1393
1534
|
})).filter((e) => e.score > 0).sort((e, t) => t.score - e.score) : this.filtered = this.symbols.map((e) => ({
|
|
1394
1535
|
symbol: e,
|
|
1395
1536
|
score: 0
|
|
@@ -1407,7 +1548,7 @@ var x = class {
|
|
|
1407
1548
|
let { symbol: n } = this.filtered[t], r = document.createElement("button");
|
|
1408
1549
|
r.className = "tcw-cmd-item", t === this.selectedIndex && r.classList.add("tcw-selected"), n === this.current && r.classList.add("tcw-active");
|
|
1409
1550
|
let i = document.createElement("span");
|
|
1410
|
-
if (i.className = "tcw-cmd-item-label", i.innerHTML =
|
|
1551
|
+
if (i.className = "tcw-cmd-item-label", i.innerHTML = D(n, e), r.appendChild(i), n === this.current) {
|
|
1411
1552
|
let e = document.createElement("span");
|
|
1412
1553
|
e.className = "tcw-cmd-check", e.textContent = "✓", r.appendChild(e);
|
|
1413
1554
|
}
|
|
@@ -1444,7 +1585,7 @@ var x = class {
|
|
|
1444
1585
|
}
|
|
1445
1586
|
}
|
|
1446
1587
|
};
|
|
1447
|
-
function
|
|
1588
|
+
function E(e, t) {
|
|
1448
1589
|
if (e === t) return 1e3;
|
|
1449
1590
|
if (e.startsWith(t)) return 500 + (50 - Math.min(50, e.length - t.length));
|
|
1450
1591
|
if (e.includes(t)) return 200 + (50 - Math.min(50, e.length - t.length));
|
|
@@ -1452,13 +1593,13 @@ function D(e, t) {
|
|
|
1452
1593
|
for (let a = 0; a < e.length && n < t.length; a++) e[a] === t[n] && (r >= 0 && (i += a - r - 1), r = a, n++);
|
|
1453
1594
|
return n < t.length ? 0 : 100 - Math.min(99, i);
|
|
1454
1595
|
}
|
|
1455
|
-
function
|
|
1456
|
-
if (!t) return
|
|
1596
|
+
function D(e, t) {
|
|
1597
|
+
if (!t) return O(e);
|
|
1457
1598
|
let n = e.toUpperCase(), r = "", i = 0;
|
|
1458
|
-
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">${
|
|
1599
|
+
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">${O(e[a])}</mark>`, i++) : r += O(e[a]);
|
|
1459
1600
|
return r;
|
|
1460
1601
|
}
|
|
1461
|
-
function
|
|
1602
|
+
function O(e) {
|
|
1462
1603
|
return e.replace(/[&<>"']/g, (e) => ({
|
|
1463
1604
|
"&": "&",
|
|
1464
1605
|
"<": "<",
|
|
@@ -1467,12 +1608,18 @@ function k(e) {
|
|
|
1467
1608
|
"'": "'"
|
|
1468
1609
|
})[e]);
|
|
1469
1610
|
}
|
|
1470
|
-
function
|
|
1611
|
+
function k() {
|
|
1471
1612
|
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>";
|
|
1472
1613
|
}
|
|
1473
1614
|
//#endregion
|
|
1474
1615
|
//#region src/widget/WidgetHotkeySheet.ts
|
|
1475
|
-
var
|
|
1616
|
+
var A = {
|
|
1617
|
+
"Search & navigation": "hotkeys.group.searchNavigation",
|
|
1618
|
+
"Chart manipulation": "hotkeys.group.chartManipulation",
|
|
1619
|
+
"Touch (mobile / tablet)": "hotkeys.group.touch",
|
|
1620
|
+
Keyboard: "hotkeys.group.keyboard",
|
|
1621
|
+
Drawing: "hotkeys.group.drawing"
|
|
1622
|
+
}, j = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent) ? "⌘" : "Ctrl", M = [
|
|
1476
1623
|
{
|
|
1477
1624
|
title: "Search & navigation",
|
|
1478
1625
|
entries: [
|
|
@@ -1590,9 +1737,10 @@ var j = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platfor
|
|
|
1590
1737
|
backdrop = null;
|
|
1591
1738
|
modal = null;
|
|
1592
1739
|
callbacks;
|
|
1740
|
+
t;
|
|
1593
1741
|
boundKeydown;
|
|
1594
|
-
constructor(e) {
|
|
1595
|
-
this.callbacks = e, this.boundKeydown = (e) => {
|
|
1742
|
+
constructor(e, t) {
|
|
1743
|
+
this.callbacks = e, this.t = t, this.boundKeydown = (e) => {
|
|
1596
1744
|
e.key === "Escape" && (e.preventDefault(), this.close());
|
|
1597
1745
|
};
|
|
1598
1746
|
}
|
|
@@ -1600,9 +1748,9 @@ var j = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platfor
|
|
|
1600
1748
|
if (this.backdrop) return;
|
|
1601
1749
|
this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.addEventListener("click", () => this.close()), this.modal = document.createElement("div"), this.modal.className = "tcw-modal tcw-hotkey-sheet", this.modal.style.width = "640px";
|
|
1602
1750
|
let e = document.createElement("div");
|
|
1603
|
-
e.className = "tcw-modal-header", e.innerHTML = "
|
|
1751
|
+
e.className = "tcw-modal-header", e.innerHTML = `<h3>${this.t("hotkeys.title")}</h3>`;
|
|
1604
1752
|
let t = document.createElement("button");
|
|
1605
|
-
t.className = "tcw-modal-close", t.setAttribute("aria-label", "
|
|
1753
|
+
t.className = "tcw-modal-close", t.setAttribute("aria-label", this.t("hotkeys.close")), t.innerHTML = "×", t.addEventListener("click", () => this.close()), e.appendChild(t), this.modal.appendChild(e);
|
|
1606
1754
|
let n = document.createElement("div");
|
|
1607
1755
|
n.className = "tcw-modal-body";
|
|
1608
1756
|
let r = document.createElement("div");
|
|
@@ -1611,7 +1759,9 @@ var j = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platfor
|
|
|
1611
1759
|
let t = document.createElement("section");
|
|
1612
1760
|
t.className = "tcw-hotkey-section";
|
|
1613
1761
|
let n = document.createElement("div");
|
|
1614
|
-
n.className = "tcw-settings-section-title"
|
|
1762
|
+
n.className = "tcw-settings-section-title";
|
|
1763
|
+
let i = A[e.title];
|
|
1764
|
+
n.textContent = i ? this.t(i) : e.title, t.appendChild(n);
|
|
1615
1765
|
for (let n of e.entries) {
|
|
1616
1766
|
let e = document.createElement("div");
|
|
1617
1767
|
e.className = "tcw-hotkey-row";
|
|
@@ -1635,7 +1785,7 @@ var j = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platfor
|
|
|
1635
1785
|
let i = document.createElement("div");
|
|
1636
1786
|
i.className = "tcw-modal-footer", i.innerHTML = "<span style=\"font-size:11px;color:var(--tcw-text-muted)\">Press ? anytime to show this sheet</span>";
|
|
1637
1787
|
let a = document.createElement("button");
|
|
1638
|
-
a.className = "tcw-done-btn", a.textContent = "
|
|
1788
|
+
a.className = "tcw-done-btn", a.textContent = this.t("hotkeys.gotIt"), a.addEventListener("click", () => this.close()), i.appendChild(a), this.modal.appendChild(i), document.body.appendChild(this.backdrop), document.body.appendChild(this.modal), document.addEventListener("keydown", this.boundKeydown);
|
|
1639
1789
|
}
|
|
1640
1790
|
close() {
|
|
1641
1791
|
document.removeEventListener("keydown", this.boundKeydown), this.backdrop?.remove(), this.modal?.remove(), this.backdrop = null, this.modal = null, this.callbacks.onClose();
|
|
@@ -1736,13 +1886,18 @@ var V = class {
|
|
|
1736
1886
|
entries = /* @__PURE__ */ new Map();
|
|
1737
1887
|
active = null;
|
|
1738
1888
|
callbacks;
|
|
1739
|
-
|
|
1889
|
+
locale;
|
|
1890
|
+
constructor(e, t, n, r = "Watchlist") {
|
|
1740
1891
|
this.callbacks = n, this.el = document.createElement("div"), this.el.className = "tcw-watchlist";
|
|
1741
|
-
let
|
|
1742
|
-
|
|
1892
|
+
let i = document.createElement("div");
|
|
1893
|
+
i.className = "tcw-watchlist-header", i.textContent = r, this.el.appendChild(i), this.listEl = document.createElement("div"), this.listEl.className = "tcw-watchlist-list", this.el.appendChild(this.listEl);
|
|
1743
1894
|
for (let e of t) this.entries.set(e, { symbol: e }), this.appendRow(e);
|
|
1744
1895
|
e.appendChild(this.el);
|
|
1745
1896
|
}
|
|
1897
|
+
setLocale(e) {
|
|
1898
|
+
this.locale = e;
|
|
1899
|
+
for (let e of this.entries.keys()) this.renderRow(e);
|
|
1900
|
+
}
|
|
1746
1901
|
setSymbols(e) {
|
|
1747
1902
|
let t = new Set(e);
|
|
1748
1903
|
for (let e of this.rowMap.keys()) t.has(e) || this.removeRow(e);
|
|
@@ -1792,9 +1947,12 @@ var V = class {
|
|
|
1792
1947
|
renderRow(e) {
|
|
1793
1948
|
let t = this.rowMap.get(e), n = this.entries.get(e);
|
|
1794
1949
|
if (!(!t || !n)) {
|
|
1795
|
-
if (n.lastPrice !== void 0 && (t.priceEl.textContent = U(n.lastPrice)), n.lastPrice !== void 0 && n.refPrice !== void 0 && n.refPrice !== 0) {
|
|
1796
|
-
let e = n.lastPrice - n.refPrice, r = e / n.refPrice * 100, i = e >= 0 ? "+" : ""
|
|
1797
|
-
|
|
1950
|
+
if (n.lastPrice !== void 0 && (t.priceEl.textContent = U(n.lastPrice, this.locale)), n.lastPrice !== void 0 && n.refPrice !== void 0 && n.refPrice !== 0) {
|
|
1951
|
+
let e = n.lastPrice - n.refPrice, r = e / n.refPrice * 100, i = e >= 0 ? "+" : "-", a = Math.abs(r).toLocaleString(this.locale, {
|
|
1952
|
+
minimumFractionDigits: 2,
|
|
1953
|
+
maximumFractionDigits: 2
|
|
1954
|
+
});
|
|
1955
|
+
t.changeEl.textContent = `${i}${a}%`, t.changeEl.className = `tcw-watchlist-change ${e >= 0 ? "tcw-up" : "tcw-down"}`;
|
|
1798
1956
|
} else t.changeEl.textContent = "";
|
|
1799
1957
|
n.sparkline && n.sparkline.length >= 2 && W(t.sparkCanvas, n.sparkline, n.refPrice ?? n.sparkline[0]);
|
|
1800
1958
|
}
|
|
@@ -1810,10 +1968,16 @@ function H(e) {
|
|
|
1810
1968
|
]) if (e.length > t.length && e.endsWith(t)) return e.slice(0, -t.length) + "/" + t;
|
|
1811
1969
|
return e;
|
|
1812
1970
|
}
|
|
1813
|
-
function U(e) {
|
|
1971
|
+
function U(e, t) {
|
|
1814
1972
|
if (e === 0) return "0";
|
|
1815
|
-
let
|
|
1816
|
-
return
|
|
1973
|
+
let n = Math.abs(e);
|
|
1974
|
+
return n >= 1e3 ? e.toLocaleString(t, {
|
|
1975
|
+
minimumFractionDigits: 2,
|
|
1976
|
+
maximumFractionDigits: 2
|
|
1977
|
+
}) : n >= 1 ? e.toLocaleString(t, {
|
|
1978
|
+
minimumFractionDigits: 4,
|
|
1979
|
+
maximumFractionDigits: 4
|
|
1980
|
+
}) : Number(e.toPrecision(4)).toLocaleString(t, { maximumFractionDigits: 10 });
|
|
1817
1981
|
}
|
|
1818
1982
|
function W(e, t, n) {
|
|
1819
1983
|
let r = e.getContext("2d");
|
|
@@ -1855,14 +2019,14 @@ var G = [
|
|
|
1855
2019
|
label: "Less than"
|
|
1856
2020
|
}
|
|
1857
2021
|
], K = new Map(G.map((e) => [e.value, e.label]));
|
|
1858
|
-
function
|
|
2022
|
+
function ce(e) {
|
|
1859
2023
|
return Math.round(e * 1e6) / 1e6;
|
|
1860
2024
|
}
|
|
1861
|
-
function
|
|
2025
|
+
function le(e) {
|
|
1862
2026
|
let t = Math.abs(e);
|
|
1863
2027
|
return t >= 1e3 || t >= 1 ? e.toFixed(2) : e.toPrecision(4);
|
|
1864
2028
|
}
|
|
1865
|
-
var
|
|
2029
|
+
var ue = class {
|
|
1866
2030
|
el;
|
|
1867
2031
|
listEl;
|
|
1868
2032
|
priceInput;
|
|
@@ -1923,7 +2087,7 @@ var ce = class {
|
|
|
1923
2087
|
}
|
|
1924
2088
|
prefillPrice() {
|
|
1925
2089
|
let e = this.callbacks.getChannelValue(this.sourceSelect.value || "price");
|
|
1926
|
-
this.priceInput.value = e === null ? "" : String(
|
|
2090
|
+
this.priceInput.value = e === null ? "" : String(ce(e));
|
|
1927
2091
|
}
|
|
1928
2092
|
close() {
|
|
1929
2093
|
this.open = !1, this.el.hidden = !0;
|
|
@@ -1952,7 +2116,7 @@ var ce = class {
|
|
|
1952
2116
|
n.className = "tcw-alerts-info";
|
|
1953
2117
|
let r = document.createElement("div");
|
|
1954
2118
|
r.className = "tcw-alerts-row-main";
|
|
1955
|
-
let i = K.get(e.condition) ?? e.condition, a = e.channel && e.channel !== "price", o = a ?
|
|
2119
|
+
let i = K.get(e.condition) ?? e.condition, a = e.channel && e.channel !== "price", o = a ? le(e.price) : this.callbacks.formatPrice(e.price);
|
|
1956
2120
|
if (r.textContent = `${a && e.label ? `${e.label} ` : ""}${i} ${o}`, n.appendChild(r), e.message) {
|
|
1957
2121
|
let t = document.createElement("div");
|
|
1958
2122
|
t.className = "tcw-alerts-row-note", t.textContent = e.message, n.appendChild(t);
|
|
@@ -1965,7 +2129,7 @@ var ce = class {
|
|
|
1965
2129
|
s.type = "button", s.className = "tcw-alerts-del", s.setAttribute("aria-label", "Delete alert"), s.innerHTML = y("trash", 14), s.addEventListener("click", () => this.callbacks.onRemove(e.id)), t.appendChild(n), t.appendChild(s), this.listEl.appendChild(t);
|
|
1966
2130
|
}
|
|
1967
2131
|
}
|
|
1968
|
-
},
|
|
2132
|
+
}, de = class {
|
|
1969
2133
|
el;
|
|
1970
2134
|
indicatorsEl;
|
|
1971
2135
|
drawingsEl;
|
|
@@ -2062,11 +2226,26 @@ var ce = class {
|
|
|
2062
2226
|
let i = document.createElement("button");
|
|
2063
2227
|
return i.type = "button", i.className = `tcw-tree-btn ${n}`.trim(), i.setAttribute("aria-label", t), i.title = t, i.innerHTML = y(e, 14), i.addEventListener("click", r), i;
|
|
2064
2228
|
}
|
|
2065
|
-
},
|
|
2229
|
+
}, fe = {
|
|
2066
2230
|
trendLine: "Trend Line",
|
|
2067
2231
|
ray: "Ray",
|
|
2068
2232
|
extendedLine: "Extended Line",
|
|
2069
2233
|
horizontalLine: "Horizontal Line",
|
|
2234
|
+
horizontalRay: "Horizontal Ray",
|
|
2235
|
+
crossLine: "Cross Line",
|
|
2236
|
+
infoLine: "Info Line",
|
|
2237
|
+
trendAngle: "Trend Angle",
|
|
2238
|
+
circle: "Circle",
|
|
2239
|
+
fibChannel: "Fib Channel",
|
|
2240
|
+
fibSpeedResistanceFan: "Fib Speed Resistance Fan",
|
|
2241
|
+
schiffPitchfork: "Schiff Pitchfork",
|
|
2242
|
+
modifiedSchiffPitchfork: "Modified Schiff Pitchfork",
|
|
2243
|
+
xabcdPattern: "XABCD Pattern",
|
|
2244
|
+
abcdPattern: "ABCD Pattern",
|
|
2245
|
+
headAndShoulders: "Head and Shoulders",
|
|
2246
|
+
dateAndPriceRange: "Date and Price Range",
|
|
2247
|
+
cyclicLines: "Cyclic Lines",
|
|
2248
|
+
priceLabel: "Price Label",
|
|
2070
2249
|
verticalLine: "Vertical Line",
|
|
2071
2250
|
rectangle: "Rectangle",
|
|
2072
2251
|
ellipse: "Ellipse",
|
|
@@ -2084,20 +2263,22 @@ var ce = class {
|
|
|
2084
2263
|
priceRange: "Price Range",
|
|
2085
2264
|
dateRange: "Date Range",
|
|
2086
2265
|
measure: "Measure",
|
|
2266
|
+
text: "Text",
|
|
2087
2267
|
textAnnotation: "Text",
|
|
2088
2268
|
anchoredVWAP: "Anchored VWAP",
|
|
2089
|
-
volumeProfileRange: "Volume Profile"
|
|
2269
|
+
volumeProfileRange: "Volume Profile",
|
|
2270
|
+
riskReward: "Long/Short Position"
|
|
2090
2271
|
};
|
|
2091
|
-
function
|
|
2092
|
-
return
|
|
2272
|
+
function pe(e) {
|
|
2273
|
+
return fe[e] ?? e;
|
|
2093
2274
|
}
|
|
2094
2275
|
//#endregion
|
|
2095
2276
|
//#region src/widget/WidgetIndicatorSettings.ts
|
|
2096
|
-
var
|
|
2097
|
-
function
|
|
2277
|
+
var me = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
2278
|
+
function he(e) {
|
|
2098
2279
|
return e.replace(/_/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (e) => e.toUpperCase());
|
|
2099
2280
|
}
|
|
2100
|
-
var
|
|
2281
|
+
var ge = class {
|
|
2101
2282
|
backdrop;
|
|
2102
2283
|
modal;
|
|
2103
2284
|
bodyEl;
|
|
@@ -2162,9 +2343,9 @@ var me = class {
|
|
|
2162
2343
|
let t = document.createElement("div");
|
|
2163
2344
|
t.className = "tcw-settings-row";
|
|
2164
2345
|
let n = document.createElement("span");
|
|
2165
|
-
n.className = "tcw-settings-label", n.textContent =
|
|
2346
|
+
n.className = "tcw-settings-label", n.textContent = he(e), t.appendChild(n);
|
|
2166
2347
|
let r = this.currentValue(e), i = typeof (this.target?.defaults[e] ?? r);
|
|
2167
|
-
return i === "boolean" ? t.appendChild(this.toggleControl(e, !!r)) : i === "number" ? t.appendChild(this.numberControl(e, Number(r))) : typeof r == "string" &&
|
|
2348
|
+
return i === "boolean" ? t.appendChild(this.toggleControl(e, !!r)) : i === "number" ? t.appendChild(this.numberControl(e, Number(r))) : typeof r == "string" && me.test(r) ? t.appendChild(this.colorControl(e, r)) : t.appendChild(this.textControl(e, String(r ?? ""))), t;
|
|
2168
2349
|
}
|
|
2169
2350
|
toggleControl(e, t) {
|
|
2170
2351
|
let n = document.createElement("button");
|
|
@@ -2182,27 +2363,27 @@ var me = class {
|
|
|
2182
2363
|
}
|
|
2183
2364
|
colorControl(e, t) {
|
|
2184
2365
|
let n = document.createElement("input");
|
|
2185
|
-
return n.type = "color", n.className = "tcw-indi-color", n.value = t.length === 4 ?
|
|
2366
|
+
return n.type = "color", n.className = "tcw-indi-color", n.value = t.length === 4 ? _e(t) : t, n.addEventListener("input", () => this.setValue(e, n.value)), n;
|
|
2186
2367
|
}
|
|
2187
2368
|
textControl(e, t) {
|
|
2188
2369
|
let n = document.createElement("input");
|
|
2189
2370
|
return n.type = "text", n.className = "tcw-indi-input", n.value = t, n.addEventListener("change", () => this.setValue(e, n.value)), n;
|
|
2190
2371
|
}
|
|
2191
2372
|
};
|
|
2192
|
-
function
|
|
2373
|
+
function _e(e) {
|
|
2193
2374
|
let t = e[1], n = e[2], r = e[3];
|
|
2194
2375
|
return `#${t}${t}${n}${n}${r}${r}`;
|
|
2195
2376
|
}
|
|
2196
2377
|
//#endregion
|
|
2197
2378
|
//#region src/widget/DrawingTemplateStore.ts
|
|
2198
|
-
function
|
|
2379
|
+
function ve() {
|
|
2199
2380
|
try {
|
|
2200
2381
|
return typeof localStorage < "u" ? localStorage : null;
|
|
2201
2382
|
} catch {
|
|
2202
2383
|
return null;
|
|
2203
2384
|
}
|
|
2204
2385
|
}
|
|
2205
|
-
var
|
|
2386
|
+
var ye = [
|
|
2206
2387
|
"color",
|
|
2207
2388
|
"lineWidth",
|
|
2208
2389
|
"lineStyle",
|
|
@@ -2210,15 +2391,15 @@ var _e = [
|
|
|
2210
2391
|
"fillOpacity",
|
|
2211
2392
|
"fontSize"
|
|
2212
2393
|
];
|
|
2213
|
-
function
|
|
2394
|
+
function q(e) {
|
|
2214
2395
|
if (!e || typeof e != "object") return {};
|
|
2215
2396
|
let t = {}, n = e;
|
|
2216
|
-
for (let e of
|
|
2397
|
+
for (let e of ye) n[e] !== void 0 && (t[e] = n[e]);
|
|
2217
2398
|
return t;
|
|
2218
2399
|
}
|
|
2219
|
-
var
|
|
2400
|
+
var be = class {
|
|
2220
2401
|
templates = [];
|
|
2221
|
-
constructor(e = "tcw:draw-templates", t =
|
|
2402
|
+
constructor(e = "tcw:draw-templates", t = ve()) {
|
|
2222
2403
|
this.storageKey = e, this.storage = t, this.load();
|
|
2223
2404
|
}
|
|
2224
2405
|
list() {
|
|
@@ -2237,7 +2418,7 @@ var ve = class {
|
|
|
2237
2418
|
save(e, t) {
|
|
2238
2419
|
let n = e.trim();
|
|
2239
2420
|
if (!n) return;
|
|
2240
|
-
let r =
|
|
2421
|
+
let r = q(t);
|
|
2241
2422
|
this.templates = this.templates.filter((e) => e.name !== n), this.templates.push({
|
|
2242
2423
|
name: n,
|
|
2243
2424
|
style: r
|
|
@@ -2258,7 +2439,7 @@ var ve = class {
|
|
|
2258
2439
|
if (!Array.isArray(t)) return;
|
|
2259
2440
|
this.templates = t.filter((e) => e && typeof e.name == "string").map((e) => ({
|
|
2260
2441
|
name: e.name,
|
|
2261
|
-
style:
|
|
2442
|
+
style: q(e.style)
|
|
2262
2443
|
}));
|
|
2263
2444
|
} catch {}
|
|
2264
2445
|
}
|
|
@@ -2267,7 +2448,7 @@ var ve = class {
|
|
|
2267
2448
|
this.storage.setItem(this.storageKey, JSON.stringify(this.templates));
|
|
2268
2449
|
} catch {}
|
|
2269
2450
|
}
|
|
2270
|
-
},
|
|
2451
|
+
}, xe = [
|
|
2271
2452
|
"#2962ff",
|
|
2272
2453
|
"#089981",
|
|
2273
2454
|
"#f23645",
|
|
@@ -2276,16 +2457,16 @@ var ve = class {
|
|
|
2276
2457
|
"#26c6da",
|
|
2277
2458
|
"#ffffff",
|
|
2278
2459
|
"#787b86"
|
|
2279
|
-
],
|
|
2460
|
+
], Se = [
|
|
2280
2461
|
1,
|
|
2281
2462
|
2,
|
|
2282
2463
|
3,
|
|
2283
2464
|
4
|
|
2284
|
-
],
|
|
2465
|
+
], Ce = [
|
|
2285
2466
|
"solid",
|
|
2286
2467
|
"dashed",
|
|
2287
2468
|
"dotted"
|
|
2288
|
-
],
|
|
2469
|
+
], we = class {
|
|
2289
2470
|
el;
|
|
2290
2471
|
templatesEl;
|
|
2291
2472
|
nameInput;
|
|
@@ -2325,7 +2506,7 @@ var ve = class {
|
|
|
2325
2506
|
colorRow() {
|
|
2326
2507
|
let e = document.createElement("div");
|
|
2327
2508
|
e.className = "tcw-style-row tcw-style-colors";
|
|
2328
|
-
for (let t of
|
|
2509
|
+
for (let t of xe) {
|
|
2329
2510
|
let n = document.createElement("button");
|
|
2330
2511
|
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);
|
|
2331
2512
|
}
|
|
@@ -2335,7 +2516,7 @@ var ve = class {
|
|
|
2335
2516
|
widthRow() {
|
|
2336
2517
|
let e = document.createElement("div");
|
|
2337
2518
|
e.className = "tcw-style-row tcw-style-widths";
|
|
2338
|
-
for (let t of
|
|
2519
|
+
for (let t of Se) {
|
|
2339
2520
|
let n = document.createElement("button");
|
|
2340
2521
|
n.type = "button", n.className = "tcw-style-width", n.dataset.width = String(t);
|
|
2341
2522
|
let r = document.createElement("span");
|
|
@@ -2346,7 +2527,7 @@ var ve = class {
|
|
|
2346
2527
|
lineStyleRow() {
|
|
2347
2528
|
let e = document.createElement("div");
|
|
2348
2529
|
e.className = "tcw-style-row tcw-style-dashes";
|
|
2349
|
-
for (let t of
|
|
2530
|
+
for (let t of Ce) {
|
|
2350
2531
|
let n = document.createElement("button");
|
|
2351
2532
|
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);
|
|
2352
2533
|
}
|
|
@@ -2397,16 +2578,16 @@ var ve = class {
|
|
|
2397
2578
|
};
|
|
2398
2579
|
//#endregion
|
|
2399
2580
|
//#region src/widget/DrawingFavoritesStore.ts
|
|
2400
|
-
function
|
|
2581
|
+
function Te() {
|
|
2401
2582
|
try {
|
|
2402
2583
|
return typeof localStorage < "u" ? localStorage : null;
|
|
2403
2584
|
} catch {
|
|
2404
2585
|
return null;
|
|
2405
2586
|
}
|
|
2406
2587
|
}
|
|
2407
|
-
var
|
|
2588
|
+
var Ee = class {
|
|
2408
2589
|
favorites = [];
|
|
2409
|
-
constructor(e = "tcw:draw-favorites", t =
|
|
2590
|
+
constructor(e = "tcw:draw-favorites", t = Te()) {
|
|
2410
2591
|
this.storageKey = e, this.storage = t, this.load();
|
|
2411
2592
|
}
|
|
2412
2593
|
list() {
|
|
@@ -2440,7 +2621,7 @@ var we = class {
|
|
|
2440
2621
|
this.storage.setItem(this.storageKey, JSON.stringify(this.favorites));
|
|
2441
2622
|
} catch {}
|
|
2442
2623
|
}
|
|
2443
|
-
},
|
|
2624
|
+
}, De = class {
|
|
2444
2625
|
el;
|
|
2445
2626
|
labelEl;
|
|
2446
2627
|
callbacks;
|
|
@@ -2466,7 +2647,7 @@ var we = class {
|
|
|
2466
2647
|
destroy() {
|
|
2467
2648
|
this.el.remove();
|
|
2468
2649
|
}
|
|
2469
|
-
},
|
|
2650
|
+
}, Oe = class {
|
|
2470
2651
|
options;
|
|
2471
2652
|
audioCtx = null;
|
|
2472
2653
|
audioEl = null;
|
|
@@ -2529,7 +2710,7 @@ var we = class {
|
|
|
2529
2710
|
};
|
|
2530
2711
|
//#endregion
|
|
2531
2712
|
//#region src/widget/ladderRows.ts
|
|
2532
|
-
function
|
|
2713
|
+
function ke(e, t = 12) {
|
|
2533
2714
|
let n = [...e.asks].sort((e, t) => e.price - t.price).slice(0, t), r = [...e.bids].sort((e, t) => t.price - e.price).slice(0, t), i = n.length > 0 ? n[0].price : null, a = r.length > 0 ? r[0].price : null, o = i !== null && a !== null ? (i + a) / 2 : null, s = /* @__PURE__ */ new Map(), c = (e) => {
|
|
2534
2715
|
let t = s.get(e);
|
|
2535
2716
|
return t || (t = {
|
|
@@ -2550,7 +2731,7 @@ function De(e, t = 12) {
|
|
|
2550
2731
|
}
|
|
2551
2732
|
//#endregion
|
|
2552
2733
|
//#region src/widget/WidgetDepthLadder.ts
|
|
2553
|
-
var
|
|
2734
|
+
var Ae = class {
|
|
2554
2735
|
el;
|
|
2555
2736
|
bodyEl;
|
|
2556
2737
|
callbacks;
|
|
@@ -2584,7 +2765,7 @@ var Oe = class {
|
|
|
2584
2765
|
this.renderEmpty();
|
|
2585
2766
|
return;
|
|
2586
2767
|
}
|
|
2587
|
-
this.render(
|
|
2768
|
+
this.render(ke(e, this.levels));
|
|
2588
2769
|
}
|
|
2589
2770
|
destroy() {
|
|
2590
2771
|
this.el.remove();
|
|
@@ -2604,20 +2785,20 @@ var Oe = class {
|
|
|
2604
2785
|
let e = n.askVolume > 0, r = document.createElement("div");
|
|
2605
2786
|
r.className = "tcw-ladder-row";
|
|
2606
2787
|
let i = document.createElement("button");
|
|
2607
|
-
i.type = "button", i.className = "tcw-ladder-cell tcw-ladder-bid", n.bidVolume > 0 ? (i.textContent =
|
|
2788
|
+
i.type = "button", i.className = "tcw-ladder-cell tcw-ladder-bid", n.bidVolume > 0 ? (i.textContent = J(n.bidVolume), i.style.setProperty("--w", `${(n.bidVolume * t * 100).toFixed(1)}%`), i.title = `Sell @ ${this.callbacks.formatPrice(n.price)}`, i.addEventListener("click", () => this.callbacks.onTrade("sell", n.price))) : i.disabled = !0;
|
|
2608
2789
|
let a = document.createElement("div");
|
|
2609
2790
|
a.className = `tcw-ladder-price ${e ? "tcw-ask" : "tcw-bid"}`, a.textContent = this.callbacks.formatPrice(n.price);
|
|
2610
2791
|
let o = document.createElement("button");
|
|
2611
|
-
o.type = "button", o.className = "tcw-ladder-cell tcw-ladder-ask", n.askVolume > 0 ? (o.textContent =
|
|
2792
|
+
o.type = "button", o.className = "tcw-ladder-cell tcw-ladder-ask", n.askVolume > 0 ? (o.textContent = J(n.askVolume), o.style.setProperty("--w", `${(n.askVolume * t * 100).toFixed(1)}%`), o.title = `Buy @ ${this.callbacks.formatPrice(n.price)}`, o.addEventListener("click", () => this.callbacks.onTrade("buy", n.price))) : o.disabled = !0, r.appendChild(i), r.appendChild(a), r.appendChild(o), this.bodyEl.appendChild(r);
|
|
2612
2793
|
}
|
|
2613
2794
|
}
|
|
2614
2795
|
};
|
|
2615
|
-
function
|
|
2796
|
+
function J(e) {
|
|
2616
2797
|
return e >= 1e3 ? (e / 1e3).toFixed(1) + "k" : e >= 1 ? e.toFixed(2).replace(/\.00$/, "") : e.toPrecision(2);
|
|
2617
2798
|
}
|
|
2618
2799
|
//#endregion
|
|
2619
2800
|
//#region src/widget/WidgetDataWindow.ts
|
|
2620
|
-
var
|
|
2801
|
+
var je = class {
|
|
2621
2802
|
el;
|
|
2622
2803
|
bodyEl;
|
|
2623
2804
|
callbacks;
|
|
@@ -2656,11 +2837,11 @@ var ke = class {
|
|
|
2656
2837
|
let t = this.callbacks.formatPrice, n = e.ohlc;
|
|
2657
2838
|
this.bodyEl.appendChild(this.row("Open", t(n.open))), this.bodyEl.appendChild(this.row("High", t(n.high))), this.bodyEl.appendChild(this.row("Low", t(n.low))), this.bodyEl.appendChild(this.row("Close", t(n.close)));
|
|
2658
2839
|
let r = e.change > 0 ? "up" : e.change < 0 ? "down" : "", i = e.change > 0 ? "+" : "";
|
|
2659
|
-
this.bodyEl.appendChild(this.row("Change", `${i}${t(e.change)} (${i}${e.changePct.toFixed(2)}%)`, r)), this.bodyEl.appendChild(this.row("Volume",
|
|
2840
|
+
this.bodyEl.appendChild(this.row("Change", `${i}${t(e.change)} (${i}${e.changePct.toFixed(2)}%)`, r)), this.bodyEl.appendChild(this.row("Volume", Ne(n.volume)));
|
|
2660
2841
|
for (let t of e.indicators) {
|
|
2661
2842
|
let e = document.createElement("div");
|
|
2662
2843
|
e.className = "tcw-datawin-sub", e.textContent = t.name, this.bodyEl.appendChild(e);
|
|
2663
|
-
for (let e of t.values) this.bodyEl.appendChild(this.row(e.key,
|
|
2844
|
+
for (let e of t.values) this.bodyEl.appendChild(this.row(e.key, Me(e.value)));
|
|
2664
2845
|
}
|
|
2665
2846
|
}
|
|
2666
2847
|
row(e, t, n = "") {
|
|
@@ -2672,43 +2853,43 @@ var ke = class {
|
|
|
2672
2853
|
return a.className = `tcw-datawin-value${n ? ` tcw-${n}` : ""}`, a.textContent = t, r.appendChild(i), r.appendChild(a), r;
|
|
2673
2854
|
}
|
|
2674
2855
|
};
|
|
2675
|
-
function
|
|
2856
|
+
function Me(e) {
|
|
2676
2857
|
if (!Number.isFinite(e)) return "—";
|
|
2677
2858
|
let t = Math.abs(e);
|
|
2678
2859
|
return t >= 1e3 ? e.toFixed(2) : t >= 1 ? e.toFixed(4) : e.toPrecision(4);
|
|
2679
2860
|
}
|
|
2680
|
-
function
|
|
2861
|
+
function Ne(e) {
|
|
2681
2862
|
return e >= 1e9 ? (e / 1e9).toFixed(2) + "B" : e >= 1e6 ? (e / 1e6).toFixed(2) + "M" : e >= 1e3 ? (e / 1e3).toFixed(2) + "K" : e.toFixed(0);
|
|
2682
2863
|
}
|
|
2683
2864
|
//#endregion
|
|
2684
2865
|
//#region src/widget/widgetShareState.ts
|
|
2685
|
-
var
|
|
2686
|
-
function
|
|
2687
|
-
if (
|
|
2866
|
+
var Y = globalThis.Buffer;
|
|
2867
|
+
function Pe(e) {
|
|
2868
|
+
if (Y) return Y.from(e, "utf8").toString("base64");
|
|
2688
2869
|
let t = new TextEncoder().encode(e), n = "";
|
|
2689
2870
|
for (let e of t) n += String.fromCharCode(e);
|
|
2690
2871
|
return btoa(n);
|
|
2691
2872
|
}
|
|
2692
|
-
function
|
|
2693
|
-
if (
|
|
2873
|
+
function Fe(e) {
|
|
2874
|
+
if (Y) return Y.from(e, "base64").toString("utf8");
|
|
2694
2875
|
let t = atob(e), n = new Uint8Array(t.length);
|
|
2695
2876
|
for (let e = 0; e < t.length; e++) n[e] = t.charCodeAt(e);
|
|
2696
2877
|
return new TextDecoder().decode(n);
|
|
2697
2878
|
}
|
|
2698
|
-
function
|
|
2879
|
+
function Ie(e) {
|
|
2699
2880
|
return e.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
2700
2881
|
}
|
|
2701
|
-
function
|
|
2882
|
+
function Le(e) {
|
|
2702
2883
|
let t = e.replace(/-/g, "+").replace(/_/g, "/");
|
|
2703
2884
|
return t + (t.length % 4 == 0 ? "" : "=".repeat(4 - t.length % 4));
|
|
2704
2885
|
}
|
|
2705
|
-
function
|
|
2706
|
-
return
|
|
2886
|
+
function Re(e) {
|
|
2887
|
+
return Ie(Pe(JSON.stringify(e)));
|
|
2707
2888
|
}
|
|
2708
|
-
function
|
|
2889
|
+
function ze(e) {
|
|
2709
2890
|
if (!e) return null;
|
|
2710
2891
|
try {
|
|
2711
|
-
let t =
|
|
2892
|
+
let t = Fe(Le(e)), n = JSON.parse(t);
|
|
2712
2893
|
return !n || n.v !== 1 || typeof n.symbol != "string" ? null : {
|
|
2713
2894
|
v: 1,
|
|
2714
2895
|
symbol: n.symbol,
|
|
@@ -2722,21 +2903,188 @@ function Ie(e) {
|
|
|
2722
2903
|
return null;
|
|
2723
2904
|
}
|
|
2724
2905
|
}
|
|
2725
|
-
var
|
|
2726
|
-
function
|
|
2906
|
+
var X = "tcw";
|
|
2907
|
+
function Be(e) {
|
|
2727
2908
|
let t = e.startsWith("#") ? e.slice(1) : e;
|
|
2728
2909
|
for (let e of t.split("&")) {
|
|
2729
2910
|
let t = e.indexOf("=");
|
|
2730
|
-
if (t > 0 && e.slice(0, t) ===
|
|
2911
|
+
if (t > 0 && e.slice(0, t) === X) return decodeURIComponent(e.slice(t + 1));
|
|
2731
2912
|
}
|
|
2732
2913
|
return null;
|
|
2733
2914
|
}
|
|
2734
|
-
function
|
|
2915
|
+
function Ve(e, t) {
|
|
2735
2916
|
let [n] = e.split("#");
|
|
2736
|
-
return `${n}#${
|
|
2917
|
+
return `${n}#${X}=${t}`;
|
|
2737
2918
|
}
|
|
2738
2919
|
//#endregion
|
|
2739
|
-
//#region src/widget/
|
|
2920
|
+
//#region src/widget/i18n.ts
|
|
2921
|
+
var Z = {
|
|
2922
|
+
"toolbar.indicators": "Indicators",
|
|
2923
|
+
"toolbar.indicators.popular": "Popular",
|
|
2924
|
+
"toolbar.indicators.all": "All",
|
|
2925
|
+
"indicatorType.overlay": "overlay",
|
|
2926
|
+
"indicatorType.panel": "panel",
|
|
2927
|
+
"toolbar.replay": "Bar replay",
|
|
2928
|
+
"toolbar.longBracket": "Long bracket",
|
|
2929
|
+
"toolbar.shortBracket": "Short bracket",
|
|
2930
|
+
"toolbar.depthLadder": "Depth ladder",
|
|
2931
|
+
"toolbar.objects": "Objects",
|
|
2932
|
+
"toolbar.priceAlerts": "Price alerts",
|
|
2933
|
+
"toolbar.screenshot": "Screenshot",
|
|
2934
|
+
"toolbar.settings": "Chart Settings",
|
|
2935
|
+
"toolbar.toggleTheme": "Toggle theme",
|
|
2936
|
+
"chartType.candlestick": "Candlestick",
|
|
2937
|
+
"chartType.line": "Line",
|
|
2938
|
+
"chartType.area": "Area",
|
|
2939
|
+
"chartType.bar": "Bar",
|
|
2940
|
+
"chartType.heikinAshi": "Heikin-Ashi",
|
|
2941
|
+
"chartType.hollowCandle": "Hollow Candle",
|
|
2942
|
+
"chartType.baseline": "Baseline",
|
|
2943
|
+
"chartType.volumeCandles": "Volume Candles",
|
|
2944
|
+
"chartType.equivolume": "Equivolume",
|
|
2945
|
+
"chartType.hlcArea": "HLC Area",
|
|
2946
|
+
"chartType.stepLine": "Step Line",
|
|
2947
|
+
"chartType.lineWithMarkers": "Line + Markers",
|
|
2948
|
+
"watchlist.title": "Watchlist",
|
|
2949
|
+
"status.connecting": "Connecting...",
|
|
2950
|
+
"status.live": "Live",
|
|
2951
|
+
"status.connectionFailed": "Connection failed",
|
|
2952
|
+
"status.loading": "Loading chart...",
|
|
2953
|
+
"settings.title": "Chart Settings",
|
|
2954
|
+
"settings.tab.style": "style",
|
|
2955
|
+
"settings.tab.display": "display",
|
|
2956
|
+
"settings.tab.scale": "scale",
|
|
2957
|
+
"settings.resetToDefaults": "Reset to defaults",
|
|
2958
|
+
"settings.done": "Done",
|
|
2959
|
+
"settings.section.candleColors": "Candle Colors",
|
|
2960
|
+
"settings.section.background": "Background",
|
|
2961
|
+
"hotkeys.title": "Keyboard shortcuts",
|
|
2962
|
+
"hotkeys.close": "Close",
|
|
2963
|
+
"hotkeys.gotIt": "Got it",
|
|
2964
|
+
"hotkeys.group.searchNavigation": "Search & navigation",
|
|
2965
|
+
"hotkeys.group.chartManipulation": "Chart manipulation",
|
|
2966
|
+
"hotkeys.group.touch": "Touch (mobile / tablet)",
|
|
2967
|
+
"hotkeys.group.keyboard": "Keyboard",
|
|
2968
|
+
"hotkeys.group.drawing": "Drawing"
|
|
2969
|
+
}, He = {
|
|
2970
|
+
en: Z,
|
|
2971
|
+
vi: {
|
|
2972
|
+
"toolbar.indicators": "Chỉ báo",
|
|
2973
|
+
"toolbar.indicators.popular": "Phổ biến",
|
|
2974
|
+
"toolbar.indicators.all": "Tất cả",
|
|
2975
|
+
"indicatorType.overlay": "phủ lên",
|
|
2976
|
+
"indicatorType.panel": "bảng riêng",
|
|
2977
|
+
"toolbar.replay": "Phát lại",
|
|
2978
|
+
"toolbar.longBracket": "Lệnh Long",
|
|
2979
|
+
"toolbar.shortBracket": "Lệnh Short",
|
|
2980
|
+
"toolbar.depthLadder": "Sổ lệnh",
|
|
2981
|
+
"toolbar.objects": "Đối tượng",
|
|
2982
|
+
"toolbar.priceAlerts": "Cảnh báo giá",
|
|
2983
|
+
"toolbar.screenshot": "Chụp màn hình",
|
|
2984
|
+
"toolbar.settings": "Cài đặt biểu đồ",
|
|
2985
|
+
"toolbar.toggleTheme": "Đổi giao diện",
|
|
2986
|
+
"chartType.candlestick": "Nến",
|
|
2987
|
+
"chartType.line": "Đường",
|
|
2988
|
+
"chartType.area": "Vùng",
|
|
2989
|
+
"chartType.bar": "Thanh",
|
|
2990
|
+
"chartType.heikinAshi": "Heikin-Ashi",
|
|
2991
|
+
"chartType.hollowCandle": "Nến rỗng",
|
|
2992
|
+
"chartType.baseline": "Đường cơ sở",
|
|
2993
|
+
"chartType.volumeCandles": "Nến khối lượng",
|
|
2994
|
+
"chartType.equivolume": "Equivolume",
|
|
2995
|
+
"chartType.hlcArea": "Vùng HLC",
|
|
2996
|
+
"chartType.stepLine": "Đường bậc thang",
|
|
2997
|
+
"chartType.lineWithMarkers": "Đường + điểm đánh dấu",
|
|
2998
|
+
"watchlist.title": "Danh mục theo dõi",
|
|
2999
|
+
"status.connecting": "Đang kết nối...",
|
|
3000
|
+
"status.live": "Trực tiếp",
|
|
3001
|
+
"status.connectionFailed": "Kết nối thất bại",
|
|
3002
|
+
"status.loading": "Đang tải biểu đồ...",
|
|
3003
|
+
"settings.title": "Cài đặt biểu đồ",
|
|
3004
|
+
"settings.tab.style": "Giao diện",
|
|
3005
|
+
"settings.tab.display": "Hiển thị",
|
|
3006
|
+
"settings.tab.scale": "Thang giá",
|
|
3007
|
+
"settings.resetToDefaults": "Khôi phục mặc định",
|
|
3008
|
+
"settings.done": "Xong",
|
|
3009
|
+
"settings.section.candleColors": "Màu nến",
|
|
3010
|
+
"settings.section.background": "Nền",
|
|
3011
|
+
"hotkeys.title": "Phím tắt",
|
|
3012
|
+
"hotkeys.close": "Đóng",
|
|
3013
|
+
"hotkeys.gotIt": "Đã hiểu",
|
|
3014
|
+
"hotkeys.group.searchNavigation": "Tìm kiếm & điều hướng",
|
|
3015
|
+
"hotkeys.group.chartManipulation": "Thao tác biểu đồ",
|
|
3016
|
+
"hotkeys.group.touch": "Cảm ứng (di động / máy tính bảng)",
|
|
3017
|
+
"hotkeys.group.keyboard": "Bàn phím",
|
|
3018
|
+
"hotkeys.group.drawing": "Vẽ"
|
|
3019
|
+
}
|
|
3020
|
+
};
|
|
3021
|
+
function Q(e, t) {
|
|
3022
|
+
let n = { ...Z }, r = e ? He[e] : void 0;
|
|
3023
|
+
return r && Object.assign(n, r), t && Object.assign(n, t), n;
|
|
3024
|
+
}
|
|
3025
|
+
function Ue(e) {
|
|
3026
|
+
return (t) => e[t] ?? Z[t] ?? t;
|
|
3027
|
+
}
|
|
3028
|
+
var We = 20, Ge = class {
|
|
3029
|
+
el;
|
|
3030
|
+
label;
|
|
3031
|
+
showTimer = null;
|
|
3032
|
+
phase = "loading";
|
|
3033
|
+
constructor(e, t) {
|
|
3034
|
+
this.loadingText = t, this.el = document.createElement("div"), this.el.className = "tcw-loading-overlay", this.el.setAttribute("role", "status"), this.el.setAttribute("aria-live", "polite");
|
|
3035
|
+
let n = document.createElement("div");
|
|
3036
|
+
n.className = "tcw-loading-card";
|
|
3037
|
+
let r = document.createElement("div");
|
|
3038
|
+
r.className = "tcw-loading-bars";
|
|
3039
|
+
for (let e = 0; e < We; e++) {
|
|
3040
|
+
let t = document.createElement("span");
|
|
3041
|
+
t.className = "tcw-loading-bar", t.style.height = `${20 + Math.round(Math.sin(e * .9) * 18 + 18)}px`, t.style.animationDelay = `${e * 45}ms`, r.appendChild(t);
|
|
3042
|
+
}
|
|
3043
|
+
n.appendChild(r), this.label = document.createElement("div"), this.label.className = "tcw-loading-label", this.label.textContent = t, n.appendChild(this.label), this.el.appendChild(n), e.appendChild(this.el);
|
|
3044
|
+
}
|
|
3045
|
+
begin(e, t = !1) {
|
|
3046
|
+
if (this.phase = "loading", this.clearTimer(), this.label.textContent = this.loadingText, this.el.classList.remove("tcw-loading-overlay--error"), this.el.classList.toggle("tcw-loading-overlay--veil", e), !e || t || this.isShown()) {
|
|
3047
|
+
this.el.classList.remove("tcw-loading-overlay--hidden");
|
|
3048
|
+
return;
|
|
3049
|
+
}
|
|
3050
|
+
this.showTimer = setTimeout(() => {
|
|
3051
|
+
this.showTimer = null, this.el.classList.remove("tcw-loading-overlay--hidden");
|
|
3052
|
+
}, 200);
|
|
3053
|
+
}
|
|
3054
|
+
end() {
|
|
3055
|
+
this.phase = "idle", this.clearTimer(), this.el.classList.add("tcw-loading-overlay--hidden");
|
|
3056
|
+
}
|
|
3057
|
+
fail(e) {
|
|
3058
|
+
this.phase !== "idle" && (this.phase = "failed", this.clearTimer(), this.label.textContent = e, this.el.classList.add("tcw-loading-overlay--error"), this.el.classList.remove("tcw-loading-overlay--hidden"));
|
|
3059
|
+
}
|
|
3060
|
+
isActive() {
|
|
3061
|
+
return this.phase !== "idle";
|
|
3062
|
+
}
|
|
3063
|
+
hasFailed() {
|
|
3064
|
+
return this.phase === "failed";
|
|
3065
|
+
}
|
|
3066
|
+
isShown() {
|
|
3067
|
+
return !this.el.classList.contains("tcw-loading-overlay--hidden");
|
|
3068
|
+
}
|
|
3069
|
+
destroy() {
|
|
3070
|
+
this.clearTimer(), this.el.remove();
|
|
3071
|
+
}
|
|
3072
|
+
clearTimer() {
|
|
3073
|
+
this.showTimer !== null && (clearTimeout(this.showTimer), this.showTimer = null);
|
|
3074
|
+
}
|
|
3075
|
+
}, Ke = 48, qe = 5e4, Je = 100;
|
|
3076
|
+
function Ye() {
|
|
3077
|
+
return new Promise((e) => {
|
|
3078
|
+
if (typeof requestAnimationFrame != "function" || document.hidden) {
|
|
3079
|
+
setTimeout(e, 0);
|
|
3080
|
+
return;
|
|
3081
|
+
}
|
|
3082
|
+
let t = setTimeout(e, Je);
|
|
3083
|
+
requestAnimationFrame(() => setTimeout(() => {
|
|
3084
|
+
clearTimeout(t), e();
|
|
3085
|
+
}, 0));
|
|
3086
|
+
});
|
|
3087
|
+
}
|
|
2740
3088
|
var $ = [
|
|
2741
3089
|
"#f7931a",
|
|
2742
3090
|
"#627eea",
|
|
@@ -2744,7 +3092,7 @@ var $ = [
|
|
|
2744
3092
|
"#e84142",
|
|
2745
3093
|
"#8247e5",
|
|
2746
3094
|
"#f3ba2f"
|
|
2747
|
-
],
|
|
3095
|
+
], Xe = class {
|
|
2748
3096
|
chart;
|
|
2749
3097
|
state;
|
|
2750
3098
|
toolbar = null;
|
|
@@ -2765,10 +3113,11 @@ var $ = [
|
|
|
2765
3113
|
depthLadder = null;
|
|
2766
3114
|
dataWindow = null;
|
|
2767
3115
|
lastHoverIndex = null;
|
|
2768
|
-
favoritesStore = new
|
|
3116
|
+
favoritesStore = new Ee();
|
|
2769
3117
|
watchlist = null;
|
|
2770
3118
|
watchlistSparkBuffer = /* @__PURE__ */ new Map();
|
|
2771
3119
|
sessionRefPrice = null;
|
|
3120
|
+
hostWatchlistRefPrice = /* @__PURE__ */ new Map();
|
|
2772
3121
|
watchlistInterval = null;
|
|
2773
3122
|
replayOriginalData = null;
|
|
2774
3123
|
replayPollInterval = null;
|
|
@@ -2778,17 +3127,25 @@ var $ = [
|
|
|
2778
3127
|
activeLayoutKey = null;
|
|
2779
3128
|
root;
|
|
2780
3129
|
chartContainer;
|
|
3130
|
+
loading;
|
|
3131
|
+
connectSeq = 0;
|
|
3132
|
+
localSeq = 0;
|
|
3133
|
+
lastLocalSwitchMs = 0;
|
|
2781
3134
|
destroyed = !1;
|
|
2782
3135
|
options;
|
|
2783
3136
|
symbols;
|
|
2784
3137
|
settingsState;
|
|
3138
|
+
t;
|
|
2785
3139
|
adapter = null;
|
|
2786
3140
|
boundGlobalKeydown = null;
|
|
2787
3141
|
baseSeries = null;
|
|
2788
3142
|
baseTimeframeMs = 0;
|
|
2789
3143
|
compares = [];
|
|
2790
3144
|
constructor(n, r = {}) {
|
|
2791
|
-
if (this.options = r, this.symbols = r.symbols ?? ee, this.settingsState = {
|
|
3145
|
+
if (this.options = r, this.symbols = r.symbols ?? ee, this.settingsState = {
|
|
3146
|
+
...p,
|
|
3147
|
+
...r.chartOptions?.numberLocale ? { numberLocale: r.chartOptions.numberLocale } : {}
|
|
3148
|
+
}, this.t = Ue(Q(r.locale, r.messages)), r.persistLayouts) {
|
|
2792
3149
|
let e = r.persistLayouts === !0 ? {} : r.persistLayouts;
|
|
2793
3150
|
this.layoutKeyPrefix = e.keyPrefix ?? "tcw:layout:", this.layoutDebounceMs = e.debounceMs ?? 1500;
|
|
2794
3151
|
}
|
|
@@ -2801,8 +3158,8 @@ var $ = [
|
|
|
2801
3158
|
activeIndicators: /* @__PURE__ */ new Map(),
|
|
2802
3159
|
activeTool: null,
|
|
2803
3160
|
magnetEnabled: !0,
|
|
2804
|
-
connectionState: "connecting",
|
|
2805
|
-
connectionMessage: "
|
|
3161
|
+
connectionState: r.adapter ? "connecting" : "disconnected",
|
|
3162
|
+
connectionMessage: r.adapter ? this.t("status.connecting") : ""
|
|
2806
3163
|
}, g(), this.root = document.createElement("div"), this.root.className = "tcw-root", this.root.dataset.tcwTheme = i ? "dark" : "light", n.appendChild(this.root), r.toolbar !== !1 && (this.toolbar = new ne(this.root, {
|
|
2807
3164
|
symbols: this.symbols,
|
|
2808
3165
|
timeframes: r.timeframes ? c.filter((e) => r.timeframes.includes(e.value)) : c,
|
|
@@ -2823,9 +3180,9 @@ var $ = [
|
|
|
2823
3180
|
onToggleObjects: r.objectTree === !1 ? void 0 : () => this.toggleObjects(),
|
|
2824
3181
|
onBracket: r.trading === !1 ? void 0 : (e) => this.startBracket(e),
|
|
2825
3182
|
onToggleLadder: r.trading !== !1 && r.depthLadder ? () => this.depthLadder?.toggle() : void 0
|
|
2826
|
-
}));
|
|
3183
|
+
}, this.t));
|
|
2827
3184
|
let o = document.createElement("div");
|
|
2828
|
-
if (o.className = "tcw-body", r.drawingTools !== !1 && (r.drawingFavorites && this.favoritesStore.seedDefaults(r.drawingFavorites), this.sidebar = new
|
|
3185
|
+
if (o.className = "tcw-body", r.drawingTools !== !1 && (r.drawingFavorites && this.favoritesStore.seedDefaults(r.drawingFavorites), this.sidebar = new se(o, {
|
|
2829
3186
|
drawingToolGroups: u,
|
|
2830
3187
|
favorites: this.favoritesStore.list()
|
|
2831
3188
|
}, {
|
|
@@ -2842,13 +3199,14 @@ var $ = [
|
|
|
2842
3199
|
}, this.updateUI();
|
|
2843
3200
|
},
|
|
2844
3201
|
onToggleStyle: () => this.drawingStyle?.toggle()
|
|
2845
|
-
})), this.chartContainer = document.createElement("div"), this.chartContainer.className = "tcw-chart-container", o.appendChild(this.chartContainer), r.watchlist && (this.watchlist = new V(o, this.symbols, { onSelect: (e) => {
|
|
3202
|
+
})), this.chartContainer = document.createElement("div"), this.chartContainer.className = "tcw-chart-container", o.appendChild(this.chartContainer), this.loading = new Ge(this.chartContainer, this.t("status.loading")), r.watchlist && (this.watchlist = new V(o, this.symbols, { onSelect: (e) => {
|
|
2846
3203
|
this.setSymbol(e);
|
|
2847
|
-
} }), this.watchlist.setActive(this.state.symbol)), this.root.appendChild(o), this.chart = new e(this.chartContainer, {
|
|
3204
|
+
} }, this.t("watchlist.title")), this.watchlist.setActive(this.state.symbol), this.watchlist.setLocale(this.settingsState.numberLocale || void 0)), this.root.appendChild(o), this.chart = new e(this.chartContainer, {
|
|
2848
3205
|
chartType: this.state.chartType,
|
|
2849
3206
|
theme: a,
|
|
2850
3207
|
autoScale: !0,
|
|
2851
3208
|
crosshair: { mode: "magnet" },
|
|
3209
|
+
...r.chartOptions,
|
|
2852
3210
|
features: {
|
|
2853
3211
|
drawings: !0,
|
|
2854
3212
|
drawingMagnet: !0,
|
|
@@ -2859,43 +3217,44 @@ var $ = [
|
|
|
2859
3217
|
volume: !0,
|
|
2860
3218
|
legend: !0,
|
|
2861
3219
|
crosshair: !0,
|
|
3220
|
+
crosshairTooltip: !1,
|
|
2862
3221
|
keyboard: !0,
|
|
2863
3222
|
screenshot: !0,
|
|
2864
3223
|
alerts: !0,
|
|
2865
3224
|
barCountdown: !0,
|
|
2866
3225
|
logScale: !0,
|
|
2867
|
-
watermark: !0
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
}), r.dragDropImport !== !1 && (this.dragDrop = new t(this.chartContainer, {
|
|
3226
|
+
watermark: !0,
|
|
3227
|
+
...r.chartOptions?.features
|
|
3228
|
+
}
|
|
3229
|
+
}), this.chart.on("dataUpdate", (e) => this.handleDataUpdate(e.payload)), r.dragDropImport !== !1 && (this.dragDrop = new t(this.chartContainer, {
|
|
2871
3230
|
onData: (e, t, n) => {
|
|
2872
3231
|
this.setData(e), this.toast(`Loaded ${t.data.length} bars from ${n.name}` + (t.skipped > 0 ? ` (${t.skipped} skipped)` : ""));
|
|
2873
3232
|
},
|
|
2874
3233
|
onError: (e, t) => {
|
|
2875
3234
|
this.toast(`${t.name}: ${e.message}`, "error");
|
|
2876
3235
|
}
|
|
2877
|
-
}), this.dragDrop.attach()), r.statusBar !== !1 && (this.statusBar = new
|
|
3236
|
+
}), this.dragDrop.attach()), r.statusBar !== !1 && (this.statusBar = new C(this.root)), r.settings !== !1 && (this.settings = new S({
|
|
2878
3237
|
onChange: (e) => this.applySettings(e),
|
|
2879
3238
|
onReset: () => this.resetSettings(),
|
|
2880
3239
|
onClose: () => {}
|
|
2881
|
-
})), this.symbolSearch = new
|
|
3240
|
+
}, this.t)), this.symbolSearch = new T({
|
|
2882
3241
|
onPick: (e) => {
|
|
2883
3242
|
this.setSymbol(e);
|
|
2884
3243
|
},
|
|
2885
3244
|
onClose: () => {}
|
|
2886
|
-
}), this.hotkeySheet = new N({ onClose: () => {} }), this.chart.on("barClick", (e) => {
|
|
3245
|
+
}), this.hotkeySheet = new N({ onClose: () => {} }, this.t), this.chart.on("barClick", (e) => {
|
|
2887
3246
|
if (!this.replayBar?.isMounted()) return;
|
|
2888
3247
|
let t = e.payload.barIndex;
|
|
2889
3248
|
typeof t == "number" && (this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(t), this.replayBar.setState("paused"));
|
|
2890
|
-
}), this.dataWindow = new
|
|
3249
|
+
}), this.dataWindow = new je(this.root, { formatPrice: (e) => this.formatAlertPrice(e) }), this.chart.on("crosshairMove", (e) => {
|
|
2891
3250
|
let t = e.payload;
|
|
2892
3251
|
this.lastHoverIndex = typeof t.barIndex == "number" ? t.barIndex : null, this.dataWindow?.isOpen() && this.dataWindow.render(this.buildDataWindowModel());
|
|
2893
|
-
}), r.drawingTools !== !1 && (this.drawingStyle = new
|
|
3252
|
+
}), r.drawingTools !== !1 && (this.drawingStyle = new we(this.root, {
|
|
2894
3253
|
onStyleChange: (e) => {
|
|
2895
3254
|
this.chart.setDrawingStyle(e), this.chart.setSelectedDrawingStyle(e);
|
|
2896
3255
|
},
|
|
2897
3256
|
getStyle: () => this.chart.getDrawingStyle()
|
|
2898
|
-
}, new
|
|
3257
|
+
}, new be())), r.trading !== !1 && (this.bracketBar = new De(this.root, {
|
|
2899
3258
|
onConfirm: () => this.chart.confirmBracket(),
|
|
2900
3259
|
onCancel: () => {
|
|
2901
3260
|
this.chart.cancelBracket(), this.bracketBar?.hide();
|
|
@@ -2903,7 +3262,7 @@ var $ = [
|
|
|
2903
3262
|
}), this.chart.on("bracketPlace", (e) => {
|
|
2904
3263
|
let t = e.payload;
|
|
2905
3264
|
this.bracketBar?.hide(), this.toast(`${t.side === "buy" ? "Long" : "Short"} bracket placed · ${t.riskReward.toFixed(2)}R`);
|
|
2906
|
-
}), r.depthLadder && (this.depthLadder = new
|
|
3265
|
+
}), r.depthLadder && (this.depthLadder = new Ae(this.root, {
|
|
2907
3266
|
onTrade: (e, t) => {
|
|
2908
3267
|
this.chart.placeOrderIntent({
|
|
2909
3268
|
side: e,
|
|
@@ -2915,7 +3274,7 @@ var $ = [
|
|
|
2915
3274
|
})), this.chart.on("dataUpdate", (e) => {
|
|
2916
3275
|
let t = e.payload;
|
|
2917
3276
|
t && t.bracket === "cancelled" && this.bracketBar?.hide();
|
|
2918
|
-
})), r.alerts !== !1 && (this.alertsPanel = new
|
|
3277
|
+
})), r.alerts !== !1 && (this.alertsPanel = new ue(this.root, {
|
|
2919
3278
|
onAdd: (e, t, n, r, i) => {
|
|
2920
3279
|
this.chart.addAlert(e, t, n, r, i);
|
|
2921
3280
|
},
|
|
@@ -2923,14 +3282,14 @@ var $ = [
|
|
|
2923
3282
|
onClear: () => this.chart.clearAlerts(),
|
|
2924
3283
|
getChannelValue: (e) => this.getAlertChannelValue(e),
|
|
2925
3284
|
formatPrice: (e) => this.formatAlertPrice(e)
|
|
2926
|
-
}), this.chart.on("alertAdd", () => this.refreshAlerts()), this.chart.on("alertRemove", () => this.refreshAlerts()), this.chart.on("alertUpdate", () => this.refreshAlerts()), r.alertNotifications && (this.alertNotifier = new
|
|
3285
|
+
}), this.chart.on("alertAdd", () => this.refreshAlerts()), this.chart.on("alertRemove", () => this.refreshAlerts()), this.chart.on("alertUpdate", () => this.refreshAlerts()), r.alertNotifications && (this.alertNotifier = new Oe(r.alertNotifications)), this.chart.on("alertTriggered", (e) => {
|
|
2927
3286
|
let t = e.payload, n = `Price ${this.formatAlertPrice(t.price)}${t.message ? ` — ${t.message}` : ""}`;
|
|
2928
3287
|
this.toast(`🔔 Alert: ${n}`, "info"), this.alertNotifier?.notify(n), this.refreshAlerts();
|
|
2929
3288
|
})), r.objectTree !== !1) {
|
|
2930
|
-
this.indicatorSettings = new
|
|
3289
|
+
this.indicatorSettings = new ge(this.root, {
|
|
2931
3290
|
onApply: (e, t) => this.chart.updateIndicator(e, t),
|
|
2932
3291
|
onClose: () => {}
|
|
2933
|
-
}), this.objectTree = new
|
|
3292
|
+
}), this.objectTree = new de(this.root, {
|
|
2934
3293
|
onRemoveIndicator: (e) => this.handleRemoveIndicator(e),
|
|
2935
3294
|
onConfigureIndicator: (e) => this.openIndicatorSettings(e),
|
|
2936
3295
|
onToggleIndicatorVisible: (e, t) => {
|
|
@@ -2953,7 +3312,7 @@ var $ = [
|
|
|
2953
3312
|
};
|
|
2954
3313
|
this.chart.on("drawingCreate", e), this.chart.on("drawingRemove", e), this.chart.on("indicatorAdd", e), this.chart.on("indicatorRemove", e);
|
|
2955
3314
|
}
|
|
2956
|
-
if (this.commandPalette = new
|
|
3315
|
+
if (this.commandPalette = new w({
|
|
2957
3316
|
onIndicator: (e) => this.handleAddIndicator(e),
|
|
2958
3317
|
onChartType: (e) => this.handleChartType(e),
|
|
2959
3318
|
onDrawingTool: (e) => this.handleDrawingTool(e),
|
|
@@ -2969,7 +3328,7 @@ var $ = [
|
|
|
2969
3328
|
e.preventDefault(), this.hotkeySheet?.open();
|
|
2970
3329
|
}
|
|
2971
3330
|
}, document.addEventListener("keydown", this.boundGlobalKeydown), r.adapter && (this.adapter = r.adapter, this.connectStream()), this.watchlist && (this.watchlistInterval = setInterval(() => this.tickWatchlist(), 1e3)), this.updateUI(), r.onReady?.(this.chart), r.shareUrl && typeof location < "u") {
|
|
2972
|
-
let e =
|
|
3331
|
+
let e = Be(location.hash);
|
|
2973
3332
|
e && this.importState(e);
|
|
2974
3333
|
}
|
|
2975
3334
|
}
|
|
@@ -2983,19 +3342,19 @@ var $ = [
|
|
|
2983
3342
|
}, this.sessionRefPrice = null, this.options.onSymbolChange?.(e), this.updateUI(), this.watchlist?.setActive(e), this.adapter && await this.connectStream();
|
|
2984
3343
|
}
|
|
2985
3344
|
setWatchlistEntry(e, t) {
|
|
2986
|
-
this.watchlist?.setEntry(e, t);
|
|
3345
|
+
t.refPrice !== void 0 && this.hostWatchlistRefPrice.set(e, t.refPrice), this.watchlist?.setEntry(e, t);
|
|
2987
3346
|
}
|
|
2988
3347
|
tickWatchlist() {
|
|
2989
3348
|
if (!this.watchlist) return;
|
|
2990
3349
|
let e = this.chart.getData();
|
|
2991
3350
|
if (e.length === 0) return;
|
|
2992
|
-
let t = e[e.length - 1];
|
|
2993
|
-
this.sessionRefPrice === null && (this.sessionRefPrice = e[0].open);
|
|
2994
|
-
let
|
|
2995
|
-
|
|
3351
|
+
let t = e[e.length - 1], n = this.hostWatchlistRefPrice.get(this.state.symbol);
|
|
3352
|
+
n === void 0 && this.sessionRefPrice === null && (this.sessionRefPrice = e[0].open);
|
|
3353
|
+
let r = this.watchlistSparkBuffer.get(this.state.symbol) ?? [];
|
|
3354
|
+
r.push(t.close), r.length > 40 && r.shift(), this.watchlistSparkBuffer.set(this.state.symbol, r), this.watchlist.setEntry(this.state.symbol, {
|
|
2996
3355
|
lastPrice: t.close,
|
|
2997
|
-
refPrice: this.sessionRefPrice,
|
|
2998
|
-
sparkline:
|
|
3356
|
+
refPrice: n ?? this.sessionRefPrice ?? e[0].open,
|
|
3357
|
+
sparkline: r.slice()
|
|
2999
3358
|
});
|
|
3000
3359
|
}
|
|
3001
3360
|
async setTimeframe(e) {
|
|
@@ -3006,7 +3365,13 @@ var $ = [
|
|
|
3006
3365
|
await this.connectStream();
|
|
3007
3366
|
return;
|
|
3008
3367
|
}
|
|
3009
|
-
this.options.resampleTimeframes !== !1
|
|
3368
|
+
if (this.options.resampleTimeframes !== !1) {
|
|
3369
|
+
if (!this.baseSeries) {
|
|
3370
|
+
let e = this.chart.getData();
|
|
3371
|
+
e.length > 0 && (this.baseSeries = e, this.baseTimeframeMs = s(e));
|
|
3372
|
+
}
|
|
3373
|
+
await this.switchLocalTimeframe();
|
|
3374
|
+
}
|
|
3010
3375
|
}
|
|
3011
3376
|
setTheme(e) {
|
|
3012
3377
|
let t = this.resolveIsDark(e), n = this.resolveTheme(e);
|
|
@@ -3019,37 +3384,65 @@ var $ = [
|
|
|
3019
3384
|
return this.chart;
|
|
3020
3385
|
}
|
|
3021
3386
|
destroy() {
|
|
3022
|
-
this.destroyed || (this.destroyed = !0, this.boundGlobalKeydown && document.removeEventListener("keydown", this.boundGlobalKeydown), this.flushActiveLayout(), this.commandPalette?.destroy(), this.symbolSearch?.destroy(), this.hotkeySheet?.destroy(), this.replayPollInterval && clearInterval(this.replayPollInterval), this.replayBar?.destroy(), this.dragDrop?.detach(), this.alertsPanel?.destroy(), this.objectTree?.destroy(), this.indicatorSettings?.destroy(), this.drawingStyle?.destroy(), this.bracketBar?.destroy(), this.alertNotifier?.destroy(), this.depthLadder?.destroy(), this.dataWindow?.destroy(), this.watchlistInterval && clearInterval(this.watchlistInterval), this.watchlist?.destroy(), this.toolbar?.destroy(), this.sidebar?.destroy(), this.settings?.destroy(), this.statusBar?.destroy(), this.chart.destroy(), this.root.remove(), _());
|
|
3387
|
+
this.destroyed || (this.destroyed = !0, this.boundGlobalKeydown && document.removeEventListener("keydown", this.boundGlobalKeydown), this.flushActiveLayout(), this.commandPalette?.destroy(), this.symbolSearch?.destroy(), this.hotkeySheet?.destroy(), this.replayPollInterval && clearInterval(this.replayPollInterval), this.replayBar?.destroy(), this.dragDrop?.detach(), this.alertsPanel?.destroy(), this.objectTree?.destroy(), this.indicatorSettings?.destroy(), this.drawingStyle?.destroy(), this.bracketBar?.destroy(), this.alertNotifier?.destroy(), this.depthLadder?.destroy(), this.dataWindow?.destroy(), this.watchlistInterval && clearInterval(this.watchlistInterval), this.watchlist?.destroy(), this.toolbar?.destroy(), this.sidebar?.destroy(), this.settings?.destroy(), this.statusBar?.destroy(), this.loading.destroy(), this.chart.destroy(), this.root.remove(), _());
|
|
3023
3388
|
}
|
|
3024
3389
|
handleSymbolClick() {
|
|
3025
3390
|
this.symbolSearch?.open(this.symbols, this.state.symbol);
|
|
3026
3391
|
}
|
|
3027
3392
|
handleTimeframe(e) {
|
|
3028
|
-
|
|
3029
|
-
...this.state,
|
|
3030
|
-
timeframe: e
|
|
3031
|
-
}, this.options.onTimeframeChange?.(e), this.updateUI(), this.adapter) {
|
|
3032
|
-
this.connectStream();
|
|
3033
|
-
return;
|
|
3034
|
-
}
|
|
3035
|
-
if (this.options.resampleTimeframes !== !1) {
|
|
3036
|
-
if (!this.baseSeries) {
|
|
3037
|
-
let e = this.chart.getData();
|
|
3038
|
-
e.length > 0 && (this.baseSeries = e, this.baseTimeframeMs = s(e));
|
|
3039
|
-
}
|
|
3040
|
-
this.applyTimeframeData();
|
|
3041
|
-
}
|
|
3393
|
+
this.setTimeframe(e);
|
|
3042
3394
|
}
|
|
3043
3395
|
setData(e) {
|
|
3044
|
-
this.baseSeries = e, this.baseTimeframeMs = s(e), this.applyTimeframeData();
|
|
3396
|
+
this.localSeq++, this.baseSeries = e, this.baseTimeframeMs = s(e), this.applyTimeframeData(), this.adapter || this.loading.end();
|
|
3397
|
+
}
|
|
3398
|
+
async switchLocalTimeframe() {
|
|
3399
|
+
if (!this.baseSeries) return;
|
|
3400
|
+
let e = ++this.localSeq, t = this.lastLocalSwitchMs >= Ke || this.baseSeries.length >= qe;
|
|
3401
|
+
try {
|
|
3402
|
+
if (t && (this.loading.begin(this.chart.getData().length > 0, !0), await Ye(), e !== this.localSeq || this.destroyed)) return;
|
|
3403
|
+
this.applyTimeframeData();
|
|
3404
|
+
} finally {
|
|
3405
|
+
e === this.localSeq && this.loading.end();
|
|
3406
|
+
}
|
|
3045
3407
|
}
|
|
3046
3408
|
applyTimeframeData() {
|
|
3047
3409
|
if (!this.baseSeries) return;
|
|
3048
|
-
let e = a(this.state.timeframe);
|
|
3049
|
-
if (this.baseTimeframeMs > 0 &&
|
|
3410
|
+
let e = performance.now(), t = a(this.state.timeframe);
|
|
3411
|
+
if (this.baseTimeframeMs > 0 && t > this.baseTimeframeMs) {
|
|
3050
3412
|
let e = this.options.weekStartsOn ?? 1;
|
|
3051
3413
|
this.chart.setData(o(this.baseSeries, this.state.timeframe, { weekStartsOn: e }));
|
|
3052
3414
|
} else this.chart.setData(this.baseSeries);
|
|
3415
|
+
this.lastLocalSwitchMs = performance.now() - e;
|
|
3416
|
+
}
|
|
3417
|
+
handleDataUpdate(e) {
|
|
3418
|
+
if (!e || typeof e != "object") return;
|
|
3419
|
+
let t = e;
|
|
3420
|
+
if (typeof t.length == "number") {
|
|
3421
|
+
t.length > 0 && this.loading.isActive() && (this.loading.end(), this.state.connectionState === "error" && this.setConnectionState("connected", this.t("status.live")));
|
|
3422
|
+
return;
|
|
3423
|
+
}
|
|
3424
|
+
if (t.error !== void 0) {
|
|
3425
|
+
this.loading.isActive() && (this.loading.fail(this.t("status.connectionFailed")), this.setConnectionState("error", t.error || this.t("status.connectionFailed")));
|
|
3426
|
+
return;
|
|
3427
|
+
}
|
|
3428
|
+
switch (t.connection?.state) {
|
|
3429
|
+
case "connected":
|
|
3430
|
+
this.loading.hasFailed() && this.loading.end(), !this.loading.isActive() && this.state.connectionState !== "connected" && this.setConnectionState("connected", this.t("status.live"));
|
|
3431
|
+
break;
|
|
3432
|
+
case "reconnecting":
|
|
3433
|
+
this.loading.isActive() || this.setConnectionState("connecting", this.t("status.connecting"));
|
|
3434
|
+
break;
|
|
3435
|
+
case "error":
|
|
3436
|
+
this.loading.isActive() || this.setConnectionState("error", this.t("status.connectionFailed"));
|
|
3437
|
+
break;
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
setConnectionState(e, t) {
|
|
3441
|
+
this.state = {
|
|
3442
|
+
...this.state,
|
|
3443
|
+
connectionState: e,
|
|
3444
|
+
connectionMessage: t
|
|
3445
|
+
}, this.updateUI();
|
|
3053
3446
|
}
|
|
3054
3447
|
toggleAlerts() {
|
|
3055
3448
|
this.alertsPanel && (this.alertsPanel.toggle(), this.alertsPanel.isOpen() && this.refreshAlerts());
|
|
@@ -3063,7 +3456,7 @@ var $ = [
|
|
|
3063
3456
|
id: e.id,
|
|
3064
3457
|
params: e.params
|
|
3065
3458
|
}));
|
|
3066
|
-
return
|
|
3459
|
+
return Re({
|
|
3067
3460
|
v: 1,
|
|
3068
3461
|
symbol: this.state.symbol,
|
|
3069
3462
|
timeframe: this.state.timeframe,
|
|
@@ -3074,7 +3467,7 @@ var $ = [
|
|
|
3074
3467
|
});
|
|
3075
3468
|
}
|
|
3076
3469
|
async importState(e) {
|
|
3077
|
-
let t =
|
|
3470
|
+
let t = ze(e);
|
|
3078
3471
|
if (!t) return !1;
|
|
3079
3472
|
t.symbol && t.symbol !== this.state.symbol && await this.setSymbol(t.symbol), t.timeframe && t.timeframe !== this.state.timeframe && await this.setTimeframe(t.timeframe), t.chartType && this.handleChartType(t.chartType), this.chart.setScaleMode(t.scaleMode);
|
|
3080
3473
|
for (let [, e] of this.state.activeIndicators) this.chart.removeIndicator(e);
|
|
@@ -3093,7 +3486,7 @@ var $ = [
|
|
|
3093
3486
|
this.toast(e ? "Chart image copied" : "Copy failed — image clipboard unavailable", e ? "info" : "error");
|
|
3094
3487
|
}
|
|
3095
3488
|
async copyShareLink() {
|
|
3096
|
-
let e =
|
|
3489
|
+
let e = Ve(typeof location < "u" ? location.href : "", this.exportState());
|
|
3097
3490
|
try {
|
|
3098
3491
|
await navigator.clipboard.writeText(e), this.toast("Share link copied");
|
|
3099
3492
|
} catch {
|
|
@@ -3161,7 +3554,7 @@ var $ = [
|
|
|
3161
3554
|
visible: e.visible
|
|
3162
3555
|
})), t = this.chart.getDrawings().map((e) => ({
|
|
3163
3556
|
id: e.id,
|
|
3164
|
-
label:
|
|
3557
|
+
label: pe(e.type),
|
|
3165
3558
|
visible: e.visible,
|
|
3166
3559
|
locked: e.locked
|
|
3167
3560
|
})), n = this.compares.map((e) => ({
|
|
@@ -3524,7 +3917,7 @@ var $ = [
|
|
|
3524
3917
|
}) : (this.chart.setScaleMode(e.scaleMode), this.settingsState = {
|
|
3525
3918
|
...this.settingsState,
|
|
3526
3919
|
logScale: e.scaleMode === "logarithmic"
|
|
3527
|
-
}), e.numberLocale !== void 0 && this.chart.setNumberLocale(e.numberLocale), e.timezone !== void 0 && this.chart.setTimezoneOffset(e.timezone === "local" ? null : Number(e.timezone));
|
|
3920
|
+
}), e.numberLocale !== void 0 && (this.chart.setNumberLocale(e.numberLocale), this.watchlist?.setLocale(e.numberLocale || void 0)), e.timezone !== void 0 && this.chart.setTimezoneOffset(e.timezone === "local" ? null : Number(e.timezone));
|
|
3528
3921
|
let t = { ...this.chart.getTheme() }, n = !1;
|
|
3529
3922
|
e.candleUpColor !== void 0 && (t.candleUp = e.candleUpColor, n = !0), e.candleDownColor !== void 0 && (t.candleDown = e.candleDownColor, n = !0), e.candleUpWick !== void 0 && (t.candleUpWick = e.candleUpWick, n = !0), e.candleDownWick !== void 0 && (t.candleDownWick = e.candleDownWick, n = !0), e.backgroundColor !== void 0 && (t.background = e.backgroundColor, n = !0), e.gridColor !== void 0 && (t.grid = e.gridColor, n = !0), n && this.chart.setTheme(t);
|
|
3530
3923
|
}
|
|
@@ -3532,35 +3925,40 @@ var $ = [
|
|
|
3532
3925
|
this.settingsState = { ...p }, this.applySettings(this.settingsState);
|
|
3533
3926
|
}
|
|
3534
3927
|
async connectStream() {
|
|
3535
|
-
if (this.adapter)
|
|
3536
|
-
|
|
3928
|
+
if (!this.adapter) return;
|
|
3929
|
+
let e = ++this.connectSeq;
|
|
3930
|
+
this.state = {
|
|
3931
|
+
...this.state,
|
|
3932
|
+
connectionState: "connecting",
|
|
3933
|
+
connectionMessage: this.t("status.connecting")
|
|
3934
|
+
}, this.updateUI(), this.loading.begin(this.chart.getData().length > 0);
|
|
3935
|
+
try {
|
|
3936
|
+
if (this.chart.disconnectStream(), await this.chart.connect({
|
|
3937
|
+
adapter: this.adapter,
|
|
3938
|
+
symbol: this.state.symbol,
|
|
3939
|
+
timeframe: this.state.timeframe,
|
|
3940
|
+
historyLimit: this.options.historyLimit ?? 500
|
|
3941
|
+
}), e !== this.connectSeq || this.destroyed) return;
|
|
3942
|
+
this.chart.setWatermark(this.state.symbol.replace("USDT", " / USDT"), {
|
|
3943
|
+
fontSize: 48,
|
|
3944
|
+
color: this.state.isDark ? "rgba(255,255,255,0.03)" : "rgba(0,0,0,0.03)"
|
|
3945
|
+
}), this.applySymbolLayout(this.state.symbol), this.loading.hasFailed() ? this.state = {
|
|
3537
3946
|
...this.state,
|
|
3538
|
-
connectionState: "
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
this.
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
...this.state,
|
|
3552
|
-
connectionState: "connected",
|
|
3553
|
-
connectionMessage: "Live"
|
|
3554
|
-
}, this.refetchCompares();
|
|
3555
|
-
} catch (e) {
|
|
3556
|
-
this.state = {
|
|
3557
|
-
...this.state,
|
|
3558
|
-
connectionState: "error",
|
|
3559
|
-
connectionMessage: e instanceof Error ? e.message : "Connection failed"
|
|
3560
|
-
};
|
|
3561
|
-
}
|
|
3562
|
-
this.updateUI();
|
|
3947
|
+
connectionState: "error"
|
|
3948
|
+
} : (this.loading.end(), this.state = {
|
|
3949
|
+
...this.state,
|
|
3950
|
+
connectionState: "connected",
|
|
3951
|
+
connectionMessage: this.t("status.live")
|
|
3952
|
+
}), this.refetchCompares();
|
|
3953
|
+
} catch (t) {
|
|
3954
|
+
if (e !== this.connectSeq || this.destroyed) return;
|
|
3955
|
+
this.loading.fail(this.t("status.connectionFailed")), this.state = {
|
|
3956
|
+
...this.state,
|
|
3957
|
+
connectionState: "error",
|
|
3958
|
+
connectionMessage: t instanceof Error ? t.message : this.t("status.connectionFailed")
|
|
3959
|
+
};
|
|
3563
3960
|
}
|
|
3961
|
+
this.updateUI();
|
|
3564
3962
|
}
|
|
3565
3963
|
updateUI() {
|
|
3566
3964
|
this.toolbar?.update(this.state), this.sidebar?.update(this.state), this.statusBar?.update({
|
|
@@ -3585,6 +3983,6 @@ var $ = [
|
|
|
3585
3983
|
}
|
|
3586
3984
|
};
|
|
3587
3985
|
//#endregion
|
|
3588
|
-
export {
|
|
3986
|
+
export { Xe as ChartWidget };
|
|
3589
3987
|
|
|
3590
3988
|
//# sourceMappingURL=index.js.map
|