@tradecanvas/chart 1.3.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 (70) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +858 -828
  3. package/dist/Chart.d.ts +124 -1
  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-cURSpfUb.js → DragDropImporter-Dd9Mud5J.js} +376 -160
  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 +2 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +70 -85
  19. package/dist/index.js.map +1 -1
  20. package/dist/widget/ChartWidget.d.ts +71 -7
  21. package/dist/widget/ChartWidget.d.ts.map +1 -1
  22. package/dist/widget/WidgetCommandPalette.d.ts +3 -1
  23. package/dist/widget/WidgetCommandPalette.d.ts.map +1 -1
  24. package/dist/widget/WidgetDrawingSidebar.d.ts +12 -0
  25. package/dist/widget/WidgetDrawingSidebar.d.ts.map +1 -1
  26. package/dist/widget/WidgetGoToDate.d.ts +45 -0
  27. package/dist/widget/WidgetGoToDate.d.ts.map +1 -0
  28. package/dist/widget/WidgetHotkeySheet.d.ts +3 -1
  29. package/dist/widget/WidgetHotkeySheet.d.ts.map +1 -1
  30. package/dist/widget/WidgetIndicatorLegend.d.ts +68 -0
  31. package/dist/widget/WidgetIndicatorLegend.d.ts.map +1 -0
  32. package/dist/widget/WidgetLoadingOverlay.d.ts.map +1 -1
  33. package/dist/widget/WidgetReplayBar.d.ts +37 -7
  34. package/dist/widget/WidgetReplayBar.d.ts.map +1 -1
  35. package/dist/widget/WidgetSettings.d.ts +13 -1
  36. package/dist/widget/WidgetSettings.d.ts.map +1 -1
  37. package/dist/widget/WidgetStatusBar.d.ts +16 -1
  38. package/dist/widget/WidgetStatusBar.d.ts.map +1 -1
  39. package/dist/widget/WidgetSymbolSearch.d.ts +3 -1
  40. package/dist/widget/WidgetSymbolSearch.d.ts.map +1 -1
  41. package/dist/widget/WidgetToolbar.d.ts +12 -3
  42. package/dist/widget/WidgetToolbar.d.ts.map +1 -1
  43. package/dist/widget/WidgetTooltip.d.ts +43 -0
  44. package/dist/widget/WidgetTooltip.d.ts.map +1 -0
  45. package/dist/widget/escapeHtml.d.ts +3 -0
  46. package/dist/widget/escapeHtml.d.ts.map +1 -0
  47. package/dist/widget/i18n.d.ts +26 -0
  48. package/dist/widget/i18n.d.ts.map +1 -1
  49. package/dist/widget/iconSet.d.ts +26 -0
  50. package/dist/widget/iconSet.d.ts.map +1 -0
  51. package/dist/widget/icons.d.ts +5 -0
  52. package/dist/widget/icons.d.ts.map +1 -1
  53. package/dist/widget/index.cjs +3035 -2561
  54. package/dist/widget/index.cjs.map +1 -1
  55. package/dist/widget/index.d.ts +3 -0
  56. package/dist/widget/index.d.ts.map +1 -1
  57. package/dist/widget/index.js +1546 -585
  58. package/dist/widget/index.js.map +1 -1
  59. package/dist/widget/legendValues.d.ts +14 -0
  60. package/dist/widget/legendValues.d.ts.map +1 -0
  61. package/dist/widget/types.d.ts +34 -8
  62. package/dist/widget/types.d.ts.map +1 -1
  63. package/dist/widget/widgetConfig.d.ts +1 -5
  64. package/dist/widget/widgetConfig.d.ts.map +1 -1
  65. package/dist/widget/widgetTimeframes.d.ts +20 -0
  66. package/dist/widget/widgetTimeframes.d.ts.map +1 -0
  67. package/package.json +3 -3
  68. package/dist/DragDropImporter-BazeSQPD.cjs +0 -2
  69. package/dist/DragDropImporter-BazeSQPD.cjs.map +0 -1
  70. package/dist/DragDropImporter-cURSpfUb.js.map +0 -1
@@ -1,12 +1,13 @@
1
- import { r as e, t } from "../DragDropImporter-cURSpfUb.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,7 +655,7 @@ var c = [
679
655
  "atr",
680
656
  "obv",
681
657
  "ichimoku"
682
- ], ee = [
658
+ ], te = [
683
659
  "BTCUSDT",
684
660
  "ETHUSDT",
685
661
  "SOLUSDT",
@@ -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: #d9dde4;\r\n background: #080b10;\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: #080b10;\r\n --tcw-bg-surface: #0c1016;\r\n --tcw-bg-elevated: #141922;\r\n --tcw-bg-overlay: rgba(20, 25, 34, 0.5);\r\n --tcw-border: #1f2630;\r\n --tcw-border-strong: #2a323e;\r\n --tcw-text: #e7e9ee;\r\n --tcw-text-dim: #aab1bd;\r\n --tcw-text-muted: #758091;\r\n\r\n /* TradeCanvas amber. --tcw-accent-ink is the text colour on an accent fill. */\r\n --tcw-accent: #f2a93b;\r\n --tcw-accent-hover: #f5b95c;\r\n --tcw-accent-ink: #1a1204;\r\n --tcw-accent-soft: rgba(242, 169, 59, 0.14);\r\n --tcw-accent-glow: rgba(242, 169, 59, 0.22);\r\n --tcw-accent-line: rgba(242, 169, 59, 0.55);\r\n\r\n --tcw-red: #e8505b;\r\n --tcw-red-soft: rgba(232, 80, 91, 0.12);\r\n --tcw-green: #1fa874;\r\n --tcw-green-soft: rgba(31, 168, 116, 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(242, 169, 59, 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: #0c1016;\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: #e3e6eb;\r\n --tcw-border-strong: #d2d6dd;\r\n --tcw-text: #0c1016;\r\n --tcw-text-dim: #3f4754;\r\n --tcw-text-muted: #626a77;\r\n\r\n /* Deeper amber: readable as text on the light ground, white text readable on it. */\r\n --tcw-accent: #a0610a;\r\n --tcw-accent-hover: #874f07;\r\n --tcw-accent-ink: #ffffff;\r\n --tcw-accent-soft: rgba(160, 97, 10, 0.10);\r\n --tcw-accent-glow: rgba(160, 97, 10, 0.16);\r\n --tcw-accent-line: rgba(160, 97, 10, 0.45);\r\n --tcw-ring: 0 0 0 2px rgba(160, 97, 10, 0.4);\r\n\r\n /* Darker semantic colours: used as text on white. */\r\n --tcw-red: #c42f3e;\r\n --tcw-red-soft: rgba(196, 47, 62, 0.10);\r\n --tcw-green: #0b7d50;\r\n --tcw-green-soft: rgba(11, 125, 80, 0.10);\r\n\r\n --tcw-hover-bg: rgba(0, 0, 0, 0.04);\r\n --tcw-active-bg: rgba(160, 97, 10, 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 (candle skeleton) === */\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: 14px;\r\n padding: 22px 26px 20px;\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-candles {\r\n position: relative;\r\n display: flex;\r\n gap: 7px;\r\n height: 64px;\r\n}\r\n\r\n/* One candle: the element is the wick's column, ::before the wick, ::after the body. */\r\n.tcw-loading-candle {\r\n position: relative;\r\n width: 8px;\r\n height: 100%;\r\n color: var(--tcw-red);\r\n opacity: 0.28;\r\n animation: tcw-candle-light 1.6s var(--tcw-ease) infinite;\r\n}\r\n\r\n.tcw-loading-candle--up { color: var(--tcw-green); }\r\n\r\n.tcw-loading-candle::before,\r\n.tcw-loading-candle::after {\r\n content: '';\r\n position: absolute;\r\n left: 50%;\r\n background: currentColor;\r\n transform: translateX(-50%);\r\n}\r\n\r\n.tcw-loading-candle::before {\r\n top: var(--tcw-wick-top);\r\n width: 1.5px;\r\n height: var(--tcw-wick-h);\r\n}\r\n\r\n.tcw-loading-candle::after {\r\n top: var(--tcw-body-top);\r\n width: 8px;\r\n height: var(--tcw-body-h);\r\n border-radius: 1.5px;\r\n}\r\n\r\n/* Each candle brightens and lifts slightly in turn, left to right. */\r\n@keyframes tcw-candle-light {\r\n 0%, 55%, 100% { opacity: 0.28; transform: translateY(0); }\r\n 20% { opacity: 1; transform: translateY(-2px); }\r\n}\r\n\r\n.tcw-loading-track {\r\n position: relative;\r\n width: 100%;\r\n min-width: 88px;\r\n height: 2px;\r\n border-radius: 1px;\r\n background: var(--tcw-border);\r\n overflow: hidden;\r\n}\r\n\r\n.tcw-loading-track > span {\r\n position: absolute;\r\n inset: 0;\r\n width: 40%;\r\n border-radius: 1px;\r\n background: linear-gradient(90deg, transparent, var(--tcw-accent), transparent);\r\n animation: tcw-loading-sweep 1.6s var(--tcw-ease) infinite;\r\n}\r\n\r\n@keyframes tcw-loading-sweep {\r\n from { transform: translateX(-100%); }\r\n to { transform: translateX(250%); }\r\n}\r\n\r\n/* The status text is announced, not shown — the candles say \"loading\". */\r\n.tcw-loading-label {\r\n position: absolute;\r\n width: 1px;\r\n height: 1px;\r\n overflow: hidden;\r\n clip-path: inset(50%);\r\n white-space: nowrap;\r\n}\r\n\r\n.tcw-loading-overlay--error .tcw-loading-candles,\r\n.tcw-loading-overlay--error .tcw-loading-track {\r\n display: none;\r\n}\r\n\r\n/* A failure is shown: why the chart is empty and that a retry is running. */\r\n.tcw-loading-overlay--error .tcw-loading-label {\r\n position: static;\r\n width: auto;\r\n height: auto;\r\n overflow: visible;\r\n clip-path: none;\r\n white-space: normal;\r\n max-width: 320px;\r\n text-align: center;\r\n color: var(--tcw-red);\r\n font-size: 13px;\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n .tcw-loading-candle,\r\n .tcw-loading-track > span {\r\n animation: none;\r\n }\r\n .tcw-loading-candle { opacity: 0.6; }\r\n .tcw-loading-track > span { transform: translateX(75%); }\r\n /* Static candles don't say \"loading\" on their own: show the text. */\r\n .tcw-loading-label {\r\n position: static;\r\n width: auto;\r\n height: auto;\r\n overflow: visible;\r\n clip-path: none;\r\n font-size: 12px;\r\n color: var(--tcw-text-muted);\r\n }\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: var(--tcw-accent-ink);\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(31, 168, 116, 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(232, 80, 91, 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: var(--tcw-accent-ink);\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: var(--tcw-accent-ink);\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: var(--tcw-accent-ink);\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: var(--tcw-accent-ink);\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"
@@ -1645,11 +1921,11 @@ var A = {
1645
1921
  label: "Pan — past the last bar into empty future space"
1646
1922
  },
1647
1923
  {
1648
- keys: [j, "Drag"],
1924
+ keys: [A, "Drag"],
1649
1925
  label: "Select drawings in a box"
1650
1926
  },
1651
1927
  {
1652
- keys: [j, "Click"],
1928
+ keys: [A, "Click"],
1653
1929
  label: "Add / remove a drawing from the selection"
1654
1930
  },
1655
1931
  {
@@ -1728,12 +2004,12 @@ var A = {
1728
2004
  title: "Drawing",
1729
2005
  entries: [
1730
2006
  {
1731
- keys: [j, "Z"],
2007
+ keys: [A, "Z"],
1732
2008
  label: "Undo"
1733
2009
  },
1734
2010
  {
1735
2011
  keys: [
1736
- j,
2012
+ A,
1737
2013
  "Shift",
1738
2014
  "Z"
1739
2015
  ],
@@ -1742,17 +2018,25 @@ var A = {
1742
2018
  {
1743
2019
  keys: ["Esc"],
1744
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)"
1745
2029
  }
1746
2030
  ]
1747
2031
  }
1748
- ], N = class {
2032
+ ], be = class {
1749
2033
  backdrop = null;
1750
2034
  modal = null;
1751
2035
  callbacks;
1752
2036
  t;
1753
2037
  boundKeydown;
1754
- constructor(e, t) {
1755
- 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) => {
1756
2040
  e.key === "Escape" && (e.preventDefault(), this.close());
1757
2041
  };
1758
2042
  }
@@ -1767,12 +2051,12 @@ var A = {
1767
2051
  n.className = "tcw-modal-body";
1768
2052
  let r = document.createElement("div");
1769
2053
  r.className = "tcw-hotkey-grid";
1770
- for (let e of M) {
2054
+ for (let e of ye) {
1771
2055
  let t = document.createElement("section");
1772
2056
  t.className = "tcw-hotkey-section";
1773
2057
  let n = document.createElement("div");
1774
2058
  n.className = "tcw-settings-section-title";
1775
- let i = A[e.title];
2059
+ let i = ve[e.title];
1776
2060
  n.textContent = i ? this.t(i) : e.title, t.appendChild(n);
1777
2061
  for (let n of e.entries) {
1778
2062
  let e = document.createElement("div");
@@ -1797,7 +2081,7 @@ var A = {
1797
2081
  let i = document.createElement("div");
1798
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>";
1799
2083
  let a = document.createElement("button");
1800
- 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);
1801
2085
  }
1802
2086
  close() {
1803
2087
  document.removeEventListener("keydown", this.boundKeydown), this.backdrop?.remove(), this.modal?.remove(), this.backdrop = null, this.modal = null, this.callbacks.onClose();
@@ -1808,90 +2092,127 @@ var A = {
1808
2092
  destroy() {
1809
2093
  this.close();
1810
2094
  }
1811
- }, P = [
1812
- .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 = [
1813
2105
  1,
1814
2106
  2,
2107
+ 3,
1815
2108
  5,
1816
2109
  10,
1817
- 20,
1818
- 50,
1819
- 100
1820
- ], F = class {
2110
+ 25,
2111
+ 50
2112
+ ], Ce = class {
1821
2113
  root = null;
1822
2114
  scrubber = null;
1823
2115
  progressLabel = null;
1824
2116
  playBtn = null;
2117
+ realtimeBtn = null;
1825
2118
  state = "stopped";
2119
+ mode = "select";
2120
+ ended = !1;
1826
2121
  total = 0;
1827
2122
  speed = 5;
1828
- callbacks;
1829
- constructor(e) {
1830
- this.callbacks = e;
2123
+ labels;
2124
+ constructor(e, t = {}) {
2125
+ this.callbacks = e, this.labels = {
2126
+ ...xe,
2127
+ ...t
2128
+ };
1831
2129
  }
1832
2130
  mount(e, t) {
1833
- 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());
1834
2132
  }
1835
2133
  unmount() {
1836
- 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;
1837
2135
  }
1838
2136
  isMounted() {
1839
2137
  return this.root !== null;
1840
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
+ }
1841
2146
  setState(e) {
1842
2147
  this.state = e, this.syncUi();
1843
2148
  }
2149
+ setEnded(e) {
2150
+ this.ended !== e && (this.ended = e, this.syncUi());
2151
+ }
1844
2152
  setProgress(e, t) {
1845
- 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}`);
1846
2154
  }
1847
2155
  destroy() {
1848
2156
  this.unmount();
1849
2157
  }
1850
2158
  markup() {
1851
- 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("");
1852
2160
  return `
1853
- <button class="tcw-replay-btn" data-act="close" title="Exit replay" aria-label="Exit replay">${B()}</button>
1854
- <button class="tcw-replay-btn" data-act="stepBack" title="Step back" aria-label="Step back">${R()}</button>
1855
- <button class="tcw-replay-btn tcw-replay-play" data-act="play" title="Play / pause" aria-label="Play / pause">${I()}</button>
1856
- <button class="tcw-replay-btn" data-act="stepForward" title="Step forward" aria-label="Step forward">${z()}</button>
1857
- <input type="range" class="tcw-replay-scrubber" data-act="seek" min="0" max="${Math.max(0, this.total - 1)}" value="0" step="1" />
1858
- <span class="tcw-replay-progress" data-tcw="progress">1 / ${this.total}</span>
1859
- <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>
1860
2174
  `;
1861
2175
  }
1862
2176
  wireEvents() {
1863
- 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", () => {
1864
2179
  this.state === "playing" ? this.callbacks.onPause() : this.callbacks.onPlay();
1865
- }), this.scrubber?.addEventListener("input", () => {
1866
- let e = Number(this.scrubber.value);
1867
- this.callbacks.onSeek(e);
1868
- }), 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) => {
1869
2181
  let t = Number(e.target.value);
1870
2182
  this.speed = t, this.callbacks.onSpeedChange(t);
1871
2183
  }));
1872
2184
  }
1873
2185
  syncUi() {
1874
- 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
+ }
1875
2196
  }
1876
2197
  };
1877
- function I() {
1878
- 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>";
1879
2200
  }
1880
- function L() {
1881
- 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>";
1882
2203
  }
1883
- function R() {
1884
- 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>";
1885
2206
  }
1886
- function z() {
1887
- 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>";
1888
2209
  }
1889
- function B() {
1890
- 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>";
1891
2212
  }
1892
2213
  //#endregion
1893
2214
  //#region src/widget/WidgetWatchlist.ts
1894
- var V = class {
2215
+ var Oe = class {
1895
2216
  el;
1896
2217
  listEl;
1897
2218
  rowMap = /* @__PURE__ */ new Map();
@@ -1935,7 +2256,7 @@ var V = class {
1935
2256
  let t = document.createElement("div");
1936
2257
  t.className = "tcw-watchlist-row", t.tabIndex = 0;
1937
2258
  let n = document.createElement("div");
1938
- n.className = "tcw-watchlist-symbol", n.textContent = H(e);
2259
+ n.className = "tcw-watchlist-symbol", n.textContent = ke(e);
1939
2260
  let r = document.createElement("canvas");
1940
2261
  r.className = "tcw-watchlist-spark", r.width = 64, r.height = 22;
1941
2262
  let i = document.createElement("div");
@@ -1959,18 +2280,18 @@ var V = class {
1959
2280
  renderRow(e) {
1960
2281
  let t = this.rowMap.get(e), n = this.entries.get(e);
1961
2282
  if (!(!t || !n)) {
1962
- 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) {
1963
2284
  let e = n.lastPrice - n.refPrice, r = e / n.refPrice * 100, i = e >= 0 ? "+" : "-", a = Math.abs(r).toLocaleString(this.locale, {
1964
2285
  minimumFractionDigits: 2,
1965
2286
  maximumFractionDigits: 2
1966
2287
  });
1967
2288
  t.changeEl.textContent = `${i}${a}%`, t.changeEl.className = `tcw-watchlist-change ${e >= 0 ? "tcw-up" : "tcw-down"}`;
1968
2289
  } else t.changeEl.textContent = "";
1969
- 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]);
1970
2291
  }
1971
2292
  }
1972
2293
  };
1973
- function H(e) {
2294
+ function ke(e) {
1974
2295
  for (let t of [
1975
2296
  "USDT",
1976
2297
  "USD",
@@ -1980,7 +2301,7 @@ function H(e) {
1980
2301
  ]) if (e.length > t.length && e.endsWith(t)) return e.slice(0, -t.length) + "/" + t;
1981
2302
  return e;
1982
2303
  }
1983
- function U(e, t) {
2304
+ function Ae(e, t) {
1984
2305
  if (e === 0) return "0";
1985
2306
  let n = Math.abs(e);
1986
2307
  return n >= 1e3 ? e.toLocaleString(t, {
@@ -1991,7 +2312,7 @@ function U(e, t) {
1991
2312
  maximumFractionDigits: 4
1992
2313
  }) : Number(e.toPrecision(4)).toLocaleString(t, { maximumFractionDigits: 10 });
1993
2314
  }
1994
- function W(e, t, n) {
2315
+ function je(e, t, n) {
1995
2316
  let r = e.getContext("2d");
1996
2317
  if (!r) return;
1997
2318
  let i = window.devicePixelRatio || 1;
@@ -2009,7 +2330,7 @@ function W(e, t, n) {
2009
2330
  }
2010
2331
  //#endregion
2011
2332
  //#region src/widget/WidgetAlertsPanel.ts
2012
- var G = [
2333
+ var M = [
2013
2334
  {
2014
2335
  value: "crossing",
2015
2336
  label: "Crossing"
@@ -2030,15 +2351,15 @@ var G = [
2030
2351
  value: "lessThan",
2031
2352
  label: "Less than"
2032
2353
  }
2033
- ], K = new Map(G.map((e) => [e.value, e.label]));
2034
- function ce(e) {
2354
+ ], Me = new Map(M.map((e) => [e.value, e.label]));
2355
+ function Ne(e) {
2035
2356
  return Math.round(e * 1e6) / 1e6;
2036
2357
  }
2037
- function le(e) {
2358
+ function Pe(e) {
2038
2359
  let t = Math.abs(e);
2039
2360
  return t >= 1e3 || t >= 1 ? e.toFixed(2) : e.toPrecision(4);
2040
2361
  }
2041
- var ue = class {
2362
+ var Fe = class {
2042
2363
  el;
2043
2364
  listEl;
2044
2365
  priceInput;
@@ -2060,16 +2381,16 @@ var ue = class {
2060
2381
  let r = document.createElement("span");
2061
2382
  r.textContent = "Price Alerts";
2062
2383
  let i = document.createElement("button");
2063
- 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);
2064
2385
  let a = document.createElement("form");
2065
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";
2066
- for (let e of G) {
2387
+ for (let e of M) {
2067
2388
  let t = document.createElement("option");
2068
2389
  t.value = e.value, t.textContent = e.label, this.conditionSelect.appendChild(t);
2069
2390
  }
2070
2391
  this.messageInput = document.createElement("input"), this.messageInput.type = "text", this.messageInput.placeholder = "Note (optional)", this.messageInput.className = "tcw-alerts-message";
2071
2392
  let o = document.createElement("button");
2072
- 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) => {
2073
2394
  e.preventDefault(), this.submitForm();
2074
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);
2075
2396
  }
@@ -2099,7 +2420,7 @@ var ue = class {
2099
2420
  }
2100
2421
  prefillPrice() {
2101
2422
  let e = this.callbacks.getChannelValue(this.sourceSelect.value || "price");
2102
- this.priceInput.value = e === null ? "" : String(ce(e));
2423
+ this.priceInput.value = e === null ? "" : String(Ne(e));
2103
2424
  }
2104
2425
  close() {
2105
2426
  this.open = !1, this.el.hidden = !0;
@@ -2128,7 +2449,7 @@ var ue = class {
2128
2449
  n.className = "tcw-alerts-info";
2129
2450
  let r = document.createElement("div");
2130
2451
  r.className = "tcw-alerts-row-main";
2131
- 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);
2132
2453
  if (r.textContent = `${a && e.label ? `${e.label} ` : ""}${i} ${o}`, n.appendChild(r), e.message) {
2133
2454
  let t = document.createElement("div");
2134
2455
  t.className = "tcw-alerts-row-note", t.textContent = e.message, n.appendChild(t);
@@ -2138,10 +2459,10 @@ var ue = class {
2138
2459
  e.className = "tcw-alerts-badge", e.textContent = "triggered", r.appendChild(e);
2139
2460
  }
2140
2461
  let s = document.createElement("button");
2141
- 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);
2142
2463
  }
2143
2464
  }
2144
- }, de = class {
2465
+ }, Ie = class {
2145
2466
  el;
2146
2467
  indicatorsEl;
2147
2468
  drawingsEl;
@@ -2155,7 +2476,7 @@ var ue = class {
2155
2476
  let r = document.createElement("span");
2156
2477
  r.textContent = "Objects";
2157
2478
  let i = document.createElement("button");
2158
- 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);
2159
2480
  }
2160
2481
  isOpen() {
2161
2482
  return this.open;
@@ -2183,7 +2504,7 @@ var ue = class {
2183
2504
  let i = document.createElement("span");
2184
2505
  if (i.textContent = e, r.appendChild(i), t) {
2185
2506
  let n = document.createElement("button");
2186
- 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);
2187
2508
  }
2188
2509
  let a = document.createElement("div");
2189
2510
  return a.className = "tcw-tree-list", n.appendChild(r), n.appendChild(a), this.el.appendChild(n), a;
@@ -2236,9 +2557,9 @@ var ue = class {
2236
2557
  }
2237
2558
  iconButton(e, t, n, r) {
2238
2559
  let i = document.createElement("button");
2239
- 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;
2240
2561
  }
2241
- }, fe = {
2562
+ }, Le = {
2242
2563
  trendLine: "Trend Line",
2243
2564
  ray: "Ray",
2244
2565
  extendedLine: "Extended Line",
@@ -2281,16 +2602,16 @@ var ue = class {
2281
2602
  volumeProfileRange: "Volume Profile",
2282
2603
  riskReward: "Long/Short Position"
2283
2604
  };
2284
- function pe(e) {
2285
- return fe[e] ?? e;
2605
+ function Re(e) {
2606
+ return Le[e] ?? e;
2286
2607
  }
2287
2608
  //#endregion
2288
2609
  //#region src/widget/WidgetIndicatorSettings.ts
2289
- var me = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
2290
- function he(e) {
2610
+ var ze = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
2611
+ function Be(e) {
2291
2612
  return e.replace(/_/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (e) => e.toUpperCase());
2292
2613
  }
2293
- var ge = class {
2614
+ var Ve = class {
2294
2615
  backdrop;
2295
2616
  modal;
2296
2617
  bodyEl;
@@ -2305,7 +2626,7 @@ var ge = class {
2305
2626
  let n = document.createElement("div");
2306
2627
  n.className = "tcw-modal-header", this.titleEl = document.createElement("h3"), this.titleEl.textContent = "Indicator";
2307
2628
  let r = document.createElement("button");
2308
- 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";
2309
2630
  let i = document.createElement("div");
2310
2631
  i.className = "tcw-modal-footer";
2311
2632
  let a = document.createElement("button");
@@ -2355,9 +2676,9 @@ var ge = class {
2355
2676
  let t = document.createElement("div");
2356
2677
  t.className = "tcw-settings-row";
2357
2678
  let n = document.createElement("span");
2358
- 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);
2359
2680
  let r = this.currentValue(e), i = typeof (this.target?.defaults[e] ?? r);
2360
- 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;
2361
2682
  }
2362
2683
  toggleControl(e, t) {
2363
2684
  let n = document.createElement("button");
@@ -2375,27 +2696,27 @@ var ge = class {
2375
2696
  }
2376
2697
  colorControl(e, t) {
2377
2698
  let n = document.createElement("input");
2378
- 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;
2379
2700
  }
2380
2701
  textControl(e, t) {
2381
2702
  let n = document.createElement("input");
2382
2703
  return n.type = "text", n.className = "tcw-indi-input", n.value = t, n.addEventListener("change", () => this.setValue(e, n.value)), n;
2383
2704
  }
2384
2705
  };
2385
- function _e(e) {
2706
+ function He(e) {
2386
2707
  let t = e[1], n = e[2], r = e[3];
2387
2708
  return `#${t}${t}${n}${n}${r}${r}`;
2388
2709
  }
2389
2710
  //#endregion
2390
2711
  //#region src/widget/DrawingTemplateStore.ts
2391
- function ve() {
2712
+ function Ue() {
2392
2713
  try {
2393
2714
  return typeof localStorage < "u" ? localStorage : null;
2394
2715
  } catch {
2395
2716
  return null;
2396
2717
  }
2397
2718
  }
2398
- var ye = [
2719
+ var We = [
2399
2720
  "color",
2400
2721
  "lineWidth",
2401
2722
  "lineStyle",
@@ -2403,15 +2724,15 @@ var ye = [
2403
2724
  "fillOpacity",
2404
2725
  "fontSize"
2405
2726
  ];
2406
- function q(e) {
2727
+ function N(e) {
2407
2728
  if (!e || typeof e != "object") return {};
2408
2729
  let t = {}, n = e;
2409
- 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]);
2410
2731
  return t;
2411
2732
  }
2412
- var be = class {
2733
+ var Ge = class {
2413
2734
  templates = [];
2414
- constructor(e = "tcw:draw-templates", t = ve()) {
2735
+ constructor(e = "tcw:draw-templates", t = Ue()) {
2415
2736
  this.storageKey = e, this.storage = t, this.load();
2416
2737
  }
2417
2738
  list() {
@@ -2430,7 +2751,7 @@ var be = class {
2430
2751
  save(e, t) {
2431
2752
  let n = e.trim();
2432
2753
  if (!n) return;
2433
- let r = q(t);
2754
+ let r = N(t);
2434
2755
  this.templates = this.templates.filter((e) => e.name !== n), this.templates.push({
2435
2756
  name: n,
2436
2757
  style: r
@@ -2451,7 +2772,7 @@ var be = class {
2451
2772
  if (!Array.isArray(t)) return;
2452
2773
  this.templates = t.filter((e) => e && typeof e.name == "string").map((e) => ({
2453
2774
  name: e.name,
2454
- style: q(e.style)
2775
+ style: N(e.style)
2455
2776
  }));
2456
2777
  } catch {}
2457
2778
  }
@@ -2460,7 +2781,7 @@ var be = class {
2460
2781
  this.storage.setItem(this.storageKey, JSON.stringify(this.templates));
2461
2782
  } catch {}
2462
2783
  }
2463
- }, xe = [
2784
+ }, Ke = [
2464
2785
  "#4c8dff",
2465
2786
  "#1fa874",
2466
2787
  "#e8505b",
@@ -2469,16 +2790,16 @@ var be = class {
2469
2790
  "#1398a8",
2470
2791
  "#ffffff",
2471
2792
  "#7d8696"
2472
- ], Se = [
2793
+ ], qe = [
2473
2794
  1,
2474
2795
  2,
2475
2796
  3,
2476
2797
  4
2477
- ], Ce = [
2798
+ ], Je = [
2478
2799
  "solid",
2479
2800
  "dashed",
2480
2801
  "dotted"
2481
- ], we = class {
2802
+ ], Ye = class {
2482
2803
  el;
2483
2804
  templatesEl;
2484
2805
  nameInput;
@@ -2492,13 +2813,13 @@ var be = class {
2492
2813
  let i = document.createElement("span");
2493
2814
  i.textContent = "Drawing Style";
2494
2815
  let a = document.createElement("button");
2495
- 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());
2496
2817
  let o = document.createElement("div");
2497
2818
  o.className = "tcw-style-subhead", o.textContent = "Templates", this.el.appendChild(o);
2498
2819
  let s = document.createElement("div");
2499
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";
2500
2821
  let c = document.createElement("button");
2501
- 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();
2502
2823
  }
2503
2824
  isOpen() {
2504
2825
  return this.open;
@@ -2518,7 +2839,7 @@ var be = class {
2518
2839
  colorRow() {
2519
2840
  let e = document.createElement("div");
2520
2841
  e.className = "tcw-style-row tcw-style-colors";
2521
- for (let t of xe) {
2842
+ for (let t of Ke) {
2522
2843
  let n = document.createElement("button");
2523
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);
2524
2845
  }
@@ -2528,7 +2849,7 @@ var be = class {
2528
2849
  widthRow() {
2529
2850
  let e = document.createElement("div");
2530
2851
  e.className = "tcw-style-row tcw-style-widths";
2531
- for (let t of Se) {
2852
+ for (let t of qe) {
2532
2853
  let n = document.createElement("button");
2533
2854
  n.type = "button", n.className = "tcw-style-width", n.dataset.width = String(t);
2534
2855
  let r = document.createElement("span");
@@ -2539,7 +2860,7 @@ var be = class {
2539
2860
  lineStyleRow() {
2540
2861
  let e = document.createElement("div");
2541
2862
  e.className = "tcw-style-row tcw-style-dashes";
2542
- for (let t of Ce) {
2863
+ for (let t of Je) {
2543
2864
  let n = document.createElement("button");
2544
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);
2545
2866
  }
@@ -2582,7 +2903,7 @@ var be = class {
2582
2903
  this.callbacks.onStyleChange({ ...t.style }), this.syncActiveControls();
2583
2904
  });
2584
2905
  let a = document.createElement("button");
2585
- 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", () => {
2586
2907
  this.store.remove(t.name), this.renderTemplates();
2587
2908
  }), e.appendChild(n), e.appendChild(a), this.templatesEl.appendChild(e);
2588
2909
  }
@@ -2590,16 +2911,16 @@ var be = class {
2590
2911
  };
2591
2912
  //#endregion
2592
2913
  //#region src/widget/DrawingFavoritesStore.ts
2593
- function Te() {
2914
+ function Xe() {
2594
2915
  try {
2595
2916
  return typeof localStorage < "u" ? localStorage : null;
2596
2917
  } catch {
2597
2918
  return null;
2598
2919
  }
2599
2920
  }
2600
- var Ee = class {
2921
+ var P = class {
2601
2922
  favorites = [];
2602
- constructor(e = "tcw:draw-favorites", t = Te()) {
2923
+ constructor(e = "tcw:draw-favorites", t = Xe()) {
2603
2924
  this.storageKey = e, this.storage = t, this.load();
2604
2925
  }
2605
2926
  list() {
@@ -2633,7 +2954,397 @@ var Ee = class {
2633
2954
  this.storage.setItem(this.storageKey, JSON.stringify(this.favorites));
2634
2955
  } catch {}
2635
2956
  }
2636
- }, 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 {
2637
3348
  el;
2638
3349
  labelEl;
2639
3350
  callbacks;
@@ -2643,9 +3354,9 @@ var Ee = class {
2643
3354
  let n = document.createElement("span");
2644
3355
  n.className = "tcw-bracket-hint", n.textContent = "drag lines to adjust", this.el.appendChild(n);
2645
3356
  let r = document.createElement("button");
2646
- 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());
2647
3358
  let i = document.createElement("button");
2648
- 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);
2649
3360
  }
2650
3361
  show(e) {
2651
3362
  this.visible = !0, this.labelEl.textContent = e === "buy" ? "Long bracket" : "Short bracket", this.labelEl.dataset.side = e, this.el.hidden = !1;
@@ -2659,7 +3370,7 @@ var Ee = class {
2659
3370
  destroy() {
2660
3371
  this.el.remove();
2661
3372
  }
2662
- }, Oe = class {
3373
+ }, St = class {
2663
3374
  options;
2664
3375
  audioCtx = null;
2665
3376
  audioEl = null;
@@ -2722,7 +3433,7 @@ var Ee = class {
2722
3433
  };
2723
3434
  //#endregion
2724
3435
  //#region src/widget/ladderRows.ts
2725
- function ke(e, t = 12) {
3436
+ function Ct(e, t = 12) {
2726
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) => {
2727
3438
  let t = s.get(e);
2728
3439
  return t || (t = {
@@ -2743,7 +3454,7 @@ function ke(e, t = 12) {
2743
3454
  }
2744
3455
  //#endregion
2745
3456
  //#region src/widget/WidgetDepthLadder.ts
2746
- var Ae = class {
3457
+ var wt = class {
2747
3458
  el;
2748
3459
  bodyEl;
2749
3460
  callbacks;
@@ -2756,7 +3467,7 @@ var Ae = class {
2756
3467
  let i = document.createElement("span");
2757
3468
  i.textContent = "Depth Ladder";
2758
3469
  let a = document.createElement("button");
2759
- 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);
2760
3471
  let o = document.createElement("div");
2761
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);
2762
3473
  }
@@ -2777,7 +3488,7 @@ var Ae = class {
2777
3488
  this.renderEmpty();
2778
3489
  return;
2779
3490
  }
2780
- this.render(ke(e, this.levels));
3491
+ this.render(Ct(e, this.levels));
2781
3492
  }
2782
3493
  destroy() {
2783
3494
  this.el.remove();
@@ -2797,20 +3508,20 @@ var Ae = class {
2797
3508
  let e = n.askVolume > 0, r = document.createElement("div");
2798
3509
  r.className = "tcw-ladder-row";
2799
3510
  let i = document.createElement("button");
2800
- 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;
2801
3512
  let a = document.createElement("div");
2802
3513
  a.className = `tcw-ladder-price ${e ? "tcw-ask" : "tcw-bid"}`, a.textContent = this.callbacks.formatPrice(n.price);
2803
3514
  let o = document.createElement("button");
2804
- 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);
2805
3516
  }
2806
3517
  }
2807
3518
  };
2808
- function J(e) {
3519
+ function K(e) {
2809
3520
  return e >= 1e3 ? (e / 1e3).toFixed(1) + "k" : e >= 1 ? e.toFixed(2).replace(/\.00$/, "") : e.toPrecision(2);
2810
3521
  }
2811
3522
  //#endregion
2812
3523
  //#region src/widget/WidgetDataWindow.ts
2813
- var je = class {
3524
+ var Tt = class {
2814
3525
  el;
2815
3526
  bodyEl;
2816
3527
  callbacks;
@@ -2822,7 +3533,7 @@ var je = class {
2822
3533
  let r = document.createElement("span");
2823
3534
  r.textContent = "Data Window";
2824
3535
  let i = document.createElement("button");
2825
- 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);
2826
3537
  }
2827
3538
  isOpen() {
2828
3539
  return this.open;
@@ -2849,11 +3560,11 @@ var je = class {
2849
3560
  let t = this.callbacks.formatPrice, n = e.ohlc;
2850
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)));
2851
3562
  let r = e.change > 0 ? "up" : e.change < 0 ? "down" : "", i = e.change > 0 ? "+" : "";
2852
- 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)));
2853
3564
  for (let t of e.indicators) {
2854
3565
  let e = document.createElement("div");
2855
3566
  e.className = "tcw-datawin-sub", e.textContent = t.name, this.bodyEl.appendChild(e);
2856
- 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)));
2857
3568
  }
2858
3569
  }
2859
3570
  row(e, t, n = "") {
@@ -2865,43 +3576,43 @@ var je = class {
2865
3576
  return a.className = `tcw-datawin-value${n ? ` tcw-${n}` : ""}`, a.textContent = t, r.appendChild(i), r.appendChild(a), r;
2866
3577
  }
2867
3578
  };
2868
- function Me(e) {
3579
+ function Et(e) {
2869
3580
  if (!Number.isFinite(e)) return "—";
2870
3581
  let t = Math.abs(e);
2871
3582
  return t >= 1e3 ? e.toFixed(2) : t >= 1 ? e.toFixed(4) : e.toPrecision(4);
2872
3583
  }
2873
- function Ne(e) {
3584
+ function Dt(e) {
2874
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);
2875
3586
  }
2876
3587
  //#endregion
2877
3588
  //#region src/widget/widgetShareState.ts
2878
- var Y = globalThis.Buffer;
2879
- function Pe(e) {
2880
- 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");
2881
3592
  let t = new TextEncoder().encode(e), n = "";
2882
3593
  for (let e of t) n += String.fromCharCode(e);
2883
3594
  return btoa(n);
2884
3595
  }
2885
- function Fe(e) {
2886
- if (Y) return Y.from(e, "base64").toString("utf8");
3596
+ function kt(e) {
3597
+ if (q) return q.from(e, "base64").toString("utf8");
2887
3598
  let t = atob(e), n = new Uint8Array(t.length);
2888
3599
  for (let e = 0; e < t.length; e++) n[e] = t.charCodeAt(e);
2889
3600
  return new TextDecoder().decode(n);
2890
3601
  }
2891
- function Ie(e) {
3602
+ function At(e) {
2892
3603
  return e.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2893
3604
  }
2894
- function Le(e) {
3605
+ function jt(e) {
2895
3606
  let t = e.replace(/-/g, "+").replace(/_/g, "/");
2896
3607
  return t + (t.length % 4 == 0 ? "" : "=".repeat(4 - t.length % 4));
2897
3608
  }
2898
- function Re(e) {
2899
- return Ie(Pe(JSON.stringify(e)));
3609
+ function Mt(e) {
3610
+ return At(Ot(JSON.stringify(e)));
2900
3611
  }
2901
- function ze(e) {
3612
+ function Nt(e) {
2902
3613
  if (!e) return null;
2903
3614
  try {
2904
- let t = Fe(Le(e)), n = JSON.parse(t);
3615
+ let t = kt(jt(e)), n = JSON.parse(t);
2905
3616
  return !n || n.v !== 1 || typeof n.symbol != "string" ? null : {
2906
3617
  v: 1,
2907
3618
  symbol: n.symbol,
@@ -2915,28 +3626,36 @@ function ze(e) {
2915
3626
  return null;
2916
3627
  }
2917
3628
  }
2918
- var X = "tcw";
2919
- function Be(e) {
3629
+ var J = "tcw";
3630
+ function Pt(e) {
2920
3631
  let t = e.startsWith("#") ? e.slice(1) : e;
2921
3632
  for (let e of t.split("&")) {
2922
3633
  let t = e.indexOf("=");
2923
- 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));
2924
3635
  }
2925
3636
  return null;
2926
3637
  }
2927
- function Ve(e, t) {
3638
+ function Ft(e, t) {
2928
3639
  let [n] = e.split("#");
2929
- return `${n}#${X}=${t}`;
3640
+ return `${n}#${J}=${t}`;
2930
3641
  }
2931
3642
  //#endregion
2932
3643
  //#region src/widget/i18n.ts
2933
- var Z = {
3644
+ var Y = {
2934
3645
  "toolbar.indicators": "Indicators",
2935
3646
  "toolbar.indicators.popular": "Popular",
2936
3647
  "toolbar.indicators.all": "All",
2937
3648
  "indicatorType.overlay": "overlay",
2938
3649
  "indicatorType.panel": "panel",
2939
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+→)",
2940
3659
  "toolbar.longBracket": "Long bracket",
2941
3660
  "toolbar.shortBracket": "Short bracket",
2942
3661
  "toolbar.depthLadder": "Depth ladder",
@@ -2945,6 +3664,24 @@ var Z = {
2945
3664
  "toolbar.screenshot": "Screenshot",
2946
3665
  "toolbar.settings": "Chart Settings",
2947
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",
2948
3685
  "chartType.candlestick": "Candlestick",
2949
3686
  "chartType.line": "Line",
2950
3687
  "chartType.area": "Area",
@@ -2978,8 +3715,8 @@ var Z = {
2978
3715
  "hotkeys.group.touch": "Touch (mobile / tablet)",
2979
3716
  "hotkeys.group.keyboard": "Keyboard",
2980
3717
  "hotkeys.group.drawing": "Drawing"
2981
- }, He = {
2982
- en: Z,
3718
+ }, It = {
3719
+ en: Y,
2983
3720
  vi: {
2984
3721
  "toolbar.indicators": "Chỉ báo",
2985
3722
  "toolbar.indicators.popular": "Phổ biến",
@@ -2987,6 +3724,14 @@ var Z = {
2987
3724
  "indicatorType.overlay": "phủ lên",
2988
3725
  "indicatorType.panel": "bảng riêng",
2989
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+→)",
2990
3735
  "toolbar.longBracket": "Lệnh Long",
2991
3736
  "toolbar.shortBracket": "Lệnh Short",
2992
3737
  "toolbar.depthLadder": "Sổ lệnh",
@@ -2995,6 +3740,24 @@ var Z = {
2995
3740
  "toolbar.screenshot": "Chụp màn hình",
2996
3741
  "toolbar.settings": "Cài đặt biểu đồ",
2997
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",
2998
3761
  "chartType.candlestick": "Nến",
2999
3762
  "chartType.line": "Đường",
3000
3763
  "chartType.area": "Vùng",
@@ -3030,14 +3793,14 @@ var Z = {
3030
3793
  "hotkeys.group.drawing": "Vẽ"
3031
3794
  }
3032
3795
  };
3033
- function Q(e, t) {
3034
- let n = { ...Z }, r = e ? He[e] : void 0;
3796
+ function Lt(e, t) {
3797
+ let n = { ...Y }, r = e ? It[e] : void 0;
3035
3798
  return r && Object.assign(n, r), t && Object.assign(n, t), n;
3036
3799
  }
3037
- function Ue(e) {
3038
- return (t) => e[t] ?? Z[t] ?? t;
3800
+ function Rt(e) {
3801
+ return (t) => e[t] ?? Y[t] ?? t;
3039
3802
  }
3040
- var We = [
3803
+ var zt = [
3041
3804
  [
3042
3805
  34,
3043
3806
  16,
@@ -3094,7 +3857,7 @@ var We = [
3094
3857
  30,
3095
3858
  !0
3096
3859
  ]
3097
- ], Ge = class {
3860
+ ], Bt = class {
3098
3861
  el;
3099
3862
  label;
3100
3863
  showTimer = null;
@@ -3104,9 +3867,9 @@ var We = [
3104
3867
  let n = document.createElement("div");
3105
3868
  n.className = "tcw-loading-card";
3106
3869
  let r = document.createElement("div");
3107
- r.className = "tcw-loading-candles", r.setAttribute("aria-hidden", "true"), We.forEach(([e, t, n, i, a], o) => {
3870
+ r.className = "tcw-loading-candles", r.setAttribute("aria-hidden", "true"), zt.forEach(([e, t, n, i, a], o) => {
3108
3871
  let s = document.createElement("span");
3109
- 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.animationDelay = `${o * 110}ms`, r.appendChild(s);
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);
3110
3873
  }), n.appendChild(r);
3111
3874
  let i = document.createElement("div");
3112
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);
@@ -3141,33 +3904,51 @@ var We = [
3141
3904
  clearTimer() {
3142
3905
  this.showTimer !== null && (clearTimeout(this.showTimer), this.showTimer = null);
3143
3906
  }
3144
- }, Ke = 48, qe = 5e4, Je = 100;
3145
- function Ye() {
3907
+ }, Vt = 48, Ht = 5e4, Ut = 100;
3908
+ function Wt() {
3146
3909
  return new Promise((e) => {
3147
3910
  if (typeof requestAnimationFrame != "function" || document.hidden) {
3148
3911
  setTimeout(e, 0);
3149
3912
  return;
3150
3913
  }
3151
- let t = setTimeout(e, Je);
3914
+ let t = setTimeout(e, Ut);
3152
3915
  requestAnimationFrame(() => setTimeout(() => {
3153
3916
  clearTimeout(t), e();
3154
3917
  }, 0));
3155
3918
  });
3156
3919
  }
3157
- var $ = [
3920
+ var X = [
3158
3921
  "#4c8dff",
3159
3922
  "#a57cff",
3160
3923
  "#1398a8",
3161
3924
  "#e25592",
3162
3925
  "#8a93a3",
3163
3926
  "#62c895"
3164
- ], Xe = class {
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 {
3165
3931
  chart;
3166
3932
  state;
3167
3933
  toolbar = null;
3168
3934
  sidebar = null;
3169
3935
  settings = null;
3170
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
+ };
3171
3952
  commandPalette = null;
3172
3953
  symbolSearch = null;
3173
3954
  hotkeySheet = null;
@@ -3182,15 +3963,18 @@ var $ = [
3182
3963
  depthLadder = null;
3183
3964
  dataWindow = null;
3184
3965
  lastHoverIndex = null;
3185
- favoritesStore = new Ee();
3966
+ legendHoverIndex = null;
3967
+ favoritesStore = new P();
3968
+ timeframeFavorites = new P("tcw:tf-favorites");
3969
+ timeframes = [];
3186
3970
  watchlist = null;
3187
3971
  watchlistSparkBuffer = /* @__PURE__ */ new Map();
3188
3972
  sessionRefPrice = null;
3189
3973
  hostWatchlistRefPrice = /* @__PURE__ */ new Map();
3190
3974
  watchlistInterval = null;
3191
- replayOriginalData = null;
3192
3975
  replayPollInterval = null;
3193
3976
  replaySpeed = 5;
3977
+ replayShade = null;
3194
3978
  layoutKeyPrefix = null;
3195
3979
  layoutDebounceMs = 1500;
3196
3980
  activeLayoutKey = null;
@@ -3211,36 +3995,64 @@ var $ = [
3211
3995
  baseTimeframeMs = 0;
3212
3996
  compares = [];
3213
3997
  constructor(n, r = {}) {
3214
- if (this.options = r, this.symbols = r.symbols ?? ee, this.settingsState = {
3998
+ if (this.options = r, this.symbols = r.symbols ?? te, this.settingsState = {
3215
3999
  ...p,
3216
4000
  ...r.chartOptions?.numberLocale ? { numberLocale: r.chartOptions.numberLocale } : {}
3217
- }, this.t = Ue(Q(r.locale, r.messages)), r.persistLayouts) {
4001
+ }, this.t = Rt(Lt(r.locale, r.messages)), r.persistLayouts) {
3218
4002
  let e = r.persistLayouts === !0 ? {} : r.persistLayouts;
3219
4003
  this.layoutKeyPrefix = e.keyPrefix ?? "tcw:layout:", this.layoutDebounceMs = e.debounceMs ?? 1500;
3220
4004
  }
3221
- 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;
3222
4029
  this.state = {
3223
4030
  symbol: r.symbol ?? this.symbols[0] ?? "BTCUSDT",
3224
- timeframe: r.timeframe ?? "5m",
4031
+ timeframe: l,
3225
4032
  chartType: r.chartOptions?.chartType ?? "candlestick",
3226
4033
  isDark: i,
3227
4034
  activeIndicators: /* @__PURE__ */ new Map(),
3228
4035
  activeTool: null,
3229
- magnetEnabled: !0,
4036
+ magnetEnabled: o.drawingMagnet !== !1,
4037
+ stayInDrawing: !1,
3230
4038
  connectionState: r.adapter ? "connecting" : "disconnected",
3231
4039
  connectionMessage: r.adapter ? this.t("status.connecting") : ""
3232
- }, 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, {
3233
4041
  symbols: this.symbols,
3234
- timeframes: r.timeframes ? c.filter((e) => r.timeframes.includes(e.value)) : c,
3235
- chartTypes: r.chartTypes ? l.filter((e) => r.chartTypes.includes(e.value)) : l,
3236
- indicators: d,
3237
- 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
3238
4050
  }, {
3239
4051
  onSymbolClick: () => this.handleSymbolClick(),
3240
4052
  onTimeframe: (e) => this.handleTimeframe(e),
4053
+ onToggleTimeframeFavorite: (e) => this.handleToggleTimeframeFavorite(e),
3241
4054
  onChartType: (e) => this.handleChartType(e),
3242
4055
  onAddIndicator: (e) => this.handleAddIndicator(e),
3243
- onRemoveIndicator: (e) => this.handleRemoveIndicator(e),
3244
4056
  onScreenshot: () => this.chart.screenshot(),
3245
4057
  onSettings: () => this.openSettings(),
3246
4058
  onToggleTheme: () => this.handleToggleTheme(),
@@ -3248,16 +4060,17 @@ var $ = [
3248
4060
  onToggleAlerts: r.alerts === !1 ? void 0 : () => this.toggleAlerts(),
3249
4061
  onToggleObjects: r.objectTree === !1 ? void 0 : () => this.toggleObjects(),
3250
4062
  onBracket: r.trading === !1 ? void 0 : (e) => this.startBracket(e),
3251
- 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
3252
4065
  }, this.t));
3253
- let o = document.createElement("div");
3254
- if (o.className = "tcw-body", r.drawingTools !== !1 && (r.drawingFavorites && this.favoritesStore.seedDefaults(r.drawingFavorites), this.sidebar = new se(o, {
3255
- 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,
3256
4069
  favorites: this.favoritesStore.list()
3257
4070
  }, {
3258
4071
  onDrawingTool: (e) => this.handleDrawingTool(e),
3259
4072
  onCancelDrawing: () => this.handleCancelDrawing(),
3260
- onToggleMagnet: () => this.handleToggleMagnet(),
4073
+ onToggleMagnet: o.drawingMagnet === !1 ? void 0 : () => this.handleToggleMagnet(),
3261
4074
  onToggleFavorite: (e) => this.handleToggleFavorite(e),
3262
4075
  onUndo: () => this.chart.undo(),
3263
4076
  onRedo: () => this.chart.redo(),
@@ -3267,34 +4080,17 @@ var $ = [
3267
4080
  activeTool: null
3268
4081
  }, this.updateUI();
3269
4082
  },
3270
- onToggleStyle: () => this.drawingStyle?.toggle()
3271
- })), 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) => {
3272
4086
  this.setSymbol(e);
3273
- } }, 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, {
3274
4088
  chartType: this.state.chartType,
3275
4089
  theme: a,
3276
4090
  autoScale: !0,
3277
4091
  crosshair: { mode: "magnet" },
3278
4092
  ...r.chartOptions,
3279
- features: {
3280
- drawings: !0,
3281
- drawingMagnet: !0,
3282
- drawingUndoRedo: !0,
3283
- indicators: !0,
3284
- trading: r.trading !== !1,
3285
- tradingContextMenu: !1,
3286
- volume: !0,
3287
- legend: !0,
3288
- crosshair: !0,
3289
- crosshairTooltip: !1,
3290
- keyboard: !0,
3291
- screenshot: !0,
3292
- alerts: !0,
3293
- barCountdown: !0,
3294
- logScale: !0,
3295
- watermark: !0,
3296
- ...r.chartOptions?.features
3297
- }
4093
+ features: o
3298
4094
  }), this.chart.on("dataUpdate", (e) => this.handleDataUpdate(e.payload)), r.dragDropImport !== !1 && (this.dragDrop = new t(this.chartContainer, {
3299
4095
  onData: (e, t, n) => {
3300
4096
  this.setData(e), this.toast(`Loaded ${t.data.length} bars from ${n.name}` + (t.skipped > 0 ? ` (${t.skipped} skipped)` : ""));
@@ -3302,28 +4098,92 @@ var $ = [
3302
4098
  onError: (e, t) => {
3303
4099
  this.toast(`${t.name}: ${e.message}`, "error");
3304
4100
  }
3305
- }), 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({
3306
4119
  onChange: (e) => this.applySettings(e),
3307
4120
  onReset: () => this.resetSettings(),
3308
4121
  onClose: () => {}
3309
- }, this.t)), this.symbolSearch = new T({
4122
+ }, this.t, {
4123
+ barCountdown: o.barCountdown,
4124
+ logScale: o.logScale
4125
+ }, this.overlayHost)), this.symbolSearch = new me({
3310
4126
  onPick: (e) => {
3311
4127
  this.setSymbol(e);
3312
4128
  },
3313
4129
  onClose: () => {}
3314
- }), 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) => {
3315
4165
  if (!this.replayBar?.isMounted()) return;
3316
4166
  let t = e.payload.barIndex;
3317
- typeof t == "number" && (this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(t), this.replayBar.setState("paused"));
3318
- }), 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) => {
3319
4179
  let t = e.payload;
3320
4180
  this.lastHoverIndex = typeof t.barIndex == "number" ? t.barIndex : null, this.dataWindow?.isOpen() && this.dataWindow.render(this.buildDataWindowModel());
3321
- }), r.drawingTools !== !1 && (this.drawingStyle = new we(this.root, {
4181
+ }), r.drawingTools !== !1 && (this.drawingStyle = new Ye(this.root, {
3322
4182
  onStyleChange: (e) => {
3323
4183
  this.chart.setDrawingStyle(e), this.chart.setSelectedDrawingStyle(e);
3324
4184
  },
3325
4185
  getStyle: () => this.chart.getDrawingStyle()
3326
- }, new be())), r.trading !== !1 && (this.bracketBar = new De(this.root, {
4186
+ }, new Ge())), r.trading !== !1 && (this.bracketBar = new xt(this.root, {
3327
4187
  onConfirm: () => this.chart.confirmBracket(),
3328
4188
  onCancel: () => {
3329
4189
  this.chart.cancelBracket(), this.bracketBar?.hide();
@@ -3331,7 +4191,7 @@ var $ = [
3331
4191
  }), this.chart.on("bracketPlace", (e) => {
3332
4192
  let t = e.payload;
3333
4193
  this.bracketBar?.hide(), this.toast(`${t.side === "buy" ? "Long" : "Short"} bracket placed · ${t.riskReward.toFixed(2)}R`);
3334
- }), r.depthLadder && (this.depthLadder = new Ae(this.root, {
4194
+ }), r.depthLadder && (this.depthLadder = new wt(this.root, {
3335
4195
  onTrade: (e, t) => {
3336
4196
  this.chart.placeOrderIntent({
3337
4197
  side: e,
@@ -3343,7 +4203,7 @@ var $ = [
3343
4203
  })), this.chart.on("dataUpdate", (e) => {
3344
4204
  let t = e.payload;
3345
4205
  t && t.bracket === "cancelled" && this.bracketBar?.hide();
3346
- })), r.alerts !== !1 && (this.alertsPanel = new ue(this.root, {
4206
+ })), r.alerts !== !1 && (this.alertsPanel = new Fe(this.root, {
3347
4207
  onAdd: (e, t, n, r, i) => {
3348
4208
  this.chart.addAlert(e, t, n, r, i);
3349
4209
  },
@@ -3351,18 +4211,20 @@ var $ = [
3351
4211
  onClear: () => this.chart.clearAlerts(),
3352
4212
  getChannelValue: (e) => this.getAlertChannelValue(e),
3353
4213
  formatPrice: (e) => this.formatAlertPrice(e)
3354
- }), 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) => {
3355
4215
  let t = e.payload, n = `Price ${this.formatAlertPrice(t.price)}${t.message ? ` — ${t.message}` : ""}`;
3356
4216
  this.toast(`🔔 Alert: ${n}`, "info"), this.alertNotifier?.notify(n), this.refreshAlerts();
3357
4217
  })), r.objectTree !== !1) {
3358
- this.indicatorSettings = new ge(this.root, {
3359
- 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
+ },
3360
4222
  onClose: () => {}
3361
- }), this.objectTree = new de(this.root, {
4223
+ }), this.objectTree = new Ie(this.root, {
3362
4224
  onRemoveIndicator: (e) => this.handleRemoveIndicator(e),
3363
4225
  onConfigureIndicator: (e) => this.openIndicatorSettings(e),
3364
4226
  onToggleIndicatorVisible: (e, t) => {
3365
- this.chart.setIndicatorVisible(e, t), this.refreshObjects();
4227
+ this.chart.setIndicatorVisible(e, t), this.refreshObjects(), this.scheduleLegend();
3366
4228
  },
3367
4229
  onRemoveDrawing: (e) => {
3368
4230
  this.chart.removeDrawing(e), this.refreshObjects();
@@ -3373,7 +4235,7 @@ var $ = [
3373
4235
  onToggleDrawingLocked: (e, t) => {
3374
4236
  this.chart.setDrawingLocked(e, t), this.refreshObjects();
3375
4237
  },
3376
- onAddCompare: () => this.handleAddCompare(),
4238
+ onAddCompare: o.compareSymbols === !1 ? void 0 : () => this.handleAddCompare(),
3377
4239
  onRemoveCompare: (e) => this.handleRemoveCompare(e)
3378
4240
  });
3379
4241
  let e = () => {
@@ -3381,23 +4243,28 @@ var $ = [
3381
4243
  };
3382
4244
  this.chart.on("drawingCreate", e), this.chart.on("drawingRemove", e), this.chart.on("indicatorAdd", e), this.chart.on("indicatorRemove", e);
3383
4245
  }
3384
- if (this.commandPalette = new w({
4246
+ if (this.commandPalette = new pe({
3385
4247
  onIndicator: (e) => this.handleAddIndicator(e),
3386
4248
  onChartType: (e) => this.handleChartType(e),
3387
4249
  onDrawingTool: (e) => this.handleDrawingTool(e),
3388
4250
  onTimeframe: (e) => this.handleTimeframe(e),
3389
4251
  onAction: (e) => this.handleAction(e),
3390
4252
  onClose: () => {}
3391
- }), this.boundGlobalKeydown = (e) => {
3392
- if ((e.ctrlKey || e.metaKey) && e.key === "k") e.preventDefault(), this.toggleCommandPalette();
3393
- else if ((e.ctrlKey || e.metaKey) && (e.key === "p" || e.key === "P")) e.preventDefault(), this.symbolSearch?.open(this.symbols, this.state.symbol);
3394
- else if (e.key === "?" && !e.ctrlKey && !e.metaKey && !e.altKey) {
3395
- let t = document.activeElement;
3396
- if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) return;
3397
- 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
+ }
3398
4265
  }
3399
- }, 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") {
3400
- 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);
3401
4268
  e && this.importState(e);
3402
4269
  }
3403
4270
  }
@@ -3427,19 +4294,21 @@ var $ = [
3427
4294
  });
3428
4295
  }
3429
4296
  async setTimeframe(e) {
3430
- if (this.state = {
3431
- ...this.state,
3432
- timeframe: e
3433
- }, this.options.onTimeframeChange?.(e), this.updateUI(), this.adapter) {
3434
- await this.connectStream();
3435
- return;
3436
- }
3437
- if (this.options.resampleTimeframes !== !1) {
3438
- if (!this.baseSeries) {
3439
- let e = this.chart.getData();
3440
- 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();
3441
4311
  }
3442
- await this.switchLocalTimeframe();
3443
4312
  }
3444
4313
  }
3445
4314
  setTheme(e) {
@@ -3447,13 +4316,13 @@ var $ = [
3447
4316
  this.state = {
3448
4317
  ...this.state,
3449
4318
  isDark: t
3450
- }, 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();
3451
4320
  }
3452
4321
  getChart() {
3453
4322
  return this.chart;
3454
4323
  }
3455
4324
  destroy() {
3456
- 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());
3457
4326
  }
3458
4327
  handleSymbolClick() {
3459
4328
  this.symbolSearch?.open(this.symbols, this.state.symbol);
@@ -3461,14 +4330,49 @@ var $ = [
3461
4330
  handleTimeframe(e) {
3462
4331
  this.setTimeframe(e);
3463
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
+ }
3464
4368
  setData(e) {
3465
- 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();
3466
4370
  }
3467
4371
  async switchLocalTimeframe() {
3468
4372
  if (!this.baseSeries) return;
3469
- 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;
3470
4374
  try {
3471
- 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;
3472
4376
  this.applyTimeframeData();
3473
4377
  } finally {
3474
4378
  e === this.localSeq && this.loading.end();
@@ -3476,10 +4380,10 @@ var $ = [
3476
4380
  }
3477
4381
  applyTimeframeData() {
3478
4382
  if (!this.baseSeries) return;
3479
- let e = performance.now(), t = a(this.state.timeframe);
4383
+ let e = performance.now(), t = o(this.state.timeframe);
3480
4384
  if (this.baseTimeframeMs > 0 && t > this.baseTimeframeMs) {
3481
4385
  let e = this.options.weekStartsOn ?? 1;
3482
- this.chart.setData(o(this.baseSeries, this.state.timeframe, { weekStartsOn: e }));
4386
+ this.chart.setData(c(this.baseSeries, this.state.timeframe, { weekStartsOn: e }));
3483
4387
  } else this.chart.setData(this.baseSeries);
3484
4388
  this.lastLocalSwitchMs = performance.now() - e;
3485
4389
  }
@@ -3525,7 +4429,7 @@ var $ = [
3525
4429
  id: e.id,
3526
4430
  params: e.params
3527
4431
  }));
3528
- return Re({
4432
+ return Mt({
3529
4433
  v: 1,
3530
4434
  symbol: this.state.symbol,
3531
4435
  timeframe: this.state.timeframe,
@@ -3536,26 +4440,19 @@ var $ = [
3536
4440
  });
3537
4441
  }
3538
4442
  async importState(e) {
3539
- let t = ze(e);
4443
+ let t = Nt(e);
3540
4444
  if (!t) return !1;
3541
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);
3542
- for (let [, e] of this.state.activeIndicators) this.chart.removeIndicator(e);
3543
- let n = /* @__PURE__ */ new Map();
3544
- for (let e of t.indicators) {
3545
- let t = this.chart.addIndicator(e.id, e.params);
3546
- t && n.set(e.id, t);
3547
- }
3548
- return this.state = {
3549
- ...this.state,
3550
- activeIndicators: n
3551
- }, 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;
3552
4449
  }
3553
4450
  async copyChartImage() {
3554
4451
  let e = await this.chart.copyScreenshot();
3555
4452
  this.toast(e ? "Chart image copied" : "Copy failed — image clipboard unavailable", e ? "info" : "error");
3556
4453
  }
3557
4454
  async copyShareLink() {
3558
- let e = Ve(typeof location < "u" ? location.href : "", this.exportState());
4455
+ let e = Ft(typeof location < "u" ? location.href : "", this.exportState());
3559
4456
  try {
3560
4457
  await navigator.clipboard.writeText(e), this.toast("Share link copied");
3561
4458
  } catch {
@@ -3623,7 +4520,7 @@ var $ = [
3623
4520
  visible: e.visible
3624
4521
  })), t = this.chart.getDrawings().map((e) => ({
3625
4522
  id: e.id,
3626
- label: pe(e.type),
4523
+ label: Re(e.type),
3627
4524
  visible: e.visible,
3628
4525
  locked: e.locked
3629
4526
  })), n = this.compares.map((e) => ({
@@ -3645,7 +4542,7 @@ var $ = [
3645
4542
  }
3646
4543
  async addCompareSymbol(e) {
3647
4544
  if (!this.adapter || this.compares.some((t) => t.symbol === e)) return;
3648
- let t = $[this.compares.length % $.length], n = `cmp_${e}`;
4545
+ let t = X[this.compares.length % X.length], n = `cmp_${e}`;
3649
4546
  try {
3650
4547
  let r = await this.adapter.fetchHistory(e, this.state.timeframe, this.options.historyLimit ?? 500);
3651
4548
  this.compares.length === 0 && this.chart.setCompareMode("percent"), this.chart.addCompareSymbol(n, e, r, t), this.compares = [...this.compares, {
@@ -3719,37 +4616,10 @@ var $ = [
3719
4616
  }, this.chart.setChartType(e), this.updateUI();
3720
4617
  }
3721
4618
  handleAddIndicator(e) {
3722
- if (this.state.activeIndicators.has(e)) {
3723
- let t = this.state.activeIndicators.get(e);
3724
- this.chart.removeIndicator(t);
3725
- let n = new Map(this.state.activeIndicators);
3726
- n.delete(e), this.state = {
3727
- ...this.state,
3728
- activeIndicators: n
3729
- };
3730
- } else {
3731
- let t = this.chart.addIndicator(e);
3732
- if (t) {
3733
- let n = new Map(this.state.activeIndicators);
3734
- n.set(e, t), this.state = {
3735
- ...this.state,
3736
- activeIndicators: n
3737
- };
3738
- }
3739
- }
3740
- this.updateUI();
4619
+ this.chart.addIndicator(e);
3741
4620
  }
3742
4621
  handleRemoveIndicator(e) {
3743
4622
  this.chart.removeIndicator(e);
3744
- let t = new Map(this.state.activeIndicators);
3745
- for (let [n, r] of t.entries()) if (r === e) {
3746
- t.delete(n);
3747
- break;
3748
- }
3749
- this.state = {
3750
- ...this.state,
3751
- activeIndicators: t
3752
- }, this.updateUI();
3753
4623
  }
3754
4624
  toggleCommandPalette() {
3755
4625
  if (this.commandPalette?.isOpen()) {
@@ -3760,29 +4630,29 @@ var $ = [
3760
4630
  }
3761
4631
  buildCommandItems() {
3762
4632
  let e = [];
3763
- for (let t of d) e.push({
4633
+ for (let t of f) e.push({
3764
4634
  id: t.id,
3765
4635
  label: t.name,
3766
4636
  category: "indicator",
3767
- active: this.state.activeIndicators.has(t.id)
4637
+ active: [...this.state.activeIndicators.values()].some((e) => e.id === t.id)
3768
4638
  });
3769
- for (let t of l) e.push({
4639
+ for (let t of u) e.push({
3770
4640
  id: t.value,
3771
4641
  label: t.label,
3772
4642
  category: "chartType",
3773
4643
  active: this.state.chartType === t.value
3774
4644
  });
3775
- 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({
3776
4646
  id: n.value,
3777
4647
  label: n.label,
3778
4648
  category: "drawing",
3779
4649
  active: this.state.activeTool === n.value
3780
4650
  });
3781
- for (let t of c) e.push({
3782
- id: t.value,
3783
- label: t.label,
4651
+ for (let t of this.timeframes) e.push({
4652
+ id: t,
4653
+ label: F(t),
3784
4654
  category: "timeframe",
3785
- active: this.state.timeframe === t.value
4655
+ active: this.state.timeframe === t
3786
4656
  });
3787
4657
  return e.push({
3788
4658
  id: "screenshot",
@@ -3864,6 +4734,13 @@ var $ = [
3864
4734
  activeTool: null
3865
4735
  }, this.chart.setDrawingTool(null), this.updateUI();
3866
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
+ }
3867
4744
  handleToggleMagnet() {
3868
4745
  let e = !this.state.magnetEnabled;
3869
4746
  this.state = {
@@ -3876,7 +4753,7 @@ var $ = [
3876
4753
  this.state = {
3877
4754
  ...this.state,
3878
4755
  isDark: e
3879
- }, 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"), {
3880
4757
  fontSize: 48,
3881
4758
  color: e ? "rgba(255,255,255,0.03)" : "rgba(0,0,0,0.03)"
3882
4759
  }), this.updateUI();
@@ -3902,7 +4779,7 @@ var $ = [
3902
4779
  let t = this.layoutKeyPrefix + e;
3903
4780
  this.activeLayoutKey = t;
3904
4781
  try {
3905
- this.chart.loadStateFromStorage(t) && this.rebuildActiveIndicatorsMapFromChart();
4782
+ this.chart.loadStateFromStorage(t) && this.syncIndicatorsFromChart();
3906
4783
  } catch {}
3907
4784
  this.chart.setAutoSave(t, this.layoutDebounceMs);
3908
4785
  }
@@ -3914,9 +4791,12 @@ var $ = [
3914
4791
  this.chart.disableAutoSave(), this.activeLayoutKey = null;
3915
4792
  }
3916
4793
  }
3917
- rebuildActiveIndicatorsMapFromChart() {
4794
+ syncIndicatorsFromChart() {
3918
4795
  let e = /* @__PURE__ */ new Map();
3919
- 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
+ });
3920
4800
  this.state = {
3921
4801
  ...this.state,
3922
4802
  activeIndicators: e
@@ -3926,61 +4806,109 @@ var $ = [
3926
4806
  this.replayBar?.isMounted() ? this.exitReplay() : this.enterReplay();
3927
4807
  }
3928
4808
  enterReplay() {
3929
- let e = this.chart.getData();
3930
- 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({
3931
4812
  onPlay: () => {
3932
- this.chart.getReplayState() === "paused" ? this.chart.replayResume() : this.chart.replayStart({
3933
- speed: this.replaySpeed,
3934
- interval: 200
3935
- }), 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");
3936
4818
  },
3937
4819
  onPause: () => {
3938
4820
  this.chart.replayPause(), this.replayBar?.setState("paused");
3939
4821
  },
3940
- onStop: () => {
3941
- this.chart.replayStop(), this.replayBar?.setState("paused");
3942
- },
3943
- onStepBack: () => {
3944
- let e = this.chart.getReplayProgress();
3945
- this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(Math.max(0, e.current - 1)), this.replayBar?.setState("paused");
3946
- },
3947
- onStepForward: () => {
3948
- let e = this.chart.getReplayProgress();
3949
- this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(Math.min(e.total - 1, e.current + 1)), this.replayBar?.setState("paused");
3950
- },
4822
+ onStepBack: () => this.stepReplay(-1),
4823
+ onStepForward: () => this.stepReplay(1),
3951
4824
  onSeek: (e) => {
3952
4825
  this.chart.getReplayState() === "playing" && this.chart.replayPause(), this.chart.replaySeek(e), this.replayBar?.setState("paused");
3953
4826
  },
3954
4827
  onSpeedChange: (e) => {
3955
4828
  this.replaySpeed = e, this.chart.setReplaySpeed(e);
3956
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
+ },
3957
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")
3958
4844
  }), this.replayBar.mount(this.chartContainer, {
3959
- total: e.length,
3960
- speed: this.replaySpeed
3961
- }), this.chart.replayStart({
4845
+ total: this.replayTotal(),
3962
4846
  speed: this.replaySpeed,
3963
- interval: 200,
3964
- startIndex: 1
3965
- }), this.chart.replayPause(), this.replayBar.setState("paused"), this.replayPollInterval = setInterval(() => {
3966
- if (!this.replayBar?.isMounted()) return;
3967
- let e = this.chart.getReplayProgress();
3968
- this.replayBar.setProgress(e.current, e.total);
3969
- let t = this.chart.getReplayState();
3970
- t === "stopped" ? this.replayBar.setState("paused") : this.replayBar.setState(t);
3971
- }, 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`;
3972
4897
  }
3973
4898
  exitReplay() {
3974
- 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;
3975
4903
  }
3976
4904
  applySettings(e) {
3977
4905
  this.settingsState = {
3978
4906
  ...this.settingsState,
3979
4907
  ...e
3980
- }, 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({
3981
4909
  left: e.pivotStrength,
3982
4910
  right: e.pivotStrength
3983
- }), 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 = {
3984
4912
  ...this.settingsState,
3985
4913
  scaleMode: e.logScale ? "logarithmic" : "regular"
3986
4914
  }) : (this.chart.setScaleMode(e.scaleMode), this.settingsState = {
@@ -4029,8 +4957,37 @@ var $ = [
4029
4957
  }
4030
4958
  this.updateUI();
4031
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
+ }
4032
4989
  updateUI() {
4033
- 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({
4034
4991
  connectionState: this.state.connectionState,
4035
4992
  message: this.state.connectionMessage,
4036
4993
  symbol: this.state.symbol,
@@ -4051,7 +5008,11 @@ var $ = [
4051
5008
  return !0;
4052
5009
  }
4053
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
+ }
4054
5015
  //#endregion
4055
- 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 };
4056
5017
 
4057
5018
  //# sourceMappingURL=index.js.map