@tradecanvas/chart 1.2.0 → 1.4.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 (74) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +858 -824
  3. package/dist/Chart.d.ts +142 -2
  4. package/dist/Chart.d.ts.map +1 -1
  5. package/dist/DragDropImporter-C5kgfbET.cjs +2 -0
  6. package/dist/DragDropImporter-C5kgfbET.cjs.map +1 -0
  7. package/dist/{DragDropImporter-BcTzFeRP.js → DragDropImporter-Dd9Mud5J.js} +423 -159
  8. package/dist/DragDropImporter-Dd9Mud5J.js.map +1 -0
  9. package/dist/PaneManager.d.ts.map +1 -1
  10. package/dist/charts/ChartTypeStrategy.d.ts +6 -0
  11. package/dist/charts/ChartTypeStrategy.d.ts.map +1 -1
  12. package/dist/grid/ChartGrid.d.ts +1 -0
  13. package/dist/grid/ChartGrid.d.ts.map +1 -1
  14. package/dist/index.cjs +1 -1
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.ts +5 -2
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +74 -89
  19. package/dist/index.js.map +1 -1
  20. package/dist/interaction/verticalPanGate.d.ts +22 -0
  21. package/dist/interaction/verticalPanGate.d.ts.map +1 -0
  22. package/dist/widget/ChartWidget.d.ts +71 -7
  23. package/dist/widget/ChartWidget.d.ts.map +1 -1
  24. package/dist/widget/WidgetCommandPalette.d.ts +3 -1
  25. package/dist/widget/WidgetCommandPalette.d.ts.map +1 -1
  26. package/dist/widget/WidgetDrawingSidebar.d.ts +12 -0
  27. package/dist/widget/WidgetDrawingSidebar.d.ts.map +1 -1
  28. package/dist/widget/WidgetGoToDate.d.ts +45 -0
  29. package/dist/widget/WidgetGoToDate.d.ts.map +1 -0
  30. package/dist/widget/WidgetHotkeySheet.d.ts +4 -2
  31. package/dist/widget/WidgetHotkeySheet.d.ts.map +1 -1
  32. package/dist/widget/WidgetIndicatorLegend.d.ts +68 -0
  33. package/dist/widget/WidgetIndicatorLegend.d.ts.map +1 -0
  34. package/dist/widget/WidgetLoadingOverlay.d.ts +3 -1
  35. package/dist/widget/WidgetLoadingOverlay.d.ts.map +1 -1
  36. package/dist/widget/WidgetObjectTree.d.ts +1 -1
  37. package/dist/widget/WidgetReplayBar.d.ts +37 -7
  38. package/dist/widget/WidgetReplayBar.d.ts.map +1 -1
  39. package/dist/widget/WidgetSettings.d.ts +13 -1
  40. package/dist/widget/WidgetSettings.d.ts.map +1 -1
  41. package/dist/widget/WidgetStatusBar.d.ts +16 -1
  42. package/dist/widget/WidgetStatusBar.d.ts.map +1 -1
  43. package/dist/widget/WidgetSymbolSearch.d.ts +3 -1
  44. package/dist/widget/WidgetSymbolSearch.d.ts.map +1 -1
  45. package/dist/widget/WidgetToolbar.d.ts +12 -3
  46. package/dist/widget/WidgetToolbar.d.ts.map +1 -1
  47. package/dist/widget/WidgetTooltip.d.ts +43 -0
  48. package/dist/widget/WidgetTooltip.d.ts.map +1 -0
  49. package/dist/widget/escapeHtml.d.ts +3 -0
  50. package/dist/widget/escapeHtml.d.ts.map +1 -0
  51. package/dist/widget/i18n.d.ts +26 -0
  52. package/dist/widget/i18n.d.ts.map +1 -1
  53. package/dist/widget/iconSet.d.ts +26 -0
  54. package/dist/widget/iconSet.d.ts.map +1 -0
  55. package/dist/widget/icons.d.ts +5 -0
  56. package/dist/widget/icons.d.ts.map +1 -1
  57. package/dist/widget/index.cjs +3035 -2465
  58. package/dist/widget/index.cjs.map +1 -1
  59. package/dist/widget/index.d.ts +3 -0
  60. package/dist/widget/index.d.ts.map +1 -1
  61. package/dist/widget/index.js +1636 -606
  62. package/dist/widget/index.js.map +1 -1
  63. package/dist/widget/legendValues.d.ts +14 -0
  64. package/dist/widget/legendValues.d.ts.map +1 -0
  65. package/dist/widget/types.d.ts +34 -8
  66. package/dist/widget/types.d.ts.map +1 -1
  67. package/dist/widget/widgetConfig.d.ts +1 -5
  68. package/dist/widget/widgetConfig.d.ts.map +1 -1
  69. package/dist/widget/widgetTimeframes.d.ts +20 -0
  70. package/dist/widget/widgetTimeframes.d.ts.map +1 -0
  71. package/package.json +3 -3
  72. package/dist/DragDropImporter-BcTzFeRP.js.map +0 -1
  73. package/dist/DragDropImporter-DZBrretS.cjs +0 -2
  74. package/dist/DragDropImporter-DZBrretS.cjs.map +0 -1
@@ -1,12 +1,13 @@
1
- import { r as e, t } from "../DragDropImporter-BcTzFeRP.js";
2
- import { DARK_THEME as n, LIGHT_THEME as r, timeframeBucketStart as i, timeframeToMs as a } from "@tradecanvas/commons";
1
+ import { r as e, t } from "../DragDropImporter-Dd9Mud5J.js";
2
+ import { DARK_THEME as n, LIGHT_THEME as r, formatPrice as i, timeframeBucketStart as a, timeframeToMs as o } from "@tradecanvas/commons";
3
+ import { RANGE_PRESETS as s } from "@tradecanvas/core";
3
4
  //#region src/io/resampleOHLCV.ts
4
- function o(e, t, n = {}) {
5
+ function c(e, t, n = {}) {
5
6
  if (e.length === 0) return [];
6
- let r = n.weekStartsOn ?? 1, a = [], o = null, s = NaN;
7
+ let r = n.weekStartsOn ?? 1, i = [], o = null, s = NaN;
7
8
  for (let n of e) {
8
- let e = i(n.time, t, r);
9
- o === null || e !== s ? (o !== null && a.push(o), o = {
9
+ let e = a(n.time, t, r);
10
+ o === null || e !== s ? (o !== null && i.push(o), o = {
10
11
  time: e,
11
12
  open: n.open,
12
13
  high: n.high,
@@ -22,9 +23,9 @@ function o(e, t, n = {}) {
22
23
  volume: o.volume + n.volume
23
24
  };
24
25
  }
25
- return o !== null && a.push(o), a;
26
+ return o !== null && i.push(o), i;
26
27
  }
27
- function s(e) {
28
+ function l(e) {
28
29
  if (e.length < 2) return 0;
29
30
  let t = [];
30
31
  for (let n = 1; n < e.length; n++) {
@@ -35,32 +36,7 @@ function s(e) {
35
36
  }
36
37
  //#endregion
37
38
  //#region src/widget/widgetConfig.ts
38
- var c = [
39
- {
40
- label: "1m",
41
- value: "1m"
42
- },
43
- {
44
- label: "5m",
45
- value: "5m"
46
- },
47
- {
48
- label: "15m",
49
- value: "15m"
50
- },
51
- {
52
- label: "1H",
53
- value: "1h"
54
- },
55
- {
56
- label: "4H",
57
- value: "4h"
58
- },
59
- {
60
- label: "1D",
61
- value: "1d"
62
- }
63
- ], l = [
39
+ var u = [
64
40
  {
65
41
  label: "Candlestick",
66
42
  value: "candlestick"
@@ -109,7 +85,7 @@ var c = [
109
85
  label: "Line + Markers",
110
86
  value: "lineWithMarkers"
111
87
  }
112
- ], u = [
88
+ ], d = [
113
89
  {
114
90
  label: "Lines",
115
91
  tools: [
@@ -317,7 +293,7 @@ var c = [
317
293
  }
318
294
  ]
319
295
  }
320
- ], d = [
296
+ ], f = [
321
297
  {
322
298
  id: "sma",
323
299
  name: "SMA",
@@ -668,7 +644,7 @@ var c = [
668
644
  name: "Volume Profile",
669
645
  type: "panel"
670
646
  }
671
- ], f = [
647
+ ], ee = [
672
648
  "sma",
673
649
  "ema",
674
650
  "bb",
@@ -679,18 +655,18 @@ var c = [
679
655
  "atr",
680
656
  "obv",
681
657
  "ichimoku"
682
- ], ee = [
658
+ ], te = [
683
659
  "BTCUSDT",
684
660
  "ETHUSDT",
685
661
  "SOLUSDT",
686
662
  "BNBUSDT"
687
663
  ], p = {
688
- candleUpColor: "#26A69A",
689
- candleDownColor: "#EF5350",
690
- candleUpWick: "#26A69A",
691
- candleDownWick: "#EF5350",
692
- backgroundColor: "#131722",
693
- gridColor: "#1E222D",
664
+ candleUpColor: n.candleUp,
665
+ candleDownColor: n.candleDown,
666
+ candleUpWick: n.candleUpWick,
667
+ candleDownWick: n.candleDownWick,
668
+ backgroundColor: n.background,
669
+ gridColor: n.grid,
694
670
  gridVisible: !0,
695
671
  volumeVisible: !0,
696
672
  volumeProfileVisible: !1,
@@ -712,68 +688,364 @@ var c = [
712
688
  logScale: !1,
713
689
  scaleMode: "regular",
714
690
  autoScale: !0,
691
+ invertScale: !1,
715
692
  crosshairMode: "magnet",
716
693
  numberLocale: "en-US",
717
694
  timezone: "local"
718
- }, te = "/* === TradeCanvas Widget — Premium Styles === */\r\n\r\n/*\r\n * The HTML `hidden` attribute only sets `display: none` via the UA stylesheet,\r\n * which any author `display` rule (e.g. `.tcw-alerts-panel { display: flex }`)\r\n * silently overrides — leaving panels stuck open when JS sets `el.hidden = true`.\r\n * Force `hidden` to win for every namespaced widget element. Scoped to `tcw-`\r\n * so it never touches the host page.\r\n */\r\n[class^=\"tcw-\"][hidden],\r\n[class*=\" tcw-\"][hidden] {\r\n display: none !important;\r\n}\r\n\r\n.tcw-root {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif;\r\n font-feature-settings: 'cv11', 'ss01', 'ss03';\r\n font-size: 13px;\r\n line-height: 1.4;\r\n color: #d1d4dc;\r\n background: #0d0f17;\r\n position: relative;\r\n overflow: hidden;\r\n -webkit-font-smoothing: antialiased;\r\n -moz-osx-font-smoothing: grayscale;\r\n\r\n /* --- Dark theme tokens (default) --- */\r\n --tcw-bg: #0d0f17;\r\n --tcw-bg-surface: #131722;\r\n --tcw-bg-elevated: #1a1e2d;\r\n --tcw-bg-overlay: #20253480;\r\n --tcw-border: #2a2e39;\r\n --tcw-border-strong: #363a45;\r\n --tcw-text: #e9ebf0;\r\n --tcw-text-dim: #b2b5be;\r\n --tcw-text-muted: #6b6f7a;\r\n\r\n --tcw-accent: #4f88ff;\r\n --tcw-accent-hover: #6b9aff;\r\n --tcw-accent-soft: rgba(79, 136, 255, 0.14);\r\n --tcw-accent-glow: rgba(79, 136, 255, 0.22);\r\n --tcw-accent-line: rgba(79, 136, 255, 0.55);\r\n\r\n --tcw-red: #f23645;\r\n --tcw-red-soft: rgba(242, 54, 69, 0.12);\r\n --tcw-green: #26a17b;\r\n --tcw-green-soft: rgba(38, 161, 123, 0.12);\r\n --tcw-amber: #ff9f43;\r\n\r\n --tcw-hover-bg: rgba(255, 255, 255, 0.05);\r\n --tcw-active-bg: rgba(255, 255, 255, 0.08);\r\n --tcw-divider: rgba(255, 255, 255, 0.06);\r\n\r\n /* Motion */\r\n --tcw-ease: cubic-bezier(0.2, 0, 0, 1);\r\n --tcw-ease-out: cubic-bezier(0.16, 1, 0.3, 1);\r\n --tcw-dur-fast: 120ms;\r\n --tcw-dur-normal: 180ms;\r\n --tcw-dur-slow: 260ms;\r\n\r\n /* Shape */\r\n --tcw-radius-sm: 4px;\r\n --tcw-radius: 6px;\r\n --tcw-radius-lg: 10px;\r\n --tcw-radius-xl: 14px;\r\n\r\n /* Elevation */\r\n --tcw-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);\r\n --tcw-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35), 0 1px 3px rgba(0, 0, 0, 0.2);\r\n --tcw-shadow-lg: 0 12px 36px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.3);\r\n --tcw-shadow-xl: 0 24px 64px rgba(0, 0, 0, 0.55), 0 12px 24px rgba(0, 0, 0, 0.35);\r\n --tcw-ring: 0 0 0 2px rgba(79, 136, 255, 0.45);\r\n\r\n /* Type */\r\n --tcw-font-mono: 'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', 'Consolas', ui-monospace, monospace;\r\n}\r\n\r\n.tcw-root[data-tcw-theme='light'] {\r\n color: #131722;\r\n background: #fcfcfd;\r\n\r\n --tcw-bg: #fcfcfd;\r\n --tcw-bg-surface: #ffffff;\r\n --tcw-bg-elevated: #ffffff;\r\n --tcw-bg-overlay: rgba(255, 255, 255, 0.75);\r\n --tcw-border: #e7e9ef;\r\n --tcw-border-strong: #d4d7e0;\r\n --tcw-text: #131722;\r\n --tcw-text-dim: #50545e;\r\n --tcw-text-muted: #8b8f99;\r\n\r\n --tcw-accent: #2962ff;\r\n --tcw-accent-hover: #1e4fd6;\r\n --tcw-accent-soft: rgba(41, 98, 255, 0.10);\r\n --tcw-accent-glow: rgba(41, 98, 255, 0.16);\r\n --tcw-accent-line: rgba(41, 98, 255, 0.45);\r\n\r\n --tcw-hover-bg: rgba(0, 0, 0, 0.04);\r\n --tcw-active-bg: rgba(41, 98, 255, 0.08);\r\n --tcw-divider: rgba(0, 0, 0, 0.06);\r\n\r\n --tcw-shadow-sm: 0 1px 2px rgba(20, 28, 56, 0.05);\r\n --tcw-shadow-md: 0 4px 12px rgba(20, 28, 56, 0.08), 0 1px 3px rgba(20, 28, 56, 0.04);\r\n --tcw-shadow-lg: 0 12px 36px rgba(20, 28, 56, 0.14), 0 4px 12px rgba(20, 28, 56, 0.08);\r\n --tcw-shadow-xl: 0 24px 64px rgba(20, 28, 56, 0.18), 0 12px 24px rgba(20, 28, 56, 0.1);\r\n}\r\n\r\n/* === Toolbar === */\r\n\r\n.tcw-toolbar {\r\n display: flex;\r\n align-items: center;\r\n gap: 0;\r\n padding: 0 10px;\r\n height: 44px;\r\n border-bottom: 1px solid var(--tcw-border);\r\n background:\r\n linear-gradient(180deg, var(--tcw-bg-elevated) 0%, var(--tcw-bg-surface) 100%);\r\n flex-shrink: 0;\r\n position: relative;\r\n z-index: 20;\r\n box-shadow: var(--tcw-shadow-sm);\r\n}\r\n\r\n.tcw-toolbar-symbol {\r\n font-size: 14px;\r\n font-weight: 650;\r\n color: var(--tcw-text);\r\n padding: 6px 12px;\r\n white-space: nowrap;\r\n letter-spacing: -0.015em;\r\n cursor: pointer;\r\n border: none;\r\n background: transparent;\r\n font-family: inherit;\r\n border-radius: var(--tcw-radius);\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-toolbar-symbol:hover {\r\n background: var(--tcw-hover-bg);\r\n}\r\n\r\n.tcw-toolbar-sep {\r\n width: 1px;\r\n height: 22px;\r\n background: var(--tcw-border);\r\n flex-shrink: 0;\r\n margin: 0 4px;\r\n}\r\n\r\n.tcw-toolbar-group {\r\n display: flex;\r\n align-items: center;\r\n gap: 2px;\r\n padding: 0 4px;\r\n}\r\n\r\n.tcw-toolbar-spacer {\r\n flex: 1;\r\n}\r\n\r\n.tcw-btn {\r\n padding: 6px 10px;\r\n font-size: 12px;\r\n font-weight: 500;\r\n font-family: inherit;\r\n border: none;\r\n border-radius: var(--tcw-radius);\r\n background: transparent;\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n transition:\r\n background var(--tcw-dur-fast) var(--tcw-ease),\r\n color var(--tcw-dur-fast) var(--tcw-ease),\r\n transform var(--tcw-dur-fast) var(--tcw-ease);\r\n white-space: nowrap;\r\n line-height: 1;\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-btn:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-btn:active {\r\n transform: translateY(0.5px);\r\n}\r\n\r\n.tcw-btn.tcw-active {\r\n background: var(--tcw-accent-soft);\r\n color: var(--tcw-accent);\r\n font-weight: 600;\r\n box-shadow: inset 0 0 0 1px var(--tcw-accent-line);\r\n}\r\n\r\n.tcw-btn:focus-visible,\r\n.tcw-btn-icon:focus-visible,\r\n.tcw-sidebar-btn:focus-visible,\r\n.tcw-dropdown-trigger:focus-visible {\r\n outline: none;\r\n box-shadow: var(--tcw-ring);\r\n}\r\n\r\n.tcw-btn-icon {\r\n width: 32px;\r\n height: 32px;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-family: inherit;\r\n border: none;\r\n border-radius: var(--tcw-radius);\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n cursor: pointer;\r\n transition:\r\n background var(--tcw-dur-fast) var(--tcw-ease),\r\n color var(--tcw-dur-fast) var(--tcw-ease);\r\n line-height: 1;\r\n position: relative;\r\n}\r\n\r\n.tcw-btn-icon:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-btn-icon svg {\r\n display: block;\r\n}\r\n\r\n.tcw-badge-count {\r\n font-size: 10px;\r\n font-weight: 600;\r\n color: var(--tcw-accent);\r\n background: var(--tcw-accent-soft);\r\n padding: 1px 5px;\r\n border-radius: 9px;\r\n font-family: var(--tcw-font-mono);\r\n}\r\n\r\n.tcw-indicator-chips {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n padding: 0 4px;\r\n flex-wrap: nowrap;\r\n overflow: hidden;\r\n}\r\n\r\n.tcw-indicator-chip {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 4px;\r\n padding: 3px 6px 3px 9px;\r\n font-size: 11px;\r\n font-weight: 500;\r\n background: var(--tcw-accent-soft);\r\n color: var(--tcw-accent);\r\n border-radius: 9999px;\r\n white-space: nowrap;\r\n line-height: 1.4;\r\n letter-spacing: -0.005em;\r\n border: 1px solid transparent;\r\n transition: border-color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-indicator-chip:hover {\r\n border-color: var(--tcw-accent-line);\r\n}\r\n\r\n.tcw-chip-remove {\r\n cursor: pointer;\r\n opacity: 0.55;\r\n padding: 0 2px;\r\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\r\n border: none;\r\n background: transparent;\r\n color: inherit;\r\n display: inline-flex;\r\n align-items: center;\r\n}\r\n\r\n.tcw-chip-remove:hover {\r\n opacity: 1;\r\n}\r\n\r\n/* === Dropdown === */\r\n\r\n.tcw-dropdown-trigger {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 4px;\r\n padding: 6px 10px;\r\n font-size: 12px;\r\n font-weight: 500;\r\n font-family: inherit;\r\n border: none;\r\n border-radius: var(--tcw-radius);\r\n background: transparent;\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n white-space: nowrap;\r\n line-height: 1;\r\n}\r\n\r\n.tcw-dropdown-trigger:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-dropdown {\r\n position: absolute;\r\n top: 100%;\r\n margin-top: 6px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n z-index: 50;\r\n padding: 6px;\r\n max-height: 420px;\r\n overflow-y: auto;\r\n backdrop-filter: blur(12px);\r\n -webkit-backdrop-filter: blur(12px);\r\n animation: tcw-pop-in var(--tcw-dur-normal) var(--tcw-ease-out);\r\n}\r\n\r\n@keyframes tcw-pop-in {\r\n from { opacity: 0; transform: translateY(-4px) scale(0.98); }\r\n to { opacity: 1; transform: translateY(0) scale(1); }\r\n}\r\n\r\n.tcw-dropdown-item {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 7px 10px;\r\n font-size: 12.5px;\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n width: 100%;\r\n border: none;\r\n background: transparent;\r\n font-family: inherit;\r\n text-align: left;\r\n border-radius: var(--tcw-radius-sm);\r\n gap: 12px;\r\n}\r\n\r\n.tcw-dropdown-item:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-dropdown-item.tcw-active {\r\n color: var(--tcw-accent);\r\n background: var(--tcw-accent-soft);\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-dropdown-label {\r\n text-transform: uppercase;\r\n font-size: 10px;\r\n color: var(--tcw-text-muted);\r\n letter-spacing: 0.08em;\r\n padding: 8px 10px 4px;\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-dropdown-divider {\r\n border-top: 1px solid var(--tcw-divider);\r\n margin: 6px 4px;\r\n}\r\n\r\n.tcw-tag {\r\n font-size: 10px;\r\n font-family: var(--tcw-font-mono);\r\n color: var(--tcw-text-muted);\r\n padding: 2px 6px;\r\n border-radius: 4px;\r\n background: var(--tcw-hover-bg);\r\n letter-spacing: 0.02em;\r\n}\r\n\r\n/* === Body === */\r\n\r\n.tcw-body {\r\n display: flex;\r\n flex: 1;\r\n min-height: 0;\r\n background: var(--tcw-bg);\r\n}\r\n\r\n.tcw-chart-container {\r\n flex: 1;\r\n min-width: 0;\r\n min-height: 0;\r\n width: 100%;\r\n height: 100%;\r\n position: relative;\r\n}\r\n\r\n/* === Loading overlay (TradingView-style skeleton bars) === */\r\n\r\n.tcw-loading-overlay {\r\n /* Uses a modifier class rather than the `hidden` attribute — the global\r\n `[hidden] { display: none !important }` rule above would cut the\r\n opacity transition off before it can play. */\r\n position: absolute;\r\n inset: 0;\r\n z-index: 5;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n background: var(--tcw-bg);\r\n opacity: 1;\r\n transition: opacity var(--tcw-dur-slow) var(--tcw-ease-out);\r\n pointer-events: none;\r\n}\r\n\r\n.tcw-loading-overlay--hidden {\r\n opacity: 0;\r\n}\r\n\r\n.tcw-loading-card {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 16px;\r\n padding: 20px 28px 16px;\r\n border: 1px solid transparent;\r\n border-radius: var(--tcw-radius-lg);\r\n}\r\n\r\n/* A slow switch: the previous chart stays readable underneath, dimmed, so the\r\n click visibly registered without blanking the screen. */\r\n.tcw-loading-overlay--veil {\r\n background: color-mix(in srgb, var(--tcw-bg) 55%, transparent);\r\n}\r\n\r\n.tcw-loading-overlay--veil .tcw-loading-card {\r\n background: var(--tcw-bg-elevated);\r\n border-color: var(--tcw-border);\r\n box-shadow: var(--tcw-shadow-lg);\r\n}\r\n\r\n.tcw-loading-overlay--error .tcw-loading-bars {\r\n display: none;\r\n}\r\n\r\n.tcw-loading-overlay--error .tcw-loading-label {\r\n color: var(--tcw-red);\r\n font-size: 13px;\r\n}\r\n\r\n.tcw-loading-bars {\r\n display: flex;\r\n align-items: flex-end;\r\n gap: 3px;\r\n height: 64px;\r\n}\r\n\r\n.tcw-loading-bar {\r\n width: 5px;\r\n border-radius: 2px 2px 0 0;\r\n background: var(--tcw-border-strong);\r\n animation: tcw-skeleton-pulse 1.1s ease-in-out infinite;\r\n}\r\n\r\n@keyframes tcw-skeleton-pulse {\r\n 0%, 100% { opacity: 0.35; transform: scaleY(0.55); }\r\n 50% { opacity: 0.85; transform: scaleY(1); }\r\n}\r\n\r\n.tcw-loading-label {\r\n font-size: 12px;\r\n color: var(--tcw-text-muted);\r\n letter-spacing: 0.02em;\r\n}\r\n\r\n/* === Sidebar === */\r\n\r\n.tcw-sidebar {\r\n width: 40px;\r\n flex-shrink: 0;\r\n background: linear-gradient(180deg, var(--tcw-bg-elevated) 0%, var(--tcw-bg-surface) 100%);\r\n border-right: 1px solid var(--tcw-border);\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n padding: 6px 0;\r\n overflow: visible;\r\n box-shadow: var(--tcw-shadow-sm);\r\n}\r\n\r\n.tcw-tool-group-wrap {\r\n position: relative;\r\n}\r\n\r\n.tcw-sidebar-btn {\r\n width: 32px;\r\n height: 32px;\r\n margin: 1px 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n cursor: pointer;\r\n font-family: inherit;\r\n transition:\r\n background var(--tcw-dur-fast) var(--tcw-ease),\r\n color var(--tcw-dur-fast) var(--tcw-ease);\r\n position: relative;\r\n flex-shrink: 0;\r\n line-height: 1;\r\n border-radius: var(--tcw-radius);\r\n}\r\n\r\n.tcw-sidebar-btn:hover {\r\n color: var(--tcw-text);\r\n background: var(--tcw-hover-bg);\r\n}\r\n\r\n.tcw-sidebar-btn.tcw-active {\r\n color: var(--tcw-accent);\r\n background: var(--tcw-accent-soft);\r\n box-shadow: inset 2px 0 0 var(--tcw-accent);\r\n}\r\n\r\n.tcw-sidebar-btn.tcw-danger:hover {\r\n color: var(--tcw-red);\r\n background: var(--tcw-red-soft);\r\n}\r\n\r\n.tcw-multi-dot {\r\n position: absolute;\r\n bottom: 3px;\r\n right: 3px;\r\n width: 4px;\r\n height: 4px;\r\n border-radius: 50%;\r\n background: var(--tcw-text-muted);\r\n opacity: 0.7;\r\n}\r\n\r\n.tcw-sidebar-divider {\r\n width: 22px;\r\n height: 1px;\r\n background: var(--tcw-divider);\r\n margin: 6px 0;\r\n flex-shrink: 0;\r\n}\r\n\r\n.tcw-sidebar-spacer {\r\n flex: 1;\r\n}\r\n\r\n/* === Flyout === */\r\n\r\n.tcw-flyout {\r\n position: absolute;\r\n left: 100%;\r\n top: 0;\r\n margin-left: 6px;\r\n min-width: 180px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n z-index: 30;\r\n padding: 6px;\r\n backdrop-filter: blur(12px);\r\n -webkit-backdrop-filter: blur(12px);\r\n animation: tcw-slide-right var(--tcw-dur-normal) var(--tcw-ease-out);\r\n}\r\n\r\n@keyframes tcw-slide-right {\r\n from { opacity: 0; transform: translateX(-4px); }\r\n to { opacity: 1; transform: translateX(0); }\r\n}\r\n\r\n.tcw-flyout-header {\r\n text-transform: uppercase;\r\n font-size: 10px;\r\n color: var(--tcw-text-muted);\r\n letter-spacing: 0.08em;\r\n padding: 6px 10px 4px;\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-flyout-item {\r\n padding: 7px 10px;\r\n font-size: 12.5px;\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n width: 100%;\r\n display: block;\r\n border: none;\r\n background: transparent;\r\n text-align: left;\r\n font-family: inherit;\r\n border-radius: var(--tcw-radius-sm);\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-flyout-item:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-flyout-item.tcw-active {\r\n color: var(--tcw-accent);\r\n background: var(--tcw-accent-soft);\r\n font-weight: 600;\r\n}\r\n\r\n/* Pinned (favorited) flyout item — a star marker on the right. */\r\n.tcw-flyout-item.tcw-flyout-faved::after {\r\n content: '★';\r\n float: right;\r\n color: var(--tcw-accent);\r\n font-size: 11px;\r\n line-height: 1.4;\r\n}\r\n\r\n/* Favorites strip — pinned drawing tools above the tool groups. */\r\n.tcw-sidebar-favorites {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n}\r\n.tcw-sidebar-favorites .tcw-sidebar-btn {\r\n position: relative;\r\n}\r\n.tcw-sidebar-favorites .tcw-sidebar-btn::before {\r\n content: '';\r\n position: absolute;\r\n top: 3px;\r\n right: 3px;\r\n width: 4px;\r\n height: 4px;\r\n border-radius: 50%;\r\n background: var(--tcw-accent);\r\n opacity: 0.7;\r\n}\r\n\r\n/* === Modal === */\r\n\r\n.tcw-modal-backdrop {\r\n position: fixed;\r\n inset: 0;\r\n background: rgba(8, 10, 18, 0.55);\r\n backdrop-filter: blur(6px) saturate(140%);\r\n -webkit-backdrop-filter: blur(6px) saturate(140%);\r\n z-index: 100;\r\n animation: tcw-fade-in var(--tcw-dur-normal) var(--tcw-ease-out);\r\n}\r\n\r\n@keyframes tcw-fade-in {\r\n from { opacity: 0; }\r\n to { opacity: 1; }\r\n}\r\n\r\n.tcw-modal {\r\n position: fixed;\r\n z-index: 101;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-xl);\r\n width: 520px;\r\n max-width: 92vw;\r\n max-height: 82vh;\r\n display: flex;\r\n flex-direction: column;\r\n box-shadow: var(--tcw-shadow-xl);\r\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\r\n}\r\n\r\n@keyframes tcw-modal-in {\r\n from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }\r\n to { opacity: 1; transform: translate(-50%, -50%) scale(1); }\r\n}\r\n\r\n.tcw-modal-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 18px 22px;\r\n border-bottom: 1px solid var(--tcw-divider);\r\n}\r\n\r\n.tcw-modal-header h3 {\r\n font-size: 15px;\r\n font-weight: 650;\r\n margin: 0;\r\n color: var(--tcw-text);\r\n letter-spacing: -0.015em;\r\n}\r\n\r\n.tcw-modal-close {\r\n width: 28px;\r\n height: 28px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n cursor: pointer;\r\n border-radius: var(--tcw-radius);\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-modal-close:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-modal-tabs {\r\n display: flex;\r\n gap: 4px;\r\n padding: 0 18px;\r\n border-bottom: 1px solid var(--tcw-divider);\r\n}\r\n\r\n.tcw-modal-tab {\r\n padding: 11px 14px;\r\n font-size: 12px;\r\n font-weight: 500;\r\n color: var(--tcw-text-muted);\r\n border: none;\r\n background: transparent;\r\n cursor: pointer;\r\n border-bottom: 2px solid transparent;\r\n margin-bottom: -1px;\r\n transition: color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\r\n font-family: inherit;\r\n text-transform: capitalize;\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-modal-tab:hover {\r\n color: var(--tcw-text-dim);\r\n}\r\n\r\n.tcw-modal-tab.tcw-active {\r\n color: var(--tcw-accent);\r\n border-bottom-color: var(--tcw-accent);\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-modal-body {\r\n padding: 20px 22px;\r\n overflow-y: auto;\r\n flex: 1;\r\n}\r\n\r\n.tcw-settings-section {\r\n margin-bottom: 22px;\r\n}\r\n\r\n.tcw-settings-section:last-child {\r\n margin-bottom: 0;\r\n}\r\n\r\n.tcw-settings-section-title {\r\n font-size: 10.5px;\r\n font-weight: 600;\r\n text-transform: uppercase;\r\n letter-spacing: 0.09em;\r\n color: var(--tcw-text-muted);\r\n margin-bottom: 12px;\r\n}\r\n\r\n.tcw-settings-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 0;\r\n}\r\n\r\n.tcw-settings-row + .tcw-settings-row {\r\n border-top: 1px solid var(--tcw-divider);\r\n}\r\n\r\n.tcw-settings-label {\r\n font-size: 13px;\r\n color: var(--tcw-text-dim);\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-color-picker-wrap {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n\r\n.tcw-color-picker-wrap input[type='color'] {\r\n width: 28px;\r\n height: 28px;\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-sm);\r\n background: transparent;\r\n cursor: pointer;\r\n padding: 2px;\r\n}\r\n\r\n.tcw-color-picker-wrap input[type='color']::-webkit-color-swatch-wrapper {\r\n padding: 0;\r\n}\r\n\r\n.tcw-color-picker-wrap input[type='color']::-webkit-color-swatch {\r\n border: none;\r\n border-radius: 2px;\r\n}\r\n\r\n.tcw-color-hex {\r\n font-size: 11px;\r\n font-family: var(--tcw-font-mono);\r\n color: var(--tcw-text-muted);\r\n min-width: 64px;\r\n letter-spacing: 0.01em;\r\n}\r\n\r\n.tcw-toggle {\r\n width: 36px;\r\n height: 20px;\r\n background: rgba(255, 255, 255, 0.12);\r\n border-radius: 10px;\r\n position: relative;\r\n cursor: pointer;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\r\n border: none;\r\n padding: 0;\r\n flex-shrink: 0;\r\n}\r\n\r\n.tcw-toggle::after {\r\n content: '';\r\n position: absolute;\r\n top: 2px;\r\n left: 2px;\r\n width: 16px;\r\n height: 16px;\r\n border-radius: 50%;\r\n background: var(--tcw-text-muted);\r\n transition:\r\n left var(--tcw-dur-normal) var(--tcw-ease-out),\r\n background var(--tcw-dur-fast) var(--tcw-ease);\r\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.tcw-toggle.tcw-on {\r\n background: var(--tcw-accent);\r\n box-shadow: 0 0 0 2px var(--tcw-accent-glow);\r\n}\r\n\r\n.tcw-toggle.tcw-on::after {\r\n left: 18px;\r\n background: #fff;\r\n}\r\n\r\n.tcw-root[data-tcw-theme='light'] .tcw-toggle {\r\n background: rgba(0, 0, 0, 0.12);\r\n}\r\n\r\n.tcw-root[data-tcw-theme='light'] .tcw-toggle::after {\r\n background: #999;\r\n}\r\n\r\n.tcw-root[data-tcw-theme='light'] .tcw-toggle.tcw-on {\r\n background: var(--tcw-accent);\r\n}\r\n\r\n.tcw-root[data-tcw-theme='light'] .tcw-toggle.tcw-on::after {\r\n background: #fff;\r\n}\r\n\r\n.tcw-settings-select {\r\n padding: 6px 10px;\r\n font-size: 12px;\r\n font-family: inherit;\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius);\r\n color: var(--tcw-text);\r\n cursor: pointer;\r\n transition: border-color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-settings-select:hover {\r\n border-color: var(--tcw-border-strong);\r\n}\r\n\r\n.tcw-settings-select:focus-visible {\r\n outline: none;\r\n border-color: var(--tcw-accent);\r\n box-shadow: var(--tcw-ring);\r\n}\r\n\r\n.tcw-modal-footer {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 14px 22px;\r\n border-top: 1px solid var(--tcw-divider);\r\n background: var(--tcw-bg-surface);\r\n border-radius: 0 0 var(--tcw-radius-xl) var(--tcw-radius-xl);\r\n}\r\n\r\n.tcw-reset-link {\r\n font-size: 12px;\r\n color: var(--tcw-text-muted);\r\n cursor: pointer;\r\n border: none;\r\n background: transparent;\r\n font-family: inherit;\r\n text-decoration: underline;\r\n text-underline-offset: 2px;\r\n text-decoration-color: var(--tcw-border-strong);\r\n transition: color var(--tcw-dur-fast) var(--tcw-ease), text-decoration-color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-reset-link:hover {\r\n color: var(--tcw-text-dim);\r\n text-decoration-color: currentColor;\r\n}\r\n\r\n.tcw-done-btn {\r\n padding: 8px 18px;\r\n font-size: 12.5px;\r\n font-weight: 600;\r\n background: var(--tcw-accent);\r\n color: #fff;\r\n border: none;\r\n border-radius: var(--tcw-radius);\r\n cursor: pointer;\r\n font-family: inherit;\r\n transition:\r\n background var(--tcw-dur-fast) var(--tcw-ease),\r\n transform var(--tcw-dur-fast) var(--tcw-ease),\r\n box-shadow var(--tcw-dur-fast) var(--tcw-ease);\r\n letter-spacing: -0.005em;\r\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.15);\r\n}\r\n\r\n.tcw-done-btn:hover {\r\n background: var(--tcw-accent-hover);\r\n box-shadow: var(--tcw-shadow-md), 0 0 0 3px var(--tcw-accent-glow);\r\n}\r\n\r\n.tcw-done-btn:active {\r\n transform: translateY(0.5px);\r\n}\r\n\r\n/* === Status Bar === */\r\n\r\n.tcw-statusbar {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 7px 16px;\r\n border-top: 1px solid var(--tcw-border);\r\n background: var(--tcw-bg-surface);\r\n font-size: 11px;\r\n color: var(--tcw-text-muted);\r\n flex-shrink: 0;\r\n font-feature-settings: 'tnum';\r\n}\r\n\r\n.tcw-status-indicator {\r\n display: flex;\r\n align-items: center;\r\n gap: 7px;\r\n font-weight: 500;\r\n}\r\n\r\n.tcw-status-dot {\r\n width: 7px;\r\n height: 7px;\r\n border-radius: 50%;\r\n background: var(--tcw-text-muted);\r\n transition: background var(--tcw-dur-normal) var(--tcw-ease), box-shadow var(--tcw-dur-normal) var(--tcw-ease);\r\n position: relative;\r\n}\r\n\r\n.tcw-status-dot.tcw-connected {\r\n background: var(--tcw-green);\r\n box-shadow: 0 0 0 3px rgba(38, 161, 123, 0.18);\r\n}\r\n\r\n.tcw-status-dot.tcw-connected::after {\r\n content: '';\r\n position: absolute;\r\n inset: -3px;\r\n border-radius: 50%;\r\n border: 2px solid var(--tcw-green);\r\n opacity: 0;\r\n animation: tcw-pulse 2.2s ease-out infinite;\r\n}\r\n\r\n@keyframes tcw-pulse {\r\n 0% { opacity: 0.6; transform: scale(0.6); }\r\n 100% { opacity: 0; transform: scale(2.2); }\r\n}\r\n\r\n.tcw-status-dot.tcw-error {\r\n background: var(--tcw-red);\r\n box-shadow: 0 0 0 3px rgba(242, 54, 69, 0.2);\r\n}\r\n\r\n/* === Command Palette === */\r\n\r\n.tcw-cmd-palette {\r\n position: fixed;\r\n z-index: 102;\r\n top: 18%;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-xl);\r\n width: 560px;\r\n max-width: 92vw;\r\n max-height: 62vh;\r\n display: flex;\r\n flex-direction: column;\r\n box-shadow: var(--tcw-shadow-xl);\r\n overflow: hidden;\r\n backdrop-filter: blur(20px);\r\n -webkit-backdrop-filter: blur(20px);\r\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\r\n}\r\n\r\n.tcw-cmd-header {\r\n display: flex;\r\n align-items: center;\r\n padding: 14px 18px;\r\n border-bottom: 1px solid var(--tcw-divider);\r\n gap: 12px;\r\n}\r\n\r\n.tcw-cmd-icon {\r\n font-size: 18px;\r\n color: var(--tcw-text-muted);\r\n flex-shrink: 0;\r\n display: inline-flex;\r\n align-items: center;\r\n}\r\n\r\n.tcw-cmd-input {\r\n flex: 1;\r\n background: transparent;\r\n border: none;\r\n outline: none;\r\n font-size: 14.5px;\r\n font-family: inherit;\r\n color: var(--tcw-text);\r\n caret-color: var(--tcw-accent);\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-cmd-input::placeholder {\r\n color: var(--tcw-text-muted);\r\n}\r\n\r\n.tcw-cmd-hint {\r\n font-size: 10px;\r\n color: var(--tcw-text-muted);\r\n font-family: var(--tcw-font-mono);\r\n border: 1px solid var(--tcw-border);\r\n background: var(--tcw-bg-surface);\r\n padding: 3px 7px;\r\n border-radius: 4px;\r\n flex-shrink: 0;\r\n box-shadow: inset 0 -1px 0 var(--tcw-border);\r\n}\r\n\r\n.tcw-cmd-list {\r\n overflow-y: auto;\r\n flex: 1;\r\n padding: 6px;\r\n max-height: 380px;\r\n}\r\n\r\n.tcw-cmd-category {\r\n text-transform: uppercase;\r\n font-size: 10px;\r\n color: var(--tcw-text-muted);\r\n letter-spacing: 0.09em;\r\n padding: 10px 10px 4px;\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-cmd-item {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 9px 12px;\r\n font-size: 13px;\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n width: 100%;\r\n border: none;\r\n background: transparent;\r\n font-family: inherit;\r\n text-align: left;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n gap: 10px;\r\n border-radius: var(--tcw-radius);\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-cmd-item:hover,\r\n.tcw-cmd-item.tcw-selected {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-cmd-item.tcw-selected {\r\n box-shadow: inset 2px 0 0 var(--tcw-accent);\r\n}\r\n\r\n.tcw-cmd-item.tcw-active .tcw-cmd-item-label {\r\n color: var(--tcw-accent);\r\n font-weight: 600;\r\n}\r\n\r\n.tcw-cmd-item-label {\r\n flex: 1;\r\n}\r\n\r\n.tcw-cmd-check {\r\n color: var(--tcw-accent);\r\n font-size: 14px;\r\n font-weight: 700;\r\n}\r\n\r\n.tcw-cmd-kbd {\r\n font-size: 10px;\r\n font-family: var(--tcw-font-mono);\r\n color: var(--tcw-text-muted);\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n padding: 2px 6px;\r\n border-radius: 4px;\r\n box-shadow: inset 0 -1px 0 var(--tcw-border);\r\n}\r\n\r\n.tcw-cmd-empty {\r\n padding: 32px 16px;\r\n text-align: center;\r\n color: var(--tcw-text-muted);\r\n font-size: 13px;\r\n}\r\n\r\n.tcw-cmd-footer {\r\n display: flex;\r\n align-items: center;\r\n gap: 18px;\r\n padding: 10px 18px;\r\n border-top: 1px solid var(--tcw-divider);\r\n font-size: 11px;\r\n color: var(--tcw-text-muted);\r\n background: var(--tcw-bg-surface);\r\n}\r\n\r\n/* === Watchlist === */\r\n\r\n.tcw-watchlist {\r\n width: 220px;\r\n flex-shrink: 0;\r\n background: var(--tcw-bg-surface);\r\n border-left: 1px solid var(--tcw-border);\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n box-shadow: var(--tcw-shadow-sm);\r\n}\r\n\r\n.tcw-watchlist-header {\r\n padding: 10px 14px;\r\n font-size: 11px;\r\n font-weight: 600;\r\n text-transform: uppercase;\r\n letter-spacing: 0.08em;\r\n color: var(--tcw-text-muted);\r\n border-bottom: 1px solid var(--tcw-divider);\r\n}\r\n\r\n.tcw-watchlist-list {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 4px 0;\r\n}\r\n\r\n.tcw-watchlist-row {\r\n display: grid;\r\n grid-template-columns: 1fr auto auto;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 8px 12px;\r\n cursor: pointer;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\r\n border-left: 2px solid transparent;\r\n outline: none;\r\n}\r\n\r\n.tcw-watchlist-row:hover {\r\n background: var(--tcw-hover-bg);\r\n}\r\n\r\n.tcw-watchlist-row:focus-visible {\r\n background: var(--tcw-hover-bg);\r\n border-left-color: var(--tcw-accent);\r\n}\r\n\r\n.tcw-watchlist-row.tcw-watchlist-active {\r\n background: var(--tcw-accent-soft);\r\n border-left-color: var(--tcw-accent);\r\n}\r\n\r\n.tcw-watchlist-symbol {\r\n font-size: 12.5px;\r\n font-weight: 600;\r\n color: var(--tcw-text);\r\n letter-spacing: -0.005em;\r\n white-space: nowrap;\r\n}\r\n\r\n.tcw-watchlist-spark {\r\n width: 56px;\r\n height: 22px;\r\n align-self: center;\r\n}\r\n\r\n.tcw-watchlist-stats {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: flex-end;\r\n gap: 1px;\r\n font-variant-numeric: tabular-nums;\r\n font-family: var(--tcw-font-mono);\r\n}\r\n\r\n.tcw-watchlist-price {\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n font-weight: 500;\r\n}\r\n\r\n.tcw-watchlist-change {\r\n font-size: 10.5px;\r\n color: var(--tcw-text-muted);\r\n font-weight: 500;\r\n}\r\n\r\n.tcw-watchlist-change.tcw-up {\r\n color: var(--tcw-green);\r\n}\r\n\r\n.tcw-watchlist-change.tcw-down {\r\n color: var(--tcw-red);\r\n}\r\n\r\n@media (max-width: 768px) {\r\n .tcw-watchlist {\r\n display: none;\r\n }\r\n}\r\n\r\n/* === Toast === */\r\n\r\n.tcw-toast {\r\n position: absolute;\r\n bottom: 60px;\r\n left: 50%;\r\n transform: translate(-50%, 12px);\r\n z-index: 40;\r\n padding: 9px 14px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: 9999px;\r\n box-shadow: var(--tcw-shadow-lg);\r\n font-size: 12.5px;\r\n font-weight: 500;\r\n color: var(--tcw-text);\r\n opacity: 0;\r\n transition: opacity var(--tcw-dur-normal) var(--tcw-ease-out), transform var(--tcw-dur-normal) var(--tcw-ease-out);\r\n pointer-events: none;\r\n max-width: calc(100% - 32px);\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n.tcw-toast.tcw-toast-in {\r\n opacity: 1;\r\n transform: translate(-50%, 0);\r\n}\r\n\r\n.tcw-toast-error {\r\n border-color: var(--tcw-red);\r\n color: var(--tcw-red);\r\n}\r\n\r\n/* === Replay scrubber === */\r\n\r\n.tcw-replay-bar {\r\n position: absolute;\r\n left: 50%;\r\n bottom: 16px;\r\n transform: translateX(-50%);\r\n z-index: 25;\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 6px 10px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: 9999px;\r\n box-shadow: var(--tcw-shadow-lg);\r\n backdrop-filter: blur(12px);\r\n -webkit-backdrop-filter: blur(12px);\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n animation: tcw-pop-in var(--tcw-dur-normal) var(--tcw-ease-out);\r\n}\r\n\r\n.tcw-replay-btn {\r\n width: 28px;\r\n height: 28px;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-dim);\r\n border-radius: 9999px;\r\n cursor: pointer;\r\n font-family: inherit;\r\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\r\n}\r\n\r\n.tcw-replay-btn:hover {\r\n background: var(--tcw-hover-bg);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-replay-btn.tcw-replay-play {\r\n background: var(--tcw-accent);\r\n color: #fff;\r\n width: 32px;\r\n height: 32px;\r\n box-shadow: 0 0 0 3px var(--tcw-accent-glow);\r\n}\r\n\r\n.tcw-replay-btn.tcw-replay-play:hover {\r\n background: var(--tcw-accent-hover);\r\n}\r\n\r\n.tcw-replay-scrubber {\r\n appearance: none;\r\n -webkit-appearance: none;\r\n width: 220px;\r\n height: 4px;\r\n background: var(--tcw-border-strong);\r\n border-radius: 2px;\r\n outline: none;\r\n cursor: pointer;\r\n}\r\n\r\n.tcw-replay-scrubber::-webkit-slider-thumb {\r\n -webkit-appearance: none;\r\n appearance: none;\r\n width: 14px;\r\n height: 14px;\r\n border-radius: 50%;\r\n background: var(--tcw-accent);\r\n border: 2px solid var(--tcw-bg-elevated);\r\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\r\n cursor: pointer;\r\n}\r\n\r\n.tcw-replay-scrubber::-moz-range-thumb {\r\n width: 14px;\r\n height: 14px;\r\n border-radius: 50%;\r\n background: var(--tcw-accent);\r\n border: 2px solid var(--tcw-bg-elevated);\r\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\r\n cursor: pointer;\r\n}\r\n\r\n.tcw-replay-progress {\r\n font-size: 11px;\r\n font-family: var(--tcw-font-mono);\r\n color: var(--tcw-text-muted);\r\n min-width: 64px;\r\n text-align: center;\r\n font-feature-settings: 'tnum';\r\n}\r\n\r\n.tcw-replay-speed {\r\n padding: 4px 8px;\r\n font-size: 11px;\r\n font-family: var(--tcw-font-mono);\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius);\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n}\r\n\r\n.tcw-replay-speed:hover {\r\n border-color: var(--tcw-border-strong);\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .tcw-replay-scrubber {\r\n width: 140px;\r\n }\r\n .tcw-replay-progress {\r\n display: none;\r\n }\r\n}\r\n\r\n/* === Hotkey sheet === */\r\n\r\n.tcw-hotkey-grid {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr;\r\n gap: 24px 32px;\r\n}\r\n\r\n.tcw-hotkey-section .tcw-settings-section-title {\r\n margin-bottom: 8px;\r\n}\r\n\r\n.tcw-hotkey-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 12px;\r\n padding: 6px 0;\r\n border-bottom: 1px solid var(--tcw-divider);\r\n}\r\n\r\n.tcw-hotkey-row:last-child {\r\n border-bottom: none;\r\n}\r\n\r\n.tcw-hotkey-keys {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n flex-shrink: 0;\r\n}\r\n\r\n.tcw-hotkey-sep {\r\n font-size: 10px;\r\n color: var(--tcw-text-muted);\r\n}\r\n\r\n.tcw-hotkey-label {\r\n font-size: 12.5px;\r\n color: var(--tcw-text-dim);\r\n text-align: right;\r\n letter-spacing: -0.005em;\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .tcw-hotkey-grid {\r\n grid-template-columns: 1fr;\r\n gap: 18px;\r\n }\r\n}\r\n\r\n/* === Scrollbar (subtle, premium feel) === */\r\n\r\n.tcw-dropdown::-webkit-scrollbar,\r\n.tcw-modal-body::-webkit-scrollbar,\r\n.tcw-cmd-list::-webkit-scrollbar {\r\n width: 8px;\r\n height: 8px;\r\n}\r\n\r\n.tcw-dropdown::-webkit-scrollbar-track,\r\n.tcw-modal-body::-webkit-scrollbar-track,\r\n.tcw-cmd-list::-webkit-scrollbar-track {\r\n background: transparent;\r\n}\r\n\r\n.tcw-dropdown::-webkit-scrollbar-thumb,\r\n.tcw-modal-body::-webkit-scrollbar-thumb,\r\n.tcw-cmd-list::-webkit-scrollbar-thumb {\r\n background: var(--tcw-border-strong);\r\n border-radius: 4px;\r\n border: 2px solid transparent;\r\n background-clip: padding-box;\r\n}\r\n\r\n.tcw-dropdown::-webkit-scrollbar-thumb:hover,\r\n.tcw-modal-body::-webkit-scrollbar-thumb:hover,\r\n.tcw-cmd-list::-webkit-scrollbar-thumb:hover {\r\n background: var(--tcw-text-muted);\r\n background-clip: padding-box;\r\n border: 2px solid transparent;\r\n}\r\n\r\n/* === Responsive === */\r\n\r\n@media (max-width: 768px) {\r\n .tcw-toolbar {\r\n padding: 0 4px;\r\n height: 44px; /* Apple HIG minimum touch target */\r\n }\r\n .tcw-toolbar-sep {\r\n display: none;\r\n }\r\n .tcw-indicator-chips {\r\n display: none;\r\n }\r\n .tcw-btn,\r\n .tcw-dropdown-trigger {\r\n padding: 10px 12px; /* fatter tap target */\r\n font-size: 13px;\r\n }\r\n .tcw-btn-icon {\r\n width: 40px;\r\n height: 40px;\r\n }\r\n .tcw-sidebar {\r\n width: 44px;\r\n }\r\n .tcw-sidebar-btn {\r\n width: 40px;\r\n height: 40px;\r\n }\r\n .tcw-modal,\r\n .tcw-cmd-palette {\r\n width: 94vw;\r\n border-radius: var(--tcw-radius-lg);\r\n }\r\n\r\n /* Hide the right-side watchlist on tablets too — already declared but\r\n * grouped here for clarity. */\r\n .tcw-watchlist {\r\n display: none;\r\n }\r\n\r\n /* Replay scrubber compact mode */\r\n .tcw-replay-scrubber {\r\n width: 120px;\r\n }\r\n .tcw-replay-progress {\r\n display: none;\r\n }\r\n}\r\n\r\n/* === Mobile bottom-sheet pattern ===\r\n * On phones, swap floating-centered modals for full-width sheets that slide\r\n * up from the bottom. Bigger hit targets, no awkward off-screen clipping,\r\n * matches how every modern iOS/Android app handles overflow UI.\r\n */\r\n@media (max-width: 640px) {\r\n .tcw-modal,\r\n .tcw-cmd-palette {\r\n top: auto;\r\n bottom: 0;\r\n left: 0;\r\n right: 0;\r\n transform: none;\r\n width: 100vw;\r\n max-width: 100vw;\r\n max-height: 92vh;\r\n border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;\r\n border-bottom: none;\r\n /* Grab handle */\r\n padding-top: 8px;\r\n }\r\n\r\n /* Visual \"grab handle\" affordance — a short pill at the top of every sheet */\r\n .tcw-modal::before,\r\n .tcw-cmd-palette::before {\r\n content: '';\r\n display: block;\r\n width: 36px;\r\n height: 4px;\r\n border-radius: 2px;\r\n background: var(--tcw-border-strong);\r\n margin: 0 auto 8px;\r\n opacity: 0.7;\r\n }\r\n\r\n /* Reuse the existing modal-in animation but slide from below instead of\r\n * popping from center, so the entrance reads as a sheet, not a dialog. */\r\n @keyframes tcw-modal-in {\r\n from { opacity: 0; transform: translateY(20px); }\r\n to { opacity: 1; transform: translateY(0); }\r\n }\r\n\r\n .tcw-modal,\r\n .tcw-cmd-palette {\r\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\r\n }\r\n\r\n /* Safe-area-aware footer padding for iPhone notch / home indicator */\r\n .tcw-modal-footer,\r\n .tcw-cmd-footer {\r\n padding-bottom: max(14px, env(safe-area-inset-bottom));\r\n }\r\n\r\n /* Larger tap targets inside sheets */\r\n .tcw-modal-tab {\r\n padding: 14px 16px;\r\n }\r\n .tcw-cmd-item {\r\n padding: 12px 14px;\r\n font-size: 14px;\r\n }\r\n .tcw-dropdown-item {\r\n padding: 12px 12px;\r\n font-size: 14px;\r\n }\r\n\r\n /* Hotkey sheet — single column on phones */\r\n .tcw-hotkey-grid {\r\n grid-template-columns: 1fr;\r\n }\r\n}\r\n\r\n/* === Price alerts panel === */\r\n\r\n.tcw-alerts-panel {\r\n position: absolute;\r\n top: 50px;\r\n right: 12px;\r\n z-index: 40;\r\n width: 300px;\r\n max-width: calc(100vw - 24px);\r\n display: flex;\r\n flex-direction: column;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n overflow: hidden;\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n\r\n@keyframes tcw-alerts-in {\r\n from { opacity: 0; transform: translateY(-6px) scale(0.98); }\r\n to { opacity: 1; transform: none; }\r\n}\r\n\r\n.tcw-alerts-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 12px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n color: var(--tcw-text);\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n\r\n.tcw-alerts-close {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-alerts-close:hover {\r\n background: var(--tcw-bg-surface);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-alerts-form {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr;\r\n gap: 8px;\r\n padding: 12px;\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n\r\n.tcw-alerts-form input,\r\n.tcw-alerts-form select {\r\n width: 100%;\r\n min-width: 0;\r\n box-sizing: border-box;\r\n height: 32px;\r\n padding: 0 8px;\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n outline: none;\r\n}\r\n.tcw-alerts-form input:focus,\r\n.tcw-alerts-form select:focus {\r\n border-color: var(--tcw-accent);\r\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\r\n}\r\n.tcw-alerts-message,\r\n.tcw-alerts-source {\r\n grid-column: 1 / -1;\r\n}\r\n\r\n.tcw-alerts-add {\r\n grid-column: 1 / -1;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 6px;\r\n height: 34px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: #fff;\r\n background: var(--tcw-accent);\r\n border: none;\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-alerts-add:hover {\r\n background: var(--tcw-accent-hover);\r\n}\r\n\r\n.tcw-alerts-list {\r\n max-height: 260px;\r\n overflow-y: auto;\r\n padding: 6px;\r\n}\r\n\r\n.tcw-alerts-empty {\r\n padding: 18px 12px;\r\n text-align: center;\r\n font-size: 12px;\r\n color: var(--tcw-text-muted);\r\n line-height: 1.5;\r\n}\r\n\r\n.tcw-alerts-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 8px;\r\n padding: 8px 8px;\r\n border-radius: var(--tcw-radius-sm);\r\n}\r\n.tcw-alerts-row:hover {\r\n background: var(--tcw-bg-surface);\r\n}\r\n.tcw-alerts-triggered {\r\n background: var(--tcw-accent-soft);\r\n}\r\n\r\n.tcw-alerts-info {\r\n min-width: 0;\r\n}\r\n.tcw-alerts-row-main {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--tcw-text);\r\n font-variant-numeric: tabular-nums;\r\n}\r\n.tcw-alerts-row-note {\r\n margin-top: 2px;\r\n font-size: 11px;\r\n color: var(--tcw-text-muted);\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n.tcw-alerts-badge {\r\n font-size: 9px;\r\n font-weight: 700;\r\n text-transform: uppercase;\r\n letter-spacing: 0.04em;\r\n padding: 2px 5px;\r\n border-radius: 999px;\r\n color: var(--tcw-accent);\r\n background: var(--tcw-accent-soft);\r\n}\r\n\r\n.tcw-alerts-del {\r\n flex-shrink: 0;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 28px;\r\n height: 28px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-alerts-del:hover {\r\n background: var(--tcw-red-soft);\r\n color: var(--tcw-red);\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .tcw-alerts-panel {\r\n top: auto;\r\n bottom: 0;\r\n left: 0;\r\n right: 0;\r\n width: 100vw;\r\n max-width: 100vw;\r\n border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;\r\n }\r\n .tcw-alerts-list {\r\n max-height: 40vh;\r\n padding-bottom: max(8px, env(safe-area-inset-bottom));\r\n }\r\n}\r\n\r\n/* === Data Window === */\r\n\r\n.tcw-datawin {\r\n position: absolute;\r\n top: 50px;\r\n right: 12px;\r\n z-index: 38;\r\n width: 200px;\r\n display: flex;\r\n flex-direction: column;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n overflow: hidden;\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n.tcw-datawin-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 9px 12px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--tcw-text);\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n.tcw-datawin-close {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 24px;\r\n height: 24px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-datawin-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\r\n.tcw-datawin-body { padding: 6px 4px; max-height: 360px; overflow-y: auto; }\r\n.tcw-datawin-empty { padding: 14px; text-align: center; font-size: 12px; color: var(--tcw-text-muted); }\r\n.tcw-datawin-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 10px;\r\n padding: 3px 8px;\r\n font-size: 12px;\r\n}\r\n.tcw-datawin-label { color: var(--tcw-text-muted); }\r\n.tcw-datawin-value { color: var(--tcw-text); font-variant-numeric: tabular-nums; font-weight: 600; }\r\n.tcw-datawin-value.tcw-up { color: var(--tcw-green); }\r\n.tcw-datawin-value.tcw-down { color: var(--tcw-red); }\r\n.tcw-datawin-sub {\r\n margin: 6px 8px 2px;\r\n font-size: 10px;\r\n font-weight: 700;\r\n text-transform: uppercase;\r\n letter-spacing: 0.04em;\r\n color: var(--tcw-text-muted);\r\n border-top: 1px solid var(--tcw-border);\r\n padding-top: 6px;\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .tcw-datawin { top: auto; bottom: 0; left: 0; right: 0; width: 100vw; border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0; }\r\n}\r\n\r\n/* === Depth-of-market ladder === */\r\n\r\n.tcw-ladder {\r\n position: absolute;\r\n top: 50px;\r\n right: 12px;\r\n z-index: 41;\r\n width: 240px;\r\n display: flex;\r\n flex-direction: column;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n overflow: hidden;\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n.tcw-ladder-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 12px;\r\n font-size: 13px;\r\n font-weight: 600;\r\n color: var(--tcw-text);\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n.tcw-ladder-close {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-ladder-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\r\n.tcw-ladder-cols {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr 1fr;\r\n padding: 4px 0;\r\n font-size: 10px;\r\n font-weight: 700;\r\n text-transform: uppercase;\r\n letter-spacing: 0.04em;\r\n color: var(--tcw-text-muted);\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n.tcw-ladder-cols span { text-align: center; }\r\n.tcw-ladder-body { max-height: 360px; overflow-y: auto; }\r\n.tcw-ladder-empty { padding: 18px; text-align: center; font-size: 12px; color: var(--tcw-text-muted); }\r\n\r\n.tcw-ladder-row {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr 1fr;\r\n height: 22px;\r\n font-variant-numeric: tabular-nums;\r\n}\r\n.tcw-ladder-cell {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n border: none;\r\n background: transparent;\r\n font-size: 11px;\r\n cursor: pointer;\r\n font-variant-numeric: tabular-nums;\r\n overflow: hidden;\r\n}\r\n.tcw-ladder-cell:disabled { cursor: default; }\r\n/* Depth bar grows from the centre column outward. */\r\n.tcw-ladder-cell::before {\r\n content: '';\r\n position: absolute;\r\n top: 1px; bottom: 1px;\r\n width: var(--w, 0%);\r\n}\r\n.tcw-ladder-bid { justify-content: flex-end; padding-right: 8px; color: var(--tcw-green); }\r\n.tcw-ladder-bid::before { right: 0; background: var(--tcw-green-soft); }\r\n.tcw-ladder-bid span, .tcw-ladder-bid { position: relative; }\r\n.tcw-ladder-ask { justify-content: flex-start; padding-left: 8px; color: var(--tcw-red); }\r\n.tcw-ladder-ask::before { left: 0; background: var(--tcw-red-soft); }\r\n.tcw-ladder-cell:not(:disabled):hover::before { opacity: 0.7; filter: brightness(1.4); }\r\n.tcw-ladder-cell > * { position: relative; }\r\n.tcw-ladder-price {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--tcw-text-dim);\r\n border-left: 1px solid var(--tcw-border);\r\n border-right: 1px solid var(--tcw-border);\r\n}\r\n.tcw-ladder-price.tcw-ask { color: var(--tcw-red); }\r\n.tcw-ladder-price.tcw-bid { color: var(--tcw-green); }\r\n\r\n@media (max-width: 640px) {\r\n .tcw-ladder { top: auto; bottom: 0; left: 0; right: 0; width: 100vw; border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0; }\r\n .tcw-ladder-body { max-height: 45vh; padding-bottom: max(0px, env(safe-area-inset-bottom)); }\r\n}\r\n\r\n/* === Bracket order placement === */\r\n\r\n.tcw-btn-long:hover { color: var(--tcw-green) !important; }\r\n.tcw-btn-short:hover { color: var(--tcw-red) !important; }\r\n\r\n.tcw-bracket-bar {\r\n position: absolute;\r\n top: 52px;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n z-index: 45;\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n padding: 7px 8px 7px 14px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: 999px;\r\n box-shadow: var(--tcw-shadow-lg);\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n.tcw-bracket-label {\r\n font-size: 12px;\r\n font-weight: 700;\r\n}\r\n.tcw-bracket-label[data-side='buy'] { color: var(--tcw-green); }\r\n.tcw-bracket-label[data-side='sell'] { color: var(--tcw-red); }\r\n.tcw-bracket-hint {\r\n font-size: 11px;\r\n color: var(--tcw-text-muted);\r\n}\r\n.tcw-bracket-cancel, .tcw-bracket-confirm {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 5px;\r\n height: 30px;\r\n padding: 0 12px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n border: none;\r\n border-radius: 999px;\r\n cursor: pointer;\r\n}\r\n.tcw-bracket-cancel {\r\n color: var(--tcw-text-dim);\r\n background: var(--tcw-bg-surface);\r\n}\r\n.tcw-bracket-cancel:hover { color: var(--tcw-text); }\r\n.tcw-bracket-confirm {\r\n color: #fff;\r\n background: var(--tcw-accent);\r\n}\r\n.tcw-bracket-confirm:hover { background: var(--tcw-accent-hover); }\r\n\r\n@media (max-width: 640px) {\r\n .tcw-bracket-bar { width: calc(100vw - 24px); justify-content: space-between; }\r\n .tcw-bracket-hint { display: none; }\r\n}\r\n\r\n/* === Drawing style + templates popover === */\r\n\r\n.tcw-style-panel {\r\n position: absolute;\r\n bottom: 12px;\r\n left: 52px;\r\n z-index: 40;\r\n width: 220px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n padding: 12px;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n.tcw-style-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--tcw-text);\r\n}\r\n.tcw-style-close {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 24px;\r\n height: 24px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-style-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\r\n\r\n.tcw-style-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\r\n.tcw-style-swatch {\r\n width: 18px;\r\n height: 18px;\r\n border-radius: 50%;\r\n border: 1px solid var(--tcw-border-strong);\r\n cursor: pointer;\r\n padding: 0;\r\n}\r\n.tcw-style-swatch.tcw-on { outline: 2px solid var(--tcw-accent); outline-offset: 1px; }\r\n.tcw-style-picker {\r\n width: 22px;\r\n height: 22px;\r\n padding: 0;\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n background: transparent;\r\n cursor: pointer;\r\n}\r\n.tcw-style-width, .tcw-style-dash {\r\n flex: 1;\r\n min-width: 0;\r\n height: 26px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n color: var(--tcw-text-dim);\r\n cursor: pointer;\r\n font-size: 11px;\r\n}\r\n.tcw-style-width span { width: 16px; background: currentColor; border-radius: 2px; }\r\n.tcw-style-width.tcw-on, .tcw-style-dash.tcw-on {\r\n border-color: var(--tcw-accent);\r\n color: var(--tcw-accent);\r\n}\r\n\r\n.tcw-style-subhead {\r\n font-size: 10px;\r\n font-weight: 700;\r\n text-transform: uppercase;\r\n letter-spacing: 0.05em;\r\n color: var(--tcw-text-muted);\r\n margin-top: 2px;\r\n}\r\n.tcw-style-save { display: flex; gap: 6px; }\r\n.tcw-style-name {\r\n flex: 1;\r\n min-width: 0;\r\n height: 28px;\r\n padding: 0 8px;\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n outline: none;\r\n}\r\n.tcw-style-name:focus { border-color: var(--tcw-accent); }\r\n.tcw-style-savebtn {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 4px;\r\n padding: 0 10px;\r\n height: 28px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: #fff;\r\n background: var(--tcw-accent);\r\n border: none;\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-style-savebtn:hover { background: var(--tcw-accent-hover); }\r\n\r\n.tcw-style-templates { display: flex; flex-direction: column; gap: 2px; max-height: 140px; overflow-y: auto; }\r\n.tcw-style-empty { font-size: 11px; color: var(--tcw-text-muted); padding: 4px 0; }\r\n.tcw-style-template { display: flex; align-items: center; gap: 4px; }\r\n.tcw-style-apply {\r\n flex: 1;\r\n min-width: 0;\r\n display: flex;\r\n align-items: center;\r\n gap: 7px;\r\n padding: 5px 7px;\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n background: transparent;\r\n border: none;\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n text-align: left;\r\n}\r\n.tcw-style-apply:hover { background: var(--tcw-bg-surface); }\r\n.tcw-style-tdot { flex-shrink: 0; width: 9px; height: 9px; border-radius: 50%; }\r\n.tcw-style-tdel {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-style-tdel:hover { background: var(--tcw-red-soft); color: var(--tcw-red); }\r\n\r\n/* === Settings range slider === */\r\n\r\n.tcw-settings-range {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n.tcw-settings-range input[type='range'] {\r\n width: 110px;\r\n accent-color: var(--tcw-accent);\r\n cursor: pointer;\r\n}\r\n.tcw-settings-range-val {\r\n min-width: 38px;\r\n text-align: right;\r\n font-size: 12px;\r\n font-variant-numeric: tabular-nums;\r\n color: var(--tcw-text-dim);\r\n}\r\n\r\n/* === Indicator settings dialog === */\r\n\r\n.tcw-modal-narrow {\r\n max-width: 360px;\r\n}\r\n.tcw-indi-input {\r\n width: 110px;\r\n height: 30px;\r\n padding: 0 8px;\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n outline: none;\r\n font-variant-numeric: tabular-nums;\r\n}\r\n.tcw-indi-input:focus {\r\n border-color: var(--tcw-accent);\r\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\r\n}\r\n.tcw-indi-color {\r\n width: 36px;\r\n height: 28px;\r\n padding: 2px;\r\n background: var(--tcw-bg-surface);\r\n border: 1px solid var(--tcw-border);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n\r\n/* === Object tree panel === */\r\n\r\n.tcw-tree-panel {\r\n position: absolute;\r\n top: 50px;\r\n right: 12px;\r\n z-index: 39;\r\n width: 280px;\r\n max-width: calc(100vw - 24px);\r\n display: flex;\r\n flex-direction: column;\r\n background: var(--tcw-bg-elevated);\r\n border: 1px solid var(--tcw-border-strong);\r\n border-radius: var(--tcw-radius-lg);\r\n box-shadow: var(--tcw-shadow-lg);\r\n overflow: hidden;\r\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\r\n}\r\n\r\n.tcw-tree-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 12px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n color: var(--tcw-text);\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n.tcw-tree-close {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-tree-close:hover {\r\n background: var(--tcw-bg-surface);\r\n color: var(--tcw-text);\r\n}\r\n\r\n.tcw-tree-section {\r\n padding: 6px;\r\n border-bottom: 1px solid var(--tcw-border);\r\n}\r\n.tcw-tree-section:last-child {\r\n border-bottom: none;\r\n}\r\n.tcw-tree-section-head {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 6px 8px 4px;\r\n font-size: 10px;\r\n font-weight: 700;\r\n text-transform: uppercase;\r\n letter-spacing: 0.05em;\r\n color: var(--tcw-text-muted);\r\n}\r\n.tcw-tree-add {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 22px;\r\n height: 22px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-tree-add:hover {\r\n background: var(--tcw-accent-soft);\r\n color: var(--tcw-accent);\r\n}\r\n.tcw-tree-dot {\r\n flex-shrink: 0;\r\n width: 8px;\r\n height: 8px;\r\n border-radius: 50%;\r\n}\r\n.tcw-tree-list {\r\n max-height: 200px;\r\n overflow-y: auto;\r\n}\r\n\r\n.tcw-tree-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 8px;\r\n padding: 6px 8px;\r\n border-radius: var(--tcw-radius-sm);\r\n}\r\n.tcw-tree-row:hover {\r\n background: var(--tcw-bg-surface);\r\n}\r\n.tcw-tree-hidden .tcw-tree-name {\r\n opacity: 0.5;\r\n}\r\n.tcw-tree-name {\r\n min-width: 0;\r\n font-size: 12px;\r\n color: var(--tcw-text);\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n.tcw-tree-actions {\r\n display: flex;\r\n align-items: center;\r\n gap: 2px;\r\n flex-shrink: 0;\r\n}\r\n.tcw-tree-btn {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n border: none;\r\n background: transparent;\r\n color: var(--tcw-text-muted);\r\n border-radius: var(--tcw-radius-sm);\r\n cursor: pointer;\r\n}\r\n.tcw-tree-btn:hover {\r\n background: var(--tcw-bg-elevated);\r\n color: var(--tcw-text);\r\n}\r\n.tcw-tree-btn.tcw-tree-on {\r\n color: var(--tcw-accent);\r\n}\r\n.tcw-tree-btn.tcw-tree-del:hover {\r\n background: var(--tcw-red-soft);\r\n color: var(--tcw-red);\r\n}\r\n.tcw-tree-empty {\r\n padding: 8px;\r\n font-size: 12px;\r\n color: var(--tcw-text-muted);\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .tcw-tree-panel {\r\n top: auto;\r\n bottom: 0;\r\n left: 0;\r\n right: 0;\r\n width: 100vw;\r\n max-width: 100vw;\r\n border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;\r\n }\r\n .tcw-tree-list {\r\n max-height: 30vh;\r\n }\r\n .tcw-tree-section:last-child {\r\n padding-bottom: max(6px, env(safe-area-inset-bottom));\r\n }\r\n}\r\n\r\n/* === Reduced motion === */\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n .tcw-root *,\r\n .tcw-root *::before,\r\n .tcw-root *::after {\r\n animation-duration: 0.01ms !important;\r\n animation-iteration-count: 1 !important;\r\n transition-duration: 0.01ms !important;\r\n }\r\n}\r\n", m = 0, h = "tcw-styles";
719
- function g() {
720
- if (m++, m > 1 || document.getElementById(h)) return;
695
+ }, m = "/* === TradeCanvas Widget — Premium Styles === */\n\n/*\n * The HTML `hidden` attribute only sets `display: none` via the UA stylesheet,\n * which any author `display` rule (e.g. `.tcw-alerts-panel { display: flex }`)\n * silently overrides — leaving panels stuck open when JS sets `el.hidden = true`.\n * Force `hidden` to win for every namespaced widget element. Scoped to `tcw-`\n * so it never touches the host page.\n */\n[class^=\"tcw-\"][hidden],\n[class*=\" tcw-\"][hidden] {\n display: none !important;\n}\n\n/* Control tooltips (WidgetTooltip): quick to appear, slide in from the control. */\n.tcw-tooltip {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 60;\n max-width: 240px;\n padding: 5px 8px;\n border-radius: var(--tcw-radius-sm);\n background: var(--tcw-tooltip-bg);\n color: var(--tcw-tooltip-fg);\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);\n width: max-content;\n font-size: 11.5px;\n font-weight: 500;\n line-height: 1.35;\n overflow-wrap: anywhere;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transform: translate(var(--tcw-tip-dx, 0), var(--tcw-tip-dy, 0));\n transition:\n opacity 110ms var(--tcw-ease-out),\n transform 110ms var(--tcw-ease-out),\n visibility 0s linear 110ms;\n}\n\n.tcw-tooltip--visible {\n opacity: 1;\n visibility: visible;\n transform: none;\n transition:\n opacity 110ms var(--tcw-ease-out),\n transform 110ms var(--tcw-ease-out),\n visibility 0s;\n}\n\n/* The modal portal: carries the tokens and fonts, but no box of its own. */\n.tcw-root.tcw-portal {\n display: contents;\n}\n\n/* Fullscreen: the root fills the screen; the chart resizes with it. */\n.tcw-root:fullscreen {\n width: 100vw;\n height: 100vh;\n}\n\n.tcw-root {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n font-family: '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: #d9dde4;\n background: #080b10;\n position: relative;\n overflow: hidden;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n /* --- Dark theme tokens (default) --- */\n --tcw-bg: #080b10;\n --tcw-bg-surface: #0c1016;\n --tcw-bg-elevated: #141922;\n --tcw-bg-overlay: rgba(20, 25, 34, 0.5);\n --tcw-border: #1f2630;\n --tcw-border-strong: #2a323e;\n --tcw-tooltip-bg: #262e3a;\n --tcw-tooltip-fg: #eef0f4;\n --tcw-text: #e7e9ee;\n --tcw-text-dim: #aab1bd;\n --tcw-text-muted: #758091;\n\n /* TradeCanvas amber. --tcw-accent-ink is the text colour on an accent fill. */\n --tcw-accent: #f2a93b;\n --tcw-accent-hover: #f5b95c;\n --tcw-accent-ink: #1a1204;\n --tcw-accent-soft: rgba(242, 169, 59, 0.14);\n --tcw-accent-glow: rgba(242, 169, 59, 0.22);\n --tcw-accent-line: rgba(242, 169, 59, 0.55);\n\n --tcw-red: #e8505b;\n --tcw-red-soft: rgba(232, 80, 91, 0.12);\n --tcw-green: #1fa874;\n --tcw-green-soft: rgba(31, 168, 116, 0.12);\n --tcw-amber: #ff9f43;\n\n --tcw-hover-bg: rgba(255, 255, 255, 0.05);\n --tcw-active-bg: rgba(255, 255, 255, 0.08);\n --tcw-divider: rgba(255, 255, 255, 0.06);\n\n /* Motion */\n --tcw-ease: cubic-bezier(0.2, 0, 0, 1);\n --tcw-ease-out: cubic-bezier(0.16, 1, 0.3, 1);\n --tcw-dur-fast: 120ms;\n --tcw-dur-normal: 180ms;\n --tcw-dur-slow: 260ms;\n\n /* 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(242, 169, 59, 0.45);\n\n /* Type */\n --tcw-font-mono: 'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', 'Consolas', ui-monospace, monospace;\n}\n\n.tcw-root[data-tcw-theme='light'] {\n color: #0c1016;\n background: #fcfcfd;\n\n --tcw-bg: #fcfcfd;\n --tcw-bg-surface: #ffffff;\n --tcw-bg-elevated: #ffffff;\n --tcw-bg-overlay: rgba(255, 255, 255, 0.75);\n --tcw-border: #e3e6eb;\n --tcw-border-strong: #d2d6dd;\n --tcw-tooltip-bg: #1f2630;\n --tcw-tooltip-fg: #f4f5f8;\n --tcw-text: #0c1016;\n --tcw-text-dim: #3f4754;\n --tcw-text-muted: #626a77;\n\n /* Deeper amber: readable as text on the light ground, white text readable on it. */\n --tcw-accent: #a0610a;\n --tcw-accent-hover: #874f07;\n --tcw-accent-ink: #ffffff;\n --tcw-accent-soft: rgba(160, 97, 10, 0.10);\n --tcw-accent-glow: rgba(160, 97, 10, 0.16);\n --tcw-accent-line: rgba(160, 97, 10, 0.45);\n --tcw-ring: 0 0 0 2px rgba(160, 97, 10, 0.4);\n\n /* Darker semantic colours: used as text on white. */\n --tcw-red: #c42f3e;\n --tcw-red-soft: rgba(196, 47, 62, 0.10);\n --tcw-green: #0b7d50;\n --tcw-green-soft: rgba(11, 125, 80, 0.10);\n\n --tcw-hover-bg: rgba(0, 0, 0, 0.04);\n --tcw-active-bg: rgba(160, 97, 10, 0.08);\n --tcw-divider: rgba(0, 0, 0, 0.06);\n\n --tcw-shadow-sm: 0 1px 2px rgba(20, 28, 56, 0.05);\n --tcw-shadow-md: 0 4px 12px rgba(20, 28, 56, 0.08), 0 1px 3px rgba(20, 28, 56, 0.04);\n --tcw-shadow-lg: 0 12px 36px rgba(20, 28, 56, 0.14), 0 4px 12px rgba(20, 28, 56, 0.08);\n --tcw-shadow-xl: 0 24px 64px rgba(20, 28, 56, 0.18), 0 12px 24px rgba(20, 28, 56, 0.1);\n}\n\n/* === Toolbar === */\n\n.tcw-toolbar {\n display: flex;\n align-items: center;\n gap: 0;\n padding: 0 10px;\n height: 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/* === 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/* A menu row led by an icon (chart types): icon then label, not spread apart. */\n.tcw-dropdown-item--icon {\n justify-content: flex-start;\n gap: 10px;\n}\n\n.tcw-dropdown-item svg,\n.tcw-flyout-item svg {\n flex-shrink: 0;\n}\n\n/* The drawing-group button's icon holder: a plain box for the swapped SVG. */\n.tcw-sidebar-icon {\n display: inline-flex;\n}\n\n.tcw-dropdown-item.tcw-active {\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n font-weight: 600;\n}\n\n/* Timeframe menu: pick on the left, pin (star) on the right. */\n.tcw-tf-more {\n padding: 6px 5px;\n}\n\n.tcw-tf-more svg {\n display: block;\n}\n\n.tcw-tf-row {\n display: flex;\n align-items: center;\n gap: 2px;\n}\n\n.tcw-tf-row .tcw-dropdown-item {\n flex: 1;\n min-width: 0;\n}\n\n.tcw-tf-star {\n display: inline-grid;\n place-items: center;\n width: 26px;\n height: 26px;\n flex-shrink: 0;\n border: none;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-tf-star:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-tf-star.tcw-active {\n color: var(--tcw-accent);\n}\n\n.tcw-tf-star.tcw-active svg {\n fill: currentColor;\n}\n\n.tcw-tf-star:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-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/* === Loading overlay (candle skeleton) === */\n\n.tcw-loading-overlay {\n /* Uses a modifier class rather than the `hidden` attribute — the global\n `[hidden] { display: none !important }` rule above would cut the\n opacity transition off before it can play. */\n position: absolute;\n inset: 0;\n z-index: 5;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--tcw-bg);\n opacity: 1;\n transition: opacity var(--tcw-dur-slow) var(--tcw-ease-out);\n pointer-events: none;\n}\n\n.tcw-loading-overlay--hidden {\n opacity: 0;\n}\n\n.tcw-loading-card {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 14px;\n padding: 22px 26px 20px;\n border: 1px solid transparent;\n border-radius: var(--tcw-radius-lg);\n}\n\n/* A slow switch: the previous chart stays readable underneath, dimmed, so the\n click visibly registered without blanking the screen. */\n.tcw-loading-overlay--veil {\n background: color-mix(in srgb, var(--tcw-bg) 55%, transparent);\n}\n\n.tcw-loading-overlay--veil .tcw-loading-card {\n background: var(--tcw-bg-elevated);\n border-color: var(--tcw-border);\n box-shadow: var(--tcw-shadow-lg);\n}\n\n.tcw-loading-candles {\n position: relative;\n display: flex;\n gap: 7px;\n height: 64px;\n}\n\n/* One candle: the element is the wick's column, ::before the wick, ::after the body. */\n.tcw-loading-candle {\n position: relative;\n width: 8px;\n height: 100%;\n color: var(--tcw-red);\n opacity: 0.28;\n animation: tcw-candle-light 1.6s var(--tcw-ease) infinite;\n animation-delay: var(--tcw-delay, 0ms);\n}\n\n.tcw-loading-candle--up { color: var(--tcw-green); }\n\n.tcw-loading-candle::before,\n.tcw-loading-candle::after {\n content: '';\n position: absolute;\n left: 50%;\n background: currentColor;\n transform: translateX(-50%);\n}\n\n.tcw-loading-candle::before {\n top: var(--tcw-wick-top);\n width: 1.5px;\n height: var(--tcw-wick-h);\n}\n\n.tcw-loading-candle::after {\n top: var(--tcw-body-top);\n width: 8px;\n height: var(--tcw-body-h);\n border-radius: 1.5px;\n}\n\n/* Each candle brightens and lifts slightly in turn, left to right. */\n@keyframes tcw-candle-light {\n 0%, 55%, 100% { opacity: 0.28; transform: translateY(0); }\n 20% { opacity: 1; transform: translateY(-2px); }\n}\n\n.tcw-loading-track {\n position: relative;\n width: 100%;\n min-width: 88px;\n height: 2px;\n border-radius: 1px;\n background: var(--tcw-border);\n overflow: hidden;\n}\n\n.tcw-loading-track > span {\n position: absolute;\n inset: 0;\n width: 40%;\n border-radius: 1px;\n background: linear-gradient(90deg, transparent, var(--tcw-accent), transparent);\n animation: tcw-loading-sweep 1.6s var(--tcw-ease) infinite;\n}\n\n@keyframes tcw-loading-sweep {\n from { transform: translateX(-100%); }\n to { transform: translateX(250%); }\n}\n\n/* The status text is announced, not shown — the candles say \"loading\". */\n.tcw-loading-label {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n.tcw-loading-overlay--error .tcw-loading-candles,\n.tcw-loading-overlay--error .tcw-loading-track {\n display: none;\n}\n\n/* A failure is shown: why the chart is empty and that a retry is running. */\n.tcw-loading-overlay--error .tcw-loading-label {\n position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip-path: none;\n white-space: normal;\n max-width: 320px;\n text-align: center;\n color: var(--tcw-red);\n font-size: 13px;\n}\n\n/* Reduced motion: nothing slides or lifts, but the candles still glow in\n turn and the track breathes, so the wait never looks frozen. */\n@media (prefers-reduced-motion: reduce) {\n .tcw-loading-candle {\n animation: tcw-candle-glow 2.4s ease-in-out infinite;\n animation-delay: var(--tcw-delay, 0ms);\n }\n .tcw-loading-track > span {\n width: 100%;\n background: var(--tcw-accent);\n animation: tcw-loading-breathe 2.4s ease-in-out infinite;\n }\n}\n\n@keyframes tcw-candle-glow {\n 0%, 60%, 100% { opacity: 0.28; }\n 25% { opacity: 0.9; }\n}\n\n@keyframes tcw-loading-breathe {\n 0%, 100% { opacity: 0.15; }\n 50% { opacity: 0.7; }\n}\n\n/* === On-chart indicator legend (WidgetIndicatorLegend) === */\n\n.tcw-ind-legend {\n position: absolute;\n z-index: 3;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 1px;\n max-width: calc(100% - 140px);\n pointer-events: none;\n}\n\n.tcw-ind-legend--collapsed > .tcw-ind-legend-row {\n display: none;\n}\n\n.tcw-ind-legend-row {\n display: flex;\n align-items: center;\n gap: 8px;\n max-width: 100%;\n padding: 0 4px;\n border-radius: var(--tcw-radius-sm);\n font-size: 11.5px;\n line-height: 19px;\n font-feature-settings: 'tnum';\n white-space: nowrap;\n color: var(--tcw-text-dim);\n pointer-events: auto;\n cursor: default;\n /* A narrow pane: the values shrink first, then the row is clipped. */\n overflow: hidden;\n}\n\n/* A pane's indicator: at the top of its pane, where the canvas title was. */\n.tcw-ind-legend-row--pane {\n position: absolute;\n z-index: 3;\n}\n\n.tcw-ind-legend-row:hover,\n.tcw-ind-legend-row:focus-within {\n background: color-mix(in srgb, var(--tcw-bg-elevated) 90%, transparent);\n box-shadow: 0 0 0 1px var(--tcw-border);\n}\n\n.tcw-ind-legend-name {\n padding: 0;\n border: none;\n background: none;\n font: inherit;\n font-weight: 600;\n color: var(--tcw-text);\n cursor: pointer;\n}\n\n.tcw-ind-legend-name:hover {\n color: var(--tcw-accent);\n}\n\n.tcw-ind-legend-values {\n display: inline-flex;\n gap: 7px;\n min-width: 0;\n overflow: hidden;\n}\n\n.tcw-ind-legend-row--hidden .tcw-ind-legend-name,\n.tcw-ind-legend-row--hidden .tcw-ind-legend-values {\n opacity: 0.45;\n}\n\n/* Show / settings / remove: on hover or keyboard focus (always on touch). */\n.tcw-ind-legend-actions {\n display: none;\n gap: 1px;\n margin-left: -2px;\n}\n\n.tcw-ind-legend-row:hover .tcw-ind-legend-actions,\n.tcw-ind-legend-row:focus-within .tcw-ind-legend-actions {\n display: inline-flex;\n}\n\n@media (hover: none) {\n .tcw-ind-legend-actions {\n display: inline-flex;\n }\n\n /* Finger-sized targets. */\n .tcw-ind-legend-act,\n .tcw-ind-legend-toggle {\n min-width: 28px;\n min-height: 24px;\n }\n}\n\n.tcw-ind-legend-act {\n display: inline-grid;\n place-items: center;\n width: 20px;\n height: 18px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n\n.tcw-ind-legend-act:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ind-legend-act[data-act='remove']:hover {\n color: var(--tcw-red);\n}\n\n.tcw-ind-legend-toggle {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n margin-top: 1px;\n padding: 1px 5px;\n border: none;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: 11px;\n cursor: pointer;\n pointer-events: auto;\n}\n\n.tcw-ind-legend-toggle[hidden] {\n display: none;\n}\n\n.tcw-ind-legend-toggle:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ind-legend-name:focus-visible,\n.tcw-ind-legend-act:focus-visible,\n.tcw-ind-legend-toggle:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n/* === Sidebar === */\n\n.tcw-sidebar {\n width: 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/* Spans the gap to the toolbar button: crossing it stays inside the menu. */\n.tcw-flyout::before {\n content: '';\n position: absolute;\n top: -1px;\n bottom: -1px;\n right: 100%;\n width: 8px;\n}\n\n@keyframes tcw-slide-right {\n from { opacity: 0; transform: translateX(-4px); }\n to { opacity: 1; transform: translateX(0); }\n}\n\n.tcw-flyout-header {\n text-transform: 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-hint {\n padding: 6px 10px 2px;\n border-top: 1px solid var(--tcw-border);\n margin-top: 4px;\n font-size: 10.5px;\n color: var(--tcw-text-muted);\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: flex;\n align-items: center;\n gap: 10px;\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: var(--tcw-accent-ink);\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 /* Above sidebar buttons that overflow a short chart; menus (z 30+) stay on top. */\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 7px 16px;\n border-top: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n font-size: 11px;\n color: var(--tcw-text-muted);\n flex-shrink: 0;\n font-feature-settings: 'tnum';\n}\n\n.tcw-status-right {\n display: flex;\n align-items: center;\n gap: 14px;\n margin-left: auto;\n min-width: 0;\n white-space: nowrap;\n}\n\n/* Narrow screens: the toolbar already names the symbol and timeframe, so the\n range bar gets the room. */\n@media (max-width: 640px) {\n .tcw-status-info {\n display: none;\n }\n\n .tcw-range-btn {\n padding: 4px 5px;\n }\n}\n\n/* Range presets + go to date, bottom left */\n.tcw-range-bar {\n display: flex;\n align-items: center;\n gap: 1px;\n margin: -4px 12px -4px -8px;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n}\n\n.tcw-range-bar::-webkit-scrollbar {\n display: none;\n}\n\n.tcw-range-btn {\n flex-shrink: 0;\n padding: 4px 7px;\n font: inherit;\n font-weight: 600;\n letter-spacing: 0.02em;\n color: var(--tcw-text-muted);\n background: transparent;\n border: none;\n border-radius: var(--tcw-radius-sm);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-range-btn:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-range-btn:active {\n color: var(--tcw-accent);\n}\n\n.tcw-range-btn:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-range-goto {\n display: inline-grid;\n place-items: center;\n margin-left: 6px;\n padding: 4px 6px;\n}\n\n.tcw-range-goto svg {\n display: block;\n}\n\n/* Go-to-date popover, anchored above the range bar */\n.tcw-goto {\n position: absolute;\n left: 10px;\n bottom: 40px;\n z-index: 40;\n display: grid;\n gap: 10px;\n width: 232px;\n padding: 14px;\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius);\n box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);\n color: var(--tcw-text);\n font-size: 12px;\n}\n\n.tcw-goto-title {\n font-weight: 600;\n font-size: 13px;\n}\n\n.tcw-goto-field {\n display: grid;\n gap: 4px;\n color: var(--tcw-text-muted);\n font-size: 11px;\n}\n\n.tcw-goto-input {\n height: 30px;\n padding: 0 8px;\n font: inherit;\n font-size: 12.5px;\n color: var(--tcw-text);\n background: var(--tcw-bg);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-sm);\n color-scheme: dark;\n}\n\n.tcw-root[data-tcw-theme='light'] .tcw-goto-input {\n color-scheme: light;\n}\n\n.tcw-goto-input:focus {\n outline: none;\n border-color: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n\n.tcw-goto-actions {\n display: flex;\n justify-content: flex-end;\n gap: 6px;\n}\n\n.tcw-goto-submit {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n font-weight: 600;\n}\n\n.tcw-goto-submit:hover {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n filter: brightness(1.08);\n}\n\n.tcw-status-indicator {\n display: flex;\n align-items: center;\n gap: 7px;\n font-weight: 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(31, 168, 116, 0.18);\n}\n\n.tcw-status-dot.tcw-connected::after {\n content: '';\n position: absolute;\n inset: -3px;\n border-radius: 50%;\n border: 2px solid var(--tcw-green);\n opacity: 0;\n animation: tcw-pulse 2.2s ease-out infinite;\n}\n\n@keyframes tcw-pulse {\n 0% { opacity: 0.6; transform: scale(0.6); }\n 100% { opacity: 0; transform: scale(2.2); }\n}\n\n.tcw-status-dot.tcw-error {\n background: var(--tcw-red);\n box-shadow: 0 0 0 3px rgba(232, 80, 91, 0.2);\n}\n\n/* === Command Palette === */\n\n.tcw-cmd-palette {\n position: fixed;\n z-index: 102;\n top: 18%;\n left: 50%;\n transform: translateX(-50%);\n background: var(--tcw-bg-elevated);\n border: 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/* Picking the replay start: the bars right of the pointer would be hidden. */\n.tcw-replay-shade {\n position: absolute;\n z-index: 4;\n pointer-events: none;\n background: color-mix(in srgb, var(--tcw-bg) 62%, transparent);\n border-left: 1.5px dashed var(--tcw-accent);\n}\n\n.tcw-replay-group {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n\n.tcw-replay-group[hidden] { display: none; }\n\n.tcw-replay-hint {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 0 4px;\n color: var(--tcw-text-dim);\n white-space: nowrap;\n}\n\n.tcw-replay-text-btn {\n height: 26px;\n padding: 0 10px;\n border: 1px solid var(--tcw-border);\n border-radius: 9999px;\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-weight: 500;\n white-space: nowrap;\n cursor: pointer;\n transition: background var(--tcw-dur-fast), border-color var(--tcw-dur-fast), color var(--tcw-dur-fast);\n}\n\n.tcw-replay-text-btn:hover { background: var(--tcw-hover-bg); border-color: var(--tcw-border-strong); }\n.tcw-replay-text-btn:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n\n/* At the last bar: the way out is the next thing to do. */\n.tcw-replay-bar--ended .tcw-replay-realtime {\n background: var(--tcw-accent);\n border-color: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n}\n\n.tcw-replay-btn:disabled { opacity: 0.4; cursor: default; }\n\n@media (max-width: 640px) {\n .tcw-replay-bar {\n flex-wrap: wrap;\n justify-content: center;\n max-width: calc(100% - 24px);\n border-radius: 14px;\n }\n .tcw-replay-hint { white-space: normal; }\n}\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: var(--tcw-accent-ink);\n width: 32px;\n height: 32px;\n box-shadow: 0 0 0 3px var(--tcw-accent-glow);\n}\n\n.tcw-replay-btn.tcw-replay-play:hover {\n background: var(--tcw-accent-hover);\n}\n\n.tcw-replay-scrubber {\n appearance: none;\n -webkit-appearance: none;\n width: 220px;\n height: 4px;\n background: var(--tcw-border-strong);\n border-radius: 2px;\n outline: none;\n cursor: pointer;\n}\n\n.tcw-replay-scrubber::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n}\n\n.tcw-replay-scrubber::-moz-range-thumb {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n}\n\n.tcw-replay-progress {\n font-size: 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-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: var(--tcw-accent-ink);\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: var(--tcw-accent-ink);\n background: var(--tcw-accent);\n}\n.tcw-bracket-confirm:hover { background: var(--tcw-accent-hover); }\n\n@media (max-width: 640px) {\n .tcw-bracket-bar { width: calc(100vw - 24px); justify-content: space-between; }\n .tcw-bracket-hint { display: none; }\n}\n\n/* === Drawing style + templates popover === */\n\n.tcw-style-panel {\n position: absolute;\n bottom: 12px;\n 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: var(--tcw-accent-ink);\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 /* Except the loader's slow glow (opacity only): without it a long wait\n looks frozen. */\n .tcw-root .tcw-loading-candle,\n .tcw-root .tcw-loading-track > span {\n animation-duration: 2.4s !important;\n animation-iteration-count: infinite !important;\n animation-delay: var(--tcw-delay, 0ms) !important;\n }\n}\n", h = 0, g = "tcw-styles";
696
+ function ne() {
697
+ if (h++, h > 1 || document.getElementById(g)) return;
721
698
  let e = document.createElement("style");
722
- e.id = h, e.textContent = te, document.head.appendChild(e);
699
+ e.id = g, e.textContent = m, document.head.appendChild(e);
723
700
  }
724
- function _() {
725
- if (m--, m > 0) return;
726
- let e = document.getElementById(h);
701
+ function re() {
702
+ if (h--, h > 0) return;
703
+ let e = document.getElementById(g);
727
704
  e && e.remove();
728
705
  }
729
706
  //#endregion
707
+ //#region src/widget/iconSet.ts
708
+ var _ = {
709
+ cursor: { d: "M6 3.5L18.5 12.5L12.6 13.6L9.7 19.4z" },
710
+ trendingUp: { d: "M3 17L9 11L13 14.5L21 6.5M15 6.5H21V12.5" },
711
+ trendingDown: { d: "M3 7L9 13L13 9.5L21 17.5M15 17.5H21V11.5" },
712
+ minus: { d: "M5 12H19" },
713
+ plus: { d: "M12 5V19M5 12H19" },
714
+ penLine: { d: "M14.5 5.5L18.5 9.5M4 20L5 15.5L15.8 4.7a2 2 0 0 1 2.83 0l.67.67a2 2 0 0 1 0 2.83L8.5 19z" },
715
+ zigzag: { d: "M3 17L8 9L13 15L21 6" },
716
+ hash: { d: "M5 9H19M5 15H19M10 4L8.5 20M15.5 4L14 20" },
717
+ square: { d: "M6.5 4.5h11a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2h-11a2 2 0 0 1-2-2v-11a2 2 0 0 1 2-2z" },
718
+ gitBranch: { d: "M6 3V15M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM18 9a9 9 0 0 1-9 9" },
719
+ ruler: { d: "M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9" },
720
+ type: { d: "M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5" },
721
+ magnet: { d: "M6 4V11a6 6 0 0 0 12 0V4M6 4h3.5v7a2.5 2.5 0 0 0 5 0V4H18M6 8h3.5M14.5 8H18" },
722
+ undo: { d: "M9 14L4 9L9 4M4 9H14.5a5.5 5.5 0 0 1 0 11H11" },
723
+ redo: { d: "M15 14L20 9L15 4M20 9H9.5a5.5 5.5 0 0 0 0 11H13" },
724
+ trash: { d: "M4 7H20M9.5 7V4.5h5V7M6.5 7l.8 12.2A1.5 1.5 0 0 0 8.8 20.6h6.4a1.5 1.5 0 0 0 1.5-1.4L17.5 7M10 11v6M14 11v6" },
725
+ camera: { d: "M4.5 7.5h3L9 5h6l1.5 2.5h3A1.5 1.5 0 0 1 21 9v9.5a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 18.5V9a1.5 1.5 0 0 1 1.5-1.5zM15.5 13.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0z" },
726
+ settings: { d: "M4 7H14M18 7H20M4 17H8M12 17H20M18 7a2 2 0 1 1-4 0 2 2 0 0 1 4 0zM12 17a2 2 0 1 1-4 0 2 2 0 0 1 4 0z" },
727
+ moon: { d: "M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z" },
728
+ sun: { d: "M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0zM12 2.5v2M12 19.5v2M4.6 4.6l1.4 1.4M18 18l1.4 1.4M2.5 12h2M19.5 12h2M4.6 19.4L6 18M18 6l1.4-1.4" },
729
+ chevronDown: { d: "M6 9L12 15L18 9" },
730
+ chevronUp: { d: "M6 15L12 9L18 15" },
731
+ barChart: { d: "M5 20V13M12 20V5M19 20V10" },
732
+ x: { d: "M6 6L18 18M18 6L6 18" },
733
+ play: { d: "M7 4.5v15L19.5 12z" },
734
+ pause: { d: "M8 5V19M16 5V19" },
735
+ stop: { d: "M7.5 6h9A1.5 1.5 0 0 1 18 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 6 16.5v-9A1.5 1.5 0 0 1 7.5 6z" },
736
+ receipt: { d: "M6 3.5h12v17l-2-1.25-2 1.25-2-1.25-2 1.25-2-1.25-2 1.25zM9 8h6M9 12h6M9 16h3" },
737
+ bell: { d: "M6 16.5V11a6 6 0 0 1 12 0v5.5l1.5 2H4.5zM10 20.5a2.2 2.2 0 0 0 4 0" },
738
+ layers: { d: "M12 3.5L21 8.5L12 13.5L3 8.5zM3 12.5L12 17.5L21 12.5M3 16.5L12 21.5L21 16.5" },
739
+ eye: { d: "M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12zM15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0z" },
740
+ eyeOff: { d: "M4 4L20 20M9.9 5.8A9.6 9.6 0 0 1 12 5.5c6 0 9.5 6.5 9.5 6.5a16 16 0 0 1-2.3 3.1M6.6 7.1C3.9 8.9 2.5 12 2.5 12S6 18.5 12 18.5a9.3 9.3 0 0 0 4.7-1.3M10 10.1a3 3 0 0 0 4 4" },
741
+ lock: { d: "M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 8 0v3" },
742
+ unlock: { d: "M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 7.7-1.5" },
743
+ palette: {
744
+ d: "M12 3.5a8.5 8.5 0 0 0 0 17c1.1 0 1.6-.8 1.6-1.6 0-.5-.2-.9-.5-1.2a1.6 1.6 0 0 1 1.2-2.7h1.9a4.3 4.3 0 0 0 4.3-4.3C20.5 6.9 16.7 3.5 12 3.5z",
745
+ dots: [
746
+ [
747
+ 7.5,
748
+ 11.5,
749
+ 1.25
750
+ ],
751
+ [
752
+ 9.5,
753
+ 7.75,
754
+ 1.25
755
+ ],
756
+ [
757
+ 14,
758
+ 7.25,
759
+ 1.25
760
+ ]
761
+ ]
762
+ },
763
+ check: { d: "M5 12.5L10 17.5L19 7" },
764
+ maximize: { d: "M8 4H5a1 1 0 0 0-1 1v3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3" },
765
+ minimize: { d: "M4 8h3a1 1 0 0 0 1-1V4M16 4v3a1 1 0 0 0 1 1h3M20 16h-3a1 1 0 0 0-1 1v3M8 20v-3a1 1 0 0 0-1-1H4" },
766
+ repeat: { d: "M17 3.5L20.5 7L17 10.5M3.5 11.5V10a3 3 0 0 1 3-3h14M7 20.5L3.5 17L7 13.5M20.5 12.5V14a3 3 0 0 1-3 3h-14" },
767
+ calendar: { d: "M5.5 5h13a2 2 0 0 1 2 2v11.5a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2zM3.5 10H20.5M8 3V7M16 3V7" },
768
+ star: { d: "M12 3.5L14.6 9L20.5 9.6L16 13.6L17.3 19.5L12 16.5L6.7 19.5L8 13.6L3.5 9.6L9.4 9z" },
769
+ ladder: { d: "M4 6H11M13 6H17M6 10H11M13 10H20M8 14H11M13 14H15M5 18H11M13 18H19" }
770
+ }, v = {
771
+ trendLine: {
772
+ d: "M5 18L19 6",
773
+ dots: [[5, 18], [19, 6]]
774
+ },
775
+ ray: {
776
+ d: "M5 17L21 5M17.5 4.81L21 5L20.2 8.41",
777
+ dots: [[5, 17], [11, 12.5]]
778
+ },
779
+ extendedLine: {
780
+ d: "M3 18.5L21 5M17.5 4.81L21 5L20.2 8.41M6.5 18.69L3 18.5L3.8 15.09",
781
+ dots: [[9, 14], [15, 9.5]]
782
+ },
783
+ infoLine: {
784
+ d: "M5 20L19 10M4.5 3.5h9a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1zM6.5 6.5h5",
785
+ dots: [[5, 20], [19, 10]]
786
+ },
787
+ trendAngle: {
788
+ d: "M5 18L19 7M5 18H20M11 18A6 6 0 0 0 9.71 14.29",
789
+ dots: [[5, 18], [19, 7]]
790
+ },
791
+ horizontalLine: {
792
+ d: "M3 12H21",
793
+ dots: [[12, 12]]
794
+ },
795
+ horizontalRay: {
796
+ d: "M7 12H21M18.5 9.5L21 12L18.5 14.5",
797
+ dots: [[7, 12]]
798
+ },
799
+ verticalLine: {
800
+ d: "M12 3V21",
801
+ dots: [[12, 12]]
802
+ },
803
+ crossLine: {
804
+ d: "M3 12H21M12 3V21",
805
+ dots: [[12, 12]]
806
+ },
807
+ parallelChannel: {
808
+ d: "M3 15L15 5M9 19L21 9",
809
+ dots: [
810
+ [3, 15],
811
+ [15, 5],
812
+ [9, 19]
813
+ ]
814
+ },
815
+ regressionChannel: {
816
+ d: "M3 12L21 4M3 20L21 12",
817
+ dash: "M3 16L21 8",
818
+ dots: [[3, 16], [21, 8]]
819
+ },
820
+ fibRetracement: {
821
+ d: "M3 4H21M3 9H21M3 13H21M3 20H21",
822
+ dots: [[5, 20], [19, 4]]
823
+ },
824
+ fibExtension: {
825
+ d: "M3 20L8 10L12 16M14 4H21M14 8H21M14 12H21",
826
+ dots: [
827
+ [3, 20],
828
+ [8, 10],
829
+ [12, 16]
830
+ ]
831
+ },
832
+ fibChannel: {
833
+ d: "M3 9L21 3M3 13L21 7M3 16L21 10M3 21L21 15",
834
+ dots: [
835
+ [3, 21],
836
+ [21, 15],
837
+ [3, 9]
838
+ ]
839
+ },
840
+ fibTimeZones: {
841
+ d: "M3 4V20M6 4V20M9.5 4V20M14 4V20M20.5 4V20",
842
+ dots: [[3, 20], [6, 20]]
843
+ },
844
+ fibSpeedResistanceFan: {
845
+ d: "M4 20L20 4M4 20L20 11M4 20L20 16M4 20L11 4",
846
+ dash: "M4 4H20V20",
847
+ dots: [[4, 20], [20, 4]]
848
+ },
849
+ rectangle: {
850
+ d: "M5.5 6h13A1.5 1.5 0 0 1 20 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 4 16.5v-9A1.5 1.5 0 0 1 5.5 6z",
851
+ dots: [[4, 6], [20, 18]]
852
+ },
853
+ circle: {
854
+ d: "M19.5 12a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0z",
855
+ dots: [[12, 12], [19.5, 12]]
856
+ },
857
+ ellipse: {
858
+ d: "M20.5 12c0 3-3.8 5.5-8.5 5.5S3.5 15 3.5 12 7.3 6.5 12 6.5s8.5 2.5 8.5 5.5z",
859
+ dots: [[3.5, 12], [20.5, 12]]
860
+ },
861
+ triangle: {
862
+ d: "M12 4.5L20 19H4z",
863
+ dots: [
864
+ [12, 4.5],
865
+ [20, 19],
866
+ [4, 19]
867
+ ]
868
+ },
869
+ pitchfork: {
870
+ d: "M4 20L16.75 3M7 9L11.5 3M13 15L21 4.33M7 9L13 15",
871
+ dots: [
872
+ [4, 20],
873
+ [7, 9],
874
+ [13, 15]
875
+ ]
876
+ },
877
+ schiffPitchfork: {
878
+ d: "M4 14.5L21 7.42M7 9L21 3.17M13 15L21 11.67M7 9L13 15",
879
+ dash: "M4 20V14.5",
880
+ dots: [
881
+ [4, 14.5],
882
+ [7, 9],
883
+ [13, 15]
884
+ ]
885
+ },
886
+ modifiedSchiffPitchfork: {
887
+ d: "M5.5 14.5L21 5.89M7 9L17.8 3M13 15L21 10.56M7 9L13 15",
888
+ dash: "M4 20L5.5 14.5",
889
+ dots: [
890
+ [5.5, 14.5],
891
+ [7, 9],
892
+ [13, 15]
893
+ ]
894
+ },
895
+ gannFan: {
896
+ d: "M4 20L20 4M4 20L20 12M4 20L12 4M4 20L20 16.5M4 20L7.5 4",
897
+ dots: [[4, 20], [20, 4]]
898
+ },
899
+ gannBox: {
900
+ d: "M4 4H20V20H4zM4 20L20 4M4 4L20 20M12 4V20",
901
+ dots: [[4, 20], [20, 4]]
902
+ },
903
+ cyclicLines: {
904
+ d: "M4 4V20M9 4V20M14 4V20M19 4V20",
905
+ dots: [[4, 20], [9, 20]]
906
+ },
907
+ xabcdPattern: {
908
+ d: "M3 18L7 6L11 13L15 8L21 19",
909
+ dash: "M3 18L11 13L21 19",
910
+ dots: [
911
+ [3, 18],
912
+ [7, 6],
913
+ [11, 13],
914
+ [15, 8],
915
+ [21, 19]
916
+ ]
917
+ },
918
+ abcdPattern: {
919
+ d: "M4 19L9 8L13 14L20 4",
920
+ dots: [
921
+ [4, 19],
922
+ [9, 8],
923
+ [13, 14],
924
+ [20, 4]
925
+ ]
926
+ },
927
+ headAndShoulders: {
928
+ d: "M3 19L6 11L8.5 15L12 5L15.5 15L18 11L21 19",
929
+ dash: "M4.5 15H19.5",
930
+ dots: [
931
+ [6, 11],
932
+ [12, 5],
933
+ [18, 11]
934
+ ]
935
+ },
936
+ elliottWave: {
937
+ d: "M3 19L6 13L8.5 16L14 6L16 10L21 4",
938
+ dots: [[3, 19], [21, 4]]
939
+ },
940
+ priceRange: { d: "M5 4H19M5 20H19M12 6.5V17.5M9 9.5L12 6.5L15 9.5M9 14.5L12 17.5L15 14.5" },
941
+ dateRange: { d: "M4 5V19M20 5V19M6.5 12H17.5M9.5 9L6.5 12L9.5 15M14.5 9L17.5 12L14.5 15" },
942
+ dateAndPriceRange: {
943
+ d: "M6 18V4M3 7L6 4L9 7M6 18H20M17 15L20 18L17 21",
944
+ dash: "M6 4H20V18"
945
+ },
946
+ measure: { d: "M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9" },
947
+ text: { d: "M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5" },
948
+ priceLabel: { d: "M9 5H19a1.5 1.5 0 0 1 1.5 1.5v11A1.5 1.5 0 0 1 19 19H9L3.5 12zM11 12H17" },
949
+ arrow: { d: "M5 19L19 5M10 5H19V14" },
950
+ riskReward: {
951
+ d: "M5 12V4H19V12M3 12H21",
952
+ dash: "M5 12V18H19V12",
953
+ dots: [[5, 12]]
954
+ },
955
+ anchoredVWAP: {
956
+ d: "M4 18C9 17 12 10 20 7M4 20.5V18",
957
+ dots: [[4, 18]]
958
+ },
959
+ volumeProfileRange: {
960
+ d: "M6 7H12M6 10.5H17M6 14H15M6 17.5H10",
961
+ dash: "M3.5 4V20M20.5 4V20",
962
+ dots: [[3.5, 20], [20.5, 20]]
963
+ }
964
+ }, y = {
965
+ candlestick: {
966
+ d: "M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19",
967
+ fills: ["M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1z", "M14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z"]
968
+ },
969
+ hollowCandle: { d: "M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1zM14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z" },
970
+ heikinAshi: {
971
+ d: "M5.5 9.5V12M5.5 18V20M12 5.5V8M12 14V16M18.5 3V4.5M18.5 10.5V12.5",
972
+ fills: [
973
+ "M4 12h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5H4a.5.5 0 0 1-.5-.5v-5A.5.5 0 0 1 4 12z",
974
+ "M10.5 8h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-5a.5.5 0 0 1 .5-.5z",
975
+ "M17 4.5h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5z"
976
+ ]
977
+ },
978
+ bar: { d: "M8 4V20M5 8H8M8 16H11M16 6V18M13 15H16M16 9H19" },
979
+ volumeCandles: {
980
+ d: "M6.5 5V8M6.5 16V19M15.5 3.5V6M15.5 16V20",
981
+ fills: ["M5.5 8h2a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-7a.5.5 0 0 1 .5-.5z", "M11.5 6h8a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5z"]
982
+ },
983
+ equivolume: { d: "M4.5 10h2a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1zM10 6h5a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zM18.5 4h1a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z" },
984
+ line: { d: "M3 17L8 11L12 14L21 5" },
985
+ area: {
986
+ d: "M3 17L8 11L12 14L21 5",
987
+ soft: "M3 17L8 11L12 14L21 5V20H3z"
988
+ },
989
+ baseline: {
990
+ d: "M3 16L7 9L11 14L15 7L21 15",
991
+ dash: "M3 12H21"
992
+ },
993
+ hlcArea: {
994
+ d: "M3 9L8 6L13 9L21 4M3 15L8 13L13 16L21 11",
995
+ dash: "M3 12L8 9.5L13 12.5L21 7.5",
996
+ soft: "M3 9L8 6L13 9L21 4V11L13 16L8 13L3 15z"
997
+ },
998
+ stepLine: { d: "M3 18H8V12H12V15H16V7H21" },
999
+ lineWithMarkers: {
1000
+ d: "M4 17L9 10L14 14L20 6",
1001
+ dots: [
1002
+ [4, 17],
1003
+ [9, 10],
1004
+ [14, 14],
1005
+ [20, 6]
1006
+ ]
1007
+ }
1008
+ }, ie = 1.75, ae = .22, b = /* @__PURE__ */ new WeakMap();
1009
+ function oe(e) {
1010
+ let t = b.get(e);
1011
+ if (t) return t;
1012
+ let n = "";
1013
+ e.soft && (n += `<path d="${e.soft}" fill="currentColor" fill-opacity="${ae}" stroke="none"/>`);
1014
+ for (let t of e.fills ?? []) n += `<path d="${t}" fill="currentColor" stroke="none"/>`;
1015
+ e.d && (n += `<path d="${e.d}"/>`), e.dash && (n += `<path d="${e.dash}" stroke-dasharray="2 2.5"/>`);
1016
+ for (let [t, r, i = ie] of e.dots ?? []) n += `<circle cx="${t}" cy="${r}" r="${i}" fill="currentColor" stroke="none"/>`;
1017
+ return b.set(e, n), n;
1018
+ }
1019
+ function x(e, t) {
1020
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${oe(e)}</svg>`;
1021
+ }
1022
+ //#endregion
730
1023
  //#region src/widget/icons.ts
731
- var v = {
732
- cursor: "<path d=\"M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z\"/><path d=\"M13 13l6 6\"/>",
733
- trendingUp: "<polyline points=\"22 7 13.5 15.5 8.5 10.5 2 17\"/><polyline points=\"16 7 22 7 22 13\"/>",
734
- minus: "<path d=\"M5 12h14\"/>",
735
- penLine: "<path d=\"M12 20h9\"/><path d=\"M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z\"/>",
736
- zigzag: "<polyline points=\"2 18 7 8 12 14 17 4 22 12\"/>",
737
- hash: "<line x1=\"4\" y1=\"9\" x2=\"20\" y2=\"9\"/><line x1=\"4\" y1=\"15\" x2=\"20\" y2=\"15\"/><line x1=\"10\" y1=\"3\" x2=\"8\" y2=\"21\"/><line x1=\"16\" y1=\"3\" x2=\"14\" y2=\"21\"/>",
738
- square: "<rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\"/>",
739
- gitBranch: "<line x1=\"6\" y1=\"3\" x2=\"6\" y2=\"15\"/><circle cx=\"18\" cy=\"6\" r=\"3\"/><circle cx=\"6\" cy=\"18\" r=\"3\"/><path d=\"M18 9a9 9 0 0 1-9 9\"/>",
740
- ruler: "<path d=\"M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.41 2.41 0 0 1 0-3.4l2.6-2.6a2.41 2.41 0 0 1 3.4 0Z\"/><path d=\"m14.5 12.5 2-2\"/><path d=\"m11.5 9.5 2-2\"/><path d=\"m8.5 6.5 2-2\"/><path d=\"m17.5 15.5 2-2\"/>",
741
- type: "<polyline points=\"4 7 4 4 20 4 20 7\"/><line x1=\"9\" y1=\"20\" x2=\"15\" y2=\"20\"/><line x1=\"12\" y1=\"4\" x2=\"12\" y2=\"20\"/>",
742
- magnet: "<path d=\"m6 15-4-4 6.75-6.77a7.79 7.79 0 0 1 11 11L13 22l-4-4 6.39-6.36a2.14 2.14 0 0 0-3-3L6 15\"/><path d=\"m5 8 4 4\"/><path d=\"m12 15 4 4\"/>",
743
- undo: "<path d=\"M3 7v6h6\"/><path d=\"M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13\"/>",
744
- redo: "<path d=\"M21 7v6h-6\"/><path d=\"M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13\"/>",
745
- trash: "<path d=\"M3 6h18\"/><path d=\"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\"/><path d=\"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\"/><line x1=\"10\" y1=\"11\" x2=\"10\" y2=\"17\"/><line x1=\"14\" y1=\"11\" x2=\"14\" y2=\"17\"/>",
746
- camera: "<path d=\"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z\"/><circle cx=\"12\" cy=\"13\" r=\"3\"/>",
747
- settings: "<path d=\"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/>",
748
- moon: "<path d=\"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z\"/>",
749
- sun: "<circle cx=\"12\" cy=\"12\" r=\"4\"/><path d=\"M12 2v2\"/><path d=\"M12 20v2\"/><path d=\"m4.93 4.93 1.41 1.41\"/><path d=\"m17.66 17.66 1.41 1.41\"/><path d=\"M2 12h2\"/><path d=\"M20 12h2\"/><path d=\"m6.34 17.66-1.41 1.41\"/><path d=\"m19.07 4.93-1.41 1.41\"/>",
750
- chevronDown: "<path d=\"m6 9 6 6 6-6\"/>",
751
- chevronUp: "<path d=\"m18 15-6-6-6 6\"/>",
752
- barChart: "<line x1=\"12\" y1=\"20\" x2=\"12\" y2=\"10\"/><line x1=\"18\" y1=\"20\" x2=\"18\" y2=\"4\"/><line x1=\"6\" y1=\"20\" x2=\"6\" y2=\"16\"/>",
753
- x: "<path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/>",
754
- play: "<polygon points=\"6 3 20 12 6 21 6 3\"/>",
755
- pause: "<rect width=\"4\" height=\"16\" x=\"6\" y=\"4\"/><rect width=\"4\" height=\"16\" x=\"14\" y=\"4\"/>",
756
- stop: "<rect width=\"14\" height=\"14\" x=\"5\" y=\"5\" rx=\"1\"/>",
757
- 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\"/>",
758
- 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\"/>",
759
- plus: "<path d=\"M5 12h14\"/><path d=\"M12 5v14\"/>",
760
- 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\"/>",
761
- 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\"/>",
762
- 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\"/>",
763
- lock: "<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"/>",
764
- unlock: "<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 9.9-1\"/>",
765
- 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\"/>",
766
- trendingDown: "<polyline points=\"22 17 13.5 8.5 8.5 13.5 2 7\"/><polyline points=\"16 17 22 17 22 11\"/>",
767
- check: "<polyline points=\"20 6 9 17 4 12\"/>",
768
- 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\"/>"
769
- };
770
- function y(e, t = 14) {
771
- let n = v[e];
772
- 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>` : "";
1024
+ var S = (e, t) => Object.prototype.hasOwnProperty.call(e, t) ? e[t] : void 0;
1025
+ function C(e, t = 14) {
1026
+ let n = S(_, e);
1027
+ return n ? x(n, t) : "";
1028
+ }
1029
+ function w(e, t = 16) {
1030
+ return x(S(v, e) ?? _.penLine, t);
1031
+ }
1032
+ function T(e, t = 14) {
1033
+ return x(S(y, e) ?? _.barChart, t);
1034
+ }
1035
+ //#endregion
1036
+ //#region src/widget/escapeHtml.ts
1037
+ function E(e) {
1038
+ return e.replace(/[&<>"']/g, (e) => ({
1039
+ "&": "&amp;",
1040
+ "<": "&lt;",
1041
+ ">": "&gt;",
1042
+ "\"": "&quot;",
1043
+ "'": "&#39;"
1044
+ })[e]);
773
1045
  }
774
1046
  //#endregion
775
1047
  //#region src/widget/WidgetDropdown.ts
776
- var b = class {
1048
+ var D = class {
777
1049
  trigger;
778
1050
  panel;
779
1051
  _isOpen = !1;
@@ -804,37 +1076,39 @@ var b = class {
804
1076
  destroy() {
805
1077
  this.trigger.removeEventListener("click", this.onTriggerClick), document.removeEventListener("mousedown", this.onOutsideClick), document.removeEventListener("keydown", this.onEscapeKey), this.panel.remove();
806
1078
  }
807
- }, ne = class {
1079
+ }, se = class {
808
1080
  config;
809
1081
  callbacks;
810
1082
  t;
811
1083
  el;
812
1084
  chartTypeDropdown = null;
813
1085
  indicatorDropdown = null;
814
- tfButtons = [];
815
- chipsContainer = null;
1086
+ tfGroup = null;
1087
+ tfDropdown = null;
1088
+ tfFavorites = [];
1089
+ tfRendered = "";
816
1090
  themeBtn = null;
1091
+ fullscreenBtn = null;
817
1092
  constructor(e, t, n, r) {
818
1093
  this.config = t, this.callbacks = n, this.t = r, this.el = document.createElement("div"), this.el.className = "tcw-toolbar", this.build(), e.appendChild(this.el);
819
1094
  }
820
1095
  build() {
821
1096
  let { config: e, callbacks: t, el: n } = this, r = document.createElement("button");
822
- r.className = "tcw-toolbar-symbol", r.dataset.role = "symbol", r.addEventListener("click", t.onSymbolClick), n.appendChild(r), n.appendChild(this.sep());
823
- let i = document.createElement("div");
824
- i.className = "tcw-toolbar-group";
825
- for (let n of e.timeframes) {
826
- let e = document.createElement("button");
827
- e.className = "tcw-btn", e.textContent = n.label, e.dataset.tf = n.value, e.addEventListener("click", () => t.onTimeframe(n.value)), i.appendChild(e), this.tfButtons.push(e);
1097
+ if (r.className = "tcw-toolbar-symbol", r.dataset.role = "symbol", r.addEventListener("click", t.onSymbolClick), n.appendChild(r), n.appendChild(this.sep()), this.tfFavorites = [...e.timeframeFavorites ?? e.timeframes.map((e) => e.value)], this.tfGroup = document.createElement("div"), this.tfGroup.className = "tcw-toolbar-group", n.appendChild(this.tfGroup), t.onToggleTimeframeFavorite && e.timeframes.length > 0) {
1098
+ let e = document.createElement("div");
1099
+ e.style.position = "relative", e.style.display = "inline-flex";
1100
+ let t = document.createElement("button");
1101
+ t.className = "tcw-btn tcw-tf-more", t.dataset.role = "timeframes", t.title = this.t("toolbar.timeframes"), t.setAttribute("aria-label", this.t("toolbar.timeframes")), t.innerHTML = C("chevronDown", 12), e.appendChild(t), n.appendChild(e), this.tfDropdown = new D(e, { width: "150px" }), this.buildTimeframeMenu();
828
1102
  }
829
- n.appendChild(i), n.appendChild(this.sep());
830
- let a = document.createElement("div");
831
- a.style.position = "relative", a.style.display = "inline-flex";
832
- let o = document.createElement("button");
833
- 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());
834
- let s = document.createElement("div");
835
- s.style.position = "relative", s.style.display = "inline-flex";
836
- let c = document.createElement("button");
837
- if (c.className = "tcw-dropdown-trigger", c.dataset.role = "indicators", s.appendChild(c), n.appendChild(s), this.indicatorDropdown = new b(s, { width: "280px" }), this.buildIndicatorMenu(), this.chipsContainer = document.createElement("div"), this.chipsContainer.className = "tcw-indicator-chips", n.appendChild(this.chipsContainer), n.appendChild(this.spacer()), t.onToggleReplay) {
1103
+ n.appendChild(this.sep());
1104
+ let i = document.createElement("div");
1105
+ i.style.position = "relative", i.style.display = "inline-flex";
1106
+ let a = document.createElement("button");
1107
+ a.className = "tcw-dropdown-trigger", a.dataset.role = "charttype", i.appendChild(a), n.appendChild(i), this.chartTypeDropdown = new D(i, { width: "160px" }), this.buildChartTypeMenu(), n.appendChild(this.sep());
1108
+ let o = document.createElement("div");
1109
+ o.style.position = "relative", o.style.display = "inline-flex";
1110
+ let s = document.createElement("button");
1111
+ if (s.className = "tcw-dropdown-trigger", s.dataset.role = "indicators", o.appendChild(s), n.appendChild(o), this.indicatorDropdown = new D(o, { width: "280px" }), this.buildIndicatorMenu(), n.appendChild(this.spacer()), t.onToggleReplay) {
838
1112
  let e = this.iconBtn("play", this.t("toolbar.replay"), t.onToggleReplay);
839
1113
  e.dataset.role = "replay", n.appendChild(e);
840
1114
  }
@@ -856,10 +1130,15 @@ var b = class {
856
1130
  let e = this.iconBtn("bell", this.t("toolbar.priceAlerts"), t.onToggleAlerts);
857
1131
  e.dataset.role = "alerts", n.appendChild(e);
858
1132
  }
859
- let l = this.iconBtn("camera", this.t("toolbar.screenshot"), t.onScreenshot);
860
- n.appendChild(l);
861
- let u = this.iconBtn("settings", this.t("toolbar.settings"), t.onSettings);
862
- n.appendChild(u), this.themeBtn = this.iconBtn("moon", this.t("toolbar.toggleTheme"), t.onToggleTheme), this.themeBtn.dataset.role = "theme", n.appendChild(this.themeBtn);
1133
+ let c = this.iconBtn("camera", this.t("toolbar.screenshot"), t.onScreenshot);
1134
+ n.appendChild(c);
1135
+ let l = this.iconBtn("settings", this.t("toolbar.settings"), t.onSettings);
1136
+ n.appendChild(l), this.themeBtn = this.iconBtn("moon", this.t("toolbar.toggleTheme"), t.onToggleTheme), this.themeBtn.dataset.role = "theme", n.appendChild(this.themeBtn), t.onToggleFullscreen && (this.fullscreenBtn = this.iconBtn("maximize", this.t("toolbar.fullscreen"), t.onToggleFullscreen), this.fullscreenBtn.dataset.role = "fullscreen", this.fullscreenBtn.setAttribute("aria-pressed", "false"), n.appendChild(this.fullscreenBtn));
1137
+ }
1138
+ setFullscreen(e) {
1139
+ if (!this.fullscreenBtn) return;
1140
+ let t = this.t(e ? "toolbar.exitFullscreen" : "toolbar.fullscreen");
1141
+ this.fullscreenBtn.innerHTML = C(e ? "minimize" : "maximize", 14), this.fullscreenBtn.title = t, this.fullscreenBtn.setAttribute("aria-pressed", String(e));
863
1142
  }
864
1143
  chartTypeLabel(e) {
865
1144
  let t = `chartType.${e.value}`, n = this.t(t);
@@ -867,7 +1146,7 @@ var b = class {
867
1146
  }
868
1147
  buildChartTypeMenu() {
869
1148
  if (!this.chartTypeDropdown) return;
870
- let e = this.config.chartTypes.map((e) => `<button class="tcw-dropdown-item" data-ct="${e.value}">${this.chartTypeLabel(e)}</button>`).join("");
1149
+ let e = this.config.chartTypes.map((e) => `<button class="tcw-dropdown-item tcw-dropdown-item--icon" data-ct="${E(e.value)}">${T(e.value, 16)}<span>${E(this.chartTypeLabel(e))}</span></button>`).join("");
871
1150
  this.chartTypeDropdown.setContent(e), this.chartTypeDropdown.panel.querySelectorAll(".tcw-dropdown-item").forEach((e) => {
872
1151
  e.addEventListener("click", (e) => {
873
1152
  let t = e.currentTarget.dataset.ct;
@@ -875,13 +1154,43 @@ var b = class {
875
1154
  });
876
1155
  });
877
1156
  }
1157
+ setTimeframeFavorites(e) {
1158
+ this.tfFavorites = [...e], this.tfRendered = "", this.buildTimeframeMenu();
1159
+ }
1160
+ buildTimeframeMenu() {
1161
+ if (!this.tfDropdown) return;
1162
+ let e = E(this.t("toolbar.timeframes.pin")), t = `<div class="tcw-dropdown-label">${E(this.t("toolbar.timeframes"))}</div>`;
1163
+ for (let n of this.config.timeframes) {
1164
+ let r = this.tfFavorites.includes(n.value), [i, a] = [E(n.value), E(n.label)];
1165
+ t += `<div class="tcw-tf-row"><button class="tcw-dropdown-item" data-tf-pick="${i}">${a}</button><button class="tcw-tf-star${r ? " tcw-active" : ""}" data-tf-star="${i}" aria-pressed="${r}" title="${e}" aria-label="${e}: ${a}">${C("star", 12)}</button></div>`;
1166
+ }
1167
+ this.tfDropdown.setContent(t);
1168
+ let n = this.tfDropdown.panel;
1169
+ n.querySelectorAll("[data-tf-pick]").forEach((e) => {
1170
+ e.addEventListener("click", () => this.callbacks.onTimeframe(e.dataset.tfPick));
1171
+ }), n.querySelectorAll("[data-tf-star]").forEach((e) => {
1172
+ e.addEventListener("click", (t) => {
1173
+ t.stopPropagation(), this.callbacks.onToggleTimeframeFavorite?.(e.dataset.tfStar);
1174
+ });
1175
+ });
1176
+ }
1177
+ renderTimeframes(e) {
1178
+ if (!this.tfGroup) return;
1179
+ let t = this.config.timeframes.filter((t) => this.tfFavorites.includes(t.value) || t.value === e), n = `${t.map((e) => e.value).join(",")}|${e}`;
1180
+ n !== this.tfRendered && (this.tfRendered = n, this.tfGroup.replaceChildren(...t.map((t) => {
1181
+ let n = document.createElement("button");
1182
+ return n.className = "tcw-btn", n.textContent = t.label, n.dataset.tf = t.value, n.classList.toggle("tcw-active", t.value === e), n.addEventListener("click", () => this.callbacks.onTimeframe(t.value)), n;
1183
+ })), (this.tfDropdown?.panel)?.querySelectorAll("[data-tf-pick]").forEach((t) => {
1184
+ t.classList.toggle("tcw-active", t.dataset.tfPick === e);
1185
+ }));
1186
+ }
878
1187
  buildIndicatorMenu() {
879
1188
  if (!this.indicatorDropdown) return;
880
- let { indicators: e, popularIndicatorIds: t } = this.config, n = e.filter((e) => t.includes(e.id)), r = e.filter((e) => !t.includes(e.id)), i = (e) => this.t(`indicatorType.${e}`), a = `<div class="tcw-dropdown-label">${this.t("toolbar.indicators.popular")}</div>`;
881
- for (let e of n) a += `<button class="tcw-dropdown-item" data-ind="${e.id}"><span>${e.name}</span><span class="tcw-tag">${i(e.type)}</span></button>`;
882
- a += "<div class=\"tcw-dropdown-divider\"></div>", a += `<div class="tcw-dropdown-label">${this.t("toolbar.indicators.all")}</div>`;
883
- for (let e of r) a += `<button class="tcw-dropdown-item" data-ind="${e.id}"><span>${e.name}</span><span class="tcw-tag">${i(e.type)}</span></button>`;
884
- this.indicatorDropdown.setContent(a), this.indicatorDropdown.panel.querySelectorAll(".tcw-dropdown-item[data-ind]").forEach((e) => {
1189
+ let { indicators: e, popularIndicatorIds: t } = this.config, n = e.filter((e) => t.includes(e.id)), r = e.filter((e) => !t.includes(e.id)), i = (e) => this.t(`indicatorType.${e}`), a = (e) => `<button class="tcw-dropdown-item" data-ind="${E(e.id)}"><span>${E(e.name)}</span><span class="tcw-tag">${E(i(e.type))}</span></button>`, o = `<div class="tcw-dropdown-label">${E(this.t("toolbar.indicators.popular"))}</div>`;
1190
+ for (let e of n) o += a(e);
1191
+ o += "<div class=\"tcw-dropdown-divider\"></div>", o += `<div class="tcw-dropdown-label">${E(this.t("toolbar.indicators.all"))}</div>`;
1192
+ for (let e of r) o += a(e);
1193
+ this.indicatorDropdown.setContent(o), this.indicatorDropdown.panel.querySelectorAll(".tcw-dropdown-item[data-ind]").forEach((e) => {
885
1194
  e.addEventListener("click", (e) => {
886
1195
  let t = e.currentTarget.dataset.ind;
887
1196
  this.callbacks.onAddIndicator(t);
@@ -890,40 +1199,18 @@ var b = class {
890
1199
  }
891
1200
  update(e) {
892
1201
  let t = this.el.querySelector("[data-role=\"symbol\"]");
893
- t && (t.textContent = e.symbol);
894
- for (let t of this.tfButtons) t.classList.toggle("tcw-active", t.dataset.tf === e.timeframe);
1202
+ t && (t.textContent = e.symbol), this.renderTimeframes(e.timeframe);
895
1203
  let n = this.el.querySelector("[data-role=\"charttype\"]");
896
1204
  if (n) {
897
1205
  let t = this.config.chartTypes.find((t) => t.value === e.chartType), r = t ? this.chartTypeLabel(t) : e.chartType;
898
- n.innerHTML = `${y("barChart", 14)} ${r} ${y("chevronDown", 12)}`;
1206
+ n.innerHTML = `${T(e.chartType, 14)} ${E(r)} ${C("chevronDown", 12)}`;
899
1207
  }
900
1208
  let r = this.el.querySelector("[data-role=\"indicators\"]");
901
1209
  if (r) {
902
- let t = e.activeIndicators.size, n = `${y("trendingUp", 14)} ${this.t("toolbar.indicators")}`;
1210
+ let t = e.activeIndicators.size, n = `${C("trendingUp", 14)} ${this.t("toolbar.indicators")}`;
903
1211
  t > 0 && (n += ` <span class="tcw-badge-count">${t}</span>`), r.innerHTML = n;
904
1212
  }
905
- if (this.chipsContainer) {
906
- let t = this.getActiveIndicatorList(e);
907
- this.chipsContainer.innerHTML = "";
908
- for (let e of t) {
909
- let t = document.createElement("div");
910
- t.className = "tcw-indicator-chip";
911
- let n = document.createElement("span");
912
- n.textContent = e.label, t.appendChild(n);
913
- let r = document.createElement("button");
914
- 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);
915
- }
916
- }
917
- this.themeBtn && (this.themeBtn.innerHTML = e.isDark ? y("moon", 14) : y("sun", 14));
918
- }
919
- getActiveIndicatorList(e) {
920
- let t = [];
921
- for (let [n, r] of e.activeIndicators.entries()) t.push({
922
- instanceId: r,
923
- id: n,
924
- label: n.toUpperCase()
925
- });
926
- return t;
1213
+ this.themeBtn && (this.themeBtn.innerHTML = e.isDark ? C("moon", 14) : C("sun", 14));
927
1214
  }
928
1215
  sep() {
929
1216
  let e = document.createElement("span");
@@ -935,84 +1222,33 @@ var b = class {
935
1222
  }
936
1223
  iconBtn(e, t, n) {
937
1224
  let r = document.createElement("button");
938
- return r.className = "tcw-btn-icon", r.title = t, r.innerHTML = y(e, 14), r.addEventListener("click", n), r;
1225
+ return r.className = "tcw-btn-icon", r.title = t, r.innerHTML = C(e, 14), r.addEventListener("click", n), r;
939
1226
  }
940
1227
  destroy() {
941
1228
  this.chartTypeDropdown?.destroy(), this.indicatorDropdown?.destroy(), this.el.remove();
942
1229
  }
943
- }, re = [
944
- "trendingUp",
945
- "minus",
946
- "penLine",
947
- "hash",
948
- "square",
949
- "gitBranch",
950
- "zigzag",
951
- "ruler",
952
- "type",
953
- "ladder"
954
- ], ie = {
955
- trendLine: "trendingUp",
956
- ray: "trendingUp",
957
- extendedLine: "trendingUp",
958
- infoLine: "trendingUp",
959
- trendAngle: "trendingUp",
960
- horizontalLine: "minus",
961
- horizontalRay: "minus",
962
- verticalLine: "penLine",
963
- crossLine: "plus",
964
- rectangle: "square",
965
- circle: "square",
966
- ellipse: "square",
967
- triangle: "square",
968
- arrow: "trendingUp",
969
- parallelChannel: "gitBranch",
970
- regressionChannel: "gitBranch",
971
- pitchfork: "gitBranch",
972
- schiffPitchfork: "gitBranch",
973
- modifiedSchiffPitchfork: "gitBranch",
974
- fibRetracement: "hash",
975
- fibExtension: "hash",
976
- fibTimeZones: "hash",
977
- fibChannel: "hash",
978
- fibSpeedResistanceFan: "hash",
979
- gannBox: "hash",
980
- gannFan: "gitBranch",
981
- cyclicLines: "barChart",
982
- elliottWave: "zigzag",
983
- xabcdPattern: "zigzag",
984
- abcdPattern: "zigzag",
985
- headAndShoulders: "zigzag",
986
- priceRange: "ruler",
987
- dateRange: "ruler",
988
- dateAndPriceRange: "ruler",
989
- measure: "ruler",
990
- text: "type",
991
- textAnnotation: "type",
992
- priceLabel: "type",
993
- anchoredVWAP: "trendingUp",
994
- volumeProfileRange: "barChart",
995
- riskReward: "square"
996
- };
997
- function ae(e) {
998
- return ie[e] ?? "penLine";
999
- }
1000
- function oe(e, t) {
1230
+ }, O = 16, ce = 150;
1231
+ function k(e, t) {
1001
1232
  for (let n of e) {
1002
1233
  let e = n.tools.find((e) => e.value === t);
1003
1234
  if (e) return e.label;
1004
1235
  }
1005
1236
  return t;
1006
1237
  }
1007
- var se = class {
1238
+ var le = class {
1008
1239
  config;
1009
1240
  callbacks;
1010
1241
  el;
1011
1242
  groupWraps = [];
1012
1243
  groupButtons = [];
1244
+ groupIcons = [];
1245
+ groupTools = [];
1013
1246
  cursorBtn = null;
1014
1247
  magnetBtn = null;
1248
+ stayBtn = null;
1015
1249
  flyoutEl = null;
1250
+ flyoutIdx = -1;
1251
+ flyoutHideTimer = null;
1016
1252
  favoritesEl = null;
1017
1253
  favoritesDivider = null;
1018
1254
  favorites = [];
@@ -1021,28 +1257,37 @@ var se = class {
1021
1257
  }
1022
1258
  build() {
1023
1259
  let { config: e, callbacks: t, el: n } = this;
1024
- 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) => {
1260
+ this.cursorBtn = document.createElement("button"), this.cursorBtn.className = "tcw-sidebar-btn", this.cursorBtn.title = "Cursor", this.cursorBtn.innerHTML = C("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) => {
1025
1261
  let i = document.createElement("div");
1026
1262
  i.className = "tcw-tool-group-wrap";
1027
1263
  let a = document.createElement("button");
1028
- if (a.className = "tcw-sidebar-btn", a.title = e.label, a.innerHTML = y(re[r] ?? "square", 14), e.tools.length > 1) {
1264
+ a.className = "tcw-sidebar-btn";
1265
+ let o = e.tools[0]?.value;
1266
+ if (!o) return;
1267
+ e.tools.length > 1 ? a.setAttribute("aria-label", `${e.label}: ${e.tools[0].label}`) : a.title = e.label;
1268
+ let s = document.createElement("span");
1269
+ if (s.className = "tcw-sidebar-icon", s.innerHTML = w(o, O), a.appendChild(s), this.groupIcons.push(s), this.groupTools.push(o), e.tools.length > 1) {
1029
1270
  let e = document.createElement("span");
1030
1271
  e.className = "tcw-multi-dot", a.appendChild(e);
1031
1272
  }
1032
- 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);
1273
+ a.addEventListener("click", () => t.onDrawingTool(this.groupTools[r])), i.appendChild(a), i.addEventListener("mouseenter", () => this.showFlyout(r)), i.addEventListener("mouseleave", () => this.scheduleHideFlyout()), a.addEventListener("focus", () => {
1274
+ a.matches(":focus-visible") && this.showFlyout(r);
1275
+ }), i.addEventListener("focusout", (e) => {
1276
+ i.contains(e.relatedTarget) || this.scheduleHideFlyout();
1277
+ }), n.appendChild(i), this.groupWraps.push(i), this.groupButtons.push(a);
1033
1278
  });
1034
1279
  let r = document.createElement("div");
1035
1280
  if (r.className = "tcw-sidebar-spacer", n.appendChild(r), n.appendChild(this.divider()), t.onToggleStyle) {
1036
1281
  let e = document.createElement("button");
1037
- 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);
1282
+ e.className = "tcw-sidebar-btn", e.title = "Drawing style & templates", e.dataset.role = "style", e.innerHTML = C("palette", 14), e.addEventListener("click", t.onToggleStyle), n.appendChild(e);
1038
1283
  }
1039
- 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);
1284
+ t.onToggleMagnet && (this.magnetBtn = document.createElement("button"), this.magnetBtn.className = "tcw-sidebar-btn", this.magnetBtn.title = "Magnet", this.magnetBtn.innerHTML = C("magnet", 14), this.magnetBtn.addEventListener("click", t.onToggleMagnet), n.appendChild(this.magnetBtn)), t.onToggleStayInDrawing && (this.stayBtn = document.createElement("button"), this.stayBtn.className = "tcw-sidebar-btn", this.stayBtn.dataset.role = "stay", this.stayBtn.title = "Stay in drawing mode", this.stayBtn.setAttribute("aria-pressed", "false"), this.stayBtn.innerHTML = C("repeat", 14), this.stayBtn.addEventListener("click", t.onToggleStayInDrawing), n.appendChild(this.stayBtn));
1040
1285
  let i = document.createElement("button");
1041
- i.className = "tcw-sidebar-btn", i.title = "Undo", i.innerHTML = y("undo", 14), i.addEventListener("click", t.onUndo), n.appendChild(i);
1286
+ i.className = "tcw-sidebar-btn", i.title = "Undo", i.innerHTML = C("undo", 14), i.addEventListener("click", t.onUndo), n.appendChild(i);
1042
1287
  let a = document.createElement("button");
1043
- a.className = "tcw-sidebar-btn", a.title = "Redo", a.innerHTML = y("redo", 14), a.addEventListener("click", t.onRedo), n.appendChild(a);
1288
+ a.className = "tcw-sidebar-btn", a.title = "Redo", a.innerHTML = C("redo", 14), a.addEventListener("click", t.onRedo), n.appendChild(a);
1044
1289
  let o = document.createElement("button");
1045
- o.className = "tcw-sidebar-btn tcw-danger", o.title = "Clear all", o.innerHTML = y("trash", 14), o.addEventListener("click", t.onClearDrawings), n.appendChild(o);
1290
+ o.className = "tcw-sidebar-btn tcw-danger", o.title = "Clear all", o.innerHTML = C("trash", 14), o.addEventListener("click", t.onClearDrawings), n.appendChild(o);
1046
1291
  }
1047
1292
  setFavorites(e) {
1048
1293
  this.favorites = [...e], this.renderFavorites();
@@ -1054,14 +1299,18 @@ var se = class {
1054
1299
  this.favoritesEl.style.display = e ? "" : "none", this.favoritesDivider && (this.favoritesDivider.style.display = e ? "" : "none");
1055
1300
  for (let e of this.favorites) {
1056
1301
  let t = document.createElement("button");
1057
- 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) => {
1302
+ t.className = "tcw-sidebar-btn", t.title = `${k(this.config.drawingToolGroups, e)} (right-click to unpin)`, t.dataset.toolValue = e, t.innerHTML = w(e, O), t.addEventListener("click", () => this.callbacks.onDrawingTool(e)), t.addEventListener("contextmenu", (t) => {
1058
1303
  t.preventDefault(), this.callbacks.onToggleFavorite?.(e);
1059
1304
  }), this.favoritesEl.appendChild(t);
1060
1305
  }
1061
1306
  }
1062
1307
  showFlyout(e) {
1308
+ if (this.cancelHideFlyout(), this.flyoutEl && this.flyoutIdx === e) return;
1063
1309
  let t = this.config.drawingToolGroups[e];
1064
- if (!t || t.tools.length <= 1) return;
1310
+ if (!t || t.tools.length <= 1) {
1311
+ this.hideFlyout();
1312
+ return;
1313
+ }
1065
1314
  this.hideFlyout();
1066
1315
  let n = document.createElement("div");
1067
1316
  n.className = "tcw-flyout";
@@ -1069,28 +1318,42 @@ var se = class {
1069
1318
  r.className = "tcw-flyout-header", r.textContent = t.label, n.appendChild(r);
1070
1319
  for (let e of t.tools) {
1071
1320
  let t = document.createElement("button");
1072
- t.className = "tcw-flyout-item", t.textContent = e.label, t.dataset.toolValue = e.value, t.addEventListener("click", () => {
1321
+ t.className = "tcw-flyout-item", t.innerHTML = w(e.value, O);
1322
+ let r = document.createElement("span");
1323
+ r.textContent = e.label, t.appendChild(r), t.dataset.toolValue = e.value, t.addEventListener("click", () => {
1073
1324
  this.callbacks.onDrawingTool(e.value), this.hideFlyout();
1074
- }), 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) => {
1325
+ }), this.callbacks.onToggleFavorite && (this.favorites.includes(e.value) && t.classList.add("tcw-flyout-faved"), t.addEventListener("contextmenu", (t) => {
1075
1326
  t.preventDefault(), this.callbacks.onToggleFavorite?.(e.value);
1076
1327
  })), n.appendChild(t);
1077
1328
  }
1078
- this.flyoutEl = n, this.groupWraps[e].appendChild(n);
1329
+ if (this.callbacks.onToggleFavorite) {
1330
+ let e = document.createElement("div");
1331
+ e.className = "tcw-flyout-hint", e.textContent = "Right-click a tool to pin it", n.appendChild(e);
1332
+ }
1333
+ this.flyoutEl = n, this.flyoutIdx = e, this.groupWraps[e].appendChild(n);
1334
+ }
1335
+ scheduleHideFlyout() {
1336
+ this.cancelHideFlyout(), this.flyoutHideTimer = setTimeout(() => {
1337
+ this.flyoutHideTimer = null, this.hideFlyout();
1338
+ }, ce);
1339
+ }
1340
+ cancelHideFlyout() {
1341
+ this.flyoutHideTimer !== null && (clearTimeout(this.flyoutHideTimer), this.flyoutHideTimer = null);
1079
1342
  }
1080
1343
  hideFlyout() {
1081
- this.flyoutEl &&= (this.flyoutEl.remove(), null);
1344
+ this.cancelHideFlyout(), this.flyoutEl &&= (this.flyoutEl.remove(), null), this.flyoutIdx = -1;
1082
1345
  }
1083
1346
  update(e) {
1084
1347
  this.cursorBtn && this.cursorBtn.classList.toggle("tcw-active", e.activeTool === null);
1085
1348
  let { drawingToolGroups: t } = this.config;
1086
1349
  for (let n = 0; n < t.length; n++) {
1087
1350
  let r = t[n].tools.some((t) => t.value === e.activeTool);
1088
- this.groupButtons[n].classList.toggle("tcw-active", r);
1351
+ this.groupButtons[n].classList.toggle("tcw-active", r), r && e.activeTool && e.activeTool !== this.groupTools[n] && (this.groupTools[n] = e.activeTool, this.groupIcons[n].innerHTML = w(e.activeTool, O), t[n].tools.length > 1 && this.groupButtons[n].setAttribute("aria-label", `${t[n].label}: ${k(t, e.activeTool)}`));
1089
1352
  }
1090
1353
  this.flyoutEl && this.flyoutEl.querySelectorAll(".tcw-flyout-item").forEach((t) => {
1091
1354
  let n = t;
1092
1355
  n.classList.toggle("tcw-active", n.dataset.toolValue === e.activeTool);
1093
- }), this.magnetBtn && (this.magnetBtn.classList.toggle("tcw-active", e.magnetEnabled), this.magnetBtn.title = e.magnetEnabled ? "Magnet ON" : "Magnet OFF");
1356
+ }), this.magnetBtn && (this.magnetBtn.classList.toggle("tcw-active", e.magnetEnabled), this.magnetBtn.title = e.magnetEnabled ? "Magnet ON" : "Magnet OFF"), this.stayBtn && (this.stayBtn.classList.toggle("tcw-active", e.stayInDrawing), this.stayBtn.setAttribute("aria-pressed", String(e.stayInDrawing)));
1094
1357
  }
1095
1358
  divider() {
1096
1359
  let e = document.createElement("div");
@@ -1099,11 +1362,11 @@ var se = class {
1099
1362
  destroy() {
1100
1363
  this.hideFlyout(), this.el.remove();
1101
1364
  }
1102
- }, x = [
1365
+ }, ue = [
1103
1366
  "style",
1104
1367
  "display",
1105
1368
  "scale"
1106
- ], S = class {
1369
+ ], de = class {
1107
1370
  callbacks;
1108
1371
  t;
1109
1372
  backdrop = null;
@@ -1112,8 +1375,8 @@ var se = class {
1112
1375
  currentSettings = null;
1113
1376
  bodyEl = null;
1114
1377
  tabButtons = [];
1115
- constructor(e, t) {
1116
- this.callbacks = e, this.t = t;
1378
+ constructor(e, t, n = {}, r = () => document.body) {
1379
+ this.available = n, this.host = r, this.callbacks = e, this.t = t;
1117
1380
  }
1118
1381
  open(e) {
1119
1382
  this.currentSettings = { ...e }, this.currentTab = "style", this.buildModal();
@@ -1124,18 +1387,18 @@ var se = class {
1124
1387
  buildModal() {
1125
1388
  this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.addEventListener("click", () => {
1126
1389
  this.callbacks.onClose(), this.close();
1127
- }), document.body.appendChild(this.backdrop), this.modal = document.createElement("div"), this.modal.className = "tcw-modal";
1390
+ }), this.host().appendChild(this.backdrop), this.modal = document.createElement("div"), this.modal.className = "tcw-modal";
1128
1391
  let e = document.createElement("div");
1129
1392
  e.className = "tcw-modal-header";
1130
1393
  let t = document.createElement("h3");
1131
1394
  t.textContent = this.t("settings.title"), e.appendChild(t);
1132
1395
  let n = document.createElement("button");
1133
- n.className = "tcw-modal-close", n.innerHTML = y("x", 16), n.addEventListener("click", () => {
1396
+ n.className = "tcw-modal-close", n.innerHTML = C("x", 16), n.addEventListener("click", () => {
1134
1397
  this.callbacks.onClose(), this.close();
1135
1398
  }), e.appendChild(n), this.modal.appendChild(e);
1136
1399
  let r = document.createElement("div");
1137
1400
  r.className = "tcw-modal-tabs", this.tabButtons = [];
1138
- for (let e of x) {
1401
+ for (let e of ue) {
1139
1402
  let t = document.createElement("button");
1140
1403
  t.className = "tcw-modal-tab", t.textContent = this.t(`settings.tab.${e}`), t.dataset.tab = e, e === this.currentTab && t.classList.add("tcw-active"), t.addEventListener("click", () => {
1141
1404
  this.currentTab = e, this.tabButtons.forEach((t) => t.classList.toggle("tcw-active", t.dataset.tab === e)), this.renderTabContent();
@@ -1149,7 +1412,7 @@ var se = class {
1149
1412
  let o = document.createElement("button");
1150
1413
  o.className = "tcw-done-btn", o.textContent = this.t("settings.done"), o.addEventListener("click", () => {
1151
1414
  this.callbacks.onClose(), this.close();
1152
- }), i.appendChild(o), this.modal.appendChild(i), document.body.appendChild(this.modal);
1415
+ }), i.appendChild(o), this.modal.appendChild(i), this.host().appendChild(this.modal);
1153
1416
  let s = (e) => {
1154
1417
  e.key === "Escape" && (document.removeEventListener("keydown", s), this.callbacks.onClose(), this.close());
1155
1418
  };
@@ -1184,7 +1447,7 @@ var se = class {
1184
1447
  }, {
1185
1448
  value: "week",
1186
1449
  label: "Prior Week (PWH/PWL)"
1187
- }], (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, [
1450
+ }], (e) => this.patch({ periodLevelsPeriod: e }))), t.appendChild(this.toggleRow("OHLC Legend", e.legendVisible, (e) => this.patch({ legendVisible: e }))), this.available.barCountdown !== !1 && t.appendChild(this.toggleRow("Bar Countdown", e.barCountdown, (e) => this.patch({ barCountdown: e }))), t.appendChild(this.selectRow("Crosshair Mode", e.crosshairMode, [
1188
1451
  {
1189
1452
  label: "Magnet",
1190
1453
  value: "magnet"
@@ -1260,7 +1523,8 @@ var se = class {
1260
1523
  renderScaleTab() {
1261
1524
  if (!this.bodyEl || !this.currentSettings) return;
1262
1525
  let e = this.currentSettings, t = this.section();
1263
- t.appendChild(this.toggleRow("Auto Scale", e.autoScale, (e) => this.patch({ autoScale: e }))), t.appendChild(this.selectRow("Price Scale", e.scaleMode, [
1526
+ t.appendChild(this.toggleRow("Auto Scale", e.autoScale, (e) => this.patch({ autoScale: e }))), t.appendChild(this.toggleRow("Invert Scale (Alt+I)", e.invertScale, (e) => this.patch({ invertScale: e })));
1527
+ let n = [
1264
1528
  {
1265
1529
  value: "regular",
1266
1530
  label: "Regular"
@@ -1277,7 +1541,8 @@ var se = class {
1277
1541
  value: "indexedTo100",
1278
1542
  label: "Indexed to 100"
1279
1543
  }
1280
- ], (e) => this.patch({ scaleMode: e }))), this.bodyEl.appendChild(t);
1544
+ ].filter((e) => e.value !== "logarithmic" || this.available.logScale !== !1);
1545
+ t.appendChild(this.selectRow("Price Scale", e.scaleMode, n, (e) => this.patch({ scaleMode: e }))), this.bodyEl.appendChild(t);
1281
1546
  }
1282
1547
  patch(e) {
1283
1548
  this.currentSettings && Object.assign(this.currentSettings, e), this.callbacks.onChange(e);
@@ -1346,15 +1611,17 @@ var se = class {
1346
1611
  destroy() {
1347
1612
  this.close();
1348
1613
  }
1349
- }, C = class {
1614
+ }, fe = class {
1350
1615
  el;
1351
1616
  dotEl;
1352
1617
  messageEl;
1353
1618
  infoEl;
1354
- constructor(e) {
1355
- this.el = document.createElement("div"), this.el.className = "tcw-statusbar";
1356
- let t = document.createElement("div");
1357
- t.className = "tcw-status-indicator", this.dotEl = document.createElement("span"), this.dotEl.className = "tcw-status-dot", t.appendChild(this.dotEl), this.messageEl = document.createElement("span"), t.appendChild(this.messageEl), this.el.appendChild(t), this.infoEl = document.createElement("span"), this.el.appendChild(this.infoEl), e.appendChild(this.el);
1619
+ constructor(e, t) {
1620
+ this.el = document.createElement("div"), this.el.className = "tcw-statusbar", t && this.el.appendChild(this.buildRange(t));
1621
+ let n = document.createElement("div");
1622
+ n.className = "tcw-status-right";
1623
+ let r = document.createElement("div");
1624
+ r.className = "tcw-status-indicator", this.dotEl = document.createElement("span"), this.dotEl.className = "tcw-status-dot", r.appendChild(this.dotEl), this.messageEl = document.createElement("span"), r.appendChild(this.messageEl), n.appendChild(r), this.infoEl = document.createElement("span"), this.infoEl.className = "tcw-status-info", n.appendChild(this.infoEl), this.el.appendChild(n), e.appendChild(this.el);
1358
1625
  }
1359
1626
  update(e) {
1360
1627
  this.dotEl.className = "tcw-status-dot", e.connectionState === "connected" ? this.dotEl.classList.add("tcw-connected") : e.connectionState === "error" && this.dotEl.classList.add("tcw-error"), this.messageEl.textContent = e.message, this.infoEl.textContent = `${e.symbol} ${e.timeframe}`;
@@ -1362,7 +1629,17 @@ var se = class {
1362
1629
  destroy() {
1363
1630
  this.el.remove();
1364
1631
  }
1365
- }, w = class {
1632
+ buildRange(e) {
1633
+ let t = document.createElement("div");
1634
+ t.className = "tcw-range-bar", t.setAttribute("role", "group"), t.setAttribute("aria-label", e.groupLabel);
1635
+ for (let n of e.presets) {
1636
+ let r = document.createElement("button");
1637
+ r.type = "button", r.className = "tcw-range-btn", r.dataset.range = n, r.textContent = e.presetLabels?.[n] ?? n, r.addEventListener("click", () => e.onPreset(n)), t.appendChild(r);
1638
+ }
1639
+ let n = document.createElement("button");
1640
+ return n.type = "button", n.className = "tcw-range-btn tcw-range-goto", n.dataset.role = "goto", n.title = `${e.goToLabel} (Alt+G)`, n.setAttribute("aria-label", e.goToLabel), n.innerHTML = C("calendar", 13), n.addEventListener("click", e.onGoTo), t.appendChild(n), t;
1641
+ }
1642
+ }, pe = class {
1366
1643
  backdrop = null;
1367
1644
  modal = null;
1368
1645
  input = null;
@@ -1372,8 +1649,8 @@ var se = class {
1372
1649
  selectedIndex = 0;
1373
1650
  callbacks;
1374
1651
  boundKeydown;
1375
- constructor(e) {
1376
- this.callbacks = e, this.boundKeydown = this.handleKeydown.bind(this);
1652
+ constructor(e, t = () => document.body) {
1653
+ this.host = t, this.callbacks = e, this.boundKeydown = this.handleKeydown.bind(this);
1377
1654
  }
1378
1655
  open(e) {
1379
1656
  if (this.backdrop) return;
@@ -1385,7 +1662,7 @@ var se = class {
1385
1662
  let r = document.createElement("span");
1386
1663
  r.className = "tcw-cmd-hint", r.textContent = "ESC", t.appendChild(r), this.modal.appendChild(t), this.list = document.createElement("div"), this.list.className = "tcw-cmd-list", this.modal.appendChild(this.list);
1387
1664
  let i = document.createElement("div");
1388
- i.className = "tcw-cmd-footer", i.innerHTML = "<span>↑↓ Navigate</span><span>⏎ Select</span><span>Esc Close</span>", this.modal.appendChild(i), document.body.appendChild(this.backdrop), document.body.appendChild(this.modal), this.renderList(), this.input.focus(), document.addEventListener("keydown", this.boundKeydown);
1665
+ i.className = "tcw-cmd-footer", i.innerHTML = "<span>↑↓ Navigate</span><span>⏎ Select</span><span>Esc Close</span>", this.modal.appendChild(i), this.host().append(this.backdrop, this.modal), this.renderList(), this.input.focus(), document.addEventListener("keydown", this.boundKeydown);
1389
1666
  }
1390
1667
  close() {
1391
1668
  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();
@@ -1487,7 +1764,7 @@ var se = class {
1487
1764
  destroy() {
1488
1765
  this.close();
1489
1766
  }
1490
- }, T = class {
1767
+ }, me = class {
1491
1768
  backdrop = null;
1492
1769
  modal = null;
1493
1770
  input = null;
@@ -1499,8 +1776,8 @@ var se = class {
1499
1776
  callbacks;
1500
1777
  boundKeydown;
1501
1778
  pickOverride = null;
1502
- constructor(e) {
1503
- this.callbacks = e, this.boundKeydown = this.handleKeydown.bind(this);
1779
+ constructor(e, t = () => document.body) {
1780
+ this.host = t, this.callbacks = e, this.boundKeydown = this.handleKeydown.bind(this);
1504
1781
  }
1505
1782
  open(e, t, n) {
1506
1783
  if (this.backdrop) return;
@@ -1511,11 +1788,11 @@ var se = class {
1511
1788
  let r = document.createElement("div");
1512
1789
  r.className = "tcw-cmd-header";
1513
1790
  let i = document.createElement("span");
1514
- i.className = "tcw-cmd-icon", i.innerHTML = k(), r.appendChild(i), this.input = document.createElement("input"), this.input.className = "tcw-cmd-input", this.input.type = "text", this.input.placeholder = "Search symbol… (e.g. BTC, ETH, AAPL)", this.input.autocomplete = "off", this.input.spellcheck = !1, this.input.addEventListener("input", () => this.filter()), r.appendChild(this.input);
1791
+ i.className = "tcw-cmd-icon", i.innerHTML = _e(), 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);
1515
1792
  let a = document.createElement("span");
1516
1793
  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);
1517
1794
  let o = document.createElement("div");
1518
- 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);
1795
+ o.className = "tcw-cmd-footer", o.innerHTML = "<span>↑↓ Navigate</span><span>⏎ Open</span><span>Esc Close</span>", this.modal.appendChild(o), this.host().append(this.backdrop, this.modal), this.renderList(), this.input.focus(), document.addEventListener("keydown", this.boundKeydown);
1519
1796
  }
1520
1797
  close() {
1521
1798
  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();
@@ -1530,7 +1807,7 @@ var se = class {
1530
1807
  let e = (this.input?.value ?? "").toUpperCase().trim();
1531
1808
  e ? this.filtered = this.symbols.map((t) => ({
1532
1809
  symbol: t,
1533
- score: E(t.toUpperCase(), e)
1810
+ score: he(t.toUpperCase(), e)
1534
1811
  })).filter((e) => e.score > 0).sort((e, t) => t.score - e.score) : this.filtered = this.symbols.map((e) => ({
1535
1812
  symbol: e,
1536
1813
  score: 0
@@ -1548,7 +1825,7 @@ var se = class {
1548
1825
  let { symbol: n } = this.filtered[t], r = document.createElement("button");
1549
1826
  r.className = "tcw-cmd-item", t === this.selectedIndex && r.classList.add("tcw-selected"), n === this.current && r.classList.add("tcw-active");
1550
1827
  let i = document.createElement("span");
1551
- if (i.className = "tcw-cmd-item-label", i.innerHTML = D(n, e), r.appendChild(i), n === this.current) {
1828
+ if (i.className = "tcw-cmd-item-label", i.innerHTML = ge(n, e), r.appendChild(i), n === this.current) {
1552
1829
  let e = document.createElement("span");
1553
1830
  e.className = "tcw-cmd-check", e.textContent = "✓", r.appendChild(e);
1554
1831
  }
@@ -1585,7 +1862,7 @@ var se = class {
1585
1862
  }
1586
1863
  }
1587
1864
  };
1588
- function E(e, t) {
1865
+ function he(e, t) {
1589
1866
  if (e === t) return 1e3;
1590
1867
  if (e.startsWith(t)) return 500 + (50 - Math.min(50, e.length - t.length));
1591
1868
  if (e.includes(t)) return 200 + (50 - Math.min(50, e.length - t.length));
@@ -1593,44 +1870,43 @@ function E(e, t) {
1593
1870
  for (let a = 0; a < e.length && n < t.length; a++) e[a] === t[n] && (r >= 0 && (i += a - r - 1), r = a, n++);
1594
1871
  return n < t.length ? 0 : 100 - Math.min(99, i);
1595
1872
  }
1596
- function D(e, t) {
1597
- if (!t) return O(e);
1873
+ function ge(e, t) {
1874
+ if (!t) return E(e);
1598
1875
  let n = e.toUpperCase(), r = "", i = 0;
1599
- for (let a = 0; a < e.length; a++) i < t.length && n[a] === t[i] ? (r += `<mark style="background:transparent;color:var(--tcw-accent);font-weight:700">${O(e[a])}</mark>`, i++) : r += O(e[a]);
1876
+ for (let a = 0; a < e.length; a++) i < t.length && n[a] === t[i] ? (r += `<mark style="background:transparent;color:var(--tcw-accent);font-weight:700">${E(e[a])}</mark>`, i++) : r += E(e[a]);
1600
1877
  return r;
1601
1878
  }
1602
- function O(e) {
1603
- return e.replace(/[&<>"']/g, (e) => ({
1604
- "&": "&amp;",
1605
- "<": "&lt;",
1606
- ">": "&gt;",
1607
- "\"": "&quot;",
1608
- "'": "&#39;"
1609
- })[e]);
1610
- }
1611
- function k() {
1879
+ function _e() {
1612
1880
  return "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"m21 21-4.3-4.3\"/></svg>";
1613
1881
  }
1614
1882
  //#endregion
1615
1883
  //#region src/widget/WidgetHotkeySheet.ts
1616
- var A = {
1884
+ var ve = {
1617
1885
  "Search & navigation": "hotkeys.group.searchNavigation",
1618
1886
  "Chart manipulation": "hotkeys.group.chartManipulation",
1619
1887
  "Touch (mobile / tablet)": "hotkeys.group.touch",
1620
1888
  Keyboard: "hotkeys.group.keyboard",
1621
1889
  Drawing: "hotkeys.group.drawing"
1622
- }, j = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent) ? "⌘" : "Ctrl", M = [
1890
+ }, A = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent) ? "⌘" : "Ctrl", ye = [
1623
1891
  {
1624
1892
  title: "Search & navigation",
1625
1893
  entries: [
1626
1894
  {
1627
- keys: [j, "K"],
1895
+ keys: [A, "K"],
1628
1896
  label: "Command palette"
1629
1897
  },
1630
1898
  {
1631
- keys: [j, "P"],
1899
+ keys: [A, "P"],
1632
1900
  label: "Symbol search"
1633
1901
  },
1902
+ {
1903
+ keys: ["Alt", "G"],
1904
+ label: "Go to date"
1905
+ },
1906
+ {
1907
+ keys: ["Alt", "I"],
1908
+ label: "Invert price scale"
1909
+ },
1634
1910
  {
1635
1911
  keys: ["?"],
1636
1912
  label: "Show this sheet"
@@ -1640,6 +1916,18 @@ var A = {
1640
1916
  {
1641
1917
  title: "Chart manipulation",
1642
1918
  entries: [
1919
+ {
1920
+ keys: ["Drag"],
1921
+ label: "Pan — past the last bar into empty future space"
1922
+ },
1923
+ {
1924
+ keys: [A, "Drag"],
1925
+ label: "Select drawings in a box"
1926
+ },
1927
+ {
1928
+ keys: [A, "Click"],
1929
+ label: "Add / remove a drawing from the selection"
1930
+ },
1643
1931
  {
1644
1932
  keys: ["Shift", "Drag"],
1645
1933
  label: "Measure tool (bars × price Δ)"
@@ -1716,12 +2004,12 @@ var A = {
1716
2004
  title: "Drawing",
1717
2005
  entries: [
1718
2006
  {
1719
- keys: [j, "Z"],
2007
+ keys: [A, "Z"],
1720
2008
  label: "Undo"
1721
2009
  },
1722
2010
  {
1723
2011
  keys: [
1724
- j,
2012
+ A,
1725
2013
  "Shift",
1726
2014
  "Z"
1727
2015
  ],
@@ -1730,17 +2018,25 @@ var A = {
1730
2018
  {
1731
2019
  keys: ["Esc"],
1732
2020
  label: "Cancel active drawing"
2021
+ },
2022
+ {
2023
+ keys: [A, "C"],
2024
+ label: "Copy selected drawings"
2025
+ },
2026
+ {
2027
+ keys: [A, "V"],
2028
+ label: "Paste drawings (into any chart on the page)"
1733
2029
  }
1734
2030
  ]
1735
2031
  }
1736
- ], N = class {
2032
+ ], be = class {
1737
2033
  backdrop = null;
1738
2034
  modal = null;
1739
2035
  callbacks;
1740
2036
  t;
1741
2037
  boundKeydown;
1742
- constructor(e, t) {
1743
- this.callbacks = e, this.t = t, this.boundKeydown = (e) => {
2038
+ constructor(e, t, n = () => document.body) {
2039
+ this.host = n, this.callbacks = e, this.t = t, this.boundKeydown = (e) => {
1744
2040
  e.key === "Escape" && (e.preventDefault(), this.close());
1745
2041
  };
1746
2042
  }
@@ -1755,12 +2051,12 @@ var A = {
1755
2051
  n.className = "tcw-modal-body";
1756
2052
  let r = document.createElement("div");
1757
2053
  r.className = "tcw-hotkey-grid";
1758
- for (let e of M) {
2054
+ for (let e of ye) {
1759
2055
  let t = document.createElement("section");
1760
2056
  t.className = "tcw-hotkey-section";
1761
2057
  let n = document.createElement("div");
1762
2058
  n.className = "tcw-settings-section-title";
1763
- let i = A[e.title];
2059
+ let i = ve[e.title];
1764
2060
  n.textContent = i ? this.t(i) : e.title, t.appendChild(n);
1765
2061
  for (let n of e.entries) {
1766
2062
  let e = document.createElement("div");
@@ -1785,7 +2081,7 @@ var A = {
1785
2081
  let i = document.createElement("div");
1786
2082
  i.className = "tcw-modal-footer", i.innerHTML = "<span style=\"font-size:11px;color:var(--tcw-text-muted)\">Press ? anytime to show this sheet</span>";
1787
2083
  let a = document.createElement("button");
1788
- a.className = "tcw-done-btn", a.textContent = this.t("hotkeys.gotIt"), a.addEventListener("click", () => this.close()), i.appendChild(a), this.modal.appendChild(i), document.body.appendChild(this.backdrop), document.body.appendChild(this.modal), document.addEventListener("keydown", this.boundKeydown);
2084
+ a.className = "tcw-done-btn", a.textContent = this.t("hotkeys.gotIt"), a.addEventListener("click", () => this.close()), i.appendChild(a), this.modal.appendChild(i), this.host().append(this.backdrop, this.modal), document.addEventListener("keydown", this.boundKeydown);
1789
2085
  }
1790
2086
  close() {
1791
2087
  document.removeEventListener("keydown", this.boundKeydown), this.backdrop?.remove(), this.modal?.remove(), this.backdrop = null, this.modal = null, this.callbacks.onClose();
@@ -1796,90 +2092,127 @@ var A = {
1796
2092
  destroy() {
1797
2093
  this.close();
1798
2094
  }
1799
- }, P = [
1800
- .5,
2095
+ }, xe = {
2096
+ selectHint: "Click a bar to start the replay",
2097
+ random: "Random bar",
2098
+ realtime: "Back to realtime",
2099
+ barsPerSecond: "bars/s",
2100
+ play: "Play",
2101
+ pause: "Pause",
2102
+ stepBack: "Step back (Shift+←)",
2103
+ stepForward: "Step forward (Shift+→)"
2104
+ }, Se = [
1801
2105
  1,
1802
2106
  2,
2107
+ 3,
1803
2108
  5,
1804
2109
  10,
1805
- 20,
1806
- 50,
1807
- 100
1808
- ], F = class {
2110
+ 25,
2111
+ 50
2112
+ ], Ce = class {
1809
2113
  root = null;
1810
2114
  scrubber = null;
1811
2115
  progressLabel = null;
1812
2116
  playBtn = null;
2117
+ realtimeBtn = null;
1813
2118
  state = "stopped";
2119
+ mode = "select";
2120
+ ended = !1;
1814
2121
  total = 0;
1815
2122
  speed = 5;
1816
- callbacks;
1817
- constructor(e) {
1818
- this.callbacks = e;
2123
+ labels;
2124
+ constructor(e, t = {}) {
2125
+ this.callbacks = e, this.labels = {
2126
+ ...xe,
2127
+ ...t
2128
+ };
1819
2129
  }
1820
2130
  mount(e, t) {
1821
- this.root || (this.total = Math.max(0, t.total), this.speed = t.speed ?? 5, this.state = "paused", this.root = document.createElement("div"), this.root.className = "tcw-replay-bar", this.root.innerHTML = this.markup(), e.appendChild(this.root), this.wireEvents(), this.syncUi());
2131
+ this.root || (this.total = Math.max(0, t.total), this.speed = t.speed ?? 5, this.state = "paused", this.mode = t.mode ?? "select", this.root = document.createElement("div"), this.root.className = "tcw-replay-bar", this.root.setAttribute("role", "toolbar"), this.root.setAttribute("aria-label", "Replay"), this.root.innerHTML = this.markup(), e.appendChild(this.root), this.wireEvents(), this.syncUi());
1822
2132
  }
1823
2133
  unmount() {
1824
- this.root?.remove(), this.root = null, this.scrubber = null, this.progressLabel = null, this.playBtn = null, this.state = "stopped";
2134
+ this.root?.remove(), this.root = null, this.scrubber = null, this.progressLabel = null, this.playBtn = null, this.realtimeBtn = null, this.state = "stopped", this.ended = !1;
1825
2135
  }
1826
2136
  isMounted() {
1827
2137
  return this.root !== null;
1828
2138
  }
2139
+ getMode() {
2140
+ return this.mode;
2141
+ }
2142
+ setMode(e) {
2143
+ let t = !!this.root?.contains(document.activeElement);
2144
+ this.mode = e, this.syncUi(), t && e === "replay" && this.playBtn?.focus();
2145
+ }
1829
2146
  setState(e) {
1830
2147
  this.state = e, this.syncUi();
1831
2148
  }
2149
+ setEnded(e) {
2150
+ this.ended !== e && (this.ended = e, this.syncUi());
2151
+ }
1832
2152
  setProgress(e, t) {
1833
- this.total = t, this.scrubber && (this.scrubber.max = String(Math.max(0, t - 1)), this.scrubber.value = String(e)), this.progressLabel && (this.progressLabel.textContent = `${e + 1} / ${t}`);
2153
+ this.total = t, this.scrubber && (this.scrubber.max = String(Math.max(0, t - 1)), this.scrubber.value = String(e)), this.progressLabel && (this.progressLabel.textContent = `${Math.min(e + 1, t)} / ${t}`);
1834
2154
  }
1835
2155
  destroy() {
1836
2156
  this.unmount();
1837
2157
  }
1838
2158
  markup() {
1839
- let e = P.map((e) => `<option value="${e}"${e === this.speed ? " selected" : ""}>${e}× bars/s</option>`).join("");
2159
+ let e = this.labels, t = Se.map((t) => `<option value="${t}"${t === this.speed ? " selected" : ""}>${t} ${E(e.barsPerSecond)}</option>`).join("");
1840
2160
  return `
1841
- <button class="tcw-replay-btn" data-act="close" title="Exit replay" aria-label="Exit replay">${B()}</button>
1842
- <button class="tcw-replay-btn" data-act="stepBack" title="Step back" aria-label="Step back">${R()}</button>
1843
- <button class="tcw-replay-btn tcw-replay-play" data-act="play" title="Play / pause" aria-label="Play / pause">${I()}</button>
1844
- <button class="tcw-replay-btn" data-act="stepForward" title="Step forward" aria-label="Step forward">${z()}</button>
1845
- <input type="range" class="tcw-replay-scrubber" data-act="seek" min="0" max="${Math.max(0, this.total - 1)}" value="0" step="1" />
1846
- <span class="tcw-replay-progress" data-tcw="progress">1 / ${this.total}</span>
1847
- <select class="tcw-replay-speed" data-act="speed">${e}</select>
2161
+ <span class="tcw-replay-group" data-mode="select">
2162
+ <span class="tcw-replay-hint" role="status">${De()}${E(e.selectHint)}</span>
2163
+ <button class="tcw-replay-text-btn" data-act="random">${E(e.random)}</button>
2164
+ </span>
2165
+ <span class="tcw-replay-group" data-mode="replay">
2166
+ <button class="tcw-replay-btn" data-act="stepBack" title="${E(e.stepBack)}" aria-label="${E(e.stepBack)}">${Te()}</button>
2167
+ <button class="tcw-replay-btn tcw-replay-play" data-act="play" title="${E(e.play)}" aria-label="${E(e.play)}">${j()}</button>
2168
+ <button class="tcw-replay-btn" data-act="stepForward" title="${E(e.stepForward)}" aria-label="${E(e.stepForward)}">${Ee()}</button>
2169
+ <input type="range" class="tcw-replay-scrubber" data-act="seek" min="0" max="${Math.max(0, this.total - 1)}" value="0" step="1" aria-label="Replay position" />
2170
+ <span class="tcw-replay-progress" data-tcw="progress">1 / ${this.total}</span>
2171
+ <select class="tcw-replay-speed" data-act="speed" aria-label="Speed">${t}</select>
2172
+ </span>
2173
+ <button class="tcw-replay-text-btn tcw-replay-realtime" data-act="realtime">${E(e.realtime)}</button>
1848
2174
  `;
1849
2175
  }
1850
2176
  wireEvents() {
1851
- this.root && (this.scrubber = this.root.querySelector("input[data-act=\"seek\"]"), this.progressLabel = this.root.querySelector("[data-tcw=\"progress\"]"), this.playBtn = this.root.querySelector("button[data-act=\"play\"]"), this.root.querySelector("[data-act=\"close\"]")?.addEventListener("click", () => this.callbacks.onClose()), this.root.querySelector("[data-act=\"stepBack\"]")?.addEventListener("click", () => this.callbacks.onStepBack()), this.root.querySelector("[data-act=\"stepForward\"]")?.addEventListener("click", () => this.callbacks.onStepForward()), this.playBtn?.addEventListener("click", () => {
2177
+ let e = this.root;
2178
+ e && (this.scrubber = e.querySelector("input[data-act=\"seek\"]"), this.progressLabel = e.querySelector("[data-tcw=\"progress\"]"), this.playBtn = e.querySelector("button[data-act=\"play\"]"), this.realtimeBtn = e.querySelector("button[data-act=\"realtime\"]"), this.realtimeBtn?.addEventListener("click", () => this.callbacks.onClose()), e.querySelector("[data-act=\"random\"]")?.addEventListener("click", () => this.callbacks.onRandomStart()), e.querySelector("[data-act=\"stepBack\"]")?.addEventListener("click", () => this.callbacks.onStepBack()), e.querySelector("[data-act=\"stepForward\"]")?.addEventListener("click", () => this.callbacks.onStepForward()), this.playBtn?.addEventListener("click", () => {
1852
2179
  this.state === "playing" ? this.callbacks.onPause() : this.callbacks.onPlay();
1853
- }), this.scrubber?.addEventListener("input", () => {
1854
- let e = Number(this.scrubber.value);
1855
- this.callbacks.onSeek(e);
1856
- }), this.root.querySelector("[data-act=\"speed\"]")?.addEventListener("change", (e) => {
2180
+ }), this.scrubber?.addEventListener("input", () => this.callbacks.onSeek(Number(this.scrubber.value))), e.querySelector("[data-act=\"speed\"]")?.addEventListener("change", (e) => {
1857
2181
  let t = Number(e.target.value);
1858
2182
  this.speed = t, this.callbacks.onSpeedChange(t);
1859
2183
  }));
1860
2184
  }
1861
2185
  syncUi() {
1862
- this.playBtn && (this.playBtn.innerHTML = this.state === "playing" ? L() : I(), this.playBtn.title = this.state === "playing" ? "Pause" : "Play");
2186
+ let e = this.root;
2187
+ if (e) {
2188
+ for (let t of e.querySelectorAll(".tcw-replay-group")) t.hidden = t.dataset.mode !== this.mode;
2189
+ if (e.classList.toggle("tcw-replay-bar--ended", this.ended), this.playBtn) {
2190
+ let e = this.state === "playing";
2191
+ this.playBtn.innerHTML = e ? we() : j(), this.playBtn.title = e ? this.labels.pause : this.labels.play, this.playBtn.setAttribute("aria-label", this.playBtn.title);
2192
+ let t = this.ended && !e;
2193
+ t && document.activeElement === this.playBtn && this.realtimeBtn?.focus(), this.playBtn.disabled = t;
2194
+ }
2195
+ }
1863
2196
  }
1864
2197
  };
1865
- function I() {
1866
- return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7L8 5z\"/></svg>";
2198
+ function j() {
2199
+ return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M8 5v14l11-7L8 5z\"/></svg>";
1867
2200
  }
1868
- function L() {
1869
- return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/></svg>";
2201
+ function we() {
2202
+ return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/></svg>";
1870
2203
  }
1871
- function R() {
1872
- return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M6 6h2v12H6zM20 6L9 12l11 6V6z\"/></svg>";
2204
+ function Te() {
2205
+ return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M6 6h2v12H6zM20 6L9 12l11 6V6z\"/></svg>";
1873
2206
  }
1874
- function z() {
1875
- return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M4 6l11 6L4 18V6zM16 6h2v12h-2z\"/></svg>";
2207
+ function Ee() {
2208
+ return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M4 6l11 6L4 18V6zM16 6h2v12h-2z\"/></svg>";
1876
2209
  }
1877
- function B() {
1878
- return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6L6 18M6 6l12 12\"/></svg>";
2210
+ function De() {
2211
+ return "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M12 3v18M8 7l4-4 4 4M8 17l4 4 4-4\"/></svg>";
1879
2212
  }
1880
2213
  //#endregion
1881
2214
  //#region src/widget/WidgetWatchlist.ts
1882
- var V = class {
2215
+ var Oe = class {
1883
2216
  el;
1884
2217
  listEl;
1885
2218
  rowMap = /* @__PURE__ */ new Map();
@@ -1923,7 +2256,7 @@ var V = class {
1923
2256
  let t = document.createElement("div");
1924
2257
  t.className = "tcw-watchlist-row", t.tabIndex = 0;
1925
2258
  let n = document.createElement("div");
1926
- n.className = "tcw-watchlist-symbol", n.textContent = H(e);
2259
+ n.className = "tcw-watchlist-symbol", n.textContent = ke(e);
1927
2260
  let r = document.createElement("canvas");
1928
2261
  r.className = "tcw-watchlist-spark", r.width = 64, r.height = 22;
1929
2262
  let i = document.createElement("div");
@@ -1947,18 +2280,18 @@ var V = class {
1947
2280
  renderRow(e) {
1948
2281
  let t = this.rowMap.get(e), n = this.entries.get(e);
1949
2282
  if (!(!t || !n)) {
1950
- if (n.lastPrice !== void 0 && (t.priceEl.textContent = U(n.lastPrice, this.locale)), n.lastPrice !== void 0 && n.refPrice !== void 0 && n.refPrice !== 0) {
2283
+ if (n.lastPrice !== void 0 && (t.priceEl.textContent = Ae(n.lastPrice, this.locale)), n.lastPrice !== void 0 && n.refPrice !== void 0 && n.refPrice !== 0) {
1951
2284
  let e = n.lastPrice - n.refPrice, r = e / n.refPrice * 100, i = e >= 0 ? "+" : "-", a = Math.abs(r).toLocaleString(this.locale, {
1952
2285
  minimumFractionDigits: 2,
1953
2286
  maximumFractionDigits: 2
1954
2287
  });
1955
2288
  t.changeEl.textContent = `${i}${a}%`, t.changeEl.className = `tcw-watchlist-change ${e >= 0 ? "tcw-up" : "tcw-down"}`;
1956
2289
  } else t.changeEl.textContent = "";
1957
- n.sparkline && n.sparkline.length >= 2 && W(t.sparkCanvas, n.sparkline, n.refPrice ?? n.sparkline[0]);
2290
+ n.sparkline && n.sparkline.length >= 2 && je(t.sparkCanvas, n.sparkline, n.refPrice ?? n.sparkline[0]);
1958
2291
  }
1959
2292
  }
1960
2293
  };
1961
- function H(e) {
2294
+ function ke(e) {
1962
2295
  for (let t of [
1963
2296
  "USDT",
1964
2297
  "USD",
@@ -1968,7 +2301,7 @@ function H(e) {
1968
2301
  ]) if (e.length > t.length && e.endsWith(t)) return e.slice(0, -t.length) + "/" + t;
1969
2302
  return e;
1970
2303
  }
1971
- function U(e, t) {
2304
+ function Ae(e, t) {
1972
2305
  if (e === 0) return "0";
1973
2306
  let n = Math.abs(e);
1974
2307
  return n >= 1e3 ? e.toLocaleString(t, {
@@ -1979,14 +2312,14 @@ function U(e, t) {
1979
2312
  maximumFractionDigits: 4
1980
2313
  }) : Number(e.toPrecision(4)).toLocaleString(t, { maximumFractionDigits: 10 });
1981
2314
  }
1982
- function W(e, t, n) {
2315
+ function je(e, t, n) {
1983
2316
  let r = e.getContext("2d");
1984
2317
  if (!r) return;
1985
2318
  let i = window.devicePixelRatio || 1;
1986
2319
  e.width !== e.clientWidth * i && (e.width = (e.clientWidth || 64) * i, e.height = (e.clientHeight || 22) * i);
1987
2320
  let a = e.width, o = e.height, s = Infinity, c = -Infinity;
1988
2321
  for (let e of t) e < s && (s = e), e > c && (c = e);
1989
- let l = Math.max(c - s, 1e-9), u = t[t.length - 1] >= n ? "#26a17b" : "#f23645";
2322
+ let l = Math.max(c - s, 1e-9), u = t[t.length - 1] >= n ? "#1fa874" : "#e8505b";
1990
2323
  r.clearRect(0, 0, a, o), r.lineWidth = 1.4 * i, r.strokeStyle = u, r.beginPath();
1991
2324
  let d = a / (t.length - 1);
1992
2325
  for (let e = 0; e < t.length; e++) {
@@ -1997,7 +2330,7 @@ function W(e, t, n) {
1997
2330
  }
1998
2331
  //#endregion
1999
2332
  //#region src/widget/WidgetAlertsPanel.ts
2000
- var G = [
2333
+ var M = [
2001
2334
  {
2002
2335
  value: "crossing",
2003
2336
  label: "Crossing"
@@ -2018,15 +2351,15 @@ var G = [
2018
2351
  value: "lessThan",
2019
2352
  label: "Less than"
2020
2353
  }
2021
- ], K = new Map(G.map((e) => [e.value, e.label]));
2022
- function ce(e) {
2354
+ ], Me = new Map(M.map((e) => [e.value, e.label]));
2355
+ function Ne(e) {
2023
2356
  return Math.round(e * 1e6) / 1e6;
2024
2357
  }
2025
- function le(e) {
2358
+ function Pe(e) {
2026
2359
  let t = Math.abs(e);
2027
2360
  return t >= 1e3 || t >= 1 ? e.toFixed(2) : e.toPrecision(4);
2028
2361
  }
2029
- var ue = class {
2362
+ var Fe = class {
2030
2363
  el;
2031
2364
  listEl;
2032
2365
  priceInput;
@@ -2048,16 +2381,16 @@ var ue = class {
2048
2381
  let r = document.createElement("span");
2049
2382
  r.textContent = "Price Alerts";
2050
2383
  let i = document.createElement("button");
2051
- 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);
2384
+ i.className = "tcw-alerts-close", i.type = "button", i.setAttribute("aria-label", "Close alerts"), i.innerHTML = C("x", 14), i.addEventListener("click", () => this.close()), n.appendChild(r), n.appendChild(i), this.el.appendChild(n);
2052
2385
  let a = document.createElement("form");
2053
2386
  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";
2054
- for (let e of G) {
2387
+ for (let e of M) {
2055
2388
  let t = document.createElement("option");
2056
2389
  t.value = e.value, t.textContent = e.label, this.conditionSelect.appendChild(t);
2057
2390
  }
2058
2391
  this.messageInput = document.createElement("input"), this.messageInput.type = "text", this.messageInput.placeholder = "Note (optional)", this.messageInput.className = "tcw-alerts-message";
2059
2392
  let o = document.createElement("button");
2060
- 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) => {
2393
+ o.type = "submit", o.className = "tcw-alerts-add", o.innerHTML = `${C("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) => {
2061
2394
  e.preventDefault(), this.submitForm();
2062
2395
  }), 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);
2063
2396
  }
@@ -2087,7 +2420,7 @@ var ue = class {
2087
2420
  }
2088
2421
  prefillPrice() {
2089
2422
  let e = this.callbacks.getChannelValue(this.sourceSelect.value || "price");
2090
- this.priceInput.value = e === null ? "" : String(ce(e));
2423
+ this.priceInput.value = e === null ? "" : String(Ne(e));
2091
2424
  }
2092
2425
  close() {
2093
2426
  this.open = !1, this.el.hidden = !0;
@@ -2116,7 +2449,7 @@ var ue = class {
2116
2449
  n.className = "tcw-alerts-info";
2117
2450
  let r = document.createElement("div");
2118
2451
  r.className = "tcw-alerts-row-main";
2119
- let i = K.get(e.condition) ?? e.condition, a = e.channel && e.channel !== "price", o = a ? le(e.price) : this.callbacks.formatPrice(e.price);
2452
+ let i = Me.get(e.condition) ?? e.condition, a = e.channel && e.channel !== "price", o = a ? Pe(e.price) : this.callbacks.formatPrice(e.price);
2120
2453
  if (r.textContent = `${a && e.label ? `${e.label} ` : ""}${i} ${o}`, n.appendChild(r), e.message) {
2121
2454
  let t = document.createElement("div");
2122
2455
  t.className = "tcw-alerts-row-note", t.textContent = e.message, n.appendChild(t);
@@ -2126,10 +2459,10 @@ var ue = class {
2126
2459
  e.className = "tcw-alerts-badge", e.textContent = "triggered", r.appendChild(e);
2127
2460
  }
2128
2461
  let s = document.createElement("button");
2129
- s.type = "button", s.className = "tcw-alerts-del", s.setAttribute("aria-label", "Delete alert"), s.innerHTML = y("trash", 14), s.addEventListener("click", () => this.callbacks.onRemove(e.id)), t.appendChild(n), t.appendChild(s), this.listEl.appendChild(t);
2462
+ s.type = "button", s.className = "tcw-alerts-del", s.setAttribute("aria-label", "Delete alert"), s.innerHTML = C("trash", 14), s.addEventListener("click", () => this.callbacks.onRemove(e.id)), t.appendChild(n), t.appendChild(s), this.listEl.appendChild(t);
2130
2463
  }
2131
2464
  }
2132
- }, de = class {
2465
+ }, Ie = class {
2133
2466
  el;
2134
2467
  indicatorsEl;
2135
2468
  drawingsEl;
@@ -2143,7 +2476,7 @@ var ue = class {
2143
2476
  let r = document.createElement("span");
2144
2477
  r.textContent = "Objects";
2145
2478
  let i = document.createElement("button");
2146
- 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);
2479
+ i.type = "button", i.className = "tcw-tree-close", i.setAttribute("aria-label", "Close objects"), i.innerHTML = C("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);
2147
2480
  }
2148
2481
  isOpen() {
2149
2482
  return this.open;
@@ -2171,7 +2504,7 @@ var ue = class {
2171
2504
  let i = document.createElement("span");
2172
2505
  if (i.textContent = e, r.appendChild(i), t) {
2173
2506
  let n = document.createElement("button");
2174
- 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);
2507
+ n.type = "button", n.className = "tcw-tree-add", n.setAttribute("aria-label", `Add ${e.toLowerCase()}`), n.title = `Add ${e.toLowerCase()}`, n.innerHTML = C("plus", 13), n.addEventListener("click", t), r.appendChild(n);
2175
2508
  }
2176
2509
  let a = document.createElement("div");
2177
2510
  return a.className = "tcw-tree-list", n.appendChild(r), n.appendChild(a), this.el.appendChild(n), a;
@@ -2224,9 +2557,9 @@ var ue = class {
2224
2557
  }
2225
2558
  iconButton(e, t, n, r) {
2226
2559
  let i = document.createElement("button");
2227
- return i.type = "button", i.className = `tcw-tree-btn ${n}`.trim(), i.setAttribute("aria-label", t), i.title = t, i.innerHTML = y(e, 14), i.addEventListener("click", r), i;
2560
+ return i.type = "button", i.className = `tcw-tree-btn ${n}`.trim(), i.setAttribute("aria-label", t), i.title = t, i.innerHTML = C(e, 14), i.addEventListener("click", r), i;
2228
2561
  }
2229
- }, fe = {
2562
+ }, Le = {
2230
2563
  trendLine: "Trend Line",
2231
2564
  ray: "Ray",
2232
2565
  extendedLine: "Extended Line",
@@ -2269,16 +2602,16 @@ var ue = class {
2269
2602
  volumeProfileRange: "Volume Profile",
2270
2603
  riskReward: "Long/Short Position"
2271
2604
  };
2272
- function pe(e) {
2273
- return fe[e] ?? e;
2605
+ function Re(e) {
2606
+ return Le[e] ?? e;
2274
2607
  }
2275
2608
  //#endregion
2276
2609
  //#region src/widget/WidgetIndicatorSettings.ts
2277
- var me = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
2278
- function he(e) {
2610
+ var ze = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
2611
+ function Be(e) {
2279
2612
  return e.replace(/_/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (e) => e.toUpperCase());
2280
2613
  }
2281
- var ge = class {
2614
+ var Ve = class {
2282
2615
  backdrop;
2283
2616
  modal;
2284
2617
  bodyEl;
@@ -2293,7 +2626,7 @@ var ge = class {
2293
2626
  let n = document.createElement("div");
2294
2627
  n.className = "tcw-modal-header", this.titleEl = document.createElement("h3"), this.titleEl.textContent = "Indicator";
2295
2628
  let r = document.createElement("button");
2296
- 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";
2629
+ r.className = "tcw-modal-close", r.setAttribute("aria-label", "Close"), r.innerHTML = C("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";
2297
2630
  let i = document.createElement("div");
2298
2631
  i.className = "tcw-modal-footer";
2299
2632
  let a = document.createElement("button");
@@ -2343,9 +2676,9 @@ var ge = class {
2343
2676
  let t = document.createElement("div");
2344
2677
  t.className = "tcw-settings-row";
2345
2678
  let n = document.createElement("span");
2346
- n.className = "tcw-settings-label", n.textContent = he(e), t.appendChild(n);
2679
+ n.className = "tcw-settings-label", n.textContent = Be(e), t.appendChild(n);
2347
2680
  let r = this.currentValue(e), i = typeof (this.target?.defaults[e] ?? r);
2348
- return i === "boolean" ? t.appendChild(this.toggleControl(e, !!r)) : i === "number" ? t.appendChild(this.numberControl(e, Number(r))) : typeof r == "string" && me.test(r) ? t.appendChild(this.colorControl(e, r)) : t.appendChild(this.textControl(e, String(r ?? ""))), t;
2681
+ return i === "boolean" ? t.appendChild(this.toggleControl(e, !!r)) : i === "number" ? t.appendChild(this.numberControl(e, Number(r))) : typeof r == "string" && ze.test(r) ? t.appendChild(this.colorControl(e, r)) : t.appendChild(this.textControl(e, String(r ?? ""))), t;
2349
2682
  }
2350
2683
  toggleControl(e, t) {
2351
2684
  let n = document.createElement("button");
@@ -2363,27 +2696,27 @@ var ge = class {
2363
2696
  }
2364
2697
  colorControl(e, t) {
2365
2698
  let n = document.createElement("input");
2366
- return n.type = "color", n.className = "tcw-indi-color", n.value = t.length === 4 ? _e(t) : t, n.addEventListener("input", () => this.setValue(e, n.value)), n;
2699
+ 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;
2367
2700
  }
2368
2701
  textControl(e, t) {
2369
2702
  let n = document.createElement("input");
2370
2703
  return n.type = "text", n.className = "tcw-indi-input", n.value = t, n.addEventListener("change", () => this.setValue(e, n.value)), n;
2371
2704
  }
2372
2705
  };
2373
- function _e(e) {
2706
+ function He(e) {
2374
2707
  let t = e[1], n = e[2], r = e[3];
2375
2708
  return `#${t}${t}${n}${n}${r}${r}`;
2376
2709
  }
2377
2710
  //#endregion
2378
2711
  //#region src/widget/DrawingTemplateStore.ts
2379
- function ve() {
2712
+ function Ue() {
2380
2713
  try {
2381
2714
  return typeof localStorage < "u" ? localStorage : null;
2382
2715
  } catch {
2383
2716
  return null;
2384
2717
  }
2385
2718
  }
2386
- var ye = [
2719
+ var We = [
2387
2720
  "color",
2388
2721
  "lineWidth",
2389
2722
  "lineStyle",
@@ -2391,15 +2724,15 @@ var ye = [
2391
2724
  "fillOpacity",
2392
2725
  "fontSize"
2393
2726
  ];
2394
- function q(e) {
2727
+ function N(e) {
2395
2728
  if (!e || typeof e != "object") return {};
2396
2729
  let t = {}, n = e;
2397
- for (let e of ye) n[e] !== void 0 && (t[e] = n[e]);
2730
+ for (let e of We) n[e] !== void 0 && (t[e] = n[e]);
2398
2731
  return t;
2399
2732
  }
2400
- var be = class {
2733
+ var Ge = class {
2401
2734
  templates = [];
2402
- constructor(e = "tcw:draw-templates", t = ve()) {
2735
+ constructor(e = "tcw:draw-templates", t = Ue()) {
2403
2736
  this.storageKey = e, this.storage = t, this.load();
2404
2737
  }
2405
2738
  list() {
@@ -2418,7 +2751,7 @@ var be = class {
2418
2751
  save(e, t) {
2419
2752
  let n = e.trim();
2420
2753
  if (!n) return;
2421
- let r = q(t);
2754
+ let r = N(t);
2422
2755
  this.templates = this.templates.filter((e) => e.name !== n), this.templates.push({
2423
2756
  name: n,
2424
2757
  style: r
@@ -2439,7 +2772,7 @@ var be = class {
2439
2772
  if (!Array.isArray(t)) return;
2440
2773
  this.templates = t.filter((e) => e && typeof e.name == "string").map((e) => ({
2441
2774
  name: e.name,
2442
- style: q(e.style)
2775
+ style: N(e.style)
2443
2776
  }));
2444
2777
  } catch {}
2445
2778
  }
@@ -2448,25 +2781,25 @@ var be = class {
2448
2781
  this.storage.setItem(this.storageKey, JSON.stringify(this.templates));
2449
2782
  } catch {}
2450
2783
  }
2451
- }, xe = [
2452
- "#2962ff",
2453
- "#089981",
2454
- "#f23645",
2455
- "#ff9800",
2456
- "#ab47bc",
2457
- "#26c6da",
2784
+ }, Ke = [
2785
+ "#4c8dff",
2786
+ "#1fa874",
2787
+ "#e8505b",
2788
+ "#f2a93b",
2789
+ "#a57cff",
2790
+ "#1398a8",
2458
2791
  "#ffffff",
2459
- "#787b86"
2460
- ], Se = [
2792
+ "#7d8696"
2793
+ ], qe = [
2461
2794
  1,
2462
2795
  2,
2463
2796
  3,
2464
2797
  4
2465
- ], Ce = [
2798
+ ], Je = [
2466
2799
  "solid",
2467
2800
  "dashed",
2468
2801
  "dotted"
2469
- ], we = class {
2802
+ ], Ye = class {
2470
2803
  el;
2471
2804
  templatesEl;
2472
2805
  nameInput;
@@ -2480,13 +2813,13 @@ var be = class {
2480
2813
  let i = document.createElement("span");
2481
2814
  i.textContent = "Drawing Style";
2482
2815
  let a = document.createElement("button");
2483
- 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());
2816
+ a.type = "button", a.className = "tcw-style-close", a.setAttribute("aria-label", "Close"), a.innerHTML = C("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());
2484
2817
  let o = document.createElement("div");
2485
2818
  o.className = "tcw-style-subhead", o.textContent = "Templates", this.el.appendChild(o);
2486
2819
  let s = document.createElement("div");
2487
2820
  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";
2488
2821
  let c = document.createElement("button");
2489
- 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();
2822
+ c.type = "button", c.className = "tcw-style-savebtn", c.innerHTML = `${C("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();
2490
2823
  }
2491
2824
  isOpen() {
2492
2825
  return this.open;
@@ -2506,7 +2839,7 @@ var be = class {
2506
2839
  colorRow() {
2507
2840
  let e = document.createElement("div");
2508
2841
  e.className = "tcw-style-row tcw-style-colors";
2509
- for (let t of xe) {
2842
+ for (let t of Ke) {
2510
2843
  let n = document.createElement("button");
2511
2844
  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);
2512
2845
  }
@@ -2516,7 +2849,7 @@ var be = class {
2516
2849
  widthRow() {
2517
2850
  let e = document.createElement("div");
2518
2851
  e.className = "tcw-style-row tcw-style-widths";
2519
- for (let t of Se) {
2852
+ for (let t of qe) {
2520
2853
  let n = document.createElement("button");
2521
2854
  n.type = "button", n.className = "tcw-style-width", n.dataset.width = String(t);
2522
2855
  let r = document.createElement("span");
@@ -2527,7 +2860,7 @@ var be = class {
2527
2860
  lineStyleRow() {
2528
2861
  let e = document.createElement("div");
2529
2862
  e.className = "tcw-style-row tcw-style-dashes";
2530
- for (let t of Ce) {
2863
+ for (let t of Je) {
2531
2864
  let n = document.createElement("button");
2532
2865
  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);
2533
2866
  }
@@ -2570,7 +2903,7 @@ var be = class {
2570
2903
  this.callbacks.onStyleChange({ ...t.style }), this.syncActiveControls();
2571
2904
  });
2572
2905
  let a = document.createElement("button");
2573
- a.type = "button", a.className = "tcw-style-tdel", a.setAttribute("aria-label", "Delete template"), a.innerHTML = y("trash", 13), a.addEventListener("click", () => {
2906
+ a.type = "button", a.className = "tcw-style-tdel", a.setAttribute("aria-label", "Delete template"), a.innerHTML = C("trash", 13), a.addEventListener("click", () => {
2574
2907
  this.store.remove(t.name), this.renderTemplates();
2575
2908
  }), e.appendChild(n), e.appendChild(a), this.templatesEl.appendChild(e);
2576
2909
  }
@@ -2578,16 +2911,16 @@ var be = class {
2578
2911
  };
2579
2912
  //#endregion
2580
2913
  //#region src/widget/DrawingFavoritesStore.ts
2581
- function Te() {
2914
+ function Xe() {
2582
2915
  try {
2583
2916
  return typeof localStorage < "u" ? localStorage : null;
2584
2917
  } catch {
2585
2918
  return null;
2586
2919
  }
2587
2920
  }
2588
- var Ee = class {
2921
+ var P = class {
2589
2922
  favorites = [];
2590
- constructor(e = "tcw:draw-favorites", t = Te()) {
2923
+ constructor(e = "tcw:draw-favorites", t = Xe()) {
2591
2924
  this.storageKey = e, this.storage = t, this.load();
2592
2925
  }
2593
2926
  list() {
@@ -2621,7 +2954,397 @@ var Ee = class {
2621
2954
  this.storage.setItem(this.storageKey, JSON.stringify(this.favorites));
2622
2955
  } catch {}
2623
2956
  }
2624
- }, De = class {
2957
+ }, Ze = [
2958
+ "1m",
2959
+ "3m",
2960
+ "5m",
2961
+ "15m",
2962
+ "30m",
2963
+ "1h",
2964
+ "2h",
2965
+ "4h",
2966
+ "1d",
2967
+ "1w",
2968
+ "1M"
2969
+ ], Qe = [
2970
+ "1m",
2971
+ "5m",
2972
+ "15m",
2973
+ "1h",
2974
+ "4h",
2975
+ "1d"
2976
+ ], $e = 6;
2977
+ function F(e) {
2978
+ let t = e.slice(-1);
2979
+ return t === "h" || t === "d" || t === "w" ? e.slice(0, -1) + t.toUpperCase() : e;
2980
+ }
2981
+ var et = (e) => Number.isFinite(o(e));
2982
+ function tt(e, t) {
2983
+ let n = t?.length ? t : null, r = e?.length ? e : n ?? Ze;
2984
+ return [...new Set(r)].filter((e) => et(e) && (!n || n.includes(e))).sort((e, t) => o(e) - o(t));
2985
+ }
2986
+ function nt(e, t, n = !1) {
2987
+ if (t?.length) return e.filter((e) => t.includes(e));
2988
+ if (n) return [...e];
2989
+ let r = e.filter((e) => Qe.includes(e));
2990
+ return r.length > 0 ? r : e.slice(0, $e);
2991
+ }
2992
+ //#endregion
2993
+ //#region src/widget/WidgetGoToDate.ts
2994
+ var I = 6e4, rt = /^(\d{4})-(\d{2})-(\d{2})$/, it = /^(\d{2}):(\d{2})$/;
2995
+ function at(e, t, n) {
2996
+ let r = rt.exec(e), i = t ? it.exec(t) : [
2997
+ "",
2998
+ "00",
2999
+ "00"
3000
+ ];
3001
+ if (!r || !i) return null;
3002
+ let [a, o, s, c, l] = [
3003
+ +r[1],
3004
+ +r[2],
3005
+ +r[3],
3006
+ +i[1],
3007
+ +i[2]
3008
+ ];
3009
+ if (o < 1 || o > 12 || s < 1 || s > 31 || c > 23 || l > 59) return null;
3010
+ if (n === null) {
3011
+ let e = new Date(a, o - 1, s, c, l);
3012
+ return e.getDate() === s ? e.getTime() : null;
3013
+ }
3014
+ let u = Date.UTC(a, o - 1, s, c, l);
3015
+ return new Date(u).getUTCDate() === s ? u - n * I : null;
3016
+ }
3017
+ function ot(e, t) {
3018
+ let n = (e) => String(e).padStart(2, "0");
3019
+ if (t === null) {
3020
+ let t = new Date(e);
3021
+ return {
3022
+ date: `${t.getFullYear()}-${n(t.getMonth() + 1)}-${n(t.getDate())}`,
3023
+ time: `${n(t.getHours())}:${n(t.getMinutes())}`
3024
+ };
3025
+ }
3026
+ let r = new Date(e + t * I);
3027
+ return {
3028
+ date: `${r.getUTCFullYear()}-${n(r.getUTCMonth() + 1)}-${n(r.getUTCDate())}`,
3029
+ time: `${n(r.getUTCHours())}:${n(r.getUTCMinutes())}`
3030
+ };
3031
+ }
3032
+ var st = class {
3033
+ form = null;
3034
+ returnFocus = null;
3035
+ opener = null;
3036
+ onOutside = (e) => {
3037
+ let t = e.target;
3038
+ this.form && !this.form.contains(t) && !this.opener?.contains(t) && this.close();
3039
+ };
3040
+ constructor(e, t, n) {
3041
+ this.host = e, this.labels = t, this.onSubmit = n;
3042
+ }
3043
+ isOpen() {
3044
+ return this.form !== null;
3045
+ }
3046
+ open(e, t = null) {
3047
+ this.close(), this.opener = t, this.returnFocus = document.activeElement;
3048
+ let n = document.createElement("form");
3049
+ n.className = "tcw-goto", n.setAttribute("role", "dialog"), n.setAttribute("aria-label", this.labels.title);
3050
+ let r = document.createElement("div");
3051
+ r.className = "tcw-goto-title", r.textContent = this.labels.title;
3052
+ let i = this.field(n, this.labels.date, "date", e.date);
3053
+ i.required = !0;
3054
+ let a = this.field(n, this.labels.time, "time", e.time), o = document.createElement("div");
3055
+ o.className = "tcw-goto-actions";
3056
+ let s = document.createElement("button");
3057
+ s.type = "button", s.className = "tcw-btn", s.textContent = this.labels.cancel, s.addEventListener("click", () => this.close());
3058
+ let c = document.createElement("button");
3059
+ c.type = "submit", c.className = "tcw-btn tcw-goto-submit", c.textContent = this.labels.submit, o.append(s, c), n.prepend(r), n.append(o), n.addEventListener("submit", (e) => {
3060
+ if (e.preventDefault(), !i.value) return;
3061
+ let t = {
3062
+ date: i.value,
3063
+ time: a.value
3064
+ };
3065
+ this.close(), this.onSubmit(t);
3066
+ }), n.addEventListener("keydown", (e) => {
3067
+ e.stopPropagation(), e.key === "Escape" && this.close();
3068
+ }), this.host.appendChild(n), this.form = n, document.addEventListener("mousedown", this.onOutside), i.focus();
3069
+ }
3070
+ close() {
3071
+ if (!this.form) return;
3072
+ document.removeEventListener("mousedown", this.onOutside), this.form.remove(), this.form = null;
3073
+ let e = this.returnFocus;
3074
+ this.returnFocus = null, e?.isConnected && e.focus();
3075
+ }
3076
+ destroy() {
3077
+ this.close();
3078
+ }
3079
+ field(e, t, n, r) {
3080
+ let i = document.createElement("label");
3081
+ i.className = "tcw-goto-field";
3082
+ let a = document.createElement("span");
3083
+ a.textContent = t;
3084
+ let o = document.createElement("input");
3085
+ return o.type = n, o.value = r, o.className = "tcw-goto-input", i.append(a, o), e.appendChild(i), o;
3086
+ }
3087
+ }, L = 8, R = 4, z = 3, ct = "[title]:not([title=\"\"]), [data-tip]:not([data-tip=\"\"])", lt = class {
3088
+ el;
3089
+ target = null;
3090
+ source = null;
3091
+ pressed = null;
3092
+ showTimer = null;
3093
+ watchFrame = 0;
3094
+ warmUntil = 0;
3095
+ observer;
3096
+ constructor(e) {
3097
+ this.root = e, this.el = document.createElement("div"), this.el.className = "tcw-tooltip", this.el.setAttribute("aria-hidden", "true"), e.appendChild(this.el), e.addEventListener("pointerover", this.onOver), e.addEventListener("pointerout", this.onOut), e.addEventListener("pointerdown", this.onPress, !0), e.addEventListener("keydown", this.onPress, !0), e.addEventListener("focusin", this.onFocus), e.addEventListener("focusout", this.onBlur), e.addEventListener("wheel", this.hide, { passive: !0 }), this.observer = new MutationObserver(() => {
3098
+ this.pressed?.hasAttribute("title") && B(this.pressed);
3099
+ let e = this.target;
3100
+ !e || this.source !== "pointer" || !e.hasAttribute("title") || (B(e), this.isVisible() && this.show(e));
3101
+ }), this.observer.observe(e, {
3102
+ subtree: !0,
3103
+ attributes: !0,
3104
+ attributeFilter: ["title"]
3105
+ });
3106
+ }
3107
+ destroy() {
3108
+ this.hide(), this.pressed && V(this.pressed), this.observer.disconnect(), this.root.removeEventListener("pointerover", this.onOver), this.root.removeEventListener("pointerout", this.onOut), this.root.removeEventListener("pointerdown", this.onPress, !0), this.root.removeEventListener("keydown", this.onPress, !0), this.root.removeEventListener("focusin", this.onFocus), this.root.removeEventListener("focusout", this.onBlur), this.root.removeEventListener("wheel", this.hide), this.el.remove();
3109
+ }
3110
+ onOver = (e) => {
3111
+ if (e.pointerType === "touch") return;
3112
+ let t = this.tipTarget(e.target);
3113
+ !t || t === this.pressed || t === this.target && this.source === "pointer" || (B(t), this.schedule(t, "pointer", Date.now() < this.warmUntil || this.isVisible()));
3114
+ };
3115
+ onOut = (e) => {
3116
+ let t = e.relatedTarget, n = (e) => !!e && !!t && e.contains(t);
3117
+ this.pressed && !n(this.pressed) && (V(this.pressed), this.pressed = null), this.source === "pointer" && !n(this.target) && this.hide();
3118
+ };
3119
+ onPress = () => {
3120
+ let e = this.target, t = this.source === "pointer";
3121
+ this.warmUntil = 0, this.clearTimer(), cancelAnimationFrame(this.watchFrame), this.el.classList.remove("tcw-tooltip--visible"), this.target = null, this.source = null, this.pressed && this.pressed !== e && V(this.pressed), this.pressed = t ? e : null;
3122
+ };
3123
+ onFocus = (e) => {
3124
+ let t = this.tipTarget(e.target);
3125
+ !t || !dt(t) || t === this.pressed || this.schedule(t, "focus", !0);
3126
+ };
3127
+ onBlur = (e) => {
3128
+ if (this.source !== "focus") return;
3129
+ let t = e.relatedTarget;
3130
+ this.target && t && this.target.contains(t) || this.hide();
3131
+ };
3132
+ hide = () => {
3133
+ this.clearTimer(), cancelAnimationFrame(this.watchFrame), this.isVisible() && (this.warmUntil = Date.now() + 500), this.el.classList.remove("tcw-tooltip--visible"), this.target && this.source === "pointer" && V(this.target), this.target = null, this.source = null;
3134
+ };
3135
+ tipTarget(e) {
3136
+ if (!(e instanceof Element)) return null;
3137
+ let t = e.closest(ct);
3138
+ return t && t !== this.el && this.root.contains(t) ? t : null;
3139
+ }
3140
+ schedule(e, t, n) {
3141
+ let r = this.target;
3142
+ if (this.clearTimer(), cancelAnimationFrame(this.watchFrame), r && r !== e && this.source === "pointer" && V(r), this.target = e, this.source = t, n) {
3143
+ this.show(e);
3144
+ return;
3145
+ }
3146
+ this.el.classList.remove("tcw-tooltip--visible"), this.showTimer = setTimeout(() => {
3147
+ this.showTimer = null, this.target === e && this.show(e);
3148
+ }, 300);
3149
+ }
3150
+ show(e) {
3151
+ if (!H(e)) {
3152
+ this.hide();
3153
+ return;
3154
+ }
3155
+ this.el.textContent = ut(e), this.place(e), this.el.classList.add("tcw-tooltip--visible"), this.watch(e);
3156
+ }
3157
+ watch(e) {
3158
+ cancelAnimationFrame(this.watchFrame), this.watchFrame = requestAnimationFrame(() => {
3159
+ this.target === e && (H(e) ? this.watch(e) : this.hide());
3160
+ });
3161
+ }
3162
+ place(e) {
3163
+ let t = this.root.getBoundingClientRect(), n = e.getBoundingClientRect(), r = this.el.offsetWidth, i = this.el.offsetHeight, a = n.left - t.left, o = n.top - t.top, s = ft(e);
3164
+ s === "bottom" && o + n.height + L + i > t.height ? s = "top" : s === "top" && o - L - i < 0 ? s = "bottom" : s === "right" && a + n.width + L + r > t.width && (s = "left");
3165
+ let c, l;
3166
+ s === "top" || s === "bottom" ? (c = a + n.width / 2 - r / 2, l = s === "bottom" ? o + n.height + L : o - L - i) : (c = s === "right" ? a + n.width + L : a - L - r, l = o + n.height / 2 - i / 2), c = Math.max(R, Math.min(t.width - r - R, c)), l = Math.max(R, Math.min(t.height - i - R, l)), this.el.style.left = `${Math.round(c)}px`, this.el.style.top = `${Math.round(l)}px`;
3167
+ let u = {
3168
+ top: [0, z],
3169
+ bottom: [0, -z],
3170
+ left: [z, 0],
3171
+ right: [-z, 0]
3172
+ }[s];
3173
+ this.el.style.setProperty("--tcw-tip-dx", `${u[0]}px`), this.el.style.setProperty("--tcw-tip-dy", `${u[1]}px`), this.el.dataset.side = s;
3174
+ }
3175
+ isVisible() {
3176
+ return this.el.classList.contains("tcw-tooltip--visible");
3177
+ }
3178
+ clearTimer() {
3179
+ this.showTimer !== null && (clearTimeout(this.showTimer), this.showTimer = null);
3180
+ }
3181
+ };
3182
+ function B(e) {
3183
+ let t = e.getAttribute("title");
3184
+ t !== null && (e.dataset.tip = t, e.removeAttribute("title"));
3185
+ }
3186
+ function V(e) {
3187
+ e.dataset.tip !== void 0 && !e.hasAttribute("title") && (e.setAttribute("title", e.dataset.tip), delete e.dataset.tip);
3188
+ }
3189
+ function ut(e) {
3190
+ return e.dataset.tip ?? e.getAttribute("title") ?? "";
3191
+ }
3192
+ function H(e) {
3193
+ return e.isConnected && e.getClientRects().length > 0 && !e.disabled;
3194
+ }
3195
+ function dt(e) {
3196
+ try {
3197
+ return e.matches(":focus-visible");
3198
+ } catch {
3199
+ return !1;
3200
+ }
3201
+ }
3202
+ function ft(e) {
3203
+ return e.dataset.tipSide || (e.closest(".tcw-sidebar") ? "right" : e.closest(".tcw-statusbar, .tcw-replay-bar") ? "top" : "bottom");
3204
+ }
3205
+ //#endregion
3206
+ //#region src/widget/WidgetIndicatorLegend.ts
3207
+ var pt = 2, mt = class {
3208
+ stack;
3209
+ toggle;
3210
+ rows = /* @__PURE__ */ new Map();
3211
+ collapsed = !1;
3212
+ toggleKey = "";
3213
+ stackKey = "";
3214
+ constructor(e, t, n) {
3215
+ this.host = e, this.callbacks = t, this.labels = n, this.stack = document.createElement("div"), this.stack.className = "tcw-ind-legend", this.toggle = document.createElement("button"), this.toggle.type = "button", this.toggle.className = "tcw-ind-legend-toggle", this.toggle.addEventListener("click", () => {
3216
+ this.setCollapsed(!this.collapsed), this.renderToggle(this.overlayCount());
3217
+ }), this.stack.appendChild(this.toggle), e.appendChild(this.stack);
3218
+ }
3219
+ update(e, t) {
3220
+ let n = `${Math.round(t.left)},${Math.round(t.top)}`;
3221
+ n !== this.stackKey && (this.stackKey = n, this.stack.style.left = `${Math.round(t.left)}px`, this.stack.style.top = `${Math.round(t.top)}px`);
3222
+ let r = /* @__PURE__ */ new Set(), i = !1;
3223
+ for (let t of e) {
3224
+ r.add(t.instanceId);
3225
+ let e = this.rows.get(t.instanceId) ?? this.createRow(t.instanceId);
3226
+ this.fill(e, t), t.pane ? e.el.parentElement !== this.host && this.host.appendChild(e.el) : e.el.parentElement !== this.stack && (this.stack.insertBefore(e.el, this.toggle), i = !0), this.place(e, t.pane);
3227
+ }
3228
+ for (let [e, t] of this.rows) r.has(e) || (t.el.remove(), this.rows.delete(e));
3229
+ i && this.collapsed && this.setCollapsed(!1), this.renderToggle(e.filter((e) => !e.pane).length);
3230
+ }
3231
+ destroy() {
3232
+ for (let e of this.rows.values()) e.el.remove();
3233
+ this.rows.clear(), this.stack.remove();
3234
+ }
3235
+ createRow(e) {
3236
+ let t = document.createElement("div");
3237
+ t.className = "tcw-ind-legend-row", t.dataset.instance = e;
3238
+ let n = document.createElement("button");
3239
+ n.type = "button", n.className = "tcw-ind-legend-name", n.addEventListener("click", () => this.callbacks.onSettings(e));
3240
+ let r = document.createElement("span");
3241
+ r.className = "tcw-ind-legend-values";
3242
+ let i = document.createElement("span");
3243
+ i.className = "tcw-ind-legend-actions";
3244
+ let a = (e, t, n) => {
3245
+ let r = document.createElement("button");
3246
+ return r.type = "button", r.className = "tcw-ind-legend-act", r.dataset.act = e, r.innerHTML = C(t, 13), r.addEventListener("click", n), i.appendChild(r), r;
3247
+ }, o = a("visible", "eye", () => {
3248
+ this.callbacks.onToggleVisible(e, !l.visible);
3249
+ }), s = a("settings", "settings", () => this.callbacks.onSettings(e)), c = a("remove", "x", () => this.callbacks.onRemove(e));
3250
+ t.append(n, r, i);
3251
+ let l = {
3252
+ el: t,
3253
+ name: n,
3254
+ values: r,
3255
+ eye: o,
3256
+ settings: s,
3257
+ remove: c,
3258
+ visible: !0,
3259
+ valuesKey: "",
3260
+ state: "",
3261
+ placeKey: ""
3262
+ };
3263
+ return this.rows.set(e, l), l;
3264
+ }
3265
+ fill(e, t) {
3266
+ let n = `${t.label}|${t.visible}`;
3267
+ n !== e.state && (e.state = n, e.visible = t.visible, e.name.textContent = t.label, e.name.title = this.labels.settings, e.el.classList.toggle("tcw-ind-legend-row--hidden", !t.visible), e.eye.innerHTML = C(t.visible ? "eye" : "eyeOff", 13), U(e.eye, t.visible ? this.labels.hide : this.labels.show, t.label), U(e.settings, this.labels.settings, t.label), U(e.remove, this.labels.remove, t.label));
3268
+ let r = t.values.map((e) => `${e.text}${e.color ?? ""}`).join("");
3269
+ r !== e.valuesKey && (e.valuesKey = r, e.values.replaceChildren(...t.values.map((e) => {
3270
+ let t = document.createElement("span");
3271
+ return t.textContent = e.text, e.color && (t.style.color = e.color), t;
3272
+ })));
3273
+ }
3274
+ place(e, t) {
3275
+ let n = t ? `${Math.round(t.x)},${Math.round(t.y)},${Math.round(t.width)}` : "";
3276
+ n !== e.placeKey && (e.placeKey = n, e.el.classList.toggle("tcw-ind-legend-row--pane", t !== null), e.el.style.left = t ? `${Math.round(t.x)}px` : "", e.el.style.top = t ? `${Math.round(t.y)}px` : "", e.el.style.maxWidth = t ? `${Math.max(0, Math.round(t.width))}px` : "");
3277
+ }
3278
+ setCollapsed(e) {
3279
+ this.collapsed = e, this.stack.classList.toggle("tcw-ind-legend--collapsed", e);
3280
+ }
3281
+ overlayCount() {
3282
+ return this.stack.querySelectorAll(":scope > .tcw-ind-legend-row").length;
3283
+ }
3284
+ renderToggle(e) {
3285
+ let t = e >= pt;
3286
+ !t && this.collapsed && this.setCollapsed(!1);
3287
+ let n = `${t}|${this.collapsed}|${e}`;
3288
+ if (n === this.toggleKey || (this.toggleKey = n, this.toggle.hidden = !t, !t)) return;
3289
+ let r = this.collapsed ? this.labels.expand : this.labels.collapse;
3290
+ U(this.toggle, r, this.collapsed ? `(${e})` : void 0), this.toggle.setAttribute("aria-expanded", String(!this.collapsed));
3291
+ let i = C(this.collapsed ? "chevronDown" : "chevronUp", 12);
3292
+ this.toggle.innerHTML = this.collapsed ? `${i}<span>${e}</span>` : i;
3293
+ }
3294
+ };
3295
+ function U(e, t, n) {
3296
+ e.title = t, e.setAttribute("aria-label", n ? `${t} ${n}` : t);
3297
+ }
3298
+ //#endregion
3299
+ //#region src/widget/legendValues.ts
3300
+ var ht = {
3301
+ psar: ["trend"],
3302
+ supertrend: ["trend"],
3303
+ svwap: ["session"],
3304
+ ao: ["up"],
3305
+ voldelta: ["up"],
3306
+ chaikinOsc: ["adl"],
3307
+ adx: ["dx"],
3308
+ lrc: ["slope"],
3309
+ ichimoku: ["chikou"]
3310
+ }, gt = {
3311
+ psar: (e) => e.trend === 1,
3312
+ supertrend: (e) => e.trend === 1,
3313
+ ao: (e) => e.up === 1,
3314
+ voldelta: (e) => e.up === 1,
3315
+ chaikinOsc: (e) => (e.value ?? 0) >= 0,
3316
+ cmf: (e) => (e.value ?? 0) >= 0,
3317
+ dpo: (e) => (e.value ?? 0) >= 0
3318
+ }, _t = new Set(["ac"]);
3319
+ function W(e, t) {
3320
+ if (!t) return [];
3321
+ let n = ht[e], r = [];
3322
+ for (let e in t) {
3323
+ let i = t[e];
3324
+ typeof i == "number" && Number.isFinite(i) && !n?.includes(e) && r.push(i);
3325
+ }
3326
+ return r;
3327
+ }
3328
+ function vt(e, t, n) {
3329
+ if (_t.has(e)) return null;
3330
+ let r = gt[e];
3331
+ return r ? n ? (r(n) ? t[0] : t[1]) ?? null : null : t[0] ?? null;
3332
+ }
3333
+ var G = /* @__PURE__ */ new Map();
3334
+ function yt(e) {
3335
+ let t = G.get(e);
3336
+ return t || (t = new Intl.NumberFormat(e, {
3337
+ notation: "compact",
3338
+ maximumFractionDigits: 2
3339
+ }), G.set(e, t)), t;
3340
+ }
3341
+ function bt(e, t = "en-US") {
3342
+ let n = Math.abs(e);
3343
+ return n >= 1e6 ? yt(t).format(e) : i(e, n >= 1e3 ? 1 : n >= 1 ? 2 : n >= .01 ? 4 : 6, t);
3344
+ }
3345
+ //#endregion
3346
+ //#region src/widget/WidgetBracketBar.ts
3347
+ var xt = class {
2625
3348
  el;
2626
3349
  labelEl;
2627
3350
  callbacks;
@@ -2631,9 +3354,9 @@ var Ee = class {
2631
3354
  let n = document.createElement("span");
2632
3355
  n.className = "tcw-bracket-hint", n.textContent = "drag lines to adjust", this.el.appendChild(n);
2633
3356
  let r = document.createElement("button");
2634
- r.type = "button", r.className = "tcw-bracket-cancel", r.innerHTML = `${y("x", 14)}<span>Cancel</span>`, r.addEventListener("click", () => this.callbacks.onCancel());
3357
+ r.type = "button", r.className = "tcw-bracket-cancel", r.innerHTML = `${C("x", 14)}<span>Cancel</span>`, r.addEventListener("click", () => this.callbacks.onCancel());
2635
3358
  let i = document.createElement("button");
2636
- 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);
3359
+ i.type = "button", i.className = "tcw-bracket-confirm", i.innerHTML = `${C("check", 14)}<span>Place</span>`, i.addEventListener("click", () => this.callbacks.onConfirm()), this.el.appendChild(r), this.el.appendChild(i), e.appendChild(this.el);
2637
3360
  }
2638
3361
  show(e) {
2639
3362
  this.visible = !0, this.labelEl.textContent = e === "buy" ? "Long bracket" : "Short bracket", this.labelEl.dataset.side = e, this.el.hidden = !1;
@@ -2647,7 +3370,7 @@ var Ee = class {
2647
3370
  destroy() {
2648
3371
  this.el.remove();
2649
3372
  }
2650
- }, Oe = class {
3373
+ }, St = class {
2651
3374
  options;
2652
3375
  audioCtx = null;
2653
3376
  audioEl = null;
@@ -2710,7 +3433,7 @@ var Ee = class {
2710
3433
  };
2711
3434
  //#endregion
2712
3435
  //#region src/widget/ladderRows.ts
2713
- function ke(e, t = 12) {
3436
+ function Ct(e, t = 12) {
2714
3437
  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) => {
2715
3438
  let t = s.get(e);
2716
3439
  return t || (t = {
@@ -2731,7 +3454,7 @@ function ke(e, t = 12) {
2731
3454
  }
2732
3455
  //#endregion
2733
3456
  //#region src/widget/WidgetDepthLadder.ts
2734
- var Ae = class {
3457
+ var wt = class {
2735
3458
  el;
2736
3459
  bodyEl;
2737
3460
  callbacks;
@@ -2744,7 +3467,7 @@ var Ae = class {
2744
3467
  let i = document.createElement("span");
2745
3468
  i.textContent = "Depth Ladder";
2746
3469
  let a = document.createElement("button");
2747
- 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);
3470
+ a.type = "button", a.className = "tcw-ladder-close", a.setAttribute("aria-label", "Close"), a.innerHTML = C("x", 14), a.addEventListener("click", () => this.close()), r.appendChild(i), r.appendChild(a), this.el.appendChild(r);
2748
3471
  let o = document.createElement("div");
2749
3472
  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);
2750
3473
  }
@@ -2765,7 +3488,7 @@ var Ae = class {
2765
3488
  this.renderEmpty();
2766
3489
  return;
2767
3490
  }
2768
- this.render(ke(e, this.levels));
3491
+ this.render(Ct(e, this.levels));
2769
3492
  }
2770
3493
  destroy() {
2771
3494
  this.el.remove();
@@ -2785,20 +3508,20 @@ var Ae = class {
2785
3508
  let e = n.askVolume > 0, r = document.createElement("div");
2786
3509
  r.className = "tcw-ladder-row";
2787
3510
  let i = document.createElement("button");
2788
- i.type = "button", i.className = "tcw-ladder-cell tcw-ladder-bid", n.bidVolume > 0 ? (i.textContent = J(n.bidVolume), i.style.setProperty("--w", `${(n.bidVolume * t * 100).toFixed(1)}%`), i.title = `Sell @ ${this.callbacks.formatPrice(n.price)}`, i.addEventListener("click", () => this.callbacks.onTrade("sell", n.price))) : i.disabled = !0;
3511
+ i.type = "button", i.className = "tcw-ladder-cell tcw-ladder-bid", n.bidVolume > 0 ? (i.textContent = K(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;
2789
3512
  let a = document.createElement("div");
2790
3513
  a.className = `tcw-ladder-price ${e ? "tcw-ask" : "tcw-bid"}`, a.textContent = this.callbacks.formatPrice(n.price);
2791
3514
  let o = document.createElement("button");
2792
- o.type = "button", o.className = "tcw-ladder-cell tcw-ladder-ask", n.askVolume > 0 ? (o.textContent = J(n.askVolume), o.style.setProperty("--w", `${(n.askVolume * t * 100).toFixed(1)}%`), o.title = `Buy @ ${this.callbacks.formatPrice(n.price)}`, o.addEventListener("click", () => this.callbacks.onTrade("buy", n.price))) : o.disabled = !0, r.appendChild(i), r.appendChild(a), r.appendChild(o), this.bodyEl.appendChild(r);
3515
+ o.type = "button", o.className = "tcw-ladder-cell tcw-ladder-ask", n.askVolume > 0 ? (o.textContent = K(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);
2793
3516
  }
2794
3517
  }
2795
3518
  };
2796
- function J(e) {
3519
+ function K(e) {
2797
3520
  return e >= 1e3 ? (e / 1e3).toFixed(1) + "k" : e >= 1 ? e.toFixed(2).replace(/\.00$/, "") : e.toPrecision(2);
2798
3521
  }
2799
3522
  //#endregion
2800
3523
  //#region src/widget/WidgetDataWindow.ts
2801
- var je = class {
3524
+ var Tt = class {
2802
3525
  el;
2803
3526
  bodyEl;
2804
3527
  callbacks;
@@ -2810,7 +3533,7 @@ var je = class {
2810
3533
  let r = document.createElement("span");
2811
3534
  r.textContent = "Data Window";
2812
3535
  let i = document.createElement("button");
2813
- 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);
3536
+ i.type = "button", i.className = "tcw-datawin-close", i.setAttribute("aria-label", "Close"), i.innerHTML = C("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);
2814
3537
  }
2815
3538
  isOpen() {
2816
3539
  return this.open;
@@ -2837,11 +3560,11 @@ var je = class {
2837
3560
  let t = this.callbacks.formatPrice, n = e.ohlc;
2838
3561
  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)));
2839
3562
  let r = e.change > 0 ? "up" : e.change < 0 ? "down" : "", i = e.change > 0 ? "+" : "";
2840
- this.bodyEl.appendChild(this.row("Change", `${i}${t(e.change)} (${i}${e.changePct.toFixed(2)}%)`, r)), this.bodyEl.appendChild(this.row("Volume", Ne(n.volume)));
3563
+ this.bodyEl.appendChild(this.row("Change", `${i}${t(e.change)} (${i}${e.changePct.toFixed(2)}%)`, r)), this.bodyEl.appendChild(this.row("Volume", Dt(n.volume)));
2841
3564
  for (let t of e.indicators) {
2842
3565
  let e = document.createElement("div");
2843
3566
  e.className = "tcw-datawin-sub", e.textContent = t.name, this.bodyEl.appendChild(e);
2844
- for (let e of t.values) this.bodyEl.appendChild(this.row(e.key, Me(e.value)));
3567
+ for (let e of t.values) this.bodyEl.appendChild(this.row(e.key, Et(e.value)));
2845
3568
  }
2846
3569
  }
2847
3570
  row(e, t, n = "") {
@@ -2853,43 +3576,43 @@ var je = class {
2853
3576
  return a.className = `tcw-datawin-value${n ? ` tcw-${n}` : ""}`, a.textContent = t, r.appendChild(i), r.appendChild(a), r;
2854
3577
  }
2855
3578
  };
2856
- function Me(e) {
3579
+ function Et(e) {
2857
3580
  if (!Number.isFinite(e)) return "—";
2858
3581
  let t = Math.abs(e);
2859
3582
  return t >= 1e3 ? e.toFixed(2) : t >= 1 ? e.toFixed(4) : e.toPrecision(4);
2860
3583
  }
2861
- function Ne(e) {
3584
+ function Dt(e) {
2862
3585
  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);
2863
3586
  }
2864
3587
  //#endregion
2865
3588
  //#region src/widget/widgetShareState.ts
2866
- var Y = globalThis.Buffer;
2867
- function Pe(e) {
2868
- if (Y) return Y.from(e, "utf8").toString("base64");
3589
+ var q = globalThis.Buffer;
3590
+ function Ot(e) {
3591
+ if (q) return q.from(e, "utf8").toString("base64");
2869
3592
  let t = new TextEncoder().encode(e), n = "";
2870
3593
  for (let e of t) n += String.fromCharCode(e);
2871
3594
  return btoa(n);
2872
3595
  }
2873
- function Fe(e) {
2874
- if (Y) return Y.from(e, "base64").toString("utf8");
3596
+ function kt(e) {
3597
+ if (q) return q.from(e, "base64").toString("utf8");
2875
3598
  let t = atob(e), n = new Uint8Array(t.length);
2876
3599
  for (let e = 0; e < t.length; e++) n[e] = t.charCodeAt(e);
2877
3600
  return new TextDecoder().decode(n);
2878
3601
  }
2879
- function Ie(e) {
3602
+ function At(e) {
2880
3603
  return e.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2881
3604
  }
2882
- function Le(e) {
3605
+ function jt(e) {
2883
3606
  let t = e.replace(/-/g, "+").replace(/_/g, "/");
2884
3607
  return t + (t.length % 4 == 0 ? "" : "=".repeat(4 - t.length % 4));
2885
3608
  }
2886
- function Re(e) {
2887
- return Ie(Pe(JSON.stringify(e)));
3609
+ function Mt(e) {
3610
+ return At(Ot(JSON.stringify(e)));
2888
3611
  }
2889
- function ze(e) {
3612
+ function Nt(e) {
2890
3613
  if (!e) return null;
2891
3614
  try {
2892
- let t = Fe(Le(e)), n = JSON.parse(t);
3615
+ let t = kt(jt(e)), n = JSON.parse(t);
2893
3616
  return !n || n.v !== 1 || typeof n.symbol != "string" ? null : {
2894
3617
  v: 1,
2895
3618
  symbol: n.symbol,
@@ -2903,28 +3626,36 @@ function ze(e) {
2903
3626
  return null;
2904
3627
  }
2905
3628
  }
2906
- var X = "tcw";
2907
- function Be(e) {
3629
+ var J = "tcw";
3630
+ function Pt(e) {
2908
3631
  let t = e.startsWith("#") ? e.slice(1) : e;
2909
3632
  for (let e of t.split("&")) {
2910
3633
  let t = e.indexOf("=");
2911
- if (t > 0 && e.slice(0, t) === X) return decodeURIComponent(e.slice(t + 1));
3634
+ if (t > 0 && e.slice(0, t) === J) return decodeURIComponent(e.slice(t + 1));
2912
3635
  }
2913
3636
  return null;
2914
3637
  }
2915
- function Ve(e, t) {
3638
+ function Ft(e, t) {
2916
3639
  let [n] = e.split("#");
2917
- return `${n}#${X}=${t}`;
3640
+ return `${n}#${J}=${t}`;
2918
3641
  }
2919
3642
  //#endregion
2920
3643
  //#region src/widget/i18n.ts
2921
- var Z = {
3644
+ var Y = {
2922
3645
  "toolbar.indicators": "Indicators",
2923
3646
  "toolbar.indicators.popular": "Popular",
2924
3647
  "toolbar.indicators.all": "All",
2925
3648
  "indicatorType.overlay": "overlay",
2926
3649
  "indicatorType.panel": "panel",
2927
3650
  "toolbar.replay": "Bar replay",
3651
+ "replay.selectHint": "Click a bar to start the replay",
3652
+ "replay.random": "Random bar",
3653
+ "replay.realtime": "Back to realtime",
3654
+ "replay.barsPerSecond": "bars/s",
3655
+ "replay.play": "Play",
3656
+ "replay.pause": "Pause",
3657
+ "replay.stepBack": "Step back (Shift+←)",
3658
+ "replay.stepForward": "Step forward (Shift+→)",
2928
3659
  "toolbar.longBracket": "Long bracket",
2929
3660
  "toolbar.shortBracket": "Short bracket",
2930
3661
  "toolbar.depthLadder": "Depth ladder",
@@ -2933,6 +3664,24 @@ var Z = {
2933
3664
  "toolbar.screenshot": "Screenshot",
2934
3665
  "toolbar.settings": "Chart Settings",
2935
3666
  "toolbar.toggleTheme": "Toggle theme",
3667
+ "toolbar.timeframes": "Timeframes",
3668
+ "toolbar.timeframes.pin": "Pin to toolbar",
3669
+ "toolbar.fullscreen": "Fullscreen",
3670
+ "legend.show": "Show",
3671
+ "legend.hide": "Hide",
3672
+ "legend.settings": "Settings",
3673
+ "legend.remove": "Remove",
3674
+ "legend.collapse": "Collapse indicators",
3675
+ "legend.expand": "Show indicators",
3676
+ "toolbar.exitFullscreen": "Exit fullscreen",
3677
+ "range.presets": "Visible range",
3678
+ "range.all": "All",
3679
+ "range.goTo": "Go to date",
3680
+ "range.goToSubmit": "Go to",
3681
+ "range.date": "Date",
3682
+ "range.time": "Time",
3683
+ "range.cancel": "Cancel",
3684
+ "range.beforeData": "Showing the earliest loaded bar",
2936
3685
  "chartType.candlestick": "Candlestick",
2937
3686
  "chartType.line": "Line",
2938
3687
  "chartType.area": "Area",
@@ -2966,8 +3715,8 @@ var Z = {
2966
3715
  "hotkeys.group.touch": "Touch (mobile / tablet)",
2967
3716
  "hotkeys.group.keyboard": "Keyboard",
2968
3717
  "hotkeys.group.drawing": "Drawing"
2969
- }, He = {
2970
- en: Z,
3718
+ }, It = {
3719
+ en: Y,
2971
3720
  vi: {
2972
3721
  "toolbar.indicators": "Chỉ báo",
2973
3722
  "toolbar.indicators.popular": "Phổ biến",
@@ -2975,6 +3724,14 @@ var Z = {
2975
3724
  "indicatorType.overlay": "phủ lên",
2976
3725
  "indicatorType.panel": "bảng riêng",
2977
3726
  "toolbar.replay": "Phát lại",
3727
+ "replay.selectHint": "Bấm vào một nến để bắt đầu phát lại",
3728
+ "replay.random": "Nến ngẫu nhiên",
3729
+ "replay.realtime": "Về thời gian thực",
3730
+ "replay.barsPerSecond": "nến/giây",
3731
+ "replay.play": "Phát",
3732
+ "replay.pause": "Tạm dừng",
3733
+ "replay.stepBack": "Lùi một nến (Shift+←)",
3734
+ "replay.stepForward": "Tiến một nến (Shift+→)",
2978
3735
  "toolbar.longBracket": "Lệnh Long",
2979
3736
  "toolbar.shortBracket": "Lệnh Short",
2980
3737
  "toolbar.depthLadder": "Sổ lệnh",
@@ -2983,6 +3740,24 @@ var Z = {
2983
3740
  "toolbar.screenshot": "Chụp màn hình",
2984
3741
  "toolbar.settings": "Cài đặt biểu đồ",
2985
3742
  "toolbar.toggleTheme": "Đổi giao diện",
3743
+ "toolbar.timeframes": "Khung thời gian",
3744
+ "toolbar.timeframes.pin": "Ghim lên thanh công cụ",
3745
+ "toolbar.fullscreen": "Toàn màn hình",
3746
+ "legend.show": "Hiện",
3747
+ "legend.hide": "Ẩn",
3748
+ "legend.settings": "Cài đặt",
3749
+ "legend.remove": "Xoá",
3750
+ "legend.collapse": "Thu gọn chỉ báo",
3751
+ "legend.expand": "Hiện chỉ báo",
3752
+ "toolbar.exitFullscreen": "Thoát toàn màn hình",
3753
+ "range.presets": "Khoảng hiển thị",
3754
+ "range.all": "Tất cả",
3755
+ "range.goTo": "Đi tới ngày",
3756
+ "range.goToSubmit": "Đi tới",
3757
+ "range.date": "Ngày",
3758
+ "range.time": "Giờ",
3759
+ "range.cancel": "Huỷ",
3760
+ "range.beforeData": "Đang hiện nến sớm nhất đã tải",
2986
3761
  "chartType.candlestick": "Nến",
2987
3762
  "chartType.line": "Đường",
2988
3763
  "chartType.area": "Vùng",
@@ -3018,14 +3793,71 @@ var Z = {
3018
3793
  "hotkeys.group.drawing": "Vẽ"
3019
3794
  }
3020
3795
  };
3021
- function Q(e, t) {
3022
- let n = { ...Z }, r = e ? He[e] : void 0;
3796
+ function Lt(e, t) {
3797
+ let n = { ...Y }, r = e ? It[e] : void 0;
3023
3798
  return r && Object.assign(n, r), t && Object.assign(n, t), n;
3024
3799
  }
3025
- function Ue(e) {
3026
- return (t) => e[t] ?? Z[t] ?? t;
3800
+ function Rt(e) {
3801
+ return (t) => e[t] ?? Y[t] ?? t;
3027
3802
  }
3028
- var We = 20, Ge = class {
3803
+ var zt = [
3804
+ [
3805
+ 34,
3806
+ 16,
3807
+ 28,
3808
+ 26,
3809
+ !1
3810
+ ],
3811
+ [
3812
+ 30,
3813
+ 14,
3814
+ 24,
3815
+ 26,
3816
+ !0
3817
+ ],
3818
+ [
3819
+ 26,
3820
+ 18,
3821
+ 20,
3822
+ 30,
3823
+ !0
3824
+ ],
3825
+ [
3826
+ 30,
3827
+ 10,
3828
+ 24,
3829
+ 22,
3830
+ !1
3831
+ ],
3832
+ [
3833
+ 20,
3834
+ 16,
3835
+ 14,
3836
+ 28,
3837
+ !0
3838
+ ],
3839
+ [
3840
+ 14,
3841
+ 18,
3842
+ 8,
3843
+ 30,
3844
+ !0
3845
+ ],
3846
+ [
3847
+ 18,
3848
+ 10,
3849
+ 12,
3850
+ 20,
3851
+ !1
3852
+ ],
3853
+ [
3854
+ 8,
3855
+ 18,
3856
+ 2,
3857
+ 30,
3858
+ !0
3859
+ ]
3860
+ ], Bt = class {
3029
3861
  el;
3030
3862
  label;
3031
3863
  showTimer = null;
@@ -3035,12 +3867,12 @@ var We = 20, Ge = class {
3035
3867
  let n = document.createElement("div");
3036
3868
  n.className = "tcw-loading-card";
3037
3869
  let r = document.createElement("div");
3038
- r.className = "tcw-loading-bars";
3039
- for (let e = 0; e < We; e++) {
3040
- let t = document.createElement("span");
3041
- t.className = "tcw-loading-bar", t.style.height = `${20 + Math.round(Math.sin(e * .9) * 18 + 18)}px`, t.style.animationDelay = `${e * 45}ms`, r.appendChild(t);
3042
- }
3043
- n.appendChild(r), this.label = document.createElement("div"), this.label.className = "tcw-loading-label", this.label.textContent = t, n.appendChild(this.label), this.el.appendChild(n), e.appendChild(this.el);
3870
+ r.className = "tcw-loading-candles", r.setAttribute("aria-hidden", "true"), zt.forEach(([e, t, n, i, a], o) => {
3871
+ let s = document.createElement("span");
3872
+ s.className = a ? "tcw-loading-candle tcw-loading-candle--up" : "tcw-loading-candle", s.style.setProperty("--tcw-body-top", `${e}px`), s.style.setProperty("--tcw-body-h", `${t}px`), s.style.setProperty("--tcw-wick-top", `${n}px`), s.style.setProperty("--tcw-wick-h", `${i}px`), s.style.setProperty("--tcw-delay", `${o * 110}ms`), r.appendChild(s);
3873
+ }), n.appendChild(r);
3874
+ let i = document.createElement("div");
3875
+ i.className = "tcw-loading-track", i.setAttribute("aria-hidden", "true"), i.appendChild(document.createElement("span")), n.appendChild(i), this.label = document.createElement("div"), this.label.className = "tcw-loading-label", this.label.textContent = t, n.appendChild(this.label), this.el.appendChild(n), e.appendChild(this.el);
3044
3876
  }
3045
3877
  begin(e, t = !1) {
3046
3878
  if (this.phase = "loading", this.clearTimer(), this.label.textContent = this.loadingText, this.el.classList.remove("tcw-loading-overlay--error"), this.el.classList.toggle("tcw-loading-overlay--veil", e), !e || t || this.isShown()) {
@@ -3072,33 +3904,51 @@ var We = 20, Ge = class {
3072
3904
  clearTimer() {
3073
3905
  this.showTimer !== null && (clearTimeout(this.showTimer), this.showTimer = null);
3074
3906
  }
3075
- }, Ke = 48, qe = 5e4, Je = 100;
3076
- function Ye() {
3907
+ }, Vt = 48, Ht = 5e4, Ut = 100;
3908
+ function Wt() {
3077
3909
  return new Promise((e) => {
3078
3910
  if (typeof requestAnimationFrame != "function" || document.hidden) {
3079
3911
  setTimeout(e, 0);
3080
3912
  return;
3081
3913
  }
3082
- let t = setTimeout(e, Je);
3914
+ let t = setTimeout(e, Ut);
3083
3915
  requestAnimationFrame(() => setTimeout(() => {
3084
3916
  clearTimeout(t), e();
3085
3917
  }, 0));
3086
3918
  });
3087
3919
  }
3088
- var $ = [
3089
- "#f7931a",
3090
- "#627eea",
3091
- "#26a17b",
3092
- "#e84142",
3093
- "#8247e5",
3094
- "#f3ba2f"
3095
- ], Xe = class {
3920
+ var X = [
3921
+ "#4c8dff",
3922
+ "#a57cff",
3923
+ "#1398a8",
3924
+ "#e25592",
3925
+ "#8a93a3",
3926
+ "#62c895"
3927
+ ], Z = 4, Q = null, $ = (e) => (e[e.length - 1]?.time ?? 0) > 0xe8d4a51000 ? 1 : 1e3, Gt = () => {
3928
+ let e = document.activeElement;
3929
+ return !!e && (e.tagName === "INPUT" || e.tagName === "TEXTAREA" || e.tagName === "SELECT" || e.isContentEditable);
3930
+ }, Kt = class {
3096
3931
  chart;
3097
3932
  state;
3098
3933
  toolbar = null;
3099
3934
  sidebar = null;
3100
3935
  settings = null;
3101
3936
  statusBar = null;
3937
+ goToDate = null;
3938
+ tooltip;
3939
+ indicatorLegend = null;
3940
+ legendFrame = 0;
3941
+ portal = document.createElement("div");
3942
+ overlayHost = () => {
3943
+ let e = document.fullscreenElement === this.root ? this.root : document.body;
3944
+ return this.portal.parentElement !== e && e.appendChild(this.portal), this.portal;
3945
+ };
3946
+ onRootPointerDown = () => {
3947
+ Q = this;
3948
+ };
3949
+ onFullscreenChange = () => {
3950
+ this.toolbar?.setFullscreen(document.fullscreenElement === this.root), this.portal.isConnected && this.overlayHost();
3951
+ };
3102
3952
  commandPalette = null;
3103
3953
  symbolSearch = null;
3104
3954
  hotkeySheet = null;
@@ -3113,15 +3963,18 @@ var $ = [
3113
3963
  depthLadder = null;
3114
3964
  dataWindow = null;
3115
3965
  lastHoverIndex = null;
3116
- favoritesStore = new Ee();
3966
+ legendHoverIndex = null;
3967
+ favoritesStore = new P();
3968
+ timeframeFavorites = new P("tcw:tf-favorites");
3969
+ timeframes = [];
3117
3970
  watchlist = null;
3118
3971
  watchlistSparkBuffer = /* @__PURE__ */ new Map();
3119
3972
  sessionRefPrice = null;
3120
3973
  hostWatchlistRefPrice = /* @__PURE__ */ new Map();
3121
3974
  watchlistInterval = null;
3122
- replayOriginalData = null;
3123
3975
  replayPollInterval = null;
3124
3976
  replaySpeed = 5;
3977
+ replayShade = null;
3125
3978
  layoutKeyPrefix = null;
3126
3979
  layoutDebounceMs = 1500;
3127
3980
  activeLayoutKey = null;
@@ -3142,36 +3995,64 @@ var $ = [
3142
3995
  baseTimeframeMs = 0;
3143
3996
  compares = [];
3144
3997
  constructor(n, r = {}) {
3145
- if (this.options = r, this.symbols = r.symbols ?? ee, this.settingsState = {
3998
+ if (this.options = r, this.symbols = r.symbols ?? te, this.settingsState = {
3146
3999
  ...p,
3147
4000
  ...r.chartOptions?.numberLocale ? { numberLocale: r.chartOptions.numberLocale } : {}
3148
- }, this.t = Ue(Q(r.locale, r.messages)), r.persistLayouts) {
4001
+ }, this.t = Rt(Lt(r.locale, r.messages)), r.persistLayouts) {
3149
4002
  let e = r.persistLayouts === !0 ? {} : r.persistLayouts;
3150
4003
  this.layoutKeyPrefix = e.keyPrefix ?? "tcw:layout:", this.layoutDebounceMs = e.debounceMs ?? 1500;
3151
4004
  }
3152
- let i = this.resolveIsDark(r.theme), a = this.resolveTheme(r.theme);
4005
+ let i = this.resolveIsDark(r.theme), a = this.resolveTheme(r.theme), o = {
4006
+ drawings: !0,
4007
+ drawingMagnet: !0,
4008
+ drawingUndoRedo: !0,
4009
+ indicators: !0,
4010
+ trading: r.trading !== !1,
4011
+ tradingContextMenu: !1,
4012
+ volume: !0,
4013
+ legend: !0,
4014
+ crosshair: !0,
4015
+ crosshairTooltip: !1,
4016
+ keyboard: !0,
4017
+ screenshot: !0,
4018
+ alerts: !0,
4019
+ barCountdown: !0,
4020
+ logScale: !0,
4021
+ watermark: !0,
4022
+ ...r.chartOptions?.features
4023
+ };
4024
+ if (this.timeframes = tt(r.timeframes, o.timeframes), !this.timeframes.some((e) => this.timeframeFavorites.has(e))) {
4025
+ let e = nt(this.timeframes, o.defaultTimeframeFavorites, !!r.timeframes?.length);
4026
+ for (let t of e) this.timeframeFavorites.add(t);
4027
+ }
4028
+ let c = r.timeframe ?? "5m", l = !o.timeframes?.length || o.timeframes.includes(c) ? c : this.timeframes[0] ?? c;
3153
4029
  this.state = {
3154
4030
  symbol: r.symbol ?? this.symbols[0] ?? "BTCUSDT",
3155
- timeframe: r.timeframe ?? "5m",
4031
+ timeframe: l,
3156
4032
  chartType: r.chartOptions?.chartType ?? "candlestick",
3157
4033
  isDark: i,
3158
4034
  activeIndicators: /* @__PURE__ */ new Map(),
3159
4035
  activeTool: null,
3160
- magnetEnabled: !0,
4036
+ magnetEnabled: o.drawingMagnet !== !1,
4037
+ stayInDrawing: !1,
3161
4038
  connectionState: r.adapter ? "connecting" : "disconnected",
3162
4039
  connectionMessage: r.adapter ? this.t("status.connecting") : ""
3163
- }, g(), this.root = document.createElement("div"), this.root.className = "tcw-root", this.root.dataset.tcwTheme = i ? "dark" : "light", n.appendChild(this.root), r.toolbar !== !1 && (this.toolbar = new ne(this.root, {
4040
+ }, ne(), this.root = document.createElement("div"), this.root.className = "tcw-root", this.root.dataset.tcwTheme = i ? "dark" : "light", n.appendChild(this.root), this.tooltip = new lt(this.root), this.portal.className = "tcw-root tcw-portal", this.portal.dataset.tcwTheme = this.root.dataset.tcwTheme, r.toolbar !== !1 && (this.toolbar = new se(this.root, {
3164
4041
  symbols: this.symbols,
3165
- timeframes: r.timeframes ? c.filter((e) => r.timeframes.includes(e.value)) : c,
3166
- chartTypes: r.chartTypes ? l.filter((e) => r.chartTypes.includes(e.value)) : l,
3167
- indicators: d,
3168
- popularIndicatorIds: f
4042
+ timeframes: this.timeframes.map((e) => ({
4043
+ value: e,
4044
+ label: F(e)
4045
+ })),
4046
+ timeframeFavorites: this.pinnedTimeframes(),
4047
+ chartTypes: r.chartTypes ? u.filter((e) => r.chartTypes.includes(e.value)) : u,
4048
+ indicators: f,
4049
+ popularIndicatorIds: ee
3169
4050
  }, {
3170
4051
  onSymbolClick: () => this.handleSymbolClick(),
3171
4052
  onTimeframe: (e) => this.handleTimeframe(e),
4053
+ onToggleTimeframeFavorite: (e) => this.handleToggleTimeframeFavorite(e),
3172
4054
  onChartType: (e) => this.handleChartType(e),
3173
4055
  onAddIndicator: (e) => this.handleAddIndicator(e),
3174
- onRemoveIndicator: (e) => this.handleRemoveIndicator(e),
3175
4056
  onScreenshot: () => this.chart.screenshot(),
3176
4057
  onSettings: () => this.openSettings(),
3177
4058
  onToggleTheme: () => this.handleToggleTheme(),
@@ -3179,16 +4060,17 @@ var $ = [
3179
4060
  onToggleAlerts: r.alerts === !1 ? void 0 : () => this.toggleAlerts(),
3180
4061
  onToggleObjects: r.objectTree === !1 ? void 0 : () => this.toggleObjects(),
3181
4062
  onBracket: r.trading === !1 ? void 0 : (e) => this.startBracket(e),
3182
- onToggleLadder: r.trading !== !1 && r.depthLadder ? () => this.depthLadder?.toggle() : void 0
4063
+ onToggleLadder: r.trading !== !1 && r.depthLadder ? () => this.depthLadder?.toggle() : void 0,
4064
+ onToggleFullscreen: r.fullscreen !== !1 && typeof document < "u" && document.fullscreenEnabled ? () => this.toggleFullscreen() : void 0
3183
4065
  }, this.t));
3184
- let o = document.createElement("div");
3185
- if (o.className = "tcw-body", r.drawingTools !== !1 && (r.drawingFavorites && this.favoritesStore.seedDefaults(r.drawingFavorites), this.sidebar = new se(o, {
3186
- drawingToolGroups: u,
4066
+ let m = document.createElement("div");
4067
+ if (m.className = "tcw-body", r.drawingTools !== !1 && (r.drawingFavorites && this.favoritesStore.seedDefaults(r.drawingFavorites), this.sidebar = new le(m, {
4068
+ drawingToolGroups: d,
3187
4069
  favorites: this.favoritesStore.list()
3188
4070
  }, {
3189
4071
  onDrawingTool: (e) => this.handleDrawingTool(e),
3190
4072
  onCancelDrawing: () => this.handleCancelDrawing(),
3191
- onToggleMagnet: () => this.handleToggleMagnet(),
4073
+ onToggleMagnet: o.drawingMagnet === !1 ? void 0 : () => this.handleToggleMagnet(),
3192
4074
  onToggleFavorite: (e) => this.handleToggleFavorite(e),
3193
4075
  onUndo: () => this.chart.undo(),
3194
4076
  onRedo: () => this.chart.redo(),
@@ -3198,34 +4080,17 @@ var $ = [
3198
4080
  activeTool: null
3199
4081
  }, this.updateUI();
3200
4082
  },
3201
- onToggleStyle: () => this.drawingStyle?.toggle()
3202
- })), this.chartContainer = document.createElement("div"), this.chartContainer.className = "tcw-chart-container", o.appendChild(this.chartContainer), this.loading = new Ge(this.chartContainer, this.t("status.loading")), r.watchlist && (this.watchlist = new V(o, this.symbols, { onSelect: (e) => {
4083
+ onToggleStyle: () => this.drawingStyle?.toggle(),
4084
+ onToggleStayInDrawing: () => this.handleToggleStayInDrawing()
4085
+ })), this.chartContainer = document.createElement("div"), this.chartContainer.className = "tcw-chart-container", m.appendChild(this.chartContainer), this.loading = new Bt(this.chartContainer, this.t("status.loading")), r.watchlist && (this.watchlist = new Oe(m, this.symbols, { onSelect: (e) => {
3203
4086
  this.setSymbol(e);
3204
- } }, this.t("watchlist.title")), this.watchlist.setActive(this.state.symbol), this.watchlist.setLocale(this.settingsState.numberLocale || void 0)), this.root.appendChild(o), this.chart = new e(this.chartContainer, {
4087
+ } }, this.t("watchlist.title")), this.watchlist.setActive(this.state.symbol), this.watchlist.setLocale(this.settingsState.numberLocale || void 0)), this.root.appendChild(m), this.chart = new e(this.chartContainer, {
3205
4088
  chartType: this.state.chartType,
3206
4089
  theme: a,
3207
4090
  autoScale: !0,
3208
4091
  crosshair: { mode: "magnet" },
3209
4092
  ...r.chartOptions,
3210
- features: {
3211
- drawings: !0,
3212
- drawingMagnet: !0,
3213
- drawingUndoRedo: !0,
3214
- indicators: !0,
3215
- trading: r.trading !== !1,
3216
- tradingContextMenu: r.trading !== !1,
3217
- volume: !0,
3218
- legend: !0,
3219
- crosshair: !0,
3220
- crosshairTooltip: !1,
3221
- keyboard: !0,
3222
- screenshot: !0,
3223
- alerts: !0,
3224
- barCountdown: !0,
3225
- logScale: !0,
3226
- watermark: !0,
3227
- ...r.chartOptions?.features
3228
- }
4093
+ features: o
3229
4094
  }), this.chart.on("dataUpdate", (e) => this.handleDataUpdate(e.payload)), r.dragDropImport !== !1 && (this.dragDrop = new t(this.chartContainer, {
3230
4095
  onData: (e, t, n) => {
3231
4096
  this.setData(e), this.toast(`Loaded ${t.data.length} bars from ${n.name}` + (t.skipped > 0 ? ` (${t.skipped} skipped)` : ""));
@@ -3233,28 +4098,92 @@ var $ = [
3233
4098
  onError: (e, t) => {
3234
4099
  this.toast(`${t.name}: ${e.message}`, "error");
3235
4100
  }
3236
- }), this.dragDrop.attach()), r.statusBar !== !1 && (this.statusBar = new C(this.root)), r.settings !== !1 && (this.settings = new S({
4101
+ }), this.dragDrop.attach()), r.statusBar !== !1) {
4102
+ let e = r.rangeBar !== !1;
4103
+ this.statusBar = new fe(this.root, e ? {
4104
+ presets: s,
4105
+ presetLabels: { All: this.t("range.all") },
4106
+ groupLabel: this.t("range.presets"),
4107
+ goToLabel: this.t("range.goTo"),
4108
+ onPreset: (e) => this.chart.setVisibleRangePreset(e),
4109
+ onGoTo: () => this.toggleGoToDate()
4110
+ } : void 0), e && (this.goToDate = new st(this.root, {
4111
+ title: this.t("range.goTo"),
4112
+ date: this.t("range.date"),
4113
+ time: this.t("range.time"),
4114
+ submit: this.t("range.goToSubmit"),
4115
+ cancel: this.t("range.cancel")
4116
+ }, ({ date: e, time: t }) => this.goToWallTime(e, t)));
4117
+ }
4118
+ if (r.settings !== !1 && (this.settings = new de({
3237
4119
  onChange: (e) => this.applySettings(e),
3238
4120
  onReset: () => this.resetSettings(),
3239
4121
  onClose: () => {}
3240
- }, this.t)), this.symbolSearch = new T({
4122
+ }, this.t, {
4123
+ barCountdown: o.barCountdown,
4124
+ logScale: o.logScale
4125
+ }, this.overlayHost)), this.symbolSearch = new me({
3241
4126
  onPick: (e) => {
3242
4127
  this.setSymbol(e);
3243
4128
  },
3244
4129
  onClose: () => {}
3245
- }), this.hotkeySheet = new N({ onClose: () => {} }, this.t), this.chart.on("barClick", (e) => {
4130
+ }, this.overlayHost), this.hotkeySheet = new be({ onClose: () => {} }, this.t, this.overlayHost), this.chart.on("drawingToolChange", (e) => {
4131
+ let t = e.payload.tool;
4132
+ t !== this.state.activeTool && (this.state = {
4133
+ ...this.state,
4134
+ activeTool: t
4135
+ }, this.updateUI());
4136
+ }), this.chart.on("indicatorAdd", () => this.syncIndicatorsFromChart()), this.chart.on("indicatorRemove", () => this.syncIndicatorsFromChart()), r.indicatorLegend !== !1) {
4137
+ this.chart.setPaneTitlesVisible(!1), this.indicatorLegend = new mt(this.chartContainer, {
4138
+ onToggleVisible: (e, t) => {
4139
+ this.chart.setIndicatorVisible(e, t), this.scheduleLegend(), this.objectTree?.isOpen() && this.refreshObjects();
4140
+ },
4141
+ onSettings: (e) => this.openIndicatorSettings(e),
4142
+ onRemove: (e) => this.handleRemoveIndicator(e)
4143
+ }, {
4144
+ show: this.t("legend.show"),
4145
+ hide: this.t("legend.hide"),
4146
+ settings: this.t("legend.settings"),
4147
+ remove: this.t("legend.remove"),
4148
+ collapse: this.t("legend.collapse"),
4149
+ expand: this.t("legend.expand")
4150
+ }), this.chart.on("crosshairMove", (e) => {
4151
+ let t = e.payload;
4152
+ this.legendHoverIndex = typeof t.barIndex == "number" ? t.barIndex : null, this.scheduleLegend();
4153
+ }), this.chart.on("crosshairLeave", () => {
4154
+ this.legendHoverIndex = null, this.scheduleLegend();
4155
+ });
4156
+ for (let e of [
4157
+ "indicatorUpdate",
4158
+ "dataUpdate",
4159
+ "resize",
4160
+ "paneResize",
4161
+ "themeChange"
4162
+ ]) this.chart.on(e, () => this.scheduleLegend());
4163
+ }
4164
+ if (this.chart.on("barClick", (e) => {
3246
4165
  if (!this.replayBar?.isMounted()) return;
3247
4166
  let t = e.payload.barIndex;
3248
- typeof t == "number" && (this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(t), this.replayBar.setState("paused"));
3249
- }), this.dataWindow = new je(this.root, { formatPrice: (e) => this.formatAlertPrice(e) }), this.chart.on("crosshairMove", (e) => {
4167
+ if (typeof t == "number") {
4168
+ if (this.replayBar.getMode() === "select") {
4169
+ this.startReplayAt(t);
4170
+ return;
4171
+ }
4172
+ this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(t), this.replayBar.setState("paused");
4173
+ }
4174
+ }), this.chart.on("crosshairMove", (e) => {
4175
+ if (this.replayBar?.getMode() !== "select" || !this.replayBar.isMounted()) return;
4176
+ let t = e.payload.point;
4177
+ this.positionReplayShade(t?.x ?? null);
4178
+ }), this.dataWindow = new Tt(this.root, { formatPrice: (e) => this.formatAlertPrice(e) }), this.chart.on("crosshairMove", (e) => {
3250
4179
  let t = e.payload;
3251
4180
  this.lastHoverIndex = typeof t.barIndex == "number" ? t.barIndex : null, this.dataWindow?.isOpen() && this.dataWindow.render(this.buildDataWindowModel());
3252
- }), r.drawingTools !== !1 && (this.drawingStyle = new we(this.root, {
4181
+ }), r.drawingTools !== !1 && (this.drawingStyle = new Ye(this.root, {
3253
4182
  onStyleChange: (e) => {
3254
4183
  this.chart.setDrawingStyle(e), this.chart.setSelectedDrawingStyle(e);
3255
4184
  },
3256
4185
  getStyle: () => this.chart.getDrawingStyle()
3257
- }, new be())), r.trading !== !1 && (this.bracketBar = new De(this.root, {
4186
+ }, new Ge())), r.trading !== !1 && (this.bracketBar = new xt(this.root, {
3258
4187
  onConfirm: () => this.chart.confirmBracket(),
3259
4188
  onCancel: () => {
3260
4189
  this.chart.cancelBracket(), this.bracketBar?.hide();
@@ -3262,7 +4191,7 @@ var $ = [
3262
4191
  }), this.chart.on("bracketPlace", (e) => {
3263
4192
  let t = e.payload;
3264
4193
  this.bracketBar?.hide(), this.toast(`${t.side === "buy" ? "Long" : "Short"} bracket placed · ${t.riskReward.toFixed(2)}R`);
3265
- }), r.depthLadder && (this.depthLadder = new Ae(this.root, {
4194
+ }), r.depthLadder && (this.depthLadder = new wt(this.root, {
3266
4195
  onTrade: (e, t) => {
3267
4196
  this.chart.placeOrderIntent({
3268
4197
  side: e,
@@ -3274,7 +4203,7 @@ var $ = [
3274
4203
  })), this.chart.on("dataUpdate", (e) => {
3275
4204
  let t = e.payload;
3276
4205
  t && t.bracket === "cancelled" && this.bracketBar?.hide();
3277
- })), r.alerts !== !1 && (this.alertsPanel = new ue(this.root, {
4206
+ })), r.alerts !== !1 && (this.alertsPanel = new Fe(this.root, {
3278
4207
  onAdd: (e, t, n, r, i) => {
3279
4208
  this.chart.addAlert(e, t, n, r, i);
3280
4209
  },
@@ -3282,18 +4211,20 @@ var $ = [
3282
4211
  onClear: () => this.chart.clearAlerts(),
3283
4212
  getChannelValue: (e) => this.getAlertChannelValue(e),
3284
4213
  formatPrice: (e) => this.formatAlertPrice(e)
3285
- }), this.chart.on("alertAdd", () => this.refreshAlerts()), this.chart.on("alertRemove", () => this.refreshAlerts()), this.chart.on("alertUpdate", () => this.refreshAlerts()), r.alertNotifications && (this.alertNotifier = new Oe(r.alertNotifications)), this.chart.on("alertTriggered", (e) => {
4214
+ }), this.chart.on("alertAdd", () => this.refreshAlerts()), this.chart.on("alertRemove", () => this.refreshAlerts()), this.chart.on("alertUpdate", () => this.refreshAlerts()), r.alertNotifications && (this.alertNotifier = new St(r.alertNotifications)), this.chart.on("alertTriggered", (e) => {
3286
4215
  let t = e.payload, n = `Price ${this.formatAlertPrice(t.price)}${t.message ? ` — ${t.message}` : ""}`;
3287
4216
  this.toast(`🔔 Alert: ${n}`, "info"), this.alertNotifier?.notify(n), this.refreshAlerts();
3288
4217
  })), r.objectTree !== !1) {
3289
- this.indicatorSettings = new ge(this.root, {
3290
- onApply: (e, t) => this.chart.updateIndicator(e, t),
4218
+ this.indicatorSettings = new Ve(this.root, {
4219
+ onApply: (e, t) => {
4220
+ this.chart.updateIndicator(e, t), this.syncIndicatorsFromChart();
4221
+ },
3291
4222
  onClose: () => {}
3292
- }), this.objectTree = new de(this.root, {
4223
+ }), this.objectTree = new Ie(this.root, {
3293
4224
  onRemoveIndicator: (e) => this.handleRemoveIndicator(e),
3294
4225
  onConfigureIndicator: (e) => this.openIndicatorSettings(e),
3295
4226
  onToggleIndicatorVisible: (e, t) => {
3296
- this.chart.setIndicatorVisible(e, t), this.refreshObjects();
4227
+ this.chart.setIndicatorVisible(e, t), this.refreshObjects(), this.scheduleLegend();
3297
4228
  },
3298
4229
  onRemoveDrawing: (e) => {
3299
4230
  this.chart.removeDrawing(e), this.refreshObjects();
@@ -3304,7 +4235,7 @@ var $ = [
3304
4235
  onToggleDrawingLocked: (e, t) => {
3305
4236
  this.chart.setDrawingLocked(e, t), this.refreshObjects();
3306
4237
  },
3307
- onAddCompare: () => this.handleAddCompare(),
4238
+ onAddCompare: o.compareSymbols === !1 ? void 0 : () => this.handleAddCompare(),
3308
4239
  onRemoveCompare: (e) => this.handleRemoveCompare(e)
3309
4240
  });
3310
4241
  let e = () => {
@@ -3312,23 +4243,28 @@ var $ = [
3312
4243
  };
3313
4244
  this.chart.on("drawingCreate", e), this.chart.on("drawingRemove", e), this.chart.on("indicatorAdd", e), this.chart.on("indicatorRemove", e);
3314
4245
  }
3315
- if (this.commandPalette = new w({
4246
+ if (this.commandPalette = new pe({
3316
4247
  onIndicator: (e) => this.handleAddIndicator(e),
3317
4248
  onChartType: (e) => this.handleChartType(e),
3318
4249
  onDrawingTool: (e) => this.handleDrawingTool(e),
3319
4250
  onTimeframe: (e) => this.handleTimeframe(e),
3320
4251
  onAction: (e) => this.handleAction(e),
3321
4252
  onClose: () => {}
3322
- }), this.boundGlobalKeydown = (e) => {
3323
- if ((e.ctrlKey || e.metaKey) && e.key === "k") e.preventDefault(), this.toggleCommandPalette();
3324
- else if ((e.ctrlKey || e.metaKey) && (e.key === "p" || e.key === "P")) e.preventDefault(), this.symbolSearch?.open(this.symbols, this.state.symbol);
3325
- else if (e.key === "?" && !e.ctrlKey && !e.metaKey && !e.altKey) {
3326
- let t = document.activeElement;
3327
- if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) return;
3328
- e.preventDefault(), this.hotkeySheet?.open();
4253
+ }, this.overlayHost), this.boundGlobalKeydown = (e) => {
4254
+ if (!(this.replayBar?.isMounted() && this.handleReplayKey(e))) {
4255
+ if ((e.ctrlKey || e.metaKey) && e.key === "k") e.preventDefault(), this.toggleCommandPalette();
4256
+ else if ((e.ctrlKey || e.metaKey) && (e.key === "p" || e.key === "P")) e.preventDefault(), this.symbolSearch?.open(this.symbols, this.state.symbol);
4257
+ else if (e.altKey && !e.ctrlKey && !e.metaKey && (e.code === "KeyI" || e.code === "KeyG")) {
4258
+ if (Gt() || Q !== null && Q !== this) return;
4259
+ e.code === "KeyI" ? (e.preventDefault(), this.applySettings({ invertScale: !this.settingsState.invertScale })) : this.goToDate && (e.preventDefault(), this.toggleGoToDate());
4260
+ } else if (e.key === "?" && !e.ctrlKey && !e.metaKey && !e.altKey) {
4261
+ let t = document.activeElement;
4262
+ if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) return;
4263
+ e.preventDefault(), this.hotkeySheet?.open();
4264
+ }
3329
4265
  }
3330
- }, document.addEventListener("keydown", this.boundGlobalKeydown), r.adapter && (this.adapter = r.adapter, this.connectStream()), this.watchlist && (this.watchlistInterval = setInterval(() => this.tickWatchlist(), 1e3)), this.updateUI(), r.onReady?.(this.chart), r.shareUrl && typeof location < "u") {
3331
- let e = Be(location.hash);
4266
+ }, document.addEventListener("keydown", this.boundGlobalKeydown), document.addEventListener("fullscreenchange", this.onFullscreenChange), this.root.addEventListener("pointerdown", this.onRootPointerDown, !0), 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") {
4267
+ let e = Pt(location.hash);
3332
4268
  e && this.importState(e);
3333
4269
  }
3334
4270
  }
@@ -3358,19 +4294,21 @@ var $ = [
3358
4294
  });
3359
4295
  }
3360
4296
  async setTimeframe(e) {
3361
- if (this.state = {
3362
- ...this.state,
3363
- timeframe: e
3364
- }, this.options.onTimeframeChange?.(e), this.updateUI(), this.adapter) {
3365
- await this.connectStream();
3366
- return;
3367
- }
3368
- if (this.options.resampleTimeframes !== !1) {
3369
- if (!this.baseSeries) {
3370
- let e = this.chart.getData();
3371
- e.length > 0 && (this.baseSeries = e, this.baseTimeframeMs = s(e));
4297
+ if (this.chart.isTimeframeAllowed(e)) {
4298
+ if (this.state = {
4299
+ ...this.state,
4300
+ timeframe: e
4301
+ }, this.options.onTimeframeChange?.(e), this.updateUI(), this.adapter) {
4302
+ await this.connectStream();
4303
+ return;
4304
+ }
4305
+ if (this.options.resampleTimeframes !== !1) {
4306
+ if (!this.baseSeries) {
4307
+ let e = this.chart.getData();
4308
+ e.length > 0 && (this.baseSeries = e, this.baseTimeframeMs = l(e));
4309
+ }
4310
+ await this.switchLocalTimeframe();
3372
4311
  }
3373
- await this.switchLocalTimeframe();
3374
4312
  }
3375
4313
  }
3376
4314
  setTheme(e) {
@@ -3378,13 +4316,13 @@ var $ = [
3378
4316
  this.state = {
3379
4317
  ...this.state,
3380
4318
  isDark: t
3381
- }, this.root.dataset.tcwTheme = t ? "dark" : "light", this.chart.setTheme(n), this.updateUI();
4319
+ }, this.root.dataset.tcwTheme = t ? "dark" : "light", this.portal.dataset.tcwTheme = this.root.dataset.tcwTheme, this.chart.setTheme(n), this.updateUI();
3382
4320
  }
3383
4321
  getChart() {
3384
4322
  return this.chart;
3385
4323
  }
3386
4324
  destroy() {
3387
- this.destroyed || (this.destroyed = !0, this.boundGlobalKeydown && document.removeEventListener("keydown", this.boundGlobalKeydown), this.flushActiveLayout(), this.commandPalette?.destroy(), this.symbolSearch?.destroy(), this.hotkeySheet?.destroy(), this.replayPollInterval && clearInterval(this.replayPollInterval), this.replayBar?.destroy(), this.dragDrop?.detach(), this.alertsPanel?.destroy(), this.objectTree?.destroy(), this.indicatorSettings?.destroy(), this.drawingStyle?.destroy(), this.bracketBar?.destroy(), this.alertNotifier?.destroy(), this.depthLadder?.destroy(), this.dataWindow?.destroy(), this.watchlistInterval && clearInterval(this.watchlistInterval), this.watchlist?.destroy(), this.toolbar?.destroy(), this.sidebar?.destroy(), this.settings?.destroy(), this.statusBar?.destroy(), this.loading.destroy(), this.chart.destroy(), this.root.remove(), _());
4325
+ this.destroyed || (this.destroyed = !0, this.boundGlobalKeydown && document.removeEventListener("keydown", this.boundGlobalKeydown), document.removeEventListener("fullscreenchange", this.onFullscreenChange), this.root.removeEventListener("pointerdown", this.onRootPointerDown, !0), this.tooltip.destroy(), this.legendFrame && cancelAnimationFrame(this.legendFrame), this.indicatorLegend?.destroy(), Q === this && (Q = null), this.portal.remove(), document.fullscreenElement === this.root && document.exitFullscreen().catch(() => {}), this.flushActiveLayout(), this.commandPalette?.destroy(), this.symbolSearch?.destroy(), this.hotkeySheet?.destroy(), this.replayPollInterval && clearInterval(this.replayPollInterval), this.replayShade?.remove(), this.replayBar?.destroy(), this.dragDrop?.detach(), this.alertsPanel?.destroy(), this.objectTree?.destroy(), this.indicatorSettings?.destroy(), this.drawingStyle?.destroy(), this.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.goToDate?.destroy(), this.loading.destroy(), this.chart.destroy(), this.root.remove(), re());
3388
4326
  }
3389
4327
  handleSymbolClick() {
3390
4328
  this.symbolSearch?.open(this.symbols, this.state.symbol);
@@ -3392,14 +4330,49 @@ var $ = [
3392
4330
  handleTimeframe(e) {
3393
4331
  this.setTimeframe(e);
3394
4332
  }
4333
+ toggleFullscreen() {
4334
+ if (document.fullscreenElement === this.root) {
4335
+ document.exitFullscreen().catch(() => {});
4336
+ return;
4337
+ }
4338
+ this.root.requestFullscreen().catch((e) => {
4339
+ this.toast(e instanceof Error ? e.message : "Fullscreen is not available", "error");
4340
+ });
4341
+ }
4342
+ displayTzOffset() {
4343
+ let e = this.settingsState.timezone;
4344
+ return e === "local" || !Number.isFinite(Number(e)) ? null : Number(e);
4345
+ }
4346
+ toggleGoToDate() {
4347
+ if (!this.goToDate) return;
4348
+ if (this.goToDate.isOpen()) {
4349
+ this.goToDate.close();
4350
+ return;
4351
+ }
4352
+ let e = this.chart.getData();
4353
+ e.length !== 0 && this.goToDate.open(ot(e[e.length - 1].time * $(e), this.displayTzOffset()), this.root.querySelector("[data-role=\"goto\"]"));
4354
+ }
4355
+ goToWallTime(e, t) {
4356
+ let n = at(e, t, this.displayTzOffset()), r = this.chart.getData();
4357
+ if (n === null || r.length === 0) return;
4358
+ let i = n / $(r);
4359
+ this.chart.goToTime(i), i < r[0].time && this.toast(this.t("range.beforeData"));
4360
+ }
4361
+ pinnedTimeframes() {
4362
+ let e = this.timeframeFavorites.list();
4363
+ return this.timeframes.filter((t) => e.includes(t));
4364
+ }
4365
+ handleToggleTimeframeFavorite(e) {
4366
+ this.timeframeFavorites.toggle(e), this.toolbar?.setTimeframeFavorites(this.pinnedTimeframes()), this.updateUI();
4367
+ }
3395
4368
  setData(e) {
3396
- this.localSeq++, this.baseSeries = e, this.baseTimeframeMs = s(e), this.applyTimeframeData(), this.adapter || this.loading.end();
4369
+ this.localSeq++, this.baseSeries = e, this.baseTimeframeMs = l(e), this.applyTimeframeData(), this.adapter || this.loading.end();
3397
4370
  }
3398
4371
  async switchLocalTimeframe() {
3399
4372
  if (!this.baseSeries) return;
3400
- let e = ++this.localSeq, t = this.lastLocalSwitchMs >= Ke || this.baseSeries.length >= qe;
4373
+ let e = ++this.localSeq, t = this.lastLocalSwitchMs >= Vt || this.baseSeries.length >= Ht;
3401
4374
  try {
3402
- if (t && (this.loading.begin(this.chart.getData().length > 0, !0), await Ye(), e !== this.localSeq || this.destroyed)) return;
4375
+ if (t && (this.loading.begin(this.chart.getData().length > 0, !0), await Wt(), e !== this.localSeq || this.destroyed)) return;
3403
4376
  this.applyTimeframeData();
3404
4377
  } finally {
3405
4378
  e === this.localSeq && this.loading.end();
@@ -3407,10 +4380,10 @@ var $ = [
3407
4380
  }
3408
4381
  applyTimeframeData() {
3409
4382
  if (!this.baseSeries) return;
3410
- let e = performance.now(), t = a(this.state.timeframe);
4383
+ let e = performance.now(), t = o(this.state.timeframe);
3411
4384
  if (this.baseTimeframeMs > 0 && t > this.baseTimeframeMs) {
3412
4385
  let e = this.options.weekStartsOn ?? 1;
3413
- this.chart.setData(o(this.baseSeries, this.state.timeframe, { weekStartsOn: e }));
4386
+ this.chart.setData(c(this.baseSeries, this.state.timeframe, { weekStartsOn: e }));
3414
4387
  } else this.chart.setData(this.baseSeries);
3415
4388
  this.lastLocalSwitchMs = performance.now() - e;
3416
4389
  }
@@ -3456,7 +4429,7 @@ var $ = [
3456
4429
  id: e.id,
3457
4430
  params: e.params
3458
4431
  }));
3459
- return Re({
4432
+ return Mt({
3460
4433
  v: 1,
3461
4434
  symbol: this.state.symbol,
3462
4435
  timeframe: this.state.timeframe,
@@ -3467,26 +4440,19 @@ var $ = [
3467
4440
  });
3468
4441
  }
3469
4442
  async importState(e) {
3470
- let t = ze(e);
4443
+ let t = Nt(e);
3471
4444
  if (!t) return !1;
3472
4445
  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);
3473
- for (let [, e] of this.state.activeIndicators) this.chart.removeIndicator(e);
3474
- let n = /* @__PURE__ */ new Map();
3475
- for (let e of t.indicators) {
3476
- let t = this.chart.addIndicator(e.id, e.params);
3477
- t && n.set(e.id, t);
3478
- }
3479
- return this.state = {
3480
- ...this.state,
3481
- activeIndicators: n
3482
- }, this.chart.setDrawings(t.drawings), this.updateUI(), !0;
4446
+ for (let e of [...this.state.activeIndicators.keys()]) this.chart.removeIndicator(e);
4447
+ for (let e of t.indicators) this.chart.addIndicator(e.id, e.params);
4448
+ return this.chart.setDrawings(t.drawings), this.updateUI(), !0;
3483
4449
  }
3484
4450
  async copyChartImage() {
3485
4451
  let e = await this.chart.copyScreenshot();
3486
4452
  this.toast(e ? "Chart image copied" : "Copy failed — image clipboard unavailable", e ? "info" : "error");
3487
4453
  }
3488
4454
  async copyShareLink() {
3489
- let e = Ve(typeof location < "u" ? location.href : "", this.exportState());
4455
+ let e = Ft(typeof location < "u" ? location.href : "", this.exportState());
3490
4456
  try {
3491
4457
  await navigator.clipboard.writeText(e), this.toast("Share link copied");
3492
4458
  } catch {
@@ -3554,7 +4520,7 @@ var $ = [
3554
4520
  visible: e.visible
3555
4521
  })), t = this.chart.getDrawings().map((e) => ({
3556
4522
  id: e.id,
3557
- label: pe(e.type),
4523
+ label: Re(e.type),
3558
4524
  visible: e.visible,
3559
4525
  locked: e.locked
3560
4526
  })), n = this.compares.map((e) => ({
@@ -3576,7 +4542,7 @@ var $ = [
3576
4542
  }
3577
4543
  async addCompareSymbol(e) {
3578
4544
  if (!this.adapter || this.compares.some((t) => t.symbol === e)) return;
3579
- let t = $[this.compares.length % $.length], n = `cmp_${e}`;
4545
+ let t = X[this.compares.length % X.length], n = `cmp_${e}`;
3580
4546
  try {
3581
4547
  let r = await this.adapter.fetchHistory(e, this.state.timeframe, this.options.historyLimit ?? 500);
3582
4548
  this.compares.length === 0 && this.chart.setCompareMode("percent"), this.chart.addCompareSymbol(n, e, r, t), this.compares = [...this.compares, {
@@ -3650,37 +4616,10 @@ var $ = [
3650
4616
  }, this.chart.setChartType(e), this.updateUI();
3651
4617
  }
3652
4618
  handleAddIndicator(e) {
3653
- if (this.state.activeIndicators.has(e)) {
3654
- let t = this.state.activeIndicators.get(e);
3655
- this.chart.removeIndicator(t);
3656
- let n = new Map(this.state.activeIndicators);
3657
- n.delete(e), this.state = {
3658
- ...this.state,
3659
- activeIndicators: n
3660
- };
3661
- } else {
3662
- let t = this.chart.addIndicator(e);
3663
- if (t) {
3664
- let n = new Map(this.state.activeIndicators);
3665
- n.set(e, t), this.state = {
3666
- ...this.state,
3667
- activeIndicators: n
3668
- };
3669
- }
3670
- }
3671
- this.updateUI();
4619
+ this.chart.addIndicator(e);
3672
4620
  }
3673
4621
  handleRemoveIndicator(e) {
3674
4622
  this.chart.removeIndicator(e);
3675
- let t = new Map(this.state.activeIndicators);
3676
- for (let [n, r] of t.entries()) if (r === e) {
3677
- t.delete(n);
3678
- break;
3679
- }
3680
- this.state = {
3681
- ...this.state,
3682
- activeIndicators: t
3683
- }, this.updateUI();
3684
4623
  }
3685
4624
  toggleCommandPalette() {
3686
4625
  if (this.commandPalette?.isOpen()) {
@@ -3691,29 +4630,29 @@ var $ = [
3691
4630
  }
3692
4631
  buildCommandItems() {
3693
4632
  let e = [];
3694
- for (let t of d) e.push({
4633
+ for (let t of f) e.push({
3695
4634
  id: t.id,
3696
4635
  label: t.name,
3697
4636
  category: "indicator",
3698
- active: this.state.activeIndicators.has(t.id)
4637
+ active: [...this.state.activeIndicators.values()].some((e) => e.id === t.id)
3699
4638
  });
3700
- for (let t of l) e.push({
4639
+ for (let t of u) e.push({
3701
4640
  id: t.value,
3702
4641
  label: t.label,
3703
4642
  category: "chartType",
3704
4643
  active: this.state.chartType === t.value
3705
4644
  });
3706
- for (let t of u) for (let n of t.tools) e.push({
4645
+ for (let t of d) for (let n of t.tools) e.push({
3707
4646
  id: n.value,
3708
4647
  label: n.label,
3709
4648
  category: "drawing",
3710
4649
  active: this.state.activeTool === n.value
3711
4650
  });
3712
- for (let t of c) e.push({
3713
- id: t.value,
3714
- label: t.label,
4651
+ for (let t of this.timeframes) e.push({
4652
+ id: t,
4653
+ label: F(t),
3715
4654
  category: "timeframe",
3716
- active: this.state.timeframe === t.value
4655
+ active: this.state.timeframe === t
3717
4656
  });
3718
4657
  return e.push({
3719
4658
  id: "screenshot",
@@ -3795,6 +4734,13 @@ var $ = [
3795
4734
  activeTool: null
3796
4735
  }, this.chart.setDrawingTool(null), this.updateUI();
3797
4736
  }
4737
+ handleToggleStayInDrawing() {
4738
+ let e = !this.state.stayInDrawing;
4739
+ this.state = {
4740
+ ...this.state,
4741
+ stayInDrawing: e
4742
+ }, this.chart.setStayInDrawingMode(e), this.updateUI();
4743
+ }
3798
4744
  handleToggleMagnet() {
3799
4745
  let e = !this.state.magnetEnabled;
3800
4746
  this.state = {
@@ -3807,7 +4753,7 @@ var $ = [
3807
4753
  this.state = {
3808
4754
  ...this.state,
3809
4755
  isDark: e
3810
- }, this.root.dataset.tcwTheme = e ? "dark" : "light", this.chart.setTheme(e ? n : r), this.chart.setWatermark(this.state.symbol.replace("USDT", " / USDT"), {
4756
+ }, this.root.dataset.tcwTheme = e ? "dark" : "light", this.portal.dataset.tcwTheme = this.root.dataset.tcwTheme, this.chart.setTheme(e ? n : r), this.chart.setWatermark(this.state.symbol.replace("USDT", " / USDT"), {
3811
4757
  fontSize: 48,
3812
4758
  color: e ? "rgba(255,255,255,0.03)" : "rgba(0,0,0,0.03)"
3813
4759
  }), this.updateUI();
@@ -3833,7 +4779,7 @@ var $ = [
3833
4779
  let t = this.layoutKeyPrefix + e;
3834
4780
  this.activeLayoutKey = t;
3835
4781
  try {
3836
- this.chart.loadStateFromStorage(t) && this.rebuildActiveIndicatorsMapFromChart();
4782
+ this.chart.loadStateFromStorage(t) && this.syncIndicatorsFromChart();
3837
4783
  } catch {}
3838
4784
  this.chart.setAutoSave(t, this.layoutDebounceMs);
3839
4785
  }
@@ -3845,9 +4791,12 @@ var $ = [
3845
4791
  this.chart.disableAutoSave(), this.activeLayoutKey = null;
3846
4792
  }
3847
4793
  }
3848
- rebuildActiveIndicatorsMapFromChart() {
4794
+ syncIndicatorsFromChart() {
3849
4795
  let e = /* @__PURE__ */ new Map();
3850
- for (let t of this.chart.getActiveIndicators()) e.set(t.id, t.instanceId);
4796
+ for (let t of this.chart.getActiveIndicators()) e.set(t.instanceId, {
4797
+ id: t.id,
4798
+ label: qt(t.id, t.params, t.descriptor.defaultConfig)
4799
+ });
3851
4800
  this.state = {
3852
4801
  ...this.state,
3853
4802
  activeIndicators: e
@@ -3857,61 +4806,109 @@ var $ = [
3857
4806
  this.replayBar?.isMounted() ? this.exitReplay() : this.enterReplay();
3858
4807
  }
3859
4808
  enterReplay() {
3860
- let e = this.chart.getData();
3861
- e.length < 2 || (this.replayOriginalData = e.slice(), this.replayBar = new F({
4809
+ if (this.replayTotal() < 2) return;
4810
+ let e = this.t;
4811
+ this.replayBar = new Ce({
3862
4812
  onPlay: () => {
3863
- this.chart.getReplayState() === "paused" ? this.chart.replayResume() : this.chart.replayStart({
3864
- speed: this.replaySpeed,
3865
- interval: 200
3866
- }), this.replayBar?.setState("playing");
4813
+ if (this.replayBar?.getMode() === "select") {
4814
+ this.startReplayAt(Math.max(1, this.replayTotal() - 100), !0);
4815
+ return;
4816
+ }
4817
+ this.chart.getReplayState() === "paused" && this.chart.replayResume(), this.replayBar?.setState("playing");
3867
4818
  },
3868
4819
  onPause: () => {
3869
4820
  this.chart.replayPause(), this.replayBar?.setState("paused");
3870
4821
  },
3871
- onStop: () => {
3872
- this.chart.replayStop(), this.replayBar?.setState("paused");
3873
- },
3874
- onStepBack: () => {
3875
- let e = this.chart.getReplayProgress();
3876
- this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(Math.max(0, e.current - 1)), this.replayBar?.setState("paused");
3877
- },
3878
- onStepForward: () => {
3879
- let e = this.chart.getReplayProgress();
3880
- this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(Math.min(e.total - 1, e.current + 1)), this.replayBar?.setState("paused");
3881
- },
4822
+ onStepBack: () => this.stepReplay(-1),
4823
+ onStepForward: () => this.stepReplay(1),
3882
4824
  onSeek: (e) => {
3883
4825
  this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(e), this.replayBar?.setState("paused");
3884
4826
  },
3885
4827
  onSpeedChange: (e) => {
3886
4828
  this.replaySpeed = e, this.chart.setReplaySpeed(e);
3887
4829
  },
4830
+ onRandomStart: () => {
4831
+ let e = this.replayTotal(), t = Math.max(1, Math.floor(e * .1)), n = Math.max(t, Math.floor(e * .9));
4832
+ this.startReplayAt(t + Math.floor(Math.random() * (n - t + 1)));
4833
+ },
3888
4834
  onClose: () => this.exitReplay()
4835
+ }, {
4836
+ selectHint: e("replay.selectHint"),
4837
+ random: e("replay.random"),
4838
+ realtime: e("replay.realtime"),
4839
+ barsPerSecond: e("replay.barsPerSecond"),
4840
+ play: e("replay.play"),
4841
+ pause: e("replay.pause"),
4842
+ stepBack: e("replay.stepBack"),
4843
+ stepForward: e("replay.stepForward")
3889
4844
  }), this.replayBar.mount(this.chartContainer, {
3890
- total: e.length,
3891
- speed: this.replaySpeed
3892
- }), this.chart.replayStart({
4845
+ total: this.replayTotal(),
3893
4846
  speed: this.replaySpeed,
3894
- interval: 200,
3895
- startIndex: 1
3896
- }), this.chart.replayPause(), this.replayBar.setState("paused"), this.replayPollInterval = setInterval(() => {
3897
- if (!this.replayBar?.isMounted()) return;
3898
- let e = this.chart.getReplayProgress();
3899
- this.replayBar.setProgress(e.current, e.total);
3900
- let t = this.chart.getReplayState();
3901
- t === "stopped" ? this.replayBar.setState("paused") : this.replayBar.setState(t);
3902
- }, 150));
4847
+ mode: "select"
4848
+ }), this.replayShade = document.createElement("div"), this.replayShade.className = "tcw-replay-shade", this.replayShade.hidden = !0, this.chartContainer.appendChild(this.replayShade), this.chartContainer.addEventListener("mouseleave", this.hideReplayShade);
4849
+ }
4850
+ hideReplayShade = () => this.positionReplayShade(null);
4851
+ replayFrom(e, t = !1) {
4852
+ this.replayBar?.isMounted() || this.enterReplay(), this.startReplayAt(e, t);
4853
+ }
4854
+ startReplayAt(e, t = !1) {
4855
+ let n = this.replayBar;
4856
+ if (!n) return;
4857
+ let r = this.replayTotal(), i = Math.max(0, Math.min(Number.isFinite(e) ? Math.floor(e) : 0, r - 1));
4858
+ this.replayShade?.remove(), this.replayShade = null, this.chartContainer.removeEventListener("mouseleave", this.hideReplayShade), n.setMode("replay"), this.chart.replayStart({
4859
+ speed: this.replaySpeed,
4860
+ interval: 1e3,
4861
+ startIndex: i,
4862
+ paused: !0
4863
+ }), t && this.chart.replayResume(), n.setState(t ? "playing" : "paused"), this.syncReplayBar(), this.replayPollInterval && clearInterval(this.replayPollInterval), this.replayPollInterval = setInterval(() => this.syncReplayBar(), 150);
4864
+ }
4865
+ replayTotal() {
4866
+ return this.chart.isReplayActive() ? this.chart.getReplayProgress().total : this.chart.getData().length;
4867
+ }
4868
+ syncReplayBar() {
4869
+ let e = this.replayBar;
4870
+ if (!e?.isMounted() || e.getMode() !== "replay") return;
4871
+ if (!this.chart.isReplayActive()) {
4872
+ this.teardownReplayUi();
4873
+ return;
4874
+ }
4875
+ let t = this.chart.getReplayProgress(), n = this.chart.getReplayState();
4876
+ e.setProgress(t.current, t.total), e.setState(n === "stopped" ? "paused" : n), e.setEnded(n !== "playing" && t.total > 0 && t.current >= t.total - 1);
4877
+ }
4878
+ stepReplay(e) {
4879
+ if (this.replayBar?.getMode() !== "replay") return;
4880
+ let t = this.chart.getReplayProgress();
4881
+ this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(Math.max(0, Math.min(t.total - 1, t.current + e))), this.replayBar.setState("paused"), this.syncReplayBar();
4882
+ }
4883
+ handleReplayKey(e) {
4884
+ if (e.defaultPrevented) return !1;
4885
+ let t = document.activeElement;
4886
+ return t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.tagName === "SELECT" || t.isContentEditable) ? !1 : e.shiftKey && (e.key === "ArrowRight" || e.key === "ArrowLeft") && this.replayBar?.getMode() === "replay" ? (e.preventDefault(), e.stopPropagation(), this.stepReplay(e.key === "ArrowRight" ? 1 : -1), !0) : e.key === "Escape" && this.replayBar?.getMode() === "select" ? (this.exitReplay(), !0) : !1;
4887
+ }
4888
+ positionReplayShade(e) {
4889
+ let t = this.replayShade;
4890
+ if (!t) return;
4891
+ let n = this.chart.getPlotRect();
4892
+ if (e === null || e < n.x || e > n.x + n.width) {
4893
+ t.hidden = !0;
4894
+ return;
4895
+ }
4896
+ t.hidden = !1, t.style.left = `${e}px`, t.style.top = `${n.y}px`, t.style.width = `${n.x + n.width - e}px`, t.style.height = `${n.height}px`;
3903
4897
  }
3904
4898
  exitReplay() {
3905
- this.replayPollInterval &&= (clearInterval(this.replayPollInterval), null), this.chart.replayStop(), this.replayBar?.unmount(), this.replayBar = null, this.replayOriginalData &&= (this.chart.setData(this.replayOriginalData), null);
4899
+ this.teardownReplayUi(), this.chart.replayStop();
4900
+ }
4901
+ teardownReplayUi() {
4902
+ this.replayPollInterval &&= (clearInterval(this.replayPollInterval), null), this.replayShade?.remove(), this.replayShade = null, this.chartContainer.removeEventListener("mouseleave", this.hideReplayShade), this.replayBar?.unmount(), this.replayBar = null;
3906
4903
  }
3907
4904
  applySettings(e) {
3908
4905
  this.settingsState = {
3909
4906
  ...this.settingsState,
3910
4907
  ...e
3911
- }, 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({
4908
+ }, this.scheduleLegend(), 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({
3912
4909
  left: e.pivotStrength,
3913
4910
  right: e.pivotStrength
3914
- }), 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 = {
4911
+ }), 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.invertScale !== void 0 && this.chart.setInvertScale(e.invertScale), e.scaleMode === void 0 ? e.logScale !== void 0 && (this.chart.setLogScale(e.logScale), this.settingsState = {
3915
4912
  ...this.settingsState,
3916
4913
  scaleMode: e.logScale ? "logarithmic" : "regular"
3917
4914
  }) : (this.chart.setScaleMode(e.scaleMode), this.settingsState = {
@@ -3960,8 +4957,37 @@ var $ = [
3960
4957
  }
3961
4958
  this.updateUI();
3962
4959
  }
4960
+ scheduleLegend() {
4961
+ !this.indicatorLegend || this.legendFrame || (this.legendFrame = requestAnimationFrame(() => {
4962
+ this.legendFrame = 0, this.renderLegend();
4963
+ }));
4964
+ }
4965
+ renderLegend() {
4966
+ if (!this.indicatorLegend || this.destroyed) return;
4967
+ let e = this.chart.getData().length - 1, t = this.chart.isTimeAligned() ? this.legendHoverIndex : null, n = t === null ? e : Math.min(Math.max(t, 0), e), r = new Map(this.chart.getIndicatorPanes().map((e) => [e.instanceId, e.rect])), i = this.settingsState.numberLocale || "en-US", a = this.chart.getActiveIndicators().map((t) => {
4968
+ let a = r.get(t.instanceId) ?? null, o = this.chart.getIndicatorOutput(t.instanceId)?.series, s = n >= 0 ? o?.[n] : null, c = W(t.id, s), l = (n === e ? c.length : W(t.id, e >= 0 ? o?.[e] : null).length) === 1 ? vt(t.id, this.chart.getIndicatorStyle(t.instanceId)?.colors ?? [], s) : null;
4969
+ return {
4970
+ instanceId: t.instanceId,
4971
+ label: qt(t.id, t.params, t.descriptor.defaultConfig),
4972
+ visible: t.visible,
4973
+ values: c.map((e) => ({
4974
+ text: a ? bt(e, i) : this.chart.formatPrice(e),
4975
+ color: l
4976
+ })),
4977
+ pane: a ? {
4978
+ x: a.x + Z,
4979
+ y: a.y + 1,
4980
+ width: a.width - 2 * Z
4981
+ } : null
4982
+ };
4983
+ }), o = this.chart.getPlotRect();
4984
+ this.indicatorLegend.update(a, {
4985
+ left: o.x + Z,
4986
+ top: this.chart.getLegendBottom() + 1
4987
+ });
4988
+ }
3963
4989
  updateUI() {
3964
- this.toolbar?.update(this.state), this.sidebar?.update(this.state), this.statusBar?.update({
4990
+ this.scheduleLegend(), this.toolbar?.update(this.state), this.sidebar?.update(this.state), this.statusBar?.update({
3965
4991
  connectionState: this.state.connectionState,
3966
4992
  message: this.state.connectionMessage,
3967
4993
  symbol: this.state.symbol,
@@ -3982,7 +5008,11 @@ var $ = [
3982
5008
  return !0;
3983
5009
  }
3984
5010
  };
5011
+ function qt(e, t, n) {
5012
+ let r = Object.keys(n || t).map((e) => t[e]).filter((e) => typeof e == "number" && Number.isFinite(e)).slice(0, 3).map((e) => String(Number(e.toFixed(4))));
5013
+ return [e.toUpperCase(), ...r].join(" ");
5014
+ }
3985
5015
  //#endregion
3986
- export { Xe as ChartWidget };
5016
+ export { y as CHART_TYPE_ICONS, Kt as ChartWidget, v as DRAWING_TOOL_ICONS, _ as UI_ICONS, T as createChartTypeIcon, C as createIcon, w as createToolIcon, x as iconSvg };
3987
5017
 
3988
5018
  //# sourceMappingURL=index.js.map