@tradecanvas/chart 0.9.0 → 1.0.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.
Files changed (81) hide show
  1. package/dist/Chart.d.ts +148 -5
  2. package/dist/Chart.d.ts.map +1 -1
  3. package/dist/{DragDropImporter-6QOjnfSj.js → DragDropImporter-C4x09P7e.js} +446 -112
  4. package/dist/DragDropImporter-C4x09P7e.js.map +1 -0
  5. package/dist/DragDropImporter-DeXlngof.cjs +2 -0
  6. package/dist/DragDropImporter-DeXlngof.cjs.map +1 -0
  7. package/dist/charts/ChartTypeStrategy.d.ts +13 -0
  8. package/dist/charts/ChartTypeStrategy.d.ts.map +1 -1
  9. package/dist/finance/PerformanceDashboard.d.ts +43 -0
  10. package/dist/finance/PerformanceDashboard.d.ts.map +1 -0
  11. package/dist/finance/index.d.ts +4 -0
  12. package/dist/finance/index.d.ts.map +1 -1
  13. package/dist/finance/performanceData.d.ts +39 -0
  14. package/dist/finance/performanceData.d.ts.map +1 -0
  15. package/dist/index.cjs +1 -1
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.ts +8 -4
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +293 -36
  20. package/dist/index.js.map +1 -1
  21. package/dist/io/index.d.ts +2 -0
  22. package/dist/io/index.d.ts.map +1 -1
  23. package/dist/io/resampleOHLCV.d.ts +29 -0
  24. package/dist/io/resampleOHLCV.d.ts.map +1 -0
  25. package/dist/plugins/PluginManager.d.ts +27 -1
  26. package/dist/plugins/PluginManager.d.ts.map +1 -1
  27. package/dist/plugins/contracts.d.ts +54 -0
  28. package/dist/plugins/contracts.d.ts.map +1 -0
  29. package/dist/plugins/index.d.ts +4 -0
  30. package/dist/plugins/index.d.ts.map +1 -1
  31. package/dist/plugins/registry.d.ts +10 -0
  32. package/dist/plugins/registry.d.ts.map +1 -0
  33. package/dist/trading/wireExecution.d.ts +26 -0
  34. package/dist/trading/wireExecution.d.ts.map +1 -0
  35. package/dist/widget/AlertNotifier.d.ts +32 -0
  36. package/dist/widget/AlertNotifier.d.ts.map +1 -0
  37. package/dist/widget/ChartWidget.d.ts +54 -1
  38. package/dist/widget/ChartWidget.d.ts.map +1 -1
  39. package/dist/widget/DrawingFavoritesStore.d.ts +22 -0
  40. package/dist/widget/DrawingFavoritesStore.d.ts.map +1 -0
  41. package/dist/widget/DrawingTemplateStore.d.ts +29 -0
  42. package/dist/widget/DrawingTemplateStore.d.ts.map +1 -0
  43. package/dist/widget/WidgetAlertsPanel.d.ts +58 -0
  44. package/dist/widget/WidgetAlertsPanel.d.ts.map +1 -0
  45. package/dist/widget/WidgetBracketBar.d.ts +21 -0
  46. package/dist/widget/WidgetBracketBar.d.ts.map +1 -0
  47. package/dist/widget/WidgetDataWindow.d.ts +41 -0
  48. package/dist/widget/WidgetDataWindow.d.ts.map +1 -0
  49. package/dist/widget/WidgetDepthLadder.d.ts +29 -0
  50. package/dist/widget/WidgetDepthLadder.d.ts.map +1 -0
  51. package/dist/widget/WidgetDrawingSidebar.d.ts +6 -0
  52. package/dist/widget/WidgetDrawingSidebar.d.ts.map +1 -1
  53. package/dist/widget/WidgetDrawingStyle.d.ts +36 -0
  54. package/dist/widget/WidgetDrawingStyle.d.ts.map +1 -0
  55. package/dist/widget/WidgetHotkeySheet.d.ts.map +1 -1
  56. package/dist/widget/WidgetIndicatorSettings.d.ts +42 -0
  57. package/dist/widget/WidgetIndicatorSettings.d.ts.map +1 -0
  58. package/dist/widget/WidgetObjectTree.d.ts +59 -0
  59. package/dist/widget/WidgetObjectTree.d.ts.map +1 -0
  60. package/dist/widget/WidgetReplayBar.d.ts +1 -1
  61. package/dist/widget/WidgetSettings.d.ts +1 -0
  62. package/dist/widget/WidgetSettings.d.ts.map +1 -1
  63. package/dist/widget/WidgetSymbolSearch.d.ts +3 -1
  64. package/dist/widget/WidgetSymbolSearch.d.ts.map +1 -1
  65. package/dist/widget/WidgetToolbar.d.ts.map +1 -1
  66. package/dist/widget/icons.d.ts.map +1 -1
  67. package/dist/widget/index.cjs +947 -15
  68. package/dist/widget/index.cjs.map +1 -1
  69. package/dist/widget/index.js +1826 -159
  70. package/dist/widget/index.js.map +1 -1
  71. package/dist/widget/ladderRows.d.ts +21 -0
  72. package/dist/widget/ladderRows.d.ts.map +1 -0
  73. package/dist/widget/types.d.ts +72 -1
  74. package/dist/widget/types.d.ts.map +1 -1
  75. package/dist/widget/widgetConfig.d.ts.map +1 -1
  76. package/dist/widget/widgetShareState.d.ts +26 -0
  77. package/dist/widget/widgetShareState.d.ts.map +1 -0
  78. package/package.json +3 -3
  79. package/dist/DragDropImporter-6QOjnfSj.js.map +0 -1
  80. package/dist/DragDropImporter-CQ3EarQn.cjs +0 -2
  81. package/dist/DragDropImporter-CQ3EarQn.cjs.map +0 -1
@@ -1,7 +1,41 @@
1
- import { r as e, t } from "../DragDropImporter-6QOjnfSj.js";
2
- import { DARK_THEME as n, LIGHT_THEME as r } from "@tradecanvas/commons";
1
+ import { r as e, t } from "../DragDropImporter-C4x09P7e.js";
2
+ import { DARK_THEME as n, LIGHT_THEME as r, timeframeBucketStart as i, timeframeToMs as a } from "@tradecanvas/commons";
3
+ //#region src/io/resampleOHLCV.ts
4
+ function o(e, t, n = {}) {
5
+ if (e.length === 0) return [];
6
+ let r = n.weekStartsOn ?? 1, a = [], o = null, s = NaN;
7
+ for (let n of e) {
8
+ let e = i(n.time, t, r);
9
+ o === null || e !== s ? (o !== null && a.push(o), o = {
10
+ time: e,
11
+ open: n.open,
12
+ high: n.high,
13
+ low: n.low,
14
+ close: n.close,
15
+ volume: n.volume
16
+ }, s = e) : o = {
17
+ time: o.time,
18
+ open: o.open,
19
+ high: Math.max(o.high, n.high),
20
+ low: Math.min(o.low, n.low),
21
+ close: n.close,
22
+ volume: o.volume + n.volume
23
+ };
24
+ }
25
+ return o !== null && a.push(o), a;
26
+ }
27
+ function s(e) {
28
+ if (e.length < 2) return 0;
29
+ let t = [];
30
+ for (let n = 1; n < e.length; n++) {
31
+ let r = e[n].time - e[n - 1].time;
32
+ r > 0 && t.push(r);
33
+ }
34
+ return t.length === 0 ? 0 : (t.sort((e, t) => e - t), t[Math.floor(t.length / 2)]);
35
+ }
36
+ //#endregion
3
37
  //#region src/widget/widgetConfig.ts
4
- var i = [
38
+ var c = [
5
39
  {
6
40
  label: "1m",
7
41
  value: "1m"
@@ -26,7 +60,7 @@ var i = [
26
60
  label: "1D",
27
61
  value: "1d"
28
62
  }
29
- ], a = [
63
+ ], l = [
30
64
  {
31
65
  label: "Candlestick",
32
66
  value: "candlestick"
@@ -75,7 +109,7 @@ var i = [
75
109
  label: "Line + Markers",
76
110
  value: "lineWithMarkers"
77
111
  }
78
- ], o = [
112
+ ], u = [
79
113
  {
80
114
  label: "Lines",
81
115
  tools: [
@@ -188,7 +222,7 @@ var i = [
188
222
  value: "arrow"
189
223
  }]
190
224
  }
191
- ], s = [
225
+ ], d = [
192
226
  {
193
227
  id: "sma",
194
228
  name: "SMA",
@@ -204,6 +238,11 @@ var i = [
204
238
  name: "Hull MA",
205
239
  type: "overlay"
206
240
  },
241
+ {
242
+ id: "mtfma",
243
+ name: "MTF Moving Average",
244
+ type: "overlay"
245
+ },
207
246
  {
208
247
  id: "bb",
209
248
  name: "Bollinger Bands",
@@ -219,6 +258,11 @@ var i = [
219
258
  name: "Anchored VWAP",
220
259
  type: "overlay"
221
260
  },
261
+ {
262
+ id: "svwap",
263
+ name: "Session VWAP",
264
+ type: "overlay"
265
+ },
222
266
  {
223
267
  id: "ichimoku",
224
268
  name: "Ichimoku Cloud",
@@ -259,6 +303,16 @@ var i = [
259
303
  name: "Linear Regression Channel",
260
304
  type: "overlay"
261
305
  },
306
+ {
307
+ id: "chandelier",
308
+ name: "Chandelier Exit",
309
+ type: "overlay"
310
+ },
311
+ {
312
+ id: "alligator",
313
+ name: "Alligator",
314
+ type: "overlay"
315
+ },
262
316
  {
263
317
  id: "rsi",
264
318
  name: "RSI",
@@ -349,12 +403,157 @@ var i = [
349
403
  name: "Chaikin Oscillator",
350
404
  type: "panel"
351
405
  },
406
+ {
407
+ id: "voldelta",
408
+ name: "Volume Delta",
409
+ type: "panel"
410
+ },
411
+ {
412
+ id: "vortex",
413
+ name: "Vortex Indicator",
414
+ type: "panel"
415
+ },
416
+ {
417
+ id: "chop",
418
+ name: "Choppiness Index",
419
+ type: "panel"
420
+ },
421
+ {
422
+ id: "uo",
423
+ name: "Ultimate Oscillator",
424
+ type: "panel"
425
+ },
426
+ {
427
+ id: "fi",
428
+ name: "Force Index",
429
+ type: "panel"
430
+ },
431
+ {
432
+ id: "crsi",
433
+ name: "Connors RSI",
434
+ type: "panel"
435
+ },
436
+ {
437
+ id: "coppock",
438
+ name: "Coppock Curve",
439
+ type: "panel"
440
+ },
441
+ {
442
+ id: "kst",
443
+ name: "Know Sure Thing",
444
+ type: "panel"
445
+ },
446
+ {
447
+ id: "elderray",
448
+ name: "Elder Ray",
449
+ type: "panel"
450
+ },
451
+ {
452
+ id: "stc",
453
+ name: "Schaff Trend Cycle",
454
+ type: "panel"
455
+ },
456
+ {
457
+ id: "kvo",
458
+ name: "Klinger Oscillator",
459
+ type: "panel"
460
+ },
461
+ {
462
+ id: "fisher",
463
+ name: "Fisher Transform",
464
+ type: "panel"
465
+ },
466
+ {
467
+ id: "dpo",
468
+ name: "Detrended Price Osc",
469
+ type: "panel"
470
+ },
471
+ {
472
+ id: "bop",
473
+ name: "Balance of Power",
474
+ type: "panel"
475
+ },
476
+ {
477
+ id: "massindex",
478
+ name: "Mass Index",
479
+ type: "panel"
480
+ },
481
+ {
482
+ id: "cmo",
483
+ name: "Chande Momentum",
484
+ type: "panel"
485
+ },
486
+ {
487
+ id: "trix",
488
+ name: "TRIX",
489
+ type: "panel"
490
+ },
491
+ {
492
+ id: "emv",
493
+ name: "Ease of Movement",
494
+ type: "panel"
495
+ },
496
+ {
497
+ id: "pvt",
498
+ name: "Price Volume Trend",
499
+ type: "panel"
500
+ },
501
+ {
502
+ id: "wad",
503
+ name: "Williams A/D",
504
+ type: "panel"
505
+ },
506
+ {
507
+ id: "chaikinvol",
508
+ name: "Chaikin Volatility",
509
+ type: "panel"
510
+ },
511
+ {
512
+ id: "rvi",
513
+ name: "Relative Vigor Index",
514
+ type: "panel"
515
+ },
516
+ {
517
+ id: "stochrsi",
518
+ name: "Stochastic RSI",
519
+ type: "panel"
520
+ },
521
+ {
522
+ id: "ppo",
523
+ name: "Percentage Price Oscillator",
524
+ type: "panel"
525
+ },
526
+ {
527
+ id: "ac",
528
+ name: "Accelerator Oscillator",
529
+ type: "panel"
530
+ },
531
+ {
532
+ id: "rmi",
533
+ name: "Relative Momentum Index",
534
+ type: "panel"
535
+ },
536
+ {
537
+ id: "disparity",
538
+ name: "Disparity Index",
539
+ type: "panel"
540
+ },
541
+ {
542
+ id: "qstick",
543
+ name: "Qstick",
544
+ type: "panel"
545
+ },
546
+ {
547
+ id: "pgo",
548
+ name: "Pretty Good Oscillator",
549
+ type: "panel"
550
+ },
352
551
  {
353
552
  id: "volumeProfile",
354
553
  name: "Volume Profile",
355
554
  type: "panel"
356
555
  }
357
- ], c = [
556
+ ], f = [
358
557
  "sma",
359
558
  "ema",
360
559
  "bb",
@@ -365,12 +564,12 @@ var i = [
365
564
  "atr",
366
565
  "obv",
367
566
  "ichimoku"
368
- ], l = [
567
+ ], ee = [
369
568
  "BTCUSDT",
370
569
  "ETHUSDT",
371
570
  "SOLUSDT",
372
571
  "BNBUSDT"
373
- ], u = {
572
+ ], p = {
374
573
  candleUpColor: "#26A69A",
375
574
  candleDownColor: "#EF5350",
376
575
  candleUpWick: "#26A69A",
@@ -380,26 +579,41 @@ var i = [
380
579
  gridVisible: !0,
381
580
  volumeVisible: !0,
382
581
  volumeProfileVisible: !1,
582
+ marketProfileVisible: !1,
583
+ marketProfileSplit: !1,
584
+ marketProfileLetters: !1,
585
+ marketProfileBuckets: 48,
586
+ marketProfileOpacity: .32,
587
+ depthHeatmapVisible: !1,
588
+ depthHeatmapOpacity: .7,
589
+ sessionShadingVisible: !1,
590
+ pivotMarkersVisible: !1,
591
+ pivotStrength: 5,
592
+ pivotStructureLabels: !1,
593
+ periodLevelsVisible: !1,
594
+ periodLevelsPeriod: "day",
383
595
  legendVisible: !0,
384
596
  barCountdown: !0,
385
597
  logScale: !1,
598
+ scaleMode: "regular",
386
599
  autoScale: !0,
387
600
  crosshairMode: "magnet",
388
- numberLocale: "en-US"
389
- }, d = "/* === TradeCanvas Widget — Premium Styles === */\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/* === 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 6px;\n height: 40px;\n }\n .tcw-toolbar-sep {\n display: none;\n }\n .tcw-indicator-chips {\n display: none;\n }\n .tcw-sidebar {\n width: 36px;\n }\n .tcw-sidebar-btn {\n width: 28px;\n height: 28px;\n }\n .tcw-modal {\n width: 94vw;\n border-radius: var(--tcw-radius-lg);\n }\n .tcw-cmd-palette {\n width: 94vw;\n border-radius: var(--tcw-radius-lg);\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", f = 0, p = "tcw-styles";
390
- function m() {
391
- if (f++, f > 1 || document.getElementById(p)) return;
601
+ numberLocale: "en-US",
602
+ 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";
604
+ function g() {
605
+ if (m++, m > 1 || document.getElementById(h)) return;
392
606
  let e = document.createElement("style");
393
- e.id = p, e.textContent = d, document.head.appendChild(e);
607
+ e.id = h, e.textContent = te, document.head.appendChild(e);
394
608
  }
395
- function h() {
396
- if (f--, f > 0) return;
397
- let e = document.getElementById(p);
609
+ function _() {
610
+ if (m--, m > 0) return;
611
+ let e = document.getElementById(h);
398
612
  e && e.remove();
399
613
  }
400
614
  //#endregion
401
615
  //#region src/widget/icons.ts
402
- var g = {
616
+ var v = {
403
617
  cursor: "<path d=\"M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z\"/><path d=\"M13 13l6 6\"/>",
404
618
  trendingUp: "<polyline points=\"22 7 13.5 15.5 8.5 10.5 2 17\"/><polyline points=\"16 7 22 7 22 13\"/>",
405
619
  minus: "<path d=\"M5 12h14\"/>",
@@ -424,15 +638,26 @@ var g = {
424
638
  play: "<polygon points=\"6 3 20 12 6 21 6 3\"/>",
425
639
  pause: "<rect width=\"4\" height=\"16\" x=\"6\" y=\"4\"/><rect width=\"4\" height=\"16\" x=\"14\" y=\"4\"/>",
426
640
  stop: "<rect width=\"14\" height=\"14\" x=\"5\" y=\"5\" rx=\"1\"/>",
427
- receipt: "<path d=\"M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1Z\"/><path d=\"M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8\"/><path d=\"M12 17.5v-11\"/>"
641
+ receipt: "<path d=\"M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1Z\"/><path d=\"M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8\"/><path d=\"M12 17.5v-11\"/>",
642
+ bell: "<path d=\"M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9\"/><path d=\"M10.3 21a1.94 1.94 0 0 0 3.4 0\"/>",
643
+ plus: "<path d=\"M5 12h14\"/><path d=\"M12 5v14\"/>",
644
+ layers: "<path d=\"m12 2 9 5-9 5-9-5 9-5Z\"/><path d=\"m3 12 9 5 9-5\"/><path d=\"m3 17 9 5 9-5\"/>",
645
+ eye: "<path d=\"M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/>",
646
+ eyeOff: "<path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c6.5 0 10 7 10 7a13.2 13.2 0 0 1-1.67 2.68\"/><path d=\"M6.6 6.6A13.06 13.06 0 0 0 2 11s3.5 7 10 7a9.1 9.1 0 0 0 5.4-1.6\"/><path d=\"m2 2 20 20\"/>",
647
+ lock: "<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"/>",
648
+ unlock: "<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 9.9-1\"/>",
649
+ palette: "<circle cx=\"13.5\" cy=\"6.5\" r=\".5\" fill=\"currentColor\"/><circle cx=\"17.5\" cy=\"10.5\" r=\".5\" fill=\"currentColor\"/><circle cx=\"8.5\" cy=\"7.5\" r=\".5\" fill=\"currentColor\"/><circle cx=\"6.5\" cy=\"12.5\" r=\".5\" fill=\"currentColor\"/><path d=\"M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2Z\"/>",
650
+ trendingDown: "<polyline points=\"22 17 13.5 8.5 8.5 13.5 2 7\"/><polyline points=\"16 17 22 17 22 11\"/>",
651
+ check: "<polyline points=\"20 6 9 17 4 12\"/>",
652
+ ladder: "<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"21\"/><line x1=\"3\" y1=\"8\" x2=\"21\" y2=\"8\"/><line x1=\"3\" y1=\"13\" x2=\"21\" y2=\"13\"/><line x1=\"3\" y1=\"18\" x2=\"21\" y2=\"18\"/>"
428
653
  };
429
- function _(e, t = 14) {
430
- let n = g[e];
654
+ function y(e, t = 14) {
655
+ let n = v[e];
431
656
  return n ? `<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${n}</svg>` : "";
432
657
  }
433
658
  //#endregion
434
659
  //#region src/widget/WidgetDropdown.ts
435
- var v = class {
660
+ var b = class {
436
661
  trigger;
437
662
  panel;
438
663
  _isOpen = !1;
@@ -463,7 +688,7 @@ var v = class {
463
688
  destroy() {
464
689
  this.trigger.removeEventListener("click", this.onTriggerClick), document.removeEventListener("mousedown", this.onOutsideClick), document.removeEventListener("keydown", this.onEscapeKey), this.panel.remove();
465
690
  }
466
- }, y = class {
691
+ }, ne = class {
467
692
  config;
468
693
  callbacks;
469
694
  el;
@@ -488,14 +713,32 @@ var v = class {
488
713
  let a = document.createElement("div");
489
714
  a.style.position = "relative", a.style.display = "inline-flex";
490
715
  let o = document.createElement("button");
491
- o.className = "tcw-dropdown-trigger", o.dataset.role = "charttype", a.appendChild(o), n.appendChild(a), this.chartTypeDropdown = new v(a, { width: "160px" }), this.buildChartTypeMenu(), n.appendChild(this.sep());
716
+ o.className = "tcw-dropdown-trigger", o.dataset.role = "charttype", a.appendChild(o), n.appendChild(a), this.chartTypeDropdown = new b(a, { width: "160px" }), this.buildChartTypeMenu(), n.appendChild(this.sep());
492
717
  let s = document.createElement("div");
493
718
  s.style.position = "relative", s.style.display = "inline-flex";
494
719
  let c = document.createElement("button");
495
- if (c.className = "tcw-dropdown-trigger", c.dataset.role = "indicators", s.appendChild(c), n.appendChild(s), this.indicatorDropdown = new v(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) {
720
+ 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) {
496
721
  let e = this.iconBtn("play", "Bar replay", t.onToggleReplay);
497
722
  e.dataset.role = "replay", n.appendChild(e);
498
723
  }
724
+ if (t.onBracket) {
725
+ let e = t.onBracket, r = this.iconBtn("trendingUp", "Long bracket", () => e("buy"));
726
+ r.dataset.role = "long", r.classList.add("tcw-btn-long"), n.appendChild(r);
727
+ let i = this.iconBtn("trendingDown", "Short bracket", () => e("sell"));
728
+ i.dataset.role = "short", i.classList.add("tcw-btn-short"), n.appendChild(i);
729
+ }
730
+ if (t.onToggleLadder) {
731
+ let e = this.iconBtn("ladder", "Depth ladder", t.onToggleLadder);
732
+ e.dataset.role = "ladder", n.appendChild(e);
733
+ }
734
+ if (t.onToggleObjects) {
735
+ let e = this.iconBtn("layers", "Objects", t.onToggleObjects);
736
+ e.dataset.role = "objects", n.appendChild(e);
737
+ }
738
+ if (t.onToggleAlerts) {
739
+ let e = this.iconBtn("bell", "Price alerts", t.onToggleAlerts);
740
+ e.dataset.role = "alerts", n.appendChild(e);
741
+ }
499
742
  let l = this.iconBtn("camera", "Screenshot", t.onScreenshot);
500
743
  n.appendChild(l);
501
744
  let u = this.iconBtn("settings", "Chart Settings", t.onSettings);
@@ -531,11 +774,11 @@ var v = class {
531
774
  let n = this.el.querySelector("[data-role=\"charttype\"]");
532
775
  if (n) {
533
776
  let t = this.config.chartTypes.find((t) => t.value === e.chartType)?.label ?? "Candles";
534
- n.innerHTML = `${_("barChart", 14)} ${t} ${_("chevronDown", 12)}`;
777
+ n.innerHTML = `${y("barChart", 14)} ${t} ${y("chevronDown", 12)}`;
535
778
  }
536
779
  let r = this.el.querySelector("[data-role=\"indicators\"]");
537
780
  if (r) {
538
- let t = e.activeIndicators.size, n = `${_("trendingUp", 14)} Indicators`;
781
+ let t = e.activeIndicators.size, n = `${y("trendingUp", 14)} Indicators`;
539
782
  t > 0 && (n += ` <span class="tcw-badge-count">${t}</span>`), r.innerHTML = n;
540
783
  }
541
784
  if (this.chipsContainer) {
@@ -547,10 +790,10 @@ var v = class {
547
790
  let n = document.createElement("span");
548
791
  n.textContent = e.label, t.appendChild(n);
549
792
  let r = document.createElement("button");
550
- r.className = "tcw-chip-remove", r.innerHTML = _("x", 10), r.addEventListener("click", () => this.callbacks.onRemoveIndicator(e.instanceId)), t.appendChild(r), this.chipsContainer.appendChild(t);
793
+ r.className = "tcw-chip-remove", r.innerHTML = y("x", 10), r.addEventListener("click", () => this.callbacks.onRemoveIndicator(e.instanceId)), t.appendChild(r), this.chipsContainer.appendChild(t);
551
794
  }
552
795
  }
553
- this.themeBtn && (this.themeBtn.innerHTML = e.isDark ? _("moon", 14) : _("sun", 14));
796
+ this.themeBtn && (this.themeBtn.innerHTML = e.isDark ? y("moon", 14) : y("sun", 14));
554
797
  }
555
798
  getActiveIndicatorList(e) {
556
799
  let t = [];
@@ -571,12 +814,12 @@ var v = class {
571
814
  }
572
815
  iconBtn(e, t, n) {
573
816
  let r = document.createElement("button");
574
- return r.className = "tcw-btn-icon", r.title = t, r.innerHTML = _(e, 14), r.addEventListener("click", n), r;
817
+ return r.className = "tcw-btn-icon", r.title = t, r.innerHTML = y(e, 14), r.addEventListener("click", n), r;
575
818
  }
576
819
  destroy() {
577
820
  this.chartTypeDropdown?.destroy(), this.indicatorDropdown?.destroy(), this.el.remove();
578
821
  }
579
- }, b = [
822
+ }, re = [
580
823
  "trendingUp",
581
824
  "minus",
582
825
  "penLine",
@@ -585,7 +828,43 @@ var v = class {
585
828
  "gitBranch",
586
829
  "ruler",
587
830
  "type"
588
- ], x = class {
831
+ ], ie = {
832
+ trendLine: "trendingUp",
833
+ ray: "trendingUp",
834
+ extendedLine: "trendingUp",
835
+ horizontalLine: "minus",
836
+ verticalLine: "penLine",
837
+ rectangle: "square",
838
+ ellipse: "square",
839
+ triangle: "square",
840
+ arrow: "trendingUp",
841
+ parallelChannel: "gitBranch",
842
+ regressionChannel: "gitBranch",
843
+ pitchfork: "gitBranch",
844
+ fibRetracement: "hash",
845
+ fibExtension: "hash",
846
+ fibTimeZones: "hash",
847
+ gannBox: "hash",
848
+ gannFan: "gitBranch",
849
+ elliottWave: "trendingUp",
850
+ priceRange: "ruler",
851
+ dateRange: "ruler",
852
+ measure: "ruler",
853
+ textAnnotation: "type",
854
+ anchoredVWAP: "trendingUp",
855
+ volumeProfileRange: "barChart"
856
+ };
857
+ function ae(e) {
858
+ return ie[e] ?? "penLine";
859
+ }
860
+ function oe(e, t) {
861
+ for (let n of e) {
862
+ let e = n.tools.find((e) => e.value === t);
863
+ if (e) return e.label;
864
+ }
865
+ return t;
866
+ }
867
+ var x = class {
589
868
  config;
590
869
  callbacks;
591
870
  el;
@@ -594,29 +873,51 @@ var v = class {
594
873
  cursorBtn = null;
595
874
  magnetBtn = null;
596
875
  flyoutEl = null;
876
+ favoritesEl = null;
877
+ favoritesDivider = null;
878
+ favorites = [];
597
879
  constructor(e, t, n) {
598
880
  this.config = t, this.callbacks = n, this.el = document.createElement("div"), this.el.className = "tcw-sidebar", this.build(), e.appendChild(this.el);
599
881
  }
600
882
  build() {
601
883
  let { config: e, callbacks: t, el: n } = this;
602
- this.cursorBtn = document.createElement("button"), this.cursorBtn.className = "tcw-sidebar-btn", this.cursorBtn.title = "Cursor", this.cursorBtn.innerHTML = _("cursor", 14), this.cursorBtn.addEventListener("click", t.onCancelDrawing), n.appendChild(this.cursorBtn), n.appendChild(this.divider()), e.drawingToolGroups.forEach((e, r) => {
884
+ this.cursorBtn = document.createElement("button"), this.cursorBtn.className = "tcw-sidebar-btn", this.cursorBtn.title = "Cursor", this.cursorBtn.innerHTML = y("cursor", 14), this.cursorBtn.addEventListener("click", t.onCancelDrawing), n.appendChild(this.cursorBtn), n.appendChild(this.divider()), t.onToggleFavorite && (this.favorites = [...e.favorites ?? []], this.favoritesEl = document.createElement("div"), this.favoritesEl.className = "tcw-sidebar-favorites", n.appendChild(this.favoritesEl), this.favoritesDivider = this.divider(), n.appendChild(this.favoritesDivider), this.renderFavorites()), e.drawingToolGroups.forEach((e, r) => {
603
885
  let i = document.createElement("div");
604
886
  i.className = "tcw-tool-group-wrap";
605
887
  let a = document.createElement("button");
606
- if (a.className = "tcw-sidebar-btn", a.title = e.label, a.innerHTML = _(b[r] ?? "square", 14), e.tools.length > 1) {
888
+ if (a.className = "tcw-sidebar-btn", a.title = e.label, a.innerHTML = y(re[r] ?? "square", 14), e.tools.length > 1) {
607
889
  let e = document.createElement("span");
608
890
  e.className = "tcw-multi-dot", a.appendChild(e);
609
891
  }
610
892
  a.addEventListener("click", () => t.onDrawingTool(e.tools[0].value)), i.appendChild(a), i.addEventListener("mouseenter", () => this.showFlyout(r)), i.addEventListener("mouseleave", () => this.hideFlyout()), n.appendChild(i), this.groupWraps.push(i), this.groupButtons.push(a);
611
893
  });
612
894
  let r = document.createElement("div");
613
- r.className = "tcw-sidebar-spacer", n.appendChild(r), n.appendChild(this.divider()), this.magnetBtn = document.createElement("button"), this.magnetBtn.className = "tcw-sidebar-btn", this.magnetBtn.title = "Magnet", this.magnetBtn.innerHTML = _("magnet", 14), this.magnetBtn.addEventListener("click", t.onToggleMagnet), n.appendChild(this.magnetBtn);
895
+ if (r.className = "tcw-sidebar-spacer", n.appendChild(r), n.appendChild(this.divider()), t.onToggleStyle) {
896
+ let e = document.createElement("button");
897
+ e.className = "tcw-sidebar-btn", e.title = "Drawing style & templates", e.dataset.role = "style", e.innerHTML = y("palette", 14), e.addEventListener("click", t.onToggleStyle), n.appendChild(e);
898
+ }
899
+ this.magnetBtn = document.createElement("button"), this.magnetBtn.className = "tcw-sidebar-btn", this.magnetBtn.title = "Magnet", this.magnetBtn.innerHTML = y("magnet", 14), this.magnetBtn.addEventListener("click", t.onToggleMagnet), n.appendChild(this.magnetBtn);
614
900
  let i = document.createElement("button");
615
- i.className = "tcw-sidebar-btn", i.title = "Undo", i.innerHTML = _("undo", 14), i.addEventListener("click", t.onUndo), n.appendChild(i);
901
+ i.className = "tcw-sidebar-btn", i.title = "Undo", i.innerHTML = y("undo", 14), i.addEventListener("click", t.onUndo), n.appendChild(i);
616
902
  let a = document.createElement("button");
617
- a.className = "tcw-sidebar-btn", a.title = "Redo", a.innerHTML = _("redo", 14), a.addEventListener("click", t.onRedo), n.appendChild(a);
903
+ a.className = "tcw-sidebar-btn", a.title = "Redo", a.innerHTML = y("redo", 14), a.addEventListener("click", t.onRedo), n.appendChild(a);
618
904
  let o = document.createElement("button");
619
- o.className = "tcw-sidebar-btn tcw-danger", o.title = "Clear all", o.innerHTML = _("trash", 14), o.addEventListener("click", t.onClearDrawings), n.appendChild(o);
905
+ o.className = "tcw-sidebar-btn tcw-danger", o.title = "Clear all", o.innerHTML = y("trash", 14), o.addEventListener("click", t.onClearDrawings), n.appendChild(o);
906
+ }
907
+ setFavorites(e) {
908
+ this.favorites = [...e], this.renderFavorites();
909
+ }
910
+ renderFavorites() {
911
+ if (!this.favoritesEl) return;
912
+ this.favoritesEl.replaceChildren();
913
+ let e = this.favorites.length > 0;
914
+ this.favoritesEl.style.display = e ? "" : "none", this.favoritesDivider && (this.favoritesDivider.style.display = e ? "" : "none");
915
+ for (let e of this.favorites) {
916
+ let t = document.createElement("button");
917
+ t.className = "tcw-sidebar-btn", t.title = `${oe(this.config.drawingToolGroups, e)} (right-click to unpin)`, t.dataset.toolValue = e, t.innerHTML = y(ae(e), 14), t.addEventListener("click", () => this.callbacks.onDrawingTool(e)), t.addEventListener("contextmenu", (t) => {
918
+ t.preventDefault(), this.callbacks.onToggleFavorite?.(e);
919
+ }), this.favoritesEl.appendChild(t);
920
+ }
620
921
  }
621
922
  showFlyout(e) {
622
923
  let t = this.config.drawingToolGroups[e];
@@ -630,7 +931,9 @@ var v = class {
630
931
  let t = document.createElement("button");
631
932
  t.className = "tcw-flyout-item", t.textContent = e.label, t.dataset.toolValue = e.value, t.addEventListener("click", () => {
632
933
  this.callbacks.onDrawingTool(e.value), this.hideFlyout();
633
- }), n.appendChild(t);
934
+ }), this.callbacks.onToggleFavorite && (this.favorites.includes(e.value) && t.classList.add("tcw-flyout-faved"), t.title = "Right-click to pin/unpin", t.addEventListener("contextmenu", (t) => {
935
+ t.preventDefault(), this.callbacks.onToggleFavorite?.(e.value);
936
+ })), n.appendChild(t);
634
937
  }
635
938
  this.flyoutEl = n, this.groupWraps[e].appendChild(n);
636
939
  }
@@ -686,7 +989,7 @@ var v = class {
686
989
  let t = document.createElement("h3");
687
990
  t.textContent = "Chart Settings", e.appendChild(t);
688
991
  let n = document.createElement("button");
689
- n.className = "tcw-modal-close", n.innerHTML = _("x", 16), n.addEventListener("click", () => {
992
+ n.className = "tcw-modal-close", n.innerHTML = y("x", 16), n.addEventListener("click", () => {
690
993
  this.callbacks.onClose(), this.close();
691
994
  }), e.appendChild(n), this.modal.appendChild(e);
692
995
  let r = document.createElement("div");
@@ -734,7 +1037,13 @@ var v = class {
734
1037
  renderDisplayTab() {
735
1038
  if (!this.bodyEl || !this.currentSettings) return;
736
1039
  let e = this.currentSettings, t = this.section();
737
- t.appendChild(this.toggleRow("Grid Lines", e.gridVisible, (e) => this.patch({ gridVisible: e }))), t.appendChild(this.toggleRow("Volume", e.volumeVisible, (e) => this.patch({ volumeVisible: e }))), t.appendChild(this.toggleRow("Volume Profile", e.volumeProfileVisible, (e) => this.patch({ volumeProfileVisible: e }))), t.appendChild(this.toggleRow("OHLC Legend", e.legendVisible, (e) => this.patch({ legendVisible: e }))), t.appendChild(this.toggleRow("Bar Countdown", e.barCountdown, (e) => this.patch({ barCountdown: e }))), t.appendChild(this.selectRow("Crosshair Mode", e.crosshairMode, [
1040
+ t.appendChild(this.toggleRow("Grid Lines", e.gridVisible, (e) => this.patch({ gridVisible: e }))), t.appendChild(this.toggleRow("Volume", e.volumeVisible, (e) => this.patch({ volumeVisible: e }))), t.appendChild(this.toggleRow("Volume Profile", e.volumeProfileVisible, (e) => this.patch({ volumeProfileVisible: e }))), t.appendChild(this.toggleRow("Market Profile (TPO)", e.marketProfileVisible, (e) => this.patch({ marketProfileVisible: e }))), t.appendChild(this.toggleRow("MP split by session", e.marketProfileSplit, (e) => this.patch({ marketProfileSplit: e }))), t.appendChild(this.toggleRow("MP letters (TPO)", e.marketProfileLetters, (e) => this.patch({ marketProfileLetters: e }))), t.appendChild(this.rangeRow("MP buckets", e.marketProfileBuckets, 8, 200, 1, (e) => this.patch({ marketProfileBuckets: e }))), t.appendChild(this.rangeRow("MP opacity", e.marketProfileOpacity, .05, 1, .05, (e) => this.patch({ marketProfileOpacity: e }), (e) => `${Math.round(e * 100)}%`)), t.appendChild(this.toggleRow("Liquidity heatmap", e.depthHeatmapVisible, (e) => this.patch({ depthHeatmapVisible: e }))), t.appendChild(this.rangeRow("Heatmap opacity", e.depthHeatmapOpacity, .1, 1, .05, (e) => this.patch({ depthHeatmapOpacity: e }), (e) => `${Math.round(e * 100)}%`)), t.appendChild(this.toggleRow("Swing markers", e.pivotMarkersVisible, (e) => this.patch({ pivotMarkersVisible: e }))), t.appendChild(this.rangeRow("Swing strength", e.pivotStrength, 2, 20, 1, (e) => this.patch({ pivotStrength: e }))), t.appendChild(this.toggleRow("Swing structure (HH/HL)", e.pivotStructureLabels, (e) => this.patch({ pivotStructureLabels: e }))), t.appendChild(this.toggleRow("Session shading (RTH)", e.sessionShadingVisible, (e) => this.patch({ sessionShadingVisible: e }))), t.appendChild(this.toggleRow("Prior-period levels", e.periodLevelsVisible, (e) => this.patch({ periodLevelsVisible: e }))), t.appendChild(this.selectRow("Period levels basis", e.periodLevelsPeriod, [{
1041
+ value: "day",
1042
+ label: "Prior Day (PDH/PDL)"
1043
+ }, {
1044
+ value: "week",
1045
+ label: "Prior Week (PWH/PWL)"
1046
+ }], (e) => this.patch({ periodLevelsPeriod: e }))), t.appendChild(this.toggleRow("OHLC Legend", e.legendVisible, (e) => this.patch({ legendVisible: e }))), t.appendChild(this.toggleRow("Bar Countdown", e.barCountdown, (e) => this.patch({ barCountdown: e }))), t.appendChild(this.selectRow("Crosshair Mode", e.crosshairMode, [
738
1047
  {
739
1048
  label: "Magnet",
740
1049
  value: "magnet"
@@ -747,7 +1056,40 @@ var v = class {
747
1056
  label: "Hidden",
748
1057
  value: "hidden"
749
1058
  }
750
- ], (e) => this.patch({ crosshairMode: e }))), t.appendChild(this.selectRow("Number Locale", e.numberLocale, [
1059
+ ], (e) => this.patch({ crosshairMode: e }))), t.appendChild(this.selectRow("Timezone", e.timezone, [
1060
+ {
1061
+ value: "local",
1062
+ label: "Local"
1063
+ },
1064
+ {
1065
+ value: "0",
1066
+ label: "UTC / London"
1067
+ },
1068
+ {
1069
+ value: "-300",
1070
+ label: "New York (UTC-5)"
1071
+ },
1072
+ {
1073
+ value: "-360",
1074
+ label: "Chicago (UTC-6)"
1075
+ },
1076
+ {
1077
+ value: "60",
1078
+ label: "Frankfurt (UTC+1)"
1079
+ },
1080
+ {
1081
+ value: "480",
1082
+ label: "Singapore/HK (UTC+8)"
1083
+ },
1084
+ {
1085
+ value: "540",
1086
+ label: "Tokyo (UTC+9)"
1087
+ },
1088
+ {
1089
+ value: "330",
1090
+ label: "Mumbai (UTC+5:30)"
1091
+ }
1092
+ ], (e) => this.patch({ timezone: e }))), t.appendChild(this.selectRow("Number Locale", e.numberLocale, [
751
1093
  {
752
1094
  label: "en-US (65,234.00)",
753
1095
  value: "en-US"
@@ -777,7 +1119,24 @@ var v = class {
777
1119
  renderScaleTab() {
778
1120
  if (!this.bodyEl || !this.currentSettings) return;
779
1121
  let e = this.currentSettings, t = this.section();
780
- t.appendChild(this.toggleRow("Auto Scale", e.autoScale, (e) => this.patch({ autoScale: e }))), t.appendChild(this.toggleRow("Log Scale", e.logScale, (e) => this.patch({ logScale: e }))), this.bodyEl.appendChild(t);
1122
+ t.appendChild(this.toggleRow("Auto Scale", e.autoScale, (e) => this.patch({ autoScale: e }))), t.appendChild(this.selectRow("Price Scale", e.scaleMode, [
1123
+ {
1124
+ value: "regular",
1125
+ label: "Regular"
1126
+ },
1127
+ {
1128
+ value: "logarithmic",
1129
+ label: "Logarithmic"
1130
+ },
1131
+ {
1132
+ value: "percentage",
1133
+ label: "Percentage"
1134
+ },
1135
+ {
1136
+ value: "indexedTo100",
1137
+ label: "Indexed to 100"
1138
+ }
1139
+ ], (e) => this.patch({ scaleMode: e }))), this.bodyEl.appendChild(t);
781
1140
  }
782
1141
  patch(e) {
783
1142
  this.currentSettings && Object.assign(this.currentSettings, e), this.callbacks.onChange(e);
@@ -828,6 +1187,21 @@ var v = class {
828
1187
  }
829
1188
  return o.addEventListener("change", () => r(o.value)), i.appendChild(o), i;
830
1189
  }
1190
+ rangeRow(e, t, n, r, i, a, o = (e) => String(e)) {
1191
+ let s = document.createElement("div");
1192
+ s.className = "tcw-settings-row";
1193
+ let c = document.createElement("span");
1194
+ c.className = "tcw-settings-label", c.textContent = e, s.appendChild(c);
1195
+ let l = document.createElement("div");
1196
+ l.className = "tcw-settings-range";
1197
+ let u = document.createElement("input");
1198
+ u.type = "range", u.min = String(n), u.max = String(r), u.step = String(i), u.value = String(t);
1199
+ let d = document.createElement("span");
1200
+ return d.className = "tcw-settings-range-val", d.textContent = o(t), u.addEventListener("input", () => {
1201
+ let e = Number(u.value);
1202
+ d.textContent = o(e), a(e);
1203
+ }), l.appendChild(u), l.appendChild(d), s.appendChild(l), s;
1204
+ }
831
1205
  destroy() {
832
1206
  this.close();
833
1207
  }
@@ -983,26 +1357,27 @@ var v = class {
983
1357
  selectedIndex = 0;
984
1358
  callbacks;
985
1359
  boundKeydown;
1360
+ pickOverride = null;
986
1361
  constructor(e) {
987
1362
  this.callbacks = e, this.boundKeydown = this.handleKeydown.bind(this);
988
1363
  }
989
- open(e, t) {
1364
+ open(e, t, n) {
990
1365
  if (this.backdrop) return;
991
- this.symbols = e, this.current = t, this.filtered = e.map((e) => ({
1366
+ this.pickOverride = n ?? null, this.symbols = e, this.current = t, this.filtered = e.map((e) => ({
992
1367
  symbol: e,
993
1368
  score: 0
994
1369
  })), this.selectedIndex = Math.max(0, e.indexOf(t)), 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-cmd-palette";
995
- let n = document.createElement("div");
996
- n.className = "tcw-cmd-header";
997
- let r = document.createElement("span");
998
- r.className = "tcw-cmd-icon", r.innerHTML = A(), n.appendChild(r), 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()), n.appendChild(this.input);
1370
+ let r = document.createElement("div");
1371
+ r.className = "tcw-cmd-header";
999
1372
  let i = document.createElement("span");
1000
- i.className = "tcw-cmd-hint", i.textContent = "ESC", n.appendChild(i), this.modal.appendChild(n), this.list = document.createElement("div"), this.list.className = "tcw-cmd-list", this.modal.appendChild(this.list);
1001
- let a = document.createElement("div");
1002
- a.className = "tcw-cmd-footer", a.innerHTML = "<span>↑↓ Navigate</span><span>⏎ Open</span><span>Esc Close</span>", this.modal.appendChild(a), document.body.appendChild(this.backdrop), document.body.appendChild(this.modal), this.renderList(), this.input.focus(), document.addEventListener("keydown", this.boundKeydown);
1373
+ i.className = "tcw-cmd-icon", i.innerHTML = A(), 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
+ let a = document.createElement("span");
1375
+ 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
+ let o = document.createElement("div");
1377
+ o.className = "tcw-cmd-footer", o.innerHTML = "<span>↑↓ Navigate</span><span>⏎ Open</span><span>Esc Close</span>", this.modal.appendChild(o), document.body.appendChild(this.backdrop), document.body.appendChild(this.modal), this.renderList(), this.input.focus(), document.addEventListener("keydown", this.boundKeydown);
1003
1378
  }
1004
1379
  close() {
1005
- document.removeEventListener("keydown", this.boundKeydown), this.backdrop?.remove(), this.modal?.remove(), this.backdrop = null, this.modal = null, this.input = null, this.list = null, this.callbacks.onClose();
1380
+ document.removeEventListener("keydown", this.boundKeydown), this.backdrop?.remove(), this.modal?.remove(), this.backdrop = null, this.modal = null, this.input = null, this.list = null, this.pickOverride = null, this.callbacks.onClose();
1006
1381
  }
1007
1382
  isOpen() {
1008
1383
  return this.backdrop !== null;
@@ -1048,7 +1423,9 @@ var v = class {
1048
1423
  }
1049
1424
  pick(e) {
1050
1425
  let t = this.filtered[e];
1051
- t && (this.callbacks.onPick(t.symbol), this.close());
1426
+ if (!t) return;
1427
+ let n = this.pickOverride;
1428
+ n ? n(t.symbol) : this.callbacks.onPick(t.symbol), this.close();
1052
1429
  }
1053
1430
  handleKeydown(e) {
1054
1431
  switch (e.key) {
@@ -1142,6 +1519,27 @@ var j = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platfor
1142
1519
  }
1143
1520
  ]
1144
1521
  },
1522
+ {
1523
+ title: "Touch (mobile / tablet)",
1524
+ entries: [
1525
+ {
1526
+ keys: ["1 finger", "Drag"],
1527
+ label: "Pan / move crosshair"
1528
+ },
1529
+ {
1530
+ keys: ["2 fingers", "Pinch"],
1531
+ label: "Zoom around midpoint"
1532
+ },
1533
+ {
1534
+ keys: ["Long-press"],
1535
+ label: "Pin OHLC tooltip at bar"
1536
+ },
1537
+ {
1538
+ keys: ["Drag", "Axis strip"],
1539
+ label: "Scale price / time axis"
1540
+ }
1541
+ ]
1542
+ },
1145
1543
  {
1146
1544
  title: "Keyboard",
1147
1545
  entries: [
@@ -1434,94 +1832,1027 @@ function W(e, t, n) {
1434
1832
  r.stroke();
1435
1833
  }
1436
1834
  //#endregion
1437
- //#region src/widget/ChartWidget.ts
1438
- var G = class {
1439
- chart;
1440
- state;
1441
- toolbar = null;
1442
- sidebar = null;
1443
- settings = null;
1444
- statusBar = null;
1445
- commandPalette = null;
1446
- symbolSearch = null;
1447
- hotkeySheet = null;
1448
- replayBar = null;
1449
- dragDrop = null;
1450
- watchlist = null;
1451
- watchlistSparkBuffer = /* @__PURE__ */ new Map();
1452
- sessionRefPrice = null;
1453
- watchlistInterval = null;
1454
- replayOriginalData = null;
1455
- replayPollInterval = null;
1456
- replaySpeed = 5;
1457
- layoutKeyPrefix = null;
1458
- layoutDebounceMs = 1500;
1459
- activeLayoutKey = null;
1460
- root;
1461
- chartContainer;
1462
- destroyed = !1;
1463
- options;
1464
- symbols;
1465
- settingsState;
1466
- adapter = null;
1467
- boundGlobalKeydown = null;
1468
- constructor(n, r = {}) {
1469
- if (this.options = r, this.symbols = r.symbols ?? l, this.settingsState = { ...u }, r.persistLayouts) {
1470
- let e = r.persistLayouts === !0 ? {} : r.persistLayouts;
1471
- this.layoutKeyPrefix = e.keyPrefix ?? "tcw:layout:", this.layoutDebounceMs = e.debounceMs ?? 1500;
1835
+ //#region src/widget/WidgetAlertsPanel.ts
1836
+ var G = [
1837
+ {
1838
+ value: "crossing",
1839
+ label: "Crossing"
1840
+ },
1841
+ {
1842
+ value: "crossingUp",
1843
+ label: "Crossing up"
1844
+ },
1845
+ {
1846
+ value: "crossingDown",
1847
+ label: "Crossing down"
1848
+ },
1849
+ {
1850
+ value: "greaterThan",
1851
+ label: "Greater than"
1852
+ },
1853
+ {
1854
+ value: "lessThan",
1855
+ label: "Less than"
1856
+ }
1857
+ ], K = new Map(G.map((e) => [e.value, e.label]));
1858
+ function q(e) {
1859
+ return Math.round(e * 1e6) / 1e6;
1860
+ }
1861
+ function se(e) {
1862
+ let t = Math.abs(e);
1863
+ return t >= 1e3 || t >= 1 ? e.toFixed(2) : e.toPrecision(4);
1864
+ }
1865
+ var ce = class {
1866
+ el;
1867
+ listEl;
1868
+ priceInput;
1869
+ conditionSelect;
1870
+ sourceSelect;
1871
+ messageInput;
1872
+ emptyEl;
1873
+ callbacks;
1874
+ open = !1;
1875
+ alerts = [];
1876
+ sources = [{
1877
+ channel: "price",
1878
+ label: "Price"
1879
+ }];
1880
+ constructor(e, t) {
1881
+ this.callbacks = t, this.el = document.createElement("div"), this.el.className = "tcw-alerts-panel", this.el.hidden = !0;
1882
+ let n = document.createElement("div");
1883
+ n.className = "tcw-alerts-header";
1884
+ let r = document.createElement("span");
1885
+ r.textContent = "Price Alerts";
1886
+ let i = document.createElement("button");
1887
+ i.className = "tcw-alerts-close", i.type = "button", i.setAttribute("aria-label", "Close alerts"), i.innerHTML = y("x", 14), i.addEventListener("click", () => this.close()), n.appendChild(r), n.appendChild(i), this.el.appendChild(n);
1888
+ let a = document.createElement("form");
1889
+ a.className = "tcw-alerts-form", this.sourceSelect = document.createElement("select"), this.sourceSelect.className = "tcw-alerts-source", this.sourceSelect.addEventListener("change", () => this.prefillPrice()), this.priceInput = document.createElement("input"), this.priceInput.type = "number", this.priceInput.step = "any", this.priceInput.placeholder = "Value", this.priceInput.className = "tcw-alerts-price", this.priceInput.required = !0, this.conditionSelect = document.createElement("select"), this.conditionSelect.className = "tcw-alerts-condition";
1890
+ for (let e of G) {
1891
+ let t = document.createElement("option");
1892
+ t.value = e.value, t.textContent = e.label, this.conditionSelect.appendChild(t);
1472
1893
  }
1473
- let d = this.resolveIsDark(r.theme), f = this.resolveTheme(r.theme);
1474
- this.state = {
1475
- symbol: r.symbol ?? this.symbols[0] ?? "BTCUSDT",
1476
- timeframe: r.timeframe ?? "5m",
1477
- chartType: r.chartOptions?.chartType ?? "candlestick",
1478
- isDark: d,
1479
- activeIndicators: /* @__PURE__ */ new Map(),
1480
- activeTool: null,
1481
- magnetEnabled: !0,
1482
- connectionState: "connecting",
1483
- connectionMessage: "Connecting..."
1484
- }, m(), this.root = document.createElement("div"), this.root.className = "tcw-root", this.root.dataset.tcwTheme = d ? "dark" : "light", n.appendChild(this.root), r.toolbar !== !1 && (this.toolbar = new y(this.root, {
1485
- symbols: this.symbols,
1486
- timeframes: r.timeframes ? i.filter((e) => r.timeframes.includes(e.value)) : i,
1487
- chartTypes: r.chartTypes ? a.filter((e) => r.chartTypes.includes(e.value)) : a,
1488
- indicators: s,
1489
- popularIndicatorIds: c
1490
- }, {
1491
- onSymbolClick: () => this.handleSymbolClick(),
1492
- onTimeframe: (e) => this.handleTimeframe(e),
1493
- onChartType: (e) => this.handleChartType(e),
1494
- onAddIndicator: (e) => this.handleAddIndicator(e),
1495
- onRemoveIndicator: (e) => this.handleRemoveIndicator(e),
1496
- onScreenshot: () => this.chart.screenshot(),
1497
- onSettings: () => this.openSettings(),
1498
- onToggleTheme: () => this.handleToggleTheme(),
1499
- onToggleReplay: () => this.toggleReplay()
1500
- }));
1501
- let p = document.createElement("div");
1502
- p.className = "tcw-body", r.drawingTools !== !1 && (this.sidebar = new x(p, { drawingToolGroups: o }, {
1503
- onDrawingTool: (e) => this.handleDrawingTool(e),
1504
- onCancelDrawing: () => this.handleCancelDrawing(),
1505
- onToggleMagnet: () => this.handleToggleMagnet(),
1506
- onUndo: () => this.chart.undo(),
1507
- onRedo: () => this.chart.redo(),
1508
- onClearDrawings: () => {
1509
- this.chart.clearDrawings(), this.state = {
1510
- ...this.state,
1511
- activeTool: null
1512
- }, this.updateUI();
1513
- }
1514
- })), this.chartContainer = document.createElement("div"), this.chartContainer.className = "tcw-chart-container", p.appendChild(this.chartContainer), r.watchlist && (this.watchlist = new V(p, this.symbols, { onSelect: (e) => {
1515
- this.setSymbol(e);
1516
- } }), this.watchlist.setActive(this.state.symbol)), this.root.appendChild(p), this.chart = new e(this.chartContainer, {
1517
- chartType: this.state.chartType,
1518
- theme: f,
1519
- autoScale: !0,
1520
- crosshair: { mode: "magnet" },
1521
- features: {
1522
- drawings: !0,
1523
- drawingMagnet: !0,
1524
- drawingUndoRedo: !0,
1894
+ this.messageInput = document.createElement("input"), this.messageInput.type = "text", this.messageInput.placeholder = "Note (optional)", this.messageInput.className = "tcw-alerts-message";
1895
+ let o = document.createElement("button");
1896
+ o.type = "submit", o.className = "tcw-alerts-add", o.innerHTML = `${y("plus", 14)}<span>Add alert</span>`, a.appendChild(this.sourceSelect), a.appendChild(this.priceInput), a.appendChild(this.conditionSelect), a.appendChild(this.messageInput), a.appendChild(o), a.addEventListener("submit", (e) => {
1897
+ e.preventDefault(), this.submitForm();
1898
+ }), this.el.appendChild(a), this.listEl = document.createElement("div"), this.listEl.className = "tcw-alerts-list", this.el.appendChild(this.listEl), this.emptyEl = document.createElement("div"), this.emptyEl.className = "tcw-alerts-empty", this.emptyEl.textContent = "No alerts yet. Add one above, or right-click the chart.", this.listEl.appendChild(this.emptyEl), this.renderSources(), e.appendChild(this.el);
1899
+ }
1900
+ setSources(e) {
1901
+ this.sources = e.length > 0 ? e : [{
1902
+ channel: "price",
1903
+ label: "Price"
1904
+ }], this.renderSources();
1905
+ }
1906
+ renderSources() {
1907
+ let e = this.sourceSelect.value || "price";
1908
+ this.sourceSelect.replaceChildren();
1909
+ for (let e of this.sources) {
1910
+ let t = document.createElement("option");
1911
+ t.value = e.channel, t.textContent = e.label, this.sourceSelect.appendChild(t);
1912
+ }
1913
+ this.sourceSelect.value = this.sources.some((t) => t.channel === e) ? e : "price";
1914
+ }
1915
+ isOpen() {
1916
+ return this.open;
1917
+ }
1918
+ toggle() {
1919
+ this.open ? this.close() : this.openPanel();
1920
+ }
1921
+ openPanel() {
1922
+ this.open = !0, this.el.hidden = !1, this.priceInput.value === "" && this.prefillPrice();
1923
+ }
1924
+ prefillPrice() {
1925
+ let e = this.callbacks.getChannelValue(this.sourceSelect.value || "price");
1926
+ this.priceInput.value = e === null ? "" : String(q(e));
1927
+ }
1928
+ close() {
1929
+ this.open = !1, this.el.hidden = !0;
1930
+ }
1931
+ setAlerts(e) {
1932
+ this.alerts = e, this.renderList();
1933
+ }
1934
+ destroy() {
1935
+ this.el.remove();
1936
+ }
1937
+ submitForm() {
1938
+ let e = Number(this.priceInput.value);
1939
+ if (!Number.isFinite(e)) return;
1940
+ let t = this.conditionSelect.value, n = this.messageInput.value.trim() || void 0, r = this.sourceSelect.value || "price", i = this.sources.find((e) => e.channel === r)?.label ?? "Price";
1941
+ this.callbacks.onAdd(e, t, n, r, i), this.messageInput.value = "", this.prefillPrice();
1942
+ }
1943
+ renderList() {
1944
+ if (this.listEl.replaceChildren(), this.alerts.length === 0) {
1945
+ this.listEl.appendChild(this.emptyEl);
1946
+ return;
1947
+ }
1948
+ for (let e of [...this.alerts].reverse()) {
1949
+ let t = document.createElement("div");
1950
+ t.className = "tcw-alerts-row" + (e.triggered ? " tcw-alerts-triggered" : "");
1951
+ let n = document.createElement("div");
1952
+ n.className = "tcw-alerts-info";
1953
+ let r = document.createElement("div");
1954
+ r.className = "tcw-alerts-row-main";
1955
+ let i = K.get(e.condition) ?? e.condition, a = e.channel && e.channel !== "price", o = a ? se(e.price) : this.callbacks.formatPrice(e.price);
1956
+ if (r.textContent = `${a && e.label ? `${e.label} ` : ""}${i} ${o}`, n.appendChild(r), e.message) {
1957
+ let t = document.createElement("div");
1958
+ t.className = "tcw-alerts-row-note", t.textContent = e.message, n.appendChild(t);
1959
+ }
1960
+ if (e.triggered) {
1961
+ let e = document.createElement("span");
1962
+ e.className = "tcw-alerts-badge", e.textContent = "triggered", r.appendChild(e);
1963
+ }
1964
+ let s = document.createElement("button");
1965
+ 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
+ }
1967
+ }
1968
+ }, le = class {
1969
+ el;
1970
+ indicatorsEl;
1971
+ drawingsEl;
1972
+ compareEl = null;
1973
+ callbacks;
1974
+ open = !1;
1975
+ constructor(e, t) {
1976
+ this.callbacks = t, this.el = document.createElement("div"), this.el.className = "tcw-tree-panel", this.el.hidden = !0;
1977
+ let n = document.createElement("div");
1978
+ n.className = "tcw-tree-header";
1979
+ let r = document.createElement("span");
1980
+ r.textContent = "Objects";
1981
+ let i = document.createElement("button");
1982
+ i.type = "button", i.className = "tcw-tree-close", i.setAttribute("aria-label", "Close objects"), i.innerHTML = y("x", 14), i.addEventListener("click", () => this.close()), n.appendChild(r), n.appendChild(i), this.el.appendChild(n), this.indicatorsEl = this.makeSection("Indicators"), this.drawingsEl = this.makeSection("Drawings"), this.callbacks.onAddCompare && (this.compareEl = this.makeSection("Compare", () => this.callbacks.onAddCompare?.())), e.appendChild(this.el);
1983
+ }
1984
+ isOpen() {
1985
+ return this.open;
1986
+ }
1987
+ toggle() {
1988
+ this.open ? this.close() : this.openPanel();
1989
+ }
1990
+ openPanel() {
1991
+ this.open = !0, this.el.hidden = !1;
1992
+ }
1993
+ close() {
1994
+ this.open = !1, this.el.hidden = !0;
1995
+ }
1996
+ destroy() {
1997
+ this.el.remove();
1998
+ }
1999
+ setObjects(e, t, n = []) {
2000
+ this.renderIndicators(e), this.renderDrawings(t), this.renderCompares(n);
2001
+ }
2002
+ makeSection(e, t) {
2003
+ let n = document.createElement("div");
2004
+ n.className = "tcw-tree-section";
2005
+ let r = document.createElement("div");
2006
+ r.className = "tcw-tree-section-head";
2007
+ let i = document.createElement("span");
2008
+ if (i.textContent = e, r.appendChild(i), t) {
2009
+ let n = document.createElement("button");
2010
+ n.type = "button", n.className = "tcw-tree-add", n.setAttribute("aria-label", `Add ${e.toLowerCase()}`), n.title = `Add ${e.toLowerCase()}`, n.innerHTML = y("plus", 13), n.addEventListener("click", t), r.appendChild(n);
2011
+ }
2012
+ let a = document.createElement("div");
2013
+ return a.className = "tcw-tree-list", n.appendChild(r), n.appendChild(a), this.el.appendChild(n), a;
2014
+ }
2015
+ renderIndicators(e) {
2016
+ if (this.indicatorsEl.replaceChildren(), e.length === 0) {
2017
+ this.indicatorsEl.appendChild(this.emptyRow("No indicators"));
2018
+ return;
2019
+ }
2020
+ for (let t of e) {
2021
+ let e = this.row(t.name);
2022
+ t.visible || e.classList.add("tcw-tree-hidden");
2023
+ let n = document.createElement("div");
2024
+ n.className = "tcw-tree-actions", this.callbacks.onToggleIndicatorVisible && n.appendChild(this.iconButton(t.visible ? "eye" : "eyeOff", t.visible ? "Hide" : "Show", "", () => this.callbacks.onToggleIndicatorVisible?.(t.instanceId, !t.visible))), this.callbacks.onConfigureIndicator && n.appendChild(this.iconButton("settings", "Indicator settings", "", () => this.callbacks.onConfigureIndicator?.(t.instanceId))), n.appendChild(this.iconButton("trash", "Remove indicator", "tcw-tree-del", () => this.callbacks.onRemoveIndicator(t.instanceId))), e.appendChild(n), this.indicatorsEl.appendChild(e);
2025
+ }
2026
+ }
2027
+ renderDrawings(e) {
2028
+ if (this.drawingsEl.replaceChildren(), e.length === 0) {
2029
+ this.drawingsEl.appendChild(this.emptyRow("No drawings"));
2030
+ return;
2031
+ }
2032
+ for (let t of e) {
2033
+ let e = this.row(t.label);
2034
+ t.visible || e.classList.add("tcw-tree-hidden");
2035
+ let n = document.createElement("div");
2036
+ n.className = "tcw-tree-actions", n.appendChild(this.iconButton(t.visible ? "eye" : "eyeOff", t.visible ? "Hide" : "Show", "", () => this.callbacks.onToggleDrawingVisible(t.id, !t.visible))), n.appendChild(this.iconButton(t.locked ? "lock" : "unlock", t.locked ? "Unlock" : "Lock", t.locked ? "tcw-tree-on" : "", () => this.callbacks.onToggleDrawingLocked(t.id, !t.locked))), n.appendChild(this.iconButton("trash", "Remove drawing", "tcw-tree-del", () => this.callbacks.onRemoveDrawing(t.id))), e.appendChild(n), this.drawingsEl.appendChild(e);
2037
+ }
2038
+ }
2039
+ renderCompares(e) {
2040
+ if (this.compareEl) {
2041
+ if (this.compareEl.replaceChildren(), e.length === 0) {
2042
+ this.compareEl.appendChild(this.emptyRow("No comparisons"));
2043
+ return;
2044
+ }
2045
+ for (let t of e) {
2046
+ let e = this.row(t.label), n = document.createElement("span");
2047
+ n.className = "tcw-tree-dot", n.style.background = t.color, e.insertBefore(n, e.firstChild), this.callbacks.onRemoveCompare && e.appendChild(this.iconButton("trash", "Remove comparison", "tcw-tree-del", () => this.callbacks.onRemoveCompare?.(t.id))), this.compareEl.appendChild(e);
2048
+ }
2049
+ }
2050
+ }
2051
+ row(e) {
2052
+ let t = document.createElement("div");
2053
+ t.className = "tcw-tree-row";
2054
+ let n = document.createElement("span");
2055
+ return n.className = "tcw-tree-name", n.textContent = e, n.title = e, t.appendChild(n), t;
2056
+ }
2057
+ emptyRow(e) {
2058
+ let t = document.createElement("div");
2059
+ return t.className = "tcw-tree-empty", t.textContent = e, t;
2060
+ }
2061
+ iconButton(e, t, n, r) {
2062
+ let i = document.createElement("button");
2063
+ 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
+ }
2065
+ }, ue = {
2066
+ trendLine: "Trend Line",
2067
+ ray: "Ray",
2068
+ extendedLine: "Extended Line",
2069
+ horizontalLine: "Horizontal Line",
2070
+ verticalLine: "Vertical Line",
2071
+ rectangle: "Rectangle",
2072
+ ellipse: "Ellipse",
2073
+ triangle: "Triangle",
2074
+ arrow: "Arrow",
2075
+ parallelChannel: "Parallel Channel",
2076
+ regressionChannel: "Regression Channel",
2077
+ pitchfork: "Pitchfork",
2078
+ fibRetracement: "Fib Retracement",
2079
+ fibExtension: "Fib Extension",
2080
+ fibTimeZones: "Fib Time Zones",
2081
+ gannBox: "Gann Box",
2082
+ gannFan: "Gann Fan",
2083
+ elliottWave: "Elliott Wave",
2084
+ priceRange: "Price Range",
2085
+ dateRange: "Date Range",
2086
+ measure: "Measure",
2087
+ textAnnotation: "Text",
2088
+ anchoredVWAP: "Anchored VWAP",
2089
+ volumeProfileRange: "Volume Profile"
2090
+ };
2091
+ function de(e) {
2092
+ return ue[e] ?? e;
2093
+ }
2094
+ //#endregion
2095
+ //#region src/widget/WidgetIndicatorSettings.ts
2096
+ var fe = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
2097
+ function pe(e) {
2098
+ return e.replace(/_/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (e) => e.toUpperCase());
2099
+ }
2100
+ var me = class {
2101
+ backdrop;
2102
+ modal;
2103
+ bodyEl;
2104
+ titleEl;
2105
+ callbacks;
2106
+ target = null;
2107
+ draft = {};
2108
+ constructor(e, t) {
2109
+ this.callbacks = t, this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.hidden = !0, this.backdrop.addEventListener("click", (e) => {
2110
+ e.target === this.backdrop && this.close();
2111
+ }), this.modal = document.createElement("div"), this.modal.className = "tcw-modal tcw-modal-narrow";
2112
+ let n = document.createElement("div");
2113
+ n.className = "tcw-modal-header", this.titleEl = document.createElement("h3"), this.titleEl.textContent = "Indicator";
2114
+ let r = document.createElement("button");
2115
+ r.className = "tcw-modal-close", r.setAttribute("aria-label", "Close"), r.innerHTML = y("x", 16), r.addEventListener("click", () => this.close()), n.appendChild(this.titleEl), n.appendChild(r), this.bodyEl = document.createElement("div"), this.bodyEl.className = "tcw-modal-body";
2116
+ let i = document.createElement("div");
2117
+ i.className = "tcw-modal-footer";
2118
+ let a = document.createElement("button");
2119
+ a.className = "tcw-reset-link", a.textContent = "Reset to defaults", a.addEventListener("click", () => this.resetDefaults());
2120
+ let o = document.createElement("button");
2121
+ o.className = "tcw-done-btn", o.textContent = "Done", o.addEventListener("click", () => this.close()), i.appendChild(a), i.appendChild(o), this.modal.appendChild(n), this.modal.appendChild(this.bodyEl), this.modal.appendChild(i), this.backdrop.appendChild(this.modal), e.appendChild(this.backdrop);
2122
+ }
2123
+ open(e) {
2124
+ this.target = e, this.titleEl.textContent = `${e.name} settings`, this.draft = {}, this.renderFields(), this.backdrop.hidden = !1;
2125
+ }
2126
+ close() {
2127
+ this.backdrop.hidden = !0, this.target = null, this.callbacks.onClose();
2128
+ }
2129
+ isOpen() {
2130
+ return !this.backdrop.hidden;
2131
+ }
2132
+ destroy() {
2133
+ this.backdrop.remove();
2134
+ }
2135
+ currentValue(e) {
2136
+ if (e in this.draft) return this.draft[e];
2137
+ let t = this.target?.params[e], n = this.target?.defaults[e];
2138
+ return t ?? n;
2139
+ }
2140
+ setValue(e, t) {
2141
+ this.target && (this.draft[e] = t, this.callbacks.onApply(this.target.instanceId, { ...this.draft }));
2142
+ }
2143
+ resetDefaults() {
2144
+ if (!this.target) return;
2145
+ let e = {};
2146
+ for (let [t, n] of Object.entries(this.target.defaults)) e[t] = n;
2147
+ this.draft = e, this.callbacks.onApply(this.target.instanceId, { ...e }), this.renderFields();
2148
+ }
2149
+ renderFields() {
2150
+ if (this.bodyEl.replaceChildren(), !this.target) return;
2151
+ let e = document.createElement("div");
2152
+ e.className = "tcw-settings-section";
2153
+ let t = Object.keys(this.target.defaults);
2154
+ if (t.length === 0) {
2155
+ let t = document.createElement("div");
2156
+ t.className = "tcw-settings-label", t.textContent = "This indicator has no adjustable parameters.", e.appendChild(t);
2157
+ }
2158
+ for (let n of t) e.appendChild(this.fieldRow(n));
2159
+ this.bodyEl.appendChild(e);
2160
+ }
2161
+ fieldRow(e) {
2162
+ let t = document.createElement("div");
2163
+ t.className = "tcw-settings-row";
2164
+ let n = document.createElement("span");
2165
+ n.className = "tcw-settings-label", n.textContent = pe(e), t.appendChild(n);
2166
+ 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" && fe.test(r) ? t.appendChild(this.colorControl(e, r)) : t.appendChild(this.textControl(e, String(r ?? ""))), t;
2168
+ }
2169
+ toggleControl(e, t) {
2170
+ let n = document.createElement("button");
2171
+ return n.className = `tcw-toggle${t ? " tcw-on" : ""}`, n.type = "button", n.addEventListener("click", () => {
2172
+ let t = !n.classList.contains("tcw-on");
2173
+ n.classList.toggle("tcw-on", t), this.setValue(e, t);
2174
+ }), n;
2175
+ }
2176
+ numberControl(e, t) {
2177
+ let n = document.createElement("input");
2178
+ return n.type = "number", n.className = "tcw-indi-input", n.value = String(t), n.step = Number.isInteger(t) ? "1" : "0.1", n.addEventListener("change", () => {
2179
+ let t = Number(n.value);
2180
+ Number.isFinite(t) && this.setValue(e, t);
2181
+ }), n;
2182
+ }
2183
+ colorControl(e, t) {
2184
+ let n = document.createElement("input");
2185
+ return n.type = "color", n.className = "tcw-indi-color", n.value = t.length === 4 ? he(t) : t, n.addEventListener("input", () => this.setValue(e, n.value)), n;
2186
+ }
2187
+ textControl(e, t) {
2188
+ let n = document.createElement("input");
2189
+ return n.type = "text", n.className = "tcw-indi-input", n.value = t, n.addEventListener("change", () => this.setValue(e, n.value)), n;
2190
+ }
2191
+ };
2192
+ function he(e) {
2193
+ let t = e[1], n = e[2], r = e[3];
2194
+ return `#${t}${t}${n}${n}${r}${r}`;
2195
+ }
2196
+ //#endregion
2197
+ //#region src/widget/DrawingTemplateStore.ts
2198
+ function ge() {
2199
+ try {
2200
+ return typeof localStorage < "u" ? localStorage : null;
2201
+ } catch {
2202
+ return null;
2203
+ }
2204
+ }
2205
+ var _e = [
2206
+ "color",
2207
+ "lineWidth",
2208
+ "lineStyle",
2209
+ "fillColor",
2210
+ "fillOpacity",
2211
+ "fontSize"
2212
+ ];
2213
+ function J(e) {
2214
+ if (!e || typeof e != "object") return {};
2215
+ let t = {}, n = e;
2216
+ for (let e of _e) n[e] !== void 0 && (t[e] = n[e]);
2217
+ return t;
2218
+ }
2219
+ var ve = class {
2220
+ templates = [];
2221
+ constructor(e = "tcw:draw-templates", t = ge()) {
2222
+ this.storageKey = e, this.storage = t, this.load();
2223
+ }
2224
+ list() {
2225
+ return this.templates.map((e) => ({
2226
+ name: e.name,
2227
+ style: { ...e.style }
2228
+ }));
2229
+ }
2230
+ get(e) {
2231
+ let t = this.templates.find((t) => t.name === e);
2232
+ return t ? {
2233
+ name: t.name,
2234
+ style: { ...t.style }
2235
+ } : null;
2236
+ }
2237
+ save(e, t) {
2238
+ let n = e.trim();
2239
+ if (!n) return;
2240
+ let r = J(t);
2241
+ this.templates = this.templates.filter((e) => e.name !== n), this.templates.push({
2242
+ name: n,
2243
+ style: r
2244
+ }), this.persist();
2245
+ }
2246
+ remove(e) {
2247
+ let t = this.templates.filter((t) => t.name !== e);
2248
+ t.length !== this.templates.length && (this.templates = t, this.persist());
2249
+ }
2250
+ clear() {
2251
+ this.templates = [], this.persist();
2252
+ }
2253
+ load() {
2254
+ if (this.storage) try {
2255
+ let e = this.storage.getItem(this.storageKey);
2256
+ if (!e) return;
2257
+ let t = JSON.parse(e);
2258
+ if (!Array.isArray(t)) return;
2259
+ this.templates = t.filter((e) => e && typeof e.name == "string").map((e) => ({
2260
+ name: e.name,
2261
+ style: J(e.style)
2262
+ }));
2263
+ } catch {}
2264
+ }
2265
+ persist() {
2266
+ if (this.storage) try {
2267
+ this.storage.setItem(this.storageKey, JSON.stringify(this.templates));
2268
+ } catch {}
2269
+ }
2270
+ }, ye = [
2271
+ "#2962ff",
2272
+ "#089981",
2273
+ "#f23645",
2274
+ "#ff9800",
2275
+ "#ab47bc",
2276
+ "#26c6da",
2277
+ "#ffffff",
2278
+ "#787b86"
2279
+ ], be = [
2280
+ 1,
2281
+ 2,
2282
+ 3,
2283
+ 4
2284
+ ], xe = [
2285
+ "solid",
2286
+ "dashed",
2287
+ "dotted"
2288
+ ], Se = class {
2289
+ el;
2290
+ templatesEl;
2291
+ nameInput;
2292
+ callbacks;
2293
+ store;
2294
+ open = !1;
2295
+ constructor(e, t, n) {
2296
+ this.callbacks = t, this.store = n, this.el = document.createElement("div"), this.el.className = "tcw-style-panel", this.el.hidden = !0;
2297
+ let r = document.createElement("div");
2298
+ r.className = "tcw-style-header";
2299
+ let i = document.createElement("span");
2300
+ i.textContent = "Drawing Style";
2301
+ let a = document.createElement("button");
2302
+ a.type = "button", a.className = "tcw-style-close", a.setAttribute("aria-label", "Close"), a.innerHTML = y("x", 14), a.addEventListener("click", () => this.close()), r.appendChild(i), r.appendChild(a), this.el.appendChild(r), this.el.appendChild(this.colorRow()), this.el.appendChild(this.widthRow()), this.el.appendChild(this.lineStyleRow());
2303
+ let o = document.createElement("div");
2304
+ o.className = "tcw-style-subhead", o.textContent = "Templates", this.el.appendChild(o);
2305
+ let s = document.createElement("div");
2306
+ s.className = "tcw-style-save", this.nameInput = document.createElement("input"), this.nameInput.type = "text", this.nameInput.placeholder = "Template name", this.nameInput.className = "tcw-style-name";
2307
+ let c = document.createElement("button");
2308
+ c.type = "button", c.className = "tcw-style-savebtn", c.innerHTML = `${y("plus", 13)}<span>Save</span>`, c.addEventListener("click", () => this.saveTemplate()), s.appendChild(this.nameInput), s.appendChild(c), this.el.appendChild(s), this.templatesEl = document.createElement("div"), this.templatesEl.className = "tcw-style-templates", this.el.appendChild(this.templatesEl), e.appendChild(this.el), this.renderTemplates();
2309
+ }
2310
+ isOpen() {
2311
+ return this.open;
2312
+ }
2313
+ toggle() {
2314
+ this.open ? this.close() : this.openPanel();
2315
+ }
2316
+ openPanel() {
2317
+ this.open = !0, this.el.hidden = !1, this.syncActiveControls(), this.renderTemplates();
2318
+ }
2319
+ close() {
2320
+ this.open = !1, this.el.hidden = !0;
2321
+ }
2322
+ destroy() {
2323
+ this.el.remove();
2324
+ }
2325
+ colorRow() {
2326
+ let e = document.createElement("div");
2327
+ e.className = "tcw-style-row tcw-style-colors";
2328
+ for (let t of ye) {
2329
+ let n = document.createElement("button");
2330
+ 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
+ }
2332
+ let t = document.createElement("input");
2333
+ return t.type = "color", t.className = "tcw-style-picker", t.addEventListener("input", () => this.applyStyle({ color: t.value })), e.appendChild(t), e;
2334
+ }
2335
+ widthRow() {
2336
+ let e = document.createElement("div");
2337
+ e.className = "tcw-style-row tcw-style-widths";
2338
+ for (let t of be) {
2339
+ let n = document.createElement("button");
2340
+ n.type = "button", n.className = "tcw-style-width", n.dataset.width = String(t);
2341
+ let r = document.createElement("span");
2342
+ r.style.height = `${t}px`, n.appendChild(r), n.addEventListener("click", () => this.applyStyle({ lineWidth: t })), e.appendChild(n);
2343
+ }
2344
+ return e;
2345
+ }
2346
+ lineStyleRow() {
2347
+ let e = document.createElement("div");
2348
+ e.className = "tcw-style-row tcw-style-dashes";
2349
+ for (let t of xe) {
2350
+ let n = document.createElement("button");
2351
+ 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
+ }
2353
+ return e;
2354
+ }
2355
+ applyStyle(e) {
2356
+ this.callbacks.onStyleChange(e), this.syncActiveControls();
2357
+ }
2358
+ syncActiveControls() {
2359
+ let e = this.callbacks.getStyle();
2360
+ this.el.querySelectorAll(".tcw-style-swatch").forEach((t) => {
2361
+ t.classList.toggle("tcw-on", t.dataset.color?.toLowerCase() === e.color?.toLowerCase());
2362
+ }), this.el.querySelectorAll(".tcw-style-width").forEach((t) => {
2363
+ t.classList.toggle("tcw-on", Number(t.dataset.width) === e.lineWidth);
2364
+ }), this.el.querySelectorAll(".tcw-style-dash").forEach((t) => {
2365
+ t.classList.toggle("tcw-on", t.dataset.linestyle === e.lineStyle);
2366
+ });
2367
+ }
2368
+ saveTemplate() {
2369
+ let e = this.nameInput.value.trim();
2370
+ e && (this.store.save(e, this.callbacks.getStyle()), this.nameInput.value = "", this.renderTemplates());
2371
+ }
2372
+ renderTemplates() {
2373
+ this.templatesEl.replaceChildren();
2374
+ let e = this.store.list();
2375
+ if (e.length === 0) {
2376
+ let e = document.createElement("div");
2377
+ e.className = "tcw-style-empty", e.textContent = "No saved templates", this.templatesEl.appendChild(e);
2378
+ return;
2379
+ }
2380
+ for (let t of e) {
2381
+ let e = document.createElement("div");
2382
+ e.className = "tcw-style-template";
2383
+ let n = document.createElement("button");
2384
+ n.type = "button", n.className = "tcw-style-apply";
2385
+ let r = document.createElement("span");
2386
+ r.className = "tcw-style-tdot", r.style.background = t.style.color ?? "var(--tcw-text-muted)";
2387
+ let i = document.createElement("span");
2388
+ i.textContent = t.name, n.appendChild(r), n.appendChild(i), n.addEventListener("click", () => {
2389
+ this.callbacks.onStyleChange({ ...t.style }), this.syncActiveControls();
2390
+ });
2391
+ let a = document.createElement("button");
2392
+ a.type = "button", a.className = "tcw-style-tdel", a.setAttribute("aria-label", "Delete template"), a.innerHTML = y("trash", 13), a.addEventListener("click", () => {
2393
+ this.store.remove(t.name), this.renderTemplates();
2394
+ }), e.appendChild(n), e.appendChild(a), this.templatesEl.appendChild(e);
2395
+ }
2396
+ }
2397
+ };
2398
+ //#endregion
2399
+ //#region src/widget/DrawingFavoritesStore.ts
2400
+ function Ce() {
2401
+ try {
2402
+ return typeof localStorage < "u" ? localStorage : null;
2403
+ } catch {
2404
+ return null;
2405
+ }
2406
+ }
2407
+ var we = class {
2408
+ favorites = [];
2409
+ constructor(e = "tcw:draw-favorites", t = Ce()) {
2410
+ this.storageKey = e, this.storage = t, this.load();
2411
+ }
2412
+ list() {
2413
+ return [...this.favorites];
2414
+ }
2415
+ has(e) {
2416
+ return this.favorites.includes(e);
2417
+ }
2418
+ add(e) {
2419
+ !e || this.favorites.includes(e) || (this.favorites = [...this.favorites, e], this.persist());
2420
+ }
2421
+ remove(e) {
2422
+ this.favorites.includes(e) && (this.favorites = this.favorites.filter((t) => t !== e), this.persist());
2423
+ }
2424
+ toggle(e) {
2425
+ return this.has(e) ? (this.remove(e), !1) : (this.add(e), !0);
2426
+ }
2427
+ seedDefaults(e) {
2428
+ this.favorites.length > 0 || (this.favorites = [...new Set(e.filter(Boolean))], this.persist());
2429
+ }
2430
+ load() {
2431
+ if (this.storage) try {
2432
+ let e = this.storage.getItem(this.storageKey);
2433
+ if (!e) return;
2434
+ let t = JSON.parse(e);
2435
+ Array.isArray(t) && (this.favorites = [...new Set(t.filter((e) => typeof e == "string"))]);
2436
+ } catch {}
2437
+ }
2438
+ persist() {
2439
+ if (this.storage) try {
2440
+ this.storage.setItem(this.storageKey, JSON.stringify(this.favorites));
2441
+ } catch {}
2442
+ }
2443
+ }, Te = class {
2444
+ el;
2445
+ labelEl;
2446
+ callbacks;
2447
+ visible = !1;
2448
+ constructor(e, t) {
2449
+ this.callbacks = t, this.el = document.createElement("div"), this.el.className = "tcw-bracket-bar", this.el.hidden = !0, this.labelEl = document.createElement("span"), this.labelEl.className = "tcw-bracket-label", this.el.appendChild(this.labelEl);
2450
+ let n = document.createElement("span");
2451
+ n.className = "tcw-bracket-hint", n.textContent = "drag lines to adjust", this.el.appendChild(n);
2452
+ let r = document.createElement("button");
2453
+ r.type = "button", r.className = "tcw-bracket-cancel", r.innerHTML = `${y("x", 14)}<span>Cancel</span>`, r.addEventListener("click", () => this.callbacks.onCancel());
2454
+ let i = document.createElement("button");
2455
+ i.type = "button", i.className = "tcw-bracket-confirm", i.innerHTML = `${y("check", 14)}<span>Place</span>`, i.addEventListener("click", () => this.callbacks.onConfirm()), this.el.appendChild(r), this.el.appendChild(i), e.appendChild(this.el);
2456
+ }
2457
+ show(e) {
2458
+ this.visible = !0, this.labelEl.textContent = e === "buy" ? "Long bracket" : "Short bracket", this.labelEl.dataset.side = e, this.el.hidden = !1;
2459
+ }
2460
+ hide() {
2461
+ this.visible = !1, this.el.hidden = !0;
2462
+ }
2463
+ isVisible() {
2464
+ return this.visible;
2465
+ }
2466
+ destroy() {
2467
+ this.el.remove();
2468
+ }
2469
+ }, Ee = class {
2470
+ options;
2471
+ audioCtx = null;
2472
+ audioEl = null;
2473
+ permissionAsked = !1;
2474
+ constructor(e = {}) {
2475
+ if (this.options = e, typeof e.sound == "string") try {
2476
+ this.audioEl = new Audio(e.sound), this.audioEl.preload = "auto";
2477
+ } catch {
2478
+ this.audioEl = null;
2479
+ }
2480
+ e.desktop && this.ensurePermission();
2481
+ }
2482
+ setOptions(e) {
2483
+ this.options = {
2484
+ ...this.options,
2485
+ ...e
2486
+ };
2487
+ }
2488
+ notify(e) {
2489
+ this.options.sound && this.playSound(), this.options.desktop && this.showDesktop(e);
2490
+ }
2491
+ playSound() {
2492
+ if (this.audioEl) {
2493
+ this.audioEl.currentTime = 0, this.audioEl.play().catch(() => {});
2494
+ return;
2495
+ }
2496
+ this.beep();
2497
+ }
2498
+ beep() {
2499
+ try {
2500
+ let e = window.AudioContext ?? window.webkitAudioContext;
2501
+ if (!e) return;
2502
+ this.audioCtx ||= new e();
2503
+ let t = this.audioCtx, n = t.currentTime, r = t.createGain();
2504
+ r.gain.setValueAtTime(1e-4, n), r.gain.exponentialRampToValueAtTime(.2, n + .01), r.gain.exponentialRampToValueAtTime(1e-4, n + .35), r.connect(t.destination);
2505
+ let i = t.createOscillator();
2506
+ i.type = "sine", i.frequency.setValueAtTime(880, n), i.frequency.setValueAtTime(1320, n + .16), i.connect(r), i.start(n), i.stop(n + .36);
2507
+ } catch {}
2508
+ }
2509
+ ensurePermission() {
2510
+ this.permissionAsked || (this.permissionAsked = !0, !(typeof Notification > "u") && Notification.permission === "default" && Notification.requestPermission().catch(() => {}));
2511
+ }
2512
+ showDesktop(e) {
2513
+ if (!(typeof Notification > "u")) {
2514
+ if (Notification.permission !== "granted") {
2515
+ this.ensurePermission();
2516
+ return;
2517
+ }
2518
+ try {
2519
+ new Notification(this.options.title ?? "Price alert", { body: e });
2520
+ } catch {}
2521
+ }
2522
+ }
2523
+ destroy() {
2524
+ try {
2525
+ this.audioCtx?.close();
2526
+ } catch {}
2527
+ this.audioCtx = null, this.audioEl = null;
2528
+ }
2529
+ };
2530
+ //#endregion
2531
+ //#region src/widget/ladderRows.ts
2532
+ function De(e, t = 12) {
2533
+ 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
+ let t = s.get(e);
2535
+ return t || (t = {
2536
+ price: e,
2537
+ bidVolume: 0,
2538
+ askVolume: 0
2539
+ }, s.set(e, t)), t;
2540
+ };
2541
+ for (let e of n) c(e.price).askVolume += e.volume;
2542
+ for (let e of r) c(e.price).bidVolume += e.volume;
2543
+ let l = [...s.values()].sort((e, t) => t.price - e.price), u = 0;
2544
+ for (let e of l) u = Math.max(u, e.bidVolume, e.askVolume);
2545
+ return {
2546
+ rows: l,
2547
+ maxVolume: u,
2548
+ mid: o
2549
+ };
2550
+ }
2551
+ //#endregion
2552
+ //#region src/widget/WidgetDepthLadder.ts
2553
+ var Oe = class {
2554
+ el;
2555
+ bodyEl;
2556
+ callbacks;
2557
+ open = !1;
2558
+ levels;
2559
+ constructor(e, t, n = 12) {
2560
+ this.callbacks = t, this.levels = n, this.el = document.createElement("div"), this.el.className = "tcw-ladder", this.el.hidden = !0;
2561
+ let r = document.createElement("div");
2562
+ r.className = "tcw-ladder-header";
2563
+ let i = document.createElement("span");
2564
+ i.textContent = "Depth Ladder";
2565
+ let a = document.createElement("button");
2566
+ a.type = "button", a.className = "tcw-ladder-close", a.setAttribute("aria-label", "Close"), a.innerHTML = y("x", 14), a.addEventListener("click", () => this.close()), r.appendChild(i), r.appendChild(a), this.el.appendChild(r);
2567
+ let o = document.createElement("div");
2568
+ o.className = "tcw-ladder-cols", o.innerHTML = "<span>Bid</span><span>Price</span><span>Ask</span>", this.el.appendChild(o), this.bodyEl = document.createElement("div"), this.bodyEl.className = "tcw-ladder-body", this.el.appendChild(this.bodyEl), e.appendChild(this.el);
2569
+ }
2570
+ isOpen() {
2571
+ return this.open;
2572
+ }
2573
+ toggle() {
2574
+ this.open ? this.close() : this.openPanel();
2575
+ }
2576
+ openPanel() {
2577
+ this.open = !0, this.el.hidden = !1;
2578
+ }
2579
+ close() {
2580
+ this.open = !1, this.el.hidden = !0;
2581
+ }
2582
+ setData(e) {
2583
+ if (!e) {
2584
+ this.renderEmpty();
2585
+ return;
2586
+ }
2587
+ this.render(De(e, this.levels));
2588
+ }
2589
+ destroy() {
2590
+ this.el.remove();
2591
+ }
2592
+ renderEmpty() {
2593
+ this.bodyEl.replaceChildren();
2594
+ let e = document.createElement("div");
2595
+ e.className = "tcw-ladder-empty", e.textContent = "No order-book data", this.bodyEl.appendChild(e);
2596
+ }
2597
+ render(e) {
2598
+ if (this.bodyEl.replaceChildren(), e.rows.length === 0) {
2599
+ this.renderEmpty();
2600
+ return;
2601
+ }
2602
+ let t = e.maxVolume > 0 ? 1 / e.maxVolume : 0;
2603
+ for (let n of e.rows) {
2604
+ let e = n.askVolume > 0, r = document.createElement("div");
2605
+ r.className = "tcw-ladder-row";
2606
+ let i = document.createElement("button");
2607
+ i.type = "button", i.className = "tcw-ladder-cell tcw-ladder-bid", n.bidVolume > 0 ? (i.textContent = Y(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
+ let a = document.createElement("div");
2609
+ a.className = `tcw-ladder-price ${e ? "tcw-ask" : "tcw-bid"}`, a.textContent = this.callbacks.formatPrice(n.price);
2610
+ let o = document.createElement("button");
2611
+ o.type = "button", o.className = "tcw-ladder-cell tcw-ladder-ask", n.askVolume > 0 ? (o.textContent = Y(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
+ }
2613
+ }
2614
+ };
2615
+ function Y(e) {
2616
+ return e >= 1e3 ? (e / 1e3).toFixed(1) + "k" : e >= 1 ? e.toFixed(2).replace(/\.00$/, "") : e.toPrecision(2);
2617
+ }
2618
+ //#endregion
2619
+ //#region src/widget/WidgetDataWindow.ts
2620
+ var ke = class {
2621
+ el;
2622
+ bodyEl;
2623
+ callbacks;
2624
+ open = !1;
2625
+ constructor(e, t) {
2626
+ this.callbacks = t, this.el = document.createElement("div"), this.el.className = "tcw-datawin", this.el.hidden = !0;
2627
+ let n = document.createElement("div");
2628
+ n.className = "tcw-datawin-header";
2629
+ let r = document.createElement("span");
2630
+ r.textContent = "Data Window";
2631
+ let i = document.createElement("button");
2632
+ i.type = "button", i.className = "tcw-datawin-close", i.setAttribute("aria-label", "Close"), i.innerHTML = y("x", 14), i.addEventListener("click", () => this.close()), n.appendChild(r), n.appendChild(i), this.el.appendChild(n), this.bodyEl = document.createElement("div"), this.bodyEl.className = "tcw-datawin-body", this.el.appendChild(this.bodyEl), e.appendChild(this.el);
2633
+ }
2634
+ isOpen() {
2635
+ return this.open;
2636
+ }
2637
+ toggle() {
2638
+ this.open ? this.close() : this.openPanel();
2639
+ }
2640
+ openPanel() {
2641
+ this.open = !0, this.el.hidden = !1;
2642
+ }
2643
+ close() {
2644
+ this.open = !1, this.el.hidden = !0;
2645
+ }
2646
+ destroy() {
2647
+ this.el.remove();
2648
+ }
2649
+ render(e) {
2650
+ if (!this.open) return;
2651
+ if (this.bodyEl.replaceChildren(), !e.ohlc) {
2652
+ let e = document.createElement("div");
2653
+ e.className = "tcw-datawin-empty", e.textContent = "Hover the chart", this.bodyEl.appendChild(e);
2654
+ return;
2655
+ }
2656
+ let t = this.callbacks.formatPrice, n = e.ohlc;
2657
+ 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
+ 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", X(n.volume)));
2660
+ for (let t of e.indicators) {
2661
+ let e = document.createElement("div");
2662
+ 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, Ae(e.value)));
2664
+ }
2665
+ }
2666
+ row(e, t, n = "") {
2667
+ let r = document.createElement("div");
2668
+ r.className = "tcw-datawin-row";
2669
+ let i = document.createElement("span");
2670
+ i.className = "tcw-datawin-label", i.textContent = e;
2671
+ let a = document.createElement("span");
2672
+ return a.className = `tcw-datawin-value${n ? ` tcw-${n}` : ""}`, a.textContent = t, r.appendChild(i), r.appendChild(a), r;
2673
+ }
2674
+ };
2675
+ function Ae(e) {
2676
+ if (!Number.isFinite(e)) return "—";
2677
+ let t = Math.abs(e);
2678
+ return t >= 1e3 ? e.toFixed(2) : t >= 1 ? e.toFixed(4) : e.toPrecision(4);
2679
+ }
2680
+ function X(e) {
2681
+ 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
+ }
2683
+ //#endregion
2684
+ //#region src/widget/widgetShareState.ts
2685
+ var Z = globalThis.Buffer;
2686
+ function je(e) {
2687
+ if (Z) return Z.from(e, "utf8").toString("base64");
2688
+ let t = new TextEncoder().encode(e), n = "";
2689
+ for (let e of t) n += String.fromCharCode(e);
2690
+ return btoa(n);
2691
+ }
2692
+ function Me(e) {
2693
+ if (Z) return Z.from(e, "base64").toString("utf8");
2694
+ let t = atob(e), n = new Uint8Array(t.length);
2695
+ for (let e = 0; e < t.length; e++) n[e] = t.charCodeAt(e);
2696
+ return new TextDecoder().decode(n);
2697
+ }
2698
+ function Ne(e) {
2699
+ return e.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2700
+ }
2701
+ function Pe(e) {
2702
+ let t = e.replace(/-/g, "+").replace(/_/g, "/");
2703
+ return t + (t.length % 4 == 0 ? "" : "=".repeat(4 - t.length % 4));
2704
+ }
2705
+ function Fe(e) {
2706
+ return Ne(je(JSON.stringify(e)));
2707
+ }
2708
+ function Ie(e) {
2709
+ if (!e) return null;
2710
+ try {
2711
+ let t = Me(Pe(e)), n = JSON.parse(t);
2712
+ return !n || n.v !== 1 || typeof n.symbol != "string" ? null : {
2713
+ v: 1,
2714
+ symbol: n.symbol,
2715
+ timeframe: n.timeframe,
2716
+ chartType: n.chartType,
2717
+ scaleMode: n.scaleMode ?? "regular",
2718
+ indicators: Array.isArray(n.indicators) ? n.indicators : [],
2719
+ drawings: Array.isArray(n.drawings) ? n.drawings : []
2720
+ };
2721
+ } catch {
2722
+ return null;
2723
+ }
2724
+ }
2725
+ var Q = "tcw";
2726
+ function Le(e) {
2727
+ let t = e.startsWith("#") ? e.slice(1) : e;
2728
+ for (let e of t.split("&")) {
2729
+ let t = e.indexOf("=");
2730
+ if (t > 0 && e.slice(0, t) === Q) return decodeURIComponent(e.slice(t + 1));
2731
+ }
2732
+ return null;
2733
+ }
2734
+ function Re(e, t) {
2735
+ let [n] = e.split("#");
2736
+ return `${n}#${Q}=${t}`;
2737
+ }
2738
+ //#endregion
2739
+ //#region src/widget/ChartWidget.ts
2740
+ var $ = [
2741
+ "#f7931a",
2742
+ "#627eea",
2743
+ "#26a17b",
2744
+ "#e84142",
2745
+ "#8247e5",
2746
+ "#f3ba2f"
2747
+ ], ze = class {
2748
+ chart;
2749
+ state;
2750
+ toolbar = null;
2751
+ sidebar = null;
2752
+ settings = null;
2753
+ statusBar = null;
2754
+ commandPalette = null;
2755
+ symbolSearch = null;
2756
+ hotkeySheet = null;
2757
+ replayBar = null;
2758
+ dragDrop = null;
2759
+ alertsPanel = null;
2760
+ objectTree = null;
2761
+ indicatorSettings = null;
2762
+ drawingStyle = null;
2763
+ bracketBar = null;
2764
+ alertNotifier = null;
2765
+ depthLadder = null;
2766
+ dataWindow = null;
2767
+ lastHoverIndex = null;
2768
+ favoritesStore = new we();
2769
+ watchlist = null;
2770
+ watchlistSparkBuffer = /* @__PURE__ */ new Map();
2771
+ sessionRefPrice = null;
2772
+ watchlistInterval = null;
2773
+ replayOriginalData = null;
2774
+ replayPollInterval = null;
2775
+ replaySpeed = 5;
2776
+ layoutKeyPrefix = null;
2777
+ layoutDebounceMs = 1500;
2778
+ activeLayoutKey = null;
2779
+ root;
2780
+ chartContainer;
2781
+ destroyed = !1;
2782
+ options;
2783
+ symbols;
2784
+ settingsState;
2785
+ adapter = null;
2786
+ boundGlobalKeydown = null;
2787
+ baseSeries = null;
2788
+ baseTimeframeMs = 0;
2789
+ compares = [];
2790
+ constructor(n, r = {}) {
2791
+ if (this.options = r, this.symbols = r.symbols ?? ee, this.settingsState = { ...p }, r.persistLayouts) {
2792
+ let e = r.persistLayouts === !0 ? {} : r.persistLayouts;
2793
+ this.layoutKeyPrefix = e.keyPrefix ?? "tcw:layout:", this.layoutDebounceMs = e.debounceMs ?? 1500;
2794
+ }
2795
+ let i = this.resolveIsDark(r.theme), a = this.resolveTheme(r.theme);
2796
+ this.state = {
2797
+ symbol: r.symbol ?? this.symbols[0] ?? "BTCUSDT",
2798
+ timeframe: r.timeframe ?? "5m",
2799
+ chartType: r.chartOptions?.chartType ?? "candlestick",
2800
+ isDark: i,
2801
+ activeIndicators: /* @__PURE__ */ new Map(),
2802
+ activeTool: null,
2803
+ magnetEnabled: !0,
2804
+ connectionState: "connecting",
2805
+ connectionMessage: "Connecting..."
2806
+ }, 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
+ symbols: this.symbols,
2808
+ timeframes: r.timeframes ? c.filter((e) => r.timeframes.includes(e.value)) : c,
2809
+ chartTypes: r.chartTypes ? l.filter((e) => r.chartTypes.includes(e.value)) : l,
2810
+ indicators: d,
2811
+ popularIndicatorIds: f
2812
+ }, {
2813
+ onSymbolClick: () => this.handleSymbolClick(),
2814
+ onTimeframe: (e) => this.handleTimeframe(e),
2815
+ onChartType: (e) => this.handleChartType(e),
2816
+ onAddIndicator: (e) => this.handleAddIndicator(e),
2817
+ onRemoveIndicator: (e) => this.handleRemoveIndicator(e),
2818
+ onScreenshot: () => this.chart.screenshot(),
2819
+ onSettings: () => this.openSettings(),
2820
+ onToggleTheme: () => this.handleToggleTheme(),
2821
+ onToggleReplay: () => this.toggleReplay(),
2822
+ onToggleAlerts: r.alerts === !1 ? void 0 : () => this.toggleAlerts(),
2823
+ onToggleObjects: r.objectTree === !1 ? void 0 : () => this.toggleObjects(),
2824
+ onBracket: r.trading === !1 ? void 0 : (e) => this.startBracket(e),
2825
+ onToggleLadder: r.trading !== !1 && r.depthLadder ? () => this.depthLadder?.toggle() : void 0
2826
+ }));
2827
+ let o = document.createElement("div");
2828
+ if (o.className = "tcw-body", r.drawingTools !== !1 && (r.drawingFavorites && this.favoritesStore.seedDefaults(r.drawingFavorites), this.sidebar = new x(o, {
2829
+ drawingToolGroups: u,
2830
+ favorites: this.favoritesStore.list()
2831
+ }, {
2832
+ onDrawingTool: (e) => this.handleDrawingTool(e),
2833
+ onCancelDrawing: () => this.handleCancelDrawing(),
2834
+ onToggleMagnet: () => this.handleToggleMagnet(),
2835
+ onToggleFavorite: (e) => this.handleToggleFavorite(e),
2836
+ onUndo: () => this.chart.undo(),
2837
+ onRedo: () => this.chart.redo(),
2838
+ onClearDrawings: () => {
2839
+ this.chart.clearDrawings(), this.state = {
2840
+ ...this.state,
2841
+ activeTool: null
2842
+ }, this.updateUI();
2843
+ },
2844
+ 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) => {
2846
+ this.setSymbol(e);
2847
+ } }), this.watchlist.setActive(this.state.symbol)), this.root.appendChild(o), this.chart = new e(this.chartContainer, {
2848
+ chartType: this.state.chartType,
2849
+ theme: a,
2850
+ autoScale: !0,
2851
+ crosshair: { mode: "magnet" },
2852
+ features: {
2853
+ drawings: !0,
2854
+ drawingMagnet: !0,
2855
+ drawingUndoRedo: !0,
1525
2856
  indicators: !0,
1526
2857
  trading: r.trading !== !1,
1527
2858
  tradingContextMenu: r.trading !== !1,
@@ -1538,7 +2869,7 @@ var G = class {
1538
2869
  ...r.chartOptions
1539
2870
  }), r.dragDropImport !== !1 && (this.dragDrop = new t(this.chartContainer, {
1540
2871
  onData: (e, t, n) => {
1541
- this.chart.setData(e), this.toast(`Loaded ${t.data.length} bars from ${n.name}` + (t.skipped > 0 ? ` (${t.skipped} skipped)` : ""));
2872
+ this.setData(e), this.toast(`Loaded ${t.data.length} bars from ${n.name}` + (t.skipped > 0 ? ` (${t.skipped} skipped)` : ""));
1542
2873
  },
1543
2874
  onError: (e, t) => {
1544
2875
  this.toast(`${t.name}: ${e.message}`, "error");
@@ -1552,7 +2883,77 @@ var G = class {
1552
2883
  this.setSymbol(e);
1553
2884
  },
1554
2885
  onClose: () => {}
1555
- }), this.hotkeySheet = new N({ onClose: () => {} }), this.commandPalette = new T({
2886
+ }), this.hotkeySheet = new N({ onClose: () => {} }), this.chart.on("barClick", (e) => {
2887
+ if (!this.replayBar?.isMounted()) return;
2888
+ let t = e.payload.barIndex;
2889
+ typeof t == "number" && (this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(t), this.replayBar.setState("paused"));
2890
+ }), this.dataWindow = new ke(this.root, { formatPrice: (e) => this.formatAlertPrice(e) }), this.chart.on("crosshairMove", (e) => {
2891
+ let t = e.payload;
2892
+ this.lastHoverIndex = typeof t.barIndex == "number" ? t.barIndex : null, this.dataWindow?.isOpen() && this.dataWindow.render(this.buildDataWindowModel());
2893
+ }), r.drawingTools !== !1 && (this.drawingStyle = new Se(this.root, {
2894
+ onStyleChange: (e) => {
2895
+ this.chart.setDrawingStyle(e), this.chart.setSelectedDrawingStyle(e);
2896
+ },
2897
+ getStyle: () => this.chart.getDrawingStyle()
2898
+ }, new ve())), r.trading !== !1 && (this.bracketBar = new Te(this.root, {
2899
+ onConfirm: () => this.chart.confirmBracket(),
2900
+ onCancel: () => {
2901
+ this.chart.cancelBracket(), this.bracketBar?.hide();
2902
+ }
2903
+ }), this.chart.on("bracketPlace", (e) => {
2904
+ let t = e.payload;
2905
+ this.bracketBar?.hide(), this.toast(`${t.side === "buy" ? "Long" : "Short"} bracket placed · ${t.riskReward.toFixed(2)}R`);
2906
+ }), r.depthLadder && (this.depthLadder = new Oe(this.root, {
2907
+ onTrade: (e, t) => {
2908
+ this.chart.placeOrderIntent({
2909
+ side: e,
2910
+ type: "limit",
2911
+ price: t
2912
+ }), this.toast(`${e === "buy" ? "Buy" : "Sell"} limit @ ${this.formatAlertPrice(t)}`);
2913
+ },
2914
+ formatPrice: (e) => this.formatAlertPrice(e)
2915
+ })), this.chart.on("dataUpdate", (e) => {
2916
+ let t = e.payload;
2917
+ t && t.bracket === "cancelled" && this.bracketBar?.hide();
2918
+ })), r.alerts !== !1 && (this.alertsPanel = new ce(this.root, {
2919
+ onAdd: (e, t, n, r, i) => {
2920
+ this.chart.addAlert(e, t, n, r, i);
2921
+ },
2922
+ onRemove: (e) => this.chart.removeAlert(e),
2923
+ onClear: () => this.chart.clearAlerts(),
2924
+ getChannelValue: (e) => this.getAlertChannelValue(e),
2925
+ 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 Ee(r.alertNotifications)), this.chart.on("alertTriggered", (e) => {
2927
+ let t = e.payload, n = `Price ${this.formatAlertPrice(t.price)}${t.message ? ` — ${t.message}` : ""}`;
2928
+ this.toast(`🔔 Alert: ${n}`, "info"), this.alertNotifier?.notify(n), this.refreshAlerts();
2929
+ })), r.objectTree !== !1) {
2930
+ this.indicatorSettings = new me(this.root, {
2931
+ onApply: (e, t) => this.chart.updateIndicator(e, t),
2932
+ onClose: () => {}
2933
+ }), this.objectTree = new le(this.root, {
2934
+ onRemoveIndicator: (e) => this.handleRemoveIndicator(e),
2935
+ onConfigureIndicator: (e) => this.openIndicatorSettings(e),
2936
+ onToggleIndicatorVisible: (e, t) => {
2937
+ this.chart.setIndicatorVisible(e, t), this.refreshObjects();
2938
+ },
2939
+ onRemoveDrawing: (e) => {
2940
+ this.chart.removeDrawing(e), this.refreshObjects();
2941
+ },
2942
+ onToggleDrawingVisible: (e, t) => {
2943
+ this.chart.setDrawingVisible(e, t), this.refreshObjects();
2944
+ },
2945
+ onToggleDrawingLocked: (e, t) => {
2946
+ this.chart.setDrawingLocked(e, t), this.refreshObjects();
2947
+ },
2948
+ onAddCompare: () => this.handleAddCompare(),
2949
+ onRemoveCompare: (e) => this.handleRemoveCompare(e)
2950
+ });
2951
+ let e = () => {
2952
+ this.objectTree?.isOpen() && this.refreshObjects();
2953
+ };
2954
+ this.chart.on("drawingCreate", e), this.chart.on("drawingRemove", e), this.chart.on("indicatorAdd", e), this.chart.on("indicatorRemove", e);
2955
+ }
2956
+ if (this.commandPalette = new T({
1556
2957
  onIndicator: (e) => this.handleAddIndicator(e),
1557
2958
  onChartType: (e) => this.handleChartType(e),
1558
2959
  onDrawingTool: (e) => this.handleDrawingTool(e),
@@ -1567,7 +2968,10 @@ var G = class {
1567
2968
  if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) return;
1568
2969
  e.preventDefault(), this.hotkeySheet?.open();
1569
2970
  }
1570
- }, 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);
2971
+ }, 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 = Le(location.hash);
2973
+ e && this.importState(e);
2974
+ }
1571
2975
  }
1572
2976
  setSymbols(e) {
1573
2977
  this.symbols = e, this.watchlist?.setSymbols(e);
@@ -1595,10 +2999,14 @@ var G = class {
1595
2999
  });
1596
3000
  }
1597
3001
  async setTimeframe(e) {
1598
- this.state = {
3002
+ if (this.state = {
1599
3003
  ...this.state,
1600
3004
  timeframe: e
1601
- }, this.options.onTimeframeChange?.(e), this.updateUI(), this.adapter && await this.connectStream();
3005
+ }, this.options.onTimeframeChange?.(e), this.updateUI(), this.adapter) {
3006
+ await this.connectStream();
3007
+ return;
3008
+ }
3009
+ this.options.resampleTimeframes !== !1 && this.applyTimeframeData();
1602
3010
  }
1603
3011
  setTheme(e) {
1604
3012
  let t = this.resolveIsDark(e), n = this.resolveTheme(e);
@@ -1611,16 +3019,236 @@ var G = class {
1611
3019
  return this.chart;
1612
3020
  }
1613
3021
  destroy() {
1614
- 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.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(), h());
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(), _());
1615
3023
  }
1616
3024
  handleSymbolClick() {
1617
3025
  this.symbolSearch?.open(this.symbols, this.state.symbol);
1618
3026
  }
1619
3027
  handleTimeframe(e) {
1620
- this.state = {
3028
+ if (this.state = {
1621
3029
  ...this.state,
1622
3030
  timeframe: e
1623
- }, this.options.onTimeframeChange?.(e), this.updateUI(), this.adapter && this.connectStream();
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
+ }
3042
+ }
3043
+ setData(e) {
3044
+ this.baseSeries = e, this.baseTimeframeMs = s(e), this.applyTimeframeData();
3045
+ }
3046
+ applyTimeframeData() {
3047
+ if (!this.baseSeries) return;
3048
+ let e = a(this.state.timeframe);
3049
+ if (this.baseTimeframeMs > 0 && e > this.baseTimeframeMs) {
3050
+ let e = this.options.weekStartsOn ?? 1;
3051
+ this.chart.setData(o(this.baseSeries, this.state.timeframe, { weekStartsOn: e }));
3052
+ } else this.chart.setData(this.baseSeries);
3053
+ }
3054
+ toggleAlerts() {
3055
+ this.alertsPanel && (this.alertsPanel.toggle(), this.alertsPanel.isOpen() && this.refreshAlerts());
3056
+ }
3057
+ handleToggleFavorite(e) {
3058
+ let t = this.favoritesStore.toggle(e);
3059
+ this.sidebar?.setFavorites(this.favoritesStore.list()), this.toast(t ? "Pinned to favorites" : "Unpinned");
3060
+ }
3061
+ exportState() {
3062
+ let e = this.chart.getActiveIndicators().map((e) => ({
3063
+ id: e.id,
3064
+ params: e.params
3065
+ }));
3066
+ return Fe({
3067
+ v: 1,
3068
+ symbol: this.state.symbol,
3069
+ timeframe: this.state.timeframe,
3070
+ chartType: this.state.chartType,
3071
+ scaleMode: this.chart.getScaleMode(),
3072
+ indicators: e,
3073
+ drawings: this.chart.getDrawings()
3074
+ });
3075
+ }
3076
+ async importState(e) {
3077
+ let t = Ie(e);
3078
+ if (!t) return !1;
3079
+ 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
+ for (let [, e] of this.state.activeIndicators) this.chart.removeIndicator(e);
3081
+ let n = /* @__PURE__ */ new Map();
3082
+ for (let e of t.indicators) {
3083
+ let t = this.chart.addIndicator(e.id, e.params);
3084
+ t && n.set(e.id, t);
3085
+ }
3086
+ return this.state = {
3087
+ ...this.state,
3088
+ activeIndicators: n
3089
+ }, this.chart.setDrawings(t.drawings), this.updateUI(), !0;
3090
+ }
3091
+ async copyChartImage() {
3092
+ let e = await this.chart.copyScreenshot();
3093
+ this.toast(e ? "Chart image copied" : "Copy failed — image clipboard unavailable", e ? "info" : "error");
3094
+ }
3095
+ async copyShareLink() {
3096
+ let e = Re(typeof location < "u" ? location.href : "", this.exportState());
3097
+ try {
3098
+ await navigator.clipboard.writeText(e), this.toast("Share link copied");
3099
+ } catch {
3100
+ this.toast("Copy failed — clipboard unavailable", "error");
3101
+ }
3102
+ }
3103
+ setDepth(e) {
3104
+ this.chart.setDepthData(e), this.depthLadder?.setData(e), e && this.chart.pushDepthSnapshot(e);
3105
+ }
3106
+ startBracket(e) {
3107
+ this.chart.startBracket(e) && this.bracketBar?.show(e);
3108
+ }
3109
+ buildDataWindowModel() {
3110
+ let e = this.chart.getData(), t = this.lastHoverIndex;
3111
+ if (t === null || t < 0 || t >= e.length) return {
3112
+ ohlc: null,
3113
+ change: 0,
3114
+ changePct: 0,
3115
+ indicators: []
3116
+ };
3117
+ let n = e[t], r = t > 0 ? e[t - 1].close : n.open, i = n.close - r, a = r === 0 ? 0 : i / r * 100, o = this.chart.getActiveIndicators().map((e) => {
3118
+ let n = this.chart.getIndicatorOutput(e.instanceId)?.series?.[t] ?? null, r = n ? Object.entries(n).filter(([, e]) => typeof e == "number" && Number.isFinite(e)).map(([e, t]) => ({
3119
+ key: e,
3120
+ value: t
3121
+ })) : [];
3122
+ return {
3123
+ name: e.descriptor.name,
3124
+ values: r
3125
+ };
3126
+ }).filter((e) => e.values.length > 0);
3127
+ return {
3128
+ ohlc: {
3129
+ open: n.open,
3130
+ high: n.high,
3131
+ low: n.low,
3132
+ close: n.close,
3133
+ volume: n.volume
3134
+ },
3135
+ change: i,
3136
+ changePct: a,
3137
+ indicators: o
3138
+ };
3139
+ }
3140
+ toggleDataWindow() {
3141
+ this.dataWindow && (this.dataWindow.toggle(), this.dataWindow.isOpen() && this.dataWindow.render(this.buildDataWindowModel()));
3142
+ }
3143
+ toggleObjects() {
3144
+ this.objectTree && (this.objectTree.toggle(), this.objectTree.isOpen() && this.refreshObjects());
3145
+ }
3146
+ openIndicatorSettings(e) {
3147
+ if (!this.indicatorSettings) return;
3148
+ let t = this.chart.getActiveIndicators().find((t) => t.instanceId === e);
3149
+ t && this.indicatorSettings.open({
3150
+ instanceId: e,
3151
+ name: t.descriptor.name,
3152
+ defaults: t.descriptor.defaultConfig,
3153
+ params: t.params
3154
+ });
3155
+ }
3156
+ refreshObjects() {
3157
+ if (!this.objectTree) return;
3158
+ let e = this.chart.getActiveIndicators().map((e) => ({
3159
+ instanceId: e.instanceId,
3160
+ name: e.descriptor.name,
3161
+ visible: e.visible
3162
+ })), t = this.chart.getDrawings().map((e) => ({
3163
+ id: e.id,
3164
+ label: de(e.type),
3165
+ visible: e.visible,
3166
+ locked: e.locked
3167
+ })), n = this.compares.map((e) => ({
3168
+ id: e.id,
3169
+ label: e.symbol,
3170
+ color: e.color
3171
+ }));
3172
+ this.objectTree.setObjects(e, t, n);
3173
+ }
3174
+ async handleAddCompare() {
3175
+ if (!this.adapter) {
3176
+ this.toast("Comparison needs a live data adapter", "error");
3177
+ return;
3178
+ }
3179
+ let e = new Set([this.state.symbol, ...this.compares.map((e) => e.symbol)]), t = this.symbols.filter((t) => !e.has(t));
3180
+ this.symbolSearch?.open(t.length ? t : this.symbols, this.state.symbol, (e) => {
3181
+ this.addCompareSymbol(e);
3182
+ });
3183
+ }
3184
+ async addCompareSymbol(e) {
3185
+ if (!this.adapter || this.compares.some((t) => t.symbol === e)) return;
3186
+ let t = $[this.compares.length % $.length], n = `cmp_${e}`;
3187
+ try {
3188
+ let r = await this.adapter.fetchHistory(e, this.state.timeframe, this.options.historyLimit ?? 500);
3189
+ this.compares.length === 0 && this.chart.setCompareMode("percent"), this.chart.addCompareSymbol(n, e, r, t), this.compares = [...this.compares, {
3190
+ id: n,
3191
+ symbol: e,
3192
+ color: t
3193
+ }], this.refreshObjects(), this.toast(`Comparing ${e}`);
3194
+ } catch (t) {
3195
+ this.toast(`${e}: ${t instanceof Error ? t.message : "failed to load"}`, "error");
3196
+ }
3197
+ }
3198
+ handleRemoveCompare(e) {
3199
+ this.chart.removeCompareSymbol(e), this.compares = this.compares.filter((t) => t.id !== e), this.refreshObjects();
3200
+ }
3201
+ async refetchCompares() {
3202
+ if (!this.adapter || this.compares.length === 0) return;
3203
+ let e = this.compares.filter((e) => e.symbol === this.state.symbol);
3204
+ for (let t of e) this.handleRemoveCompare(t.id);
3205
+ for (let e of this.compares) try {
3206
+ let t = await this.adapter.fetchHistory(e.symbol, this.state.timeframe, this.options.historyLimit ?? 500);
3207
+ this.chart.updateCompareData(e.id, t);
3208
+ } catch {}
3209
+ }
3210
+ refreshAlerts() {
3211
+ this.alertsPanel && (this.alertsPanel.setSources(this.buildAlertSources()), this.alertsPanel.setAlerts(this.chart.getAlerts().map((e) => ({
3212
+ id: e.id,
3213
+ price: e.price,
3214
+ condition: e.condition,
3215
+ message: e.message,
3216
+ triggered: e.triggered,
3217
+ channel: e.channel,
3218
+ label: e.label
3219
+ }))));
3220
+ }
3221
+ buildAlertSources() {
3222
+ let e = [{
3223
+ channel: "price",
3224
+ label: "Price"
3225
+ }];
3226
+ for (let t of this.chart.getActiveIndicators()) {
3227
+ let n = this.chart.getIndicatorOutput(t.instanceId)?.series, r = n && n.length > 0 ? n[n.length - 1] : null, i = r ? Object.keys(r).filter((e) => typeof r[e] == "number") : [];
3228
+ for (let n of i) {
3229
+ let r = i.length > 1 ? `${t.descriptor.name} ${n}` : t.descriptor.name;
3230
+ e.push({
3231
+ channel: `${t.instanceId}:${n}`,
3232
+ label: r
3233
+ });
3234
+ }
3235
+ }
3236
+ return e;
3237
+ }
3238
+ getAlertChannelValue(e) {
3239
+ let t = this.chart.getData();
3240
+ if (e === "price") return t.length > 0 ? t[t.length - 1].close : null;
3241
+ let n = e.indexOf(":");
3242
+ if (n < 0 || t.length === 0) return null;
3243
+ let r = e.slice(0, n), i = e.slice(n + 1), a = this.chart.getIndicatorOutput(r)?.series?.[t.length - 1]?.[i];
3244
+ return typeof a == "number" && Number.isFinite(a) ? a : null;
3245
+ }
3246
+ formatAlertPrice(e) {
3247
+ let t = Math.abs(e), n = t >= 1e3 ? 2 : t >= 1 ? 4 : 6, r = this.settingsState.numberLocale || void 0;
3248
+ return e.toLocaleString(r, {
3249
+ minimumFractionDigits: 2,
3250
+ maximumFractionDigits: n
3251
+ });
1624
3252
  }
1625
3253
  handleChartType(e) {
1626
3254
  this.state = {
@@ -1670,25 +3298,25 @@ var G = class {
1670
3298
  }
1671
3299
  buildCommandItems() {
1672
3300
  let e = [];
1673
- for (let t of s) e.push({
3301
+ for (let t of d) e.push({
1674
3302
  id: t.id,
1675
3303
  label: t.name,
1676
3304
  category: "indicator",
1677
3305
  active: this.state.activeIndicators.has(t.id)
1678
3306
  });
1679
- for (let t of a) e.push({
3307
+ for (let t of l) e.push({
1680
3308
  id: t.value,
1681
3309
  label: t.label,
1682
3310
  category: "chartType",
1683
3311
  active: this.state.chartType === t.value
1684
3312
  });
1685
- for (let t of o) for (let n of t.tools) e.push({
3313
+ for (let t of u) for (let n of t.tools) e.push({
1686
3314
  id: n.value,
1687
3315
  label: n.label,
1688
3316
  category: "drawing",
1689
3317
  active: this.state.activeTool === n.value
1690
3318
  });
1691
- for (let t of i) e.push({
3319
+ for (let t of c) e.push({
1692
3320
  id: t.value,
1693
3321
  label: t.label,
1694
3322
  category: "timeframe",
@@ -1699,6 +3327,10 @@ var G = class {
1699
3327
  label: "Screenshot",
1700
3328
  category: "action",
1701
3329
  shortcut: ""
3330
+ }, {
3331
+ id: "copyImage",
3332
+ label: "Copy Chart Image",
3333
+ category: "action"
1702
3334
  }, {
1703
3335
  id: "toggleTheme",
1704
3336
  label: "Toggle Theme",
@@ -1707,6 +3339,18 @@ var G = class {
1707
3339
  id: "settings",
1708
3340
  label: "Settings",
1709
3341
  category: "action"
3342
+ }, {
3343
+ id: "shareView",
3344
+ label: "Share View (copy link)",
3345
+ category: "action"
3346
+ }, {
3347
+ id: "autoFib",
3348
+ label: "Auto Fibonacci (visible swing)",
3349
+ category: "action"
3350
+ }, {
3351
+ id: "dataWindow",
3352
+ label: "Toggle Data Window",
3353
+ category: "action"
1710
3354
  }, {
1711
3355
  id: "clearDrawings",
1712
3356
  label: "Clear All Drawings",
@@ -1724,6 +3368,20 @@ var G = class {
1724
3368
  case "settings":
1725
3369
  this.openSettings();
1726
3370
  break;
3371
+ case "copyImage":
3372
+ this.copyChartImage();
3373
+ break;
3374
+ case "shareView":
3375
+ this.copyShareLink();
3376
+ break;
3377
+ case "autoFib": {
3378
+ let e = this.chart.autoFib();
3379
+ this.toast(e ? "Auto Fibonacci added" : "No clear swing in view");
3380
+ break;
3381
+ }
3382
+ case "dataWindow":
3383
+ this.toggleDataWindow();
3384
+ break;
1727
3385
  case "clearDrawings":
1728
3386
  this.chart.clearDrawings(), this.state = {
1729
3387
  ...this.state,
@@ -1809,7 +3467,7 @@ var G = class {
1809
3467
  let e = this.chart.getData();
1810
3468
  e.length < 2 || (this.replayOriginalData = e.slice(), this.replayBar = new F({
1811
3469
  onPlay: () => {
1812
- this.chart.getReplayState() === "paused" ? this.chart.replayResume() : this.chart.replay({
3470
+ this.chart.getReplayState() === "paused" ? this.chart.replayResume() : this.chart.replayStart({
1813
3471
  speed: this.replaySpeed,
1814
3472
  interval: 200
1815
3473
  }), this.replayBar?.setState("playing");
@@ -1838,7 +3496,7 @@ var G = class {
1838
3496
  }), this.replayBar.mount(this.chartContainer, {
1839
3497
  total: e.length,
1840
3498
  speed: this.replaySpeed
1841
- }), this.chart.replay({
3499
+ }), this.chart.replayStart({
1842
3500
  speed: this.replaySpeed,
1843
3501
  interval: 200,
1844
3502
  startIndex: 1
@@ -1857,12 +3515,21 @@ var G = class {
1857
3515
  this.settingsState = {
1858
3516
  ...this.settingsState,
1859
3517
  ...e
1860
- }, e.gridVisible !== void 0 && this.chart.setGridVisible(e.gridVisible), e.volumeVisible !== void 0 && this.chart.setVolumeVisible(e.volumeVisible), e.volumeProfileVisible !== void 0 && this.chart.setVolumeProfileVisible(e.volumeProfileVisible), e.crosshairMode !== void 0 && this.chart.setCrosshairMode(e.crosshairMode), e.autoScale !== void 0 && this.chart.setAutoScale(e.autoScale), e.logScale !== void 0 && this.chart.setLogScale(e.logScale), e.numberLocale !== void 0 && this.chart.setNumberLocale(e.numberLocale);
3518
+ }, e.gridVisible !== void 0 && this.chart.setGridVisible(e.gridVisible), e.volumeVisible !== void 0 && this.chart.setVolumeVisible(e.volumeVisible), e.volumeProfileVisible !== void 0 && this.chart.setVolumeProfileVisible(e.volumeProfileVisible), e.marketProfileVisible !== void 0 && this.chart.setMarketProfileVisible(e.marketProfileVisible), e.marketProfileSplit !== void 0 && this.chart.setMarketProfileConfig({ splitBySession: e.marketProfileSplit }), e.marketProfileLetters !== void 0 && this.chart.setMarketProfileConfig({ letters: e.marketProfileLetters }), e.marketProfileBuckets !== void 0 && this.chart.setMarketProfileConfig({ buckets: e.marketProfileBuckets }), e.marketProfileOpacity !== void 0 && this.chart.setMarketProfileConfig({ opacity: e.marketProfileOpacity }), e.depthHeatmapVisible !== void 0 && this.chart.setDepthHeatmapVisible(e.depthHeatmapVisible), e.depthHeatmapOpacity !== void 0 && this.chart.setDepthHeatmapConfig({ opacity: e.depthHeatmapOpacity }), e.sessionShadingVisible !== void 0 && this.chart.setSessionShadingVisible(e.sessionShadingVisible), e.pivotMarkersVisible !== void 0 && this.chart.setPivotMarkersVisible(e.pivotMarkersVisible), e.pivotStrength !== void 0 && this.chart.setPivotMarkersConfig({
3519
+ left: e.pivotStrength,
3520
+ right: e.pivotStrength
3521
+ }), e.pivotStructureLabels !== void 0 && this.chart.setPivotMarkersConfig({ structureLabels: e.pivotStructureLabels }), e.periodLevelsVisible !== void 0 && this.chart.setPeriodLevelsVisible(e.periodLevelsVisible), e.periodLevelsPeriod !== void 0 && this.chart.setPeriodLevelsPeriod(e.periodLevelsPeriod), e.crosshairMode !== void 0 && this.chart.setCrosshairMode(e.crosshairMode), e.autoScale !== void 0 && this.chart.setAutoScale(e.autoScale), e.scaleMode === void 0 ? e.logScale !== void 0 && (this.chart.setLogScale(e.logScale), this.settingsState = {
3522
+ ...this.settingsState,
3523
+ scaleMode: e.logScale ? "logarithmic" : "regular"
3524
+ }) : (this.chart.setScaleMode(e.scaleMode), this.settingsState = {
3525
+ ...this.settingsState,
3526
+ 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));
1861
3528
  let t = { ...this.chart.getTheme() }, n = !1;
1862
3529
  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);
1863
3530
  }
1864
3531
  resetSettings() {
1865
- this.settingsState = { ...u }, this.applySettings(this.settingsState);
3532
+ this.settingsState = { ...p }, this.applySettings(this.settingsState);
1866
3533
  }
1867
3534
  async connectStream() {
1868
3535
  if (this.adapter) {
@@ -1884,7 +3551,7 @@ var G = class {
1884
3551
  ...this.state,
1885
3552
  connectionState: "connected",
1886
3553
  connectionMessage: "Live"
1887
- };
3554
+ }, this.refetchCompares();
1888
3555
  } catch (e) {
1889
3556
  this.state = {
1890
3557
  ...this.state,
@@ -1918,6 +3585,6 @@ var G = class {
1918
3585
  }
1919
3586
  };
1920
3587
  //#endregion
1921
- export { G as ChartWidget };
3588
+ export { ze as ChartWidget };
1922
3589
 
1923
3590
  //# sourceMappingURL=index.js.map