@tradecanvas/chart 1.1.0 → 1.2.0

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