@tradecanvas/chart 1.43.0 → 1.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Chart.d.ts +56 -11
- package/dist/Chart.d.ts.map +1 -1
- package/dist/DataManager.d.ts +2 -0
- package/dist/DataManager.d.ts.map +1 -1
- package/dist/{LayoutSession-Cg9dd59R.js → LayoutSession-BI2ADwWW.js} +86 -41
- package/dist/LayoutSession-BI2ADwWW.js.map +1 -0
- package/dist/LayoutSession-CJlxg9Ep.cjs +2 -0
- package/dist/LayoutSession-CJlxg9Ep.cjs.map +1 -0
- package/dist/i18n-DVeWlg64.cjs +2 -0
- package/dist/i18n-DVeWlg64.cjs.map +1 -0
- package/dist/{i18n-Bt8FI6Wl.js → i18n-DjzoHpMJ.js} +5 -1
- package/dist/i18n-DjzoHpMJ.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/widget/ChartWidget.d.ts +13 -3
- package/dist/widget/ChartWidget.d.ts.map +1 -1
- package/dist/widget/WidgetAccountPanel.d.ts +26 -5
- package/dist/widget/WidgetAccountPanel.d.ts.map +1 -1
- package/dist/widget/WidgetDepthLadder.d.ts +48 -7
- package/dist/widget/WidgetDepthLadder.d.ts.map +1 -1
- package/dist/widget/WidgetOrderTicket.d.ts.map +1 -1
- package/dist/widget/WidgetSettings.d.ts +2 -2
- package/dist/widget/WidgetSettings.d.ts.map +1 -1
- package/dist/widget/index.cjs +291 -146
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.js +700 -518
- package/dist/widget/index.js.map +1 -1
- package/dist/widget/ladderRows.d.ts +4 -0
- package/dist/widget/ladderRows.d.ts.map +1 -1
- package/dist/widget/locales/ar.d.ts.map +1 -1
- package/dist/widget/locales/cs.d.ts.map +1 -1
- package/dist/widget/locales/da.d.ts.map +1 -1
- package/dist/widget/locales/de.d.ts.map +1 -1
- package/dist/widget/locales/el.d.ts.map +1 -1
- package/dist/widget/locales/en.d.ts +2 -0
- package/dist/widget/locales/en.d.ts.map +1 -1
- package/dist/widget/locales/es.d.ts.map +1 -1
- package/dist/widget/locales/et.d.ts.map +1 -1
- package/dist/widget/locales/fa.d.ts.map +1 -1
- package/dist/widget/locales/fr.d.ts.map +1 -1
- package/dist/widget/locales/he.d.ts.map +1 -1
- package/dist/widget/locales/hu.d.ts.map +1 -1
- package/dist/widget/locales/id.d.ts.map +1 -1
- package/dist/widget/locales/index.cjs +1 -1
- package/dist/widget/locales/index.cjs.map +1 -1
- package/dist/widget/locales/index.js +57 -1
- package/dist/widget/locales/index.js.map +1 -1
- package/dist/widget/locales/it.d.ts.map +1 -1
- package/dist/widget/locales/ja.d.ts.map +1 -1
- package/dist/widget/locales/ko.d.ts.map +1 -1
- package/dist/widget/locales/ms.d.ts.map +1 -1
- package/dist/widget/locales/nb.d.ts.map +1 -1
- package/dist/widget/locales/nl.d.ts.map +1 -1
- package/dist/widget/locales/pl.d.ts.map +1 -1
- package/dist/widget/locales/pt.d.ts.map +1 -1
- package/dist/widget/locales/ro.d.ts.map +1 -1
- package/dist/widget/locales/ru.d.ts.map +1 -1
- package/dist/widget/locales/sk.d.ts.map +1 -1
- package/dist/widget/locales/sv.d.ts.map +1 -1
- package/dist/widget/locales/th.d.ts.map +1 -1
- package/dist/widget/locales/tr.d.ts.map +1 -1
- package/dist/widget/locales/vi.d.ts.map +1 -1
- package/dist/widget/locales/zh.d.ts.map +1 -1
- package/dist/widget/locales/zhHant.d.ts.map +1 -1
- package/dist/widget/signedFigure.d.ts +10 -0
- package/dist/widget/signedFigure.d.ts.map +1 -0
- package/dist/widget/types.d.ts +5 -3
- package/dist/widget/types.d.ts.map +1 -1
- package/dist/widget/widgetFeatures.d.ts +1 -1
- package/dist/widget/widgetFeatures.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/LayoutSession-Cg9dd59R.js.map +0 -1
- package/dist/LayoutSession-PXegVR9P.cjs +0 -2
- package/dist/LayoutSession-PXegVR9P.cjs.map +0 -1
- package/dist/i18n-BjrZRqdb.cjs +0 -2
- package/dist/i18n-BjrZRqdb.cjs.map +0 -1
- package/dist/i18n-Bt8FI6Wl.js.map +0 -1
package/dist/widget/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as e, a as t, c as n, i as r, n as i, o as a, r as o, t as s } from "../LayoutSession-
|
|
2
|
-
import { a as c, c as l, i as u, n as d, o as f, r as p, s as m, t as h } from "../i18n-
|
|
1
|
+
import { C as e, a as t, c as n, i as r, n as i, o as a, r as o, t as s } from "../LayoutSession-BI2ADwWW.js";
|
|
2
|
+
import { a as c, c as l, i as u, n as d, o as f, r as p, s as m, t as h } from "../i18n-DjzoHpMJ.js";
|
|
3
3
|
import { CHART_STYLE_KEYS as g, CHART_TYPE_ICONS as _, DARK_THEME as v, DEFAULT_SIGNAL_STYLE as y, DEFAULT_TRADE_ZONE_STYLE as b, DEFAULT_TRADING_CONFIG as x, DRAWING_TOOL_ICONS as ee, LIGHT_THEME as te, PHI as ne, PRICE_SOURCES as re, UI_ICONS as ie, barTimeUnit as ae, formatPrice as oe, iconSvg as se, indicatorSource as ce, isTimeFrame as le, isValidTimeZone as ue, marketStatus as de, offsetAt as fe, parseIndicatorSource as pe, phiStep as me, readChartStyleOverrides as he, readChartTypeOptions as ge, readIndicatorPlotStyles as _e, readNews as ve, readQuote as ye, sanitizeDrawingOptions as be, sanitizeDrawingStyle as xe, stepDecimals as Se, tickBarCount as Ce, timeParts as we, timeframeBucketStart as Te, timeframeToMs as S, tzLabel as Ee, wallToUtc as De, zoneOffsetMinutes as Oe } from "@tradecanvas/commons";
|
|
4
4
|
import { ChartStateManager as ke, INDICATOR_CATEGORIES as Ae, INTERVAL_LIMITS as je, INTERVAL_UNITS as Me, MAX_ALERT_BARS as Ne, MIN_ALERT_BARS as Pe, RANGE_PRESETS as Fe, SYMBOL_INDICATOR_IDS as Ie, indicatorCategory as Le, indicatorValuePrecision as Re, isSeriesPalette as ze, plotColor as Be, plotShown as Ve, rangePresetStart as He, servesTimeframe as Ue, sourceParam as We, withResampling as Ge } from "@tradecanvas/core";
|
|
5
5
|
//#region src/io/resampleOHLCV.ts
|
|
@@ -1224,7 +1224,7 @@ var O = [...new Set([
|
|
|
1224
1224
|
...jt
|
|
1225
1225
|
].flatMap((e) => e.rows.flatMap((e) => e.keys)),
|
|
1226
1226
|
...[...Ot, ...kt].flatMap((e) => e.keys)
|
|
1227
|
-
])], Ft = "/* === TradeCanvas Widget — Premium Styles === */\n\n/*\n * The HTML `hidden` attribute only sets `display: none` via the UA stylesheet,\n * which any author `display` rule (e.g. `.tcw-alerts-panel { display: flex }`)\n * silently overrides — leaving panels stuck open when JS sets `el.hidden = true`.\n * Force `hidden` to win for every namespaced widget element. Scoped to `tcw-`\n * so it never touches the host page.\n */\n[class^=\"tcw-\"][hidden],\n[class*=\" tcw-\"][hidden] {\n display: none !important;\n}\n\n/* Control tooltips (WidgetTooltip): quick to appear, slide in from the control. */\n.tcw-tooltip {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 60;\n max-width: 240px;\n padding: var(--tcw-space-3) var(--tcw-space-4);\n border-radius: var(--tcw-tooltip-radius);\n background: var(--tcw-tooltip-bg);\n color: var(--tcw-tooltip-fg);\n box-shadow: var(--tcw-tooltip-shadow);\n width: max-content;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n line-height: 1.35;\n overflow-wrap: anywhere;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transform: translate(var(--tcw-tip-dx, 0), var(--tcw-tip-dy, 0));\n transition:\n opacity 110ms var(--tcw-ease-out),\n transform 110ms var(--tcw-ease-out),\n visibility 0s linear 110ms;\n}\n\n.tcw-tooltip--visible {\n opacity: 1;\n visibility: visible;\n transform: none;\n transition:\n opacity 110ms var(--tcw-ease-out),\n transform 110ms var(--tcw-ease-out),\n visibility 0s;\n}\n\n/* The modal portal: carries the tokens and fonts, but no box of its own. */\n.tcw-root.tcw-portal {\n display: contents;\n}\n\n/* Fullscreen: the root fills the screen; the chart resizes with it. */\n.tcw-root:fullscreen {\n width: 100vw;\n height: 100vh;\n height: 100dvh;\n}\n\n.tcw-root {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n font-family: var(--tcw-font);\n font-feature-settings: 'cv11', 'ss01', 'ss03';\n font-size: var(--tcw-font-size);\n line-height: 1.4;\n color: #e6e3dc;\n background: #131416;\n font-variant-numeric: tabular-nums;\n position: relative;\n overflow: hidden;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n /* --- Dark theme tokens (default) ---\n * Print at night: warm ink on an off-black, never pure white on black, so\n * text doesn't glare. Grey for everything that is normal; colour only where\n * it means something. */\n --tcw-bg: #131416;\n --tcw-bg-surface: #131416;\n --tcw-bg-elevated: #1b1c1f;\n --tcw-bg-overlay: rgba(19, 20, 22, 0.6);\n --tcw-border: #2a2b2f;\n --tcw-border-strong: #3a3b40;\n /* Tooltips are the ink turned over: light on the dark ground. */\n --tcw-tooltip-bg: #e6e3dc;\n --tcw-tooltip-fg: #131416;\n --tcw-text: #e6e3dc;\n --tcw-text-dim: #a9a6a0;\n --tcw-text-muted: #8c8a85;\n\n /* Ink blue: links, focus and what you picked. --tcw-accent-ink is the text colour on an accent fill. */\n --tcw-accent: #7d9bff;\n --tcw-accent-hover: #98b0ff;\n --tcw-accent-ink: #131416;\n --tcw-accent-soft: rgba(125, 155, 255, 0.14);\n --tcw-accent-glow: rgba(125, 155, 255, 0.22);\n --tcw-accent-line: rgba(125, 155, 255, 0.55);\n\n --tcw-red: #e2706b;\n --tcw-red-soft: rgba(226, 112, 107, 0.12);\n --tcw-green: #4fae8a;\n --tcw-green-soft: rgba(79, 174, 138, 0.12);\n\n --tcw-hover-bg: rgba(230, 227, 220, 0.06);\n --tcw-active-bg: rgba(230, 227, 220, 0.1);\n --tcw-divider: rgba(230, 227, 220, 0.07);\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 /* Spacing: Fibonacci numbers, so each step is near φ times the one before. */\n --tcw-space-1: 2px;\n --tcw-space-2: 3px;\n --tcw-space-3: 5px;\n --tcw-space-4: 8px;\n --tcw-space-5: 13px;\n --tcw-space-6: 21px;\n --tcw-space-7: 34px;\n\n /* The look (UI system): Print's values. The `ui` option sets them inline. */\n --tcw-radius-xs: 1px;\n --tcw-radius-sm: 2px;\n --tcw-radius: 3px;\n --tcw-radius-lg: 5px;\n --tcw-radius-xl: 8px;\n --tcw-control-radius: var(--tcw-radius);\n --tcw-input-radius: var(--tcw-radius);\n --tcw-menu-radius: var(--tcw-radius-lg);\n --tcw-dialog-radius: var(--tcw-radius-xl);\n --tcw-panel-radius: var(--tcw-radius-lg);\n --tcw-tooltip-radius: var(--tcw-radius-sm);\n --tcw-tag-radius: var(--tcw-radius-sm);\n --tcw-toast-radius: var(--tcw-radius-lg);\n --tcw-toolbar-radius: 0px;\n --tcw-sidebar-radius: 0px;\n --tcw-toolbar-h: 42px;\n --tcw-control-h: 26px;\n --tcw-control-h-sm: 20px;\n --tcw-icon: 16px;\n --tcw-sidebar-w: 42px;\n --tcw-menu-item-h: 33px;\n --tcw-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n --tcw-font-size: 13px;\n --tcw-font-size-sm: 11px;\n --tcw-font-size-xs: 10px;\n --tcw-font-size-lg: 15px;\n --tcw-font-size-xl: 18px;\n --tcw-font-size-display: 21px;\n --tcw-weight: 400;\n --tcw-weight-strong: 600;\n --tcw-label-case: uppercase;\n --tcw-label-tracking: 0.06em;\n --tcw-border-w: 1px;\n --tcw-sep-w: 1px;\n --tcw-menu-shadow: 0 0 0 1px var(--tcw-border), var(--tcw-shadow-md);\n --tcw-dialog-shadow: 0 0 0 1px var(--tcw-border), var(--tcw-shadow-lg);\n --tcw-tooltip-shadow: var(--tcw-shadow-sm);\n --tcw-blur: 0px;\n --tcw-surface-opacity: 100%;\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(125, 155, 255, 0.5);\n\n /* Type */\n --tcw-font-mono: 'Cascadia Mono', 'SF Mono', ui-monospace, Menlo, Consolas, monospace;\n}\n\n/* Print by day: ink on paper. */\n.tcw-root[data-tcw-theme='light'] {\n color: #1b1d21;\n background: #fbfaf6;\n\n --tcw-bg: #fbfaf6;\n --tcw-bg-surface: #fbfaf6;\n --tcw-bg-elevated: #ffffff;\n --tcw-bg-overlay: rgba(251, 250, 246, 0.8);\n --tcw-border: #dcd8cf;\n --tcw-border-strong: #c7c2b7;\n --tcw-tooltip-bg: #1b1d21;\n --tcw-tooltip-fg: #fbfaf6;\n --tcw-text: #1b1d21;\n --tcw-text-dim: #4a4e57;\n --tcw-text-muted: #6c7077;\n\n /* A deeper ink blue: readable as text on paper, white text readable on it. */\n --tcw-accent: #2348c4;\n --tcw-accent-hover: #1b3a9f;\n --tcw-accent-ink: #ffffff;\n --tcw-accent-soft: rgba(35, 72, 196, 0.1);\n --tcw-accent-glow: rgba(35, 72, 196, 0.16);\n --tcw-accent-line: rgba(35, 72, 196, 0.45);\n --tcw-ring: 0 0 0 2px rgba(35, 72, 196, 0.4);\n\n /* Darker semantic colours: used as text on paper. */\n --tcw-red: #b8423f;\n --tcw-red-soft: rgba(184, 66, 63, 0.1);\n --tcw-green: #1f7a5c;\n --tcw-green-soft: rgba(31, 122, 92, 0.1);\n\n --tcw-hover-bg: rgba(27, 29, 33, 0.05);\n --tcw-active-bg: rgba(27, 29, 33, 0.08);\n --tcw-divider: #e7e3da;\n\n /* Warm shadows, as paper casts. */\n --tcw-shadow-sm: 0 1px 2px rgba(40, 34, 22, 0.06);\n --tcw-shadow-md: 0 4px 12px rgba(40, 34, 22, 0.08), 0 1px 3px rgba(40, 34, 22, 0.05);\n --tcw-shadow-lg: 0 12px 36px rgba(40, 34, 22, 0.13), 0 4px 12px rgba(40, 34, 22, 0.07);\n --tcw-shadow-xl: 0 24px 64px rgba(40, 34, 22, 0.17), 0 12px 24px rgba(40, 34, 22, 0.09);\n}\n\n/* === Toolbar === */\n\n.tcw-toolbar {\n display: flex;\n align-items: center;\n gap: 0;\n padding: 0 var(--tcw-space-4);\n height: var(--tcw-toolbar-h);\n border-bottom: var(--tcw-border-w) solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n flex-shrink: 0;\n position: relative;\n z-index: 20;\n}\n\n.tcw-toolbar-symbol {\n font-size: var(--tcw-font-size-lg);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n display: inline-flex;\n align-items: center;\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-4);\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-control-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/* With the symbol search switched off, the button only names the symbol. */\n.tcw-toolbar-symbol[aria-disabled=\"true\"] {\n cursor: default;\n}\n\n.tcw-toolbar-symbol[aria-disabled=\"true\"]:hover {\n background: transparent;\n}\n\n.tcw-toolbar-sep {\n width: var(--tcw-sep-w);\n /* A button's height over phi: the rule stands as tall as the icons beside it. */\n height: calc(var(--tcw-control-h) / 1.618);\n background: var(--tcw-border);\n flex-shrink: 0;\n margin: 0 var(--tcw-space-3);\n}\n\n.tcw-toolbar-group {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-1);\n padding: 0 var(--tcw-space-2);\n}\n\n.tcw-toolbar-spacer {\n flex: 1;\n}\n\n.tcw-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-4);\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight);\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-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-on-bg);\n color: var(--tcw-on-fg);\n font-weight: var(--tcw-weight-strong);\n box-shadow: var(--tcw-on-ring);\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: var(--tcw-control-h);\n height: var(--tcw-control-h);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-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 width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n\n.tcw-badge-count {\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n padding: 1px var(--tcw-space-3);\n border-radius: var(--tcw-tag-radius);\n font-family: var(--tcw-font-mono);\n}\n\n/* === Dropdown === */\n\n.tcw-dropdown-trigger {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-3);\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-4);\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight);\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-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: var(--tcw-space-3);\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n z-index: 50;\n width: max-content;\n max-width: min(340px, calc(100vw - 16px));\n padding: var(--tcw-menu-pad);\n max-height: 420px;\n overflow-y: auto;\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\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 min-height: var(--tcw-menu-item-h);\n padding: var(--tcw-space-1) var(--tcw-space-4);\n font-size: var(--tcw-font-size);\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: start;\n border-radius: var(--tcw-menu-item-radius);\n gap: var(--tcw-space-5);\n}\n\n.tcw-dropdown-item:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n/* A menu row led by an icon (chart types): icon then label, not spread apart. */\n.tcw-dropdown-item--icon {\n justify-content: flex-start;\n gap: var(--tcw-space-4);\n}\n\n.tcw-dropdown-item svg,\n.tcw-flyout-item svg {\n flex-shrink: 0;\n}\n\n/* The drawing-group button's icon holder: a plain box for the swapped SVG. */\n.tcw-sidebar-icon {\n display: inline-flex;\n}\n\n.tcw-dropdown-item.tcw-active {\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n font-weight: var(--tcw-weight-strong);\n}\n\n/* Timeframe menu: pick on the left, pin (star) on the right. */\n.tcw-tf-more {\n padding: 0 5px;\n}\n\n.tcw-tf-more svg {\n display: block;\n}\n\n.tcw-tf-row {\n display: flex;\n align-items: center;\n gap: 2px;\n}\n\n.tcw-tf-row .tcw-dropdown-item {\n flex: 1;\n min-width: 0;\n}\n\n.tcw-tf-star {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-tf-star:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-tf-star.tcw-active {\n color: var(--tcw-accent);\n}\n\n.tcw-tf-star.tcw-active svg {\n fill: currentColor;\n}\n\n.tcw-tf-star:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-tf-remove {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-tf-row:hover .tcw-tf-remove,\n.tcw-tf-remove:focus-visible {\n opacity: 1;\n}\n\n/* No hover on touch screens: keep it visible rather than a hidden tap target. */\n@media (hover: none) {\n .tcw-tf-remove { opacity: 1; }\n}\n\n.tcw-tf-remove:hover {\n color: var(--tcw-red);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-tf-remove:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n/* Typed interval, under the list: stays in view while the list scrolls. */\n.tcw-tf-custom {\n position: sticky;\n bottom: -6px;\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin: 4px -6px -6px;\n padding: 6px 10px 8px;\n border-top: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-elevated);\n}\n\n.tcw-tf-custom-hint:empty {\n display: none;\n}\n\n.tcw-tf-custom-hint {\n flex-basis: 100%;\n width: 0;\n min-width: 100%;\n color: var(--tcw-red);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.35;\n}\n\n.tcw-tf-custom-input {\n flex: 1;\n /* Fills the row: its own width would follow the font (16px on touch). */\n width: 0;\n min-width: 0;\n height: 26px;\n padding: 0 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text);\n font: inherit;\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-tf-custom-input::placeholder {\n color: var(--tcw-text-dim);\n}\n\n.tcw-tf-custom-input:focus {\n outline: none;\n border-color: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n\n.tcw-tf-custom-input[aria-invalid='true'] {\n border-color: var(--tcw-red);\n box-shadow: 0 0 0 2px var(--tcw-red-soft);\n}\n\n.tcw-tf-custom-add {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n cursor: pointer;\n}\n\n.tcw-tf-custom-add:hover {\n border-color: var(--tcw-accent);\n color: var(--tcw-accent);\n}\n\n.tcw-tf-custom-add:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: 1px;\n}\n\n.tcw-dropdown-label {\n text-transform: var(--tcw-label-case);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n letter-spacing: var(--tcw-label-tracking);\n padding: var(--tcw-space-4) var(--tcw-space-4) var(--tcw-space-2);\n font-weight: var(--tcw-weight-strong);\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: var(--tcw-font-size-xs);\n font-family: var(--tcw-font-mono);\n color: var(--tcw-text-muted);\n padding: 2px 6px;\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-hover-bg);\n letter-spacing: 0.02em;\n}\n\n/* === Body === */\n\n.tcw-body {\n position: relative;\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/* === History pill (older bars loading at the left edge) === */\n\n.tcw-history-pill {\n position: absolute;\n top: 50%;\n left: 10px;\n z-index: 4;\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 5px 10px 5px 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-shadow-sm);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n line-height: 1;\n white-space: nowrap;\n transform: translateY(-50%);\n opacity: 1;\n transition: opacity var(--tcw-dur-normal) var(--tcw-ease-out);\n pointer-events: none;\n}\n\n.tcw-history-pill--hidden {\n opacity: 0;\n}\n\n.tcw-history-pill--error {\n border-color: color-mix(in srgb, var(--tcw-red) 45%, var(--tcw-border));\n color: var(--tcw-red);\n}\n\n.tcw-history-spinner {\n width: 10px;\n height: 10px;\n border: 1.5px solid var(--tcw-accent-soft);\n border-top-color: var(--tcw-accent);\n border-radius: 50%;\n animation: tcw-history-spin 0.8s linear infinite;\n}\n\n.tcw-history-pill--error .tcw-history-spinner {\n border-color: currentColor;\n animation: none;\n}\n\n@keyframes tcw-history-spin {\n to { transform: rotate(360deg); }\n}\n\n/* === Loading overlay (candle skeleton) === */\n\n.tcw-loading-overlay {\n /* Uses a modifier class rather than the `hidden` attribute — the global\n `[hidden] { display: none !important }` rule above would cut the\n opacity transition off before it can play. */\n position: absolute;\n inset: 0;\n z-index: 5;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--tcw-bg);\n opacity: 1;\n transition: opacity var(--tcw-dur-slow) var(--tcw-ease-out);\n pointer-events: none;\n}\n\n.tcw-loading-overlay--hidden {\n opacity: 0;\n}\n\n.tcw-loading-card {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 14px;\n padding: 22px 26px 20px;\n border: 1px solid transparent;\n border-radius: var(--tcw-panel-radius);\n}\n\n/* A slow switch: the previous chart stays readable underneath, dimmed, so the\n click visibly registered without blanking the screen. */\n.tcw-loading-overlay--veil {\n background: color-mix(in srgb, var(--tcw-bg) 55%, transparent);\n}\n\n.tcw-loading-overlay--veil .tcw-loading-card {\n background: var(--tcw-bg-elevated);\n border-color: var(--tcw-border);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n.tcw-loading-candles {\n position: relative;\n display: flex;\n gap: 7px;\n height: 64px;\n}\n\n/* One candle: the element is the wick's column, ::before the wick, ::after the body. */\n.tcw-loading-candle {\n position: relative;\n width: 8px;\n height: 100%;\n color: var(--tcw-red);\n opacity: 0.28;\n animation: tcw-candle-light 1.6s var(--tcw-ease) infinite;\n animation-delay: var(--tcw-delay, 0ms);\n}\n\n.tcw-loading-candle--up { color: var(--tcw-green); }\n\n.tcw-loading-candle::before,\n.tcw-loading-candle::after {\n content: '';\n position: absolute;\n left: 50%;\n background: currentColor;\n transform: translateX(-50%);\n}\n\n.tcw-loading-candle::before {\n top: var(--tcw-wick-top);\n width: 1.5px;\n height: var(--tcw-wick-h);\n}\n\n.tcw-loading-candle::after {\n top: var(--tcw-body-top);\n width: 8px;\n height: var(--tcw-body-h);\n border-radius: 1.5px;\n}\n\n/* Each candle brightens and lifts slightly in turn, left to right. */\n@keyframes tcw-candle-light {\n 0%, 55%, 100% { opacity: 0.28; transform: translateY(0); }\n 20% { opacity: 1; transform: translateY(-2px); }\n}\n\n.tcw-loading-track {\n position: relative;\n width: 100%;\n min-width: 88px;\n height: 2px;\n border-radius: 1px;\n background: var(--tcw-border);\n overflow: hidden;\n}\n\n.tcw-loading-track > span {\n position: absolute;\n inset: 0;\n width: 40%;\n border-radius: 1px;\n background: linear-gradient(90deg, transparent, var(--tcw-accent), transparent);\n animation: tcw-loading-sweep 1.6s var(--tcw-ease) infinite;\n}\n\n@keyframes tcw-loading-sweep {\n from { transform: translateX(-100%); }\n to { transform: translateX(250%); }\n}\n\n/* The status text is announced, not shown — the candles say \"loading\". */\n.tcw-loading-label {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n.tcw-loading-overlay--error .tcw-loading-candles,\n.tcw-loading-overlay--error .tcw-loading-track {\n display: none;\n}\n\n/* A failure is shown: why the chart is empty and that a retry is running. */\n.tcw-loading-overlay--error .tcw-loading-label {\n position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip-path: none;\n white-space: normal;\n max-width: 320px;\n text-align: center;\n color: var(--tcw-red);\n font-size: var(--tcw-font-size);\n}\n\n/* Reduced motion: nothing slides or lifts, but the candles still glow in\n turn and the track breathes, so the wait never looks frozen. */\n@media (prefers-reduced-motion: reduce) {\n .tcw-loading-candle {\n animation: tcw-candle-glow 2.4s ease-in-out infinite;\n animation-delay: var(--tcw-delay, 0ms);\n }\n .tcw-loading-track > span {\n width: 100%;\n background: var(--tcw-accent);\n animation: tcw-loading-breathe 2.4s ease-in-out infinite;\n }\n}\n\n@keyframes tcw-candle-glow {\n 0%, 60%, 100% { opacity: 0.28; }\n 25% { opacity: 0.9; }\n}\n\n@keyframes tcw-loading-breathe {\n 0%, 100% { opacity: 0.15; }\n 50% { opacity: 0.7; }\n}\n\n/* === On-chart indicator legend (WidgetIndicatorLegend) === */\n\n.tcw-ind-legend {\n position: absolute;\n z-index: 3;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 1px;\n max-width: calc(100% - 140px);\n pointer-events: none;\n}\n\n.tcw-ind-legend--collapsed > .tcw-ind-legend-row {\n display: none;\n}\n\n.tcw-ind-legend-row {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n max-width: 100%;\n padding: 0 var(--tcw-space-2);\n border-radius: var(--tcw-radius-sm);\n /* The figures face at the size of the price legend above: one block, columns that line up. */\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n line-height: 19px;\n font-feature-settings: 'tnum';\n white-space: nowrap;\n color: var(--tcw-text-dim);\n pointer-events: auto;\n cursor: default;\n /* A narrow pane: the values shrink first, then the row is clipped. */\n overflow: hidden;\n}\n\n/* A pane's indicator: at the top of its pane, where the canvas title was,\n short enough to sit in the pane's header below the divider's grab zone. */\n.tcw-ind-legend-row--pane {\n position: absolute;\n z-index: 3;\n line-height: 15px;\n}\n\n.tcw-ind-legend-row:hover,\n.tcw-ind-legend-row:focus-within {\n background: color-mix(in srgb, var(--tcw-bg-elevated) 90%, transparent);\n box-shadow: 0 0 0 1px var(--tcw-border);\n}\n\n.tcw-ind-legend-name {\n padding: 0;\n border: none;\n background: none;\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n cursor: pointer;\n}\n\n.tcw-ind-legend-name:hover {\n color: var(--tcw-accent);\n}\n\n.tcw-ind-legend-values {\n display: inline-flex;\n gap: var(--tcw-space-4);\n min-width: 0;\n overflow: hidden;\n}\n\n.tcw-ind-legend-row--hidden .tcw-ind-legend-name,\n.tcw-ind-legend-row--hidden .tcw-ind-legend-values {\n opacity: 0.45;\n}\n\n/* Show / settings / remove: on hover or keyboard focus (always on touch). */\n.tcw-ind-legend-actions {\n display: none;\n gap: 1px;\n margin-left: -2px;\n}\n\n.tcw-ind-legend-row:hover .tcw-ind-legend-actions,\n.tcw-ind-legend-row:focus-within .tcw-ind-legend-actions {\n display: inline-flex;\n}\n\n@media (hover: none) {\n .tcw-ind-legend-actions {\n display: inline-flex;\n }\n\n /* Finger-sized targets. */\n .tcw-ind-legend-act,\n .tcw-ind-legend-toggle {\n min-width: 28px;\n min-height: 24px;\n }\n}\n\n.tcw-ind-legend-act {\n display: inline-grid;\n place-items: center;\n width: 20px;\n height: 18px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n\n.tcw-ind-legend-act:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ind-legend-act[data-act='remove']:hover {\n color: var(--tcw-red);\n}\n\n.tcw-ind-legend-toggle {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n margin-top: 1px;\n padding: 1px 5px;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n cursor: pointer;\n pointer-events: auto;\n}\n\n.tcw-ind-legend-toggle[hidden] {\n display: none;\n}\n\n.tcw-ind-legend-toggle:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ind-legend-name:focus-visible,\n.tcw-ind-legend-act:focus-visible,\n.tcw-ind-legend-toggle:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n/* === Sidebar === */\n\n.tcw-sidebar {\n width: var(--tcw-sidebar-w);\n flex-shrink: 0;\n background: var(--tcw-bg-surface);\n border-inline-end: var(--tcw-border-w) solid var(--tcw-border);\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: var(--tcw-space-3) 0;\n /* On a short screen the tools scroll; the menus sit outside it. */\n overflow-x: hidden;\n overflow-y: auto;\n scrollbar-width: none;\n}\n.tcw-sidebar::-webkit-scrollbar {\n display: none;\n}\n.tcw-sidebar > * {\n flex-shrink: 0;\n}\n\n.tcw-tool-group-wrap {\n position: relative;\n}\n\n.tcw-sidebar-btn {\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\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-control-radius);\n}\n\n.tcw-sidebar-btn svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\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-on-icon-fg);\n background: var(--tcw-on-icon-bg);\n box-shadow: var(--tcw-on-icon-ring);\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/* The drawing tools' sections: always a hairline (it groups the tools), even in\n looks that drop the rules between toolbar groups. */\n.tcw-sidebar-divider {\n width: 20px;\n height: max(1px, var(--tcw-sep-w));\n background: var(--tcw-divider);\n margin: 5px 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 margin-inline-start: 6px;\n overflow-y: auto;\n overscroll-behavior: contain;\n min-width: 180px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n z-index: 30;\n padding: var(--tcw-menu-pad);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n animation: tcw-slide-right var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n/* Spans the gap to the toolbar button: crossing it stays inside the menu. */\n.tcw-flyout::before {\n content: '';\n position: absolute;\n top: -1px;\n bottom: -1px;\n right: 100%;\n width: 8px;\n}\n\n@keyframes tcw-slide-right {\n from { opacity: 0; transform: translateX(-4px); }\n to { opacity: 1; transform: translateX(0); }\n}\n\n.tcw-flyout-header {\n text-transform: var(--tcw-label-case);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n letter-spacing: var(--tcw-label-tracking);\n padding: var(--tcw-space-3) var(--tcw-space-4) var(--tcw-space-2);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-flyout-hint {\n padding: var(--tcw-space-3) var(--tcw-space-4) var(--tcw-space-1);\n border-top: 1px solid var(--tcw-border);\n margin-top: var(--tcw-space-2);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n\n.tcw-flyout-item {\n min-height: var(--tcw-menu-item-h);\n padding: var(--tcw-space-1) var(--tcw-space-4);\n font-size: var(--tcw-font-size);\n color: var(--tcw-text-dim);\n cursor: pointer;\n width: 100%;\n display: flex;\n align-items: center;\n gap: 10px;\n border: none;\n background: transparent;\n text-align: start;\n font-family: inherit;\n border-radius: var(--tcw-menu-item-radius);\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.tcw-flyout-item:focus-visible {\n outline: none;\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n box-shadow: inset 0 0 0 1px var(--tcw-accent);\n}\n\n.tcw-flyout-item.tcw-active {\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n font-weight: var(--tcw-weight-strong);\n}\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(12, 12, 10, 0.42);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\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: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-dialog-radius);\n width: 520px;\n max-width: 92vw;\n max-height: 82vh;\n max-height: 82dvh;\n display: flex;\n flex-direction: column;\n box-shadow: var(--tcw-dialog-shadow);\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: var(--tcw-space-5) var(--tcw-space-6);\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n/* A dialog's title is phi times its text (21 to 13). */\n.tcw-modal-header h3 {\n font-size: var(--tcw-font-size-display);\n font-weight: var(--tcw-weight-strong);\n margin: 0;\n color: var(--tcw-text);\n letter-spacing: -0.015em;\n}\n\n.tcw-modal-close {\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\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-control-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 /* Four tabs in a long language on a phone: they wrap rather than clip. No overflow here: in the\n dialog's column it would let a long body squash the tabs, and clip the underline of the active one. */\n flex-wrap: wrap;\n flex-shrink: 0;\n gap: var(--tcw-space-2);\n padding: var(--tcw-tabs-pad-block) var(--tcw-space-6);\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n.tcw-modal-tab {\n flex-shrink: 0;\n white-space: nowrap;\n height: var(--tcw-tab-h);\n padding: var(--tcw-tab-pad);\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight);\n color: var(--tcw-text-muted);\n border: none;\n background: transparent;\n cursor: pointer;\n border-bottom: var(--tcw-tab-line) solid transparent;\n border-radius: var(--tcw-tab-radius);\n margin-bottom: calc(var(--tcw-tab-line) / -2);\n transition: color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n font-family: inherit;\n letter-spacing: -0.005em;\n}\n\n.tcw-modal-tab:hover {\n color: var(--tcw-text-dim);\n background: var(--tcw-tab-hover);\n}\n\n.tcw-modal-tab.tcw-active {\n color: var(--tcw-tab-on-fg);\n background: var(--tcw-tab-on-bg);\n border-bottom-color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-modal-body {\n padding: var(--tcw-space-6);\n overflow-y: auto;\n flex: 1;\n}\n\n.tcw-settings-section {\n margin-bottom: var(--tcw-space-6);\n}\n\n.tcw-settings-section:last-child {\n margin-bottom: 0;\n}\n\n.tcw-settings-section-title {\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n margin-bottom: var(--tcw-space-4);\n}\n\n.tcw-settings-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--tcw-space-4) 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: var(--tcw-font-size);\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: var(--tcw-radius-xs);\n}\n\n.tcw-color-hex {\n font-size: var(--tcw-font-size-xs);\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/* A colour left to the part itself: the swatch shows where the picker starts, faded. */\n.tcw-color-auto input[type='color'] {\n opacity: 0.45;\n border-style: dashed;\n}\n\n.tcw-color-auto .tcw-color-hex {\n font-family: inherit;\n font-style: italic;\n}\n\n.tcw-color-auto-btn {\n height: 24px;\n padding: 0 8px;\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n background: transparent;\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-radius-sm);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-color-auto-btn:hover,\n.tcw-color-auto-btn:focus-visible {\n color: var(--tcw-text);\n border-color: var(--tcw-accent);\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: var(--tcw-font-size-sm);\n font-family: inherit;\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-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: var(--tcw-space-5) var(--tcw-space-6);\n border-top: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-surface);\n border-radius: 0 0 var(--tcw-dialog-radius) var(--tcw-dialog-radius);\n}\n\n.tcw-reset-link {\n font-size: var(--tcw-font-size-sm);\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: var(--tcw-space-4) var(--tcw-space-6);\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n border: none;\n border-radius: var(--tcw-control-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}\n\n.tcw-done-btn:hover {\n background: var(--tcw-accent-hover);\n}\n\n.tcw-done-btn:disabled { opacity: 0.45; cursor: not-allowed; }\n\n.tcw-done-btn:active {\n transform: translateY(0.5px);\n}\n\n/* === Status Bar === */\n\n.tcw-statusbar {\n /* Above sidebar buttons that overflow a short chart; menus (z 30+) stay on top. */\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 7px 16px;\n border-top: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n flex-shrink: 0;\n font-feature-settings: 'tnum';\n}\n\n.tcw-status-right {\n display: flex;\n align-items: center;\n gap: 14px;\n margin-inline-start: auto;\n min-width: 0;\n white-space: nowrap;\n}\n\n/* Narrow screens: the range presets close up. */\n@media (max-width: 640px) {\n .tcw-range-btn {\n padding: 4px 5px;\n }\n}\n\n/* Range presets + go to date, bottom left */\n.tcw-range-bar {\n display: flex;\n align-items: center;\n gap: 1px;\n margin: -4px 12px -4px -8px;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n}\n\n.tcw-range-bar::-webkit-scrollbar {\n display: none;\n}\n\n.tcw-range-btn {\n flex-shrink: 0;\n padding: 4px 7px;\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n letter-spacing: 0.02em;\n color: var(--tcw-text-muted);\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-range-btn:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-range-btn:active {\n color: var(--tcw-accent);\n}\n\n.tcw-range-btn:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-range-goto {\n display: inline-grid;\n place-items: center;\n margin-inline-start: 6px;\n padding: 4px 6px;\n}\n\n.tcw-range-goto svg {\n display: block;\n}\n\n.tcw-status-indicator {\n display: flex;\n align-items: center;\n gap: 7px;\n font-weight: var(--tcw-weight);\n}\n\n.tcw-status-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n transition: background var(--tcw-dur-normal) var(--tcw-ease), box-shadow var(--tcw-dur-normal) var(--tcw-ease);\n position: relative;\n}\n\n.tcw-status-dot.tcw-connected {\n background: var(--tcw-green);\n box-shadow: 0 0 0 3px rgba(31, 168, 116, 0.18);\n}\n\n.tcw-status-dot.tcw-connected::after {\n content: '';\n position: absolute;\n inset: -3px;\n border-radius: 50%;\n border: 2px solid var(--tcw-green);\n opacity: 0;\n animation: tcw-pulse 2.2s ease-out 3;\n}\n\n@keyframes tcw-pulse {\n 0% { opacity: 0.6; transform: scale(0.6); }\n 100% { opacity: 0; transform: scale(2.2); }\n}\n\n.tcw-status-dot.tcw-error {\n background: var(--tcw-red);\n box-shadow: 0 0 0 3px rgba(232, 80, 91, 0.2);\n}\n\n/* === Watchlist === */\n\n.tcw-watchlist {\n width: 220px;\n flex-shrink: 0;\n background: var(--tcw-bg-surface);\n border-inline-start: 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 position: relative;\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 6px 8px 6px 8px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n/* The shown list's name: opens the lists menu. */\n.tcw-watchlist-name {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 6px;\n height: var(--tcw-control-h-sm);\n padding: 0 6px;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n text-align: start;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n}\n.tcw-watchlist-name::after {\n content: '';\n flex: none;\n width: 0;\n height: 0;\n margin-inline-start: auto;\n border: 4px solid transparent;\n border-top-color: currentColor;\n border-bottom-width: 0;\n opacity: 0.7;\n}\n\n.tcw-watchlist-add {\n flex: none;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-lg);\n line-height: 1;\n cursor: pointer;\n}\n\n.tcw-watchlist-name:hover,\n.tcw-watchlist-add:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n.tcw-watchlist-name:focus-visible,\n.tcw-watchlist-add:focus-visible,\n.tcw-watchlist-input:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* The lists menu, under the header. */\n.tcw-watchlist-menu {\n top: calc(100% - 2px);\n left: 6px;\n right: 6px;\n margin-top: 0;\n}\n.tcw-watchlist-count {\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n}\n.tcw-watchlist-menu .tcw-danger {\n color: var(--tcw-red);\n}\n\n/* Naming a list in place. */\n.tcw-watchlist-input {\n flex: 1;\n min-width: 0;\n height: var(--tcw-control-h-sm);\n padding: 0 8px;\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-watchlist-empty {\n padding: 16px 14px;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.5;\n}\n\n/* A row's remove button shows on hover or focus, over its numbers. */\n.tcw-watchlist-remove {\n position: absolute;\n top: 50%;\n right: 6px;\n display: grid;\n place-items: center;\n width: 20px;\n height: 20px;\n border: 0;\n border-radius: var(--tcw-radius-sm);\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size);\n line-height: 1;\n opacity: 0;\n transform: translateY(-50%);\n cursor: pointer;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-watchlist-row:hover .tcw-watchlist-remove,\n.tcw-watchlist-row:focus-within .tcw-watchlist-remove {\n opacity: 1;\n}\n.tcw-watchlist-remove:hover {\n color: var(--tcw-red);\n}\n.tcw-watchlist-row.tcw-watchlist-dragging {\n opacity: 0.45;\n}\n\n.tcw-watchlist-list {\n flex: 1;\n overflow-y: auto;\n padding: 4px 0;\n}\n\n.tcw-watchlist-row {\n position: relative;\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-inline-start: 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-inline-start-color: var(--tcw-accent);\n}\n\n.tcw-watchlist-row.tcw-watchlist-active {\n background: var(--tcw-accent-soft);\n border-inline-start-color: var(--tcw-accent);\n}\n\n.tcw-watchlist-symbol {\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\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: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n font-weight: var(--tcw-weight);\n}\n\n.tcw-watchlist-change {\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n font-weight: var(--tcw-weight);\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/* === Toast === */\n\n.tcw-toast-icon {\n display: inline-flex;\n vertical-align: -2px;\n margin-inline-end: 7px;\n color: var(--tcw-accent);\n}\n.tcw-toast-error .tcw-toast-icon { color: var(--tcw-red); }\n\n/* Over an open dialog: above its backdrop, at the window's foot. */\n.tcw-toast.tcw-toast-over {\n position: fixed;\n z-index: 120;\n}\n\n.tcw-toast {\n position: absolute;\n bottom: 60px;\n left: 50%;\n transform: translate(-50%, 12px);\n z-index: 40;\n padding: var(--tcw-space-4) var(--tcw-space-5);\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-toast-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n color: var(--tcw-text);\n opacity: 0;\n transition: opacity var(--tcw-dur-normal) var(--tcw-ease-out), transform var(--tcw-dur-normal) var(--tcw-ease-out);\n pointer-events: none;\n max-width: calc(100% - 32px);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n letter-spacing: -0.005em;\n}\n\n.tcw-toast.tcw-toast-in {\n opacity: 1;\n transform: translate(-50%, 0);\n}\n\n.tcw-toast-error {\n border-color: var(--tcw-red);\n color: var(--tcw-red);\n}\n\n/* === Replay scrubber === */\n\n/* Picking the replay start: the bars right of the pointer would be hidden. */\n.tcw-replay-shade {\n position: absolute;\n z-index: 4;\n pointer-events: none;\n background: color-mix(in srgb, var(--tcw-bg) 62%, transparent);\n border-inline-start: 1.5px dashed var(--tcw-accent);\n}\n\n.tcw-replay-group {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n\n.tcw-replay-group[hidden] { display: none; }\n\n.tcw-replay-hint {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 0 4px;\n color: var(--tcw-text-dim);\n white-space: nowrap;\n}\n\n.tcw-replay-text-btn {\n height: 26px;\n padding: 0 10px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-weight: var(--tcw-weight);\n white-space: nowrap;\n cursor: pointer;\n transition: background var(--tcw-dur-fast), border-color var(--tcw-dur-fast), color var(--tcw-dur-fast);\n}\n\n.tcw-replay-text-btn:hover { background: var(--tcw-hover-bg); border-color: var(--tcw-border-strong); }\n.tcw-replay-text-btn:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n\n/* At the last bar: the way out is the next thing to do. */\n.tcw-replay-bar--ended .tcw-replay-realtime {\n background: var(--tcw-accent);\n border-color: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n}\n\n.tcw-replay-btn:disabled { opacity: 0.4; cursor: default; }\n\n@media (max-width: 640px) {\n .tcw-replay-bar {\n flex-wrap: wrap;\n justify-content: center;\n max-width: calc(100% - 24px);\n border-radius: var(--tcw-panel-radius);\n }\n .tcw-replay-hint { white-space: normal; }\n}\n\n.tcw-replay-bar {\n position: absolute;\n left: 50%;\n /* Above the 30px time axis, so its dates stay readable. */\n bottom: 40px;\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: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n font-size: var(--tcw-font-size-sm);\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: var(--tcw-control-radius);\n cursor: pointer;\n font-family: inherit;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-replay-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-replay-btn.tcw-replay-play {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n width: 32px;\n height: 32px;\n box-shadow: 0 0 0 3px var(--tcw-accent-glow);\n}\n\n.tcw-replay-btn.tcw-replay-play:hover {\n background: var(--tcw-accent-hover);\n}\n\n.tcw-replay-scrubber {\n appearance: none;\n -webkit-appearance: none;\n width: 220px;\n height: 4px;\n background: var(--tcw-border-strong);\n border-radius: 2px;\n outline: none;\n cursor: pointer;\n}\n\n.tcw-replay-scrubber::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n}\n\n.tcw-replay-scrubber::-moz-range-thumb {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n}\n\n.tcw-replay-progress {\n font-size: var(--tcw-font-size-xs);\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: var(--tcw-font-size-xs);\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-control-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/* === Responsive === */\n\n@media (max-width: 768px) {\n .tcw-toolbar {\n padding: 0 4px;\n height: max(44px, var(--tcw-toolbar-h)); /* Apple HIG minimum touch target */\n }\n .tcw-toolbar-sep {\n display: none;\n }\n .tcw-btn,\n .tcw-dropdown-trigger {\n height: max(40px, var(--tcw-control-h)); /* fatter tap target */\n padding: 0 12px;\n font-size: var(--tcw-font-size);\n }\n .tcw-btn-icon {\n width: max(40px, var(--tcw-control-h));\n height: max(40px, var(--tcw-control-h));\n }\n .tcw-sidebar {\n width: max(44px, var(--tcw-sidebar-w));\n }\n .tcw-sidebar-btn {\n width: max(40px, var(--tcw-control-h));\n height: max(40px, var(--tcw-control-h));\n }\n .tcw-modal {\n width: 94vw;\n border-radius: var(--tcw-dialog-radius);\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 top: auto;\n /* Above the on-screen keyboard (the widget sets it from visualViewport). */\n bottom: var(--tcw-keyboard-inset, 0px);\n padding-left: env(safe-area-inset-left, 0px);\n padding-right: env(safe-area-inset-right, 0px);\n left: 0;\n right: 0;\n transform: none;\n /* The border and the safe-area padding inside the screen's width. */\n box-sizing: border-box;\n width: 100vw;\n max-width: 100vw;\n /* Less the on-screen keyboard: a sheet's top never goes above the screen. */\n max-height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n max-height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 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 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 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 padding-bottom: max(14px, env(safe-area-inset-bottom));\n }\n\n /* Larger tap targets inside sheets: taller, not more padding, so a tab's text stays inside its chip. */\n .tcw-modal-tab {\n min-height: 40px;\n padding-inline: 16px;\n }\n .tcw-dropdown-item {\n padding: 12px 12px;\n font-size: var(--tcw-font-size-lg);\n }\n}\n\n/* === Price alerts panel === */\n\n.tcw-alerts-panel {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-end: 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: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\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: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-sm);\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: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent-ink);\n background: var(--tcw-accent);\n border: none;\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-sm);\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: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n font-variant-numeric: tabular-nums;\n}\n.tcw-alerts-row-note {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\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: var(--tcw-font-size-xs);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n padding: 2px 5px;\n border-radius: var(--tcw-tag-radius);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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 max-height: 40dvh;\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: var(--tcw-panel-top);\n inset-inline-end: 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-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\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: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-sm); 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: var(--tcw-font-size-sm);\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: var(--tcw-weight-strong); }\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: var(--tcw-font-size-xs);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\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: var(--tcw-panel-top);\n inset-inline-end: 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-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\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: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-xs);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\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: var(--tcw-font-size-sm); 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: var(--tcw-font-size-xs);\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: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text-dim);\n border-inline-start: 1px solid var(--tcw-border);\n border-inline-end: 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; max-height: 45dvh; 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/*\n * Placing a bracket: a strip at the foot of the chart, over its time axis\n * (30 px, the chart's TIME_AXIS_HEIGHT), clear of the tags along its top; its\n * name and Place in the side's colour. Centred by its margins, not a\n * transform: the entrance animation ends on `transform: none`, which left it\n * starting at the middle.\n */\n.tcw-bracket-bar {\n position: absolute;\n bottom: calc(30px + var(--tcw-space-5));\n inset-inline: 0;\n margin-inline: auto;\n box-sizing: border-box;\n width: max-content;\n max-width: calc(100% - 2 * var(--tcw-space-4));\n z-index: 45;\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n padding-block: var(--tcw-space-3);\n padding-inline: var(--tcw-space-5) var(--tcw-space-3);\n background: var(--tcw-bg-elevated);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-bracket-bar[data-side='buy'] { --tcw-side: var(--tcw-green); }\n.tcw-bracket-bar[data-side='sell'] { --tcw-side: var(--tcw-red); }\n/* The name gives way first: in German or Russian it would push Place off a phone. */\n.tcw-bracket-label {\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-side, var(--tcw-text));\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n/* The replay bar has the chart's foot while it shows: the bracket's goes to the top. */\n.tcw-chart-container:has(> .tcw-replay-bar) > .tcw-bracket-bar {\n top: var(--tcw-space-4);\n bottom: auto;\n}\n.tcw-bracket-hint {\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.tcw-bracket-cancel,\n.tcw-bracket-confirm {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: var(--tcw-space-3);\n height: var(--tcw-control-h);\n padding-inline: var(--tcw-space-5);\n border-radius: var(--tcw-control-radius);\n font: inherit;\n font-size: var(--tcw-font-size);\n white-space: nowrap;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-bracket-cancel {\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n background: transparent;\n color: var(--tcw-text);\n}\n.tcw-bracket-cancel:hover { background: var(--tcw-hover-bg); }\n/* The ground's own colour reads on the side's: dark on the dark theme's light greens, paper on the light theme's deep ones. */\n.tcw-bracket-confirm {\n border: none;\n background: var(--tcw-side, var(--tcw-accent));\n color: var(--tcw-bg);\n font-weight: var(--tcw-weight-strong);\n}\n.tcw-bracket-confirm:hover { background: color-mix(in srgb, var(--tcw-side, var(--tcw-accent)) 86%, var(--tcw-text)); }\n.tcw-bracket-cancel:focus-visible,\n.tcw-bracket-confirm:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n@media (max-width: 640px) {\n .tcw-bracket-bar {\n inset-inline: var(--tcw-space-4);\n width: auto;\n max-width: none;\n }\n .tcw-bracket-hint { display: none; }\n .tcw-bracket-label { margin-inline-end: auto; }\n .tcw-bracket-cancel,\n .tcw-bracket-confirm { height: 34px; }\n}\n\n@media (forced-colors: active) {\n .tcw-bracket-bar { border: 1px solid CanvasText; }\n .tcw-bracket-confirm { border: 1px solid ButtonText; }\n .tcw-bracket-cancel:focus-visible,\n .tcw-bracket-confirm:focus-visible { outline: 2px solid Highlight; }\n}\n\n/* === Drawing style + templates popover === */\n\n.tcw-style-panel {\n position: absolute;\n bottom: 12px;\n inset-inline-start: var(--tcw-panel-left);\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-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\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: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-style-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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-control-radius);\n color: var(--tcw-text-dim);\n cursor: pointer;\n font-size: var(--tcw-font-size-xs);\n}\n.tcw-style-width span { width: 16px; background: currentColor; border-radius: var(--tcw-radius-xs); }\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: var(--tcw-font-size-xs);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\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: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\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: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent-ink);\n background: var(--tcw-accent);\n border: none;\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-xs); 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: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n text-align: start;\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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: end;\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text-dim);\n}\n\n/* === Indicator settings dialog === */\n\n/* Narrow on a desktop; on a phone a sheet across the screen like every dialog. */\n@media (min-width: 641px) {\n .tcw-modal-narrow {\n max-width: 360px;\n }\n}\n.tcw-indi-input {\n width: 110px;\n height: 30px;\n padding: 0 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\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-select {\n width: 150px;\n padding-right: 4px;\n cursor: pointer;\n}\n/* A level: its value and a remove button. */\n.tcw-indi-level {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n.tcw-indi-remove {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-indi-remove:hover {\n color: var(--tcw-red);\n background: var(--tcw-hover-bg);\n}\n.tcw-indi-remove:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n.tcw-indi-add {\n margin-top: 8px;\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: var(--tcw-panel-top);\n inset-inline-end: 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-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\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: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-xs);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-sm);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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-group .tcw-tree-name {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: var(--tcw-weight-strong);\n}\n.tcw-tree-group .tcw-tree-name svg {\n flex: none;\n color: var(--tcw-text-muted);\n}\n.tcw-tree-member {\n margin-left: 14px;\n padding-left: 10px;\n border-inline-start: 1px solid var(--tcw-border-strong);\n border-radius: 0 var(--tcw-radius-sm) var(--tcw-radius-sm) 0;\n}\n.tcw-tree-rename {\n flex: 1;\n min-width: 0;\n padding: 3px 6px;\n border: 1px solid var(--tcw-accent-line);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-tree-rename:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n.tcw-tree-empty {\n padding: 8px;\n font-size: var(--tcw-font-size-sm);\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 max-height: 30dvh;\n }\n .tcw-tree-section:last-child {\n padding-bottom: max(6px, env(safe-area-inset-bottom));\n }\n}\n\n/* === Reduced motion === */\n\n@media (prefers-reduced-motion: reduce) {\n .tcw-root *,\n .tcw-root *::before,\n .tcw-root *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n\n /* Except the loader's slow glow (opacity only): without it a long wait\n looks frozen. */\n .tcw-root .tcw-loading-candle,\n .tcw-root .tcw-loading-track > span {\n animation-duration: 2.4s !important;\n animation-iteration-count: infinite !important;\n animation-delay: var(--tcw-delay, 0ms) !important;\n }\n}\n\n/* --- Drawing settings dialog --- */\n.tcw-drawing-text {\n min-height: 56px;\n resize: vertical;\n font-family: inherit;\n}\n/* The text a drawing writes takes the dialog's width, under its name. */\n.tcw-text-row {\n flex-direction: column;\n align-items: stretch;\n gap: var(--tcw-space-3);\n}\n.tcw-text-row .tcw-drawing-text { box-sizing: border-box; width: 100%; }\n.tcw-levels-editor { display: grid; gap: var(--tcw-space-3); }\n/* Two columns of levels on a desktop, as a Fibonacci tool has a dozen. */\n.tcw-levels-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--tcw-space-3) var(--tcw-space-6);\n max-height: 260px;\n overflow-y: auto;\n padding-inline-end: var(--tcw-space-1);\n}\n@media (max-width: 640px) {\n .tcw-levels-grid { grid-template-columns: minmax(0, 1fr); }\n}\n.tcw-level-row {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) auto auto;\n align-items: center;\n gap: var(--tcw-space-3);\n}\n.tcw-level-row .tcw-indi-input { box-sizing: border-box; width: 100%; min-width: 0; }\n.tcw-level-row input[type='checkbox'] { accent-color: var(--tcw-accent); }\n.tcw-level-remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: 0;\n border-radius: var(--tcw-radius-sm, 4px);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-level-remove:hover { color: var(--tcw-text); background: var(--tcw-bg-elevated); }\n.tcw-level-remove:focus-visible { outline: 2px solid var(--tcw-accent); outline-offset: 1px; }\n.tcw-level-add { justify-self: start; }\n\n/* --- Context menu (right-click on a drawing) --- */\n.tcw-context-menu {\n position: absolute;\n z-index: 70;\n min-width: 200px;\n /* Taller than the room (many templates, say), it scrolls. */\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: var(--tcw-menu-pad);\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n}\n.tcw-context-item {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n width: 100%;\n min-height: var(--tcw-menu-item-h);\n padding: var(--tcw-space-1) var(--tcw-space-4);\n border: 0;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size);\n text-align: start;\n cursor: pointer;\n}\n.tcw-context-item svg, .tcw-context-icon { flex: none; width: 14px; height: 14px; color: var(--tcw-text-muted); }\n.tcw-context-item:hover, .tcw-context-item:focus-visible { background: var(--tcw-hover-bg); outline: none; }\n.tcw-context-item:focus-visible { box-shadow: inset 0 0 0 1px var(--tcw-accent); }\n.tcw-context-danger, .tcw-context-danger svg { color: var(--tcw-red); }\n.tcw-context-sep { height: 1px; margin: var(--tcw-space-2) var(--tcw-space-4); background: var(--tcw-divider); }\n.tcw-context-label { flex: 1; min-width: 0; }\n/* A shortcut, and the mark of a submenu, at the row's end. */\n.tcw-context-key {\n flex: none;\n margin-inline-start: var(--tcw-space-5);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text-muted);\n}\n.tcw-context-item svg.tcw-context-more { width: 12px; height: 12px; }\n/* Right to left, a submenu opens to the left: its marks point there. */\n[dir='rtl'] .tcw-context-more, [dir='rtl'] .tcw-context-back > svg { transform: scaleX(-1); }\n/* No keyboard under a finger: the keys stay named to a screen reader only. */\n@media (hover: none) { .tcw-context-key { display: none; } }\n.tcw-context-item[aria-expanded='true'] { background: var(--tcw-hover-bg); }\n/* The choice made among radios: a dot where a switch has its tick. */\n.tcw-context-dot { display: grid; place-items: center; }\n.tcw-context-dot::after { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--tcw-text); }\n/* An entry that can be removed: its x on the row in hand, always on a touch screen. */\n.tcw-context-row { display: flex; align-items: center; border-radius: var(--tcw-menu-item-radius); }\n.tcw-context-row .tcw-context-item { flex: 1; min-width: 0; }\n.tcw-context-row:hover { background: var(--tcw-hover-bg); }\n.tcw-context-row:hover .tcw-context-item { background: transparent; }\n.tcw-context-remove {\n flex: none;\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n margin-inline-end: var(--tcw-space-1);\n border: 0;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-context-row:hover .tcw-context-remove, .tcw-context-row:focus-within .tcw-context-remove { opacity: 1; }\n.tcw-context-remove:hover { color: var(--tcw-red); background: var(--tcw-hover-bg); }\n@media (hover: none) { .tcw-context-remove { opacity: 1; } }\n/* --- Toolbar over a selected drawing --- */\n.tcw-sel-toolbar {\n position: absolute;\n z-index: 65;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 3px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-divider);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-family: var(--tcw-font);\n white-space: nowrap;\n animation: tcw-sel-in var(--tcw-dur-fast) var(--tcw-ease-out);\n}\n@keyframes tcw-sel-in { from { opacity: 0; transform: translateY(3px); } }\n.tcw-sel-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n min-width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n padding: 0 6px;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-sel-btn svg { flex: none; }\n.tcw-sel-btn:hover, .tcw-sel-btn[aria-expanded=\"true\"] { background: var(--tcw-hover-bg); color: var(--tcw-text); }\n.tcw-sel-btn:focus-visible, .tcw-sel-swatch:focus-visible, .tcw-sel-option:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--tcw-accent); }\n.tcw-sel-btn.tcw-sel-on { color: var(--tcw-accent); background: var(--tcw-accent-soft); }\n.tcw-sel-danger:hover { color: var(--tcw-red); background: var(--tcw-red-soft); }\n.tcw-sel-color {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tcw-text) 25%, transparent);\n}\n.tcw-sel-width {\n display: inline-block;\n width: 16px;\n height: var(--w, 1px);\n max-height: 6px;\n border-radius: 1px;\n background: currentColor;\n}\n.tcw-sel-sep { flex: none; width: 1px; height: 18px; margin: 0 3px; background: var(--tcw-divider); }\n.tcw-sel-pop {\n position: absolute;\n z-index: 66;\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 120px;\n padding: 4px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-divider);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-family: var(--tcw-font);\n}\n.tcw-sel-pop--color {\n display: grid;\n grid-template-columns: repeat(4, 24px);\n gap: 6px;\n min-width: 0;\n padding: 8px;\n}\n.tcw-sel-swatch {\n width: 24px;\n height: 24px;\n padding: 0;\n border: 0;\n border-radius: 50%;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tcw-text) 20%, transparent);\n cursor: pointer;\n transition: transform var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-sel-swatch:hover { transform: scale(1.1); }\n.tcw-sel-swatch.tcw-sel-on { box-shadow: 0 0 0 2px var(--tcw-bg-elevated), 0 0 0 4px var(--tcw-accent); }\n.tcw-sel-option {\n display: flex;\n align-items: center;\n gap: 10px;\n min-height: var(--tcw-menu-item-h);\n padding: 4px 10px;\n border: 0;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n text-align: start;\n cursor: pointer;\n}\n.tcw-sel-option:hover { background: var(--tcw-bg-surface); }\n.tcw-sel-option.tcw-sel-on { color: var(--tcw-accent); }\n@media (prefers-reduced-motion: reduce) {\n .tcw-sel-toolbar { animation: none; }\n .tcw-sel-swatch { transition: none; }\n}\n\n/* --- Account panel (positions, orders, history) --- */\n.tcw-account-dock {\n flex: none;\n}\n.tcw-account {\n display: flex;\n flex-direction: column;\n height: 220px;\n border-top: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n}\n.tcw-account-head {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 8px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n.tcw-account-tabs {\n display: flex;\n gap: 2px;\n flex: 1;\n min-width: 0;\n overflow-x: auto;\n}\n.tcw-account-tab {\n padding: 6px 10px;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n white-space: nowrap;\n cursor: pointer;\n}\n.tcw-account-tab:hover { color: var(--tcw-text); background: var(--tcw-hover-bg); }\n.tcw-account-tab[aria-selected=\"true\"] { color: var(--tcw-text); background: var(--tcw-active-bg); }\n.tcw-account-tab:focus-visible, .tcw-account-new:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--tcw-accent); }\n.tcw-account-new {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 10px;\n border: 1px solid var(--tcw-accent-line);\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-accent-soft);\n color: var(--tcw-accent);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n cursor: pointer;\n}\n.tcw-account-new:hover { background: var(--tcw-accent-glow); }\n.tcw-account-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n}\n.tcw-account-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n}\n.tcw-account-table th {\n position: sticky;\n top: 0;\n padding: 6px 10px;\n background: var(--tcw-bg-surface);\n color: var(--tcw-text-muted);\n font-weight: var(--tcw-weight);\n text-align: start;\n border-bottom: 1px solid var(--tcw-divider);\n}\n.tcw-account-table td {\n padding: 5px 10px;\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-divider);\n white-space: nowrap;\n}\n.tcw-account-table tr:hover td { background: var(--tcw-hover-bg); }\n.tcw-account-side { font-weight: var(--tcw-weight-strong); }\n.tcw-account-buy, .tcw-account-up { color: var(--tcw-green); }\n.tcw-account-sell, .tcw-account-down { color: var(--tcw-red); }\n.tcw-account-actions { display: flex; gap: 2px; }\n.tcw-account-empty, .tcw-account-summary {\n margin: 0;\n padding: 14px 12px;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-account-summary { padding: 8px 12px; color: var(--tcw-text-dim); }\n@media (max-width: 640px) {\n .tcw-account { height: 45vh; height: 45dvh; }\n}\n\n/* --- Named layouts --- */\n.tcw-layouts-btn { max-width: 190px; }\n.tcw-layouts-label {\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n.tcw-layouts-dirty {\n width: 6px;\n height: 6px;\n flex: none;\n border-radius: 50%;\n background: var(--tcw-accent);\n}\n.tcw-name-field { display: flex; flex-direction: column; gap: 6px; font-size: var(--tcw-font-size-sm); color: var(--tcw-text-dim); }\n.tcw-name-field .tcw-indi-input { width: 100%; height: 34px; font-size: var(--tcw-font-size); }\n\n/* --- Chart grid --- */\n.tcw-grid { background: var(--tcw-bg); }\n.tcw-grid-bar {\n display: flex;\n align-items: center;\n gap: 6px;\n min-height: calc(var(--tcw-control-h) + 8px);\n padding: 0 8px;\n border-bottom: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n overflow-x: auto;\n scrollbar-width: none;\n}\n.tcw-grid-bar::-webkit-scrollbar { display: none; }\n.tcw-grid-group { display: flex; align-items: center; gap: 2px; flex: none; }\n.tcw-grid-label {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-right: 4px;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n letter-spacing: var(--tcw-label-tracking);\n text-transform: var(--tcw-label-case);\n color: var(--tcw-text-muted);\n}\n.tcw-grid-sync[aria-pressed=\"true\"] { color: var(--tcw-accent); }\n.tcw-grid-cells {\n flex: 1;\n min-height: 0;\n display: grid;\n gap: 1px;\n background: var(--tcw-border);\n}\n.tcw-grid-cell {\n position: relative;\n min-width: 0;\n min-height: 0;\n background: var(--tcw-bg);\n}\n.tcw-grid-cell-active::after {\n content: '';\n position: absolute;\n inset: 0;\n border: 1px solid var(--tcw-accent);\n pointer-events: none;\n z-index: 5;\n}\n\n/* --- Host toolbar buttons --- */\n.tcw-toolbar-host { display: inline-flex; align-items: center; gap: 2px; }\n.tcw-toolbar-host:empty { display: none; }\n.tcw-host-btn { display: inline-flex; align-items: center; gap: 4px; }\n\n/* --- Host sidebar buttons, status bar items, and the layer over the chart --- */\n.tcw-sidebar-host { display: flex; flex-direction: column; align-items: center; }\n.tcw-sidebar-host:empty { display: none; }\n.tcw-status-host { display: flex; align-items: center; gap: 10px; min-width: 0; }\n.tcw-status-host:empty { display: none; }\n.tcw-status-host-item { white-space: nowrap; }\n.tcw-status-host-btn {\n margin: -4px -6px;\n padding: 4px 6px;\n font: inherit;\n color: inherit;\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-status-host-btn:hover { color: var(--tcw-text); background: var(--tcw-hover-bg); }\n.tcw-status-host-btn:focus-visible { outline: 2px solid var(--tcw-accent); outline-offset: -2px; }\n/* Over the plot and under the widget's own overlays; the pointer reaches the chart unless an element of yours takes it. */\n.tcw-host-layer { position: absolute; inset: 0; z-index: 2; pointer-events: none; }\n\n/* --- Pane buttons (move, fold, maximise) --- */\n.tcw-pane-controls {\n position: absolute;\n z-index: 4;\n display: flex;\n gap: 1px;\n transform: translateX(-100%);\n padding: 1px;\n border-radius: var(--tcw-radius-sm);\n background: color-mix(in srgb, var(--tcw-bg) 80%, transparent);\n opacity: 0.55;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-pane-controls:hover,\n.tcw-pane-controls:focus-within { opacity: 1; }\n.tcw-pane-btn {\n display: inline-grid;\n place-items: center;\n width: 18px;\n height: 16px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-pane-btn:hover { color: var(--tcw-text); background: var(--tcw-hover-bg); }\n.tcw-pane-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--tcw-accent-soft); }\n\n/* --- Typed interval --- */\n.tcw-interval-input {\n position: absolute;\n z-index: 20;\n left: 50%;\n top: 40%;\n transform: translate(-50%, -50%);\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 12px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-lg, 10px);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n.tcw-interval-field {\n width: 150px;\n height: 36px;\n padding: 0 10px;\n font: inherit;\n font-size: var(--tcw-font-size-xl);\n font-weight: var(--tcw-weight-strong);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-accent);\n border-radius: var(--tcw-input-radius);\n outline: none;\n}\n.tcw-interval-field[aria-invalid] { border-color: var(--tcw-red); }\n.tcw-interval-hint { font-size: var(--tcw-font-size-xs); color: var(--tcw-text-muted); max-width: 170px; }\n\n/* --- Alerts: lines, moves, bar close, expiry --- */\n.tcw-alerts-source { grid-column: auto; }\n.tcw-alerts-row-fields {\n grid-column: 1 / -1;\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 8px;\n}\n.tcw-alerts-row-fields[hidden] { display: none; }\n.tcw-alerts-row-fields > input[hidden] { display: none; }\n.tcw-alerts-row-fields:has(> input[hidden]) { grid-template-columns: 1fr; }\n.tcw-alerts-options { align-items: center; }\n.tcw-alerts-form .tcw-alerts-check {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-alerts-form .tcw-alerts-check input { width: auto; height: auto; }\n.tcw-alerts-form input[aria-invalid=\"true\"] { border-color: var(--tcw-red); }\n.tcw-alerts-row-meta { margin-top: 2px; font-size: var(--tcw-font-size-xs); color: var(--tcw-text-muted); }\n.tcw-alerts-expired { opacity: 0.6; }\n\n/* --- Signal marker note --- */\n.tcw-marker-tip {\n position: absolute;\n z-index: 12;\n pointer-events: none;\n padding: 6px 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-tooltip-radius);\n background: var(--tcw-tooltip-bg);\n color: var(--tcw-tooltip-fg);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.45;\n font-variant-numeric: tabular-nums;\n box-shadow: var(--tcw-menu-shadow);\n max-width: 240px;\n}\n.tcw-marker-tip strong { display: block; font-size: var(--tcw-font-size-sm); }\n\n/* === Navigation over the chart ===\n * Centred on the plot's bottom edge, shown while a mouse is over the chart. */\n.tcw-nav {\n position: absolute;\n z-index: 15;\n display: flex;\n gap: 2px;\n padding: 3px;\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: calc(var(--tcw-control-radius) + 3px);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n opacity: 0;\n pointer-events: none;\n transform: translate(-50%, calc(-100% - 12px));\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-nav.tcw-nav-shown {\n opacity: 1;\n pointer-events: auto;\n}\n.tcw-nav-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n cursor: pointer;\n touch-action: none;\n}\n.tcw-nav-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n.tcw-nav-btn:active {\n background: var(--tcw-active-bg);\n}\n.tcw-nav-btn:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n.tcw-nav-btn svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n@media (hover: none) {\n .tcw-nav { display: none; }\n}\n\n/* === Symbol info ===\n * Top left, beside the drawing tools: the panels on the right stay clear. */\n.tcw-syminfo {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-start: var(--tcw-panel-left);\n z-index: 38;\n width: 288px;\n max-height: calc(100% - var(--tcw-panel-top) - 12px);\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-syminfo-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 9px 12px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-syminfo-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-syminfo-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\n.tcw-syminfo-body,\n.tcw-syminfo-news {\n padding: 12px 14px;\n overflow-y: auto;\n}\n.tcw-syminfo-body {\n display: grid;\n gap: 10px;\n}\n.tcw-syminfo-symbol {\n font-size: var(--tcw-font-size-lg);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-syminfo-desc {\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-syminfo-meta {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n.tcw-syminfo-quote {\n display: flex;\n align-items: baseline;\n gap: 10px;\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n}\n.tcw-syminfo-price {\n font-size: var(--tcw-font-size-display);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-syminfo-change { font-size: var(--tcw-font-size-sm); }\n.tcw-syminfo-change.tcw-up { color: var(--tcw-green); }\n.tcw-syminfo-change.tcw-down { color: var(--tcw-red); }\n.tcw-syminfo-status {\n display: flex;\n align-items: center;\n gap: 7px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-syminfo-status::before,\n.tcw-status-market::before {\n content: '';\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n}\n.tcw-syminfo-status[data-state='open']::before,\n.tcw-syminfo-status[data-state='always']::before,\n.tcw-status-market[data-state='open']::before {\n background: var(--tcw-green);\n}\n.tcw-syminfo-stats {\n display: grid;\n gap: 4px;\n margin: 0;\n padding-top: 10px;\n border-top: 1px solid var(--tcw-divider);\n}\n.tcw-syminfo-stat {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-syminfo-stat dt { color: var(--tcw-text-muted); }\n.tcw-syminfo-stat dd {\n margin: 0;\n color: var(--tcw-text);\n text-align: end;\n font-variant-numeric: tabular-nums;\n overflow-wrap: anywhere;\n}\n.tcw-syminfo-news {\n border-top: 1px solid var(--tcw-divider);\n}\n.tcw-syminfo-news-title {\n margin-bottom: 8px;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text-muted);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n.tcw-syminfo-news-list {\n display: grid;\n gap: 10px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.tcw-syminfo-news-item {\n font-size: var(--tcw-font-size-sm);\n line-height: 1.4;\n color: var(--tcw-text);\n}\n.tcw-syminfo-news-item a {\n color: var(--tcw-text);\n text-decoration: none;\n}\n.tcw-syminfo-news-item a:hover { color: var(--tcw-accent); text-decoration: underline; }\n.tcw-syminfo-news-item a:focus-visible { outline: none; box-shadow: var(--tcw-ring); border-radius: var(--tcw-radius-xs); }\n.tcw-syminfo-news-meta,\n.tcw-syminfo-news-note {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n\n/* Numbers keep their sign on the left, and mixed text its own order, in a right-to-left widget too. */\n.tcw-watchlist-price,\n.tcw-watchlist-change,\n.tcw-syminfo-price,\n.tcw-syminfo-change {\n unicode-bidi: isolate;\n direction: ltr;\n}\n.tcw-syminfo-desc,\n.tcw-syminfo-meta,\n.tcw-syminfo-status,\n.tcw-syminfo-stat dd,\n.tcw-syminfo-news-meta {\n unicode-bidi: plaintext;\n}\n\n/* The market's status in the status bar. */\n.tcw-status-market {\n display: flex;\n align-items: center;\n gap: 7px;\n color: var(--tcw-text-muted);\n}\n\n@media (max-width: 640px) {\n .tcw-syminfo {\n top: auto;\n bottom: 0;\n left: 0;\n right: 0;\n width: 100vw;\n max-height: 70%;\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 0 0;\n }\n}\n\n/* === The look: how chosen controls show, floating bars, segmented intervals ===\n * Each switch sets variables on its own root, which its parts read: a grid's\n * look never reaches into a chart that has one of its own. */\n\n/* A chosen button (`ui.active`): a tinted fill (default), a solid pill, or an underline.\n * Dialog tabs are chips, or underlined in the underline look. Panels sit below the\n * toolbar and beside the drawing tools. */\n.tcw-root {\n --tcw-on-bg: var(--tcw-accent-soft);\n --tcw-on-fg: var(--tcw-accent);\n --tcw-on-ring: none;\n --tcw-on-icon-bg: var(--tcw-accent-soft);\n --tcw-on-icon-fg: var(--tcw-accent);\n --tcw-on-icon-ring: none;\n --tcw-tabs-pad-block: var(--tcw-space-4);\n --tcw-tab-h: var(--tcw-control-h);\n --tcw-tab-pad: 0 var(--tcw-space-5);\n --tcw-tab-line: 0px;\n --tcw-tab-radius: var(--tcw-control-radius);\n --tcw-tab-hover: var(--tcw-hover-bg);\n --tcw-tab-on-bg: var(--tcw-on-bg);\n --tcw-tab-on-fg: var(--tcw-on-fg);\n /* A menu's rows sit inside its padding with corners that follow its own: the menu's\n * corner less the padding between, so the two curves run parallel (Print: 5 - 3 = 2). */\n --tcw-menu-pad: var(--tcw-space-2);\n --tcw-menu-item-radius: max(0px, calc(var(--tcw-menu-radius) - var(--tcw-menu-pad)));\n --tcw-panel-top: calc(var(--tcw-toolbar-h) + var(--tcw-space-3));\n --tcw-panel-left: calc(var(--tcw-sidebar-w) + var(--tcw-space-5));\n}\n.tcw-root[data-tcw-active='solid'] {\n --tcw-on-bg: var(--tcw-text);\n --tcw-on-fg: var(--tcw-bg);\n --tcw-on-icon-bg: var(--tcw-text);\n --tcw-on-icon-fg: var(--tcw-bg);\n}\n/* Print picks a tool in ink blue on a tint: a solid square would outweigh the chart beside it. */\n.tcw-root[data-tcw-ui='print'][data-tcw-active='solid'] {\n --tcw-on-icon-bg: var(--tcw-accent-soft);\n --tcw-on-icon-fg: var(--tcw-accent);\n}\n.tcw-root[data-tcw-active='underline'] {\n --tcw-on-bg: var(--tcw-active-bg);\n --tcw-on-fg: var(--tcw-text);\n --tcw-on-ring: inset 0 -2px 0 var(--tcw-accent);\n --tcw-on-icon-bg: var(--tcw-active-bg);\n --tcw-on-icon-fg: var(--tcw-accent);\n --tcw-on-icon-ring: inset 2px 0 0 var(--tcw-accent);\n --tcw-tabs-pad-block: 0px;\n --tcw-tab-h: auto;\n --tcw-tab-pad: 11px 14px;\n --tcw-tab-line: 2px;\n --tcw-tab-radius: 0px;\n --tcw-tab-hover: transparent;\n --tcw-tab-on-bg: transparent;\n --tcw-tab-on-fg: var(--tcw-accent);\n}\n.tcw-root[data-tcw-toolbar='floating'] {\n --tcw-panel-top: calc(var(--tcw-toolbar-h) + 2 * var(--tcw-border-w) + 14px);\n}\n.tcw-root[data-tcw-sidebar='floating'] {\n --tcw-panel-left: calc(var(--tcw-sidebar-w) + 2 * var(--tcw-border-w) + 22px);\n}\n\n/* The toolbar as an island (`ui.toolbar: 'floating'`). */\n.tcw-root[data-tcw-toolbar='floating'] > .tcw-toolbar {\n margin: 8px 10px 0;\n padding-inline: calc(min(var(--tcw-toolbar-radius), var(--tcw-toolbar-h) / 2) / 2 + 8px);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-toolbar-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n/* The drawing tools as an island (`ui.sidebar: 'floating'`). */\n.tcw-root[data-tcw-sidebar='floating'] > .tcw-body > .tcw-sidebar {\n align-self: flex-start;\n max-height: calc(100% - 20px);\n margin: 10px 6px 10px 10px;\n padding-block: calc(min(var(--tcw-sidebar-radius), var(--tcw-sidebar-w) / 2) / 2 + 6px);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-sidebar-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n/* Frosted menus (`ui.blur` above 0): the chart shows through, blurred. */\n@supports (background: color-mix(in srgb, red 50%, transparent)) {\n .tcw-dropdown,\n .tcw-flyout,\n .tcw-context-menu {\n background: color-mix(in srgb, var(--tcw-bg-elevated) var(--tcw-surface-opacity), transparent);\n }\n}\n\n/* The interval buttons in one track (`ui.intervals: 'segmented'`). */\n.tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group {\n gap: 2px;\n margin: 0 4px;\n padding: 3px;\n border-radius: calc(var(--tcw-control-radius) + 3px);\n background: var(--tcw-hover-bg);\n}\n.tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group .tcw-btn {\n height: calc(var(--tcw-control-h) - 6px);\n padding: 0 9px;\n}\n\n/* Phones: the variants keep comfortable tap targets and room for the bar. */\n@media (max-width: 768px) {\n .tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group .tcw-btn {\n height: max(34px, calc(var(--tcw-control-h) - 6px));\n padding: 0 10px;\n }\n .tcw-root[data-tcw-toolbar='floating'] > .tcw-toolbar {\n margin: 6px 6px 0;\n padding-inline: 4px;\n }\n .tcw-root[data-tcw-sidebar='floating'] > .tcw-body > .tcw-sidebar {\n margin: 6px 4px 6px 6px;\n }\n}\n\n/* --- Phones and tablets --- */\n\n/* Taps without the grey flash or the double-tap zoom's wait. The chart area\n sets its own touch-action for its gestures. */\n.tcw-root {\n -webkit-tap-highlight-color: transparent;\n touch-action: manipulation;\n}\n\n/* iOS zooms the page into an input under 16 px when it takes focus. */\n@media (pointer: coarse) {\n .tcw-root input:not([type='color']):not([type='range']):not([type='checkbox']):not([type='radio']),\n .tcw-root select,\n .tcw-root textarea {\n font-size: max(16px, 1em);\n }\n}\n\n/* Sheets and lists scroll on their own, without dragging the page behind them. */\n.tcw-modal {\n overscroll-behavior: contain;\n}\n\n/* === The bars' newer parts ===\n * Interval sections and the chart type's icon, the Trade menu's button, undo\n * and redo off while idle, the tool menus' shortcuts and stars, the status\n * bar's clock and scale switches, and the grip of the selection toolbar. */\n\n/* The interval menu: each unit under its heading, a hairline between them. */\n.tcw-tf-section + .tcw-tf-section {\n margin-top: var(--tcw-space-2);\n padding-top: var(--tcw-space-1);\n border-top: 1px solid var(--tcw-divider);\n}\n\n/* The chart type: its icon alone, square. */\n.tcw-dropdown-trigger[data-role='charttype'] {\n justify-content: center;\n width: var(--tcw-control-h);\n padding: 0;\n}\n\n/* Undo and redo with nothing to do: there, quiet, not pressable. */\n.tcw-btn-icon:disabled {\n opacity: 0.35;\n cursor: default;\n background: transparent;\n color: var(--tcw-text-muted);\n}\n\n/* A tool menu's row: the tool, its shortcut, and a star beside it. */\n.tcw-flyout-row {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-1);\n}\n.tcw-flyout-row > .tcw-flyout-item {\n flex: 1;\n min-width: 0;\n}\n.tcw-flyout-name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.tcw-flyout-key {\n flex: none;\n margin-inline-start: var(--tcw-space-5);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n.tcw-flyout-pin {\n flex: none;\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n/* Shown on the row in hand; always for a pinned tool, filled in ink blue; always on a touch screen. */\n.tcw-flyout-row:hover .tcw-flyout-pin,\n.tcw-flyout-row:focus-within .tcw-flyout-pin,\n.tcw-flyout-pin[aria-pressed='true'],\n.tcw-root[data-tcw-narrow] .tcw-flyout-pin {\n opacity: 1;\n}\n@media (hover: none) {\n .tcw-flyout-pin {\n opacity: 1;\n }\n}\n.tcw-flyout-pin:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n.tcw-flyout-pin[aria-pressed='true'] {\n color: var(--tcw-accent);\n}\n.tcw-flyout-pin[aria-pressed='true'] svg path {\n fill: currentColor;\n}\n\n/* The clock: the time in figures, the zone beside it; it opens the zones. */\n.tcw-status-clock,\n.tcw-status-scale-btn {\n height: var(--tcw-control-h-sm);\n padding: 0 var(--tcw-space-3);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-status-clock {\n font-family: var(--tcw-font-mono);\n}\n.tcw-status-clock:hover,\n.tcw-status-scale-btn:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n.tcw-status-clock:focus-visible,\n.tcw-status-scale-btn:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n/* The scale switches: %, log, auto, in ink blue while on. */\n.tcw-status-scale {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-1);\n padding-inline-start: var(--tcw-space-3);\n border-inline-start: var(--tcw-sep-w) solid var(--tcw-border);\n}\n.tcw-status-scale-btn[aria-pressed='true'] {\n color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n/* A narrow widget keeps the range presets and the clock: the scale switches (also in the\n settings and the scale's menu) give them the room, and the connection's word is left to\n screen readers beside its dot. */\n.tcw-root[data-tcw-narrow] .tcw-status-scale {\n display: none;\n}\n.tcw-root[data-tcw-narrow] .tcw-status-indicator > span:not(.tcw-status-dot) {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n/* The selection toolbar's grip: dots to take it by. */\n.tcw-sel-grip {\n flex: none;\n width: var(--tcw-space-4);\n height: var(--tcw-control-h-sm);\n margin-inline: var(--tcw-space-1) var(--tcw-space-2);\n background-image: radial-gradient(circle, var(--tcw-text-muted) 1px, transparent 1.4px);\n background-size: 4px 4px;\n background-position: center;\n opacity: 0.7;\n cursor: grab;\n touch-action: none;\n}\n.tcw-sel-grip:active {\n cursor: grabbing;\n}\n\n/* --- A narrow widget (a phone, or a narrow column): data-tcw-narrow ---\n Set from the widget's own width, below 641px. The toolbar keeps the\n chart's own controls (symbol, interval, type, indicators) and puts the\n rest under \"more\"; the drawing tools wait behind a button over the chart;\n a grid shows one chart at a time, picked by its tab. */\n\n.tcw-toolbar-more,\n.tcw-sidebar-fab,\n.tcw-tf-current,\n.tcw-grid-tabs {\n display: none;\n}\n\n/* The toolbar fits itself too (on a tablet, a window half a screen wide):\n the right-hand buttons that don't fit fold under \"more\" (`--collapsed`\n shows it), and `--icons` drops the menus' labels and the interval buttons.\n Narrow folds them all. */\n.tcw-toolbar [data-tcw-folded],\n.tcw-root[data-tcw-narrow] > .tcw-toolbar .tcw-toolbar-overflow {\n display: none;\n}\n.tcw-toolbar--collapsed > .tcw-toolbar-more,\n.tcw-root[data-tcw-narrow] > .tcw-toolbar > .tcw-toolbar-more {\n display: inline-flex;\n margin-inline-start: auto;\n}\n.tcw-toolbar--icons.tcw-toolbar--tf-menu > .tcw-tf-group,\n.tcw-root[data-tcw-narrow] > .tcw-toolbar.tcw-toolbar--tf-menu > .tcw-tf-group {\n display: none;\n}\n.tcw-toolbar--icons .tcw-tf-more,\n.tcw-root[data-tcw-narrow] > .tcw-toolbar .tcw-tf-more {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 0 10px;\n}\n.tcw-toolbar--icons .tcw-tf-current,\n.tcw-root[data-tcw-narrow] > .tcw-toolbar .tcw-tf-current {\n display: inline;\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent);\n}\n.tcw-toolbar--icons .tcw-trigger-label,\n.tcw-root[data-tcw-narrow] > .tcw-toolbar .tcw-trigger-label {\n display: none;\n}\n\n/* The drawing tools lie over the chart when opened, from its edge. */\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar {\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n /* Under the toolbar (20), whose menus open over it. */\n z-index: 18;\n box-shadow: var(--tcw-menu-shadow);\n transform: translateX(-100%);\n visibility: hidden;\n transition: transform var(--tcw-dur-normal) var(--tcw-ease-out), visibility 0s linear var(--tcw-dur-normal);\n}\n.tcw-root[data-tcw-narrow][dir='rtl'] > .tcw-body > .tcw-sidebar {\n transform: translateX(100%);\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar.tcw-sidebar-open {\n transform: none;\n visibility: visible;\n transition: transform var(--tcw-dur-normal) var(--tcw-ease-out), visibility 0s;\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-flyout {\n z-index: 19;\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar-fab {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n inset-inline-start: 10px;\n /* Clear of the time axis. */\n bottom: 44px;\n z-index: 17;\n width: 44px;\n height: 44px;\n padding: 0;\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: 999px;\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text);\n box-shadow: var(--tcw-menu-shadow);\n cursor: pointer;\n transition: background var(--tcw-dur-fast), color var(--tcw-dur-fast), border-color var(--tcw-dur-fast);\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar-fab.tcw-active {\n background: var(--tcw-accent);\n border-color: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar-fab:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar-fab[aria-expanded='true'] {\n visibility: hidden;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar,\n .tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar.tcw-sidebar-open {\n transition: none;\n }\n}\n\n/* A narrow grid: one chart at a time, a tab for each. */\n.tcw-grid[data-tcw-narrow] > .tcw-grid-bar > .tcw-grid-tabs {\n display: flex;\n}\n.tcw-grid-tab {\n white-space: nowrap;\n}\n.tcw-grid-has-tabs[data-tcw-narrow] > .tcw-grid-cells {\n display: flex;\n flex-direction: column;\n}\n.tcw-grid-has-tabs[data-tcw-narrow] > .tcw-grid-cells > .tcw-grid-cell {\n flex: 1;\n}\n.tcw-grid-has-tabs[data-tcw-narrow] > .tcw-grid-cells > .tcw-grid-cell:not(.tcw-grid-cell-current) {\n display: none;\n}\n.tcw-grid-has-tabs[data-tcw-narrow] > .tcw-grid-cells > .tcw-grid-cell-active::after {\n display: none;\n}\n\n/* Phones: menus open as sheets from the bottom, in reach of a thumb and\n never off screen (a menu's own place may be off the side of a phone). */\n@media (max-width: 640px) {\n .tcw-dropdown,\n .tcw-context-menu {\n position: fixed !important;\n /* Above the on-screen keyboard (the indicators' search). */\n inset: auto 0 var(--tcw-keyboard-inset, 0px) 0 !important;\n margin: 0 !important;\n width: auto;\n max-width: none;\n max-height: 70vh !important;\n max-height: 70dvh !important;\n overflow-y: auto;\n overscroll-behavior: contain;\n z-index: 80;\n padding: 8px 8px calc(8px + env(safe-area-inset-bottom, 0px));\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 0 0;\n border-bottom: none;\n }\n .tcw-dropdown-item,\n .tcw-context-item {\n min-height: 44px;\n }\n}\n", It = "/* === Base controls: fields, selects, checks, sliders, calendar, scrollbars ===\n *\n * One look for every form control in the widget, from tokens. Fields are\n * quiet until used: a faint fill and hairline, a firmer line on hover, and\n * on focus the line turns accent (no ring). Selects and date fields open\n * the widget's own list and calendar (formControls.ts).\n */\n\n.tcw-root {\n color-scheme: dark;\n\n --tcw-field-bg: rgba(230, 227, 220, 0.04);\n --tcw-field-bg-hover: rgba(230, 227, 220, 0.06);\n --tcw-field-bg-focus: rgba(230, 227, 220, 0.03);\n --tcw-field-line: rgba(230, 227, 220, 0.12);\n --tcw-field-line-hover: rgba(230, 227, 220, 0.22);\n --tcw-field-line-focus: var(--tcw-accent-line);\n --tcw-field-placeholder: var(--tcw-text-muted);\n --tcw-check-line: rgba(230, 227, 220, 0.3);\n --tcw-scroll-thumb: rgba(230, 227, 220, 0.14);\n --tcw-scroll-thumb-hover: rgba(230, 227, 220, 0.26);\n /* Glyphs drawn in a field's background (a background image takes no currentColor). */\n --tcw-field-chevron: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.75l3 3 3-3' fill='none' stroke='%238c8a85' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n --tcw-field-calendar: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%238c8a85' stroke-width='1.3' stroke-linecap='round'%3E%3Crect x='2.5' y='3.5' width='11' height='10' rx='2'/%3E%3Cpath d='M2.5 6.5h11M5.5 2v3M10.5 2v3'/%3E%3C/g%3E%3C/svg%3E\");\n --tcw-check-mark: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.25l2.6 2.6L12 5.5' fill='none' stroke='%23131416' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n}\n\n.tcw-root[data-tcw-theme='light'] {\n color-scheme: light;\n\n /* Fields are white boxes on the paper, ruled in ink, as on a printed form. */\n --tcw-field-bg: #ffffff;\n --tcw-field-bg-hover: #ffffff;\n --tcw-field-bg-focus: #ffffff;\n --tcw-field-line: rgba(27, 29, 33, 0.16);\n --tcw-field-line-hover: rgba(27, 29, 33, 0.3);\n --tcw-check-line: rgba(27, 29, 33, 0.34);\n --tcw-scroll-thumb: rgba(27, 29, 33, 0.16);\n --tcw-scroll-thumb-hover: rgba(27, 29, 33, 0.3);\n --tcw-field-chevron: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.75l3 3 3-3' fill='none' stroke='%236c7077' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n --tcw-field-calendar: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%236c7077' stroke-width='1.3' stroke-linecap='round'%3E%3Crect x='2.5' y='3.5' width='11' height='10' rx='2'/%3E%3Cpath d='M2.5 6.5h11M5.5 2v3M10.5 2v3'/%3E%3C/g%3E%3C/svg%3E\");\n --tcw-check-mark: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.25l2.6 2.6L12 5.5' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n}\n\n/* --- Text, number, date and time fields, and selects --- */\n\n/* Fields speak the widget's type, not the browser's (a part's own font still wins). */\n:where(.tcw-root) :where(input, select, textarea, button) {\n font-family: inherit;\n font-weight: inherit;\n letter-spacing: inherit;\n}\n\n.tcw-root :is(\n .tcw-tf-custom-input,\n .tcw-settings-select,\n .tcw-settings-number,\n .tcw-goto-input,\n .tcw-watchlist-input,\n .tcw-indi-input,\n .tcw-style-name,\n .tcw-drawing-text,\n .tcw-replay-speed,\n .tcw-alerts-form input:not([type='checkbox']),\n .tcw-alerts-form select\n) {\n border: 1px solid var(--tcw-field-line);\n border-radius: var(--tcw-input-radius);\n background-color: var(--tcw-field-bg);\n color: var(--tcw-text);\n outline: none;\n box-shadow: none;\n transition:\n border-color var(--tcw-dur-fast) var(--tcw-ease),\n background-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-root :is(\n .tcw-tf-custom-input,\n .tcw-settings-select,\n .tcw-settings-number,\n .tcw-goto-input,\n .tcw-watchlist-input,\n .tcw-indi-input,\n .tcw-style-name,\n .tcw-drawing-text,\n .tcw-replay-speed,\n .tcw-alerts-form input:not([type='checkbox']),\n .tcw-alerts-form select\n):hover:not(:disabled, :focus) {\n border-color: var(--tcw-field-line-hover);\n background-color: var(--tcw-field-bg-hover);\n}\n\n.tcw-root :is(\n .tcw-tf-custom-input,\n .tcw-settings-select,\n .tcw-settings-number,\n .tcw-goto-input,\n .tcw-watchlist-input,\n .tcw-indi-input,\n .tcw-style-name,\n .tcw-drawing-text,\n .tcw-replay-speed,\n .tcw-alerts-form input:not([type='checkbox']),\n .tcw-alerts-form select\n):is(:focus, :focus-visible, [aria-expanded='true']) {\n border-color: var(--tcw-field-line-focus);\n background-color: var(--tcw-field-bg-focus);\n outline: none;\n box-shadow: none;\n}\n\n.tcw-root :is(\n .tcw-tf-custom-input,\n .tcw-indi-input,\n .tcw-watchlist-input,\n .tcw-goto-input,\n .tcw-alerts-form input\n):is([aria-invalid='true'], [aria-invalid='']):is(*, :hover, :focus) {\n /* As specific as the hover rule and later, so a wrong value stays red under the pointer and in focus. */\n border-color: var(--tcw-red);\n box-shadow: none;\n}\n\n.tcw-root :is(input, textarea)::placeholder {\n color: var(--tcw-field-placeholder);\n opacity: 1;\n}\n\n.tcw-root :is(input, select, textarea):disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Selects: the browser's arrow gives way to a fine chevron. */\n.tcw-root select:not([multiple]):not([size]) {\n appearance: none;\n -webkit-appearance: none;\n background-image: var(--tcw-field-chevron);\n background-repeat: no-repeat;\n background-size: 12px 12px;\n background-position: right 8px center;\n padding-inline-end: 26px;\n text-overflow: ellipsis;\n cursor: pointer;\n}\n\n.tcw-root[dir='rtl'] select:not([multiple]):not([size]),\n.tcw-root [dir='rtl'] select:not([multiple]):not([size]) {\n background-position: left 8px center;\n}\n\n/* Number fields: the steppers show only on a field in use. */\n.tcw-root input[type='number']::-webkit-inner-spin-button,\n.tcw-root input[type='number']::-webkit-outer-spin-button {\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-root input[type='number']:is(:hover, :focus)::-webkit-inner-spin-button {\n opacity: 0.55;\n}\n\n/* Date and time: the widget's calendar icon where the browser's own can be hidden. */\n@supports selector(::-webkit-calendar-picker-indicator) {\n .tcw-root input[type='date'] {\n background-image: var(--tcw-field-calendar);\n background-repeat: no-repeat;\n background-size: 15px 15px;\n background-position: right 8px center;\n padding-inline-end: 30px;\n cursor: text;\n }\n\n .tcw-root[dir='rtl'] input[type='date'],\n .tcw-root [dir='rtl'] input[type='date'] {\n background-position: left 8px center;\n }\n}\n\n.tcw-root input:is([type='date'], [type='time'])::-webkit-calendar-picker-indicator {\n display: none;\n}\n\n.tcw-root input:is([type='date'], [type='time'])::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n}\n\n/* --- Checkboxes and radios --- */\n\n.tcw-root input:is([type='checkbox'], [type='radio']) {\n appearance: none;\n -webkit-appearance: none;\n flex-shrink: 0;\n width: 16px;\n height: 16px;\n margin: 0;\n border: 1.5px solid var(--tcw-check-line);\n border-radius: var(--tcw-radius-sm);\n background: transparent center / 14px 14px no-repeat;\n cursor: pointer;\n vertical-align: middle;\n transition:\n border-color var(--tcw-dur-fast) var(--tcw-ease),\n background-color var(--tcw-dur-fast) var(--tcw-ease),\n box-shadow var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-root input[type='radio'] {\n border-radius: 50%;\n}\n\n.tcw-root input:is([type='checkbox'], [type='radio']):hover:not(:disabled) {\n border-color: var(--tcw-text-dim);\n}\n\n.tcw-root input[type='checkbox']:checked {\n border-color: var(--tcw-accent);\n background-color: var(--tcw-accent);\n background-image: var(--tcw-check-mark);\n}\n\n.tcw-root input[type='radio']:checked {\n border-color: var(--tcw-accent);\n background-image: radial-gradient(circle, var(--tcw-accent) 0 3.5px, transparent 4px);\n}\n\n.tcw-root input:is([type='checkbox'], [type='radio']):focus {\n outline: none;\n}\n\n.tcw-root input:is([type='checkbox'], [type='radio']):focus-visible {\n box-shadow: 0 0 0 3px var(--tcw-accent-soft);\n}\n\n/* --- Sliders --- */\n\n.tcw-root input[type='range'] {\n appearance: none;\n -webkit-appearance: none;\n height: 4px;\n border-radius: 999px;\n background: var(--tcw-field-line-hover);\n outline: none;\n cursor: pointer;\n}\n\n.tcw-root input[type='range']::-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 1px 3px rgba(0, 0, 0, 0.35);\n transition: transform var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-root input[type='range']::-moz-range-thumb {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n}\n\n.tcw-root input[type='range']:hover::-webkit-slider-thumb {\n transform: scale(1.12);\n}\n\n.tcw-root input[type='range']:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 4px var(--tcw-accent-soft);\n}\n\n/* --- The select list --- */\n\n.tcw-select-menu {\n z-index: 120;\n padding: var(--tcw-menu-pad);\n max-width: min(360px, calc(100vw - 16px));\n font-size: var(--tcw-font-size);\n}\n\n.tcw-select-group {\n padding: var(--tcw-space-4) var(--tcw-space-4) var(--tcw-space-2);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text-muted);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n.tcw-select-option {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-3);\n min-height: var(--tcw-menu-item-h);\n padding-block: 0;\n padding-inline: var(--tcw-space-3) var(--tcw-space-5);\n border-radius: var(--tcw-menu-item-radius);\n color: var(--tcw-text-dim);\n cursor: pointer;\n user-select: none;\n white-space: nowrap;\n}\n\n.tcw-select-option-text {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.tcw-select-check {\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n}\n\n.tcw-select-option.tcw-active {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-select-option[aria-selected='true'] {\n color: var(--tcw-text);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-select-option[aria-selected='true'] .tcw-select-check {\n background: var(--tcw-accent);\n -webkit-mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.25l3 3L12.5 5' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\") center / contain no-repeat;\n mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.25l3 3L12.5 5' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\") center / contain no-repeat;\n}\n\n.tcw-select-option[aria-disabled='true'] {\n opacity: 0.4;\n cursor: default;\n background: none;\n}\n\n/* --- The calendar --- */\n\n.tcw-calendar {\n z-index: 120;\n width: 268px;\n padding: 10px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n animation: tcw-pop-in var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n.tcw-calendar-head {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-bottom: 8px;\n}\n\n.tcw-calendar-title {\n flex: 1;\n text-align: center;\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n letter-spacing: -0.01em;\n}\n\n.tcw-calendar-nav {\n display: inline-grid;\n place-items: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-radius-sm);\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}\n\n.tcw-calendar-nav svg {\n width: 16px;\n height: 16px;\n fill: none;\n stroke: currentColor;\n stroke-width: 1.6;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.tcw-calendar[dir='rtl'] .tcw-calendar-nav svg,\n[dir='rtl'] .tcw-calendar-nav svg {\n transform: scaleX(-1);\n}\n\n.tcw-calendar-nav:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-calendar-weekdays,\n.tcw-calendar-grid {\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n}\n\n.tcw-calendar-weekdays {\n margin-bottom: 4px;\n padding: 3px 0;\n border-radius: var(--tcw-radius-sm);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-calendar-weekday {\n text-align: center;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text-muted);\n line-height: 20px;\n}\n\n.tcw-calendar-grid {\n row-gap: 2px;\n}\n\n.tcw-calendar-week {\n display: contents;\n}\n\n.tcw-calendar-day {\n position: relative;\n height: 32px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-calendar-day:hover:not(:disabled) {\n background: var(--tcw-hover-bg);\n}\n\n.tcw-calendar-day.tcw-outside {\n color: var(--tcw-text-muted);\n opacity: 0.55;\n}\n\n/* Today: accent figures over a short line. */\n.tcw-calendar-day.tcw-today {\n color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-calendar-day.tcw-today::after {\n content: '';\n position: absolute;\n left: 50%;\n bottom: 5px;\n width: 12px;\n height: 2px;\n margin-left: -6px;\n border-radius: 1px;\n background: currentColor;\n}\n\n.tcw-calendar-day[aria-selected='true'] {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n font-weight: var(--tcw-weight-strong);\n opacity: 1;\n}\n\n.tcw-calendar-day:disabled {\n opacity: 0.28;\n cursor: not-allowed;\n}\n\n.tcw-calendar-day:focus {\n outline: none;\n}\n\n.tcw-calendar-day:focus-visible {\n box-shadow: inset 0 0 0 1.5px var(--tcw-accent);\n}\n\n.tcw-calendar-foot {\n display: flex;\n justify-content: flex-end;\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--tcw-divider);\n}\n\n.tcw-calendar-today {\n height: 26px;\n padding: 0 10px;\n border: none;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-accent);\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n}\n\n.tcw-calendar-today:hover {\n background: var(--tcw-accent-soft);\n}\n\n.tcw-calendar-today:focus-visible,\n.tcw-calendar-nav:focus-visible {\n outline: none;\n box-shadow: inset 0 0 0 1.5px var(--tcw-accent);\n}\n\n/* --- Scrollbars: thin and rounded, a thumb on no track. Low specificity:\n a part that hides its bar keeps it hidden. --- */\n\n:where(.tcw-root) ::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\n\n:where(.tcw-root) ::-webkit-scrollbar-track,\n:where(.tcw-root) ::-webkit-scrollbar-corner {\n background: transparent;\n}\n\n:where(.tcw-root) ::-webkit-scrollbar-thumb {\n background: var(--tcw-scroll-thumb);\n background-clip: padding-box;\n border: 3px solid transparent;\n border-radius: 999px;\n}\n\n:where(.tcw-root) ::-webkit-scrollbar-thumb:hover {\n background: var(--tcw-scroll-thumb-hover);\n background-clip: padding-box;\n border: 2.5px solid transparent;\n}\n\n/* Engines without the pseudo-elements take the standard properties. */\n@supports not selector(::-webkit-scrollbar) {\n :where(.tcw-root, .tcw-root *) {\n scrollbar-width: thin;\n scrollbar-color: var(--tcw-scroll-thumb) transparent;\n }\n}\n\n/* --- Switches: flat, no glow --- */\n\n.tcw-root .tcw-toggle.tcw-on {\n box-shadow: none;\n}\n\n.tcw-root .tcw-toggle::after {\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);\n}\n\n.tcw-root .tcw-toggle:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--tcw-accent-soft);\n}\n\n/* One choice of a few in a row (a radio group): the chosen one as the look shows a chosen button. */\n.tcw-segmented {\n display: inline-flex;\n flex-wrap: wrap;\n max-width: 100%;\n gap: 2px;\n padding: 2px;\n border-radius: calc(var(--tcw-control-radius) + 2px);\n background: var(--tcw-hover-bg);\n}\n.tcw-segment {\n height: calc(var(--tcw-control-h) - 4px);\n padding-inline: var(--tcw-space-4);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n white-space: nowrap;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-segment:hover { color: var(--tcw-text); }\n.tcw-segment[aria-checked='true'] {\n background: var(--tcw-on-bg);\n color: var(--tcw-on-fg);\n font-weight: var(--tcw-weight-strong);\n box-shadow: var(--tcw-on-ring);\n}\n.tcw-segment:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* A number between a − and a +: one field, the figure right-aligned in the chart's mono type. */\n.tcw-stepper {\n box-sizing: border-box;\n display: inline-flex;\n align-items: stretch;\n height: var(--tcw-control-h);\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-bg);\n overflow: hidden;\n}\n.tcw-stepper:focus-within { box-shadow: var(--tcw-ring); }\n.tcw-stepper .tcw-indi-input {\n width: 110px;\n height: auto;\n padding-inline: var(--tcw-space-3);\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n text-align: end;\n -moz-appearance: textfield;\n appearance: textfield;\n}\n.tcw-stepper .tcw-indi-input::-webkit-inner-spin-button,\n.tcw-stepper .tcw-indi-input::-webkit-outer-spin-button { margin: 0; -webkit-appearance: none; }\n.tcw-stepper .tcw-indi-input:focus { outline: none; box-shadow: none; }\n.tcw-stepper-btn {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h);\n border: none;\n background: transparent;\n color: var(--tcw-text-dim);\n cursor: pointer;\n}\n.tcw-stepper-btn:hover { background: var(--tcw-hover-bg); color: var(--tcw-text); }\n.tcw-stepper-btn:focus-visible { outline: none; background: var(--tcw-hover-bg); color: var(--tcw-text); }\n\n/* Forced colours drop the box-shadow rings: an outline marks focus and the chosen choice. */\n@media (forced-colors: active) {\n .tcw-segment[aria-checked='true'] { outline: 2px solid Highlight; }\n .tcw-segment:focus-visible,\n .tcw-stepper-btn:focus-visible { outline: 2px solid Highlight; outline-offset: -2px; }\n .tcw-stepper:focus-within { outline: 2px solid Highlight; }\n}\n", Lt = "/* === The indicators dialog === */\n\n/* 610 wide, a Fibonacci number: the groups take 233 and the list 377 beside them (377 : 233 = phi).\n A fixed height, so the dialog keeps still while a search shortens the list. */\n.tcw-modal.tcw-ip {\n width: 610px;\n height: min(610px, 86vh);\n height: min(610px, 86dvh);\n max-height: none;\n}\n\n.tcw-ip-search,\n.tcw-ss-search {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-3);\n flex: none;\n height: var(--tcw-control-h);\n margin: var(--tcw-space-4) var(--tcw-space-6);\n padding: 0 var(--tcw-space-4);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text-muted);\n transition: border-color var(--tcw-dur-fast) var(--tcw-ease), box-shadow var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-ip-search:focus-within,\n.tcw-ss-search:focus-within {\n border-color: var(--tcw-accent);\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-ip-search svg,\n.tcw-ss-search svg {\n flex: none;\n}\n\n.tcw-ip-search input,\n.tcw-ss-search input {\n flex: 1;\n min-width: 0;\n height: 100%;\n border: none;\n outline: none;\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size);\n}\n\n.tcw-ip-search input::placeholder,\n.tcw-ss-search input::placeholder {\n color: var(--tcw-text-muted);\n}\n\n.tcw-ip-body {\n display: grid;\n grid-template-columns: 233px minmax(0, 1fr);\n flex: 1;\n min-height: 0;\n border-top: 1px solid var(--tcw-divider);\n}\n\n.tcw-ip-nav,\n.tcw-set-nav {\n display: flex;\n flex-direction: column;\n gap: 1px;\n padding: var(--tcw-space-4) var(--tcw-space-3);\n /* Logical sides: in Arabic, Hebrew or Persian the tabs sit on the right. */\n border-inline-end: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-surface);\n overflow-y: auto;\n border-end-start-radius: var(--tcw-dialog-radius);\n}\n\n.tcw-ip-tab,\n.tcw-set-tab {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-3);\n flex: none;\n height: var(--tcw-menu-item-h);\n padding: 0 var(--tcw-space-4);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size);\n text-align: start;\n white-space: nowrap;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-ip-tab svg,\n.tcw-set-tab svg {\n flex: none;\n}\n\n/* The kinds start below a gap: favourites and templates are yours, the rest the library's. */\n.tcw-ip-tab[data-view='all'] {\n margin-top: var(--tcw-space-4);\n}\n\n.tcw-ip-tab:hover,\n.tcw-set-tab:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-ip-tab.tcw-active,\n.tcw-set-tab.tcw-active {\n background: var(--tcw-on-bg);\n color: var(--tcw-on-fg);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-ip-nav--searching .tcw-ip-tab.tcw-active {\n background: transparent;\n color: var(--tcw-text-dim);\n font-weight: var(--tcw-weight);\n}\n\n.tcw-ip-list {\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: 0 var(--tcw-space-4) var(--tcw-space-5);\n}\n\n/* Each kind's name stays at the top while its indicators scroll under it. */\n.tcw-ip-heading {\n position: sticky;\n top: 0;\n z-index: 1;\n padding: var(--tcw-space-5) var(--tcw-space-4) var(--tcw-space-2);\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n.tcw-ip-list > :first-child:not(.tcw-ip-heading) {\n margin-top: var(--tcw-space-4);\n}\n\n.tcw-ip-row {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-1);\n border-radius: var(--tcw-menu-item-radius);\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-ip-row:hover {\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ip-add {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-3);\n flex: 1;\n min-width: 0;\n height: var(--tcw-menu-item-h);\n padding: 0 var(--tcw-space-4);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size);\n text-align: start;\n cursor: pointer;\n}\n\n.tcw-ip-add:focus-visible,\n.tcw-ip-aside:focus-visible,\n.tcw-ip-tab:focus-visible,\n.tcw-set-tab:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-ip-add svg {\n flex: none;\n color: var(--tcw-text-muted);\n}\n\n.tcw-ip-name {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-ip-short {\n flex: none;\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n}\n\n/* Where it draws, quietly at the row's end. */\n.tcw-ip-kind {\n flex: none;\n margin-inline-start: auto;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n/* How many are on the chart: ink on its wash, the figures in a column. */\n.tcw-ip-count {\n flex: none;\n display: inline-grid;\n place-items: center;\n min-width: var(--tcw-space-6);\n height: var(--tcw-space-6);\n padding: 0 var(--tcw-space-2);\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-accent-soft);\n color: var(--tcw-accent);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n}\n\n.tcw-ip-aside {\n flex: none;\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n/* Shown on the row in hand; always for a starred one, filled in ink; always on a touch screen. */\n.tcw-ip-row:hover .tcw-ip-aside,\n.tcw-ip-row:focus-within .tcw-ip-aside,\n.tcw-ip-star[aria-pressed='true'] {\n opacity: 1;\n}\n\n@media (hover: none) {\n .tcw-ip-aside {\n opacity: 1;\n }\n}\n\n.tcw-ip-aside:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ip-star[aria-pressed='true'] {\n color: var(--tcw-accent);\n}\n\n.tcw-ip-star[aria-pressed='true'] svg path {\n fill: currentColor;\n}\n\n.tcw-ip-remove:hover {\n color: var(--tcw-red);\n}\n\n.tcw-ip-save {\n flex: none;\n width: 100%;\n color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-ip-save svg {\n color: currentColor;\n}\n\n.tcw-ip-save:hover {\n background: var(--tcw-accent-soft);\n}\n\n.tcw-ip-empty {\n max-width: 34ch;\n padding: var(--tcw-space-6) var(--tcw-space-4);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.5;\n text-wrap: pretty;\n}\n\n/* Heard by a screen reader, not seen. */\n.tcw-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n/* A phone: the dialog is the widget's sheet, as tall as a sheet goes, and the groups a row of chips. */\n@media (max-width: 640px) {\n .tcw-modal.tcw-ip {\n /* Above the on-screen keyboard: the sheet's top stays on the screen. */\n height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n\n .tcw-ip-search,\n .tcw-ss-search {\n margin-inline: var(--tcw-space-4);\n }\n\n .tcw-ip-body {\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto minmax(0, 1fr);\n }\n\n .tcw-ip-nav,\n .tcw-set-nav {\n flex-direction: row;\n gap: var(--tcw-space-2);\n padding: var(--tcw-space-3) var(--tcw-space-4);\n border-inline-end: none;\n border-bottom: 1px solid var(--tcw-divider);\n border-radius: 0;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n }\n\n .tcw-ip-tab[data-view='all'] {\n margin-top: 0;\n margin-inline-start: var(--tcw-space-4);\n }\n\n .tcw-ip-tab,\n .tcw-set-tab {\n /* A finger's size, as the dialogs' other tabs on a phone. */\n min-height: 40px;\n border: var(--tcw-border-w) solid var(--tcw-border);\n }\n\n\n .tcw-ip-list {\n padding-inline: var(--tcw-space-3);\n }\n}\n\n/* === The indicator settings, and a drawing's === */\n\n/* One half step of phi under the indicators dialog: 610 / sqrt(phi) = 480. */\n@media (min-width: 641px) {\n .tcw-modal.tcw-modal-narrow.tcw-indi,\n .tcw-modal.tcw-modal-narrow.tcw-drawing-settings {\n width: 480px;\n max-width: 92vw;\n }\n}\n\n/* A line, or a kind of interval: ticked where it shows, its name, then what sets it. */\n.tcw-indi-plot-name {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-4);\n min-width: 0;\n cursor: pointer;\n}\n\n.tcw-indi-plot-name .tcw-settings-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Unticked, its name steps back. */\n.tcw-indi-plot-name:has(input:not(:checked)) .tcw-settings-label {\n color: var(--tcw-text-muted);\n}\n\n.tcw-indi-plot-controls,\n.tcw-indi-range {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-3);\n flex: none;\n}\n\n.tcw-indi-plot-controls .tcw-indi-select {\n width: 104px;\n}\n\n.tcw-indi-range {\n color: var(--tcw-text-muted);\n}\n\n.tcw-indi-range .tcw-indi-input {\n width: 68px;\n text-align: end;\n}\n\n.tcw-indi-range .tcw-indi-input:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n\n/* Defaults on the left; Cancel and Ok on the right, one height for all three. */\n.tcw-indi .tcw-modal-footer,\n.tcw-set .tcw-modal-footer,\n.tcw-drawing-settings .tcw-modal-footer {\n gap: var(--tcw-space-4);\n}\n\n.tcw-footer-end {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n}\n\n.tcw-indi .tcw-modal-footer button,\n.tcw-set .tcw-modal-footer button,\n.tcw-drawing-settings .tcw-modal-footer button {\n height: var(--tcw-menu-item-h);\n padding-block: 0;\n}\n\n.tcw-footer-menu,\n.tcw-footer-cancel {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-2);\n padding-inline: var(--tcw-space-5);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-footer-cancel {\n border-color: var(--tcw-border-strong);\n color: var(--tcw-text);\n}\n\n.tcw-footer-menu:hover,\n.tcw-footer-menu[aria-expanded='true'],\n.tcw-footer-cancel:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-footer-menu:focus-visible,\n.tcw-footer-cancel:focus-visible,\n.tcw-indi .tcw-done-btn:focus-visible,\n.tcw-set .tcw-done-btn:focus-visible,\n.tcw-drawing-settings .tcw-done-btn:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* A drawing's switches: the box, then its name, a list without rules between. */\n.tcw-check-row {\n justify-content: flex-start;\n gap: var(--tcw-space-4);\n padding-block: var(--tcw-space-3);\n cursor: pointer;\n}\n\n.tcw-settings-row + .tcw-check-row,\n.tcw-check-row + .tcw-settings-row {\n border-top: 0;\n}\n\n/* A point: its name, then its price, date and time in columns; on a phone the price over the date and time. */\n.tcw-draw-point {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) minmax(0, 1.3fr) minmax(0, 1fr);\n gap: var(--tcw-space-4);\n}\n\n.tcw-draw-point > .tcw-settings-label {\n white-space: nowrap;\n}\n\n.tcw-draw-point .tcw-indi-plot-controls {\n display: contents;\n}\n\n.tcw-draw-point input {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n}\n\n.tcw-draw-point input[type='number'] {\n text-align: end;\n}\n\n@media (max-width: 640px) {\n .tcw-draw-point {\n grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr);\n }\n\n .tcw-draw-point > .tcw-settings-label {\n grid-row: span 2;\n }\n\n .tcw-draw-point input[type='number'] {\n grid-column: span 2;\n }\n}\n\n.tcw-drawing-settings .tcw-indi-plot-controls input[type='number']:not(.tcw-draw-point *) {\n width: 68px;\n text-align: end;\n}\n\n/* The unit after a number (the fill's opacity in %). */\n.tcw-unit {\n margin-inline-start: calc(-1 * var(--tcw-space-2));\n color: var(--tcw-text-muted);\n}\n\n/* === The chart settings === */\n\n/* 776 x 610: half a step of phi wider than the indicators dialog (610 x sqrt(phi) = 776), as tall as it,\n so the dialog is a sqrt(phi) rectangle. The tabs take 233 down the side, as the indicator groups do. */\n.tcw-modal.tcw-set {\n width: 776px;\n max-width: 94vw;\n height: min(610px, 86vh);\n height: min(610px, 86dvh);\n max-height: none;\n}\n\n.tcw-set-body {\n display: grid;\n grid-template-columns: 233px minmax(0, 1fr);\n flex: 1;\n min-height: 0;\n}\n\n.tcw-set-panel {\n min-width: 0;\n}\n\n/* A phone: the widget's sheet across the screen, the tabs a row of chips over the settings. After the rules above, which it overrides. */\n@media (max-width: 640px) {\n .tcw-modal.tcw-set {\n width: 100vw;\n max-width: 100vw;\n /* Above the on-screen keyboard: the sheet's top stays on the screen. */\n height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n\n .tcw-set-body {\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto minmax(0, 1fr);\n }\n}\n\n/* === The symbol search, and the same dialog comparing === */\n\n/* As wide and as still as the indicators dialog: 610, a fixed height while a search shortens the list. */\n.tcw-modal.tcw-ss {\n width: 610px;\n height: min(610px, 86vh);\n height: min(610px, 86dvh);\n max-height: none;\n}\n\n/* Comparing: how the next symbol goes on the chart, under the search. */\n.tcw-ss-way {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n flex: none;\n margin: 0 var(--tcw-space-6) var(--tcw-space-4);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-ss-way > span {\n flex: none;\n}\n\n.tcw-root .tcw-ss-way-select {\n flex: 1;\n min-width: 0;\n height: var(--tcw-control-h);\n padding-block: 0;\n}\n\n/* The kinds the results come in: All, stock, crypto… */\n.tcw-ss-kinds {\n display: flex;\n flex-wrap: wrap;\n flex: none;\n gap: var(--tcw-space-3);\n margin: 0 var(--tcw-space-6) var(--tcw-space-4);\n}\n\n.tcw-ss-type {\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-5);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n text-transform: capitalize;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-ss-type:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-ss-type[aria-pressed='true'] {\n border-color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n color: var(--tcw-accent);\n}\n\n.tcw-ss-type:focus-visible,\n.tcw-ss-remove:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* The symbol takes 144 (89 x phi), the name the rest; kind and exchange at the end. The heads line up\n with the rows: the inset of what scrolls and the row's own. */\n.tcw-ss-columns,\n.tcw-ss-row {\n display: grid;\n grid-template-columns: 144px minmax(0, 1fr) auto;\n align-items: center;\n column-gap: var(--tcw-space-5);\n}\n\n.tcw-ss-columns {\n flex: none;\n padding: var(--tcw-space-3) calc(var(--tcw-space-4) * 2);\n border-top: 1px solid var(--tcw-divider);\n border-bottom: 1px solid var(--tcw-divider);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n/* What scrolls: what is compared, the symbols, a note when there are none. */\n.tcw-ss-results {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n /* A row the arrows reach scrolls in below its heading, not under it. */\n scroll-padding-block-start: calc(var(--tcw-space-5) + var(--tcw-space-2) + var(--tcw-font-size-xs) * 1.5 - var(--tcw-space-3));\n padding: var(--tcw-space-3) var(--tcw-space-4) var(--tcw-space-5);\n}\n\n.tcw-ss-row {\n min-height: var(--tcw-menu-item-h);\n padding: 0 var(--tcw-space-4);\n border-radius: var(--tcw-menu-item-radius);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-ss-row.tcw-selected {\n background: var(--tcw-hover-bg);\n}\n\n/* The figures of a ticker, in the mono face, left to right in any widget, at the start of its column;\n the chart's own in ink. */\n.tcw-ss-symbol {\n justify-self: start;\n max-width: 100%;\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-text);\n font-family: var(--tcw-font-mono);\n font-weight: var(--tcw-weight-strong);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-ss-row.tcw-current .tcw-ss-symbol {\n color: var(--tcw-accent);\n}\n\n.tcw-ss-symbol mark {\n background: transparent;\n color: var(--tcw-accent);\n}\n\n.tcw-ss-desc-cell {\n min-width: 0;\n}\n\n/* As wide as its words, at the start of the column, whichever way they run. */\n.tcw-ss-desc {\n display: block;\n width: fit-content;\n max-width: 100%;\n overflow: hidden;\n color: var(--tcw-text-dim);\n font-size: var(--tcw-font-size-sm);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-ss-meta {\n display: flex;\n align-items: baseline;\n gap: var(--tcw-space-4);\n justify-self: end;\n white-space: nowrap;\n}\n\n.tcw-ss-kind {\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n}\n\n.tcw-ss-exchange {\n color: var(--tcw-text-dim);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n/* The chart's symbol, or one on it already: a check after the exchange. */\n.tcw-ss-row:has(.tcw-ss-check) {\n grid-template-columns: 144px minmax(0, 1fr) auto auto;\n}\n\n.tcw-ss-check {\n display: inline-grid;\n place-items: center;\n color: var(--tcw-accent);\n}\n\n.tcw-ss-heading[hidden] {\n display: none;\n}\n\n/* \"On the chart\" and \"Symbols\", above their rows while they scroll. */\n.tcw-ss-heading {\n position: sticky;\n top: calc(var(--tcw-space-3) * -1);\n z-index: 1;\n padding: var(--tcw-space-5) var(--tcw-space-4) var(--tcw-space-2);\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n.tcw-ss-added-row {\n display: grid;\n grid-template-columns: 144px minmax(0, 1fr) auto;\n align-items: center;\n column-gap: var(--tcw-space-5);\n min-height: var(--tcw-menu-item-h);\n padding: 0 var(--tcw-space-4);\n border-radius: var(--tcw-menu-item-radius);\n}\n\n.tcw-ss-added-row:hover {\n background: var(--tcw-hover-bg);\n}\n\n/* How it is compared, after the line's colour where it has one of its own. */\n.tcw-ss-way-cell {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n min-width: 0;\n}\n\n.tcw-ss-swatch {\n flex: none;\n width: var(--tcw-space-4);\n height: var(--tcw-space-4);\n border-radius: var(--tcw-radius-sm);\n}\n\n.tcw-ss-way-label {\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-text-dim);\n font-size: var(--tcw-font-size-sm);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-ss-remove {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n\n.tcw-ss-remove:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-red);\n}\n\n.tcw-ss-empty {\n max-width: 44ch;\n padding: var(--tcw-space-6) var(--tcw-space-4);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.5;\n text-wrap: pretty;\n}\n\n/* The way the dialog opens too: a letter typed on the chart. */\n.tcw-ss-foot {\n flex: none;\n padding: var(--tcw-space-5) var(--tcw-space-6);\n border-top: 1px solid var(--tcw-divider);\n border-radius: 0 0 var(--tcw-dialog-radius) var(--tcw-dialog-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n text-align: center;\n}\n\n/* === Go to === */\n\n/* 377: the step of phi under the search dialogs. */\n@media (min-width: 641px) {\n .tcw-modal.tcw-goto {\n width: 377px;\n }\n}\n\n.tcw-goto-form {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n\n.tcw-goto-fields {\n display: grid;\n gap: var(--tcw-space-5);\n padding: var(--tcw-space-6) var(--tcw-space-6) var(--tcw-space-4);\n}\n\n/* The date takes the room; the time 144 beside it; a range's end named above its two. */\n.tcw-goto-row {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 144px;\n gap: var(--tcw-space-3) var(--tcw-space-4);\n align-items: center;\n}\n\n.tcw-goto-label {\n grid-column: 1 / -1;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n.tcw-root .tcw-goto-input {\n width: 100%;\n min-width: 0;\n height: var(--tcw-control-h);\n box-sizing: border-box;\n padding: 0 var(--tcw-space-4);\n font-size: var(--tcw-font-size);\n font-variant-numeric: tabular-nums;\n}\n\n/* No time on daily bars: the date across the row. */\n.tcw-goto-input[type='date']:last-child {\n grid-column: 1 / -1;\n}\n\n/* The month under the fields, part of the dialog: no card of its own. */\n.tcw-calendar.tcw-goto-calendar {\n position: static;\n width: auto;\n padding: var(--tcw-space-4) var(--tcw-space-6) var(--tcw-space-5);\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n animation: none;\n}\n\n.tcw-goto-calendar .tcw-calendar-day {\n height: 34px;\n}\n\n.tcw-goto .tcw-modal-footer {\n justify-content: flex-end;\n gap: var(--tcw-space-4);\n}\n\n.tcw-goto .tcw-modal-footer button {\n height: var(--tcw-menu-item-h);\n padding-block: 0;\n}\n\n.tcw-goto .tcw-done-btn:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* A phone: both are the widget's sheet; the search as tall as a sheet goes, its symbols 89 wide. */\n@media (max-width: 640px) {\n .tcw-modal.tcw-ss {\n /* Above the on-screen keyboard: the sheet's top stays on the screen. */\n height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n\n .tcw-ss-way,\n .tcw-ss-kinds {\n margin-inline: var(--tcw-space-4);\n }\n\n .tcw-ss-columns,\n .tcw-ss-row,\n .tcw-ss-added-row {\n grid-template-columns: 89px minmax(0, 1fr) auto;\n }\n\n .tcw-ss-row:has(.tcw-ss-check) {\n grid-template-columns: 89px minmax(0, 1fr) auto auto;\n }\n\n .tcw-ss-kind {\n display: none;\n }\n\n .tcw-ss-row,\n .tcw-ss-added-row {\n min-height: 44px;\n }\n}\n\n/* Without a keyboard there are no letters to type on the chart. */\n@media (hover: none) and (pointer: coarse) {\n .tcw-ss-foot {\n display: none;\n }\n}\n\n/* === The shortcut sheet === */\n\n/* As wide and as still as the indicators dialog: 610, a fixed height while a search shortens the list. */\n.tcw-modal.tcw-hotkey-sheet {\n width: 610px;\n height: min(610px, 86vh);\n height: min(610px, 86dvh);\n max-height: none;\n}\n\n.tcw-hotkey-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: 0 var(--tcw-space-6) var(--tcw-space-5);\n border-top: 1px solid var(--tcw-divider);\n columns: 2;\n column-gap: var(--tcw-space-7);\n}\n\n/* A group keeps together in its column, its name above its rows. */\n.tcw-hotkey-group {\n break-inside: avoid;\n padding-top: var(--tcw-space-5);\n}\n\n.tcw-hotkey-heading {\n padding-bottom: var(--tcw-space-3);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n/* What it does on the left, its keys on the right, the keys in a column of their own. */\n.tcw-hotkey-row {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--tcw-space-4);\n min-height: calc(var(--tcw-space-6) + var(--tcw-space-3));\n padding: var(--tcw-space-2) 0;\n}\n\n.tcw-hotkey-label {\n min-width: 0;\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.4;\n}\n\n.tcw-hotkey-keys {\n display: inline-flex;\n align-items: baseline;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: var(--tcw-space-2);\n flex: none;\n max-width: 55%;\n}\n\n/* A key: its name in the mono face on a key's face. */\n.tcw-hotkey-key,\n.tcw-cp-key {\n display: inline-block;\n min-width: calc(var(--tcw-space-6) - var(--tcw-space-2));\n padding: 0 var(--tcw-space-3);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-bottom-width: 2px;\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text-dim);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.6;\n text-align: center;\n white-space: nowrap;\n}\n\n/* A gesture is not a key: its words, quieter. */\n.tcw-hotkey-gesture {\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n white-space: nowrap;\n}\n\n.tcw-hotkey-sep {\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n}\n\n.tcw-hotkey-empty {\n padding: var(--tcw-space-6) 0;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n}\n\n/* How to open it again, at its foot. */\n.tcw-hotkey-foot {\n flex: none;\n padding: var(--tcw-space-5) var(--tcw-space-6);\n border-top: 1px solid var(--tcw-divider);\n border-radius: 0 0 var(--tcw-dialog-radius) var(--tcw-dialog-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n}\n\n/* === The command palette === */\n\n/* 610 wide, a third of the way down: a launcher, not a form; its search is the dialogs' search row. */\n.tcw-modal.tcw-cp {\n top: 19.1%;\n transform: translate(-50%, 0);\n width: 610px;\n max-height: min(610px, 76.4vh);\n max-height: min(610px, 76.4dvh);\n animation: none;\n}\n\n.tcw-cp .tcw-cp-search {\n margin-top: var(--tcw-space-5);\n}\n\n.tcw-cp-results {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n /* A row the arrows reach scrolls in below its group's heading, not under it. */\n scroll-padding-block-start: calc(var(--tcw-space-5) + var(--tcw-space-2) + var(--tcw-font-size-xs) * 1.5);\n padding: 0 var(--tcw-space-4) var(--tcw-space-4);\n border-top: 1px solid var(--tcw-divider);\n}\n\n.tcw-cp-heading {\n position: sticky;\n top: 0;\n z-index: 1;\n padding: var(--tcw-space-5) var(--tcw-space-4) var(--tcw-space-2);\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n.tcw-cp-row {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n min-height: var(--tcw-menu-item-h);\n padding: 0 var(--tcw-space-4);\n border-radius: var(--tcw-menu-item-radius);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size);\n cursor: pointer;\n}\n\n.tcw-cp-row.tcw-selected {\n background: var(--tcw-hover-bg);\n}\n\n.tcw-cp-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* What is on now: its name in ink, a check at the end. */\n.tcw-cp-row.tcw-on .tcw-cp-label {\n color: var(--tcw-accent);\n}\n\n.tcw-cp-check {\n display: inline-grid;\n place-items: center;\n flex: none;\n color: var(--tcw-accent);\n}\n\n.tcw-cp-empty {\n padding: var(--tcw-space-6) var(--tcw-space-4);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n}\n\n/* === Layouts === */\n\n/* 480, as the settings of an indicator: a list of names and when they were saved. On a phone, the sheet's width. */\n.tcw-modal.tcw-layouts-dialog {\n max-height: min(610px, 86vh);\n max-height: min(610px, 86dvh);\n}\n@media (min-width: 641px) {\n .tcw-modal.tcw-layouts-dialog { width: 480px; }\n}\n\n.tcw-layouts-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: var(--tcw-space-3) var(--tcw-space-4) var(--tcw-space-5);\n border-top: 1px solid var(--tcw-divider);\n}\n\n.tcw-layouts-list {\n display: flex;\n flex-direction: column;\n gap: var(--tcw-space-1);\n}\n\n.tcw-layouts-row {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-2);\n padding-inline-end: var(--tcw-space-3);\n border-radius: var(--tcw-menu-item-radius);\n}\n\n.tcw-layouts-row:hover,\n.tcw-layouts-row:focus-within {\n background: var(--tcw-hover-bg);\n}\n\n/* A column for the check of the one open, so every name starts at the same place. */\n.tcw-layouts-open {\n display: grid;\n grid-template-columns: var(--tcw-space-5) minmax(0, 1fr);\n column-gap: var(--tcw-space-3);\n align-items: center;\n flex: 1;\n min-width: 0;\n padding: var(--tcw-space-3) var(--tcw-space-4);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n text-align: start;\n cursor: pointer;\n}\n\n.tcw-layouts-open:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-layouts-name,\n.tcw-layouts-meta {\n grid-column: 2;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-layouts-name {\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-layouts-meta {\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n}\n\n.tcw-layouts-check {\n display: inline-grid;\n place-items: center;\n grid-column: 1;\n grid-row: 1 / span 2;\n color: var(--tcw-accent);\n}\n\n.tcw-layouts-open[aria-current='true'] .tcw-layouts-name {\n color: var(--tcw-accent);\n}\n\n/* Rename and delete show on the row in hand; always on a touch screen. */\n.tcw-layouts-row .tcw-account-actions {\n display: flex;\n gap: var(--tcw-space-1);\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-layouts-row:is(:hover, :focus-within) .tcw-account-actions,\n.tcw-layouts-row .tcw-account-actions:has(.tcw-layouts-confirm) {\n opacity: 1;\n}\n\n@media (hover: none) {\n .tcw-layouts-row .tcw-account-actions {\n opacity: 1;\n }\n}\n\n.tcw-layouts-confirm {\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-4);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-red);\n /* White on the red in every theme. */\n color: #fff;\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n}\n\n.tcw-layouts-confirm:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* A phone: the sheets as tall as they go, the shortcuts in one column. */\n@media (max-width: 640px) {\n .tcw-modal.tcw-hotkey-sheet {\n height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n\n .tcw-hotkey-body {\n columns: 1;\n padding-inline: var(--tcw-space-4);\n }\n\n /* Their own heights outrank the sheet's: give them back its height, less the keyboard, and the palette its slide up. */\n .tcw-modal.tcw-cp,\n .tcw-modal.tcw-layouts-dialog {\n max-height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n max-height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n\n .tcw-modal.tcw-cp {\n top: auto;\n transform: none;\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\n }\n\n .tcw-cp .tcw-cp-search {\n margin-top: var(--tcw-space-3);\n }\n\n :is(.tcw-hotkey-search, .tcw-cp-search, .tcw-layouts-search-row) {\n margin-inline: var(--tcw-space-4);\n }\n\n .tcw-cp-row {\n min-height: 44px;\n }\n}\n\n/* === The order ticket === */\n\n/* 480, as a drawing's settings: the side, the order, its stop and target, then the receipt. On a phone, the sheet's width. */\n.tcw-modal.tcw-order-ticket {\n max-height: min(610px, 92vh);\n max-height: min(610px, 92dvh);\n}\n@media (min-width: 641px) {\n .tcw-modal.tcw-order-ticket { width: 480px; }\n}\n.tcw-order-ticket[data-side='buy'] { --tcw-side: var(--tcw-green); }\n.tcw-order-ticket[data-side='sell'] { --tcw-side: var(--tcw-red); }\n\n.tcw-ticket-heading {\n display: flex;\n align-items: baseline;\n gap: var(--tcw-space-4);\n min-width: 0;\n}\n.tcw-ticket-symbol {\n overflow: hidden;\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size);\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.tcw-ticket-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n/* Buy and Sell: the chosen one filled with its colour, the ground's own colour on it. */\n.tcw-ticket-side {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: var(--tcw-space-3);\n margin-bottom: var(--tcw-space-4);\n}\n.tcw-ticket-side-btn {\n height: 34px;\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size-lg);\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-ticket-side-btn:hover { color: var(--tcw-text); }\n.tcw-ticket-buy[aria-pressed='true'] { border-color: var(--tcw-green); background: var(--tcw-green); color: var(--tcw-bg); }\n.tcw-ticket-sell[aria-pressed='true'] { border-color: var(--tcw-red); background: var(--tcw-red); color: var(--tcw-bg); }\n.tcw-ticket-side-btn:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n\n/* A row's control goes under its name when they don't fit side by side (a long choice at 320 px). */\n.tcw-ticket-row {\n flex-wrap: wrap;\n gap: var(--tcw-space-3) var(--tcw-space-5);\n}\n.tcw-ticket-market {\n color: var(--tcw-text-dim);\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n}\n\n/* A stop or a target: its switch, its name with how far it is under it, then its price. */\n.tcw-ticket-optional {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--tcw-space-4);\n}\n.tcw-ticket-optional-name {\n display: flex;\n flex-direction: column;\n gap: var(--tcw-space-1);\n min-width: 0;\n}\n.tcw-ticket-away {\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n overflow-wrap: anywhere;\n /* Left to right inside, but at the name's start in either direction (the column's, not its own). */\n align-self: flex-start;\n}\n\n/* The receipt: under a torn-paper rule, each sum a label and a figure in the mono type. */\n.tcw-ticket-summary:not(:empty) {\n display: grid;\n gap: var(--tcw-space-2);\n margin: 0 var(--tcw-space-6) var(--tcw-space-4);\n padding-top: var(--tcw-space-4);\n border-top: var(--tcw-border-w) dashed var(--tcw-border-strong);\n}\n.tcw-ticket-summary-row {\n display: flex;\n justify-content: space-between;\n gap: var(--tcw-space-5);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-ticket-figure {\n color: var(--tcw-text);\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n}\n.tcw-ticket-figure.tcw-ticket-up { color: var(--tcw-green); }\n.tcw-ticket-figure.tcw-ticket-down { color: var(--tcw-red); }\n\n.tcw-ticket-problems {\n padding: 0 var(--tcw-space-6) var(--tcw-space-4);\n color: var(--tcw-red);\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-ticket-problems p { margin: var(--tcw-space-1) 0; }\n\n/* Cancel and Place alone, at the end, as tall as each other. */\n.tcw-order-ticket .tcw-modal-footer { justify-content: flex-end; }\n.tcw-order-ticket .tcw-modal-footer button { height: var(--tcw-menu-item-h); padding-block: 0; }\n.tcw-ticket-place {\n height: var(--tcw-menu-item-h);\n padding-inline: var(--tcw-space-6);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-side, var(--tcw-accent));\n color: var(--tcw-bg);\n font: inherit;\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n}\n.tcw-ticket-place:hover:not(:disabled) { background: color-mix(in srgb, var(--tcw-side, var(--tcw-accent)) 86%, var(--tcw-text)); }\n.tcw-ticket-place:disabled { opacity: 0.45; cursor: not-allowed; }\n.tcw-ticket-place:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n\n/* A phone: the ticket is a sheet above the keyboard, its controls a finger's size. */\n@media (max-width: 640px) {\n .tcw-modal.tcw-order-ticket {\n max-height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n max-height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n .tcw-stepper .tcw-indi-input { width: 96px; }\n .tcw-stepper-btn, .tcw-segment { min-width: 34px; }\n .tcw-segment { height: 34px; }\n .tcw-stepper { height: 38px; }\n}\n\n/* Forced colours drop the box-shadow rings: an outline marks focus and the chosen side. */\n@media (forced-colors: active) {\n .tcw-ticket-side-btn[aria-pressed='true'] { outline: 2px solid Highlight; }\n .tcw-ticket-place { border: 1px solid ButtonText; }\n .tcw-ticket-side-btn:focus-visible,\n .tcw-ticket-place:focus-visible { outline: 2px solid Highlight; outline-offset: 2px; }\n}\n", Rt = "/* === The dock: the panels by the chart, and their rail === */\n\n/* In the body's row after the chart: the panel of the page open beside the chart, the rail at the outer edge\n (both mirror in a right-to-left widget). */\n.tcw-dock {\n position: relative;\n display: flex;\n flex: none;\n min-height: 0;\n}\n\n/* The rail: as wide as the drawing tools on the other side, its buttons as theirs. */\n.tcw-dock-rail {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--tcw-space-2);\n width: var(--tcw-sidebar-w);\n padding: var(--tcw-space-3) 0;\n border-inline-start: var(--tcw-border-w) solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n}\n\n.tcw-dock-btn {\n display: inline-grid;\n place-items: center;\n flex: none;\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-dock-btn svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n\n.tcw-dock-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n/* The page open: in ink on its wash, as a tool in use on the other side. */\n.tcw-dock-btn[aria-pressed='true'] {\n background: var(--tcw-on-icon-bg, var(--tcw-accent-soft));\n color: var(--tcw-on-icon-fg, var(--tcw-accent));\n}\n\n.tcw-dock-btn:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* The edge in focus shows as its line, in ink: a ring round a strip this thin reads as two lines. */\n.tcw-dock-resize:focus-visible {\n outline: none;\n}\n\n@media (forced-colors: active) {\n .tcw-dock-resize:is(:hover, :active, :focus-visible)::after {\n background: Highlight;\n }\n}\n\n/* The panel: 296 wide to start (377 / sqrt(phi)), from 233 to 377. */\n.tcw-dock-panel {\n position: relative;\n display: flex;\n flex-direction: column;\n width: var(--tcw-dock-w, 296px);\n min-height: 0;\n border-inline-start: var(--tcw-border-w) solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n}\n\n/* Its edge by the chart: a strip to drag, a line in ink while in hand. */\n.tcw-dock-resize {\n position: absolute;\n inset-block: 0;\n inset-inline-start: calc(var(--tcw-space-3) * -1);\n z-index: 3;\n width: calc(var(--tcw-space-3) * 2);\n cursor: col-resize;\n touch-action: none;\n}\n\n.tcw-dock-resize::after {\n content: '';\n position: absolute;\n inset-block: 0;\n inset-inline-start: calc(var(--tcw-space-3) - 1px);\n width: 2px;\n background: transparent;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-dock-resize:hover::after,\n.tcw-dock-resize:active::after,\n.tcw-dock-resize:focus-visible::after {\n background: var(--tcw-accent);\n}\n\n/* A page fills the panel and scrolls under its header; the floating panels it was lose their card. */\n.tcw-dock-panel > .tcw-dock-page {\n position: static;\n inset: auto;\n display: flex;\n flex-direction: column;\n flex: 1;\n width: auto;\n max-width: none;\n max-height: none;\n min-height: 0;\n margin: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n animation: none;\n}\n\n/* One header for every page: its title, its own buttons, and the close at the end. 34 tall (21 + 13). */\n.tcw-dock-page > :is(.tcw-watchlist-header, .tcw-alerts-header, .tcw-tree-header, .tcw-datawin-header, .tcw-syminfo-header) {\n position: sticky;\n top: 0;\n z-index: 2;\n display: flex;\n align-items: center;\n gap: var(--tcw-space-2);\n flex: none;\n min-height: calc(var(--tcw-space-6) + var(--tcw-space-5));\n margin: 0;\n padding-block: 0;\n padding-inline: var(--tcw-space-5) var(--tcw-space-3);\n border-bottom: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-dock-page > :is(.tcw-alerts-header, .tcw-tree-header, .tcw-datawin-header, .tcw-syminfo-header) > span:first-child {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-dock-page :is(.tcw-watchlist-add, .tcw-watchlist-close, .tcw-alerts-close, .tcw-tree-close, .tcw-datawin-close, .tcw-syminfo-close) {\n display: inline-grid;\n place-items: center;\n flex: none;\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n\n.tcw-dock-page :is(.tcw-watchlist-add, .tcw-watchlist-close, .tcw-alerts-close, .tcw-tree-close, .tcw-datawin-close, .tcw-syminfo-close):hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-dock-page :is(.tcw-watchlist-add, .tcw-watchlist-close, .tcw-alerts-close, .tcw-tree-close, .tcw-datawin-close, .tcw-syminfo-close):focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* What scrolled in a box of its own on a floating panel scrolls with the page here (a phone's caps too). */\n.tcw-dock-page :is(.tcw-alerts-list, .tcw-datawin-body, .tcw-watchlist-list, .tcw-tree-list) {\n max-height: none;\n overflow-y: visible;\n}\n\n.tcw-dock-page .tcw-watchlist-list {\n flex: 1;\n}\n\n/* The watchlist was a bar of its own: its width and shadow are the panel's now. */\n.tcw-dock-panel > .tcw-watchlist {\n width: auto;\n border-inline-start: none;\n box-shadow: none;\n overflow: hidden;\n}\n\n/* The symbol info's own padding sits under the header. */\n.tcw-dock-page.tcw-syminfo > .tcw-syminfo-body {\n padding: var(--tcw-space-5);\n}\n\n/* Narrow (a phone, a narrow column): no rail; the panel rises from the bottom over the chart, 61.8% tall. */\n.tcw-root[data-tcw-narrow] .tcw-dock-rail,\n.tcw-root[data-tcw-narrow] .tcw-dock-resize {\n display: none;\n}\n\n.tcw-root[data-tcw-narrow] .tcw-dock {\n position: static;\n}\n\n/* Above the chart's lines and tags, under its toasts; above the on-screen keyboard. */\n.tcw-root[data-tcw-narrow] .tcw-dock-panel {\n position: absolute;\n inset-inline: 0;\n bottom: var(--tcw-keyboard-inset, 0px);\n z-index: 38;\n width: auto;\n height: 61.8%;\n max-height: calc(100% - var(--tcw-keyboard-inset, 0px));\n border-inline-start: none;\n border-top: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 0 0;\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-dialog-shadow);\n padding-bottom: env(safe-area-inset-bottom, 0px);\n}\n\n.tcw-root[data-tcw-narrow] .tcw-dock-page > :is(.tcw-watchlist-header, .tcw-alerts-header, .tcw-tree-header, .tcw-datawin-header, .tcw-syminfo-header) {\n background: var(--tcw-bg-elevated);\n}\n\n/* The small buttons in a panel's rows: the browser's padding left their icons 8 px wide in a 20 px button. */\n:is(.tcw-tree-btn, .tcw-tree-add, .tcw-alerts-del, .tcw-watchlist-remove) {\n padding: 0;\n}\n\n:is(.tcw-tree-btn, .tcw-tree-add, .tcw-alerts-del, .tcw-watchlist-remove) svg {\n flex: none;\n}\n\n/* A page's title as the others': the watchlist's is its list's name, a menu. */\n.tcw-dock-page .tcw-watchlist-name {\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-3);\n margin-inline-start: calc(var(--tcw-space-3) * -1);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n text-transform: none;\n letter-spacing: normal;\n flex: 0 1 auto;\n}\n\n/* Its caret beside the name, the add and close buttons at the end. */\n.tcw-dock-page .tcw-watchlist-name::after {\n margin-inline-start: var(--tcw-space-3);\n}\n\n.tcw-dock-page .tcw-watchlist-add {\n margin-inline-start: auto;\n}\n", zt = /* @__PURE__ */ "toolbar,sidebar,statusBar,dock,alerts,objectTree,symbolInfo,symbolSearch,settings,indicatorSettings,drawingSettings,dataWindow,commandPalette,hotkeySheet,goToDate,replay,screenshot,copyImage,shareView,autoFib,themeToggle,fullscreen,accountPanel,orderTicket,bracketOrders,depthLadder,layouts,indicatorTemplates,compare,indicatorLegend,navigation,customTimeframes,intervalTyping,symbolTyping,dragDropImport,hotkeys,toasts,toolbar.symbol,toolbar.symbolInfo,toolbar.timeframes,toolbar.timeframeMenu,toolbar.chartType,toolbar.indicators,toolbar.layouts,toolbar.replay,toolbar.bracketOrders,toolbar.depthLadder,toolbar.accountPanel,toolbar.objectTree,toolbar.alerts,toolbar.screenshot,toolbar.settings,toolbar.themeToggle,toolbar.fullscreen,toolbar.compare,toolbar.undo,toolbar.redo,toolbar.trade,sidebar.cursor,sidebar.favorites,sidebar.lines,sidebar.fibonacci,sidebar.patterns,sidebar.forecasting,sidebar.annotation,sidebar.style,sidebar.magnet,sidebar.eraser,sidebar.zoomArea,sidebar.stayInDrawing,sidebar.undo,sidebar.redo,sidebar.clear,sidebar.lockAll,sidebar.hideAll,dock.watchlist,dock.alerts,dock.objectTree,dock.dataWindow,dock.symbolInfo,statusBar.range,statusBar.goToDate,statusBar.market,statusBar.connection,statusBar.symbol,statusBar.clock,statusBar.scale,statusBar.rangeTimeframe,indicatorLegend.values,indicatorLegend.visibility,indicatorLegend.settings,indicatorLegend.remove,indicatorLegend.more,pane.move,pane.collapse,pane.maximize,navigation.zoom,navigation.scroll,navigation.reset,menu.chart,menu.chart.alert,menu.chart.order,menu.chart.orderTicket,menu.chart.horizontalLine,menu.chart.resetView,menu.chart.drawings,menu.chart.exportData,menu.chart.settings,menu.chart.scale,menu.chart.goToDate,menu.chart.paneScale,menu.priceAxisAdd,menu.chart.indicators,menu.chart.timezone,menu.drawing,menu.drawing.settings,menu.drawing.alert,menu.drawing.order,menu.drawing.group,menu.drawing.lock,menu.drawing.hide,menu.drawing.duplicate,menu.drawing.delete,selectionToolbar,hotkeys.commandPalette,hotkeys.symbolSearch,hotkeys.save,hotkeys.tools,hotkeys.invertScale,hotkeys.goToDate,hotkeys.help,hotkeys.resetView".split(","), Bt = new Set(zt), Vt = {
|
|
1227
|
+
])], Ft = "/* === TradeCanvas Widget — Premium Styles === */\n\n/*\n * The HTML `hidden` attribute only sets `display: none` via the UA stylesheet,\n * which any author `display` rule (e.g. `.tcw-alerts-panel { display: flex }`)\n * silently overrides — leaving panels stuck open when JS sets `el.hidden = true`.\n * Force `hidden` to win for every namespaced widget element. Scoped to `tcw-`\n * so it never touches the host page.\n */\n[class^=\"tcw-\"][hidden],\n[class*=\" tcw-\"][hidden] {\n display: none !important;\n}\n\n/* Control tooltips (WidgetTooltip): quick to appear, slide in from the control. */\n.tcw-tooltip {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 60;\n max-width: 240px;\n padding: var(--tcw-space-3) var(--tcw-space-4);\n border-radius: var(--tcw-tooltip-radius);\n background: var(--tcw-tooltip-bg);\n color: var(--tcw-tooltip-fg);\n box-shadow: var(--tcw-tooltip-shadow);\n width: max-content;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n line-height: 1.35;\n overflow-wrap: anywhere;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transform: translate(var(--tcw-tip-dx, 0), var(--tcw-tip-dy, 0));\n transition:\n opacity 110ms var(--tcw-ease-out),\n transform 110ms var(--tcw-ease-out),\n visibility 0s linear 110ms;\n}\n\n.tcw-tooltip--visible {\n opacity: 1;\n visibility: visible;\n transform: none;\n transition:\n opacity 110ms var(--tcw-ease-out),\n transform 110ms var(--tcw-ease-out),\n visibility 0s;\n}\n\n/* The modal portal: carries the tokens and fonts, but no box of its own. */\n.tcw-root.tcw-portal {\n display: contents;\n}\n\n/* Fullscreen: the root fills the screen; the chart resizes with it. */\n.tcw-root:fullscreen {\n width: 100vw;\n height: 100vh;\n height: 100dvh;\n}\n\n.tcw-root {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n font-family: var(--tcw-font);\n font-feature-settings: 'cv11', 'ss01', 'ss03';\n font-size: var(--tcw-font-size);\n line-height: 1.4;\n color: #e6e3dc;\n background: #131416;\n font-variant-numeric: tabular-nums;\n position: relative;\n overflow: hidden;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n /* --- Dark theme tokens (default) ---\n * Print at night: warm ink on an off-black, never pure white on black, so\n * text doesn't glare. Grey for everything that is normal; colour only where\n * it means something. */\n --tcw-bg: #131416;\n --tcw-bg-surface: #131416;\n --tcw-bg-elevated: #1b1c1f;\n --tcw-bg-overlay: rgba(19, 20, 22, 0.6);\n --tcw-border: #2a2b2f;\n --tcw-border-strong: #3a3b40;\n /* Tooltips are the ink turned over: light on the dark ground. */\n --tcw-tooltip-bg: #e6e3dc;\n --tcw-tooltip-fg: #131416;\n --tcw-text: #e6e3dc;\n --tcw-text-dim: #a9a6a0;\n --tcw-text-muted: #8c8a85;\n\n /* Ink blue: links, focus and what you picked. --tcw-accent-ink is the text colour on an accent fill. */\n --tcw-accent: #7d9bff;\n --tcw-accent-hover: #98b0ff;\n --tcw-accent-ink: #131416;\n --tcw-accent-soft: rgba(125, 155, 255, 0.14);\n --tcw-accent-glow: rgba(125, 155, 255, 0.22);\n --tcw-accent-line: rgba(125, 155, 255, 0.55);\n\n --tcw-red: #e2706b;\n --tcw-red-soft: rgba(226, 112, 107, 0.12);\n --tcw-green: #4fae8a;\n --tcw-green-soft: rgba(79, 174, 138, 0.12);\n\n --tcw-hover-bg: rgba(230, 227, 220, 0.06);\n --tcw-active-bg: rgba(230, 227, 220, 0.1);\n --tcw-divider: rgba(230, 227, 220, 0.07);\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 /* Spacing: Fibonacci numbers, so each step is near φ times the one before. */\n --tcw-space-1: 2px;\n --tcw-space-2: 3px;\n --tcw-space-3: 5px;\n --tcw-space-4: 8px;\n --tcw-space-5: 13px;\n --tcw-space-6: 21px;\n --tcw-space-7: 34px;\n\n /* The look (UI system): Print's values. The `ui` option sets them inline. */\n --tcw-radius-xs: 1px;\n --tcw-radius-sm: 2px;\n --tcw-radius: 3px;\n --tcw-radius-lg: 5px;\n --tcw-radius-xl: 8px;\n --tcw-control-radius: var(--tcw-radius);\n --tcw-input-radius: var(--tcw-radius);\n --tcw-menu-radius: var(--tcw-radius-lg);\n --tcw-dialog-radius: var(--tcw-radius-xl);\n --tcw-panel-radius: var(--tcw-radius-lg);\n --tcw-tooltip-radius: var(--tcw-radius-sm);\n --tcw-tag-radius: var(--tcw-radius-sm);\n --tcw-toast-radius: var(--tcw-radius-lg);\n --tcw-toolbar-radius: 0px;\n --tcw-sidebar-radius: 0px;\n --tcw-toolbar-h: 42px;\n --tcw-control-h: 26px;\n --tcw-control-h-sm: 20px;\n --tcw-icon: 16px;\n --tcw-sidebar-w: 42px;\n --tcw-menu-item-h: 33px;\n --tcw-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n --tcw-font-size: 13px;\n --tcw-font-size-sm: 11px;\n --tcw-font-size-xs: 10px;\n --tcw-font-size-lg: 15px;\n --tcw-font-size-xl: 18px;\n --tcw-font-size-display: 21px;\n --tcw-weight: 400;\n --tcw-weight-strong: 600;\n --tcw-label-case: uppercase;\n --tcw-label-tracking: 0.06em;\n --tcw-border-w: 1px;\n --tcw-sep-w: 1px;\n --tcw-menu-shadow: 0 0 0 1px var(--tcw-border), var(--tcw-shadow-md);\n --tcw-dialog-shadow: 0 0 0 1px var(--tcw-border), var(--tcw-shadow-lg);\n --tcw-tooltip-shadow: var(--tcw-shadow-sm);\n --tcw-blur: 0px;\n --tcw-surface-opacity: 100%;\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(125, 155, 255, 0.5);\n\n /* Type */\n --tcw-font-mono: 'Cascadia Mono', 'SF Mono', ui-monospace, Menlo, Consolas, monospace;\n}\n\n/* Print by day: ink on paper. */\n.tcw-root[data-tcw-theme='light'] {\n color: #1b1d21;\n background: #fbfaf6;\n\n --tcw-bg: #fbfaf6;\n --tcw-bg-surface: #fbfaf6;\n --tcw-bg-elevated: #ffffff;\n --tcw-bg-overlay: rgba(251, 250, 246, 0.8);\n --tcw-border: #dcd8cf;\n --tcw-border-strong: #c7c2b7;\n --tcw-tooltip-bg: #1b1d21;\n --tcw-tooltip-fg: #fbfaf6;\n --tcw-text: #1b1d21;\n --tcw-text-dim: #4a4e57;\n --tcw-text-muted: #6c7077;\n\n /* A deeper ink blue: readable as text on paper, white text readable on it. */\n --tcw-accent: #2348c4;\n --tcw-accent-hover: #1b3a9f;\n --tcw-accent-ink: #ffffff;\n --tcw-accent-soft: rgba(35, 72, 196, 0.1);\n --tcw-accent-glow: rgba(35, 72, 196, 0.16);\n --tcw-accent-line: rgba(35, 72, 196, 0.45);\n --tcw-ring: 0 0 0 2px rgba(35, 72, 196, 0.4);\n\n /* Darker semantic colours: used as text on paper. */\n --tcw-red: #b8423f;\n --tcw-red-soft: rgba(184, 66, 63, 0.1);\n --tcw-green: #1f7a5c;\n --tcw-green-soft: rgba(31, 122, 92, 0.1);\n\n --tcw-hover-bg: rgba(27, 29, 33, 0.05);\n --tcw-active-bg: rgba(27, 29, 33, 0.08);\n --tcw-divider: #e7e3da;\n\n /* Warm shadows, as paper casts. */\n --tcw-shadow-sm: 0 1px 2px rgba(40, 34, 22, 0.06);\n --tcw-shadow-md: 0 4px 12px rgba(40, 34, 22, 0.08), 0 1px 3px rgba(40, 34, 22, 0.05);\n --tcw-shadow-lg: 0 12px 36px rgba(40, 34, 22, 0.13), 0 4px 12px rgba(40, 34, 22, 0.07);\n --tcw-shadow-xl: 0 24px 64px rgba(40, 34, 22, 0.17), 0 12px 24px rgba(40, 34, 22, 0.09);\n}\n\n/* === Toolbar === */\n\n.tcw-toolbar {\n display: flex;\n align-items: center;\n gap: 0;\n padding: 0 var(--tcw-space-4);\n height: var(--tcw-toolbar-h);\n border-bottom: var(--tcw-border-w) solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n flex-shrink: 0;\n position: relative;\n z-index: 20;\n}\n\n.tcw-toolbar-symbol {\n font-size: var(--tcw-font-size-lg);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n display: inline-flex;\n align-items: center;\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-4);\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-control-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/* With the symbol search switched off, the button only names the symbol. */\n.tcw-toolbar-symbol[aria-disabled=\"true\"] {\n cursor: default;\n}\n\n.tcw-toolbar-symbol[aria-disabled=\"true\"]:hover {\n background: transparent;\n}\n\n.tcw-toolbar-sep {\n width: var(--tcw-sep-w);\n /* A button's height over phi: the rule stands as tall as the icons beside it. */\n height: calc(var(--tcw-control-h) / 1.618);\n background: var(--tcw-border);\n flex-shrink: 0;\n margin: 0 var(--tcw-space-3);\n}\n\n.tcw-toolbar-group {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-1);\n padding: 0 var(--tcw-space-2);\n}\n\n.tcw-toolbar-spacer {\n flex: 1;\n}\n\n.tcw-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-4);\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight);\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-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-on-bg);\n color: var(--tcw-on-fg);\n font-weight: var(--tcw-weight-strong);\n box-shadow: var(--tcw-on-ring);\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: var(--tcw-control-h);\n height: var(--tcw-control-h);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-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 width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n\n.tcw-badge-count {\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n padding: 1px var(--tcw-space-3);\n border-radius: var(--tcw-tag-radius);\n font-family: var(--tcw-font-mono);\n}\n\n/* === Dropdown === */\n\n.tcw-dropdown-trigger {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-3);\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-4);\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight);\n font-family: inherit;\n border: none;\n border-radius: var(--tcw-control-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: var(--tcw-space-3);\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n z-index: 50;\n width: max-content;\n max-width: min(340px, calc(100vw - 16px));\n padding: var(--tcw-menu-pad);\n max-height: 420px;\n overflow-y: auto;\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\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 min-height: var(--tcw-menu-item-h);\n padding: var(--tcw-space-1) var(--tcw-space-4);\n font-size: var(--tcw-font-size);\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: start;\n border-radius: var(--tcw-menu-item-radius);\n gap: var(--tcw-space-5);\n}\n\n.tcw-dropdown-item:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n/* A menu row led by an icon (chart types): icon then label, not spread apart. */\n.tcw-dropdown-item--icon {\n justify-content: flex-start;\n gap: var(--tcw-space-4);\n}\n\n.tcw-dropdown-item svg,\n.tcw-flyout-item svg {\n flex-shrink: 0;\n}\n\n/* The drawing-group button's icon holder: a plain box for the swapped SVG. */\n.tcw-sidebar-icon {\n display: inline-flex;\n}\n\n.tcw-dropdown-item.tcw-active {\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n font-weight: var(--tcw-weight-strong);\n}\n\n/* Timeframe menu: pick on the left, pin (star) on the right. */\n.tcw-tf-more {\n padding: 0 5px;\n}\n\n.tcw-tf-more svg {\n display: block;\n}\n\n.tcw-tf-row {\n display: flex;\n align-items: center;\n gap: 2px;\n}\n\n.tcw-tf-row .tcw-dropdown-item {\n flex: 1;\n min-width: 0;\n}\n\n.tcw-tf-star {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-tf-star:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-tf-star.tcw-active {\n color: var(--tcw-accent);\n}\n\n.tcw-tf-star.tcw-active svg {\n fill: currentColor;\n}\n\n.tcw-tf-star:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-tf-remove {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-tf-row:hover .tcw-tf-remove,\n.tcw-tf-remove:focus-visible {\n opacity: 1;\n}\n\n/* No hover on touch screens: keep it visible rather than a hidden tap target. */\n@media (hover: none) {\n .tcw-tf-remove { opacity: 1; }\n}\n\n.tcw-tf-remove:hover {\n color: var(--tcw-red);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-tf-remove:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n/* Typed interval, under the list: stays in view while the list scrolls. */\n.tcw-tf-custom {\n position: sticky;\n bottom: -6px;\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin: 4px -6px -6px;\n padding: 6px 10px 8px;\n border-top: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-elevated);\n}\n\n.tcw-tf-custom-hint:empty {\n display: none;\n}\n\n.tcw-tf-custom-hint {\n flex-basis: 100%;\n width: 0;\n min-width: 100%;\n color: var(--tcw-red);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.35;\n}\n\n.tcw-tf-custom-input {\n flex: 1;\n /* Fills the row: its own width would follow the font (16px on touch). */\n width: 0;\n min-width: 0;\n height: 26px;\n padding: 0 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text);\n font: inherit;\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-tf-custom-input::placeholder {\n color: var(--tcw-text-dim);\n}\n\n.tcw-tf-custom-input:focus {\n outline: none;\n border-color: var(--tcw-accent);\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n\n.tcw-tf-custom-input[aria-invalid='true'] {\n border-color: var(--tcw-red);\n box-shadow: 0 0 0 2px var(--tcw-red-soft);\n}\n\n.tcw-tf-custom-add {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n flex-shrink: 0;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n cursor: pointer;\n}\n\n.tcw-tf-custom-add:hover {\n border-color: var(--tcw-accent);\n color: var(--tcw-accent);\n}\n\n.tcw-tf-custom-add:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: 1px;\n}\n\n.tcw-dropdown-label {\n text-transform: var(--tcw-label-case);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n letter-spacing: var(--tcw-label-tracking);\n padding: var(--tcw-space-4) var(--tcw-space-4) var(--tcw-space-2);\n font-weight: var(--tcw-weight-strong);\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: var(--tcw-font-size-xs);\n font-family: var(--tcw-font-mono);\n color: var(--tcw-text-muted);\n padding: 2px 6px;\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-hover-bg);\n letter-spacing: 0.02em;\n}\n\n/* === Body === */\n\n.tcw-body {\n position: relative;\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/* === History pill (older bars loading at the left edge) === */\n\n.tcw-history-pill {\n position: absolute;\n top: 50%;\n left: 10px;\n z-index: 4;\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 5px 10px 5px 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-shadow-sm);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n line-height: 1;\n white-space: nowrap;\n transform: translateY(-50%);\n opacity: 1;\n transition: opacity var(--tcw-dur-normal) var(--tcw-ease-out);\n pointer-events: none;\n}\n\n.tcw-history-pill--hidden {\n opacity: 0;\n}\n\n.tcw-history-pill--error {\n border-color: color-mix(in srgb, var(--tcw-red) 45%, var(--tcw-border));\n color: var(--tcw-red);\n}\n\n.tcw-history-spinner {\n width: 10px;\n height: 10px;\n border: 1.5px solid var(--tcw-accent-soft);\n border-top-color: var(--tcw-accent);\n border-radius: 50%;\n animation: tcw-history-spin 0.8s linear infinite;\n}\n\n.tcw-history-pill--error .tcw-history-spinner {\n border-color: currentColor;\n animation: none;\n}\n\n@keyframes tcw-history-spin {\n to { transform: rotate(360deg); }\n}\n\n/* === Loading overlay (candle skeleton) === */\n\n.tcw-loading-overlay {\n /* Uses a modifier class rather than the `hidden` attribute — the global\n `[hidden] { display: none !important }` rule above would cut the\n opacity transition off before it can play. */\n position: absolute;\n inset: 0;\n z-index: 5;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--tcw-bg);\n opacity: 1;\n transition: opacity var(--tcw-dur-slow) var(--tcw-ease-out);\n pointer-events: none;\n}\n\n.tcw-loading-overlay--hidden {\n opacity: 0;\n}\n\n.tcw-loading-card {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 14px;\n padding: 22px 26px 20px;\n border: 1px solid transparent;\n border-radius: var(--tcw-panel-radius);\n}\n\n/* A slow switch: the previous chart stays readable underneath, dimmed, so the\n click visibly registered without blanking the screen. */\n.tcw-loading-overlay--veil {\n background: color-mix(in srgb, var(--tcw-bg) 55%, transparent);\n}\n\n.tcw-loading-overlay--veil .tcw-loading-card {\n background: var(--tcw-bg-elevated);\n border-color: var(--tcw-border);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n.tcw-loading-candles {\n position: relative;\n display: flex;\n gap: 7px;\n height: 64px;\n}\n\n/* One candle: the element is the wick's column, ::before the wick, ::after the body. */\n.tcw-loading-candle {\n position: relative;\n width: 8px;\n height: 100%;\n color: var(--tcw-red);\n opacity: 0.28;\n animation: tcw-candle-light 1.6s var(--tcw-ease) infinite;\n animation-delay: var(--tcw-delay, 0ms);\n}\n\n.tcw-loading-candle--up { color: var(--tcw-green); }\n\n.tcw-loading-candle::before,\n.tcw-loading-candle::after {\n content: '';\n position: absolute;\n left: 50%;\n background: currentColor;\n transform: translateX(-50%);\n}\n\n.tcw-loading-candle::before {\n top: var(--tcw-wick-top);\n width: 1.5px;\n height: var(--tcw-wick-h);\n}\n\n.tcw-loading-candle::after {\n top: var(--tcw-body-top);\n width: 8px;\n height: var(--tcw-body-h);\n border-radius: 1.5px;\n}\n\n/* Each candle brightens and lifts slightly in turn, left to right. */\n@keyframes tcw-candle-light {\n 0%, 55%, 100% { opacity: 0.28; transform: translateY(0); }\n 20% { opacity: 1; transform: translateY(-2px); }\n}\n\n.tcw-loading-track {\n position: relative;\n width: 100%;\n min-width: 88px;\n height: 2px;\n border-radius: 1px;\n background: var(--tcw-border);\n overflow: hidden;\n}\n\n.tcw-loading-track > span {\n position: absolute;\n inset: 0;\n width: 40%;\n border-radius: 1px;\n background: linear-gradient(90deg, transparent, var(--tcw-accent), transparent);\n animation: tcw-loading-sweep 1.6s var(--tcw-ease) infinite;\n}\n\n@keyframes tcw-loading-sweep {\n from { transform: translateX(-100%); }\n to { transform: translateX(250%); }\n}\n\n/* The status text is announced, not shown — the candles say \"loading\". */\n.tcw-loading-label {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n.tcw-loading-overlay--error .tcw-loading-candles,\n.tcw-loading-overlay--error .tcw-loading-track {\n display: none;\n}\n\n/* A failure is shown: why the chart is empty and that a retry is running. */\n.tcw-loading-overlay--error .tcw-loading-label {\n position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip-path: none;\n white-space: normal;\n max-width: 320px;\n text-align: center;\n color: var(--tcw-red);\n font-size: var(--tcw-font-size);\n}\n\n/* Reduced motion: nothing slides or lifts, but the candles still glow in\n turn and the track breathes, so the wait never looks frozen. */\n@media (prefers-reduced-motion: reduce) {\n .tcw-loading-candle {\n animation: tcw-candle-glow 2.4s ease-in-out infinite;\n animation-delay: var(--tcw-delay, 0ms);\n }\n .tcw-loading-track > span {\n width: 100%;\n background: var(--tcw-accent);\n animation: tcw-loading-breathe 2.4s ease-in-out infinite;\n }\n}\n\n@keyframes tcw-candle-glow {\n 0%, 60%, 100% { opacity: 0.28; }\n 25% { opacity: 0.9; }\n}\n\n@keyframes tcw-loading-breathe {\n 0%, 100% { opacity: 0.15; }\n 50% { opacity: 0.7; }\n}\n\n/* === On-chart indicator legend (WidgetIndicatorLegend) === */\n\n.tcw-ind-legend {\n position: absolute;\n z-index: 3;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 1px;\n max-width: calc(100% - 140px);\n pointer-events: none;\n}\n\n.tcw-ind-legend--collapsed > .tcw-ind-legend-row {\n display: none;\n}\n\n.tcw-ind-legend-row {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n max-width: 100%;\n padding: 0 var(--tcw-space-2);\n border-radius: var(--tcw-radius-sm);\n /* The figures face at the size of the price legend above: one block, columns that line up. */\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n line-height: 19px;\n font-feature-settings: 'tnum';\n white-space: nowrap;\n color: var(--tcw-text-dim);\n pointer-events: auto;\n cursor: default;\n /* A narrow pane: the values shrink first, then the row is clipped. */\n overflow: hidden;\n}\n\n/* A pane's indicator: at the top of its pane, where the canvas title was,\n short enough to sit in the pane's header below the divider's grab zone. */\n.tcw-ind-legend-row--pane {\n position: absolute;\n z-index: 3;\n line-height: 15px;\n}\n\n.tcw-ind-legend-row:hover,\n.tcw-ind-legend-row:focus-within {\n background: color-mix(in srgb, var(--tcw-bg-elevated) 90%, transparent);\n box-shadow: 0 0 0 1px var(--tcw-border);\n}\n\n.tcw-ind-legend-name {\n padding: 0;\n border: none;\n background: none;\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n cursor: pointer;\n}\n\n.tcw-ind-legend-name:hover {\n color: var(--tcw-accent);\n}\n\n.tcw-ind-legend-values {\n display: inline-flex;\n gap: var(--tcw-space-4);\n min-width: 0;\n overflow: hidden;\n}\n\n.tcw-ind-legend-row--hidden .tcw-ind-legend-name,\n.tcw-ind-legend-row--hidden .tcw-ind-legend-values {\n opacity: 0.45;\n}\n\n/* Show / settings / remove: on hover or keyboard focus (always on touch). */\n.tcw-ind-legend-actions {\n display: none;\n gap: 1px;\n margin-left: -2px;\n}\n\n.tcw-ind-legend-row:hover .tcw-ind-legend-actions,\n.tcw-ind-legend-row:focus-within .tcw-ind-legend-actions {\n display: inline-flex;\n}\n\n@media (hover: none) {\n .tcw-ind-legend-actions {\n display: inline-flex;\n }\n\n /* Finger-sized targets. */\n .tcw-ind-legend-act,\n .tcw-ind-legend-toggle {\n min-width: 28px;\n min-height: 24px;\n }\n}\n\n.tcw-ind-legend-act {\n display: inline-grid;\n place-items: center;\n width: 20px;\n height: 18px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n\n.tcw-ind-legend-act:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ind-legend-act[data-act='remove']:hover {\n color: var(--tcw-red);\n}\n\n.tcw-ind-legend-toggle {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n margin-top: 1px;\n padding: 1px 5px;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n cursor: pointer;\n pointer-events: auto;\n}\n\n.tcw-ind-legend-toggle[hidden] {\n display: none;\n}\n\n.tcw-ind-legend-toggle:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ind-legend-name:focus-visible,\n.tcw-ind-legend-act:focus-visible,\n.tcw-ind-legend-toggle:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n/* === Sidebar === */\n\n.tcw-sidebar {\n width: var(--tcw-sidebar-w);\n flex-shrink: 0;\n background: var(--tcw-bg-surface);\n border-inline-end: var(--tcw-border-w) solid var(--tcw-border);\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: var(--tcw-space-3) 0;\n /* On a short screen the tools scroll; the menus sit outside it. */\n overflow-x: hidden;\n overflow-y: auto;\n scrollbar-width: none;\n}\n.tcw-sidebar::-webkit-scrollbar {\n display: none;\n}\n.tcw-sidebar > * {\n flex-shrink: 0;\n}\n\n.tcw-tool-group-wrap {\n position: relative;\n}\n\n.tcw-sidebar-btn {\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\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-control-radius);\n}\n\n.tcw-sidebar-btn svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\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-on-icon-fg);\n background: var(--tcw-on-icon-bg);\n box-shadow: var(--tcw-on-icon-ring);\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/* The drawing tools' sections: always a hairline (it groups the tools), even in\n looks that drop the rules between toolbar groups. */\n.tcw-sidebar-divider {\n width: 20px;\n height: max(1px, var(--tcw-sep-w));\n background: var(--tcw-divider);\n margin: 5px 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 margin-inline-start: 6px;\n overflow-y: auto;\n overscroll-behavior: contain;\n min-width: 180px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n z-index: 30;\n padding: var(--tcw-menu-pad);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n animation: tcw-slide-right var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n/* Spans the gap to the toolbar button: crossing it stays inside the menu. */\n.tcw-flyout::before {\n content: '';\n position: absolute;\n top: -1px;\n bottom: -1px;\n right: 100%;\n width: 8px;\n}\n\n@keyframes tcw-slide-right {\n from { opacity: 0; transform: translateX(-4px); }\n to { opacity: 1; transform: translateX(0); }\n}\n\n.tcw-flyout-header {\n text-transform: var(--tcw-label-case);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n letter-spacing: var(--tcw-label-tracking);\n padding: var(--tcw-space-3) var(--tcw-space-4) var(--tcw-space-2);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-flyout-hint {\n padding: var(--tcw-space-3) var(--tcw-space-4) var(--tcw-space-1);\n border-top: 1px solid var(--tcw-border);\n margin-top: var(--tcw-space-2);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n\n.tcw-flyout-item {\n min-height: var(--tcw-menu-item-h);\n padding: var(--tcw-space-1) var(--tcw-space-4);\n font-size: var(--tcw-font-size);\n color: var(--tcw-text-dim);\n cursor: pointer;\n width: 100%;\n display: flex;\n align-items: center;\n gap: 10px;\n border: none;\n background: transparent;\n text-align: start;\n font-family: inherit;\n border-radius: var(--tcw-menu-item-radius);\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.tcw-flyout-item:focus-visible {\n outline: none;\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n box-shadow: inset 0 0 0 1px var(--tcw-accent);\n}\n\n.tcw-flyout-item.tcw-active {\n color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n font-weight: var(--tcw-weight-strong);\n}\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(12, 12, 10, 0.42);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\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: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-dialog-radius);\n width: 520px;\n max-width: 92vw;\n max-height: 82vh;\n max-height: 82dvh;\n display: flex;\n flex-direction: column;\n box-shadow: var(--tcw-dialog-shadow);\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: var(--tcw-space-5) var(--tcw-space-6);\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n/* A dialog's title is phi times its text (21 to 13). */\n.tcw-modal-header h3 {\n font-size: var(--tcw-font-size-display);\n font-weight: var(--tcw-weight-strong);\n margin: 0;\n color: var(--tcw-text);\n letter-spacing: -0.015em;\n}\n\n.tcw-modal-close {\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\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-control-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 /* Four tabs in a long language on a phone: they wrap rather than clip. No overflow here: in the\n dialog's column it would let a long body squash the tabs, and clip the underline of the active one. */\n flex-wrap: wrap;\n flex-shrink: 0;\n gap: var(--tcw-space-2);\n padding: var(--tcw-tabs-pad-block) var(--tcw-space-6);\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n.tcw-modal-tab {\n flex-shrink: 0;\n white-space: nowrap;\n height: var(--tcw-tab-h);\n padding: var(--tcw-tab-pad);\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight);\n color: var(--tcw-text-muted);\n border: none;\n background: transparent;\n cursor: pointer;\n border-bottom: var(--tcw-tab-line) solid transparent;\n border-radius: var(--tcw-tab-radius);\n margin-bottom: calc(var(--tcw-tab-line) / -2);\n transition: color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n font-family: inherit;\n letter-spacing: -0.005em;\n}\n\n.tcw-modal-tab:hover {\n color: var(--tcw-text-dim);\n background: var(--tcw-tab-hover);\n}\n\n.tcw-modal-tab.tcw-active {\n color: var(--tcw-tab-on-fg);\n background: var(--tcw-tab-on-bg);\n border-bottom-color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-modal-body {\n padding: var(--tcw-space-6);\n overflow-y: auto;\n flex: 1;\n}\n\n.tcw-settings-section {\n margin-bottom: var(--tcw-space-6);\n}\n\n.tcw-settings-section:last-child {\n margin-bottom: 0;\n}\n\n.tcw-settings-section-title {\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n margin-bottom: var(--tcw-space-4);\n}\n\n.tcw-settings-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--tcw-space-4) 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: var(--tcw-font-size);\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: var(--tcw-radius-xs);\n}\n\n.tcw-color-hex {\n font-size: var(--tcw-font-size-xs);\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/* A colour left to the part itself: the swatch shows where the picker starts, faded. */\n.tcw-color-auto input[type='color'] {\n opacity: 0.45;\n border-style: dashed;\n}\n\n.tcw-color-auto .tcw-color-hex {\n font-family: inherit;\n font-style: italic;\n}\n\n.tcw-color-auto-btn {\n height: 24px;\n padding: 0 8px;\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n background: transparent;\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-radius-sm);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-color-auto-btn:hover,\n.tcw-color-auto-btn:focus-visible {\n color: var(--tcw-text);\n border-color: var(--tcw-accent);\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: var(--tcw-font-size-sm);\n font-family: inherit;\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-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: var(--tcw-space-5) var(--tcw-space-6);\n border-top: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-surface);\n border-radius: 0 0 var(--tcw-dialog-radius) var(--tcw-dialog-radius);\n}\n\n.tcw-reset-link {\n font-size: var(--tcw-font-size-sm);\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: var(--tcw-space-4) var(--tcw-space-6);\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n border: none;\n border-radius: var(--tcw-control-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}\n\n.tcw-done-btn:hover {\n background: var(--tcw-accent-hover);\n}\n\n.tcw-done-btn:disabled { opacity: 0.45; cursor: not-allowed; }\n\n.tcw-done-btn:active {\n transform: translateY(0.5px);\n}\n\n/* === Status Bar === */\n\n.tcw-statusbar {\n /* Above sidebar buttons that overflow a short chart; menus (z 30+) stay on top. */\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 7px 16px;\n border-top: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n flex-shrink: 0;\n font-feature-settings: 'tnum';\n}\n\n.tcw-status-right {\n display: flex;\n align-items: center;\n gap: 14px;\n margin-inline-start: auto;\n min-width: 0;\n white-space: nowrap;\n}\n\n/* Narrow screens: the range presets close up. */\n@media (max-width: 640px) {\n .tcw-range-btn {\n padding: 4px 5px;\n }\n}\n\n/* Range presets + go to date, bottom left */\n.tcw-range-bar {\n display: flex;\n align-items: center;\n gap: 1px;\n margin: -4px 12px -4px -8px;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n}\n\n.tcw-range-bar::-webkit-scrollbar {\n display: none;\n}\n\n.tcw-range-btn {\n flex-shrink: 0;\n padding: 4px 7px;\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n letter-spacing: 0.02em;\n color: var(--tcw-text-muted);\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-range-btn:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-range-btn:active {\n color: var(--tcw-accent);\n}\n\n.tcw-range-btn:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-range-goto {\n display: inline-grid;\n place-items: center;\n margin-inline-start: 6px;\n padding: 4px 6px;\n}\n\n.tcw-range-goto svg {\n display: block;\n}\n\n.tcw-status-indicator {\n display: flex;\n align-items: center;\n gap: 7px;\n font-weight: var(--tcw-weight);\n}\n\n.tcw-status-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n transition: background var(--tcw-dur-normal) var(--tcw-ease), box-shadow var(--tcw-dur-normal) var(--tcw-ease);\n position: relative;\n}\n\n.tcw-status-dot.tcw-connected {\n background: var(--tcw-green);\n box-shadow: 0 0 0 3px rgba(31, 168, 116, 0.18);\n}\n\n.tcw-status-dot.tcw-connected::after {\n content: '';\n position: absolute;\n inset: -3px;\n border-radius: 50%;\n border: 2px solid var(--tcw-green);\n opacity: 0;\n animation: tcw-pulse 2.2s ease-out 3;\n}\n\n@keyframes tcw-pulse {\n 0% { opacity: 0.6; transform: scale(0.6); }\n 100% { opacity: 0; transform: scale(2.2); }\n}\n\n.tcw-status-dot.tcw-error {\n background: var(--tcw-red);\n box-shadow: 0 0 0 3px rgba(232, 80, 91, 0.2);\n}\n\n/* === Watchlist === */\n\n.tcw-watchlist {\n width: 220px;\n flex-shrink: 0;\n background: var(--tcw-bg-surface);\n border-inline-start: 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 position: relative;\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 6px 8px 6px 8px;\n border-bottom: 1px solid var(--tcw-divider);\n}\n\n/* The shown list's name: opens the lists menu. */\n.tcw-watchlist-name {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 6px;\n height: var(--tcw-control-h-sm);\n padding: 0 6px;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n text-align: start;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n}\n.tcw-watchlist-name::after {\n content: '';\n flex: none;\n width: 0;\n height: 0;\n margin-inline-start: auto;\n border: 4px solid transparent;\n border-top-color: currentColor;\n border-bottom-width: 0;\n opacity: 0.7;\n}\n\n.tcw-watchlist-add {\n flex: none;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-lg);\n line-height: 1;\n cursor: pointer;\n}\n\n.tcw-watchlist-name:hover,\n.tcw-watchlist-add:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n.tcw-watchlist-name:focus-visible,\n.tcw-watchlist-add:focus-visible,\n.tcw-watchlist-input:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* The lists menu, under the header. */\n.tcw-watchlist-menu {\n top: calc(100% - 2px);\n left: 6px;\n right: 6px;\n margin-top: 0;\n}\n.tcw-watchlist-count {\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n}\n.tcw-watchlist-menu .tcw-danger {\n color: var(--tcw-red);\n}\n\n/* Naming a list in place. */\n.tcw-watchlist-input {\n flex: 1;\n min-width: 0;\n height: var(--tcw-control-h-sm);\n padding: 0 8px;\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-watchlist-empty {\n padding: 16px 14px;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.5;\n}\n\n/* A row's remove button shows on hover or focus, over its numbers. */\n.tcw-watchlist-remove {\n position: absolute;\n top: 50%;\n right: 6px;\n display: grid;\n place-items: center;\n width: 20px;\n height: 20px;\n border: 0;\n border-radius: var(--tcw-radius-sm);\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size);\n line-height: 1;\n opacity: 0;\n transform: translateY(-50%);\n cursor: pointer;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-watchlist-row:hover .tcw-watchlist-remove,\n.tcw-watchlist-row:focus-within .tcw-watchlist-remove {\n opacity: 1;\n}\n.tcw-watchlist-remove:hover {\n color: var(--tcw-red);\n}\n.tcw-watchlist-row.tcw-watchlist-dragging {\n opacity: 0.45;\n}\n\n.tcw-watchlist-list {\n flex: 1;\n overflow-y: auto;\n padding: 4px 0;\n}\n\n.tcw-watchlist-row {\n position: relative;\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-inline-start: 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-inline-start-color: var(--tcw-accent);\n}\n\n.tcw-watchlist-row.tcw-watchlist-active {\n background: var(--tcw-accent-soft);\n border-inline-start-color: var(--tcw-accent);\n}\n\n.tcw-watchlist-symbol {\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\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: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n font-weight: var(--tcw-weight);\n}\n\n.tcw-watchlist-change {\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n font-weight: var(--tcw-weight);\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/* === Toast === */\n\n.tcw-toast-icon {\n display: inline-flex;\n vertical-align: -2px;\n margin-inline-end: 7px;\n color: var(--tcw-accent);\n}\n.tcw-toast-error .tcw-toast-icon { color: var(--tcw-red); }\n\n/* Over an open dialog: above its backdrop, at the window's foot. */\n.tcw-toast.tcw-toast-over {\n position: fixed;\n z-index: 120;\n}\n\n.tcw-toast {\n position: absolute;\n bottom: 60px;\n left: 50%;\n transform: translate(-50%, 12px);\n z-index: 40;\n padding: var(--tcw-space-4) var(--tcw-space-5);\n background: var(--tcw-bg-elevated);\n border: 1px solid var(--tcw-border-strong);\n border-radius: var(--tcw-toast-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight);\n color: var(--tcw-text);\n opacity: 0;\n transition: opacity var(--tcw-dur-normal) var(--tcw-ease-out), transform var(--tcw-dur-normal) var(--tcw-ease-out);\n pointer-events: none;\n max-width: calc(100% - 32px);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n letter-spacing: -0.005em;\n}\n\n.tcw-toast.tcw-toast-in {\n opacity: 1;\n transform: translate(-50%, 0);\n}\n\n.tcw-toast-error {\n border-color: var(--tcw-red);\n color: var(--tcw-red);\n}\n\n/* === Replay scrubber === */\n\n/* Picking the replay start: the bars right of the pointer would be hidden. */\n.tcw-replay-shade {\n position: absolute;\n z-index: 4;\n pointer-events: none;\n background: color-mix(in srgb, var(--tcw-bg) 62%, transparent);\n border-inline-start: 1.5px dashed var(--tcw-accent);\n}\n\n.tcw-replay-group {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n\n.tcw-replay-group[hidden] { display: none; }\n\n.tcw-replay-hint {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 0 4px;\n color: var(--tcw-text-dim);\n white-space: nowrap;\n}\n\n.tcw-replay-text-btn {\n height: 26px;\n padding: 0 10px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-weight: var(--tcw-weight);\n white-space: nowrap;\n cursor: pointer;\n transition: background var(--tcw-dur-fast), border-color var(--tcw-dur-fast), color var(--tcw-dur-fast);\n}\n\n.tcw-replay-text-btn:hover { background: var(--tcw-hover-bg); border-color: var(--tcw-border-strong); }\n.tcw-replay-text-btn:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n\n/* At the last bar: the way out is the next thing to do. */\n.tcw-replay-bar--ended .tcw-replay-realtime {\n background: var(--tcw-accent);\n border-color: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n}\n\n.tcw-replay-btn:disabled { opacity: 0.4; cursor: default; }\n\n@media (max-width: 640px) {\n .tcw-replay-bar {\n flex-wrap: wrap;\n justify-content: center;\n max-width: calc(100% - 24px);\n border-radius: var(--tcw-panel-radius);\n }\n .tcw-replay-hint { white-space: normal; }\n}\n\n.tcw-replay-bar {\n position: absolute;\n left: 50%;\n /* Above the 30px time axis, so its dates stay readable. */\n bottom: 40px;\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: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n font-size: var(--tcw-font-size-sm);\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: var(--tcw-control-radius);\n cursor: pointer;\n font-family: inherit;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-replay-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-replay-btn.tcw-replay-play {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n width: 32px;\n height: 32px;\n box-shadow: 0 0 0 3px var(--tcw-accent-glow);\n}\n\n.tcw-replay-btn.tcw-replay-play:hover {\n background: var(--tcw-accent-hover);\n}\n\n.tcw-replay-scrubber {\n appearance: none;\n -webkit-appearance: none;\n width: 220px;\n height: 4px;\n background: var(--tcw-border-strong);\n border-radius: 2px;\n outline: none;\n cursor: pointer;\n}\n\n.tcw-replay-scrubber::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n}\n\n.tcw-replay-scrubber::-moz-range-thumb {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n box-shadow: 0 0 0 1px var(--tcw-accent), 0 2px 6px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n}\n\n.tcw-replay-progress {\n font-size: var(--tcw-font-size-xs);\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: var(--tcw-font-size-xs);\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-control-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/* === Responsive === */\n\n@media (max-width: 768px) {\n .tcw-toolbar {\n padding: 0 4px;\n height: max(44px, var(--tcw-toolbar-h)); /* Apple HIG minimum touch target */\n }\n .tcw-toolbar-sep {\n display: none;\n }\n .tcw-btn,\n .tcw-dropdown-trigger {\n height: max(40px, var(--tcw-control-h)); /* fatter tap target */\n padding: 0 12px;\n font-size: var(--tcw-font-size);\n }\n .tcw-btn-icon {\n width: max(40px, var(--tcw-control-h));\n height: max(40px, var(--tcw-control-h));\n }\n .tcw-sidebar {\n width: max(44px, var(--tcw-sidebar-w));\n }\n .tcw-sidebar-btn {\n width: max(40px, var(--tcw-control-h));\n height: max(40px, var(--tcw-control-h));\n }\n .tcw-modal {\n width: 94vw;\n border-radius: var(--tcw-dialog-radius);\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 top: auto;\n /* Above the on-screen keyboard (the widget sets it from visualViewport). */\n bottom: var(--tcw-keyboard-inset, 0px);\n padding-left: env(safe-area-inset-left, 0px);\n padding-right: env(safe-area-inset-right, 0px);\n left: 0;\n right: 0;\n transform: none;\n /* The border and the safe-area padding inside the screen's width. */\n box-sizing: border-box;\n width: 100vw;\n max-width: 100vw;\n /* Less the on-screen keyboard: a sheet's top never goes above the screen. */\n max-height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n max-height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 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 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 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 padding-bottom: max(14px, env(safe-area-inset-bottom));\n }\n\n /* Larger tap targets inside sheets: taller, not more padding, so a tab's text stays inside its chip. */\n .tcw-modal-tab {\n min-height: 40px;\n padding-inline: 16px;\n }\n .tcw-dropdown-item {\n padding: 12px 12px;\n font-size: var(--tcw-font-size-lg);\n }\n}\n\n/* === Price alerts panel === */\n\n.tcw-alerts-panel {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-end: 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: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\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: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-sm);\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: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent-ink);\n background: var(--tcw-accent);\n border: none;\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-sm);\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: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n font-variant-numeric: tabular-nums;\n}\n.tcw-alerts-row-note {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\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: var(--tcw-font-size-xs);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n padding: 2px 5px;\n border-radius: var(--tcw-tag-radius);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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 max-height: 40dvh;\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: var(--tcw-panel-top);\n inset-inline-end: 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-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\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: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-sm); 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: var(--tcw-font-size-sm);\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: var(--tcw-weight-strong); }\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: var(--tcw-font-size-xs);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\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/* === 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/*\n * Placing a bracket: a strip at the foot of the chart, over its time axis\n * (30 px, the chart's TIME_AXIS_HEIGHT), clear of the tags along its top; its\n * name and Place in the side's colour. Centred by its margins, not a\n * transform: the entrance animation ends on `transform: none`, which left it\n * starting at the middle.\n */\n.tcw-bracket-bar {\n position: absolute;\n bottom: calc(30px + var(--tcw-space-5));\n inset-inline: 0;\n margin-inline: auto;\n box-sizing: border-box;\n width: max-content;\n max-width: calc(100% - 2 * var(--tcw-space-4));\n z-index: 45;\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n padding-block: var(--tcw-space-3);\n padding-inline: var(--tcw-space-5) var(--tcw-space-3);\n background: var(--tcw-bg-elevated);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-bracket-bar[data-side='buy'] { --tcw-side: var(--tcw-green); }\n.tcw-bracket-bar[data-side='sell'] { --tcw-side: var(--tcw-red); }\n/* The name gives way first: in German or Russian it would push Place off a phone. */\n.tcw-bracket-label {\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-side, var(--tcw-text));\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n/* The replay bar has the chart's foot while it shows: the bracket's goes to the top. */\n.tcw-chart-container:has(> .tcw-replay-bar) > .tcw-bracket-bar {\n top: var(--tcw-space-4);\n bottom: auto;\n}\n.tcw-bracket-hint {\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.tcw-bracket-cancel,\n.tcw-bracket-confirm {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: var(--tcw-space-3);\n height: var(--tcw-control-h);\n padding-inline: var(--tcw-space-5);\n border-radius: var(--tcw-control-radius);\n font: inherit;\n font-size: var(--tcw-font-size);\n white-space: nowrap;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-bracket-cancel {\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n background: transparent;\n color: var(--tcw-text);\n}\n.tcw-bracket-cancel:hover { background: var(--tcw-hover-bg); }\n/* The ground's own colour reads on the side's: dark on the dark theme's light greens, paper on the light theme's deep ones. */\n.tcw-bracket-confirm {\n border: none;\n background: var(--tcw-side, var(--tcw-accent));\n color: var(--tcw-bg);\n font-weight: var(--tcw-weight-strong);\n}\n.tcw-bracket-confirm:hover { background: color-mix(in srgb, var(--tcw-side, var(--tcw-accent)) 86%, var(--tcw-text)); }\n.tcw-bracket-cancel:focus-visible,\n.tcw-bracket-confirm:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n@media (max-width: 640px) {\n .tcw-bracket-bar {\n inset-inline: var(--tcw-space-4);\n width: auto;\n max-width: none;\n }\n .tcw-bracket-hint { display: none; }\n .tcw-bracket-label { margin-inline-end: auto; }\n .tcw-bracket-cancel,\n .tcw-bracket-confirm { height: 34px; }\n}\n\n@media (forced-colors: active) {\n .tcw-bracket-bar { border: 1px solid CanvasText; }\n .tcw-bracket-confirm { border: 1px solid ButtonText; }\n .tcw-bracket-cancel:focus-visible,\n .tcw-bracket-confirm:focus-visible { outline: 2px solid Highlight; }\n}\n\n/* === Drawing style + templates popover === */\n\n.tcw-style-panel {\n position: absolute;\n bottom: 12px;\n inset-inline-start: var(--tcw-panel-left);\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-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\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: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-style-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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-control-radius);\n color: var(--tcw-text-dim);\n cursor: pointer;\n font-size: var(--tcw-font-size-xs);\n}\n.tcw-style-width span { width: 16px; background: currentColor; border-radius: var(--tcw-radius-xs); }\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: var(--tcw-font-size-xs);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\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: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\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: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent-ink);\n background: var(--tcw-accent);\n border: none;\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-xs); 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: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n text-align: start;\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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: end;\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text-dim);\n}\n\n/* === Indicator settings dialog === */\n\n/* Narrow on a desktop; on a phone a sheet across the screen like every dialog. */\n@media (min-width: 641px) {\n .tcw-modal-narrow {\n max-width: 360px;\n }\n}\n.tcw-indi-input {\n width: 110px;\n height: 30px;\n padding: 0 8px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\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-select {\n width: 150px;\n padding-right: 4px;\n cursor: pointer;\n}\n/* A level: its value and a remove button. */\n.tcw-indi-level {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n.tcw-indi-remove {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-indi-remove:hover {\n color: var(--tcw-red);\n background: var(--tcw-hover-bg);\n}\n.tcw-indi-remove:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n.tcw-indi-add {\n margin-top: 8px;\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: var(--tcw-panel-top);\n inset-inline-end: 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-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\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: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-xs);\n font-weight: calc(var(--tcw-weight-strong) + 100);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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: var(--tcw-font-size-sm);\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: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n background: transparent;\n color: var(--tcw-text-muted);\n border-radius: var(--tcw-control-radius);\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-group .tcw-tree-name {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: var(--tcw-weight-strong);\n}\n.tcw-tree-group .tcw-tree-name svg {\n flex: none;\n color: var(--tcw-text-muted);\n}\n.tcw-tree-member {\n margin-left: 14px;\n padding-left: 10px;\n border-inline-start: 1px solid var(--tcw-border-strong);\n border-radius: 0 var(--tcw-radius-sm) var(--tcw-radius-sm) 0;\n}\n.tcw-tree-rename {\n flex: 1;\n min-width: 0;\n padding: 3px 6px;\n border: 1px solid var(--tcw-accent-line);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-tree-rename:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--tcw-accent-soft);\n}\n.tcw-tree-empty {\n padding: 8px;\n font-size: var(--tcw-font-size-sm);\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 max-height: 30dvh;\n }\n .tcw-tree-section:last-child {\n padding-bottom: max(6px, env(safe-area-inset-bottom));\n }\n}\n\n/* === Reduced motion === */\n\n@media (prefers-reduced-motion: reduce) {\n .tcw-root *,\n .tcw-root *::before,\n .tcw-root *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n\n /* Except the loader's slow glow (opacity only): without it a long wait\n looks frozen. */\n .tcw-root .tcw-loading-candle,\n .tcw-root .tcw-loading-track > span {\n animation-duration: 2.4s !important;\n animation-iteration-count: infinite !important;\n animation-delay: var(--tcw-delay, 0ms) !important;\n }\n}\n\n/* --- Drawing settings dialog --- */\n.tcw-drawing-text {\n min-height: 56px;\n resize: vertical;\n font-family: inherit;\n}\n/* The text a drawing writes takes the dialog's width, under its name. */\n.tcw-text-row {\n flex-direction: column;\n align-items: stretch;\n gap: var(--tcw-space-3);\n}\n.tcw-text-row .tcw-drawing-text { box-sizing: border-box; width: 100%; }\n.tcw-levels-editor { display: grid; gap: var(--tcw-space-3); }\n/* Two columns of levels on a desktop, as a Fibonacci tool has a dozen. */\n.tcw-levels-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--tcw-space-3) var(--tcw-space-6);\n max-height: 260px;\n overflow-y: auto;\n padding-inline-end: var(--tcw-space-1);\n}\n@media (max-width: 640px) {\n .tcw-levels-grid { grid-template-columns: minmax(0, 1fr); }\n}\n.tcw-level-row {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) auto auto;\n align-items: center;\n gap: var(--tcw-space-3);\n}\n.tcw-level-row .tcw-indi-input { box-sizing: border-box; width: 100%; min-width: 0; }\n.tcw-level-row input[type='checkbox'] { accent-color: var(--tcw-accent); }\n.tcw-level-remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: 0;\n border-radius: var(--tcw-radius-sm, 4px);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-level-remove:hover { color: var(--tcw-text); background: var(--tcw-bg-elevated); }\n.tcw-level-remove:focus-visible { outline: 2px solid var(--tcw-accent); outline-offset: 1px; }\n.tcw-level-add { justify-self: start; }\n\n/* --- Context menu (right-click on a drawing) --- */\n.tcw-context-menu {\n position: absolute;\n z-index: 70;\n min-width: 200px;\n /* Taller than the room (many templates, say), it scrolls. */\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: var(--tcw-menu-pad);\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n}\n.tcw-context-item {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n width: 100%;\n min-height: var(--tcw-menu-item-h);\n padding: var(--tcw-space-1) var(--tcw-space-4);\n border: 0;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size);\n text-align: start;\n cursor: pointer;\n}\n.tcw-context-item svg, .tcw-context-icon { flex: none; width: 14px; height: 14px; color: var(--tcw-text-muted); }\n.tcw-context-item:hover, .tcw-context-item:focus-visible { background: var(--tcw-hover-bg); outline: none; }\n.tcw-context-item:focus-visible { box-shadow: inset 0 0 0 1px var(--tcw-accent); }\n.tcw-context-danger, .tcw-context-danger svg { color: var(--tcw-red); }\n.tcw-context-sep { height: 1px; margin: var(--tcw-space-2) var(--tcw-space-4); background: var(--tcw-divider); }\n.tcw-context-label { flex: 1; min-width: 0; }\n/* A shortcut, and the mark of a submenu, at the row's end. */\n.tcw-context-key {\n flex: none;\n margin-inline-start: var(--tcw-space-5);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text-muted);\n}\n.tcw-context-item svg.tcw-context-more { width: 12px; height: 12px; }\n/* Right to left, a submenu opens to the left: its marks point there. */\n[dir='rtl'] .tcw-context-more, [dir='rtl'] .tcw-context-back > svg { transform: scaleX(-1); }\n/* No keyboard under a finger: the keys stay named to a screen reader only. */\n@media (hover: none) { .tcw-context-key { display: none; } }\n.tcw-context-item[aria-expanded='true'] { background: var(--tcw-hover-bg); }\n/* The choice made among radios: a dot where a switch has its tick. */\n.tcw-context-dot { display: grid; place-items: center; }\n.tcw-context-dot::after { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--tcw-text); }\n/* An entry that can be removed: its x on the row in hand, always on a touch screen. */\n.tcw-context-row { display: flex; align-items: center; border-radius: var(--tcw-menu-item-radius); }\n.tcw-context-row .tcw-context-item { flex: 1; min-width: 0; }\n.tcw-context-row:hover { background: var(--tcw-hover-bg); }\n.tcw-context-row:hover .tcw-context-item { background: transparent; }\n.tcw-context-remove {\n flex: none;\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n margin-inline-end: var(--tcw-space-1);\n border: 0;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-context-row:hover .tcw-context-remove, .tcw-context-row:focus-within .tcw-context-remove { opacity: 1; }\n.tcw-context-remove:hover { color: var(--tcw-red); background: var(--tcw-hover-bg); }\n@media (hover: none) { .tcw-context-remove { opacity: 1; } }\n/* --- Toolbar over a selected drawing --- */\n.tcw-sel-toolbar {\n position: absolute;\n z-index: 65;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 3px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-divider);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-family: var(--tcw-font);\n white-space: nowrap;\n animation: tcw-sel-in var(--tcw-dur-fast) var(--tcw-ease-out);\n}\n@keyframes tcw-sel-in { from { opacity: 0; transform: translateY(3px); } }\n.tcw-sel-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n min-width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n padding: 0 6px;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-sel-btn svg { flex: none; }\n.tcw-sel-btn:hover, .tcw-sel-btn[aria-expanded=\"true\"] { background: var(--tcw-hover-bg); color: var(--tcw-text); }\n.tcw-sel-btn:focus-visible, .tcw-sel-swatch:focus-visible, .tcw-sel-option:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--tcw-accent); }\n.tcw-sel-btn.tcw-sel-on { color: var(--tcw-accent); background: var(--tcw-accent-soft); }\n.tcw-sel-danger:hover { color: var(--tcw-red); background: var(--tcw-red-soft); }\n.tcw-sel-color {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tcw-text) 25%, transparent);\n}\n.tcw-sel-width {\n display: inline-block;\n width: 16px;\n height: var(--w, 1px);\n max-height: 6px;\n border-radius: 1px;\n background: currentColor;\n}\n.tcw-sel-sep { flex: none; width: 1px; height: 18px; margin: 0 3px; background: var(--tcw-divider); }\n.tcw-sel-pop {\n position: absolute;\n z-index: 66;\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 120px;\n padding: 4px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-divider);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n font-family: var(--tcw-font);\n}\n.tcw-sel-pop--color {\n display: grid;\n grid-template-columns: repeat(4, 24px);\n gap: 6px;\n min-width: 0;\n padding: 8px;\n}\n.tcw-sel-swatch {\n width: 24px;\n height: 24px;\n padding: 0;\n border: 0;\n border-radius: 50%;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tcw-text) 20%, transparent);\n cursor: pointer;\n transition: transform var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-sel-swatch:hover { transform: scale(1.1); }\n.tcw-sel-swatch.tcw-sel-on { box-shadow: 0 0 0 2px var(--tcw-bg-elevated), 0 0 0 4px var(--tcw-accent); }\n.tcw-sel-option {\n display: flex;\n align-items: center;\n gap: 10px;\n min-height: var(--tcw-menu-item-h);\n padding: 4px 10px;\n border: 0;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n text-align: start;\n cursor: pointer;\n}\n.tcw-sel-option:hover { background: var(--tcw-bg-surface); }\n.tcw-sel-option.tcw-sel-on { color: var(--tcw-accent); }\n@media (prefers-reduced-motion: reduce) {\n .tcw-sel-toolbar { animation: none; }\n .tcw-sel-swatch { transition: none; }\n}\n\n/* --- The account: a panel under the chart; its head the tabs, the totals, a new order and its close. --- */\n.tcw-account-dock {\n flex: none;\n}\n.tcw-account {\n display: flex;\n flex-direction: column;\n /* 233, on the widget's φ ladder. */\n height: 233px;\n border-top: var(--tcw-border-w) solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n}\n.tcw-account-head {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n min-height: calc(var(--tcw-space-6) + var(--tcw-space-5));\n padding-inline: var(--tcw-space-4) var(--tcw-space-3);\n border-bottom: 1px solid var(--tcw-divider);\n}\n.tcw-account-tabs {\n display: flex;\n gap: var(--tcw-space-1);\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n}\n.tcw-account-tab {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-3);\n height: var(--tcw-tab-h);\n padding: var(--tcw-tab-pad);\n border: 0;\n border-radius: var(--tcw-tab-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n white-space: nowrap;\n cursor: pointer;\n}\n.tcw-account-tab:hover { color: var(--tcw-text); background: var(--tcw-tab-hover); }\n.tcw-account-tab[aria-selected='true'] {\n color: var(--tcw-tab-on-fg);\n background: var(--tcw-tab-on-bg);\n font-weight: var(--tcw-weight-strong);\n box-shadow: inset 0 calc(-1 * var(--tcw-tab-line)) 0 var(--tcw-accent);\n}\n/* A tab's count: a figure in a soft pill. */\n.tcw-account-count {\n min-width: 1.6em;\n padding-inline: var(--tcw-space-2);\n border-radius: 999px;\n background: var(--tcw-hover-bg);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n text-align: center;\n}\n/* The open and realised P&L, on every tab, in the mono figures. Short of room, they keep their start: the open P&L's words stay whole. */\n.tcw-account-totals {\n display: flex;\n flex: 1;\n justify-content: flex-end;\n justify-content: safe flex-end;\n gap: var(--tcw-space-5);\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-text-dim);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n.tcw-account-new {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: var(--tcw-space-3);\n height: var(--tcw-control-h);\n padding-inline: var(--tcw-space-4);\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n cursor: pointer;\n}\n.tcw-account-new:hover { background: var(--tcw-hover-bg); }\n.tcw-account-tab:focus-visible,\n.tcw-account-new:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n.tcw-account-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n overscroll-behavior: contain;\n}\n/* The rows: headings in the label case, figures set right in the mono type. */\n.tcw-account-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-account-table th {\n position: sticky;\n top: 0;\n z-index: 1;\n height: var(--tcw-control-h);\n padding-inline: var(--tcw-space-4);\n border-bottom: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-align: start;\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n white-space: nowrap;\n}\n.tcw-account-table td {\n height: calc(var(--tcw-control-h) + var(--tcw-space-2));\n padding-inline: var(--tcw-space-4);\n border-bottom: 1px solid var(--tcw-divider);\n color: var(--tcw-text);\n white-space: nowrap;\n}\n.tcw-account-table :is(th, td).tcw-num {\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n text-align: end;\n}\n.tcw-account-table tbody tr:hover td { background: var(--tcw-hover-bg); }\n.tcw-account-side { font-weight: var(--tcw-weight-strong); }\n.tcw-account-buy, .tcw-account-up { color: var(--tcw-green); }\n.tcw-account-sell, .tcw-account-down { color: var(--tcw-red); }\n.tcw-account-actions { display: flex; justify-content: flex-end; gap: var(--tcw-space-1); }\n.tcw-account-empty {\n margin: 0;\n padding: var(--tcw-space-6);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n text-align: center;\n}\n\n/*\n * A narrow widget (a phone, a narrow column): the totals go under the tabs,\n * and each row is a card of named figures. The headings stay for a screen\n * reader, unseen: the cells name themselves on screen. The panel is a step\n * of phi taller (377) for two cards and more, at most 45% of a phone's screen.\n */\n.tcw-root[data-tcw-narrow] .tcw-account {\n height: 377px;\n max-height: 45vh;\n max-height: 45dvh;\n}\n.tcw-root[data-tcw-narrow] .tcw-account-head { flex-wrap: wrap; padding-block: var(--tcw-space-2); }\n/* The tabs give way (they scroll): New order and the close keep the first line. */\n.tcw-root[data-tcw-narrow] .tcw-account-tabs { flex: 1 1 0; }\n.tcw-root[data-tcw-narrow] .tcw-account-totals { order: 3; flex-basis: 100%; justify-content: flex-start; padding-inline: var(--tcw-space-3); }\n.tcw-root[data-tcw-narrow] .tcw-account-table thead {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n.tcw-root[data-tcw-narrow] .tcw-account-table,\n.tcw-root[data-tcw-narrow] .tcw-account-table tbody { display: block; }\n.tcw-root[data-tcw-narrow] .tcw-account-table tbody tr {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--tcw-space-2) var(--tcw-space-5);\n padding: var(--tcw-space-4);\n border-bottom: 1px solid var(--tcw-divider);\n}\n.tcw-root[data-tcw-narrow] .tcw-account-table td {\n display: flex;\n justify-content: space-between;\n gap: var(--tcw-space-3);\n height: auto;\n padding: 0;\n border: 0;\n}\n.tcw-root[data-tcw-narrow] .tcw-account-table td::before {\n content: attr(data-label);\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font);\n font-size: var(--tcw-font-size-xs);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n.tcw-root[data-tcw-narrow] .tcw-account-table td:first-child,\n.tcw-root[data-tcw-narrow] .tcw-account-table td[data-label=''] { grid-column: 1 / -1; }\n.tcw-root[data-tcw-narrow] .tcw-account-table td[data-label='']::before { content: none; }\n.tcw-root[data-tcw-narrow] .tcw-account-table td[data-label=''] .tcw-account-actions { width: 100%; }\n.tcw-root[data-tcw-narrow] .tcw-account-table .tcw-tree-btn { width: 34px; height: 34px; }\n\n@media (forced-colors: active) {\n .tcw-account-tab[aria-selected='true'] { outline: 2px solid Highlight; }\n .tcw-account-tab:focus-visible,\n .tcw-account-new:focus-visible { outline: 2px solid Highlight; }\n}\n\n/* --- Named layouts --- */\n.tcw-layouts-btn { max-width: 190px; }\n.tcw-layouts-label {\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n.tcw-layouts-dirty {\n width: 6px;\n height: 6px;\n flex: none;\n border-radius: 50%;\n background: var(--tcw-accent);\n}\n.tcw-name-field { display: flex; flex-direction: column; gap: 6px; font-size: var(--tcw-font-size-sm); color: var(--tcw-text-dim); }\n.tcw-name-field .tcw-indi-input { width: 100%; height: 34px; font-size: var(--tcw-font-size); }\n\n/* --- Chart grid --- */\n.tcw-grid { background: var(--tcw-bg); }\n.tcw-grid-bar {\n display: flex;\n align-items: center;\n gap: 6px;\n min-height: calc(var(--tcw-control-h) + 8px);\n padding: 0 8px;\n border-bottom: 1px solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n overflow-x: auto;\n scrollbar-width: none;\n}\n.tcw-grid-bar::-webkit-scrollbar { display: none; }\n.tcw-grid-group { display: flex; align-items: center; gap: 2px; flex: none; }\n.tcw-grid-label {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-right: 4px;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n letter-spacing: var(--tcw-label-tracking);\n text-transform: var(--tcw-label-case);\n color: var(--tcw-text-muted);\n}\n.tcw-grid-sync[aria-pressed=\"true\"] { color: var(--tcw-accent); }\n.tcw-grid-cells {\n flex: 1;\n min-height: 0;\n display: grid;\n gap: 1px;\n background: var(--tcw-border);\n}\n.tcw-grid-cell {\n position: relative;\n min-width: 0;\n min-height: 0;\n background: var(--tcw-bg);\n}\n.tcw-grid-cell-active::after {\n content: '';\n position: absolute;\n inset: 0;\n border: 1px solid var(--tcw-accent);\n pointer-events: none;\n z-index: 5;\n}\n\n/* --- Host toolbar buttons --- */\n.tcw-toolbar-host { display: inline-flex; align-items: center; gap: 2px; }\n.tcw-toolbar-host:empty { display: none; }\n.tcw-host-btn { display: inline-flex; align-items: center; gap: 4px; }\n\n/* --- Host sidebar buttons, status bar items, and the layer over the chart --- */\n.tcw-sidebar-host { display: flex; flex-direction: column; align-items: center; }\n.tcw-sidebar-host:empty { display: none; }\n.tcw-status-host { display: flex; align-items: center; gap: 10px; min-width: 0; }\n.tcw-status-host:empty { display: none; }\n.tcw-status-host-item { white-space: nowrap; }\n.tcw-status-host-btn {\n margin: -4px -6px;\n padding: 4px 6px;\n font: inherit;\n color: inherit;\n background: transparent;\n border: none;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-status-host-btn:hover { color: var(--tcw-text); background: var(--tcw-hover-bg); }\n.tcw-status-host-btn:focus-visible { outline: 2px solid var(--tcw-accent); outline-offset: -2px; }\n/* Over the plot and under the widget's own overlays; the pointer reaches the chart unless an element of yours takes it. */\n.tcw-host-layer { position: absolute; inset: 0; z-index: 2; pointer-events: none; }\n\n/* --- Pane buttons (move, fold, maximise) --- */\n.tcw-pane-controls {\n position: absolute;\n z-index: 4;\n display: flex;\n gap: 1px;\n transform: translateX(-100%);\n padding: 1px;\n border-radius: var(--tcw-radius-sm);\n background: color-mix(in srgb, var(--tcw-bg) 80%, transparent);\n opacity: 0.55;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-pane-controls:hover,\n.tcw-pane-controls:focus-within { opacity: 1; }\n.tcw-pane-btn {\n display: inline-grid;\n place-items: center;\n width: 18px;\n height: 16px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-pane-btn:hover { color: var(--tcw-text); background: var(--tcw-hover-bg); }\n.tcw-pane-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--tcw-accent-soft); }\n\n/* --- Typed interval --- */\n.tcw-interval-input {\n position: absolute;\n z-index: 20;\n left: 50%;\n top: 40%;\n transform: translate(-50%, -50%);\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 12px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-radius-lg, 10px);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n.tcw-interval-field {\n width: 150px;\n height: 36px;\n padding: 0 10px;\n font: inherit;\n font-size: var(--tcw-font-size-xl);\n font-weight: var(--tcw-weight-strong);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text);\n background: var(--tcw-bg-surface);\n border: 1px solid var(--tcw-accent);\n border-radius: var(--tcw-input-radius);\n outline: none;\n}\n.tcw-interval-field[aria-invalid] { border-color: var(--tcw-red); }\n.tcw-interval-hint { font-size: var(--tcw-font-size-xs); color: var(--tcw-text-muted); max-width: 170px; }\n\n/* --- Alerts: lines, moves, bar close, expiry --- */\n.tcw-alerts-source { grid-column: auto; }\n.tcw-alerts-row-fields {\n grid-column: 1 / -1;\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 8px;\n}\n.tcw-alerts-row-fields[hidden] { display: none; }\n.tcw-alerts-row-fields > input[hidden] { display: none; }\n.tcw-alerts-row-fields:has(> input[hidden]) { grid-template-columns: 1fr; }\n.tcw-alerts-options { align-items: center; }\n.tcw-alerts-form .tcw-alerts-check {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-alerts-form .tcw-alerts-check input { width: auto; height: auto; }\n.tcw-alerts-form input[aria-invalid=\"true\"] { border-color: var(--tcw-red); }\n.tcw-alerts-row-meta { margin-top: 2px; font-size: var(--tcw-font-size-xs); color: var(--tcw-text-muted); }\n.tcw-alerts-expired { opacity: 0.6; }\n\n/* --- Signal marker note --- */\n.tcw-marker-tip {\n position: absolute;\n z-index: 12;\n pointer-events: none;\n padding: 6px 8px;\n border: 1px solid var(--tcw-border);\n border-radius: var(--tcw-tooltip-radius);\n background: var(--tcw-tooltip-bg);\n color: var(--tcw-tooltip-fg);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.45;\n font-variant-numeric: tabular-nums;\n box-shadow: var(--tcw-menu-shadow);\n max-width: 240px;\n}\n.tcw-marker-tip strong { display: block; font-size: var(--tcw-font-size-sm); }\n\n/* === Navigation over the chart ===\n * Centred on the plot's bottom edge, shown while a mouse is over the chart. */\n.tcw-nav {\n position: absolute;\n z-index: 15;\n display: flex;\n gap: 2px;\n padding: 3px;\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: calc(var(--tcw-control-radius) + 3px);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n opacity: 0;\n pointer-events: none;\n transform: translate(-50%, calc(-100% - 12px));\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-nav.tcw-nav-shown {\n opacity: 1;\n pointer-events: auto;\n}\n.tcw-nav-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n cursor: pointer;\n touch-action: none;\n}\n.tcw-nav-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n.tcw-nav-btn:active {\n background: var(--tcw-active-bg);\n}\n.tcw-nav-btn:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n.tcw-nav-btn svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n@media (hover: none) {\n .tcw-nav { display: none; }\n}\n\n/* === Symbol info ===\n * Top left, beside the drawing tools: the panels on the right stay clear. */\n.tcw-syminfo {\n position: absolute;\n top: var(--tcw-panel-top);\n inset-inline-start: var(--tcw-panel-left);\n z-index: 38;\n width: 288px;\n max-height: calc(100% - var(--tcw-panel-top) - 12px);\n display: flex;\n flex-direction: column;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n overflow: hidden;\n animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;\n}\n.tcw-syminfo-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 9px 12px;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n border-bottom: 1px solid var(--tcw-border);\n}\n.tcw-syminfo-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n.tcw-syminfo-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }\n.tcw-syminfo-body,\n.tcw-syminfo-news {\n padding: 12px 14px;\n overflow-y: auto;\n}\n.tcw-syminfo-body {\n display: grid;\n gap: 10px;\n}\n.tcw-syminfo-symbol {\n font-size: var(--tcw-font-size-lg);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-syminfo-desc {\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-syminfo-meta {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n.tcw-syminfo-quote {\n display: flex;\n align-items: baseline;\n gap: 10px;\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n}\n.tcw-syminfo-price {\n font-size: var(--tcw-font-size-display);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text);\n}\n.tcw-syminfo-change { font-size: var(--tcw-font-size-sm); }\n.tcw-syminfo-change.tcw-up { color: var(--tcw-green); }\n.tcw-syminfo-change.tcw-down { color: var(--tcw-red); }\n.tcw-syminfo-status {\n display: flex;\n align-items: center;\n gap: 7px;\n font-size: var(--tcw-font-size-sm);\n color: var(--tcw-text-dim);\n}\n.tcw-syminfo-status::before,\n.tcw-status-market::before {\n content: '';\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--tcw-text-muted);\n}\n.tcw-syminfo-status[data-state='open']::before,\n.tcw-syminfo-status[data-state='always']::before,\n.tcw-status-market[data-state='open']::before {\n background: var(--tcw-green);\n}\n.tcw-syminfo-stats {\n display: grid;\n gap: 4px;\n margin: 0;\n padding-top: 10px;\n border-top: 1px solid var(--tcw-divider);\n}\n.tcw-syminfo-stat {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-syminfo-stat dt { color: var(--tcw-text-muted); }\n.tcw-syminfo-stat dd {\n margin: 0;\n color: var(--tcw-text);\n text-align: end;\n font-variant-numeric: tabular-nums;\n overflow-wrap: anywhere;\n}\n.tcw-syminfo-news {\n border-top: 1px solid var(--tcw-divider);\n}\n.tcw-syminfo-news-title {\n margin-bottom: 8px;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text-muted);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n.tcw-syminfo-news-list {\n display: grid;\n gap: 10px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.tcw-syminfo-news-item {\n font-size: var(--tcw-font-size-sm);\n line-height: 1.4;\n color: var(--tcw-text);\n}\n.tcw-syminfo-news-item a {\n color: var(--tcw-text);\n text-decoration: none;\n}\n.tcw-syminfo-news-item a:hover { color: var(--tcw-accent); text-decoration: underline; }\n.tcw-syminfo-news-item a:focus-visible { outline: none; box-shadow: var(--tcw-ring); border-radius: var(--tcw-radius-xs); }\n.tcw-syminfo-news-meta,\n.tcw-syminfo-news-note {\n margin-top: 2px;\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n\n/* Numbers keep their sign on the left, and mixed text its own order, in a right-to-left widget too. */\n.tcw-watchlist-price,\n.tcw-watchlist-change,\n.tcw-syminfo-price,\n.tcw-syminfo-change {\n unicode-bidi: isolate;\n direction: ltr;\n}\n.tcw-syminfo-desc,\n.tcw-syminfo-meta,\n.tcw-syminfo-status,\n.tcw-syminfo-stat dd,\n.tcw-syminfo-news-meta {\n unicode-bidi: plaintext;\n}\n\n/* The market's status in the status bar. */\n.tcw-status-market {\n display: flex;\n align-items: center;\n gap: 7px;\n color: var(--tcw-text-muted);\n}\n\n@media (max-width: 640px) {\n .tcw-syminfo {\n top: auto;\n bottom: 0;\n left: 0;\n right: 0;\n width: 100vw;\n max-height: 70%;\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 0 0;\n }\n}\n\n/* === The look: how chosen controls show, floating bars, segmented intervals ===\n * Each switch sets variables on its own root, which its parts read: a grid's\n * look never reaches into a chart that has one of its own. */\n\n/* A chosen button (`ui.active`): a tinted fill (default), a solid pill, or an underline.\n * Dialog tabs are chips, or underlined in the underline look. Panels sit below the\n * toolbar and beside the drawing tools. */\n.tcw-root {\n --tcw-on-bg: var(--tcw-accent-soft);\n --tcw-on-fg: var(--tcw-accent);\n --tcw-on-ring: none;\n --tcw-on-icon-bg: var(--tcw-accent-soft);\n --tcw-on-icon-fg: var(--tcw-accent);\n --tcw-on-icon-ring: none;\n --tcw-tabs-pad-block: var(--tcw-space-4);\n --tcw-tab-h: var(--tcw-control-h);\n --tcw-tab-pad: 0 var(--tcw-space-5);\n --tcw-tab-line: 0px;\n --tcw-tab-radius: var(--tcw-control-radius);\n --tcw-tab-hover: var(--tcw-hover-bg);\n --tcw-tab-on-bg: var(--tcw-on-bg);\n --tcw-tab-on-fg: var(--tcw-on-fg);\n /* A menu's rows sit inside its padding with corners that follow its own: the menu's\n * corner less the padding between, so the two curves run parallel (Print: 5 - 3 = 2). */\n --tcw-menu-pad: var(--tcw-space-2);\n --tcw-menu-item-radius: max(0px, calc(var(--tcw-menu-radius) - var(--tcw-menu-pad)));\n --tcw-panel-top: calc(var(--tcw-toolbar-h) + var(--tcw-space-3));\n --tcw-panel-left: calc(var(--tcw-sidebar-w) + var(--tcw-space-5));\n}\n.tcw-root[data-tcw-active='solid'] {\n --tcw-on-bg: var(--tcw-text);\n --tcw-on-fg: var(--tcw-bg);\n --tcw-on-icon-bg: var(--tcw-text);\n --tcw-on-icon-fg: var(--tcw-bg);\n}\n/* Print picks a tool in ink blue on a tint: a solid square would outweigh the chart beside it. */\n.tcw-root[data-tcw-ui='print'][data-tcw-active='solid'] {\n --tcw-on-icon-bg: var(--tcw-accent-soft);\n --tcw-on-icon-fg: var(--tcw-accent);\n}\n.tcw-root[data-tcw-active='underline'] {\n --tcw-on-bg: var(--tcw-active-bg);\n --tcw-on-fg: var(--tcw-text);\n --tcw-on-ring: inset 0 -2px 0 var(--tcw-accent);\n --tcw-on-icon-bg: var(--tcw-active-bg);\n --tcw-on-icon-fg: var(--tcw-accent);\n --tcw-on-icon-ring: inset 2px 0 0 var(--tcw-accent);\n --tcw-tabs-pad-block: 0px;\n --tcw-tab-h: auto;\n --tcw-tab-pad: 11px 14px;\n --tcw-tab-line: 2px;\n --tcw-tab-radius: 0px;\n --tcw-tab-hover: transparent;\n --tcw-tab-on-bg: transparent;\n --tcw-tab-on-fg: var(--tcw-accent);\n}\n.tcw-root[data-tcw-toolbar='floating'] {\n --tcw-panel-top: calc(var(--tcw-toolbar-h) + 2 * var(--tcw-border-w) + 14px);\n}\n.tcw-root[data-tcw-sidebar='floating'] {\n --tcw-panel-left: calc(var(--tcw-sidebar-w) + 2 * var(--tcw-border-w) + 22px);\n}\n\n/* The toolbar as an island (`ui.toolbar: 'floating'`). */\n.tcw-root[data-tcw-toolbar='floating'] > .tcw-toolbar {\n margin: 8px 10px 0;\n padding-inline: calc(min(var(--tcw-toolbar-radius), var(--tcw-toolbar-h) / 2) / 2 + 8px);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-toolbar-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n/* The drawing tools as an island (`ui.sidebar: 'floating'`). */\n.tcw-root[data-tcw-sidebar='floating'] > .tcw-body > .tcw-sidebar {\n align-self: flex-start;\n max-height: calc(100% - 20px);\n margin: 10px 6px 10px 10px;\n padding-block: calc(min(var(--tcw-sidebar-radius), var(--tcw-sidebar-w) / 2) / 2 + 6px);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-sidebar-radius);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n}\n\n/* Frosted menus (`ui.blur` above 0): the chart shows through, blurred. */\n@supports (background: color-mix(in srgb, red 50%, transparent)) {\n .tcw-dropdown,\n .tcw-flyout,\n .tcw-context-menu {\n background: color-mix(in srgb, var(--tcw-bg-elevated) var(--tcw-surface-opacity), transparent);\n }\n}\n\n/* The interval buttons in one track (`ui.intervals: 'segmented'`). */\n.tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group {\n gap: 2px;\n margin: 0 4px;\n padding: 3px;\n border-radius: calc(var(--tcw-control-radius) + 3px);\n background: var(--tcw-hover-bg);\n}\n.tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group .tcw-btn {\n height: calc(var(--tcw-control-h) - 6px);\n padding: 0 9px;\n}\n\n/* Phones: the variants keep comfortable tap targets and room for the bar. */\n@media (max-width: 768px) {\n .tcw-root[data-tcw-intervals='segmented'] > .tcw-toolbar > .tcw-tf-group .tcw-btn {\n height: max(34px, calc(var(--tcw-control-h) - 6px));\n padding: 0 10px;\n }\n .tcw-root[data-tcw-toolbar='floating'] > .tcw-toolbar {\n margin: 6px 6px 0;\n padding-inline: 4px;\n }\n .tcw-root[data-tcw-sidebar='floating'] > .tcw-body > .tcw-sidebar {\n margin: 6px 4px 6px 6px;\n }\n}\n\n/* --- Phones and tablets --- */\n\n/* Taps without the grey flash or the double-tap zoom's wait. The chart area\n sets its own touch-action for its gestures. */\n.tcw-root {\n -webkit-tap-highlight-color: transparent;\n touch-action: manipulation;\n}\n\n/* iOS zooms the page into an input under 16 px when it takes focus. */\n@media (pointer: coarse) {\n .tcw-root input:not([type='color']):not([type='range']):not([type='checkbox']):not([type='radio']),\n .tcw-root select,\n .tcw-root textarea {\n font-size: max(16px, 1em);\n }\n}\n\n/* Sheets and lists scroll on their own, without dragging the page behind them. */\n.tcw-modal {\n overscroll-behavior: contain;\n}\n\n/* === The bars' newer parts ===\n * Interval sections and the chart type's icon, the Trade menu's button, undo\n * and redo off while idle, the tool menus' shortcuts and stars, the status\n * bar's clock and scale switches, and the grip of the selection toolbar. */\n\n/* The interval menu: each unit under its heading, a hairline between them. */\n.tcw-tf-section + .tcw-tf-section {\n margin-top: var(--tcw-space-2);\n padding-top: var(--tcw-space-1);\n border-top: 1px solid var(--tcw-divider);\n}\n\n/* The chart type: its icon alone, square. */\n.tcw-dropdown-trigger[data-role='charttype'] {\n justify-content: center;\n width: var(--tcw-control-h);\n padding: 0;\n}\n\n/* Undo and redo with nothing to do: there, quiet, not pressable. */\n.tcw-btn-icon:disabled {\n opacity: 0.35;\n cursor: default;\n background: transparent;\n color: var(--tcw-text-muted);\n}\n\n/* A tool menu's row: the tool, its shortcut, and a star beside it. */\n.tcw-flyout-row {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-1);\n}\n.tcw-flyout-row > .tcw-flyout-item {\n flex: 1;\n min-width: 0;\n}\n.tcw-flyout-name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.tcw-flyout-key {\n flex: none;\n margin-inline-start: var(--tcw-space-5);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n}\n.tcw-flyout-pin {\n flex: none;\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n/* Shown on the row in hand; always for a pinned tool, filled in ink blue; always on a touch screen. */\n.tcw-flyout-row:hover .tcw-flyout-pin,\n.tcw-flyout-row:focus-within .tcw-flyout-pin,\n.tcw-flyout-pin[aria-pressed='true'],\n.tcw-root[data-tcw-narrow] .tcw-flyout-pin {\n opacity: 1;\n}\n@media (hover: none) {\n .tcw-flyout-pin {\n opacity: 1;\n }\n}\n.tcw-flyout-pin:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n.tcw-flyout-pin[aria-pressed='true'] {\n color: var(--tcw-accent);\n}\n.tcw-flyout-pin[aria-pressed='true'] svg path {\n fill: currentColor;\n}\n\n/* The clock: the time in figures, the zone beside it; it opens the zones. */\n.tcw-status-clock,\n.tcw-status-scale-btn {\n height: var(--tcw-control-h-sm);\n padding: 0 var(--tcw-space-3);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n cursor: pointer;\n transition: color var(--tcw-dur-fast) var(--tcw-ease), background var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-status-clock {\n font-family: var(--tcw-font-mono);\n}\n.tcw-status-clock:hover,\n.tcw-status-scale-btn:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n.tcw-status-clock:focus-visible,\n.tcw-status-scale-btn:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n/* The scale switches: %, log, auto, in ink blue while on. */\n.tcw-status-scale {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-1);\n padding-inline-start: var(--tcw-space-3);\n border-inline-start: var(--tcw-sep-w) solid var(--tcw-border);\n}\n.tcw-status-scale-btn[aria-pressed='true'] {\n color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n/* A narrow widget keeps the range presets and the clock: the scale switches (also in the\n settings and the scale's menu) give them the room, and the connection's word is left to\n screen readers beside its dot. */\n.tcw-root[data-tcw-narrow] .tcw-status-scale {\n display: none;\n}\n.tcw-root[data-tcw-narrow] .tcw-status-indicator > span:not(.tcw-status-dot) {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n/* The selection toolbar's grip: dots to take it by. */\n.tcw-sel-grip {\n flex: none;\n width: var(--tcw-space-4);\n height: var(--tcw-control-h-sm);\n margin-inline: var(--tcw-space-1) var(--tcw-space-2);\n background-image: radial-gradient(circle, var(--tcw-text-muted) 1px, transparent 1.4px);\n background-size: 4px 4px;\n background-position: center;\n opacity: 0.7;\n cursor: grab;\n touch-action: none;\n}\n.tcw-sel-grip:active {\n cursor: grabbing;\n}\n\n/* --- A narrow widget (a phone, or a narrow column): data-tcw-narrow ---\n Set from the widget's own width, below 641px. The toolbar keeps the\n chart's own controls (symbol, interval, type, indicators) and puts the\n rest under \"more\"; the drawing tools wait behind a button over the chart;\n a grid shows one chart at a time, picked by its tab. */\n\n.tcw-toolbar-more,\n.tcw-sidebar-fab,\n.tcw-tf-current,\n.tcw-grid-tabs {\n display: none;\n}\n\n/* The toolbar fits itself too (on a tablet, a window half a screen wide):\n the right-hand buttons that don't fit fold under \"more\" (`--collapsed`\n shows it), and `--icons` drops the menus' labels and the interval buttons.\n Narrow folds them all. */\n.tcw-toolbar [data-tcw-folded],\n.tcw-root[data-tcw-narrow] > .tcw-toolbar .tcw-toolbar-overflow {\n display: none;\n}\n.tcw-toolbar--collapsed > .tcw-toolbar-more,\n.tcw-root[data-tcw-narrow] > .tcw-toolbar > .tcw-toolbar-more {\n display: inline-flex;\n margin-inline-start: auto;\n}\n.tcw-toolbar--icons.tcw-toolbar--tf-menu > .tcw-tf-group,\n.tcw-root[data-tcw-narrow] > .tcw-toolbar.tcw-toolbar--tf-menu > .tcw-tf-group {\n display: none;\n}\n.tcw-toolbar--icons .tcw-tf-more,\n.tcw-root[data-tcw-narrow] > .tcw-toolbar .tcw-tf-more {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 0 10px;\n}\n.tcw-toolbar--icons .tcw-tf-current,\n.tcw-root[data-tcw-narrow] > .tcw-toolbar .tcw-tf-current {\n display: inline;\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-accent);\n}\n.tcw-toolbar--icons .tcw-trigger-label,\n.tcw-root[data-tcw-narrow] > .tcw-toolbar .tcw-trigger-label {\n display: none;\n}\n\n/* The drawing tools lie over the chart when opened, from its edge. */\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar {\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n /* Under the toolbar (20), whose menus open over it. */\n z-index: 18;\n box-shadow: var(--tcw-menu-shadow);\n transform: translateX(-100%);\n visibility: hidden;\n transition: transform var(--tcw-dur-normal) var(--tcw-ease-out), visibility 0s linear var(--tcw-dur-normal);\n}\n.tcw-root[data-tcw-narrow][dir='rtl'] > .tcw-body > .tcw-sidebar {\n transform: translateX(100%);\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar.tcw-sidebar-open {\n transform: none;\n visibility: visible;\n transition: transform var(--tcw-dur-normal) var(--tcw-ease-out), visibility 0s;\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-flyout {\n z-index: 19;\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar-fab {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n inset-inline-start: 10px;\n /* Clear of the time axis. */\n bottom: 44px;\n z-index: 17;\n width: 44px;\n height: 44px;\n padding: 0;\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: 999px;\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text);\n box-shadow: var(--tcw-menu-shadow);\n cursor: pointer;\n transition: background var(--tcw-dur-fast), color var(--tcw-dur-fast), border-color var(--tcw-dur-fast);\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar-fab.tcw-active {\n background: var(--tcw-accent);\n border-color: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar-fab:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n.tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar-fab[aria-expanded='true'] {\n visibility: hidden;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar,\n .tcw-root[data-tcw-narrow] > .tcw-body > .tcw-sidebar.tcw-sidebar-open {\n transition: none;\n }\n}\n\n/* A narrow grid: one chart at a time, a tab for each. */\n.tcw-grid[data-tcw-narrow] > .tcw-grid-bar > .tcw-grid-tabs {\n display: flex;\n}\n.tcw-grid-tab {\n white-space: nowrap;\n}\n.tcw-grid-has-tabs[data-tcw-narrow] > .tcw-grid-cells {\n display: flex;\n flex-direction: column;\n}\n.tcw-grid-has-tabs[data-tcw-narrow] > .tcw-grid-cells > .tcw-grid-cell {\n flex: 1;\n}\n.tcw-grid-has-tabs[data-tcw-narrow] > .tcw-grid-cells > .tcw-grid-cell:not(.tcw-grid-cell-current) {\n display: none;\n}\n.tcw-grid-has-tabs[data-tcw-narrow] > .tcw-grid-cells > .tcw-grid-cell-active::after {\n display: none;\n}\n\n/* Phones: menus open as sheets from the bottom, in reach of a thumb and\n never off screen (a menu's own place may be off the side of a phone). */\n@media (max-width: 640px) {\n .tcw-dropdown,\n .tcw-context-menu {\n position: fixed !important;\n /* Above the on-screen keyboard (the indicators' search). */\n inset: auto 0 var(--tcw-keyboard-inset, 0px) 0 !important;\n margin: 0 !important;\n width: auto;\n max-width: none;\n max-height: 70vh !important;\n max-height: 70dvh !important;\n overflow-y: auto;\n overscroll-behavior: contain;\n z-index: 80;\n padding: 8px 8px calc(8px + env(safe-area-inset-bottom, 0px));\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 0 0;\n border-bottom: none;\n }\n .tcw-dropdown-item,\n .tcw-context-item {\n min-height: 44px;\n }\n}\n", It = "/* === Base controls: fields, selects, checks, sliders, calendar, scrollbars ===\n *\n * One look for every form control in the widget, from tokens. Fields are\n * quiet until used: a faint fill and hairline, a firmer line on hover, and\n * on focus the line turns accent (no ring). Selects and date fields open\n * the widget's own list and calendar (formControls.ts).\n */\n\n.tcw-root {\n color-scheme: dark;\n\n --tcw-field-bg: rgba(230, 227, 220, 0.04);\n --tcw-field-bg-hover: rgba(230, 227, 220, 0.06);\n --tcw-field-bg-focus: rgba(230, 227, 220, 0.03);\n --tcw-field-line: rgba(230, 227, 220, 0.12);\n --tcw-field-line-hover: rgba(230, 227, 220, 0.22);\n --tcw-field-line-focus: var(--tcw-accent-line);\n --tcw-field-placeholder: var(--tcw-text-muted);\n --tcw-check-line: rgba(230, 227, 220, 0.3);\n --tcw-scroll-thumb: rgba(230, 227, 220, 0.14);\n --tcw-scroll-thumb-hover: rgba(230, 227, 220, 0.26);\n /* Glyphs drawn in a field's background (a background image takes no currentColor). */\n --tcw-field-chevron: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.75l3 3 3-3' fill='none' stroke='%238c8a85' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n --tcw-field-calendar: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%238c8a85' stroke-width='1.3' stroke-linecap='round'%3E%3Crect x='2.5' y='3.5' width='11' height='10' rx='2'/%3E%3Cpath d='M2.5 6.5h11M5.5 2v3M10.5 2v3'/%3E%3C/g%3E%3C/svg%3E\");\n --tcw-check-mark: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.25l2.6 2.6L12 5.5' fill='none' stroke='%23131416' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n}\n\n.tcw-root[data-tcw-theme='light'] {\n color-scheme: light;\n\n /* Fields are white boxes on the paper, ruled in ink, as on a printed form. */\n --tcw-field-bg: #ffffff;\n --tcw-field-bg-hover: #ffffff;\n --tcw-field-bg-focus: #ffffff;\n --tcw-field-line: rgba(27, 29, 33, 0.16);\n --tcw-field-line-hover: rgba(27, 29, 33, 0.3);\n --tcw-check-line: rgba(27, 29, 33, 0.34);\n --tcw-scroll-thumb: rgba(27, 29, 33, 0.16);\n --tcw-scroll-thumb-hover: rgba(27, 29, 33, 0.3);\n --tcw-field-chevron: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.75l3 3 3-3' fill='none' stroke='%236c7077' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n --tcw-field-calendar: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%236c7077' stroke-width='1.3' stroke-linecap='round'%3E%3Crect x='2.5' y='3.5' width='11' height='10' rx='2'/%3E%3Cpath d='M2.5 6.5h11M5.5 2v3M10.5 2v3'/%3E%3C/g%3E%3C/svg%3E\");\n --tcw-check-mark: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.25l2.6 2.6L12 5.5' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n}\n\n/* --- Text, number, date and time fields, and selects --- */\n\n/* Fields speak the widget's type, not the browser's (a part's own font still wins). */\n:where(.tcw-root) :where(input, select, textarea, button) {\n font-family: inherit;\n font-weight: inherit;\n letter-spacing: inherit;\n}\n\n.tcw-root :is(\n .tcw-tf-custom-input,\n .tcw-settings-select,\n .tcw-settings-number,\n .tcw-goto-input,\n .tcw-watchlist-input,\n .tcw-indi-input,\n .tcw-style-name,\n .tcw-drawing-text,\n .tcw-replay-speed,\n .tcw-alerts-form input:not([type='checkbox']),\n .tcw-alerts-form select\n) {\n border: 1px solid var(--tcw-field-line);\n border-radius: var(--tcw-input-radius);\n background-color: var(--tcw-field-bg);\n color: var(--tcw-text);\n outline: none;\n box-shadow: none;\n transition:\n border-color var(--tcw-dur-fast) var(--tcw-ease),\n background-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-root :is(\n .tcw-tf-custom-input,\n .tcw-settings-select,\n .tcw-settings-number,\n .tcw-goto-input,\n .tcw-watchlist-input,\n .tcw-indi-input,\n .tcw-style-name,\n .tcw-drawing-text,\n .tcw-replay-speed,\n .tcw-alerts-form input:not([type='checkbox']),\n .tcw-alerts-form select\n):hover:not(:disabled, :focus) {\n border-color: var(--tcw-field-line-hover);\n background-color: var(--tcw-field-bg-hover);\n}\n\n.tcw-root :is(\n .tcw-tf-custom-input,\n .tcw-settings-select,\n .tcw-settings-number,\n .tcw-goto-input,\n .tcw-watchlist-input,\n .tcw-indi-input,\n .tcw-style-name,\n .tcw-drawing-text,\n .tcw-replay-speed,\n .tcw-alerts-form input:not([type='checkbox']),\n .tcw-alerts-form select\n):is(:focus, :focus-visible, [aria-expanded='true']) {\n border-color: var(--tcw-field-line-focus);\n background-color: var(--tcw-field-bg-focus);\n outline: none;\n box-shadow: none;\n}\n\n.tcw-root :is(\n .tcw-tf-custom-input,\n .tcw-indi-input,\n .tcw-watchlist-input,\n .tcw-goto-input,\n .tcw-alerts-form input\n):is([aria-invalid='true'], [aria-invalid='']):is(*, :hover, :focus) {\n /* As specific as the hover rule and later, so a wrong value stays red under the pointer and in focus. */\n border-color: var(--tcw-red);\n box-shadow: none;\n}\n\n.tcw-root :is(input, textarea)::placeholder {\n color: var(--tcw-field-placeholder);\n opacity: 1;\n}\n\n.tcw-root :is(input, select, textarea):disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Selects: the browser's arrow gives way to a fine chevron. */\n.tcw-root select:not([multiple]):not([size]) {\n appearance: none;\n -webkit-appearance: none;\n background-image: var(--tcw-field-chevron);\n background-repeat: no-repeat;\n background-size: 12px 12px;\n background-position: right 8px center;\n padding-inline-end: 26px;\n text-overflow: ellipsis;\n cursor: pointer;\n}\n\n.tcw-root[dir='rtl'] select:not([multiple]):not([size]),\n.tcw-root [dir='rtl'] select:not([multiple]):not([size]) {\n background-position: left 8px center;\n}\n\n/* Number fields: the steppers show only on a field in use. */\n.tcw-root input[type='number']::-webkit-inner-spin-button,\n.tcw-root input[type='number']::-webkit-outer-spin-button {\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-root input[type='number']:is(:hover, :focus)::-webkit-inner-spin-button {\n opacity: 0.55;\n}\n\n/* Date and time: the widget's calendar icon where the browser's own can be hidden. */\n@supports selector(::-webkit-calendar-picker-indicator) {\n .tcw-root input[type='date'] {\n background-image: var(--tcw-field-calendar);\n background-repeat: no-repeat;\n background-size: 15px 15px;\n background-position: right 8px center;\n padding-inline-end: 30px;\n cursor: text;\n }\n\n .tcw-root[dir='rtl'] input[type='date'],\n .tcw-root [dir='rtl'] input[type='date'] {\n background-position: left 8px center;\n }\n}\n\n.tcw-root input:is([type='date'], [type='time'])::-webkit-calendar-picker-indicator {\n display: none;\n}\n\n.tcw-root input:is([type='date'], [type='time'])::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n}\n\n/* --- Checkboxes and radios --- */\n\n.tcw-root input:is([type='checkbox'], [type='radio']) {\n appearance: none;\n -webkit-appearance: none;\n flex-shrink: 0;\n width: 16px;\n height: 16px;\n margin: 0;\n border: 1.5px solid var(--tcw-check-line);\n border-radius: var(--tcw-radius-sm);\n background: transparent center / 14px 14px no-repeat;\n cursor: pointer;\n vertical-align: middle;\n transition:\n border-color var(--tcw-dur-fast) var(--tcw-ease),\n background-color var(--tcw-dur-fast) var(--tcw-ease),\n box-shadow var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-root input[type='radio'] {\n border-radius: 50%;\n}\n\n.tcw-root input:is([type='checkbox'], [type='radio']):hover:not(:disabled) {\n border-color: var(--tcw-text-dim);\n}\n\n.tcw-root input[type='checkbox']:checked {\n border-color: var(--tcw-accent);\n background-color: var(--tcw-accent);\n background-image: var(--tcw-check-mark);\n}\n\n.tcw-root input[type='radio']:checked {\n border-color: var(--tcw-accent);\n background-image: radial-gradient(circle, var(--tcw-accent) 0 3.5px, transparent 4px);\n}\n\n.tcw-root input:is([type='checkbox'], [type='radio']):focus {\n outline: none;\n}\n\n.tcw-root input:is([type='checkbox'], [type='radio']):focus-visible {\n box-shadow: 0 0 0 3px var(--tcw-accent-soft);\n}\n\n/* --- Sliders --- */\n\n.tcw-root input[type='range'] {\n appearance: none;\n -webkit-appearance: none;\n height: 4px;\n border-radius: 999px;\n background: var(--tcw-field-line-hover);\n outline: none;\n cursor: pointer;\n}\n\n.tcw-root input[type='range']::-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 1px 3px rgba(0, 0, 0, 0.35);\n transition: transform var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-root input[type='range']::-moz-range-thumb {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: var(--tcw-accent);\n border: 2px solid var(--tcw-bg-elevated);\n}\n\n.tcw-root input[type='range']:hover::-webkit-slider-thumb {\n transform: scale(1.12);\n}\n\n.tcw-root input[type='range']:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 4px var(--tcw-accent-soft);\n}\n\n/* --- The select list --- */\n\n.tcw-select-menu {\n z-index: 120;\n padding: var(--tcw-menu-pad);\n max-width: min(360px, calc(100vw - 16px));\n font-size: var(--tcw-font-size);\n}\n\n.tcw-select-group {\n padding: var(--tcw-space-4) var(--tcw-space-4) var(--tcw-space-2);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text-muted);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n.tcw-select-option {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-3);\n min-height: var(--tcw-menu-item-h);\n padding-block: 0;\n padding-inline: var(--tcw-space-3) var(--tcw-space-5);\n border-radius: var(--tcw-menu-item-radius);\n color: var(--tcw-text-dim);\n cursor: pointer;\n user-select: none;\n white-space: nowrap;\n}\n\n.tcw-select-option-text {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.tcw-select-check {\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n}\n\n.tcw-select-option.tcw-active {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-select-option[aria-selected='true'] {\n color: var(--tcw-text);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-select-option[aria-selected='true'] .tcw-select-check {\n background: var(--tcw-accent);\n -webkit-mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.25l3 3L12.5 5' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\") center / contain no-repeat;\n mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.25l3 3L12.5 5' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\") center / contain no-repeat;\n}\n\n.tcw-select-option[aria-disabled='true'] {\n opacity: 0.4;\n cursor: default;\n background: none;\n}\n\n/* --- The calendar --- */\n\n.tcw-calendar {\n z-index: 120;\n width: 268px;\n padding: 10px;\n background: var(--tcw-bg-elevated);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-menu-radius);\n box-shadow: var(--tcw-menu-shadow);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n animation: tcw-pop-in var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n.tcw-calendar-head {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-bottom: 8px;\n}\n\n.tcw-calendar-title {\n flex: 1;\n text-align: center;\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n letter-spacing: -0.01em;\n}\n\n.tcw-calendar-nav {\n display: inline-grid;\n place-items: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-radius-sm);\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}\n\n.tcw-calendar-nav svg {\n width: 16px;\n height: 16px;\n fill: none;\n stroke: currentColor;\n stroke-width: 1.6;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.tcw-calendar[dir='rtl'] .tcw-calendar-nav svg,\n[dir='rtl'] .tcw-calendar-nav svg {\n transform: scaleX(-1);\n}\n\n.tcw-calendar-nav:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-calendar-weekdays,\n.tcw-calendar-grid {\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n}\n\n.tcw-calendar-weekdays {\n margin-bottom: 4px;\n padding: 3px 0;\n border-radius: var(--tcw-radius-sm);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-calendar-weekday {\n text-align: center;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n color: var(--tcw-text-muted);\n line-height: 20px;\n}\n\n.tcw-calendar-grid {\n row-gap: 2px;\n}\n\n.tcw-calendar-week {\n display: contents;\n}\n\n.tcw-calendar-day {\n position: relative;\n height: 32px;\n padding: 0;\n border: none;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-calendar-day:hover:not(:disabled) {\n background: var(--tcw-hover-bg);\n}\n\n.tcw-calendar-day.tcw-outside {\n color: var(--tcw-text-muted);\n opacity: 0.55;\n}\n\n/* Today: accent figures over a short line. */\n.tcw-calendar-day.tcw-today {\n color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-calendar-day.tcw-today::after {\n content: '';\n position: absolute;\n left: 50%;\n bottom: 5px;\n width: 12px;\n height: 2px;\n margin-left: -6px;\n border-radius: 1px;\n background: currentColor;\n}\n\n.tcw-calendar-day[aria-selected='true'] {\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n font-weight: var(--tcw-weight-strong);\n opacity: 1;\n}\n\n.tcw-calendar-day:disabled {\n opacity: 0.28;\n cursor: not-allowed;\n}\n\n.tcw-calendar-day:focus {\n outline: none;\n}\n\n.tcw-calendar-day:focus-visible {\n box-shadow: inset 0 0 0 1.5px var(--tcw-accent);\n}\n\n.tcw-calendar-foot {\n display: flex;\n justify-content: flex-end;\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--tcw-divider);\n}\n\n.tcw-calendar-today {\n height: 26px;\n padding: 0 10px;\n border: none;\n border-radius: var(--tcw-radius-sm);\n background: transparent;\n color: var(--tcw-accent);\n font: inherit;\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n}\n\n.tcw-calendar-today:hover {\n background: var(--tcw-accent-soft);\n}\n\n.tcw-calendar-today:focus-visible,\n.tcw-calendar-nav:focus-visible {\n outline: none;\n box-shadow: inset 0 0 0 1.5px var(--tcw-accent);\n}\n\n/* --- Scrollbars: thin and rounded, a thumb on no track. Low specificity:\n a part that hides its bar keeps it hidden. --- */\n\n:where(.tcw-root) ::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\n\n:where(.tcw-root) ::-webkit-scrollbar-track,\n:where(.tcw-root) ::-webkit-scrollbar-corner {\n background: transparent;\n}\n\n:where(.tcw-root) ::-webkit-scrollbar-thumb {\n background: var(--tcw-scroll-thumb);\n background-clip: padding-box;\n border: 3px solid transparent;\n border-radius: 999px;\n}\n\n:where(.tcw-root) ::-webkit-scrollbar-thumb:hover {\n background: var(--tcw-scroll-thumb-hover);\n background-clip: padding-box;\n border: 2.5px solid transparent;\n}\n\n/* Engines without the pseudo-elements take the standard properties. */\n@supports not selector(::-webkit-scrollbar) {\n :where(.tcw-root, .tcw-root *) {\n scrollbar-width: thin;\n scrollbar-color: var(--tcw-scroll-thumb) transparent;\n }\n}\n\n/* --- Switches: flat, no glow --- */\n\n.tcw-root .tcw-toggle.tcw-on {\n box-shadow: none;\n}\n\n.tcw-root .tcw-toggle::after {\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);\n}\n\n.tcw-root .tcw-toggle:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--tcw-accent-soft);\n}\n\n/* One choice of a few in a row (a radio group): the chosen one as the look shows a chosen button. */\n.tcw-segmented {\n display: inline-flex;\n flex-wrap: wrap;\n max-width: 100%;\n gap: 2px;\n padding: 2px;\n border-radius: calc(var(--tcw-control-radius) + 2px);\n background: var(--tcw-hover-bg);\n}\n.tcw-segment {\n height: calc(var(--tcw-control-h) - 4px);\n padding-inline: var(--tcw-space-4);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n white-space: nowrap;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-segment:hover { color: var(--tcw-text); }\n.tcw-segment[aria-checked='true'] {\n background: var(--tcw-on-bg);\n color: var(--tcw-on-fg);\n font-weight: var(--tcw-weight-strong);\n box-shadow: var(--tcw-on-ring);\n}\n.tcw-segment:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* A number between a − and a +: one field, the figure right-aligned in the chart's mono type. */\n.tcw-stepper {\n box-sizing: border-box;\n display: inline-flex;\n align-items: stretch;\n height: var(--tcw-control-h);\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-bg);\n overflow: hidden;\n}\n.tcw-stepper:focus-within { box-shadow: var(--tcw-ring); }\n.tcw-stepper .tcw-indi-input {\n width: 110px;\n height: auto;\n padding-inline: var(--tcw-space-3);\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n text-align: end;\n -moz-appearance: textfield;\n appearance: textfield;\n}\n.tcw-stepper .tcw-indi-input::-webkit-inner-spin-button,\n.tcw-stepper .tcw-indi-input::-webkit-outer-spin-button { margin: 0; -webkit-appearance: none; }\n.tcw-stepper .tcw-indi-input:focus { outline: none; box-shadow: none; }\n.tcw-stepper-btn {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--tcw-control-h);\n border: none;\n background: transparent;\n color: var(--tcw-text-dim);\n cursor: pointer;\n}\n.tcw-stepper-btn:hover { background: var(--tcw-hover-bg); color: var(--tcw-text); }\n.tcw-stepper-btn:focus-visible { outline: none; background: var(--tcw-hover-bg); color: var(--tcw-text); }\n\n/* Forced colours drop the box-shadow rings: an outline marks focus and the chosen choice. */\n@media (forced-colors: active) {\n .tcw-segment[aria-checked='true'] { outline: 2px solid Highlight; }\n .tcw-segment:focus-visible,\n .tcw-stepper-btn:focus-visible { outline: 2px solid Highlight; outline-offset: -2px; }\n .tcw-stepper:focus-within { outline: 2px solid Highlight; }\n}\n", Lt = "/* === The indicators dialog === */\n\n/* 610 wide, a Fibonacci number: the groups take 233 and the list 377 beside them (377 : 233 = phi).\n A fixed height, so the dialog keeps still while a search shortens the list. */\n.tcw-modal.tcw-ip {\n width: 610px;\n height: min(610px, 86vh);\n height: min(610px, 86dvh);\n max-height: none;\n}\n\n.tcw-ip-search,\n.tcw-ss-search {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-3);\n flex: none;\n height: var(--tcw-control-h);\n margin: var(--tcw-space-4) var(--tcw-space-6);\n padding: 0 var(--tcw-space-4);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-input-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text-muted);\n transition: border-color var(--tcw-dur-fast) var(--tcw-ease), box-shadow var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-ip-search:focus-within,\n.tcw-ss-search:focus-within {\n border-color: var(--tcw-accent);\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-ip-search svg,\n.tcw-ss-search svg {\n flex: none;\n}\n\n.tcw-ip-search input,\n.tcw-ss-search input {\n flex: 1;\n min-width: 0;\n height: 100%;\n border: none;\n outline: none;\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size);\n}\n\n.tcw-ip-search input::placeholder,\n.tcw-ss-search input::placeholder {\n color: var(--tcw-text-muted);\n}\n\n.tcw-ip-body {\n display: grid;\n grid-template-columns: 233px minmax(0, 1fr);\n flex: 1;\n min-height: 0;\n border-top: 1px solid var(--tcw-divider);\n}\n\n.tcw-ip-nav,\n.tcw-set-nav {\n display: flex;\n flex-direction: column;\n gap: 1px;\n padding: var(--tcw-space-4) var(--tcw-space-3);\n /* Logical sides: in Arabic, Hebrew or Persian the tabs sit on the right. */\n border-inline-end: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-surface);\n overflow-y: auto;\n border-end-start-radius: var(--tcw-dialog-radius);\n}\n\n.tcw-ip-tab,\n.tcw-set-tab {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-3);\n flex: none;\n height: var(--tcw-menu-item-h);\n padding: 0 var(--tcw-space-4);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size);\n text-align: start;\n white-space: nowrap;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-ip-tab svg,\n.tcw-set-tab svg {\n flex: none;\n}\n\n/* The kinds start below a gap: favourites and templates are yours, the rest the library's. */\n.tcw-ip-tab[data-view='all'] {\n margin-top: var(--tcw-space-4);\n}\n\n.tcw-ip-tab:hover,\n.tcw-set-tab:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-ip-tab.tcw-active,\n.tcw-set-tab.tcw-active {\n background: var(--tcw-on-bg);\n color: var(--tcw-on-fg);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-ip-nav--searching .tcw-ip-tab.tcw-active {\n background: transparent;\n color: var(--tcw-text-dim);\n font-weight: var(--tcw-weight);\n}\n\n.tcw-ip-list {\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: 0 var(--tcw-space-4) var(--tcw-space-5);\n}\n\n/* Each kind's name stays at the top while its indicators scroll under it. */\n.tcw-ip-heading {\n position: sticky;\n top: 0;\n z-index: 1;\n padding: var(--tcw-space-5) var(--tcw-space-4) var(--tcw-space-2);\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n.tcw-ip-list > :first-child:not(.tcw-ip-heading) {\n margin-top: var(--tcw-space-4);\n}\n\n.tcw-ip-row {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-1);\n border-radius: var(--tcw-menu-item-radius);\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-ip-row:hover {\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ip-add {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-3);\n flex: 1;\n min-width: 0;\n height: var(--tcw-menu-item-h);\n padding: 0 var(--tcw-space-4);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n font-size: var(--tcw-font-size);\n text-align: start;\n cursor: pointer;\n}\n\n.tcw-ip-add:focus-visible,\n.tcw-ip-aside:focus-visible,\n.tcw-ip-tab:focus-visible,\n.tcw-set-tab:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-ip-add svg {\n flex: none;\n color: var(--tcw-text-muted);\n}\n\n.tcw-ip-name {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-ip-short {\n flex: none;\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n}\n\n/* Where it draws, quietly at the row's end. */\n.tcw-ip-kind {\n flex: none;\n margin-inline-start: auto;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n/* How many are on the chart: ink on its wash, the figures in a column. */\n.tcw-ip-count {\n flex: none;\n display: inline-grid;\n place-items: center;\n min-width: var(--tcw-space-6);\n height: var(--tcw-space-6);\n padding: 0 var(--tcw-space-2);\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-accent-soft);\n color: var(--tcw-accent);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n}\n\n.tcw-ip-aside {\n flex: none;\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n/* Shown on the row in hand; always for a starred one, filled in ink; always on a touch screen. */\n.tcw-ip-row:hover .tcw-ip-aside,\n.tcw-ip-row:focus-within .tcw-ip-aside,\n.tcw-ip-star[aria-pressed='true'] {\n opacity: 1;\n}\n\n@media (hover: none) {\n .tcw-ip-aside {\n opacity: 1;\n }\n}\n\n.tcw-ip-aside:hover {\n color: var(--tcw-text);\n background: var(--tcw-hover-bg);\n}\n\n.tcw-ip-star[aria-pressed='true'] {\n color: var(--tcw-accent);\n}\n\n.tcw-ip-star[aria-pressed='true'] svg path {\n fill: currentColor;\n}\n\n.tcw-ip-remove:hover {\n color: var(--tcw-red);\n}\n\n.tcw-ip-save {\n flex: none;\n width: 100%;\n color: var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-ip-save svg {\n color: currentColor;\n}\n\n.tcw-ip-save:hover {\n background: var(--tcw-accent-soft);\n}\n\n.tcw-ip-empty {\n max-width: 34ch;\n padding: var(--tcw-space-6) var(--tcw-space-4);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.5;\n text-wrap: pretty;\n}\n\n/* Heard by a screen reader, not seen. */\n.tcw-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n/* A phone: the dialog is the widget's sheet, as tall as a sheet goes, and the groups a row of chips. */\n@media (max-width: 640px) {\n .tcw-modal.tcw-ip {\n /* Above the on-screen keyboard: the sheet's top stays on the screen. */\n height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n\n .tcw-ip-search,\n .tcw-ss-search {\n margin-inline: var(--tcw-space-4);\n }\n\n .tcw-ip-body {\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto minmax(0, 1fr);\n }\n\n .tcw-ip-nav,\n .tcw-set-nav {\n flex-direction: row;\n gap: var(--tcw-space-2);\n padding: var(--tcw-space-3) var(--tcw-space-4);\n border-inline-end: none;\n border-bottom: 1px solid var(--tcw-divider);\n border-radius: 0;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n }\n\n .tcw-ip-tab[data-view='all'] {\n margin-top: 0;\n margin-inline-start: var(--tcw-space-4);\n }\n\n .tcw-ip-tab,\n .tcw-set-tab {\n /* A finger's size, as the dialogs' other tabs on a phone. */\n min-height: 40px;\n border: var(--tcw-border-w) solid var(--tcw-border);\n }\n\n\n .tcw-ip-list {\n padding-inline: var(--tcw-space-3);\n }\n}\n\n/* === The indicator settings, and a drawing's === */\n\n/* One half step of phi under the indicators dialog: 610 / sqrt(phi) = 480. */\n@media (min-width: 641px) {\n .tcw-modal.tcw-modal-narrow.tcw-indi,\n .tcw-modal.tcw-modal-narrow.tcw-drawing-settings {\n width: 480px;\n max-width: 92vw;\n }\n}\n\n/* A line, or a kind of interval: ticked where it shows, its name, then what sets it. */\n.tcw-indi-plot-name {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-4);\n min-width: 0;\n cursor: pointer;\n}\n\n.tcw-indi-plot-name .tcw-settings-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Unticked, its name steps back. */\n.tcw-indi-plot-name:has(input:not(:checked)) .tcw-settings-label {\n color: var(--tcw-text-muted);\n}\n\n.tcw-indi-plot-controls,\n.tcw-indi-range {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-3);\n flex: none;\n}\n\n.tcw-indi-plot-controls .tcw-indi-select {\n width: 104px;\n}\n\n.tcw-indi-range {\n color: var(--tcw-text-muted);\n}\n\n.tcw-indi-range .tcw-indi-input {\n width: 68px;\n text-align: end;\n}\n\n.tcw-indi-range .tcw-indi-input:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n\n/* Defaults on the left; Cancel and Ok on the right, one height for all three. */\n.tcw-indi .tcw-modal-footer,\n.tcw-set .tcw-modal-footer,\n.tcw-drawing-settings .tcw-modal-footer {\n gap: var(--tcw-space-4);\n}\n\n.tcw-footer-end {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n}\n\n.tcw-indi .tcw-modal-footer button,\n.tcw-set .tcw-modal-footer button,\n.tcw-drawing-settings .tcw-modal-footer button {\n height: var(--tcw-menu-item-h);\n padding-block: 0;\n}\n\n.tcw-footer-menu,\n.tcw-footer-cancel {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-2);\n padding-inline: var(--tcw-space-5);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-footer-cancel {\n border-color: var(--tcw-border-strong);\n color: var(--tcw-text);\n}\n\n.tcw-footer-menu:hover,\n.tcw-footer-menu[aria-expanded='true'],\n.tcw-footer-cancel:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-footer-menu:focus-visible,\n.tcw-footer-cancel:focus-visible,\n.tcw-indi .tcw-done-btn:focus-visible,\n.tcw-set .tcw-done-btn:focus-visible,\n.tcw-drawing-settings .tcw-done-btn:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* A drawing's switches: the box, then its name, a list without rules between. */\n.tcw-check-row {\n justify-content: flex-start;\n gap: var(--tcw-space-4);\n padding-block: var(--tcw-space-3);\n cursor: pointer;\n}\n\n.tcw-settings-row + .tcw-check-row,\n.tcw-check-row + .tcw-settings-row {\n border-top: 0;\n}\n\n/* A point: its name, then its price, date and time in columns; on a phone the price over the date and time. */\n.tcw-draw-point {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) minmax(0, 1.3fr) minmax(0, 1fr);\n gap: var(--tcw-space-4);\n}\n\n.tcw-draw-point > .tcw-settings-label {\n white-space: nowrap;\n}\n\n.tcw-draw-point .tcw-indi-plot-controls {\n display: contents;\n}\n\n.tcw-draw-point input {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n}\n\n.tcw-draw-point input[type='number'] {\n text-align: end;\n}\n\n@media (max-width: 640px) {\n .tcw-draw-point {\n grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr);\n }\n\n .tcw-draw-point > .tcw-settings-label {\n grid-row: span 2;\n }\n\n .tcw-draw-point input[type='number'] {\n grid-column: span 2;\n }\n}\n\n.tcw-drawing-settings .tcw-indi-plot-controls input[type='number']:not(.tcw-draw-point *) {\n width: 68px;\n text-align: end;\n}\n\n/* The unit after a number (the fill's opacity in %). */\n.tcw-unit {\n margin-inline-start: calc(-1 * var(--tcw-space-2));\n color: var(--tcw-text-muted);\n}\n\n/* === The chart settings === */\n\n/* 776 x 610: half a step of phi wider than the indicators dialog (610 x sqrt(phi) = 776), as tall as it,\n so the dialog is a sqrt(phi) rectangle. The tabs take 233 down the side, as the indicator groups do. */\n.tcw-modal.tcw-set {\n width: 776px;\n max-width: 94vw;\n height: min(610px, 86vh);\n height: min(610px, 86dvh);\n max-height: none;\n}\n\n.tcw-set-body {\n display: grid;\n grid-template-columns: 233px minmax(0, 1fr);\n flex: 1;\n min-height: 0;\n}\n\n.tcw-set-panel {\n min-width: 0;\n}\n\n/* A phone: the widget's sheet across the screen, the tabs a row of chips over the settings. After the rules above, which it overrides. */\n@media (max-width: 640px) {\n .tcw-modal.tcw-set {\n width: 100vw;\n max-width: 100vw;\n /* Above the on-screen keyboard: the sheet's top stays on the screen. */\n height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n\n .tcw-set-body {\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto minmax(0, 1fr);\n }\n}\n\n/* === The symbol search, and the same dialog comparing === */\n\n/* As wide and as still as the indicators dialog: 610, a fixed height while a search shortens the list. */\n.tcw-modal.tcw-ss {\n width: 610px;\n height: min(610px, 86vh);\n height: min(610px, 86dvh);\n max-height: none;\n}\n\n/* Comparing: how the next symbol goes on the chart, under the search. */\n.tcw-ss-way {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n flex: none;\n margin: 0 var(--tcw-space-6) var(--tcw-space-4);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n}\n\n.tcw-ss-way > span {\n flex: none;\n}\n\n.tcw-root .tcw-ss-way-select {\n flex: 1;\n min-width: 0;\n height: var(--tcw-control-h);\n padding-block: 0;\n}\n\n/* The kinds the results come in: All, stock, crypto… */\n.tcw-ss-kinds {\n display: flex;\n flex-wrap: wrap;\n flex: none;\n gap: var(--tcw-space-3);\n margin: 0 var(--tcw-space-6) var(--tcw-space-4);\n}\n\n.tcw-ss-type {\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-5);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n text-transform: capitalize;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease), border-color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-ss-type:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-ss-type[aria-pressed='true'] {\n border-color: var(--tcw-accent);\n background: var(--tcw-accent-soft);\n color: var(--tcw-accent);\n}\n\n.tcw-ss-type:focus-visible,\n.tcw-ss-remove:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* The symbol takes 144 (89 x phi), the name the rest; kind and exchange at the end. The heads line up\n with the rows: the inset of what scrolls and the row's own. */\n.tcw-ss-columns,\n.tcw-ss-row {\n display: grid;\n grid-template-columns: 144px minmax(0, 1fr) auto;\n align-items: center;\n column-gap: var(--tcw-space-5);\n}\n\n.tcw-ss-columns {\n flex: none;\n padding: var(--tcw-space-3) calc(var(--tcw-space-4) * 2);\n border-top: 1px solid var(--tcw-divider);\n border-bottom: 1px solid var(--tcw-divider);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n/* What scrolls: what is compared, the symbols, a note when there are none. */\n.tcw-ss-results {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n /* A row the arrows reach scrolls in below its heading, not under it. */\n scroll-padding-block-start: calc(var(--tcw-space-5) + var(--tcw-space-2) + var(--tcw-font-size-xs) * 1.5 - var(--tcw-space-3));\n padding: var(--tcw-space-3) var(--tcw-space-4) var(--tcw-space-5);\n}\n\n.tcw-ss-row {\n min-height: var(--tcw-menu-item-h);\n padding: 0 var(--tcw-space-4);\n border-radius: var(--tcw-menu-item-radius);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-ss-row.tcw-selected {\n background: var(--tcw-hover-bg);\n}\n\n/* The figures of a ticker, in the mono face, left to right in any widget, at the start of its column;\n the chart's own in ink. */\n.tcw-ss-symbol {\n justify-self: start;\n max-width: 100%;\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-text);\n font-family: var(--tcw-font-mono);\n font-weight: var(--tcw-weight-strong);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-ss-row.tcw-current .tcw-ss-symbol {\n color: var(--tcw-accent);\n}\n\n.tcw-ss-symbol mark {\n background: transparent;\n color: var(--tcw-accent);\n}\n\n.tcw-ss-desc-cell {\n min-width: 0;\n}\n\n/* As wide as its words, at the start of the column, whichever way they run. */\n.tcw-ss-desc {\n display: block;\n width: fit-content;\n max-width: 100%;\n overflow: hidden;\n color: var(--tcw-text-dim);\n font-size: var(--tcw-font-size-sm);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-ss-meta {\n display: flex;\n align-items: baseline;\n gap: var(--tcw-space-4);\n justify-self: end;\n white-space: nowrap;\n}\n\n.tcw-ss-kind {\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n}\n\n.tcw-ss-exchange {\n color: var(--tcw-text-dim);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n/* The chart's symbol, or one on it already: a check after the exchange. */\n.tcw-ss-row:has(.tcw-ss-check) {\n grid-template-columns: 144px minmax(0, 1fr) auto auto;\n}\n\n.tcw-ss-check {\n display: inline-grid;\n place-items: center;\n color: var(--tcw-accent);\n}\n\n.tcw-ss-heading[hidden] {\n display: none;\n}\n\n/* \"On the chart\" and \"Symbols\", above their rows while they scroll. */\n.tcw-ss-heading {\n position: sticky;\n top: calc(var(--tcw-space-3) * -1);\n z-index: 1;\n padding: var(--tcw-space-5) var(--tcw-space-4) var(--tcw-space-2);\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n.tcw-ss-added-row {\n display: grid;\n grid-template-columns: 144px minmax(0, 1fr) auto;\n align-items: center;\n column-gap: var(--tcw-space-5);\n min-height: var(--tcw-menu-item-h);\n padding: 0 var(--tcw-space-4);\n border-radius: var(--tcw-menu-item-radius);\n}\n\n.tcw-ss-added-row:hover {\n background: var(--tcw-hover-bg);\n}\n\n/* How it is compared, after the line's colour where it has one of its own. */\n.tcw-ss-way-cell {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n min-width: 0;\n}\n\n.tcw-ss-swatch {\n flex: none;\n width: var(--tcw-space-4);\n height: var(--tcw-space-4);\n border-radius: var(--tcw-radius-sm);\n}\n\n.tcw-ss-way-label {\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-text-dim);\n font-size: var(--tcw-font-size-sm);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-ss-remove {\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n\n.tcw-ss-remove:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-red);\n}\n\n.tcw-ss-empty {\n max-width: 44ch;\n padding: var(--tcw-space-6) var(--tcw-space-4);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.5;\n text-wrap: pretty;\n}\n\n/* The way the dialog opens too: a letter typed on the chart. */\n.tcw-ss-foot {\n flex: none;\n padding: var(--tcw-space-5) var(--tcw-space-6);\n border-top: 1px solid var(--tcw-divider);\n border-radius: 0 0 var(--tcw-dialog-radius) var(--tcw-dialog-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n text-align: center;\n}\n\n/* === Go to === */\n\n/* 377: the step of phi under the search dialogs. */\n@media (min-width: 641px) {\n .tcw-modal.tcw-goto {\n width: 377px;\n }\n}\n\n.tcw-goto-form {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n\n.tcw-goto-fields {\n display: grid;\n gap: var(--tcw-space-5);\n padding: var(--tcw-space-6) var(--tcw-space-6) var(--tcw-space-4);\n}\n\n/* The date takes the room; the time 144 beside it; a range's end named above its two. */\n.tcw-goto-row {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 144px;\n gap: var(--tcw-space-3) var(--tcw-space-4);\n align-items: center;\n}\n\n.tcw-goto-label {\n grid-column: 1 / -1;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n.tcw-root .tcw-goto-input {\n width: 100%;\n min-width: 0;\n height: var(--tcw-control-h);\n box-sizing: border-box;\n padding: 0 var(--tcw-space-4);\n font-size: var(--tcw-font-size);\n font-variant-numeric: tabular-nums;\n}\n\n/* No time on daily bars: the date across the row. */\n.tcw-goto-input[type='date']:last-child {\n grid-column: 1 / -1;\n}\n\n/* The month under the fields, part of the dialog: no card of its own. */\n.tcw-calendar.tcw-goto-calendar {\n position: static;\n width: auto;\n padding: var(--tcw-space-4) var(--tcw-space-6) var(--tcw-space-5);\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n animation: none;\n}\n\n.tcw-goto-calendar .tcw-calendar-day {\n height: 34px;\n}\n\n.tcw-goto .tcw-modal-footer {\n justify-content: flex-end;\n gap: var(--tcw-space-4);\n}\n\n.tcw-goto .tcw-modal-footer button {\n height: var(--tcw-menu-item-h);\n padding-block: 0;\n}\n\n.tcw-goto .tcw-done-btn:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* A phone: both are the widget's sheet; the search as tall as a sheet goes, its symbols 89 wide. */\n@media (max-width: 640px) {\n .tcw-modal.tcw-ss {\n /* Above the on-screen keyboard: the sheet's top stays on the screen. */\n height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n\n .tcw-ss-way,\n .tcw-ss-kinds {\n margin-inline: var(--tcw-space-4);\n }\n\n .tcw-ss-columns,\n .tcw-ss-row,\n .tcw-ss-added-row {\n grid-template-columns: 89px minmax(0, 1fr) auto;\n }\n\n .tcw-ss-row:has(.tcw-ss-check) {\n grid-template-columns: 89px minmax(0, 1fr) auto auto;\n }\n\n .tcw-ss-kind {\n display: none;\n }\n\n .tcw-ss-row,\n .tcw-ss-added-row {\n min-height: 44px;\n }\n}\n\n/* Without a keyboard there are no letters to type on the chart. */\n@media (hover: none) and (pointer: coarse) {\n .tcw-ss-foot {\n display: none;\n }\n}\n\n/* === The shortcut sheet === */\n\n/* As wide and as still as the indicators dialog: 610, a fixed height while a search shortens the list. */\n.tcw-modal.tcw-hotkey-sheet {\n width: 610px;\n height: min(610px, 86vh);\n height: min(610px, 86dvh);\n max-height: none;\n}\n\n.tcw-hotkey-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: 0 var(--tcw-space-6) var(--tcw-space-5);\n border-top: 1px solid var(--tcw-divider);\n columns: 2;\n column-gap: var(--tcw-space-7);\n}\n\n/* A group keeps together in its column, its name above its rows. */\n.tcw-hotkey-group {\n break-inside: avoid;\n padding-top: var(--tcw-space-5);\n}\n\n.tcw-hotkey-heading {\n padding-bottom: var(--tcw-space-3);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n/* What it does on the left, its keys on the right, the keys in a column of their own. */\n.tcw-hotkey-row {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--tcw-space-4);\n min-height: calc(var(--tcw-space-6) + var(--tcw-space-3));\n padding: var(--tcw-space-2) 0;\n}\n\n.tcw-hotkey-label {\n min-width: 0;\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.4;\n}\n\n.tcw-hotkey-keys {\n display: inline-flex;\n align-items: baseline;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: var(--tcw-space-2);\n flex: none;\n max-width: 55%;\n}\n\n/* A key: its name in the mono face on a key's face. */\n.tcw-hotkey-key,\n.tcw-cp-key {\n display: inline-block;\n min-width: calc(var(--tcw-space-6) - var(--tcw-space-2));\n padding: 0 var(--tcw-space-3);\n border: var(--tcw-border-w) solid var(--tcw-border);\n border-bottom-width: 2px;\n border-radius: var(--tcw-tag-radius);\n background: var(--tcw-bg);\n color: var(--tcw-text-dim);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.6;\n text-align: center;\n white-space: nowrap;\n}\n\n/* A gesture is not a key: its words, quieter. */\n.tcw-hotkey-gesture {\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n white-space: nowrap;\n}\n\n.tcw-hotkey-sep {\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n}\n\n.tcw-hotkey-empty {\n padding: var(--tcw-space-6) 0;\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n}\n\n/* How to open it again, at its foot. */\n.tcw-hotkey-foot {\n flex: none;\n padding: var(--tcw-space-5) var(--tcw-space-6);\n border-top: 1px solid var(--tcw-divider);\n border-radius: 0 0 var(--tcw-dialog-radius) var(--tcw-dialog-radius);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n}\n\n/* === The command palette === */\n\n/* 610 wide, a third of the way down: a launcher, not a form; its search is the dialogs' search row. */\n.tcw-modal.tcw-cp {\n top: 19.1%;\n transform: translate(-50%, 0);\n width: 610px;\n max-height: min(610px, 76.4vh);\n max-height: min(610px, 76.4dvh);\n animation: none;\n}\n\n.tcw-cp .tcw-cp-search {\n margin-top: var(--tcw-space-5);\n}\n\n.tcw-cp-results {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n /* A row the arrows reach scrolls in below its group's heading, not under it. */\n scroll-padding-block-start: calc(var(--tcw-space-5) + var(--tcw-space-2) + var(--tcw-font-size-xs) * 1.5);\n padding: 0 var(--tcw-space-4) var(--tcw-space-4);\n border-top: 1px solid var(--tcw-divider);\n}\n\n.tcw-cp-heading {\n position: sticky;\n top: 0;\n z-index: 1;\n padding: var(--tcw-space-5) var(--tcw-space-4) var(--tcw-space-2);\n background: var(--tcw-bg-elevated);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n\n.tcw-cp-row {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n min-height: var(--tcw-menu-item-h);\n padding: 0 var(--tcw-space-4);\n border-radius: var(--tcw-menu-item-radius);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size);\n cursor: pointer;\n}\n\n.tcw-cp-row.tcw-selected {\n background: var(--tcw-hover-bg);\n}\n\n.tcw-cp-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* What is on now: its name in ink, a check at the end. */\n.tcw-cp-row.tcw-on .tcw-cp-label {\n color: var(--tcw-accent);\n}\n\n.tcw-cp-check {\n display: inline-grid;\n place-items: center;\n flex: none;\n color: var(--tcw-accent);\n}\n\n.tcw-cp-empty {\n padding: var(--tcw-space-6) var(--tcw-space-4);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n}\n\n/* === Layouts === */\n\n/* 480, as the settings of an indicator: a list of names and when they were saved. On a phone, the sheet's width. */\n.tcw-modal.tcw-layouts-dialog {\n max-height: min(610px, 86vh);\n max-height: min(610px, 86dvh);\n}\n@media (min-width: 641px) {\n .tcw-modal.tcw-layouts-dialog { width: 480px; }\n}\n\n.tcw-layouts-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: var(--tcw-space-3) var(--tcw-space-4) var(--tcw-space-5);\n border-top: 1px solid var(--tcw-divider);\n}\n\n.tcw-layouts-list {\n display: flex;\n flex-direction: column;\n gap: var(--tcw-space-1);\n}\n\n.tcw-layouts-row {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-2);\n padding-inline-end: var(--tcw-space-3);\n border-radius: var(--tcw-menu-item-radius);\n}\n\n.tcw-layouts-row:hover,\n.tcw-layouts-row:focus-within {\n background: var(--tcw-hover-bg);\n}\n\n/* A column for the check of the one open, so every name starts at the same place. */\n.tcw-layouts-open {\n display: grid;\n grid-template-columns: var(--tcw-space-5) minmax(0, 1fr);\n column-gap: var(--tcw-space-3);\n align-items: center;\n flex: 1;\n min-width: 0;\n padding: var(--tcw-space-3) var(--tcw-space-4);\n border: none;\n border-radius: var(--tcw-menu-item-radius);\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n text-align: start;\n cursor: pointer;\n}\n\n.tcw-layouts-open:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-layouts-name,\n.tcw-layouts-meta {\n grid-column: 2;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-layouts-name {\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-layouts-meta {\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n}\n\n.tcw-layouts-check {\n display: inline-grid;\n place-items: center;\n grid-column: 1;\n grid-row: 1 / span 2;\n color: var(--tcw-accent);\n}\n\n.tcw-layouts-open[aria-current='true'] .tcw-layouts-name {\n color: var(--tcw-accent);\n}\n\n/* Rename and delete show on the row in hand; always on a touch screen. */\n.tcw-layouts-row .tcw-account-actions {\n display: flex;\n gap: var(--tcw-space-1);\n opacity: 0;\n transition: opacity var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-layouts-row:is(:hover, :focus-within) .tcw-account-actions,\n.tcw-layouts-row .tcw-account-actions:has(.tcw-layouts-confirm) {\n opacity: 1;\n}\n\n@media (hover: none) {\n .tcw-layouts-row .tcw-account-actions {\n opacity: 1;\n }\n}\n\n.tcw-layouts-confirm {\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-4);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-red);\n /* White on the red in every theme. */\n color: #fff;\n font: inherit;\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n}\n\n.tcw-layouts-confirm:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* A phone: the sheets as tall as they go, the shortcuts in one column. */\n@media (max-width: 640px) {\n .tcw-modal.tcw-hotkey-sheet {\n height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n\n .tcw-hotkey-body {\n columns: 1;\n padding-inline: var(--tcw-space-4);\n }\n\n /* Their own heights outrank the sheet's: give them back its height, less the keyboard, and the palette its slide up. */\n .tcw-modal.tcw-cp,\n .tcw-modal.tcw-layouts-dialog {\n max-height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n max-height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n\n .tcw-modal.tcw-cp {\n top: auto;\n transform: none;\n animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);\n }\n\n .tcw-cp .tcw-cp-search {\n margin-top: var(--tcw-space-3);\n }\n\n :is(.tcw-hotkey-search, .tcw-cp-search, .tcw-layouts-search-row) {\n margin-inline: var(--tcw-space-4);\n }\n\n .tcw-cp-row {\n min-height: 44px;\n }\n}\n\n/* === The order ticket === */\n\n/* 480, as a drawing's settings: the side, the order, its stop and target, then the receipt. On a phone, the sheet's width. */\n.tcw-modal.tcw-order-ticket {\n max-height: min(610px, 92vh);\n max-height: min(610px, 92dvh);\n}\n@media (min-width: 641px) {\n .tcw-modal.tcw-order-ticket { width: 480px; }\n}\n.tcw-order-ticket[data-side='buy'] { --tcw-side: var(--tcw-green); }\n.tcw-order-ticket[data-side='sell'] { --tcw-side: var(--tcw-red); }\n\n.tcw-ticket-heading {\n display: flex;\n align-items: baseline;\n gap: var(--tcw-space-4);\n min-width: 0;\n}\n.tcw-ticket-symbol {\n overflow: hidden;\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size);\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.tcw-ticket-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n/* Buy and Sell: the chosen one filled with its colour, the ground's own colour on it. */\n.tcw-ticket-side {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: var(--tcw-space-3);\n margin-bottom: var(--tcw-space-4);\n}\n.tcw-ticket-side-btn {\n height: 34px;\n border: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-size: var(--tcw-font-size-lg);\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-ticket-side-btn:hover { color: var(--tcw-text); }\n.tcw-ticket-buy[aria-pressed='true'] { border-color: var(--tcw-green); background: var(--tcw-green); color: var(--tcw-bg); }\n.tcw-ticket-sell[aria-pressed='true'] { border-color: var(--tcw-red); background: var(--tcw-red); color: var(--tcw-bg); }\n.tcw-ticket-side-btn:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n\n/* A row's control goes under its name when they don't fit side by side (a long choice at 320 px). */\n.tcw-ticket-row {\n flex-wrap: wrap;\n gap: var(--tcw-space-3) var(--tcw-space-5);\n}\n.tcw-ticket-market {\n color: var(--tcw-text-dim);\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n}\n\n/* A stop or a target: its switch, its name with how far it is under it, then its price. */\n.tcw-ticket-optional {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--tcw-space-4);\n}\n.tcw-ticket-optional-name {\n display: flex;\n flex-direction: column;\n gap: var(--tcw-space-1);\n min-width: 0;\n}\n.tcw-ticket-away {\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n overflow-wrap: anywhere;\n /* Left to right inside, but at the name's start in either direction (the column's, not its own). */\n align-self: flex-start;\n}\n\n/* The receipt: under a torn-paper rule, each sum a label and a figure in the mono type. */\n.tcw-ticket-summary:not(:empty) {\n display: grid;\n gap: var(--tcw-space-2);\n margin: 0 var(--tcw-space-6) var(--tcw-space-4);\n padding-top: var(--tcw-space-4);\n border-top: var(--tcw-border-w) dashed var(--tcw-border-strong);\n}\n.tcw-ticket-summary-row {\n display: flex;\n justify-content: space-between;\n gap: var(--tcw-space-5);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-ticket-figure {\n color: var(--tcw-text);\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n}\n.tcw-ticket-figure.tcw-ticket-up { color: var(--tcw-green); }\n.tcw-ticket-figure.tcw-ticket-down { color: var(--tcw-red); }\n\n.tcw-ticket-problems {\n padding: 0 var(--tcw-space-6) var(--tcw-space-4);\n color: var(--tcw-red);\n font-size: var(--tcw-font-size-sm);\n}\n.tcw-ticket-problems p { margin: var(--tcw-space-1) 0; }\n\n/* Cancel and Place alone, at the end, as tall as each other. */\n.tcw-order-ticket .tcw-modal-footer { justify-content: flex-end; }\n.tcw-order-ticket .tcw-modal-footer button { height: var(--tcw-menu-item-h); padding-block: 0; }\n.tcw-ticket-place {\n height: var(--tcw-menu-item-h);\n padding-inline: var(--tcw-space-6);\n border: none;\n border-radius: var(--tcw-control-radius);\n background: var(--tcw-side, var(--tcw-accent));\n color: var(--tcw-bg);\n font: inherit;\n font-size: var(--tcw-font-size);\n font-weight: var(--tcw-weight-strong);\n cursor: pointer;\n}\n.tcw-ticket-place:hover:not(:disabled) { background: color-mix(in srgb, var(--tcw-side, var(--tcw-accent)) 86%, var(--tcw-text)); }\n.tcw-ticket-place:disabled { opacity: 0.45; cursor: not-allowed; }\n.tcw-ticket-place:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n\n/* A phone: the ticket is a sheet above the keyboard, its controls a finger's size. */\n@media (max-width: 640px) {\n .tcw-modal.tcw-order-ticket {\n max-height: calc(92vh - var(--tcw-keyboard-inset, 0px));\n max-height: calc(92dvh - var(--tcw-keyboard-inset, 0px));\n }\n .tcw-stepper .tcw-indi-input { width: 96px; }\n .tcw-stepper-btn, .tcw-segment { min-width: 34px; }\n .tcw-segment { height: 34px; }\n .tcw-stepper { height: 38px; }\n}\n\n/* Forced colours drop the box-shadow rings: an outline marks focus and the chosen side. */\n@media (forced-colors: active) {\n .tcw-ticket-side-btn[aria-pressed='true'] { outline: 2px solid Highlight; }\n .tcw-ticket-place { border: 1px solid ButtonText; }\n .tcw-ticket-side-btn:focus-visible,\n .tcw-ticket-place:focus-visible { outline: 2px solid Highlight; outline-offset: 2px; }\n}\n", Rt = "/* === The dock: the panels by the chart, and their rail === */\n\n/* In the body's row after the chart: the panel of the page open beside the chart, the rail at the outer edge\n (both mirror in a right-to-left widget). */\n.tcw-dock {\n position: relative;\n display: flex;\n flex: none;\n min-height: 0;\n}\n\n/* The rail: as wide as the drawing tools on the other side, its buttons as theirs. */\n.tcw-dock-rail {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--tcw-space-2);\n width: var(--tcw-sidebar-w);\n padding: var(--tcw-space-3) 0;\n border-inline-start: var(--tcw-border-w) solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n}\n\n.tcw-dock-btn {\n display: inline-grid;\n place-items: center;\n flex: none;\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-dock-btn svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\n}\n\n.tcw-dock-btn:hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n/* The page open: in ink on its wash, as a tool in use on the other side. */\n.tcw-dock-btn[aria-pressed='true'] {\n background: var(--tcw-on-icon-bg, var(--tcw-accent-soft));\n color: var(--tcw-on-icon-fg, var(--tcw-accent));\n}\n\n.tcw-dock-btn:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* The edge in focus shows as its line, in ink: a ring round a strip this thin reads as two lines. */\n.tcw-dock-resize:focus-visible {\n outline: none;\n}\n\n@media (forced-colors: active) {\n .tcw-dock-resize:is(:hover, :active, :focus-visible)::after {\n background: Highlight;\n }\n}\n\n/* The panel: 296 wide to start (377 / sqrt(phi)), from 233 to 377. */\n.tcw-dock-panel {\n position: relative;\n display: flex;\n flex-direction: column;\n width: var(--tcw-dock-w, 296px);\n min-height: 0;\n border-inline-start: var(--tcw-border-w) solid var(--tcw-border);\n background: var(--tcw-bg-surface);\n}\n\n/* Its edge by the chart: a strip to drag, a line in ink while in hand. */\n.tcw-dock-resize {\n position: absolute;\n inset-block: 0;\n inset-inline-start: calc(var(--tcw-space-3) * -1);\n z-index: 3;\n width: calc(var(--tcw-space-3) * 2);\n cursor: col-resize;\n touch-action: none;\n}\n\n.tcw-dock-resize::after {\n content: '';\n position: absolute;\n inset-block: 0;\n inset-inline-start: calc(var(--tcw-space-3) - 1px);\n width: 2px;\n background: transparent;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n.tcw-dock-resize:hover::after,\n.tcw-dock-resize:active::after,\n.tcw-dock-resize:focus-visible::after {\n background: var(--tcw-accent);\n}\n\n/* A page fills the panel and scrolls under its header; the floating panels it was lose their card. */\n.tcw-dock-panel > .tcw-dock-page {\n position: static;\n inset: auto;\n display: flex;\n flex-direction: column;\n flex: 1;\n width: auto;\n max-width: none;\n max-height: none;\n min-height: 0;\n margin: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n animation: none;\n}\n\n/* One header for every page: its title, its own buttons, and the close at the end. 34 tall (21 + 13). */\n.tcw-dock-page > :is(.tcw-watchlist-header, .tcw-alerts-header, .tcw-tree-header, .tcw-datawin-header, .tcw-syminfo-header, .tcw-ladder-header) {\n position: sticky;\n top: 0;\n z-index: 2;\n display: flex;\n align-items: center;\n gap: var(--tcw-space-2);\n flex: none;\n min-height: calc(var(--tcw-space-6) + var(--tcw-space-5));\n margin: 0;\n padding-block: 0;\n padding-inline: var(--tcw-space-5) var(--tcw-space-3);\n border-bottom: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n}\n\n.tcw-dock-page > :is(.tcw-alerts-header, .tcw-tree-header, .tcw-datawin-header, .tcw-syminfo-header) > span:first-child {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-dock-page :is(.tcw-watchlist-add, .tcw-watchlist-close, .tcw-alerts-close, .tcw-tree-close, .tcw-datawin-close, .tcw-syminfo-close, .tcw-ladder-close) {\n display: inline-grid;\n place-items: center;\n flex: none;\n width: var(--tcw-control-h);\n height: var(--tcw-control-h);\n padding: 0;\n border: none;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-muted);\n cursor: pointer;\n}\n\n.tcw-dock-page :is(.tcw-watchlist-add, .tcw-watchlist-close, .tcw-alerts-close, .tcw-tree-close, .tcw-datawin-close, .tcw-syminfo-close, .tcw-ladder-close):hover {\n background: var(--tcw-hover-bg);\n color: var(--tcw-text);\n}\n\n.tcw-dock-page :is(.tcw-watchlist-add, .tcw-watchlist-close, .tcw-alerts-close, .tcw-tree-close, .tcw-datawin-close, .tcw-syminfo-close, .tcw-ladder-close):focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n/* What scrolled in a box of its own on a floating panel scrolls with the page here (a phone's caps too). */\n.tcw-dock-page :is(.tcw-alerts-list, .tcw-datawin-body, .tcw-watchlist-list, .tcw-tree-list) {\n max-height: none;\n overflow-y: visible;\n}\n\n.tcw-dock-page .tcw-watchlist-list {\n flex: 1;\n}\n\n/* The watchlist was a bar of its own: its width and shadow are the panel's now. */\n.tcw-dock-panel > .tcw-watchlist {\n width: auto;\n border-inline-start: none;\n box-shadow: none;\n overflow: hidden;\n}\n\n/* The symbol info's own padding sits under the header. */\n.tcw-dock-page.tcw-syminfo > .tcw-syminfo-body {\n padding: var(--tcw-space-5);\n}\n\n/* Narrow (a phone, a narrow column): no rail; the panel rises from the bottom over the chart, 61.8% tall. */\n.tcw-root[data-tcw-narrow] .tcw-dock-rail,\n.tcw-root[data-tcw-narrow] .tcw-dock-resize {\n display: none;\n}\n\n.tcw-root[data-tcw-narrow] .tcw-dock {\n position: static;\n}\n\n/* Above the chart's lines and tags, under its toasts; above the on-screen keyboard. */\n.tcw-root[data-tcw-narrow] .tcw-dock-panel {\n position: absolute;\n inset-inline: 0;\n bottom: var(--tcw-keyboard-inset, 0px);\n z-index: 38;\n width: auto;\n height: 61.8%;\n max-height: calc(100% - var(--tcw-keyboard-inset, 0px));\n border-inline-start: none;\n border-top: var(--tcw-border-w) solid var(--tcw-border-strong);\n border-radius: var(--tcw-dialog-radius) var(--tcw-dialog-radius) 0 0;\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-dialog-shadow);\n padding-bottom: env(safe-area-inset-bottom, 0px);\n}\n\n.tcw-root[data-tcw-narrow] .tcw-dock-page > :is(.tcw-watchlist-header, .tcw-alerts-header, .tcw-tree-header, .tcw-datawin-header, .tcw-syminfo-header, .tcw-ladder-header) {\n background: var(--tcw-bg-elevated);\n}\n\n/* The small buttons in a panel's rows: the browser's padding left their icons 8 px wide in a 20 px button. */\n:is(.tcw-tree-btn, .tcw-tree-add, .tcw-alerts-del, .tcw-watchlist-remove) {\n padding: 0;\n}\n\n:is(.tcw-tree-btn, .tcw-tree-add, .tcw-alerts-del, .tcw-watchlist-remove) svg {\n flex: none;\n}\n\n/* A page's title as the others': the watchlist's is its list's name, a menu. */\n.tcw-dock-page .tcw-watchlist-name {\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-3);\n margin-inline-start: calc(var(--tcw-space-3) * -1);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n font-weight: var(--tcw-weight-strong);\n text-transform: none;\n letter-spacing: normal;\n flex: 0 1 auto;\n}\n\n/* Its caret beside the name, the add and close buttons at the end. */\n.tcw-dock-page .tcw-watchlist-name::after {\n margin-inline-start: var(--tcw-space-3);\n}\n\n.tcw-dock-page .tcw-watchlist-add {\n margin-inline-start: auto;\n}\n\n/* === The depth ladder, a page of the dock === */\n\n.tcw-ladder-title {\n flex: 1;\n min-width: 0;\n margin: 0;\n overflow: hidden;\n font: inherit;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n/*\n * Bid, price, ask: under the header, in the label case. The heading and each\n * row are grids of their own, so their columns are fixed shares: a row's\n * content (a mark of your orders) never moves its column off the others'.\n */\n.tcw-ladder-cols,\n.tcw-ladder-row {\n --tcw-ladder-columns: minmax(0, 1fr) minmax(0, 1.3fr) minmax(0, 1fr);\n}\n.tcw-ladder-cols {\n position: sticky;\n top: calc(var(--tcw-space-6) + var(--tcw-space-5));\n z-index: 1;\n display: grid;\n grid-template-columns: var(--tcw-ladder-columns);\n align-items: center;\n height: var(--tcw-space-6);\n padding-inline: var(--tcw-space-3);\n border-bottom: 1px solid var(--tcw-divider);\n background: var(--tcw-bg-surface);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n}\n.tcw-ladder-cols span:first-child { text-align: end; padding-inline-end: var(--tcw-space-4); }\n.tcw-ladder-cols span:nth-child(2) { text-align: center; }\n.tcw-ladder-cols span:last-child { padding-inline-start: var(--tcw-space-4); }\n\n.tcw-ladder-body { flex: 1; padding-inline: var(--tcw-space-3); }\n\n/* A row 21 tall: the bid's size, the price, the ask's size, in the mono figures. */\n.tcw-ladder-row {\n display: grid;\n grid-template-columns: var(--tcw-ladder-columns);\n height: var(--tcw-space-6);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n}\n/* A side's size over a bar grown from the price outward, as long as its share of the largest. */\n.tcw-ladder-cell {\n position: relative;\n isolation: isolate;\n display: flex;\n align-items: center;\n min-width: 0;\n padding-inline: var(--tcw-space-4);\n border: none;\n background: transparent;\n color: var(--tcw-text);\n font: inherit;\n cursor: pointer;\n}\n.tcw-ladder-cell::before {\n content: '';\n position: absolute;\n inset-block: 2px;\n z-index: -1;\n width: var(--w, 0%);\n border-radius: 1px;\n}\n.tcw-ladder-bid { justify-content: flex-end; }\n.tcw-ladder-bid::before { inset-inline-end: 0; background: var(--tcw-green-soft); }\n.tcw-ladder-ask { justify-content: flex-start; }\n.tcw-ladder-ask::before { inset-inline-start: 0; background: var(--tcw-red-soft); }\n.tcw-ladder-cell:not(:disabled):hover { background: var(--tcw-hover-bg); }\n.tcw-ladder-cell:disabled { cursor: default; }\n.tcw-ladder-cell:focus-visible { outline: none; box-shadow: inset var(--tcw-ring); }\n.tcw-ladder-price {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--tcw-space-2);\n min-width: 0;\n overflow: hidden;\n padding-inline: var(--tcw-space-3);\n border-inline: 1px solid var(--tcw-divider);\n white-space: nowrap;\n}\n.tcw-ladder-price.tcw-ask { color: var(--tcw-red); }\n.tcw-ladder-price.tcw-bid { color: var(--tcw-green); }\n/* Your orders at a price: their quantity, stamped in the side's colour. */\n.tcw-ladder-own {\n flex: none;\n padding-inline: var(--tcw-space-2);\n border-radius: 2px;\n color: var(--tcw-bg);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n}\n.tcw-ladder-own[data-side='buy'] { background: var(--tcw-green); }\n.tcw-ladder-own[data-side='sell'] { background: var(--tcw-red); }\n/* The spread, between the asks and the bids, on a torn-paper rule. */\n.tcw-ladder-spread {\n display: flex;\n align-items: center;\n justify-content: center;\n height: var(--tcw-space-6);\n border-block: 1px dashed var(--tcw-border-strong);\n color: var(--tcw-text-muted);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-xs);\n font-variant-numeric: tabular-nums;\n}\n.tcw-ladder-empty {\n padding: var(--tcw-space-6);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-sm);\n text-align: center;\n}\n\n/* Narrow (a finger, not a pointer): rows a control tall, 26 not 21. */\n.tcw-root[data-tcw-narrow] .tcw-ladder-row {\n height: var(--tcw-control-h);\n}\n\n/* Forced colours drop the bars' and the marks' fills: the bars show in the system's highlight, the marks framed. */\n@media (forced-colors: active) {\n .tcw-ladder-cell::before { forced-color-adjust: none; background: Highlight; opacity: 0.3; }\n .tcw-ladder-cell:focus-visible { outline: 2px solid Highlight; outline-offset: -2px; }\n .tcw-ladder-own { border: 1px solid CanvasText; }\n}\n", zt = /* @__PURE__ */ "toolbar,sidebar,statusBar,dock,alerts,objectTree,symbolInfo,symbolSearch,settings,indicatorSettings,drawingSettings,dataWindow,commandPalette,hotkeySheet,goToDate,replay,screenshot,copyImage,shareView,autoFib,themeToggle,fullscreen,accountPanel,orderTicket,bracketOrders,depthLadder,layouts,indicatorTemplates,compare,indicatorLegend,navigation,customTimeframes,intervalTyping,symbolTyping,dragDropImport,hotkeys,toasts,toolbar.symbol,toolbar.symbolInfo,toolbar.timeframes,toolbar.timeframeMenu,toolbar.chartType,toolbar.indicators,toolbar.layouts,toolbar.replay,toolbar.bracketOrders,toolbar.depthLadder,toolbar.accountPanel,toolbar.objectTree,toolbar.alerts,toolbar.screenshot,toolbar.settings,toolbar.themeToggle,toolbar.fullscreen,toolbar.compare,toolbar.undo,toolbar.redo,toolbar.trade,sidebar.cursor,sidebar.favorites,sidebar.lines,sidebar.fibonacci,sidebar.patterns,sidebar.forecasting,sidebar.annotation,sidebar.style,sidebar.magnet,sidebar.eraser,sidebar.zoomArea,sidebar.stayInDrawing,sidebar.undo,sidebar.redo,sidebar.clear,sidebar.lockAll,sidebar.hideAll,dock.watchlist,dock.alerts,dock.objectTree,dock.dataWindow,dock.symbolInfo,dock.depthLadder,statusBar.range,statusBar.goToDate,statusBar.market,statusBar.connection,statusBar.symbol,statusBar.clock,statusBar.scale,statusBar.rangeTimeframe,indicatorLegend.values,indicatorLegend.visibility,indicatorLegend.settings,indicatorLegend.remove,indicatorLegend.more,pane.move,pane.collapse,pane.maximize,navigation.zoom,navigation.scroll,navigation.reset,menu.chart,menu.chart.alert,menu.chart.order,menu.chart.orderTicket,menu.chart.horizontalLine,menu.chart.resetView,menu.chart.drawings,menu.chart.exportData,menu.chart.settings,menu.chart.scale,menu.chart.goToDate,menu.chart.paneScale,menu.priceAxisAdd,menu.chart.indicators,menu.chart.timezone,menu.drawing,menu.drawing.settings,menu.drawing.alert,menu.drawing.order,menu.drawing.group,menu.drawing.lock,menu.drawing.hide,menu.drawing.duplicate,menu.drawing.delete,selectionToolbar,hotkeys.commandPalette,hotkeys.symbolSearch,hotkeys.save,hotkeys.tools,hotkeys.invertScale,hotkeys.goToDate,hotkeys.help,hotkeys.resetView".split(","), Bt = new Set(zt), Vt = {
|
|
1228
1228
|
toolbar: ["toolbar"],
|
|
1229
1229
|
drawingTools: [
|
|
1230
1230
|
"sidebar",
|
|
@@ -3020,10 +3020,10 @@ var V = [
|
|
|
3020
3020
|
value: "indexedTo100",
|
|
3021
3021
|
label: this.t("settings.scale.indexedTo100")
|
|
3022
3022
|
}
|
|
3023
|
-
].filter((e) => e.value !== "logarithmic" || this.available.logScale !== !1), n = Ze(e.timezone, Date.now(), this.t("settings.timezone.local"),
|
|
3023
|
+
].filter((e) => e.value !== "logarithmic" || this.available.logScale !== !1), n = this.available.exchangeZone?.(), r = Ze(e.timezone, Date.now(), this.t("settings.timezone.local"), n === void 0 ? void 0 : {
|
|
3024
3024
|
label: this.t("settings.timezone.exchange"),
|
|
3025
|
-
zone:
|
|
3026
|
-
}
|
|
3025
|
+
zone: n
|
|
3026
|
+
});
|
|
3027
3027
|
this.addSection(void 0, [
|
|
3028
3028
|
B(this.t("settings.priceScale"), e.scaleMode, t, (e) => this.patch({ scaleMode: e })),
|
|
3029
3029
|
z(this.t("settings.autoScale"), e.autoScale, (e) => this.patch({ autoScale: e })),
|
|
@@ -3031,7 +3031,7 @@ var V = [
|
|
|
3031
3031
|
z(this.t("settings.leftScale"), e.leftPriceScale, (e) => this.patch({ leftPriceScale: e })),
|
|
3032
3032
|
z(this.t("settings.indicatorValues"), e.indicatorValueLabels, (e) => this.patch({ indicatorValueLabels: e })),
|
|
3033
3033
|
...this.available.barCountdown === !1 ? [] : [z(this.t("settings.barCountdown"), e.barCountdown, (e) => this.patch({ barCountdown: e }))],
|
|
3034
|
-
B(this.t("settings.timezone"), e.timezone,
|
|
3034
|
+
B(this.t("settings.timezone"), e.timezone, r, (e) => this.patch({ timezone: e })),
|
|
3035
3035
|
B(this.t("settings.numberLocale"), e.numberLocale, bn(e.numberLocale), (e) => this.patch({ numberLocale: e }))
|
|
3036
3036
|
]), this.addSection(this.t("settings.section.axes"), kt.map((e) => this.lookRow(e)));
|
|
3037
3037
|
}
|
|
@@ -7763,29 +7763,39 @@ function Zo(e, t, n) {
|
|
|
7763
7763
|
}
|
|
7764
7764
|
}
|
|
7765
7765
|
//#endregion
|
|
7766
|
+
//#region src/widget/signedFigure.ts
|
|
7767
|
+
var Qo = /^[-+−]/;
|
|
7768
|
+
function $o(e, t, n) {
|
|
7769
|
+
let r = e.replace(Qo, "");
|
|
7770
|
+
return r === n.replace(Qo, "") ? r : t > 0 ? `+${r}` : t < 0 ? `-${r}` : r;
|
|
7771
|
+
}
|
|
7772
|
+
function es(e) {
|
|
7773
|
+
return e.startsWith("+") ? "up" : e.startsWith("-") ? "down" : null;
|
|
7774
|
+
}
|
|
7775
|
+
//#endregion
|
|
7766
7776
|
//#region src/widget/WidgetAccountPanel.ts
|
|
7767
|
-
var
|
|
7777
|
+
var ts = [
|
|
7768
7778
|
"positions",
|
|
7769
7779
|
"orders",
|
|
7770
7780
|
"history"
|
|
7771
|
-
],
|
|
7781
|
+
], ns = [
|
|
7772
7782
|
"order",
|
|
7773
7783
|
"close",
|
|
7774
7784
|
"reverse",
|
|
7775
7785
|
"stopLoss",
|
|
7776
7786
|
"takeProfit"
|
|
7777
|
-
],
|
|
7787
|
+
], rs = [
|
|
7778
7788
|
"market",
|
|
7779
7789
|
"limit",
|
|
7780
7790
|
"stop"
|
|
7781
|
-
],
|
|
7782
|
-
function
|
|
7791
|
+
], is = ["gtc", "day"], as = "—", os = "{pnl}", ss = 3;
|
|
7792
|
+
function cs(e, t, n) {
|
|
7783
7793
|
return e.includes(t ?? "") ? t : n;
|
|
7784
7794
|
}
|
|
7785
|
-
function
|
|
7795
|
+
function ls(e, t) {
|
|
7786
7796
|
return e.length === t.length && e.every((e, n) => e === t[n]);
|
|
7787
7797
|
}
|
|
7788
|
-
function
|
|
7798
|
+
function us(e, t) {
|
|
7789
7799
|
if (t === null) return null;
|
|
7790
7800
|
let n = e.quantity - (e.closedQuantity ?? 0), r = e.side === "buy" ? 1 : -1;
|
|
7791
7801
|
return {
|
|
@@ -7793,12 +7803,20 @@ function is(e, t) {
|
|
|
7793
7803
|
pct: e.entryPrice === 0 ? 0 : (t - e.entryPrice) / e.entryPrice * 100 * r
|
|
7794
7804
|
};
|
|
7795
7805
|
}
|
|
7796
|
-
function
|
|
7797
|
-
|
|
7806
|
+
function ds(e) {
|
|
7807
|
+
let t = document.createElement("span");
|
|
7808
|
+
return t.dir = "ltr", t.textContent = e, t;
|
|
7798
7809
|
}
|
|
7799
|
-
|
|
7810
|
+
function fs(e) {
|
|
7811
|
+
let t = es(e);
|
|
7812
|
+
return t ? `tcw-account-${t}` : "";
|
|
7813
|
+
}
|
|
7814
|
+
var ps = class {
|
|
7800
7815
|
el;
|
|
7801
7816
|
tabButtons = /* @__PURE__ */ new Map();
|
|
7817
|
+
tabLabels = /* @__PURE__ */ new Map();
|
|
7818
|
+
tabCounts = /* @__PURE__ */ new Map();
|
|
7819
|
+
totalsEl;
|
|
7802
7820
|
content;
|
|
7803
7821
|
tab = "positions";
|
|
7804
7822
|
snapshot = {
|
|
@@ -7815,14 +7833,19 @@ var os = class {
|
|
|
7815
7833
|
r.className = "tcw-account-head";
|
|
7816
7834
|
let i = document.createElement("div");
|
|
7817
7835
|
i.className = "tcw-account-tabs", i.setAttribute("role", "tablist"), i.addEventListener("keydown", (e) => this.onTabKey(e));
|
|
7818
|
-
for (let e of
|
|
7836
|
+
for (let e of ts) {
|
|
7819
7837
|
let t = document.createElement("button");
|
|
7820
|
-
t.type = "button", t.className = "tcw-account-tab", t.setAttribute("role", "tab"), t.id = `tcw-account-tab-${e}
|
|
7838
|
+
t.type = "button", t.className = "tcw-account-tab", t.setAttribute("role", "tab"), t.id = `tcw-account-tab-${e}`;
|
|
7839
|
+
let n = document.createElement("span");
|
|
7840
|
+
n.className = "tcw-account-tab-label", n.textContent = this.t(`account.${e}`);
|
|
7841
|
+
let r = document.createElement("span");
|
|
7842
|
+
r.className = "tcw-account-count", t.append(n, r), t.addEventListener("click", () => this.selectTab(e)), this.tabButtons.set(e, t), this.tabLabels.set(e, n.textContent), this.tabCounts.set(e, r), i.appendChild(t);
|
|
7821
7843
|
}
|
|
7844
|
+
this.totalsEl = document.createElement("div"), this.totalsEl.className = "tcw-account-totals";
|
|
7822
7845
|
let a = document.createElement("button");
|
|
7823
7846
|
a.type = "button", a.className = "tcw-account-new", k(a, "orderTicket"), a.innerHTML = A("plus", 13), a.append(this.t("account.newOrder")), a.addEventListener("click", () => this.callbacks.onNewOrder());
|
|
7824
7847
|
let o = document.createElement("button");
|
|
7825
|
-
o.type = "button", o.className = "tcw-tree-close", o.setAttribute("aria-label", this.t("account.close")), o.innerHTML = A("x", 14), o.addEventListener("click", () => this.closePanel()), r.append(i, a, o), this.content = document.createElement("div"), this.content.className = "tcw-account-body", this.content.setAttribute("role", "tabpanel"), this.el.append(r, this.content), e.appendChild(this.el), this.renderTabs();
|
|
7848
|
+
o.type = "button", o.className = "tcw-tree-close", o.setAttribute("aria-label", this.t("account.close")), o.innerHTML = A("x", 14), o.addEventListener("click", () => this.closePanel()), r.append(i, this.totalsEl, a, o), this.content = document.createElement("div"), this.content.className = "tcw-account-body", this.content.setAttribute("role", "tabpanel"), this.el.append(r, this.content), e.appendChild(this.el), this.renderTabs();
|
|
7826
7849
|
}
|
|
7827
7850
|
isOpen() {
|
|
7828
7851
|
return this.open;
|
|
@@ -7838,8 +7861,8 @@ var os = class {
|
|
|
7838
7861
|
}
|
|
7839
7862
|
update(e) {
|
|
7840
7863
|
let t = this.snapshot;
|
|
7841
|
-
if (this.snapshot = e,
|
|
7842
|
-
this.open && this.tab === "positions" &&
|
|
7864
|
+
if (this.snapshot = e, ls(t.positions, e.positions) && ls(t.orders, e.orders) && ls(t.fills, e.fills) && t.realisedPnl === e.realisedPnl) {
|
|
7865
|
+
t.price !== e.price && (this.renderTotals(), this.open && this.tab === "positions" && this.patchPrices());
|
|
7843
7866
|
return;
|
|
7844
7867
|
}
|
|
7845
7868
|
this.renderTabs(), this.open && this.render();
|
|
@@ -7851,10 +7874,10 @@ var os = class {
|
|
|
7851
7874
|
this.tab = e, this.renderTabs(), this.render();
|
|
7852
7875
|
}
|
|
7853
7876
|
onTabKey(e) {
|
|
7854
|
-
let t =
|
|
7877
|
+
let t = ts.indexOf(this.tab), n = e.key === "ArrowRight" ? t + 1 : e.key === "ArrowLeft" ? t - 1 : -2;
|
|
7855
7878
|
if (n === -2) return;
|
|
7856
7879
|
e.preventDefault();
|
|
7857
|
-
let r =
|
|
7880
|
+
let r = ts[(n + ts.length) % ts.length];
|
|
7858
7881
|
this.selectTab(r), this.tabButtons.get(r)?.focus();
|
|
7859
7882
|
}
|
|
7860
7883
|
renderTabs() {
|
|
@@ -7865,8 +7888,22 @@ var os = class {
|
|
|
7865
7888
|
};
|
|
7866
7889
|
for (let [t, n] of this.tabButtons) {
|
|
7867
7890
|
let r = t === this.tab;
|
|
7868
|
-
|
|
7891
|
+
this.tabCounts.get(t).textContent = String(e[t]), n.setAttribute("aria-label", `${this.tabLabels.get(t)} (${e[t]})`), n.setAttribute("aria-selected", String(r)), n.tabIndex = r ? 0 : -1, r && this.content.setAttribute("aria-labelledby", n.id);
|
|
7869
7892
|
}
|
|
7893
|
+
this.renderTotals();
|
|
7894
|
+
}
|
|
7895
|
+
renderTotals() {
|
|
7896
|
+
let { positions: e, price: t, fills: n, realisedPnl: r } = this.snapshot, i = [], a = e.reduce((e, n) => {
|
|
7897
|
+
let r = us(n, t);
|
|
7898
|
+
return r === null ? e : (e ?? 0) + r.pnl;
|
|
7899
|
+
}, null);
|
|
7900
|
+
a !== null && i.push(this.total("account.openPnl", a)), (n.length > 0 || r !== void 0 && r !== 0) && i.push(this.total("account.realised", r ?? n.reduce((e, t) => e + (t.pnl ?? 0), 0))), this.totalsEl.replaceChildren(...i);
|
|
7901
|
+
}
|
|
7902
|
+
total(e, t) {
|
|
7903
|
+
let n = document.createElement("span"), r = this.amount(t);
|
|
7904
|
+
n.className = `tcw-account-total ${fs(r)}`.trim();
|
|
7905
|
+
let i = this.t(e), a = i.indexOf(os), o = ds(r);
|
|
7906
|
+
return a < 0 ? n.append(`${i} `, o) : n.append(i.slice(0, a), o, i.slice(a + 5)), n;
|
|
7870
7907
|
}
|
|
7871
7908
|
render() {
|
|
7872
7909
|
let e = document.activeElement, t = e instanceof HTMLElement && this.content.contains(e) ? e.dataset.focusKey : void 0;
|
|
@@ -7874,34 +7911,47 @@ var os = class {
|
|
|
7874
7911
|
}
|
|
7875
7912
|
patchPrices() {
|
|
7876
7913
|
let { price: e } = this.snapshot;
|
|
7877
|
-
for (let t of this.live) t.price.textContent = e === null ?
|
|
7914
|
+
for (let t of this.live) t.price.textContent = e === null ? as : this.callbacks.formatPrice(e), this.writePnl(t.pnl, us(t.position, e));
|
|
7915
|
+
}
|
|
7916
|
+
amount(e) {
|
|
7917
|
+
return $o(this.money(Math.abs(e)), e, this.money(0));
|
|
7918
|
+
}
|
|
7919
|
+
money(e) {
|
|
7920
|
+
return this.callbacks.formatAmount ? this.callbacks.formatAmount(e) : e.toFixed(2);
|
|
7921
|
+
}
|
|
7922
|
+
percent(e) {
|
|
7923
|
+
let t = (e) => this.callbacks.formatNumber ? this.callbacks.formatNumber(e, 2) : e.toFixed(2);
|
|
7924
|
+
return `${$o(t(Math.abs(e)), e, t(0))}%`;
|
|
7878
7925
|
}
|
|
7879
7926
|
writePnl(e, t) {
|
|
7880
|
-
|
|
7927
|
+
if (t === null) {
|
|
7928
|
+
e.className = "", e.textContent = as;
|
|
7929
|
+
return;
|
|
7930
|
+
}
|
|
7931
|
+
let n = this.amount(t.pnl);
|
|
7932
|
+
e.className = fs(n), e.textContent = `${n} · ${this.percent(t.pct)}`;
|
|
7881
7933
|
}
|
|
7882
7934
|
table(e, t, n) {
|
|
7883
7935
|
if (t.length === 0) {
|
|
7884
7936
|
let e = document.createElement("p");
|
|
7885
|
-
e.className = "tcw-account-empty", e.textContent = this.t(n), this.content.replaceChildren(e);
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
7895
|
-
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
let e = n.insertCell();
|
|
7902
|
-
typeof t == "string" ? e.textContent = t : e.appendChild(t);
|
|
7937
|
+
return e.className = "tcw-account-empty", e.textContent = this.t(n), this.content.replaceChildren(e), null;
|
|
7938
|
+
}
|
|
7939
|
+
let r = e.map((e) => e.key ? this.t(e.key) : ""), i = document.createElement("table");
|
|
7940
|
+
i.className = "tcw-account-table", i.setAttribute("role", "table");
|
|
7941
|
+
let a = i.createTHead().insertRow();
|
|
7942
|
+
a.setAttribute("role", "row"), e.forEach((e, t) => {
|
|
7943
|
+
let n = document.createElement("th");
|
|
7944
|
+
n.scope = "col", n.setAttribute("role", "columnheader"), n.textContent = r[t], e.num && (n.className = "tcw-num"), a.appendChild(n);
|
|
7945
|
+
});
|
|
7946
|
+
let o = i.createTBody();
|
|
7947
|
+
for (let n of t) {
|
|
7948
|
+
let t = o.insertRow();
|
|
7949
|
+
t.setAttribute("role", "row"), n.forEach((n, i) => {
|
|
7950
|
+
let a = t.insertCell();
|
|
7951
|
+
a.setAttribute("role", "cell"), a.dataset.label = r[i], e[i].num && (a.className = "tcw-num"), typeof n == "string" ? a.textContent = n : a.appendChild(n);
|
|
7952
|
+
});
|
|
7903
7953
|
}
|
|
7904
|
-
return
|
|
7954
|
+
return this.content.replaceChildren(i), i;
|
|
7905
7955
|
}
|
|
7906
7956
|
sideCell(e, t = "position") {
|
|
7907
7957
|
let n = document.createElement("span");
|
|
@@ -7919,59 +7969,82 @@ var os = class {
|
|
|
7919
7969
|
}
|
|
7920
7970
|
return t;
|
|
7921
7971
|
}
|
|
7972
|
+
price(e) {
|
|
7973
|
+
return e === void 0 ? as : this.callbacks.formatPrice(e);
|
|
7974
|
+
}
|
|
7922
7975
|
renderPositions() {
|
|
7923
|
-
let { formatPrice: e } = this.callbacks, { price: t } = this.snapshot, n = this.snapshot.positions.map((
|
|
7924
|
-
let
|
|
7925
|
-
this.writePnl(
|
|
7926
|
-
let
|
|
7927
|
-
|
|
7928
|
-
|
|
7929
|
-
|
|
7930
|
-
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
|
|
7976
|
+
let { formatPrice: e } = this.callbacks, { price: t } = this.snapshot, n = [], r = this.snapshot.positions.map((r) => {
|
|
7977
|
+
let i = r.quantity - (r.closedQuantity ?? 0), a = ds("");
|
|
7978
|
+
this.writePnl(a, us(r, t)), n.push(a);
|
|
7979
|
+
let o = `${this.sideText(r.side, "position")} ${i} @ ${e(r.entryPrice)}`;
|
|
7980
|
+
return [
|
|
7981
|
+
this.sideCell(r.side),
|
|
7982
|
+
String(i),
|
|
7983
|
+
e(r.entryPrice),
|
|
7984
|
+
t === null ? as : e(t),
|
|
7985
|
+
a,
|
|
7986
|
+
this.price(r.stopLoss),
|
|
7987
|
+
this.price(r.takeProfit),
|
|
7934
7988
|
this.actions({
|
|
7935
|
-
icon: "
|
|
7936
|
-
label: `${this.t("account.reverse")}: ${
|
|
7937
|
-
key: `reverse:${
|
|
7938
|
-
run: () => this.callbacks.onReversePosition(
|
|
7989
|
+
icon: "arrowUpDown",
|
|
7990
|
+
label: `${this.t("account.reverse")}: ${o}`,
|
|
7991
|
+
key: `reverse:${r.id}`,
|
|
7992
|
+
run: () => this.callbacks.onReversePosition(r.id)
|
|
7939
7993
|
}, {
|
|
7940
7994
|
icon: "x",
|
|
7941
|
-
label: `${this.t("account.closePosition")}: ${
|
|
7942
|
-
key: `close:${
|
|
7943
|
-
run: () => this.callbacks.onClosePosition(
|
|
7995
|
+
label: `${this.t("account.closePosition")}: ${o}`,
|
|
7996
|
+
key: `close:${r.id}`,
|
|
7997
|
+
run: () => this.callbacks.onClosePosition(r.id),
|
|
7944
7998
|
danger: !0
|
|
7945
7999
|
})
|
|
7946
|
-
]
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
|
|
7952
|
-
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
|
|
7958
|
-
|
|
7959
|
-
|
|
7960
|
-
|
|
7961
|
-
|
|
7962
|
-
|
|
8000
|
+
];
|
|
8001
|
+
}), i = this.table([
|
|
8002
|
+
{ key: "account.side" },
|
|
8003
|
+
{
|
|
8004
|
+
key: "account.quantity",
|
|
8005
|
+
num: !0
|
|
8006
|
+
},
|
|
8007
|
+
{
|
|
8008
|
+
key: "account.entry",
|
|
8009
|
+
num: !0
|
|
8010
|
+
},
|
|
8011
|
+
{
|
|
8012
|
+
key: "account.price",
|
|
8013
|
+
num: !0
|
|
8014
|
+
},
|
|
8015
|
+
{
|
|
8016
|
+
key: "account.pnl",
|
|
8017
|
+
num: !0
|
|
8018
|
+
},
|
|
8019
|
+
{
|
|
8020
|
+
key: "account.stopLoss",
|
|
8021
|
+
num: !0
|
|
8022
|
+
},
|
|
8023
|
+
{
|
|
8024
|
+
key: "account.takeProfit",
|
|
8025
|
+
num: !0
|
|
8026
|
+
},
|
|
8027
|
+
{ key: null }
|
|
8028
|
+
], r, "account.noPositions");
|
|
8029
|
+
if (!i) return;
|
|
8030
|
+
let a = [...i.tBodies[0].rows];
|
|
8031
|
+
this.snapshot.positions.forEach((e, t) => this.live.push({
|
|
8032
|
+
position: e,
|
|
8033
|
+
price: a[t].cells[ss],
|
|
8034
|
+
pnl: n[t]
|
|
8035
|
+
}));
|
|
7963
8036
|
}
|
|
7964
8037
|
renderOrders() {
|
|
7965
8038
|
let { formatPrice: e } = this.callbacks, t = this.snapshot.orders.map((t) => {
|
|
7966
|
-
let n =
|
|
7967
|
-
return
|
|
8039
|
+
let n = cs(rs, t.type === "stopLimit" ? "stop" : t.type, "limit"), r = `${this.sideText(t.side, "trade")} ${t.quantity} @ ${e(t.price)}`;
|
|
8040
|
+
return [
|
|
7968
8041
|
this.sideCell(t.side, "trade"),
|
|
7969
8042
|
this.t(`ticket.type.${n}`),
|
|
7970
8043
|
String(t.quantity),
|
|
7971
8044
|
e(t.price),
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
t.timeInForce ? this.t(`ticket.tif.${
|
|
8045
|
+
this.price(t.stopLoss),
|
|
8046
|
+
this.price(t.takeProfit),
|
|
8047
|
+
t.timeInForce ? this.t(`ticket.tif.${cs(is, t.timeInForce, "gtc")}`) : as,
|
|
7975
8048
|
this.actions({
|
|
7976
8049
|
icon: "x",
|
|
7977
8050
|
label: `${this.t("account.cancelOrder")}: ${r}`,
|
|
@@ -7979,50 +8052,66 @@ var os = class {
|
|
|
7979
8052
|
run: () => this.callbacks.onCancelOrder(t.id),
|
|
7980
8053
|
danger: !0
|
|
7981
8054
|
})
|
|
7982
|
-
]
|
|
8055
|
+
];
|
|
7983
8056
|
});
|
|
7984
8057
|
this.table([
|
|
7985
|
-
"account.side",
|
|
7986
|
-
"ticket.type",
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
|
|
7992
|
-
|
|
8058
|
+
{ key: "account.side" },
|
|
8059
|
+
{ key: "ticket.type" },
|
|
8060
|
+
{
|
|
8061
|
+
key: "account.quantity",
|
|
8062
|
+
num: !0
|
|
8063
|
+
},
|
|
8064
|
+
{
|
|
8065
|
+
key: "account.price",
|
|
8066
|
+
num: !0
|
|
8067
|
+
},
|
|
8068
|
+
{
|
|
8069
|
+
key: "account.stopLoss",
|
|
8070
|
+
num: !0
|
|
8071
|
+
},
|
|
8072
|
+
{
|
|
8073
|
+
key: "account.takeProfit",
|
|
8074
|
+
num: !0
|
|
8075
|
+
},
|
|
8076
|
+
{ key: "ticket.timeInForce" },
|
|
8077
|
+
{ key: null }
|
|
7993
8078
|
], t, "account.noOrders");
|
|
7994
8079
|
}
|
|
7995
8080
|
renderHistory() {
|
|
7996
8081
|
let { formatPrice: e, formatTime: t } = this.callbacks, n = [...this.snapshot.fills].reverse().map((n) => {
|
|
7997
|
-
let r =
|
|
7998
|
-
return n.pnl === void 0 ? r.textContent =
|
|
8082
|
+
let r = ds("");
|
|
8083
|
+
return n.pnl === void 0 ? r.textContent = as : (r.textContent = this.amount(n.pnl), r.className = fs(r.textContent)), [
|
|
7999
8084
|
t(n.time),
|
|
8000
8085
|
this.sideCell(n.side, "trade"),
|
|
8001
8086
|
String(n.quantity),
|
|
8002
8087
|
e(n.price),
|
|
8003
|
-
this.t(`account.reason.${ns
|
|
8088
|
+
this.t(`account.reason.${cs(ns, n.reason, "order")}`),
|
|
8004
8089
|
r
|
|
8005
|
-
]
|
|
8090
|
+
];
|
|
8006
8091
|
});
|
|
8007
8092
|
this.table([
|
|
8008
|
-
"account.time",
|
|
8009
|
-
"account.side",
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8093
|
+
{ key: "account.time" },
|
|
8094
|
+
{ key: "account.side" },
|
|
8095
|
+
{
|
|
8096
|
+
key: "account.quantity",
|
|
8097
|
+
num: !0
|
|
8098
|
+
},
|
|
8099
|
+
{
|
|
8100
|
+
key: "account.price",
|
|
8101
|
+
num: !0
|
|
8102
|
+
},
|
|
8103
|
+
{ key: "account.reason" },
|
|
8104
|
+
{
|
|
8105
|
+
key: "account.pnl",
|
|
8106
|
+
num: !0
|
|
8107
|
+
}
|
|
8014
8108
|
], n, "account.noFills");
|
|
8015
|
-
let r = this.snapshot.realisedPnl ?? this.snapshot.fills.reduce((e, t) => e + (t.pnl ?? 0), 0);
|
|
8016
|
-
if (n.length > 0) {
|
|
8017
|
-
let e = document.createElement("p");
|
|
8018
|
-
e.className = "tcw-account-summary", e.textContent = p(this.t("account.realised"), { pnl: as(r) }), this.content.appendChild(e);
|
|
8019
|
-
}
|
|
8020
8109
|
}
|
|
8021
|
-
},
|
|
8022
|
-
function
|
|
8110
|
+
}, ms = 1e-9;
|
|
8111
|
+
function hs(e, t) {
|
|
8023
8112
|
return e.type === "market" ? t : e.price;
|
|
8024
8113
|
}
|
|
8025
|
-
function
|
|
8114
|
+
function gs(e, t, n = {}) {
|
|
8026
8115
|
let r = [];
|
|
8027
8116
|
(!(e.quantity > 0) || !Number.isFinite(e.quantity)) && r.push("quantity"), e.type !== "market" && (!(e.price > 0) || !Number.isFinite(e.price)) && r.push("price"), e.type === "market" && !((t ?? e.price) > 0) && r.push("market");
|
|
8028
8117
|
let i = e.side === "buy";
|
|
@@ -8032,18 +8121,18 @@ function ls(e, t, n = {}) {
|
|
|
8032
8121
|
}
|
|
8033
8122
|
let a = (e) => e === null || Number.isFinite(e) && e > 0;
|
|
8034
8123
|
a(e.stopLoss) || r.push("stopLoss"), a(e.takeProfit) || r.push("takeProfit");
|
|
8035
|
-
let o =
|
|
8036
|
-
return o !== null && o > 0 && (e.stopLoss !== null && a(e.stopLoss) && (i ? e.stopLoss >= o : e.stopLoss <= o) && r.push("stopLossSide"), e.takeProfit !== null && a(e.takeProfit) && (i ? e.takeProfit <= o : e.takeProfit >= o) && r.push("takeProfitSide")), [...r, ...
|
|
8124
|
+
let o = hs(e, t);
|
|
8125
|
+
return o !== null && o > 0 && (e.stopLoss !== null && a(e.stopLoss) && (i ? e.stopLoss >= o : e.stopLoss <= o) && r.push("stopLossSide"), e.takeProfit !== null && a(e.takeProfit) && (i ? e.takeProfit <= o : e.takeProfit >= o) && r.push("takeProfitSide")), [...r, ..._s(e, n)];
|
|
8037
8126
|
}
|
|
8038
|
-
function
|
|
8127
|
+
function _s(e, t) {
|
|
8039
8128
|
let n = [], r = e.type === "market" ? null : e.price, i = [
|
|
8040
8129
|
r,
|
|
8041
8130
|
e.stopLoss,
|
|
8042
8131
|
e.takeProfit
|
|
8043
8132
|
].filter((e) => e !== null && Number.isFinite(e) && e > 0), { roundPrice: a, limits: o, lot: s } = t;
|
|
8044
|
-
return a && i.some((e) => Math.abs(a(e) - e) >
|
|
8133
|
+
return a && i.some((e) => Math.abs(a(e) - e) > ms) && n.push("priceStep"), o && r !== null && r > 0 && (r > o.ceiling + ms || r < o.floor - ms) && n.push("priceLimits"), s !== void 0 && s > 1 && e.quantity > s && e.quantity % s !== 0 && n.push("lot"), n;
|
|
8045
8134
|
}
|
|
8046
|
-
function
|
|
8135
|
+
function vs(e, t) {
|
|
8047
8136
|
let n = {
|
|
8048
8137
|
side: e.side,
|
|
8049
8138
|
type: e.type,
|
|
@@ -8052,14 +8141,14 @@ function ds(e, t) {
|
|
|
8052
8141
|
};
|
|
8053
8142
|
return e.type === "stop" && (n.stopPrice = e.price), e.type !== "market" && (n.timeInForce = e.timeInForce), e.stopLoss !== null && (n.stopLoss = e.stopLoss), e.takeProfit !== null && (n.takeProfit = e.takeProfit), n;
|
|
8054
8143
|
}
|
|
8055
|
-
function
|
|
8056
|
-
let n =
|
|
8144
|
+
function ys(e, t) {
|
|
8145
|
+
let n = hs(e, t);
|
|
8057
8146
|
if (n === null || e.stopLoss === null || e.takeProfit === null) return null;
|
|
8058
8147
|
let r = Math.abs(n - e.stopLoss);
|
|
8059
8148
|
return r > 0 ? Math.abs(e.takeProfit - n) / r : null;
|
|
8060
8149
|
}
|
|
8061
|
-
function
|
|
8062
|
-
let i =
|
|
8150
|
+
function bs(e, t, n, r = 1) {
|
|
8151
|
+
let i = hs(e, t);
|
|
8063
8152
|
if (i === null || !(i > 0) || !Number.isFinite(n) || !(e.quantity > 0)) return null;
|
|
8064
8153
|
let a = e.side === "buy" ? 1 : -1;
|
|
8065
8154
|
return {
|
|
@@ -8067,18 +8156,18 @@ function ps(e, t, n, r = 1) {
|
|
|
8067
8156
|
amount: (n - i) * e.quantity * a * r
|
|
8068
8157
|
};
|
|
8069
8158
|
}
|
|
8070
|
-
function
|
|
8071
|
-
let r = n.multiplier !== void 0 && n.multiplier > 0 ? n.multiplier : 1, i =
|
|
8159
|
+
function xs(e, t, n = {}) {
|
|
8160
|
+
let r = n.multiplier !== void 0 && n.multiplier > 0 ? n.multiplier : 1, i = hs(e, t), a = i !== null && i > 0 && e.quantity > 0 ? i * e.quantity * r : null, o = gs(e, t), s = (n, i) => n === null || o.includes(i) ? null : bs(e, t, n, r)?.amount ?? null, c = s(e.stopLoss, "stopLossSide"), l = s(e.takeProfit, "takeProfitSide");
|
|
8072
8161
|
return {
|
|
8073
8162
|
value: a,
|
|
8074
8163
|
risk: c,
|
|
8075
8164
|
reward: l,
|
|
8076
|
-
ratio: c !== null && l !== null ?
|
|
8165
|
+
ratio: c !== null && l !== null ? ys(e, t) : null
|
|
8077
8166
|
};
|
|
8078
8167
|
}
|
|
8079
8168
|
//#endregion
|
|
8080
8169
|
//#region src/widget/WidgetOrderTicket.ts
|
|
8081
|
-
var
|
|
8170
|
+
var Ss = 229, Cs = 1, ws = 2, Ts = .999999999, Es = 0, Ds = class {
|
|
8082
8171
|
backdrop;
|
|
8083
8172
|
modal;
|
|
8084
8173
|
symbolEl;
|
|
@@ -8089,11 +8178,11 @@ var hs = 229, gs = 1, _s = 2, vs = .999999999, ys = 0, bs = class {
|
|
|
8089
8178
|
draft = null;
|
|
8090
8179
|
lastPrice = null;
|
|
8091
8180
|
rules = {};
|
|
8092
|
-
step =
|
|
8093
|
-
round = (e) =>
|
|
8181
|
+
step = ks;
|
|
8182
|
+
round = (e) => As(e, e);
|
|
8094
8183
|
typed = /* @__PURE__ */ new Map();
|
|
8095
8184
|
returnFocus = null;
|
|
8096
|
-
uid = ++
|
|
8185
|
+
uid = ++Es;
|
|
8097
8186
|
constructor(e, t, n = h) {
|
|
8098
8187
|
this.callbacks = t, this.t = n, this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.hidden = !0;
|
|
8099
8188
|
let r = !1;
|
|
@@ -8102,7 +8191,7 @@ var hs = 229, gs = 1, _s = 2, vs = .999999999, ys = 0, bs = class {
|
|
|
8102
8191
|
}), this.backdrop.addEventListener("click", (e) => {
|
|
8103
8192
|
e.target === this.backdrop && r && this.close(), r = !1;
|
|
8104
8193
|
}), this.modal = document.createElement("div"), this.modal.className = "tcw-modal tcw-order-ticket", this.modal.setAttribute("role", "dialog"), this.modal.setAttribute("aria-modal", "true"), this.modal.setAttribute("aria-labelledby", `tcw-ticket-title-${this.uid}`), this.modal.addEventListener("keydown", (e) => {
|
|
8105
|
-
if (e.key === "Escape" && !e.isComposing && e.keyCode !==
|
|
8194
|
+
if (e.key === "Escape" && !e.isComposing && e.keyCode !== Ss) {
|
|
8106
8195
|
e.stopPropagation(), this.close();
|
|
8107
8196
|
return;
|
|
8108
8197
|
}
|
|
@@ -8124,7 +8213,7 @@ var hs = 229, gs = 1, _s = 2, vs = .999999999, ys = 0, bs = class {
|
|
|
8124
8213
|
u.className = "tcw-footer-end", u.append(l, this.submit), c.append(u), this.modal.append(i, this.body, this.summaryEl, this.problemsEl, c), this.backdrop.appendChild(this.modal), e.appendChild(this.backdrop);
|
|
8125
8214
|
}
|
|
8126
8215
|
open(e) {
|
|
8127
|
-
this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null, this.lastPrice = e.lastPrice, this.rules = e.rules ?? {}, this.step = e.step ??
|
|
8216
|
+
this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null, this.lastPrice = e.lastPrice, this.rules = e.rules ?? {}, this.step = e.step ?? ks, this.round = e.round ?? ((e) => As(e, e)), this.typed.clear(), this.symbolEl.textContent = e.symbol ?? "";
|
|
8128
8217
|
let t = this.round(e.price ?? e.lastPrice ?? 0), n = e.side ?? "buy", r = "market";
|
|
8129
8218
|
e.price !== void 0 && e.lastPrice !== null && t !== e.lastPrice && (r = t < e.lastPrice == (n === "buy") ? "limit" : "stop"), this.draft = {
|
|
8130
8219
|
side: n,
|
|
@@ -8160,14 +8249,14 @@ var hs = 229, gs = 1, _s = 2, vs = .999999999, ys = 0, bs = class {
|
|
|
8160
8249
|
return t > 0 ? Number((10 ** -t).toFixed(t)) : 1;
|
|
8161
8250
|
}
|
|
8162
8251
|
priceStep(e, t) {
|
|
8163
|
-
return this.step(t > 0 ? e : e *
|
|
8252
|
+
return this.step(t > 0 ? e : e * Ts);
|
|
8164
8253
|
}
|
|
8165
8254
|
writePrice(e) {
|
|
8166
|
-
return Number.isFinite(e) ? this.step ===
|
|
8255
|
+
return Number.isFinite(e) ? this.step === ks ? String(e) : e.toFixed(Se(this.step(e))) : "";
|
|
8167
8256
|
}
|
|
8168
8257
|
place() {
|
|
8169
8258
|
let e = this.draft;
|
|
8170
|
-
!e ||
|
|
8259
|
+
!e || gs(e, this.lastPrice, this.rules).length > 0 || (this.callbacks.onSubmit(vs(e, this.lastPrice)), this.close());
|
|
8171
8260
|
}
|
|
8172
8261
|
set(e, t = !1) {
|
|
8173
8262
|
this.draft && (this.draft = {
|
|
@@ -8202,7 +8291,7 @@ var hs = 229, gs = 1, _s = 2, vs = .999999999, ys = 0, bs = class {
|
|
|
8202
8291
|
return r.className = "tcw-settings-label", r.textContent = this.t(e), n.append(r, t), n;
|
|
8203
8292
|
}
|
|
8204
8293
|
choices(e, t, n, r, i) {
|
|
8205
|
-
let a = e === "type" ? "ticket.type" : "ticket.tif", o =
|
|
8294
|
+
let a = e === "type" ? "ticket.type" : "ticket.tif", o = Os(e, pr(t.map((e) => ({
|
|
8206
8295
|
value: e,
|
|
8207
8296
|
label: this.t(`${a}.${e}`)
|
|
8208
8297
|
})), n, i, this.t(r)));
|
|
@@ -8235,7 +8324,7 @@ var hs = 229, gs = 1, _s = 2, vs = .999999999, ys = 0, bs = class {
|
|
|
8235
8324
|
return this.stepped(e, t, (e, t) => this.priceStep(e, t), () => this.lastPrice ?? this.draft?.price ?? 0, (e) => this.writePrice(e), n);
|
|
8236
8325
|
}
|
|
8237
8326
|
stepped(e, t, n, r, i, a) {
|
|
8238
|
-
let o =
|
|
8327
|
+
let o = Os(e, document.createElement("input"));
|
|
8239
8328
|
o.type = "number", o.className = "tcw-indi-input", o.step = "any", o.min = "0", o.value = this.typed.get(e) ?? i(t);
|
|
8240
8329
|
let s = this.t(`ticket.${e}`);
|
|
8241
8330
|
o.setAttribute("aria-label", s), o.addEventListener("input", () => {
|
|
@@ -8273,25 +8362,25 @@ var hs = 229, gs = 1, _s = 2, vs = .999999999, ys = 0, bs = class {
|
|
|
8273
8362
|
if (!t) return NaN;
|
|
8274
8363
|
let n = t.type === "market" ? this.lastPrice ?? t.price : t.price;
|
|
8275
8364
|
if (!(n > 0)) return NaN;
|
|
8276
|
-
let r = e === "stopLoss" ? -
|
|
8365
|
+
let r = e === "stopLoss" ? -Cs : ws;
|
|
8277
8366
|
return this.round(n * (1 + (t.side === "buy" ? r : -r) / 100));
|
|
8278
8367
|
}
|
|
8279
8368
|
check() {
|
|
8280
8369
|
let e = this.draft;
|
|
8281
8370
|
if (!e) return;
|
|
8282
|
-
let t =
|
|
8371
|
+
let t = gs(e, this.lastPrice, this.rules), n = t.map((e) => this.problemText(e));
|
|
8283
8372
|
n.join("\n") !== [...this.problemsEl.children].map((e) => e.textContent).join("\n") && this.problemsEl.replaceChildren(...n.map((e) => {
|
|
8284
8373
|
let t = document.createElement("p");
|
|
8285
8374
|
return t.textContent = e, t;
|
|
8286
8375
|
}));
|
|
8287
8376
|
for (let t of ["stopLoss", "takeProfit"]) {
|
|
8288
|
-
let n = this.body.querySelector(`.tcw-ticket-away[data-for="${t}"]`), r = e[t], i = r === null ? null :
|
|
8377
|
+
let n = this.body.querySelector(`.tcw-ticket-away[data-for="${t}"]`), r = e[t], i = r === null ? null : bs(e, this.lastPrice, r, this.rules.multiplier);
|
|
8289
8378
|
n && (n.textContent = i ? `${this.signedNumber(i.pct, 2)}% · ${this.amount(i.amount)}` : "");
|
|
8290
8379
|
}
|
|
8291
8380
|
this.renderSummary(e), this.submit.disabled = t.length > 0, this.submit.textContent = this.t(e.side === "buy" ? "ticket.placeBuy" : "ticket.placeSell");
|
|
8292
8381
|
}
|
|
8293
8382
|
renderSummary(e) {
|
|
8294
|
-
let t =
|
|
8383
|
+
let t = xs(e, this.lastPrice, this.rules), n = t.risk === null ? null : this.amount(t.risk), r = t.reward === null ? null : this.amount(t.reward), i = [
|
|
8295
8384
|
[
|
|
8296
8385
|
"value",
|
|
8297
8386
|
"ticket.value",
|
|
@@ -8301,14 +8390,14 @@ var hs = 229, gs = 1, _s = 2, vs = .999999999, ys = 0, bs = class {
|
|
|
8301
8390
|
[
|
|
8302
8391
|
"risk",
|
|
8303
8392
|
"ticket.risk",
|
|
8304
|
-
|
|
8305
|
-
|
|
8393
|
+
n,
|
|
8394
|
+
n === null ? null : es(n)
|
|
8306
8395
|
],
|
|
8307
8396
|
[
|
|
8308
8397
|
"reward",
|
|
8309
8398
|
"ticket.reward",
|
|
8310
|
-
|
|
8311
|
-
|
|
8399
|
+
r,
|
|
8400
|
+
r === null ? null : es(r)
|
|
8312
8401
|
],
|
|
8313
8402
|
[
|
|
8314
8403
|
"ratio",
|
|
@@ -8317,7 +8406,7 @@ var hs = 229, gs = 1, _s = 2, vs = .999999999, ys = 0, bs = class {
|
|
|
8317
8406
|
null
|
|
8318
8407
|
]
|
|
8319
8408
|
];
|
|
8320
|
-
this.summaryEl.replaceChildren(...
|
|
8409
|
+
this.summaryEl.replaceChildren(...i.filter(([, , e]) => e !== null).map(([e, t, n, r]) => {
|
|
8321
8410
|
let i = document.createElement("div");
|
|
8322
8411
|
i.className = "tcw-ticket-summary-row", i.dataset.row = e;
|
|
8323
8412
|
let a = document.createElement("span");
|
|
@@ -8330,10 +8419,10 @@ var hs = 229, gs = 1, _s = 2, vs = .999999999, ys = 0, bs = class {
|
|
|
8330
8419
|
return this.callbacks.formatNumber ? this.callbacks.formatNumber(e, t) : e.toFixed(t);
|
|
8331
8420
|
}
|
|
8332
8421
|
signedNumber(e, t) {
|
|
8333
|
-
return
|
|
8422
|
+
return $o(this.number(Math.abs(e), t), e, this.number(0, t));
|
|
8334
8423
|
}
|
|
8335
8424
|
amount(e) {
|
|
8336
|
-
return
|
|
8425
|
+
return $o(this.money(Math.abs(e)), e, this.money(0));
|
|
8337
8426
|
}
|
|
8338
8427
|
money(e) {
|
|
8339
8428
|
return (this.callbacks.formatAmount ?? this.callbacks.formatPrice)(e);
|
|
@@ -8346,27 +8435,20 @@ var hs = 229, gs = 1, _s = 2, vs = .999999999, ys = 0, bs = class {
|
|
|
8346
8435
|
}) : e === "lot" ? p(t, { lot: r ?? 1 }) : t;
|
|
8347
8436
|
}
|
|
8348
8437
|
};
|
|
8349
|
-
function
|
|
8438
|
+
function Os(e, t) {
|
|
8350
8439
|
return t.dataset.ticketField = e, t;
|
|
8351
8440
|
}
|
|
8352
|
-
function
|
|
8353
|
-
return e === null || e === 0 ? null : e > 0 ? "up" : "down";
|
|
8354
|
-
}
|
|
8355
|
-
function Cs(e, t) {
|
|
8356
|
-
let n = e.replace(/^[-+−]/, "");
|
|
8357
|
-
return /[1-9]/.test(n) ? t > 0 ? `+${n}` : t < 0 ? `-${n}` : n : n;
|
|
8358
|
-
}
|
|
8359
|
-
function ws(e) {
|
|
8441
|
+
function ks(e) {
|
|
8360
8442
|
let t = Math.abs(e);
|
|
8361
8443
|
return t > 0 ? 10 ** Math.floor(Math.log10(t / 100)) : 1;
|
|
8362
8444
|
}
|
|
8363
|
-
function
|
|
8445
|
+
function As(e, t) {
|
|
8364
8446
|
let n = Math.abs(t), r = n >= 10 || n === 0 ? 2 : n >= 1 ? 4 : Math.min(10, Math.ceil(-Math.log10(n)) + 3);
|
|
8365
8447
|
return Number(e.toFixed(r));
|
|
8366
8448
|
}
|
|
8367
8449
|
//#endregion
|
|
8368
8450
|
//#region src/widget/WidgetNamePrompt.ts
|
|
8369
|
-
var
|
|
8451
|
+
var js = 0, Ms = class {
|
|
8370
8452
|
backdrop;
|
|
8371
8453
|
titleEl;
|
|
8372
8454
|
input;
|
|
@@ -8374,7 +8456,7 @@ var Es = 0, Ds = class {
|
|
|
8374
8456
|
request = null;
|
|
8375
8457
|
returnFocus = null;
|
|
8376
8458
|
busy = !1;
|
|
8377
|
-
uid = ++
|
|
8459
|
+
uid = ++js;
|
|
8378
8460
|
constructor(e, t = h) {
|
|
8379
8461
|
this.t = t, this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.hidden = !0;
|
|
8380
8462
|
let n = !1;
|
|
@@ -8434,7 +8516,7 @@ var Es = 0, Ds = class {
|
|
|
8434
8516
|
}
|
|
8435
8517
|
}
|
|
8436
8518
|
}
|
|
8437
|
-
},
|
|
8519
|
+
}, Ns = 0, Ps = class {
|
|
8438
8520
|
backdrop;
|
|
8439
8521
|
search;
|
|
8440
8522
|
listEl;
|
|
@@ -8442,7 +8524,7 @@ var Es = 0, Ds = class {
|
|
|
8442
8524
|
confirming = null;
|
|
8443
8525
|
returnFocus = null;
|
|
8444
8526
|
loadSeq = 0;
|
|
8445
|
-
uid = ++
|
|
8527
|
+
uid = ++Ns;
|
|
8446
8528
|
constructor(e, t, n = h) {
|
|
8447
8529
|
this.callbacks = t, this.t = n, this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.hidden = !0;
|
|
8448
8530
|
let r = !1;
|
|
@@ -8548,7 +8630,7 @@ var Es = 0, Ds = class {
|
|
|
8548
8630
|
this.confirming = null, await this.refresh(), this.isOpen() && this.search.focus();
|
|
8549
8631
|
}
|
|
8550
8632
|
}
|
|
8551
|
-
},
|
|
8633
|
+
}, Fs = 5, Is = class {
|
|
8552
8634
|
menu;
|
|
8553
8635
|
prompt;
|
|
8554
8636
|
dialog;
|
|
@@ -8556,7 +8638,7 @@ var Es = 0, Ds = class {
|
|
|
8556
8638
|
constructor(e, t) {
|
|
8557
8639
|
this.session = e, this.host = t;
|
|
8558
8640
|
let { root: n, t: r } = t;
|
|
8559
|
-
this.menu = new M(n, r("toolbar.layouts")), this.prompt = new
|
|
8641
|
+
this.menu = new M(n, r("toolbar.layouts")), this.prompt = new Ms(n, r), this.dialog = new Ps(n, {
|
|
8560
8642
|
list: () => e.list(),
|
|
8561
8643
|
currentId: () => e.current()?.id ?? null,
|
|
8562
8644
|
onOpen: (e) => void this.open(e),
|
|
@@ -8634,7 +8716,7 @@ var Es = 0, Ds = class {
|
|
|
8634
8716
|
}
|
|
8635
8717
|
let { session: t } = this, { t: n, root: r } = this.host, i = [];
|
|
8636
8718
|
try {
|
|
8637
|
-
i = (await t.list()).slice(0,
|
|
8719
|
+
i = (await t.list()).slice(0, Fs);
|
|
8638
8720
|
} catch {}
|
|
8639
8721
|
if (this.destroyed) return;
|
|
8640
8722
|
let a = t.current(), o = [{
|
|
@@ -8672,13 +8754,13 @@ var Es = 0, Ds = class {
|
|
|
8672
8754
|
destroy() {
|
|
8673
8755
|
this.destroyed = !0, this.menu.destroy(), this.prompt.destroy(), this.dialog.destroy();
|
|
8674
8756
|
}
|
|
8675
|
-
},
|
|
8757
|
+
}, Ls = 0, Rs = class {
|
|
8676
8758
|
el;
|
|
8677
8759
|
input;
|
|
8678
8760
|
hint;
|
|
8679
8761
|
returnFocus = null;
|
|
8680
8762
|
constructor(e, t, n) {
|
|
8681
|
-
this.labels = t, this.onApply = n, this.el = document.createElement("div"), this.el.className = "tcw-interval-input", this.el.hidden = !0, this.el.setAttribute("role", "dialog"), this.el.setAttribute("aria-label", t.title), this.input = document.createElement("input"), this.input.type = "text", this.input.className = "tcw-interval-field", this.input.autocomplete = "off", this.input.spellcheck = !1, this.input.maxLength = 6, this.input.setAttribute("aria-label", t.title), this.hint = document.createElement("div"), this.hint.className = "tcw-interval-hint", this.hint.setAttribute("role", "status"), this.hint.id = `tcw-interval-hint-${++
|
|
8763
|
+
this.labels = t, this.onApply = n, this.el = document.createElement("div"), this.el.className = "tcw-interval-input", this.el.hidden = !0, this.el.setAttribute("role", "dialog"), this.el.setAttribute("aria-label", t.title), this.input = document.createElement("input"), this.input.type = "text", this.input.className = "tcw-interval-field", this.input.autocomplete = "off", this.input.spellcheck = !1, this.input.maxLength = 6, this.input.setAttribute("aria-label", t.title), this.hint = document.createElement("div"), this.hint.className = "tcw-interval-hint", this.hint.setAttribute("role", "status"), this.hint.id = `tcw-interval-hint-${++Ls}`, this.input.setAttribute("aria-describedby", this.hint.id), this.el.append(this.input, this.hint), e.appendChild(this.el), this.input.addEventListener("input", () => this.check()), this.input.addEventListener("keydown", (e) => {
|
|
8682
8764
|
e.key === "Enter" ? (e.preventDefault(), e.stopPropagation(), this.apply()) : e.key === "Escape" && (e.preventDefault(), e.stopPropagation(), this.close());
|
|
8683
8765
|
}), this.input.addEventListener("blur", () => this.close(!1));
|
|
8684
8766
|
}
|
|
@@ -8709,7 +8791,7 @@ var Es = 0, Ds = class {
|
|
|
8709
8791
|
}
|
|
8710
8792
|
this.input.setAttribute("aria-invalid", "true"), this.hint.textContent = this.labels.invalid;
|
|
8711
8793
|
}
|
|
8712
|
-
},
|
|
8794
|
+
}, zs = class {
|
|
8713
8795
|
constructor(e = "tcw:indicator-templates") {
|
|
8714
8796
|
this.key = e;
|
|
8715
8797
|
}
|
|
@@ -8754,23 +8836,23 @@ var Es = 0, Ds = class {
|
|
|
8754
8836
|
localStorage.setItem(this.key, JSON.stringify(this.list().filter((t) => t.name !== e)));
|
|
8755
8837
|
} catch {}
|
|
8756
8838
|
}
|
|
8757
|
-
}, Y = [],
|
|
8839
|
+
}, Y = [], Bs = /* @__PURE__ */ new Map(), Vs = null, Hs = (e) => {
|
|
8758
8840
|
let t = e.target instanceof Node ? e.target : null;
|
|
8759
|
-
t !== null && Y.some((e) => e.contains(t) ||
|
|
8841
|
+
t !== null && Y.some((e) => e.contains(t) || Bs.get(e)?.some((e) => e.contains(t))) || (Vs = null);
|
|
8760
8842
|
};
|
|
8761
|
-
function
|
|
8843
|
+
function Us(e, t = []) {
|
|
8762
8844
|
let n = () => {
|
|
8763
|
-
|
|
8845
|
+
Vs = e;
|
|
8764
8846
|
}, r = [e, ...t];
|
|
8765
8847
|
for (let e of r) e.addEventListener("pointerdown", n, !0);
|
|
8766
|
-
return Y.length === 0 && document.addEventListener("pointerdown",
|
|
8848
|
+
return Y.length === 0 && document.addEventListener("pointerdown", Hs, !0), Y.push(e), Bs.set(e, t), () => {
|
|
8767
8849
|
for (let e of r) e.removeEventListener("pointerdown", n, !0);
|
|
8768
8850
|
let t = Y.indexOf(e);
|
|
8769
|
-
t >= 0 && Y.splice(t, 1),
|
|
8851
|
+
t >= 0 && Y.splice(t, 1), Bs.delete(e), Y.length === 0 && document.removeEventListener("pointerdown", Hs, !0), Vs === e && (Vs = null);
|
|
8770
8852
|
};
|
|
8771
8853
|
}
|
|
8772
|
-
function
|
|
8773
|
-
let n =
|
|
8854
|
+
function Ws(e, t = !1) {
|
|
8855
|
+
let n = Vs?.isConnected ? Vs : null;
|
|
8774
8856
|
if (!n) {
|
|
8775
8857
|
let e = document.activeElement;
|
|
8776
8858
|
n = e ? Y.find((t) => t.contains(e)) ?? null : null;
|
|
@@ -8783,27 +8865,27 @@ function X() {
|
|
|
8783
8865
|
}
|
|
8784
8866
|
//#endregion
|
|
8785
8867
|
//#region src/widget/widgetLayout.ts
|
|
8786
|
-
var
|
|
8868
|
+
var Gs = [
|
|
8787
8869
|
"regular",
|
|
8788
8870
|
"logarithmic",
|
|
8789
8871
|
"percentage",
|
|
8790
8872
|
"indexedTo100"
|
|
8791
|
-
],
|
|
8792
|
-
function
|
|
8873
|
+
], Ks = (e) => typeof e == "object" && !!e && !Array.isArray(e);
|
|
8874
|
+
function qs(e) {
|
|
8793
8875
|
let { theme: t, timestamp: n, ...r } = e;
|
|
8794
8876
|
return r;
|
|
8795
8877
|
}
|
|
8796
|
-
function
|
|
8797
|
-
return !
|
|
8878
|
+
function Js(e) {
|
|
8879
|
+
return !Ks(e) || e.v !== 1 || typeof e.symbol != "string" || !e.symbol || typeof e.timeframe != "string" || !(le(e.timeframe) || Ce(e.timeframe) !== null) ? null : {
|
|
8798
8880
|
v: 1,
|
|
8799
8881
|
symbol: e.symbol,
|
|
8800
8882
|
timeframe: e.timeframe,
|
|
8801
|
-
scaleMode:
|
|
8883
|
+
scaleMode: Gs.find((t) => t === e.scaleMode) ?? "regular",
|
|
8802
8884
|
invertScale: e.invertScale === !0,
|
|
8803
|
-
chart:
|
|
8885
|
+
chart: Ks(e.chart) ? qs(e.chart) : null
|
|
8804
8886
|
};
|
|
8805
8887
|
}
|
|
8806
|
-
function
|
|
8888
|
+
function Ys(e) {
|
|
8807
8889
|
try {
|
|
8808
8890
|
return JSON.parse(e);
|
|
8809
8891
|
} catch {
|
|
@@ -8812,16 +8894,16 @@ function Ws(e) {
|
|
|
8812
8894
|
}
|
|
8813
8895
|
//#endregion
|
|
8814
8896
|
//#region src/widget/DrawingFavoritesStore.ts
|
|
8815
|
-
function
|
|
8897
|
+
function Xs() {
|
|
8816
8898
|
try {
|
|
8817
8899
|
return typeof localStorage < "u" ? localStorage : null;
|
|
8818
8900
|
} catch {
|
|
8819
8901
|
return null;
|
|
8820
8902
|
}
|
|
8821
8903
|
}
|
|
8822
|
-
var
|
|
8904
|
+
var Zs = class {
|
|
8823
8905
|
favorites = [];
|
|
8824
|
-
constructor(e = "tcw:draw-favorites", t =
|
|
8906
|
+
constructor(e = "tcw:draw-favorites", t = Xs()) {
|
|
8825
8907
|
this.storageKey = e, this.storage = t, this.load();
|
|
8826
8908
|
}
|
|
8827
8909
|
list() {
|
|
@@ -8858,7 +8940,7 @@ var Ks = class {
|
|
|
8858
8940
|
};
|
|
8859
8941
|
//#endregion
|
|
8860
8942
|
//#region src/widget/keyboardInset.ts
|
|
8861
|
-
function
|
|
8943
|
+
function Qs(e) {
|
|
8862
8944
|
let t = typeof window < "u" ? window.visualViewport : null;
|
|
8863
8945
|
if (!t) return () => {};
|
|
8864
8946
|
let n = -1, r = () => {
|
|
@@ -8872,7 +8954,7 @@ function qs(e) {
|
|
|
8872
8954
|
t.removeEventListener("resize", r), t.removeEventListener("scroll", r);
|
|
8873
8955
|
};
|
|
8874
8956
|
}
|
|
8875
|
-
function
|
|
8957
|
+
function $s(e, t) {
|
|
8876
8958
|
let n = null, r = () => {
|
|
8877
8959
|
let r = e.clientWidth;
|
|
8878
8960
|
if (r === 0 && n !== null) return;
|
|
@@ -8885,9 +8967,9 @@ function Js(e, t) {
|
|
|
8885
8967
|
}
|
|
8886
8968
|
//#endregion
|
|
8887
8969
|
//#region src/widget/WidgetGoToDate.ts
|
|
8888
|
-
var
|
|
8889
|
-
function
|
|
8890
|
-
let r =
|
|
8970
|
+
var ec = /^(\d{4})-(\d{2})-(\d{2})$/, tc = /^(\d{2}):(\d{2})$/;
|
|
8971
|
+
function nc(e, t, n) {
|
|
8972
|
+
let r = ec.exec(e), i = t ? tc.exec(t) : [
|
|
8891
8973
|
"",
|
|
8892
8974
|
"00",
|
|
8893
8975
|
"00"
|
|
@@ -8911,7 +8993,7 @@ function Z(e, t) {
|
|
|
8911
8993
|
time: `${n(r.hours)}:${n(r.minutes)}`
|
|
8912
8994
|
};
|
|
8913
8995
|
}
|
|
8914
|
-
var Q = ["date", "range"],
|
|
8996
|
+
var Q = ["date", "range"], rc = 1, ic = class {
|
|
8915
8997
|
backdrop = null;
|
|
8916
8998
|
fieldsEl = null;
|
|
8917
8999
|
tabButtons = [];
|
|
@@ -8928,7 +9010,7 @@ var Q = ["date", "range"], Qs = 1, $s = class {
|
|
|
8928
9010
|
start = null;
|
|
8929
9011
|
tab = "date";
|
|
8930
9012
|
returnFocus = null;
|
|
8931
|
-
uid =
|
|
9013
|
+
uid = rc++;
|
|
8932
9014
|
constructor(e, t, n, r) {
|
|
8933
9015
|
this.layer = e, this.labels = t, this.locale = n, this.onSubmit = r;
|
|
8934
9016
|
}
|
|
@@ -9097,7 +9179,7 @@ var Q = ["date", "range"], Qs = 1, $s = class {
|
|
|
9097
9179
|
min: 233,
|
|
9098
9180
|
default: 296,
|
|
9099
9181
|
max: 377
|
|
9100
|
-
},
|
|
9182
|
+
}, ac = .382, oc = (e) => !e.hidden && getComputedStyle(e).display !== "none", sc = class {
|
|
9101
9183
|
element;
|
|
9102
9184
|
panel;
|
|
9103
9185
|
rail;
|
|
@@ -9143,7 +9225,7 @@ var Q = ["date", "range"], Qs = 1, $s = class {
|
|
|
9143
9225
|
let t = this.panel.contains(document.activeElement);
|
|
9144
9226
|
if (this.hideCurrent(), this.panel.hidden = !0, t) {
|
|
9145
9227
|
let t = this.pages.get(e)?.button;
|
|
9146
|
-
(t && (this.options.railShown?.() ?? !0) &&
|
|
9228
|
+
(t && (this.options.railShown?.() ?? !0) && oc(t) ? t : this.options.focusAfterClose?.(e))?.focus();
|
|
9147
9229
|
}
|
|
9148
9230
|
this.options.onChange?.(null);
|
|
9149
9231
|
}
|
|
@@ -9160,7 +9242,7 @@ var Q = ["date", "range"], Qs = 1, $s = class {
|
|
|
9160
9242
|
return this.open_ === e;
|
|
9161
9243
|
}
|
|
9162
9244
|
syncRail() {
|
|
9163
|
-
let e = [...this.pages.values()].map((e) => e.button), t = e.filter(
|
|
9245
|
+
let e = [...this.pages.values()].map((e) => e.button), t = e.filter(oc), n = e.find((e) => e.tabIndex === 0);
|
|
9164
9246
|
if (n && t.includes(n)) return;
|
|
9165
9247
|
let r = t.find((e) => e.getAttribute("aria-pressed") === "true") ?? t[0];
|
|
9166
9248
|
for (let t of e) t.tabIndex = t === r ? 0 : -1;
|
|
@@ -9177,7 +9259,7 @@ var Q = ["date", "range"], Qs = 1, $s = class {
|
|
|
9177
9259
|
}
|
|
9178
9260
|
maxNow() {
|
|
9179
9261
|
let e = this.options.room?.() ?? 0;
|
|
9180
|
-
return e <= 0 ? $.max : Math.max($.min, Math.min($.max, Math.floor(e *
|
|
9262
|
+
return e <= 0 ? $.max : Math.max($.min, Math.min($.max, Math.floor(e * ac)));
|
|
9181
9263
|
}
|
|
9182
9264
|
clamp(e, t = this.maxNow()) {
|
|
9183
9265
|
return Math.round(Math.min(t, Math.max($.min, e)));
|
|
@@ -9221,12 +9303,12 @@ var Q = ["date", "range"], Qs = 1, $s = class {
|
|
|
9221
9303
|
for (let { button: t } of this.pages.values()) t.tabIndex = t === e ? 0 : -1;
|
|
9222
9304
|
}
|
|
9223
9305
|
onRailKey(e) {
|
|
9224
|
-
let t = [...this.pages.values()].map((e) => e.button).filter(
|
|
9306
|
+
let t = [...this.pages.values()].map((e) => e.button).filter(oc), n = t.indexOf(e.target);
|
|
9225
9307
|
if (n < 0) return;
|
|
9226
9308
|
let r = e.key === "ArrowDown" ? (n + 1) % t.length : e.key === "ArrowUp" ? (n - 1 + t.length) % t.length : e.key === "Home" ? 0 : e.key === "End" ? t.length - 1 : -1;
|
|
9227
9309
|
r < 0 || (e.preventDefault(), t[r].focus());
|
|
9228
9310
|
}
|
|
9229
|
-
},
|
|
9311
|
+
}, cc = [
|
|
9230
9312
|
"percent",
|
|
9231
9313
|
"scale",
|
|
9232
9314
|
"pane",
|
|
@@ -9234,7 +9316,7 @@ var Q = ["date", "range"], Qs = 1, $s = class {
|
|
|
9234
9316
|
"ratio",
|
|
9235
9317
|
"correlation",
|
|
9236
9318
|
"correlationLog"
|
|
9237
|
-
],
|
|
9319
|
+
], lc = {
|
|
9238
9320
|
percent: "compare.percent",
|
|
9239
9321
|
scale: "compare.ownScale",
|
|
9240
9322
|
pane: "compare.ownPane",
|
|
@@ -9243,16 +9325,16 @@ var Q = ["date", "range"], Qs = 1, $s = class {
|
|
|
9243
9325
|
correlation: "compare.way.correlation",
|
|
9244
9326
|
correlationLog: "compare.way.correlationLog"
|
|
9245
9327
|
};
|
|
9246
|
-
function
|
|
9247
|
-
return
|
|
9328
|
+
function uc(e) {
|
|
9329
|
+
return cc.includes(e);
|
|
9248
9330
|
}
|
|
9249
|
-
function
|
|
9250
|
-
return
|
|
9331
|
+
function dc(e) {
|
|
9332
|
+
return cc.map((t) => ({
|
|
9251
9333
|
id: t,
|
|
9252
|
-
label: e(
|
|
9334
|
+
label: e(lc[t])
|
|
9253
9335
|
}));
|
|
9254
9336
|
}
|
|
9255
|
-
function
|
|
9337
|
+
function fc(e, t) {
|
|
9256
9338
|
switch (e.id) {
|
|
9257
9339
|
case "compareSymbol": return t ? "pane" : "scale";
|
|
9258
9340
|
case "spread": return e.params.mode === "ratio" ? "ratio" : "spread";
|
|
@@ -9261,24 +9343,24 @@ function sc(e, t) {
|
|
|
9261
9343
|
default: return null;
|
|
9262
9344
|
}
|
|
9263
9345
|
}
|
|
9264
|
-
function
|
|
9346
|
+
function pc(e, t, n, r) {
|
|
9265
9347
|
let i = e.map((e) => ({
|
|
9266
9348
|
id: e.id,
|
|
9267
9349
|
symbol: e.symbol,
|
|
9268
|
-
way: r(
|
|
9350
|
+
way: r(lc.percent),
|
|
9269
9351
|
color: e.color
|
|
9270
9352
|
}));
|
|
9271
9353
|
for (let e of t) {
|
|
9272
|
-
let t = e.params.symbol, a =
|
|
9354
|
+
let t = e.params.symbol, a = fc(e, n.has(e.instanceId));
|
|
9273
9355
|
!a || typeof t != "string" || !t || i.push({
|
|
9274
9356
|
id: e.instanceId,
|
|
9275
9357
|
symbol: t,
|
|
9276
|
-
way: r(
|
|
9358
|
+
way: r(lc[a])
|
|
9277
9359
|
});
|
|
9278
9360
|
}
|
|
9279
9361
|
return i;
|
|
9280
9362
|
}
|
|
9281
|
-
var
|
|
9363
|
+
var mc = 8, hc = 4, gc = 3, _c = "[title]:not([title=\"\"]), [data-tip]:not([data-tip=\"\"])", vc = class {
|
|
9282
9364
|
el;
|
|
9283
9365
|
target = null;
|
|
9284
9366
|
source = null;
|
|
@@ -9289,9 +9371,9 @@ var lc = 8, uc = 4, dc = 3, fc = "[title]:not([title=\"\"]), [data-tip]:not([dat
|
|
|
9289
9371
|
observer;
|
|
9290
9372
|
constructor(e) {
|
|
9291
9373
|
this.root = e, this.el = document.createElement("div"), this.el.className = "tcw-tooltip", this.el.setAttribute("aria-hidden", "true"), e.appendChild(this.el), e.addEventListener("pointerover", this.onOver), e.addEventListener("pointerout", this.onOut), e.addEventListener("pointerdown", this.onPress, !0), e.addEventListener("keydown", this.onPress, !0), e.addEventListener("focusin", this.onFocus), e.addEventListener("focusout", this.onBlur), e.addEventListener("wheel", this.hide, { passive: !0 }), this.observer = new MutationObserver(() => {
|
|
9292
|
-
this.pressed?.hasAttribute("title") &&
|
|
9374
|
+
this.pressed?.hasAttribute("title") && yc(this.pressed);
|
|
9293
9375
|
let e = this.target;
|
|
9294
|
-
!e || this.source !== "pointer" || !e.hasAttribute("title") || (
|
|
9376
|
+
!e || this.source !== "pointer" || !e.hasAttribute("title") || (yc(e), this.isVisible() && this.show(e));
|
|
9295
9377
|
}), this.observer.observe(e, {
|
|
9296
9378
|
subtree: !0,
|
|
9297
9379
|
attributes: !0,
|
|
@@ -9299,24 +9381,24 @@ var lc = 8, uc = 4, dc = 3, fc = "[title]:not([title=\"\"]), [data-tip]:not([dat
|
|
|
9299
9381
|
});
|
|
9300
9382
|
}
|
|
9301
9383
|
destroy() {
|
|
9302
|
-
this.hide(), this.pressed &&
|
|
9384
|
+
this.hide(), this.pressed && bc(this.pressed), this.observer.disconnect(), this.root.removeEventListener("pointerover", this.onOver), this.root.removeEventListener("pointerout", this.onOut), this.root.removeEventListener("pointerdown", this.onPress, !0), this.root.removeEventListener("keydown", this.onPress, !0), this.root.removeEventListener("focusin", this.onFocus), this.root.removeEventListener("focusout", this.onBlur), this.root.removeEventListener("wheel", this.hide), this.el.remove();
|
|
9303
9385
|
}
|
|
9304
9386
|
onOver = (e) => {
|
|
9305
9387
|
if (e.pointerType === "touch") return;
|
|
9306
9388
|
let t = this.tipTarget(e.target);
|
|
9307
|
-
!t || t === this.pressed || t === this.target && this.source === "pointer" || (
|
|
9389
|
+
!t || t === this.pressed || t === this.target && this.source === "pointer" || (yc(t), this.schedule(t, "pointer", Date.now() < this.warmUntil || this.isVisible()));
|
|
9308
9390
|
};
|
|
9309
9391
|
onOut = (e) => {
|
|
9310
9392
|
let t = e.relatedTarget, n = (e) => !!e && !!t && e.contains(t);
|
|
9311
|
-
this.pressed && !n(this.pressed) && (
|
|
9393
|
+
this.pressed && !n(this.pressed) && (bc(this.pressed), this.pressed = null), this.source === "pointer" && !n(this.target) && this.hide();
|
|
9312
9394
|
};
|
|
9313
9395
|
onPress = () => {
|
|
9314
9396
|
let e = this.target, t = this.source === "pointer";
|
|
9315
|
-
this.warmUntil = 0, this.clearTimer(), cancelAnimationFrame(this.watchFrame), this.el.classList.remove("tcw-tooltip--visible"), this.target = null, this.source = null, this.pressed && this.pressed !== e &&
|
|
9397
|
+
this.warmUntil = 0, this.clearTimer(), cancelAnimationFrame(this.watchFrame), this.el.classList.remove("tcw-tooltip--visible"), this.target = null, this.source = null, this.pressed && this.pressed !== e && bc(this.pressed), this.pressed = t ? e : null;
|
|
9316
9398
|
};
|
|
9317
9399
|
onFocus = (e) => {
|
|
9318
9400
|
let t = this.tipTarget(e.target);
|
|
9319
|
-
!t || !
|
|
9401
|
+
!t || !Cc(t) || t === this.pressed || this.schedule(t, "focus", !0);
|
|
9320
9402
|
};
|
|
9321
9403
|
onBlur = (e) => {
|
|
9322
9404
|
if (this.source !== "focus") return;
|
|
@@ -9324,16 +9406,16 @@ var lc = 8, uc = 4, dc = 3, fc = "[title]:not([title=\"\"]), [data-tip]:not([dat
|
|
|
9324
9406
|
this.target && t && this.target.contains(t) || this.hide();
|
|
9325
9407
|
};
|
|
9326
9408
|
hide = () => {
|
|
9327
|
-
this.clearTimer(), cancelAnimationFrame(this.watchFrame), this.isVisible() && (this.warmUntil = Date.now() + 500), this.el.classList.remove("tcw-tooltip--visible"), this.target && this.source === "pointer" &&
|
|
9409
|
+
this.clearTimer(), cancelAnimationFrame(this.watchFrame), this.isVisible() && (this.warmUntil = Date.now() + 500), this.el.classList.remove("tcw-tooltip--visible"), this.target && this.source === "pointer" && bc(this.target), this.target = null, this.source = null;
|
|
9328
9410
|
};
|
|
9329
9411
|
tipTarget(e) {
|
|
9330
9412
|
if (!(e instanceof Element)) return null;
|
|
9331
|
-
let t = e.closest(
|
|
9413
|
+
let t = e.closest(_c);
|
|
9332
9414
|
return t && t !== this.el && this.root.contains(t) ? t : null;
|
|
9333
9415
|
}
|
|
9334
9416
|
schedule(e, t, n) {
|
|
9335
9417
|
let r = this.target;
|
|
9336
|
-
if (this.clearTimer(), cancelAnimationFrame(this.watchFrame), r && r !== e && this.source === "pointer" &&
|
|
9418
|
+
if (this.clearTimer(), cancelAnimationFrame(this.watchFrame), r && r !== e && this.source === "pointer" && bc(r), this.target = e, this.source = t, n) {
|
|
9337
9419
|
this.show(e);
|
|
9338
9420
|
return;
|
|
9339
9421
|
}
|
|
@@ -9342,27 +9424,27 @@ var lc = 8, uc = 4, dc = 3, fc = "[title]:not([title=\"\"]), [data-tip]:not([dat
|
|
|
9342
9424
|
}, 300);
|
|
9343
9425
|
}
|
|
9344
9426
|
show(e) {
|
|
9345
|
-
if (!
|
|
9427
|
+
if (!Sc(e)) {
|
|
9346
9428
|
this.hide();
|
|
9347
9429
|
return;
|
|
9348
9430
|
}
|
|
9349
|
-
this.el.textContent =
|
|
9431
|
+
this.el.textContent = xc(e), this.place(e), this.el.classList.add("tcw-tooltip--visible"), this.watch(e);
|
|
9350
9432
|
}
|
|
9351
9433
|
watch(e) {
|
|
9352
9434
|
cancelAnimationFrame(this.watchFrame), this.watchFrame = requestAnimationFrame(() => {
|
|
9353
|
-
this.target === e && (
|
|
9435
|
+
this.target === e && (Sc(e) ? this.watch(e) : this.hide());
|
|
9354
9436
|
});
|
|
9355
9437
|
}
|
|
9356
9438
|
place(e) {
|
|
9357
|
-
let t = this.root.getBoundingClientRect(), n = e.getBoundingClientRect(), r = this.el.offsetWidth, i = this.el.offsetHeight, a = n.left - t.left, o = n.top - t.top, s =
|
|
9358
|
-
s === "bottom" && o + n.height +
|
|
9439
|
+
let t = this.root.getBoundingClientRect(), n = e.getBoundingClientRect(), r = this.el.offsetWidth, i = this.el.offsetHeight, a = n.left - t.left, o = n.top - t.top, s = wc(e);
|
|
9440
|
+
s === "bottom" && o + n.height + mc + i > t.height ? s = "top" : s === "top" && o - mc - i < 0 ? s = "bottom" : s === "right" && a + n.width + mc + r > t.width && (s = "left");
|
|
9359
9441
|
let c, l;
|
|
9360
|
-
s === "top" || s === "bottom" ? (c = a + n.width / 2 - r / 2, l = s === "bottom" ? o + n.height +
|
|
9442
|
+
s === "top" || s === "bottom" ? (c = a + n.width / 2 - r / 2, l = s === "bottom" ? o + n.height + mc : o - mc - i) : (c = s === "right" ? a + n.width + mc : a - mc - r, l = o + n.height / 2 - i / 2), c = Math.max(hc, Math.min(t.width - r - hc, c)), l = Math.max(hc, Math.min(t.height - i - hc, l)), this.el.style.left = `${Math.round(c)}px`, this.el.style.top = `${Math.round(l)}px`;
|
|
9361
9443
|
let u = {
|
|
9362
|
-
top: [0,
|
|
9363
|
-
bottom: [0, -
|
|
9364
|
-
left: [
|
|
9365
|
-
right: [-
|
|
9444
|
+
top: [0, gc],
|
|
9445
|
+
bottom: [0, -gc],
|
|
9446
|
+
left: [gc, 0],
|
|
9447
|
+
right: [-gc, 0]
|
|
9366
9448
|
}[s];
|
|
9367
9449
|
this.el.style.setProperty("--tcw-tip-dx", `${u[0]}px`), this.el.style.setProperty("--tcw-tip-dy", `${u[1]}px`), this.el.dataset.side = s;
|
|
9368
9450
|
}
|
|
@@ -9373,32 +9455,32 @@ var lc = 8, uc = 4, dc = 3, fc = "[title]:not([title=\"\"]), [data-tip]:not([dat
|
|
|
9373
9455
|
this.showTimer !== null && (clearTimeout(this.showTimer), this.showTimer = null);
|
|
9374
9456
|
}
|
|
9375
9457
|
};
|
|
9376
|
-
function
|
|
9458
|
+
function yc(e) {
|
|
9377
9459
|
let t = e.getAttribute("title");
|
|
9378
9460
|
t !== null && (e.dataset.tip = t, e.removeAttribute("title"));
|
|
9379
9461
|
}
|
|
9380
|
-
function
|
|
9462
|
+
function bc(e) {
|
|
9381
9463
|
e.dataset.tip !== void 0 && !e.hasAttribute("title") && (e.setAttribute("title", e.dataset.tip), delete e.dataset.tip);
|
|
9382
9464
|
}
|
|
9383
|
-
function
|
|
9465
|
+
function xc(e) {
|
|
9384
9466
|
return e.dataset.tip ?? e.getAttribute("title") ?? "";
|
|
9385
9467
|
}
|
|
9386
|
-
function
|
|
9468
|
+
function Sc(e) {
|
|
9387
9469
|
return e.isConnected && e.getClientRects().length > 0 && !e.disabled;
|
|
9388
9470
|
}
|
|
9389
|
-
function
|
|
9471
|
+
function Cc(e) {
|
|
9390
9472
|
try {
|
|
9391
9473
|
return e.matches(":focus-visible");
|
|
9392
9474
|
} catch {
|
|
9393
9475
|
return !1;
|
|
9394
9476
|
}
|
|
9395
9477
|
}
|
|
9396
|
-
function
|
|
9478
|
+
function wc(e) {
|
|
9397
9479
|
return e.dataset.tipSide || (e.closest(".tcw-sidebar") ? "right" : e.closest(".tcw-statusbar, .tcw-replay-bar") ? "top" : "bottom");
|
|
9398
9480
|
}
|
|
9399
9481
|
//#endregion
|
|
9400
9482
|
//#region src/widget/WidgetIndicatorLegend.ts
|
|
9401
|
-
var
|
|
9483
|
+
var Tc = 2, Ec = class {
|
|
9402
9484
|
stack;
|
|
9403
9485
|
toggle;
|
|
9404
9486
|
rows = /* @__PURE__ */ new Map();
|
|
@@ -9440,7 +9522,7 @@ var bc = 2, xc = class {
|
|
|
9440
9522
|
e.key = r, e.el.style.left = `${Math.round(n.x)}px`, e.el.style.top = `${Math.round(n.y)}px`;
|
|
9441
9523
|
let i = this.labels, a = (t, r, i, a) => {
|
|
9442
9524
|
let o = e.buttons.get(t);
|
|
9443
|
-
!r && document.activeElement === o && e.buttons.get("max").focus(), o.hidden = !r, o.innerHTML = A(i, 12),
|
|
9525
|
+
!r && document.activeElement === o && e.buttons.get("max").focus(), o.hidden = !r, o.innerHTML = A(i, 12), Dc(o, a ?? t, n.label);
|
|
9444
9526
|
};
|
|
9445
9527
|
a("up", n.canMoveUp && !n.maximized, "arrowUp", i.paneUp), a("down", n.canMoveDown && !n.maximized, "arrowDown", i.paneDown), a("fold", !n.maximized, n.collapsed ? "chevronDown" : "chevronUp", n.collapsed ? i.paneExpand : i.paneCollapse), a("max", !0, n.maximized ? "minimize" : "maximize", n.maximized ? i.paneRestore : i.paneMaximize), e.el.dataset.collapsed = String(n.collapsed), e.el.dataset.maximized = String(n.maximized);
|
|
9446
9528
|
}
|
|
@@ -9505,7 +9587,7 @@ var bc = 2, xc = class {
|
|
|
9505
9587
|
}
|
|
9506
9588
|
fill(e, t) {
|
|
9507
9589
|
let n = `${t.label}|${t.visible}|${!!t.offInterval}`;
|
|
9508
|
-
n !== e.state && (e.state = n, e.visible = t.visible, e.name.textContent = t.label, e.name.title = this.labels.settings, e.el.classList.toggle("tcw-ind-legend-row--hidden", !t.visible || !!t.offInterval), t.offInterval && this.labels.offInterval ? e.el.title = this.labels.offInterval : e.el.removeAttribute("title"), e.eye.innerHTML = A(t.visible ? "eye" : "eyeOff", 13),
|
|
9590
|
+
n !== e.state && (e.state = n, e.visible = t.visible, e.name.textContent = t.label, e.name.title = this.labels.settings, e.el.classList.toggle("tcw-ind-legend-row--hidden", !t.visible || !!t.offInterval), t.offInterval && this.labels.offInterval ? e.el.title = this.labels.offInterval : e.el.removeAttribute("title"), e.eye.innerHTML = A(t.visible ? "eye" : "eyeOff", 13), Dc(e.eye, t.visible ? this.labels.hide : this.labels.show, t.label), Dc(e.settings, this.labels.settings, t.label), e.more && (Dc(e.more, this.labels.more ?? "More", t.label), e.more.setAttribute("aria-haspopup", "menu")), Dc(e.remove, this.labels.remove, t.label));
|
|
9509
9591
|
let r = t.values.map((e) => `${e.text}${e.color ?? ""}`).join("");
|
|
9510
9592
|
r !== e.valuesKey && (e.valuesKey = r, e.values.replaceChildren(...t.values.map((e) => {
|
|
9511
9593
|
let t = document.createElement("span");
|
|
@@ -9523,22 +9605,22 @@ var bc = 2, xc = class {
|
|
|
9523
9605
|
return this.stack.querySelectorAll(":scope > .tcw-ind-legend-row").length;
|
|
9524
9606
|
}
|
|
9525
9607
|
renderToggle(e) {
|
|
9526
|
-
let t = e >=
|
|
9608
|
+
let t = e >= Tc;
|
|
9527
9609
|
!t && this.collapsed && this.setCollapsed(!1);
|
|
9528
9610
|
let n = `${t}|${this.collapsed}|${e}`;
|
|
9529
9611
|
if (n === this.toggleKey || (this.toggleKey = n, this.toggle.hidden = !t, !t)) return;
|
|
9530
9612
|
let r = this.collapsed ? this.labels.expand : this.labels.collapse;
|
|
9531
|
-
|
|
9613
|
+
Dc(this.toggle, r, this.collapsed ? `(${e})` : void 0), this.toggle.setAttribute("aria-expanded", String(!this.collapsed));
|
|
9532
9614
|
let i = A(this.collapsed ? "chevronDown" : "chevronUp", 12);
|
|
9533
9615
|
this.toggle.innerHTML = this.collapsed ? `${i}<span>${e}</span>` : i;
|
|
9534
9616
|
}
|
|
9535
9617
|
};
|
|
9536
|
-
function
|
|
9618
|
+
function Dc(e, t, n) {
|
|
9537
9619
|
e.title = t, e.setAttribute("aria-label", n ? `${t} ${n}` : t);
|
|
9538
9620
|
}
|
|
9539
9621
|
//#endregion
|
|
9540
9622
|
//#region src/widget/legendValues.ts
|
|
9541
|
-
function
|
|
9623
|
+
function Oc(e, t, n, r) {
|
|
9542
9624
|
if (!t) return [];
|
|
9543
9625
|
let i = e.plots;
|
|
9544
9626
|
if (!i) {
|
|
@@ -9568,20 +9650,20 @@ function Cc(e, t, n, r) {
|
|
|
9568
9650
|
}
|
|
9569
9651
|
return o;
|
|
9570
9652
|
}
|
|
9571
|
-
var
|
|
9572
|
-
function
|
|
9573
|
-
let t =
|
|
9653
|
+
var kc = /* @__PURE__ */ new Map();
|
|
9654
|
+
function Ac(e) {
|
|
9655
|
+
let t = kc.get(e);
|
|
9574
9656
|
return t || (t = new Intl.NumberFormat(e, {
|
|
9575
9657
|
notation: "compact",
|
|
9576
9658
|
maximumFractionDigits: 2
|
|
9577
|
-
}),
|
|
9659
|
+
}), kc.set(e, t)), t;
|
|
9578
9660
|
}
|
|
9579
|
-
function
|
|
9580
|
-
return Math.abs(e) >= 1e6 ?
|
|
9661
|
+
function jc(e, t = "en-US") {
|
|
9662
|
+
return Math.abs(e) >= 1e6 ? Ac(t).format(e) : oe(e, Re(e), t);
|
|
9581
9663
|
}
|
|
9582
9664
|
//#endregion
|
|
9583
9665
|
//#region src/widget/WidgetBracketBar.ts
|
|
9584
|
-
var
|
|
9666
|
+
var Mc = class {
|
|
9585
9667
|
el;
|
|
9586
9668
|
labelEl;
|
|
9587
9669
|
callbacks;
|
|
@@ -9609,7 +9691,7 @@ var Dc = class {
|
|
|
9609
9691
|
destroy() {
|
|
9610
9692
|
this.el.remove();
|
|
9611
9693
|
}
|
|
9612
|
-
},
|
|
9694
|
+
}, Nc = class {
|
|
9613
9695
|
options;
|
|
9614
9696
|
audioCtx = null;
|
|
9615
9697
|
audioEl = null;
|
|
@@ -9672,7 +9754,7 @@ var Dc = class {
|
|
|
9672
9754
|
};
|
|
9673
9755
|
//#endregion
|
|
9674
9756
|
//#region src/widget/ladderRows.ts
|
|
9675
|
-
function
|
|
9757
|
+
function Pc(e, t = 12) {
|
|
9676
9758
|
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) => {
|
|
9677
9759
|
let t = s.get(e);
|
|
9678
9760
|
return t || (t = {
|
|
@@ -9688,31 +9770,45 @@ function kc(e, t = 12) {
|
|
|
9688
9770
|
return {
|
|
9689
9771
|
rows: l,
|
|
9690
9772
|
maxVolume: u,
|
|
9691
|
-
mid: o
|
|
9773
|
+
mid: o,
|
|
9774
|
+
spread: i !== null && a !== null ? i - a : null,
|
|
9775
|
+
bestBid: a
|
|
9692
9776
|
};
|
|
9693
9777
|
}
|
|
9694
9778
|
//#endregion
|
|
9695
9779
|
//#region src/widget/WidgetDepthLadder.ts
|
|
9696
|
-
var
|
|
9780
|
+
var Fc = 1e-9, Ic = class {
|
|
9697
9781
|
el;
|
|
9782
|
+
colsEl;
|
|
9698
9783
|
bodyEl;
|
|
9699
9784
|
callbacks;
|
|
9700
9785
|
open = !1;
|
|
9701
9786
|
levels;
|
|
9787
|
+
model = null;
|
|
9788
|
+
orders = [];
|
|
9789
|
+
drawn = [];
|
|
9790
|
+
spreadEl;
|
|
9791
|
+
placed = !1;
|
|
9702
9792
|
constructor(e, t, n = 12, r = h) {
|
|
9703
|
-
this.t = r, this.callbacks = t, this.levels = n, this.el = document.createElement("
|
|
9793
|
+
this.t = r, this.callbacks = t, this.levels = n, this.el = document.createElement("section"), this.el.className = "tcw-ladder", this.el.setAttribute("aria-label", this.t("ladder.title")), k(this.el, "depthLadder"), this.el.hidden = !0;
|
|
9704
9794
|
let i = document.createElement("div");
|
|
9705
9795
|
i.className = "tcw-ladder-header";
|
|
9706
|
-
let a = document.createElement("
|
|
9707
|
-
a.textContent = this.t("ladder.title");
|
|
9796
|
+
let a = document.createElement("h3");
|
|
9797
|
+
a.className = "tcw-ladder-title", a.textContent = this.t("ladder.title");
|
|
9708
9798
|
let o = document.createElement("button");
|
|
9709
|
-
o.type = "button", o.className = "tcw-ladder-close", o.setAttribute("aria-label", this.t("common.close")), o.innerHTML = A("x", 14), o.addEventListener("click", () => this.close()), i.
|
|
9710
|
-
let
|
|
9711
|
-
|
|
9712
|
-
|
|
9713
|
-
|
|
9714
|
-
|
|
9715
|
-
|
|
9799
|
+
o.type = "button", o.className = "tcw-ladder-close", o.setAttribute("aria-label", this.t("common.close")), o.innerHTML = A("x", 14), o.addEventListener("click", () => this.callbacks.onClose ? this.callbacks.onClose() : this.close()), i.append(a, o), this.colsEl = document.createElement("div"), this.colsEl.className = "tcw-ladder-cols";
|
|
9800
|
+
for (let e of [
|
|
9801
|
+
"ladder.bid",
|
|
9802
|
+
"ladder.price",
|
|
9803
|
+
"ladder.ask"
|
|
9804
|
+
]) {
|
|
9805
|
+
let t = document.createElement("span");
|
|
9806
|
+
t.textContent = this.t(e), this.colsEl.appendChild(t);
|
|
9807
|
+
}
|
|
9808
|
+
this.bodyEl = document.createElement("div"), this.bodyEl.className = "tcw-ladder-body", this.spreadEl = document.createElement("div"), this.spreadEl.className = "tcw-ladder-spread", this.el.append(i, this.colsEl, this.bodyEl), e.appendChild(this.el);
|
|
9809
|
+
}
|
|
9810
|
+
get element() {
|
|
9811
|
+
return this.el;
|
|
9716
9812
|
}
|
|
9717
9813
|
isOpen() {
|
|
9718
9814
|
return this.open;
|
|
@@ -9721,50 +9817,109 @@ var Ac = class {
|
|
|
9721
9817
|
this.open ? this.close() : this.openPanel();
|
|
9722
9818
|
}
|
|
9723
9819
|
openPanel() {
|
|
9724
|
-
this.open = !0, this.el.hidden = !1, this.callbacks.onToggle?.(!0);
|
|
9820
|
+
this.open = !0, this.placed = !1, this.el.hidden = !1, this.render(), this.callbacks.onToggle?.(!0);
|
|
9725
9821
|
}
|
|
9726
9822
|
close() {
|
|
9727
|
-
this.open = !1, this.el.hidden = !0, this.callbacks.onToggle?.(!1);
|
|
9823
|
+
this.open && (this.open = !1, this.el.hidden = !0, this.callbacks.onToggle?.(!1));
|
|
9728
9824
|
}
|
|
9729
9825
|
setData(e) {
|
|
9730
|
-
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
this.render(kc(e, this.levels));
|
|
9826
|
+
this.model = e ? Pc(e, this.levels) : null, this.render();
|
|
9827
|
+
}
|
|
9828
|
+
setOrders(e) {
|
|
9829
|
+
this.orders = e, this.render();
|
|
9735
9830
|
}
|
|
9736
9831
|
destroy() {
|
|
9737
9832
|
this.el.remove();
|
|
9738
9833
|
}
|
|
9739
|
-
|
|
9740
|
-
this.
|
|
9741
|
-
let e =
|
|
9742
|
-
e
|
|
9834
|
+
render() {
|
|
9835
|
+
if (!this.open) return;
|
|
9836
|
+
let e = this.model;
|
|
9837
|
+
if (!e || e.rows.length === 0) {
|
|
9838
|
+
let e = document.createElement("div");
|
|
9839
|
+
e.className = "tcw-ladder-empty", e.textContent = this.t("ladder.empty"), this.bodyEl.replaceChildren(e), this.drawn = [];
|
|
9840
|
+
return;
|
|
9841
|
+
}
|
|
9842
|
+
let t = Lc(e.rows);
|
|
9843
|
+
e.rows.length === this.drawn.length && e.rows.every((e, t) => e.price === this.drawn[t].price) || (this.drawn = e.rows.map((e) => this.newRow(e.price)), this.bodyEl.replaceChildren(...this.drawn.map((e) => e.row)));
|
|
9844
|
+
let n = e.maxVolume > 0 ? 100 / e.maxVolume : 0;
|
|
9845
|
+
e.rows.forEach((e, r) => this.fillRow(this.drawn[r], e, n, this.nearness(e.price, t))), this.putSpread(e, t), this.placeSpread();
|
|
9743
9846
|
}
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
9847
|
+
putSpread(e, t) {
|
|
9848
|
+
let { spread: n, bestBid: r } = e, i = n === null || r === null ? -1 : e.rows.findIndex((e) => e.price < r + t);
|
|
9849
|
+
if (n === null || i < 0) {
|
|
9850
|
+
this.spreadEl.remove();
|
|
9747
9851
|
return;
|
|
9748
9852
|
}
|
|
9749
|
-
|
|
9750
|
-
|
|
9751
|
-
|
|
9752
|
-
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
|
|
9853
|
+
this.spreadEl.textContent = p(this.t("ladder.spread"), { spread: this.callbacks.formatPrice(n) });
|
|
9854
|
+
let a = this.drawn[i].row;
|
|
9855
|
+
this.spreadEl.nextElementSibling !== a && this.bodyEl.insertBefore(this.spreadEl, a);
|
|
9856
|
+
}
|
|
9857
|
+
nearness(e, t) {
|
|
9858
|
+
let n = this.callbacks.priceStep?.(e) ?? 0;
|
|
9859
|
+
return n > 0 ? Math.min(n / 2, t) : t;
|
|
9860
|
+
}
|
|
9861
|
+
newRow(e) {
|
|
9862
|
+
let t = document.createElement("div");
|
|
9863
|
+
t.className = "tcw-ladder-row";
|
|
9864
|
+
let n = document.createElement("div");
|
|
9865
|
+
n.className = "tcw-ladder-price";
|
|
9866
|
+
let r = document.createElement("span");
|
|
9867
|
+
r.className = "tcw-ladder-figure", n.appendChild(r);
|
|
9868
|
+
let i = this.newCell("sell", e), a = this.newCell("buy", e);
|
|
9869
|
+
return t.append(i, n, a), {
|
|
9870
|
+
price: e,
|
|
9871
|
+
row: t,
|
|
9872
|
+
bid: i,
|
|
9873
|
+
ask: a,
|
|
9874
|
+
cell: n,
|
|
9875
|
+
figure: r
|
|
9876
|
+
};
|
|
9877
|
+
}
|
|
9878
|
+
newCell(e, t) {
|
|
9879
|
+
let n = document.createElement("button");
|
|
9880
|
+
return n.type = "button", n.className = `tcw-ladder-cell ${e === "sell" ? "tcw-ladder-bid" : "tcw-ladder-ask"}`, n.addEventListener("click", () => this.callbacks.onTrade(e, t)), n;
|
|
9881
|
+
}
|
|
9882
|
+
fillRow(e, t, n, r) {
|
|
9883
|
+
e.cell.className = `tcw-ladder-price ${t.askVolume > 0 ? "tcw-ask" : "tcw-bid"}`, e.figure.textContent = this.callbacks.formatPrice(t.price), this.fillCell(e.bid, "sell", t.bidVolume, t.price, n), this.fillCell(e.ask, "buy", t.askVolume, t.price, n);
|
|
9884
|
+
for (let t of e.cell.querySelectorAll(".tcw-ladder-own")) t.remove();
|
|
9885
|
+
for (let n of ["buy", "sell"]) {
|
|
9886
|
+
let i = this.orders.filter((e) => e.side === n && Math.abs(e.price - t.price) < r).reduce((e, t) => e + t.quantity, 0);
|
|
9887
|
+
if (i <= 0) continue;
|
|
9888
|
+
let a = document.createElement("span");
|
|
9889
|
+
a.className = "tcw-ladder-own", a.dataset.side = n, a.textContent = String(i);
|
|
9890
|
+
let o = `${this.t(n === "buy" ? "ticket.buy" : "ticket.sell")} ${i}`;
|
|
9891
|
+
a.setAttribute("aria-label", o), a.title = o, n === "buy" ? e.cell.insertBefore(a, e.figure) : e.cell.appendChild(a);
|
|
9892
|
+
}
|
|
9893
|
+
}
|
|
9894
|
+
fillCell(e, t, n, r, i) {
|
|
9895
|
+
if (!(n > 0)) {
|
|
9896
|
+
e.disabled = !0, e.textContent = "", e.removeAttribute("aria-label"), e.title = "", e.style.removeProperty("--w");
|
|
9897
|
+
return;
|
|
9759
9898
|
}
|
|
9899
|
+
e.disabled = !1;
|
|
9900
|
+
let a = Rc(n);
|
|
9901
|
+
e.textContent = a, e.style.setProperty("--w", `${(n * i).toFixed(1)}%`);
|
|
9902
|
+
let o = p(this.t(t === "sell" ? "ladder.sellAt" : "ladder.buyAt"), { price: this.callbacks.formatPrice(r) });
|
|
9903
|
+
e.setAttribute("aria-label", `${a}, ${o}`), e.title = o;
|
|
9904
|
+
}
|
|
9905
|
+
placeSpread() {
|
|
9906
|
+
let e = this.el;
|
|
9907
|
+
if (this.placed || !this.spreadEl.isConnected || e.clientHeight === 0) return;
|
|
9908
|
+
let t = e.getBoundingClientRect().top, n = this.colsEl.getBoundingClientRect().bottom - t, r = this.spreadEl.getBoundingClientRect().top - t;
|
|
9909
|
+
e.scrollTop += r - n - (e.clientHeight - n - this.spreadEl.offsetHeight) / 2, this.placed = !0;
|
|
9760
9910
|
}
|
|
9761
9911
|
};
|
|
9762
|
-
function
|
|
9763
|
-
|
|
9912
|
+
function Lc(e) {
|
|
9913
|
+
let t = Infinity;
|
|
9914
|
+
for (let n = 1; n < e.length; n++) t = Math.min(t, Math.abs(e[n - 1].price - e[n].price));
|
|
9915
|
+
return Number.isFinite(t) && t > 0 ? t / 2 : Fc;
|
|
9916
|
+
}
|
|
9917
|
+
function Rc(e) {
|
|
9918
|
+
return e >= 1e3 ? `${Number((e / 1e3).toFixed(1))}k` : String(Number(e >= 1 ? e.toFixed(2) : e.toPrecision(2)));
|
|
9764
9919
|
}
|
|
9765
9920
|
//#endregion
|
|
9766
9921
|
//#region src/widget/WidgetDataWindow.ts
|
|
9767
|
-
var
|
|
9922
|
+
var zc = class {
|
|
9768
9923
|
el;
|
|
9769
9924
|
bodyEl;
|
|
9770
9925
|
callbacks;
|
|
@@ -9806,11 +9961,11 @@ var Mc = class {
|
|
|
9806
9961
|
let t = this.callbacks.formatPrice, n = e.ohlc;
|
|
9807
9962
|
this.bodyEl.appendChild(this.row(this.t("dataWindow.open"), t(n.open))), this.bodyEl.appendChild(this.row(this.t("dataWindow.high"), t(n.high))), this.bodyEl.appendChild(this.row(this.t("dataWindow.low"), t(n.low))), this.bodyEl.appendChild(this.row(this.t("dataWindow.close"), t(n.close)));
|
|
9808
9963
|
let r = e.change > 0 ? "up" : e.change < 0 ? "down" : "", i = e.change > 0 ? "+" : "";
|
|
9809
|
-
this.bodyEl.appendChild(this.row(this.t("dataWindow.change"), `${i}${t(e.change)} (${i}${e.changePct.toFixed(2)}%)`, r)), this.bodyEl.appendChild(this.row(this.t("dataWindow.volume"),
|
|
9964
|
+
this.bodyEl.appendChild(this.row(this.t("dataWindow.change"), `${i}${t(e.change)} (${i}${e.changePct.toFixed(2)}%)`, r)), this.bodyEl.appendChild(this.row(this.t("dataWindow.volume"), Vc(n.volume)));
|
|
9810
9965
|
for (let t of e.indicators) {
|
|
9811
9966
|
let e = document.createElement("div");
|
|
9812
9967
|
e.className = "tcw-datawin-sub", e.textContent = t.name, this.bodyEl.appendChild(e);
|
|
9813
|
-
for (let e of t.values) this.bodyEl.appendChild(this.row(e.key,
|
|
9968
|
+
for (let e of t.values) this.bodyEl.appendChild(this.row(e.key, Bc(e.value)));
|
|
9814
9969
|
}
|
|
9815
9970
|
}
|
|
9816
9971
|
row(e, t, n = "") {
|
|
@@ -9822,43 +9977,43 @@ var Mc = class {
|
|
|
9822
9977
|
return a.className = `tcw-datawin-value${n ? ` tcw-${n}` : ""}`, a.textContent = t, r.appendChild(i), r.appendChild(a), r;
|
|
9823
9978
|
}
|
|
9824
9979
|
};
|
|
9825
|
-
function
|
|
9980
|
+
function Bc(e) {
|
|
9826
9981
|
if (!Number.isFinite(e)) return "—";
|
|
9827
9982
|
let t = Math.abs(e);
|
|
9828
9983
|
return t >= 1e3 ? e.toFixed(2) : t >= 1 ? e.toFixed(4) : e.toPrecision(4);
|
|
9829
9984
|
}
|
|
9830
|
-
function
|
|
9985
|
+
function Vc(e) {
|
|
9831
9986
|
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);
|
|
9832
9987
|
}
|
|
9833
9988
|
//#endregion
|
|
9834
9989
|
//#region src/widget/widgetShareState.ts
|
|
9835
|
-
var
|
|
9836
|
-
function
|
|
9837
|
-
if (
|
|
9990
|
+
var Hc = globalThis.Buffer;
|
|
9991
|
+
function Uc(e) {
|
|
9992
|
+
if (Hc) return Hc.from(e, "utf8").toString("base64");
|
|
9838
9993
|
let t = new TextEncoder().encode(e), n = "";
|
|
9839
9994
|
for (let e of t) n += String.fromCharCode(e);
|
|
9840
9995
|
return btoa(n);
|
|
9841
9996
|
}
|
|
9842
|
-
function
|
|
9843
|
-
if (
|
|
9997
|
+
function Wc(e) {
|
|
9998
|
+
if (Hc) return Hc.from(e, "base64").toString("utf8");
|
|
9844
9999
|
let t = atob(e), n = new Uint8Array(t.length);
|
|
9845
10000
|
for (let e = 0; e < t.length; e++) n[e] = t.charCodeAt(e);
|
|
9846
10001
|
return new TextDecoder().decode(n);
|
|
9847
10002
|
}
|
|
9848
|
-
function
|
|
10003
|
+
function Gc(e) {
|
|
9849
10004
|
return e.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
9850
10005
|
}
|
|
9851
|
-
function
|
|
10006
|
+
function Kc(e) {
|
|
9852
10007
|
let t = e.replace(/-/g, "+").replace(/_/g, "/");
|
|
9853
10008
|
return t + (t.length % 4 == 0 ? "" : "=".repeat(4 - t.length % 4));
|
|
9854
10009
|
}
|
|
9855
|
-
function
|
|
9856
|
-
return
|
|
10010
|
+
function qc(e) {
|
|
10011
|
+
return Gc(Uc(JSON.stringify(e)));
|
|
9857
10012
|
}
|
|
9858
|
-
function
|
|
10013
|
+
function Jc(e) {
|
|
9859
10014
|
if (!e) return null;
|
|
9860
10015
|
try {
|
|
9861
|
-
let t =
|
|
10016
|
+
let t = Wc(Kc(e)), n = JSON.parse(t);
|
|
9862
10017
|
return !n || n.v !== 1 || typeof n.symbol != "string" ? null : {
|
|
9863
10018
|
v: 1,
|
|
9864
10019
|
symbol: n.symbol,
|
|
@@ -9872,20 +10027,20 @@ function Vc(e) {
|
|
|
9872
10027
|
return null;
|
|
9873
10028
|
}
|
|
9874
10029
|
}
|
|
9875
|
-
var
|
|
9876
|
-
function
|
|
10030
|
+
var Yc = "tcw";
|
|
10031
|
+
function Xc(e) {
|
|
9877
10032
|
let t = e.startsWith("#") ? e.slice(1) : e;
|
|
9878
10033
|
for (let e of t.split("&")) {
|
|
9879
10034
|
let t = e.indexOf("=");
|
|
9880
|
-
if (t > 0 && e.slice(0, t) ===
|
|
10035
|
+
if (t > 0 && e.slice(0, t) === Yc) return decodeURIComponent(e.slice(t + 1));
|
|
9881
10036
|
}
|
|
9882
10037
|
return null;
|
|
9883
10038
|
}
|
|
9884
|
-
function
|
|
10039
|
+
function Zc(e, t) {
|
|
9885
10040
|
let [n] = e.split("#");
|
|
9886
|
-
return `${n}#${
|
|
10041
|
+
return `${n}#${Yc}=${t}`;
|
|
9887
10042
|
}
|
|
9888
|
-
var
|
|
10043
|
+
var Qc = [
|
|
9889
10044
|
[
|
|
9890
10045
|
34,
|
|
9891
10046
|
16,
|
|
@@ -9942,7 +10097,7 @@ var Gc = [
|
|
|
9942
10097
|
30,
|
|
9943
10098
|
!0
|
|
9944
10099
|
]
|
|
9945
|
-
],
|
|
10100
|
+
], $c = class {
|
|
9946
10101
|
el;
|
|
9947
10102
|
label;
|
|
9948
10103
|
showTimer = null;
|
|
@@ -9952,7 +10107,7 @@ var Gc = [
|
|
|
9952
10107
|
let n = document.createElement("div");
|
|
9953
10108
|
n.className = "tcw-loading-card";
|
|
9954
10109
|
let r = document.createElement("div");
|
|
9955
|
-
r.className = "tcw-loading-candles", r.setAttribute("aria-hidden", "true"),
|
|
10110
|
+
r.className = "tcw-loading-candles", r.setAttribute("aria-hidden", "true"), Qc.forEach(([e, t, n, i, a], o) => {
|
|
9956
10111
|
let s = document.createElement("span");
|
|
9957
10112
|
s.className = a ? "tcw-loading-candle tcw-loading-candle--up" : "tcw-loading-candle", s.style.setProperty("--tcw-body-top", `${e}px`), s.style.setProperty("--tcw-body-h", `${t}px`), s.style.setProperty("--tcw-wick-top", `${n}px`), s.style.setProperty("--tcw-wick-h", `${i}px`), s.style.setProperty("--tcw-delay", `${o * 110}ms`), r.appendChild(s);
|
|
9958
10113
|
}), n.appendChild(r);
|
|
@@ -9989,7 +10144,7 @@ var Gc = [
|
|
|
9989
10144
|
clearTimer() {
|
|
9990
10145
|
this.showTimer !== null && (clearTimeout(this.showTimer), this.showTimer = null);
|
|
9991
10146
|
}
|
|
9992
|
-
},
|
|
10147
|
+
}, el = 4e3, tl = class {
|
|
9993
10148
|
el;
|
|
9994
10149
|
text;
|
|
9995
10150
|
hideTimer = null;
|
|
@@ -9999,7 +10154,7 @@ var Gc = [
|
|
|
9999
10154
|
n.className = "tcw-history-spinner", n.setAttribute("aria-hidden", "true"), this.text = document.createElement("span"), this.el.append(n, this.text), e.appendChild(this.el);
|
|
10000
10155
|
}
|
|
10001
10156
|
update(e) {
|
|
10002
|
-
this.clearTimer(), e.state === "loading" ? this.show(this.texts.loading, !1) : e.state === "error" ? (this.show(this.texts.failed, !0), this.hideTimer = setTimeout(() => this.hide(),
|
|
10157
|
+
this.clearTimer(), e.state === "loading" ? this.show(this.texts.loading, !1) : e.state === "error" ? (this.show(this.texts.failed, !0), this.hideTimer = setTimeout(() => this.hide(), el)) : this.hide();
|
|
10003
10158
|
}
|
|
10004
10159
|
destroy() {
|
|
10005
10160
|
this.clearTimer(), this.el.remove();
|
|
@@ -10013,13 +10168,13 @@ var Gc = [
|
|
|
10013
10168
|
clearTimer() {
|
|
10014
10169
|
this.hideTimer !== null && clearTimeout(this.hideTimer), this.hideTimer = null;
|
|
10015
10170
|
}
|
|
10016
|
-
},
|
|
10017
|
-
function
|
|
10171
|
+
}, nl = "host:";
|
|
10172
|
+
function rl(e, t) {
|
|
10018
10173
|
return [
|
|
10019
10174
|
...e,
|
|
10020
10175
|
...e.length > 0 && t.length > 0 ? ["separator"] : [],
|
|
10021
10176
|
...t.map((e, t) => ({
|
|
10022
|
-
id: `${
|
|
10177
|
+
id: `${nl}${t}`,
|
|
10023
10178
|
label: e.label,
|
|
10024
10179
|
icon: e.icon,
|
|
10025
10180
|
danger: e.danger,
|
|
@@ -10027,12 +10182,12 @@ function Xc(e, t) {
|
|
|
10027
10182
|
}))
|
|
10028
10183
|
];
|
|
10029
10184
|
}
|
|
10030
|
-
function
|
|
10031
|
-
return e.startsWith(
|
|
10185
|
+
function il(e, t) {
|
|
10186
|
+
return e.startsWith(nl) ? (t[Number(e.slice(5))]?.onSelect(), !0) : !1;
|
|
10032
10187
|
}
|
|
10033
10188
|
//#endregion
|
|
10034
10189
|
//#region src/widget/hostHotkeys.ts
|
|
10035
|
-
var
|
|
10190
|
+
var al = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent), ol = {
|
|
10036
10191
|
ctrl: "ctrl",
|
|
10037
10192
|
control: "ctrl",
|
|
10038
10193
|
cmd: "ctrl",
|
|
@@ -10043,7 +10198,7 @@ var Qc = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platfo
|
|
|
10043
10198
|
option: "alt",
|
|
10044
10199
|
opt: "alt",
|
|
10045
10200
|
shift: "shift"
|
|
10046
|
-
},
|
|
10201
|
+
}, sl = {
|
|
10047
10202
|
esc: "escape",
|
|
10048
10203
|
space: " ",
|
|
10049
10204
|
spacebar: " ",
|
|
@@ -10055,7 +10210,7 @@ var Qc = typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platfo
|
|
|
10055
10210
|
return: "enter",
|
|
10056
10211
|
plus: "+"
|
|
10057
10212
|
};
|
|
10058
|
-
function
|
|
10213
|
+
function cl(e) {
|
|
10059
10214
|
let t = e.split("+").map((e) => e.trim()), n = t.pop();
|
|
10060
10215
|
if (!n) return null;
|
|
10061
10216
|
let r = {
|
|
@@ -10065,23 +10220,23 @@ function tl(e) {
|
|
|
10065
10220
|
display: []
|
|
10066
10221
|
};
|
|
10067
10222
|
for (let e of t) {
|
|
10068
|
-
let t =
|
|
10223
|
+
let t = ol[e.toLowerCase()];
|
|
10069
10224
|
if (!t) return null;
|
|
10070
10225
|
r[t] = !0;
|
|
10071
10226
|
}
|
|
10072
10227
|
let i = n.toLowerCase();
|
|
10073
|
-
if (
|
|
10228
|
+
if (ol[i]) return null;
|
|
10074
10229
|
if (/^[a-z]$/.test(i)) r.code = `Key${i.toUpperCase()}`, r.char = i;
|
|
10075
10230
|
else if (/^[0-9]$/.test(i)) r.code = `Digit${i}`, r.char = i;
|
|
10076
|
-
else if (r.key =
|
|
10231
|
+
else if (r.key = sl[i] ?? i, r.shift && r.key.length === 1) return null;
|
|
10077
10232
|
return r.display = [
|
|
10078
|
-
...r.ctrl ? [
|
|
10233
|
+
...r.ctrl ? [al ? "⌘" : "Ctrl"] : [],
|
|
10079
10234
|
...r.alt ? ["Alt"] : [],
|
|
10080
10235
|
...r.shift ? ["Shift"] : [],
|
|
10081
10236
|
r.key === " " ? "Space" : n.length === 1 ? n.toUpperCase() : n
|
|
10082
10237
|
], r;
|
|
10083
10238
|
}
|
|
10084
|
-
function
|
|
10239
|
+
function ll(e, t) {
|
|
10085
10240
|
if ((e.ctrlKey || e.metaKey) !== t.ctrl || e.altKey !== t.alt) return !1;
|
|
10086
10241
|
if (t.code !== void 0) {
|
|
10087
10242
|
if (e.shiftKey !== t.shift) return !1;
|
|
@@ -10091,54 +10246,56 @@ function nl(e, t) {
|
|
|
10091
10246
|
}
|
|
10092
10247
|
return t.shift && !e.shiftKey ? !1 : e.key.toLowerCase() === t.key;
|
|
10093
10248
|
}
|
|
10094
|
-
var
|
|
10095
|
-
function
|
|
10249
|
+
var ul = new Set(/* @__PURE__ */ "escape(enter(delete(backspace(arrowleft(arrowright(arrowup(arrowdown(home(end(+(-(=( (,(.(ctrl+z(ctrl+shift+z(ctrl+y(ctrl+c(ctrl+v(ctrl+d(ctrl+g(ctrl+shift+g(ctrl+[(ctrl+]".split("("));
|
|
10250
|
+
function dl(e) {
|
|
10096
10251
|
let t = `${e.ctrl ? "ctrl+" : ""}${e.alt ? "alt+" : ""}${e.shift ? "shift+" : ""}${e.char ?? e.key}`;
|
|
10097
|
-
return
|
|
10252
|
+
return ul.has(t);
|
|
10098
10253
|
}
|
|
10099
|
-
function
|
|
10254
|
+
function fl(e) {
|
|
10100
10255
|
let t = typeof e.composedPath == "function" ? e.composedPath()[0] : e.target;
|
|
10101
10256
|
return t instanceof HTMLElement ? t.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName) : !1;
|
|
10102
10257
|
}
|
|
10103
10258
|
//#endregion
|
|
10104
10259
|
//#region src/widget/ChartWidget.ts
|
|
10105
|
-
var
|
|
10106
|
-
function
|
|
10260
|
+
var pl = 48, ml = 5e4, hl = 100;
|
|
10261
|
+
function gl() {
|
|
10107
10262
|
return new Promise((e) => {
|
|
10108
10263
|
if (typeof requestAnimationFrame != "function" || document.hidden) {
|
|
10109
10264
|
setTimeout(e, 0);
|
|
10110
10265
|
return;
|
|
10111
10266
|
}
|
|
10112
|
-
let t = setTimeout(e,
|
|
10267
|
+
let t = setTimeout(e, hl);
|
|
10113
10268
|
requestAnimationFrame(() => setTimeout(() => {
|
|
10114
10269
|
clearTimeout(t), e();
|
|
10115
10270
|
}, 0));
|
|
10116
10271
|
});
|
|
10117
10272
|
}
|
|
10118
|
-
var
|
|
10273
|
+
var _l = [
|
|
10119
10274
|
"#4c8dff",
|
|
10120
10275
|
"#a57cff",
|
|
10121
10276
|
"#1398a8",
|
|
10122
10277
|
"#e25592",
|
|
10123
10278
|
"#8a93a3",
|
|
10124
10279
|
"#62c895"
|
|
10125
|
-
],
|
|
10280
|
+
], vl = 864e5, yl = {
|
|
10126
10281
|
alerts: "alerts",
|
|
10127
10282
|
objectTree: "objectTree",
|
|
10128
10283
|
dataWindow: "dataWindow",
|
|
10129
|
-
symbolInfo: "symbolInfo"
|
|
10130
|
-
|
|
10284
|
+
symbolInfo: "symbolInfo",
|
|
10285
|
+
depthLadder: "depthLadder"
|
|
10286
|
+
}, bl = 2, xl = {
|
|
10131
10287
|
alerts: "alerts",
|
|
10132
10288
|
objectTree: "objects",
|
|
10133
|
-
symbolInfo: "symbolInfo"
|
|
10289
|
+
symbolInfo: "symbolInfo",
|
|
10290
|
+
depthLadder: "trade"
|
|
10134
10291
|
};
|
|
10135
|
-
function
|
|
10136
|
-
if (e.ctrlKey || e.metaKey || e.altKey || e.isComposing || e.keyCode ===
|
|
10292
|
+
function Sl(e) {
|
|
10293
|
+
if (e.ctrlKey || e.metaKey || e.altKey || e.isComposing || e.keyCode === Al || e.getModifierState?.("AltGraph")) return null;
|
|
10137
10294
|
if (/^[a-z]$/i.test(e.key)) return e.key;
|
|
10138
10295
|
let t = /^Key([A-Z])$/.exec(e.code ?? "");
|
|
10139
10296
|
return t && [...e.key].length === 1 && !/[\s\d]/.test(e.key) ? t[1].toLowerCase() : null;
|
|
10140
10297
|
}
|
|
10141
|
-
var
|
|
10298
|
+
var Cl = 4, wl = 7, Tl = 17, El = 3, Dl = [
|
|
10142
10299
|
"1m",
|
|
10143
10300
|
"3m",
|
|
10144
10301
|
"5m",
|
|
@@ -10148,10 +10305,10 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10148
10305
|
"2h",
|
|
10149
10306
|
"4h",
|
|
10150
10307
|
"1d"
|
|
10151
|
-
],
|
|
10308
|
+
], Ol = 5e3, kl = () => {
|
|
10152
10309
|
let e = document.activeElement;
|
|
10153
10310
|
return e instanceof Element && e.closest("[role=\"dialog\"], [aria-modal=\"true\"], [role=\"menu\"]") !== null;
|
|
10154
|
-
},
|
|
10311
|
+
}, Al = 229, jl = 1e3, Ml = O.filter((e) => g[e] !== "color"), Nl = () => typeof document < "u" && document.hidden, Pl = 200, Fl = class {
|
|
10155
10312
|
chart;
|
|
10156
10313
|
state;
|
|
10157
10314
|
themeOf = {
|
|
@@ -10201,7 +10358,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10201
10358
|
symbolLoads = /* @__PURE__ */ new Map();
|
|
10202
10359
|
ui;
|
|
10203
10360
|
legendMenu = null;
|
|
10204
|
-
templates = new
|
|
10361
|
+
templates = new zs();
|
|
10205
10362
|
templatePrompt = null;
|
|
10206
10363
|
chartTemplates = new Xa();
|
|
10207
10364
|
chartTemplatePrompt = null;
|
|
@@ -10220,11 +10377,11 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10220
10377
|
dataWindow = null;
|
|
10221
10378
|
lastHoverIndex = null;
|
|
10222
10379
|
legendHoverIndex = null;
|
|
10223
|
-
favoritesStore = new
|
|
10224
|
-
indicatorFavorites = new
|
|
10380
|
+
favoritesStore = new Zs();
|
|
10381
|
+
indicatorFavorites = new Zs("tcw:indicator-favorites");
|
|
10225
10382
|
indicatorDefaults = new Ha();
|
|
10226
|
-
timeframeFavorites = new
|
|
10227
|
-
customTimeframes = new
|
|
10383
|
+
timeframeFavorites = new Zs("tcw:tf-favorites");
|
|
10384
|
+
customTimeframes = new Zs("tcw:tf-custom");
|
|
10228
10385
|
timeframes = [];
|
|
10229
10386
|
watchlist = null;
|
|
10230
10387
|
watchlistSparkBuffer = /* @__PURE__ */ new Map();
|
|
@@ -10351,8 +10508,8 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10351
10508
|
connectionState: t.adapter ? "connecting" : "disconnected",
|
|
10352
10509
|
connectionMessage: t.adapter ? this.t("status.connecting") : ""
|
|
10353
10510
|
}, rn(), this.root = document.createElement("div"), this.root.className = "tcw-root", this.root.dataset.tcwTheme = i ? "dark" : "light";
|
|
10354
|
-
let m = t.dir === "ltr" || t.dir === "rtl" ? t.dir :
|
|
10355
|
-
this.root.dir = m, this.portal.dir = m, e.appendChild(this.root), this.tooltip = new
|
|
10511
|
+
let m = t.dir === "ltr" || t.dir === "rtl" ? t.dir : Kl(t.locale) ? "rtl" : "ltr";
|
|
10512
|
+
this.root.dir = m, this.portal.dir = m, e.appendChild(this.root), this.tooltip = new vc(this.root), this.portal.className = "tcw-root tcw-portal", this.portal.dataset.tcwTheme = this.root.dataset.tcwTheme, this.stopKeyboardInset = Qs([this.root, this.portal]), this.stopNarrow = $s(this.root, (e) => {
|
|
10356
10513
|
this.toolbar?.fit(), e || this.sidebar?.closeOverlay(), this.syncRail();
|
|
10357
10514
|
}), this.ui = G(t.ui);
|
|
10358
10515
|
let h = t.ui !== void 0;
|
|
@@ -10387,7 +10544,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10387
10544
|
onToggleAccount: t.trading === !1 ? void 0 : () => this.toggleAccountPanel(),
|
|
10388
10545
|
onLayouts: t.layouts === !1 ? void 0 : (e) => void this.layoutsUI?.openMenu(e),
|
|
10389
10546
|
onBracket: t.trading === !1 ? void 0 : (e) => this.startBracket(e),
|
|
10390
|
-
onToggleLadder: t.trading !== !1 && t.depthLadder ? () => this.
|
|
10547
|
+
onToggleLadder: t.trading !== !1 && t.depthLadder ? () => this.toggleLadder() : void 0,
|
|
10391
10548
|
onOrderTicket: t.trading === !1 ? void 0 : () => this.openOrderTicket(),
|
|
10392
10549
|
onCompare: t.adapter && s.compareSymbols !== !1 ? () => this.handleAddCompare() : void 0,
|
|
10393
10550
|
onUndo: () => this.chart.undo(),
|
|
@@ -10420,16 +10577,16 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10420
10577
|
onHideAll: (e) => {
|
|
10421
10578
|
this.chart.setDrawingsVisible(this.chart.getDrawings().map((e) => e.id), !e), this.refreshDrawingsState(), this.refreshObjects();
|
|
10422
10579
|
}
|
|
10423
|
-
}, this.t), this.chartContainer = document.createElement("div"), this.chartContainer.className = "tcw-chart-container", this.chartContainer.dir = "ltr", g.appendChild(this.chartContainer), this.loading = new
|
|
10580
|
+
}, this.t), this.chartContainer = document.createElement("div"), this.chartContainer.className = "tcw-chart-container", this.chartContainer.dir = "ltr", g.appendChild(this.chartContainer), this.loading = new $c(this.chartContainer, this.t("status.loading")), this.historyPill = new tl(this.chartContainer, {
|
|
10424
10581
|
loading: this.t("history.loading"),
|
|
10425
10582
|
failed: this.t("history.failed")
|
|
10426
|
-
}), this.dock = new
|
|
10583
|
+
}), this.dock = new sc(g, {
|
|
10427
10584
|
labels: {
|
|
10428
10585
|
rail: this.t("dock.rail"),
|
|
10429
10586
|
resize: this.t("dock.resize")
|
|
10430
10587
|
},
|
|
10431
|
-
savedWidth: () =>
|
|
10432
|
-
saveWidth: (e) =>
|
|
10588
|
+
savedWidth: () => Hl(),
|
|
10589
|
+
saveWidth: (e) => Ul(e),
|
|
10433
10590
|
railShown: () => this.railShown(),
|
|
10434
10591
|
focusAfterClose: (e) => this.panelFocusTarget(e),
|
|
10435
10592
|
room: () => g.clientWidth
|
|
@@ -10474,7 +10631,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10474
10631
|
this.toolbar?.setActive("symbolInfo", e), e && (this.refreshSymbolInfo(), this.loadNews());
|
|
10475
10632
|
}
|
|
10476
10633
|
}), this.marketTimer = setInterval(() => this.refreshMarket(), 3e4), this.onPageShown = () => {
|
|
10477
|
-
|
|
10634
|
+
Nl() || this.refreshMarket();
|
|
10478
10635
|
}, document.addEventListener("visibilitychange", this.onPageShown), this.dragDrop = new a(this.chartContainer, {
|
|
10479
10636
|
onData: (e, t, n) => {
|
|
10480
10637
|
this.setData(e);
|
|
@@ -10500,10 +10657,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10500
10657
|
now: () => this.clockNow(),
|
|
10501
10658
|
options: () => ({
|
|
10502
10659
|
current: this.settingsState.timezone,
|
|
10503
|
-
list: Ze(this.settingsState.timezone, Date.now(), this.t("settings.timezone.local"), this.
|
|
10504
|
-
label: this.t("settings.timezone.exchange"),
|
|
10505
|
-
zone: this.chart.getSymbolInfo()?.timezone ?? null
|
|
10506
|
-
} : void 0)
|
|
10660
|
+
list: Ze(this.settingsState.timezone, Date.now(), this.t("settings.timezone.local"), this.exchangeChoice())
|
|
10507
10661
|
}),
|
|
10508
10662
|
onPick: (e) => this.changeSettings({ timezone: e })
|
|
10509
10663
|
},
|
|
@@ -10523,8 +10677,8 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10523
10677
|
onAuto: () => this.changeSettings({ autoScale: !this.chart.isAutoScale() })
|
|
10524
10678
|
}
|
|
10525
10679
|
}), this.clockTimer = setInterval(() => {
|
|
10526
|
-
!
|
|
10527
|
-
},
|
|
10680
|
+
!Nl() && this.featureState.statusBar && this.featureState["statusBar.clock"] && this.statusBar?.tick();
|
|
10681
|
+
}, jl), this.chart.on("priceRangeChange", () => this.refreshScaleSwitches()), this.refreshScaleSwitches(), this.goToDate = new ic(this.overlayHost, () => ({
|
|
10528
10682
|
title: this.t("goTo.title"),
|
|
10529
10683
|
date: this.t("range.date"),
|
|
10530
10684
|
range: this.t("goTo.range"),
|
|
@@ -10556,7 +10710,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10556
10710
|
barCountdown: s.barCountdown,
|
|
10557
10711
|
logScale: s.logScale,
|
|
10558
10712
|
trading: s.trading !== !1,
|
|
10559
|
-
exchangeZone:
|
|
10713
|
+
exchangeZone: () => this.exchangeChoice()?.zone
|
|
10560
10714
|
}, this.overlayHost), this.symbolSearch = new Vr({
|
|
10561
10715
|
onPick: (e) => {
|
|
10562
10716
|
this.setSymbol(e);
|
|
@@ -10575,7 +10729,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10575
10729
|
eraser: t ?? this.state.eraser,
|
|
10576
10730
|
zoomArea: n ?? this.state.zoomArea
|
|
10577
10731
|
}, this.updateUI();
|
|
10578
|
-
}), this.chart.on("indicatorAdd", () => this.syncIndicatorsFromChart()), this.chart.on("indicatorRemove", () => this.syncIndicatorsFromChart()), this.chart.setPaneTitlesVisible(!this.featureState.indicatorLegend), this.indicatorLegend = new
|
|
10732
|
+
}), this.chart.on("indicatorAdd", () => this.syncIndicatorsFromChart()), this.chart.on("indicatorRemove", () => this.syncIndicatorsFromChart()), this.chart.setPaneTitlesVisible(!this.featureState.indicatorLegend), this.indicatorLegend = new Ec(this.chartContainer, {
|
|
10579
10733
|
onToggleVisible: (e, t) => {
|
|
10580
10734
|
this.chart.setIndicatorVisible(e, t), this.scheduleLegend(), this.objectTree?.isOpen() && this.refreshObjects();
|
|
10581
10735
|
},
|
|
@@ -10630,7 +10784,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10630
10784
|
if (this.replayBar?.getMode() !== "select" || !this.replayBar.isMounted()) return;
|
|
10631
10785
|
let t = e.payload.point;
|
|
10632
10786
|
this.positionReplayShade(t?.x ?? null);
|
|
10633
|
-
}), this.dataWindow = new
|
|
10787
|
+
}), this.dataWindow = new zc(this.root, {
|
|
10634
10788
|
formatPrice: (e) => this.formatAlertPrice(e),
|
|
10635
10789
|
onClose: () => this.closePanelByHand("dataWindow")
|
|
10636
10790
|
}, this.t), this.chart.on("crosshairMove", (e) => {
|
|
@@ -10647,7 +10801,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10647
10801
|
},
|
|
10648
10802
|
toWallTime: (e) => Z(e * ae(this.chart.getData()), this.displayTimezone()),
|
|
10649
10803
|
fromWallTime: (e, t) => {
|
|
10650
|
-
let n =
|
|
10804
|
+
let n = nc(e, t, this.displayTimezone());
|
|
10651
10805
|
return n === null ? null : n / ae(this.chart.getData());
|
|
10652
10806
|
},
|
|
10653
10807
|
roundPrice: (e) => this.chart.roundPrice(e),
|
|
@@ -10740,12 +10894,12 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10740
10894
|
area: "priceAxisAdd",
|
|
10741
10895
|
price: i
|
|
10742
10896
|
});
|
|
10743
|
-
}), this.chart.on("signalMarkerHover", (e) => this.showMarkerTip(e.payload)), this.intervalInput = new
|
|
10897
|
+
}), this.chart.on("signalMarkerHover", (e) => this.showMarkerTip(e.payload)), this.intervalInput = new Rs(this.chartContainer, {
|
|
10744
10898
|
title: this.t("interval.title"),
|
|
10745
10899
|
hint: this.t("interval.hint"),
|
|
10746
10900
|
invalid: this.t("interval.invalid")
|
|
10747
10901
|
}, (e) => this.selectTypedTimeframe(e)), t.layouts !== !1 && this.setupLayouts(t.layouts === !0 || t.layouts === void 0 ? {} : t.layouts), t.trading !== !1) {
|
|
10748
|
-
this.orderTicket = new
|
|
10902
|
+
this.orderTicket = new Ds(this.root, {
|
|
10749
10903
|
onSubmit: (e) => {
|
|
10750
10904
|
this.chart.placeOrderIntent(e), this.say(p(this.t("ticket.sent"), {
|
|
10751
10905
|
side: this.t(e.side === "buy" ? "ticket.buy" : "ticket.sell"),
|
|
@@ -10756,7 +10910,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10756
10910
|
formatPrice: (e) => this.formatAlertPrice(e),
|
|
10757
10911
|
formatAmount: (e) => this.formatMoney(e),
|
|
10758
10912
|
formatNumber: (e, t) => this.formatNumber(e, t)
|
|
10759
|
-
}, this.t), this.accountPanel = new
|
|
10913
|
+
}, this.t), this.accountPanel = new ps(_, {
|
|
10760
10914
|
onClosePosition: (e) => this.chart.closePositionIntent(e),
|
|
10761
10915
|
onReversePosition: (e) => this.chart.reversePositionIntent(e),
|
|
10762
10916
|
onCancelOrder: (e) => this.chart.cancelOrderIntent(e),
|
|
@@ -10766,6 +10920,8 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10766
10920
|
let { date: t, time: n } = Z(e, this.displayTimezone());
|
|
10767
10921
|
return `${t} ${n}`;
|
|
10768
10922
|
},
|
|
10923
|
+
formatAmount: (e) => this.formatMoney(e),
|
|
10924
|
+
formatNumber: (e, t) => this.formatNumber(e, t),
|
|
10769
10925
|
onToggle: (e) => {
|
|
10770
10926
|
this.toolbar?.setActive("account", e), this.refreshAccount();
|
|
10771
10927
|
}
|
|
@@ -10778,28 +10934,37 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10778
10934
|
"indicatorUpdate"
|
|
10779
10935
|
]) this.chart.on(e, () => this.refreshAccountSoon());
|
|
10780
10936
|
}
|
|
10781
|
-
t.trading !== !1
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10937
|
+
if (t.trading !== !1) {
|
|
10938
|
+
if (this.bracketBar = new Mc(this.chartContainer, {
|
|
10939
|
+
onConfirm: () => this.chart.confirmBracket(),
|
|
10940
|
+
onCancel: () => {
|
|
10941
|
+
this.chart.cancelBracket(), this.bracketBar?.hide();
|
|
10942
|
+
}
|
|
10943
|
+
}, this.t), this.chart.on("bracketPlace", (e) => {
|
|
10944
|
+
let t = e.payload;
|
|
10945
|
+
this.bracketBar?.hide(), this.say(p(this.t(t.side === "buy" ? "bracket.longPlaced" : "bracket.shortPlaced"), { rr: t.riskReward.toFixed(2) }));
|
|
10946
|
+
}), t.depthLadder) {
|
|
10947
|
+
this.depthLadder = new Ic(this.root, {
|
|
10948
|
+
onTrade: (e, t) => {
|
|
10949
|
+
this.chart.placeOrderIntent({
|
|
10950
|
+
side: e,
|
|
10951
|
+
type: "limit",
|
|
10952
|
+
price: t
|
|
10953
|
+
}), this.say(p(this.t(e === "buy" ? "order.buyLimit" : "order.sellLimit"), { price: this.formatAlertPrice(t) }));
|
|
10954
|
+
},
|
|
10955
|
+
formatPrice: (e) => this.formatAlertPrice(e),
|
|
10956
|
+
priceStep: (e) => this.chart.getPriceStep(e),
|
|
10957
|
+
onToggle: (e) => this.toolbar?.setActive("ladder", e),
|
|
10958
|
+
onClose: () => this.closePanelByHand("depthLadder")
|
|
10959
|
+
}, void 0, this.t);
|
|
10960
|
+
let e = this.depthLadder;
|
|
10961
|
+
this.chart.on("ordersChange", () => e.setOrders(this.chart.getOrders()));
|
|
10785
10962
|
}
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
}
|
|
10790
|
-
|
|
10791
|
-
this.chart.placeOrderIntent({
|
|
10792
|
-
side: e,
|
|
10793
|
-
type: "limit",
|
|
10794
|
-
price: t
|
|
10795
|
-
}), this.say(p(this.t(e === "buy" ? "order.buyLimit" : "order.sellLimit"), { price: this.formatAlertPrice(t) }));
|
|
10796
|
-
},
|
|
10797
|
-
formatPrice: (e) => this.formatAlertPrice(e),
|
|
10798
|
-
onToggle: (e) => this.toolbar?.setActive("ladder", e)
|
|
10799
|
-
}, void 0, this.t)), this.chart.on("dataUpdate", (e) => {
|
|
10800
|
-
let t = e.payload;
|
|
10801
|
-
t && t.bracket === "cancelled" && this.bracketBar?.hide();
|
|
10802
|
-
})), this.alertsPanel = new Hi(this.root, {
|
|
10963
|
+
this.chart.on("dataUpdate", (e) => {
|
|
10964
|
+
e.payload.kind === "bracket" && this.bracketBar?.hide();
|
|
10965
|
+
});
|
|
10966
|
+
}
|
|
10967
|
+
this.alertsPanel = new Hi(this.root, {
|
|
10803
10968
|
onClose: () => this.closePanelByHand("alerts"),
|
|
10804
10969
|
onAdd: ({ price: e, condition: t, message: n, channel: r, label: i, options: a }) => {
|
|
10805
10970
|
try {
|
|
@@ -10819,7 +10984,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10819
10984
|
}, this.t), this.chart.on("alertAdd", () => this.refreshAlerts()), this.chart.on("alertRemove", () => this.refreshAlerts()), this.chart.on("alertUpdate", () => this.refreshAlerts()), this.chart.on("alertExpired", (e) => {
|
|
10820
10985
|
let t = e.payload;
|
|
10821
10986
|
this.refreshAlerts(), this.featureState.alerts && this.say(p(this.t("alerts.expiredToast"), { text: t.message ?? this.alertText(t) }));
|
|
10822
|
-
}), t.alertNotifications && (this.alertNotifier = new
|
|
10987
|
+
}), t.alertNotifications && (this.alertNotifier = new Nc(t.alertNotifications)), this.chart.on("alertTriggered", (e) => {
|
|
10823
10988
|
let t = e.payload;
|
|
10824
10989
|
if (this.refreshAlerts(), !this.featureState.alerts) return;
|
|
10825
10990
|
let n = `${this.alertText(t)}${t.message ? ` — ${t.message}` : ""}`;
|
|
@@ -10898,11 +11063,11 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10898
11063
|
onAction: (e) => this.handleAction(e),
|
|
10899
11064
|
onClose: () => {}
|
|
10900
11065
|
}, this.overlayHost, this.t, {
|
|
10901
|
-
list: () =>
|
|
10902
|
-
add: (e) =>
|
|
11066
|
+
list: () => zl(),
|
|
11067
|
+
add: (e) => Bl([e, ...zl().filter((t) => t !== e)])
|
|
10903
11068
|
}), this.boundGlobalKeydown = (e) => {
|
|
10904
11069
|
if (this.featureState.hotkeys && this.replayBar?.isMounted() && this.handleReplayKey(e) || this.handleHostHotkey(e)) return;
|
|
10905
|
-
let t =
|
|
11070
|
+
let t = Ws(this.root), n = (e) => this.featureState.hotkeys && this.featureState[e];
|
|
10906
11071
|
if ((e.ctrlKey || e.metaKey) && e.key === "k") {
|
|
10907
11072
|
if (!t || !n("hotkeys.commandPalette") || !this.featureState.commandPalette) return;
|
|
10908
11073
|
e.preventDefault(), this.toggleCommandPalette();
|
|
@@ -10910,21 +11075,21 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10910
11075
|
if (!t || !n("hotkeys.symbolSearch") || !this.featureState.symbolSearch) return;
|
|
10911
11076
|
e.preventDefault(), this.openSymbolSearch();
|
|
10912
11077
|
} else if ((e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey && (e.key === "s" || e.key === "S")) {
|
|
10913
|
-
if (!this.layoutSession || !n("hotkeys.save") || !this.featureState.layouts || X() || !
|
|
11078
|
+
if (!this.layoutSession || !n("hotkeys.save") || !this.featureState.layouts || X() || !Ws(this.root, !0)) return;
|
|
10914
11079
|
e.preventDefault(), this.saveLayout();
|
|
10915
11080
|
} else if (e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey && Di[e.code]) {
|
|
10916
|
-
if (e.defaultPrevented || X() || !t ||
|
|
11081
|
+
if (e.defaultPrevented || X() || !t || kl() || !n("hotkeys.tools")) return;
|
|
10917
11082
|
e.preventDefault(), this.handleDrawingTool(Di[e.code]);
|
|
10918
11083
|
} else if (/^[0-9]$/.test(e.key) && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
10919
|
-
if (e.defaultPrevented || !this.intervalInput || !n("intervalTyping") || X() ||
|
|
11084
|
+
if (e.defaultPrevented || !this.intervalInput || !n("intervalTyping") || X() || kl() || !Ws(this.root, !0)) return;
|
|
10920
11085
|
let t = document.activeElement;
|
|
10921
11086
|
if (t && t !== document.body && !this.root.contains(t)) return;
|
|
10922
11087
|
e.preventDefault(), this.intervalInput.open(e.key);
|
|
10923
|
-
} else if (
|
|
10924
|
-
if (e.defaultPrevented || !n("symbolTyping") || !this.featureState.symbolSearch || X() ||
|
|
11088
|
+
} else if (Sl(e) !== null) {
|
|
11089
|
+
if (e.defaultPrevented || !n("symbolTyping") || !this.featureState.symbolSearch || X() || kl() || !Ws(this.root, !0)) return;
|
|
10925
11090
|
let t = document.activeElement;
|
|
10926
11091
|
if (t && t !== document.body && !this.root.contains(t)) return;
|
|
10927
|
-
e.preventDefault(), this.openSymbolSearch(
|
|
11092
|
+
e.preventDefault(), this.openSymbolSearch(Sl(e));
|
|
10928
11093
|
} else if (e.altKey && !e.ctrlKey && !e.metaKey && (e.code === "KeyI" || e.code === "KeyG" || e.code === "KeyR")) {
|
|
10929
11094
|
if (X() || !t) return;
|
|
10930
11095
|
if (e.code === "KeyI") {
|
|
@@ -10938,10 +11103,10 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10938
11103
|
if (X() || !t || !n("hotkeys.help") || !this.featureState.hotkeySheet) return;
|
|
10939
11104
|
e.preventDefault(), this.openHotkeySheet();
|
|
10940
11105
|
}
|
|
10941
|
-
}, document.addEventListener("keydown", this.boundGlobalKeydown), document.addEventListener("fullscreenchange", this.onFullscreenChange), this.unregisterKeys =
|
|
11106
|
+
}, document.addEventListener("keydown", this.boundGlobalKeydown), document.addEventListener("fullscreenchange", this.onFullscreenChange), this.unregisterKeys = Us(this.root, [this.portal]), t.adapter ? (this.adapter = t.adapter, this.connectStream()) : this.chart.setDataTimeframe(this.state.timeframe), this.watchlist && (this.watchlistInterval = setInterval(() => this.tickWatchlist(), 1e3)), this.markSwitchedOff(), requestAnimationFrame(() => {
|
|
10942
11107
|
this.destroyed || (this.toolbar?.tidy(), this.sidebar?.tidy());
|
|
10943
11108
|
}), this.refreshMarket(), this.updateUI(), t.onReady?.(this.chart), t.shareUrl && typeof location < "u") {
|
|
10944
|
-
let e =
|
|
11109
|
+
let e = Xc(location.hash);
|
|
10945
11110
|
e && this.importState(e);
|
|
10946
11111
|
}
|
|
10947
11112
|
}
|
|
@@ -10980,7 +11145,10 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10980
11145
|
return t ? { ...t } : null;
|
|
10981
11146
|
}
|
|
10982
11147
|
openPanel(e) {
|
|
10983
|
-
return !
|
|
11148
|
+
return !this.hasPanel(e) || !this.dock ? !1 : (this.dock.open(e), this.dock.current() === e);
|
|
11149
|
+
}
|
|
11150
|
+
hasPanel(e) {
|
|
11151
|
+
return e === "watchlist" ? this.watchlist !== null : e === "depthLadder" && this.depthLadder === null ? !1 : this.featureState[yl[e]];
|
|
10984
11152
|
}
|
|
10985
11153
|
closePanel() {
|
|
10986
11154
|
this.dock?.close();
|
|
@@ -10995,7 +11163,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10995
11163
|
n && !this.featureState.symbolInfo || (n ? this.dock?.open("symbolInfo") : this.dock?.closePage("symbolInfo"));
|
|
10996
11164
|
}
|
|
10997
11165
|
refreshMarket() {
|
|
10998
|
-
if (
|
|
11166
|
+
if (Nl()) return;
|
|
10999
11167
|
let e = de(this.chart.getSymbolInfo(), Date.now());
|
|
11000
11168
|
this.statusBar?.setMarket(e.state, this.t(e.state === "open" ? "symbolInfo.open" : "symbolInfo.closed")), this.refreshSymbolInfo();
|
|
11001
11169
|
}
|
|
@@ -11030,7 +11198,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11030
11198
|
return this.options.locale || "en";
|
|
11031
11199
|
}
|
|
11032
11200
|
createWatchlist(e, t) {
|
|
11033
|
-
let n = t.persist ?
|
|
11201
|
+
let n = t.persist ? Wl() : null, r = new gi({
|
|
11034
11202
|
lists: t.lists,
|
|
11035
11203
|
activeList: t.activeList,
|
|
11036
11204
|
symbols: this.symbols,
|
|
@@ -11118,7 +11286,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11118
11286
|
t.refPrice !== void 0 && this.hostWatchlistRefPrice.set(e, t.refPrice), this.watchlist?.setEntry(e, t);
|
|
11119
11287
|
}
|
|
11120
11288
|
tickWatchlist() {
|
|
11121
|
-
if (!this.watchlist || this.quotes.has(this.state.symbol) ||
|
|
11289
|
+
if (!this.watchlist || this.quotes.has(this.state.symbol) || Nl()) return;
|
|
11122
11290
|
let e = this.chart.getData();
|
|
11123
11291
|
if (e.length === 0) return;
|
|
11124
11292
|
let t = e[e.length - 1], n = this.hostWatchlistRefPrice.get(this.state.symbol);
|
|
@@ -11229,7 +11397,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11229
11397
|
for (; o > 0 && n[o - 1].time * r >= a;) o--;
|
|
11230
11398
|
let s = this.displayTimezone();
|
|
11231
11399
|
return Vn({
|
|
11232
|
-
dayShare: n.slice(-
|
|
11400
|
+
dayShare: n.slice(-Pl).some((e) => {
|
|
11233
11401
|
let t = e.time * r, n = new Date(t + fe(s, t) * 6e4).getUTCDay();
|
|
11234
11402
|
return n === 0 || n === 6;
|
|
11235
11403
|
}) ? 1 : 5 / 7,
|
|
@@ -11287,7 +11455,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11287
11455
|
e.hide();
|
|
11288
11456
|
return;
|
|
11289
11457
|
}
|
|
11290
|
-
let i = this.chartOffset(), a = this.chart.getPlotRect(), o =
|
|
11458
|
+
let i = this.chartOffset(), a = this.chart.getPlotRect(), o = Gl(r.map((e) => this.chart.getDrawingRect(e.id))) ?? {
|
|
11291
11459
|
x: a.x + a.width / 2,
|
|
11292
11460
|
y: a.y,
|
|
11293
11461
|
width: 0,
|
|
@@ -11329,7 +11497,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11329
11497
|
});
|
|
11330
11498
|
}
|
|
11331
11499
|
promptSaveDrawingTemplate(e, t) {
|
|
11332
|
-
this.drawingTemplatePrompt ??= new
|
|
11500
|
+
this.drawingTemplatePrompt ??= new Ms(this.root, this.t), this.drawingTemplatePrompt.open({
|
|
11333
11501
|
title: this.t("drawingSettings.saveTemplateTitle"),
|
|
11334
11502
|
submitLabel: this.t("common.save"),
|
|
11335
11503
|
placeholder: this.drawingToolName(t.type),
|
|
@@ -11365,11 +11533,11 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11365
11533
|
id: e,
|
|
11366
11534
|
type: s.type,
|
|
11367
11535
|
selected: o
|
|
11368
|
-
}) ?? [] : [], l =
|
|
11536
|
+
}) ?? [] : [], l = rl(a, c);
|
|
11369
11537
|
if (l.length === 0) return;
|
|
11370
11538
|
let u = this.chartContainer.getBoundingClientRect(), d = this.root.getBoundingClientRect();
|
|
11371
11539
|
this.drawingMenu.open(l, u.left - d.left + t, u.top - d.top + n, (t) => {
|
|
11372
|
-
|
|
11540
|
+
il(t, c) || this.runDrawingMenuAction(e, o, t);
|
|
11373
11541
|
});
|
|
11374
11542
|
}
|
|
11375
11543
|
runDrawingMenuAction(e, t, n) {
|
|
@@ -11451,23 +11619,26 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11451
11619
|
removableIndicators() {
|
|
11452
11620
|
return this.chart.getActiveIndicators().filter((e) => !Ie.has(e.id)).map((e) => e.instanceId);
|
|
11453
11621
|
}
|
|
11454
|
-
|
|
11455
|
-
let e = this.
|
|
11622
|
+
exchangeChoice() {
|
|
11623
|
+
let e = this.chart.getExchangeTimezone() ?? null;
|
|
11624
|
+
if (!(e === null && !this.adapter?.resolveSymbol)) return {
|
|
11456
11625
|
label: this.t("settings.timezone.exchange"),
|
|
11457
|
-
zone:
|
|
11458
|
-
}
|
|
11459
|
-
|
|
11626
|
+
zone: e
|
|
11627
|
+
};
|
|
11628
|
+
}
|
|
11629
|
+
timezoneChoices() {
|
|
11630
|
+
return Ze(this.settingsState.timezone, Date.now(), this.t("settings.timezone.local"), this.exchangeChoice()).map(({ value: e, label: t }) => ({
|
|
11460
11631
|
value: e,
|
|
11461
11632
|
label: t
|
|
11462
11633
|
}));
|
|
11463
11634
|
}
|
|
11464
11635
|
openChartMenu(e, t, n, r) {
|
|
11465
11636
|
if (!this.chartMenu) return;
|
|
11466
|
-
let i = this.options.chartMenuItems?.(r) ?? [], a =
|
|
11637
|
+
let i = this.options.chartMenuItems?.(r) ?? [], a = rl(e, i);
|
|
11467
11638
|
if (a.length === 0) return;
|
|
11468
11639
|
let o = this.chartContainer.getBoundingClientRect(), s = this.root.getBoundingClientRect();
|
|
11469
11640
|
this.chartMenu.open(a, o.left - s.left + t, o.top - s.top + n, (e) => {
|
|
11470
|
-
|
|
11641
|
+
il(e, i) || (e.startsWith("tz:") ? this.changeSettings({ timezone: e.slice(3) }) : this.runChartMenuAction(e, r));
|
|
11471
11642
|
});
|
|
11472
11643
|
}
|
|
11473
11644
|
setFeatures(e) {
|
|
@@ -11499,7 +11670,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11499
11670
|
["dataWindow", () => this.dock?.closePage("dataWindow")],
|
|
11500
11671
|
["accountPanel", () => this.toggleAccountPanel(!1)],
|
|
11501
11672
|
["orderTicket", () => this.orderTicket?.close()],
|
|
11502
|
-
["depthLadder", () => this.
|
|
11673
|
+
["depthLadder", () => this.dock?.closePage("depthLadder")],
|
|
11503
11674
|
["goToDate", () => this.goToDate?.close()],
|
|
11504
11675
|
["settings", () => this.settings?.close()],
|
|
11505
11676
|
["indicatorSettings", () => this.indicatorSettings?.close()],
|
|
@@ -11521,9 +11692,9 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11521
11692
|
for (let [n, r] of t) e(n) && r();
|
|
11522
11693
|
}
|
|
11523
11694
|
addHotkey(e) {
|
|
11524
|
-
let t =
|
|
11695
|
+
let t = cl(e.keys);
|
|
11525
11696
|
if (!t) return console.warn(`[ChartWidget] Can't read the shortcut "${e.keys}": modifiers (Ctrl, Alt, Shift) and a key, joined by +.`), null;
|
|
11526
|
-
|
|
11697
|
+
dl(t) && console.warn(`[ChartWidget] The chart answers ${e.keys} itself (drawings, scrolling or zoom): both will run.`);
|
|
11527
11698
|
let n = {
|
|
11528
11699
|
spec: e,
|
|
11529
11700
|
parsed: t
|
|
@@ -11533,17 +11704,17 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11533
11704
|
} };
|
|
11534
11705
|
}
|
|
11535
11706
|
handleHostHotkey(e) {
|
|
11536
|
-
if (this.hostHotkeys.length === 0 || !this.featureState.hotkeys || e.isComposing || e.keyCode ===
|
|
11537
|
-
let t = this.hostHotkeys.find((t) =>
|
|
11707
|
+
if (this.hostHotkeys.length === 0 || !this.featureState.hotkeys || e.isComposing || e.keyCode === Al || e.getModifierState?.("AltGraph") || e.defaultPrevented || X() || fl(e) || kl()) return !1;
|
|
11708
|
+
let t = this.hostHotkeys.find((t) => ll(e, t.parsed));
|
|
11538
11709
|
if (!t) return !1;
|
|
11539
11710
|
let n = !t.parsed.ctrl && !t.parsed.alt;
|
|
11540
|
-
if (!
|
|
11711
|
+
if (!Ws(this.root, n)) return !1;
|
|
11541
11712
|
let r = document.activeElement;
|
|
11542
11713
|
return n && r && r !== document.body && !this.root.contains(r) ? !1 : (e.preventDefault(), t.spec.onPress(e), !0);
|
|
11543
11714
|
}
|
|
11544
11715
|
keepingLook(e) {
|
|
11545
11716
|
this.settingsEdit && this.settings?.close();
|
|
11546
|
-
let t = this.chart.getOverrides?.({ layer: "user" }) ?? {}, n = Object.fromEntries(
|
|
11717
|
+
let t = this.chart.getOverrides?.({ layer: "user" }) ?? {}, n = Object.fromEntries(Ml.filter((e) => t[e] !== void 0).map((e) => [e, t[e]]));
|
|
11547
11718
|
e(), Object.keys(n).length > 0 && this.chart.applyOverrides(n, { layer: "user" });
|
|
11548
11719
|
}
|
|
11549
11720
|
sheetKeyOn(e) {
|
|
@@ -11596,7 +11767,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11596
11767
|
let r = e.items();
|
|
11597
11768
|
if (r.length === 0) return;
|
|
11598
11769
|
let i = t.getBoundingClientRect(), a = this.root.getBoundingClientRect();
|
|
11599
|
-
n.open(
|
|
11770
|
+
n.open(rl([], r), i.left - a.left, i.bottom - a.top + 2, (e) => il(e, r), t);
|
|
11600
11771
|
}
|
|
11601
11772
|
});
|
|
11602
11773
|
return r.setAttribute("aria-haspopup", "menu"), r.setAttribute("aria-expanded", "false"), t.tidy(), {
|
|
@@ -11835,7 +12006,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11835
12006
|
from: r(a.from),
|
|
11836
12007
|
to: r(a.to)
|
|
11837
12008
|
},
|
|
11838
|
-
withTime: !(S(this.state.timeframe) >=
|
|
12009
|
+
withTime: !(S(this.state.timeframe) >= vl),
|
|
11839
12010
|
max: o,
|
|
11840
12011
|
today: o
|
|
11841
12012
|
});
|
|
@@ -11845,12 +12016,12 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11845
12016
|
if (t.length === 0) return;
|
|
11846
12017
|
let r = ae(t);
|
|
11847
12018
|
if (e.kind === "date") {
|
|
11848
|
-
let i =
|
|
12019
|
+
let i = nc(e.date, e.time, n);
|
|
11849
12020
|
if (i === null) return;
|
|
11850
12021
|
this.chart.goToTime(i / r), i / r < t[0].time && this.say(this.t("range.beforeData"));
|
|
11851
12022
|
return;
|
|
11852
12023
|
}
|
|
11853
|
-
let i =
|
|
12024
|
+
let i = nc(e.from.date, e.from.time, n), a = nc(e.to.date, e.to.time, n);
|
|
11854
12025
|
i === null || a === null || (this.chart.setVisibleRange(i / r, a / r), Math.min(i, a) / r < t[0].time && this.say(this.t("range.beforeData")));
|
|
11855
12026
|
}
|
|
11856
12027
|
pinnedTimeframes() {
|
|
@@ -11899,7 +12070,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11899
12070
|
this.say(this.t("templates.nothing"), "error");
|
|
11900
12071
|
return;
|
|
11901
12072
|
}
|
|
11902
|
-
this.templatePrompt ??= new
|
|
12073
|
+
this.templatePrompt ??= new Ms(this.root, this.t), this.templatePrompt.open({
|
|
11903
12074
|
title: this.t("templates.saveTitle"),
|
|
11904
12075
|
submitLabel: this.t("common.save"),
|
|
11905
12076
|
placeholder: this.t("templates.namePlaceholder"),
|
|
@@ -11925,9 +12096,9 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11925
12096
|
}
|
|
11926
12097
|
async switchLocalTimeframe() {
|
|
11927
12098
|
if (!this.baseSeries) return;
|
|
11928
|
-
let e = ++this.localSeq, t = this.lastLocalSwitchMs >=
|
|
12099
|
+
let e = ++this.localSeq, t = this.lastLocalSwitchMs >= pl || this.baseSeries.length >= ml;
|
|
11929
12100
|
try {
|
|
11930
|
-
if (t && (this.loading.begin(this.chart.getData().length > 0, !0), await
|
|
12101
|
+
if (t && (this.loading.begin(this.chart.getData().length > 0, !0), await gl(), e !== this.localSeq || this.destroyed)) return;
|
|
11931
12102
|
this.applyTimeframeData();
|
|
11932
12103
|
} finally {
|
|
11933
12104
|
e === this.localSeq && this.loading.end();
|
|
@@ -11943,17 +12114,15 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11943
12114
|
this.lastLocalSwitchMs = performance.now() - e;
|
|
11944
12115
|
}
|
|
11945
12116
|
handleDataUpdate(e) {
|
|
11946
|
-
if (
|
|
11947
|
-
|
|
11948
|
-
if (typeof t.length == "number") {
|
|
11949
|
-
t.length > 0 && this.loading.isActive() && (this.loading.end(), this.state.connectionState === "error" && this.setConnectionState("connected", this.t("status.live")));
|
|
12117
|
+
if (e.kind === "bars") {
|
|
12118
|
+
e.length > 0 && this.loading.isActive() && (this.loading.end(), this.state.connectionState === "error" && this.setConnectionState("connected", this.t("status.live")));
|
|
11950
12119
|
return;
|
|
11951
12120
|
}
|
|
11952
|
-
if (
|
|
11953
|
-
this.loading.isActive() && (this.loading.fail(this.t("status.connectionFailed")), this.setConnectionState("error",
|
|
12121
|
+
if (e.kind === "error") {
|
|
12122
|
+
this.loading.isActive() && (this.loading.fail(this.t("status.connectionFailed")), this.setConnectionState("error", e.error || this.t("status.connectionFailed")));
|
|
11954
12123
|
return;
|
|
11955
12124
|
}
|
|
11956
|
-
switch (
|
|
12125
|
+
if (e.kind === "connection") switch (e.connection.state) {
|
|
11957
12126
|
case "connected":
|
|
11958
12127
|
this.loading.hasFailed() && this.loading.end(), !this.loading.isActive() && this.state.connectionState !== "connected" && this.setConnectionState("connected", this.t("status.live"));
|
|
11959
12128
|
break;
|
|
@@ -11972,6 +12141,9 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11972
12141
|
connectionMessage: t
|
|
11973
12142
|
}, this.updateUI();
|
|
11974
12143
|
}
|
|
12144
|
+
toggleLadder() {
|
|
12145
|
+
!this.depthLadder || !this.featureState.depthLadder || this.dock?.toggle("depthLadder");
|
|
12146
|
+
}
|
|
11975
12147
|
toggleAlerts() {
|
|
11976
12148
|
!this.alertsPanel || !this.featureState.alerts || this.dock?.toggle("alerts");
|
|
11977
12149
|
}
|
|
@@ -11984,7 +12156,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11984
12156
|
id: e.id,
|
|
11985
12157
|
params: e.params
|
|
11986
12158
|
}));
|
|
11987
|
-
return
|
|
12159
|
+
return qc({
|
|
11988
12160
|
v: 1,
|
|
11989
12161
|
symbol: this.state.symbol,
|
|
11990
12162
|
timeframe: this.state.timeframe,
|
|
@@ -11995,7 +12167,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11995
12167
|
});
|
|
11996
12168
|
}
|
|
11997
12169
|
async importState(e) {
|
|
11998
|
-
let t =
|
|
12170
|
+
let t = Jc(e);
|
|
11999
12171
|
return t ? (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.applyChartType(t.chartType), this.chart.setScaleMode(t.scaleMode), this.chart.applyIndicatorSetup(t.indicators.map((e, t) => ({
|
|
12000
12172
|
id: e.id,
|
|
12001
12173
|
instanceId: `shared_${t}`,
|
|
@@ -12007,7 +12179,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12007
12179
|
this.say(e ? this.t("toast.imageCopied") : this.t("toast.imageCopyFailed"), e ? "info" : "error");
|
|
12008
12180
|
}
|
|
12009
12181
|
async copyShareLink() {
|
|
12010
|
-
let e =
|
|
12182
|
+
let e = Zc(typeof location < "u" ? location.href : "", this.exportState());
|
|
12011
12183
|
try {
|
|
12012
12184
|
await navigator.clipboard.writeText(e), this.say(this.t("toast.linkCopied"));
|
|
12013
12185
|
} catch {
|
|
@@ -12120,6 +12292,16 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12120
12292
|
parts: ["dock.symbolInfo", "symbolInfo"],
|
|
12121
12293
|
onShow: () => i.open(),
|
|
12122
12294
|
onHide: () => i.close()
|
|
12295
|
+
});
|
|
12296
|
+
let a = this.depthLadder;
|
|
12297
|
+
a && e.addPage({
|
|
12298
|
+
id: "depthLadder",
|
|
12299
|
+
label: this.t("ladder.title"),
|
|
12300
|
+
icon: "ladder",
|
|
12301
|
+
element: a.element,
|
|
12302
|
+
parts: ["dock.depthLadder", "depthLadder"],
|
|
12303
|
+
onShow: () => a.openPanel(),
|
|
12304
|
+
onHide: () => a.close()
|
|
12123
12305
|
}), this.syncRail(), this.fitDockToWidth(), typeof ResizeObserver < "u" && (this.dockObserver = new ResizeObserver(() => this.fitDockToWidth()), this.dockObserver.observe(this.root));
|
|
12124
12306
|
}
|
|
12125
12307
|
fitDockToWidth() {
|
|
@@ -12137,7 +12319,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12137
12319
|
this.toolbar?.setRailed("alerts", e && this.featureState["dock.alerts"]), this.toolbar?.setRailed("objects", e && this.featureState["dock.objectTree"]), this.toolbar?.fit();
|
|
12138
12320
|
}
|
|
12139
12321
|
panelFocusTarget(e) {
|
|
12140
|
-
let t =
|
|
12322
|
+
let t = xl[e], n = t ? this.root.querySelector(`.tcw-toolbar [data-role="${t}"]`) : null, r = this.root.hasAttribute("data-tcw-narrow");
|
|
12141
12323
|
return n && !n.hidden && !(r && n.classList.contains("tcw-toolbar-overflow")) ? n : this.root.querySelector(".tcw-toolbar-more") ?? this.chartContainer;
|
|
12142
12324
|
}
|
|
12143
12325
|
closePanelByHand(e) {
|
|
@@ -12155,7 +12337,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12155
12337
|
defaults: n.descriptor.defaultConfig,
|
|
12156
12338
|
params: n.params,
|
|
12157
12339
|
inputs: n.descriptor.inputs,
|
|
12158
|
-
lineSources:
|
|
12340
|
+
lineSources: Il(e, t),
|
|
12159
12341
|
plots: n.descriptor.plots,
|
|
12160
12342
|
colors: r?.colors,
|
|
12161
12343
|
lineWidth: r?.lineWidths[0],
|
|
@@ -12197,11 +12379,11 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12197
12379
|
symbols: this.symbols,
|
|
12198
12380
|
current: this.state.symbol,
|
|
12199
12381
|
search: this.symbolSearchFn(),
|
|
12200
|
-
ways:
|
|
12382
|
+
ways: dc(this.t),
|
|
12201
12383
|
way: this.compareWay,
|
|
12202
12384
|
compared: this.comparedNow(),
|
|
12203
12385
|
onAdd: (e, t) => {
|
|
12204
|
-
|
|
12386
|
+
uc(t) && (this.compareWay = t, this.addCompareSymbol(e, t));
|
|
12205
12387
|
},
|
|
12206
12388
|
onRemove: (e) => {
|
|
12207
12389
|
this.compares.some((t) => t.id === e) ? this.handleRemoveCompare(e) : this.chart.removeIndicator(e);
|
|
@@ -12211,7 +12393,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12211
12393
|
}
|
|
12212
12394
|
comparedNow() {
|
|
12213
12395
|
let e = new Set(this.chart.getIndicatorPanes().flatMap((e) => e.instanceIds));
|
|
12214
|
-
return
|
|
12396
|
+
return pc(this.compares, this.chart.getActiveIndicators(), e, this.t);
|
|
12215
12397
|
}
|
|
12216
12398
|
refreshCompareDialog() {
|
|
12217
12399
|
this.symbolSearch?.isComparing() && this.symbolSearch.setCompared(this.comparedNow());
|
|
@@ -12235,7 +12417,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12235
12417
|
try {
|
|
12236
12418
|
let t = await Ge(this.adapter).fetchHistory(e, this.state.timeframe, this.options.historyLimit ?? 500);
|
|
12237
12419
|
if (this.destroyed || this.compares.some((t) => t.symbol === e)) return;
|
|
12238
|
-
let r =
|
|
12420
|
+
let r = _l[this.compares.length % _l.length];
|
|
12239
12421
|
this.compares.length === 0 && this.chart.setCompareMode("percent"), this.chart.addCompareSymbol(n, e, t, r), this.compares = [...this.compares, {
|
|
12240
12422
|
id: n,
|
|
12241
12423
|
symbol: e,
|
|
@@ -12330,7 +12512,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12330
12512
|
return typeof a == "number" && Number.isFinite(a) ? a : null;
|
|
12331
12513
|
}
|
|
12332
12514
|
formatMoney(e) {
|
|
12333
|
-
return this.formatNumber(e, Math.min(Se(this.chart.getPriceStep()),
|
|
12515
|
+
return this.formatNumber(e, Math.min(Se(this.chart.getPriceStep()), bl));
|
|
12334
12516
|
}
|
|
12335
12517
|
formatNumber(e, t) {
|
|
12336
12518
|
let n = this.settingsState.numberLocale || void 0;
|
|
@@ -12658,7 +12840,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12658
12840
|
t && (this.touchSettings(Object.keys(t.settings), O), this.applySettings(t.settings), this.chart.resetOverrides([...O], { layer: "user" }), this.chart.applyOverrides(t.style, { layer: "user" }), this.settings?.refresh(this.settingsState), this.say(p(this.t("templates.applied"), { name: e })));
|
|
12659
12841
|
}
|
|
12660
12842
|
promptSaveChartTemplate() {
|
|
12661
|
-
this.chartTemplatePrompt ??= new
|
|
12843
|
+
this.chartTemplatePrompt ??= new Ms(this.overlayHost(), this.t), this.chartTemplatePrompt.open({
|
|
12662
12844
|
title: this.t("settings.saveTemplateTitle"),
|
|
12663
12845
|
submitLabel: this.t("common.save"),
|
|
12664
12846
|
placeholder: this.t("settings.templatePlaceholder"),
|
|
@@ -12695,7 +12877,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12695
12877
|
return this.state.timeframe;
|
|
12696
12878
|
}
|
|
12697
12879
|
captureLayout() {
|
|
12698
|
-
let e = this.chart.saveState(), t = e ?
|
|
12880
|
+
let e = this.chart.saveState(), t = e ? Ys(e) : null, n = t && typeof t == "object" ? qs(t) : null;
|
|
12699
12881
|
return {
|
|
12700
12882
|
v: 1,
|
|
12701
12883
|
symbol: this.state.symbol,
|
|
@@ -12708,7 +12890,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12708
12890
|
async restoreLayout(e) {
|
|
12709
12891
|
if (e.symbol !== this.state.symbol && await this.setSymbol(e.symbol), e.timeframe !== this.state.timeframe && await this.setTimeframe(e.timeframe), !this.destroyed) {
|
|
12710
12892
|
if (e.chart) {
|
|
12711
|
-
this.chart.loadState(JSON.stringify(
|
|
12893
|
+
this.chart.loadState(JSON.stringify(qs(e.chart)));
|
|
12712
12894
|
let t = e.chart.chartType;
|
|
12713
12895
|
typeof t == "string" && (this.state = {
|
|
12714
12896
|
...this.state,
|
|
@@ -12725,7 +12907,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12725
12907
|
return JSON.stringify(this.captureLayout());
|
|
12726
12908
|
}
|
|
12727
12909
|
async applyLayoutContent(e) {
|
|
12728
|
-
let t =
|
|
12910
|
+
let t = Js(Ys(e));
|
|
12729
12911
|
return t ? (await this.restoreLayout(t), !0) : !1;
|
|
12730
12912
|
}
|
|
12731
12913
|
setupLayouts(e) {
|
|
@@ -12744,7 +12926,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12744
12926
|
onChange: () => this.toolbar?.setLayout(t.current()?.name ?? null, t.isDirty()),
|
|
12745
12927
|
onError: () => this.say(this.t("layouts.saveFailed"), "error")
|
|
12746
12928
|
});
|
|
12747
|
-
this.layoutSession = t, this.layoutsUI = new
|
|
12929
|
+
this.layoutSession = t, this.layoutsUI = new Is(t, {
|
|
12748
12930
|
root: this.root,
|
|
12749
12931
|
t: this.t,
|
|
12750
12932
|
saveKeys: () => this.keysShown("hotkeys.save", `${kr}+S`),
|
|
@@ -12918,7 +13100,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12918
13100
|
}
|
|
12919
13101
|
replayStepOptions() {
|
|
12920
13102
|
let e = S(this.state.timeframe);
|
|
12921
|
-
return
|
|
13103
|
+
return Dl.filter((t) => {
|
|
12922
13104
|
let n = S(t);
|
|
12923
13105
|
return !(n < e) || e % n !== 0 ? !1 : this.adapter ? Ue(this.adapter, t) : this.baseSeries !== null && this.baseTimeframeMs > 0 && n >= this.baseTimeframeMs && n % this.baseTimeframeMs === 0;
|
|
12924
13106
|
});
|
|
@@ -12928,7 +13110,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12928
13110
|
if (this.replayStepsCache?.key === t) return this.replayStepsCache.steps;
|
|
12929
13111
|
let n = null;
|
|
12930
13112
|
if (this.adapter) {
|
|
12931
|
-
let t = Math.max(1, Math.round(S(this.state.timeframe) / S(e))), r = Math.min(
|
|
13113
|
+
let t = Math.max(1, Math.round(S(this.state.timeframe) / S(e))), r = Math.min(Ol, Math.max(this.chart.getData().length, 100) * t);
|
|
12932
13114
|
try {
|
|
12933
13115
|
n = await Ge(this.adapter).fetchHistory(this.state.symbol, e, r);
|
|
12934
13116
|
} catch {
|
|
@@ -13099,26 +13281,26 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
13099
13281
|
row: n
|
|
13100
13282
|
}));
|
|
13101
13283
|
let a = this.settingsState.numberLocale || "en-US", o = this.chart.getActiveIndicators().map((t) => {
|
|
13102
|
-
let n = i.get(t.instanceId) ?? null, o = r >= 0 ? this.chart.getIndicatorOutput(t.instanceId)?.series?.[r] : null, s = this.chart.getIndicatorStyle(t.instanceId), c = t.visible && t.shown === !1, l = c ? [] :
|
|
13284
|
+
let n = i.get(t.instanceId) ?? null, o = r >= 0 ? this.chart.getIndicatorOutput(t.instanceId)?.series?.[r] : null, s = this.chart.getIndicatorStyle(t.instanceId), c = t.visible && t.shown === !1, l = c ? [] : Oc(t.descriptor, o, s?.colors ?? [], s?.plots);
|
|
13103
13285
|
return {
|
|
13104
13286
|
instanceId: t.instanceId,
|
|
13105
13287
|
label: e(t.id, t.params, t.descriptor.defaultConfig, t.descriptor.shortName),
|
|
13106
13288
|
visible: t.visible,
|
|
13107
13289
|
offInterval: c,
|
|
13108
13290
|
values: l.map((e) => ({
|
|
13109
|
-
text: n ?
|
|
13291
|
+
text: n ? jc(e.value, a) : this.chart.formatPrice(e.value),
|
|
13110
13292
|
color: e.color
|
|
13111
13293
|
})),
|
|
13112
13294
|
pane: n ? {
|
|
13113
|
-
x: n.x +
|
|
13114
|
-
y: n.y + Math.min(
|
|
13115
|
-
width: n.width - 2 *
|
|
13295
|
+
x: n.x + Cl,
|
|
13296
|
+
y: n.y + Math.min(wl + n.row * Tl, Math.max(wl, n.height - Tl)),
|
|
13297
|
+
width: n.width - 2 * Cl
|
|
13116
13298
|
} : null
|
|
13117
13299
|
};
|
|
13118
13300
|
}), s = this.chart.getPlotRect(), c = this.chart.getMaximizedPane(), l = (e) => o.find((t) => t.instanceId === e)?.label ?? "", u = this.chart.getIndicatorPanes().map((e) => ({
|
|
13119
13301
|
instanceId: e.instanceId,
|
|
13120
|
-
x: e.rect.x + e.rect.width -
|
|
13121
|
-
y: e.rect.y +
|
|
13302
|
+
x: e.rect.x + e.rect.width - Cl,
|
|
13303
|
+
y: e.rect.y + El,
|
|
13122
13304
|
label: l(e.instanceId),
|
|
13123
13305
|
collapsed: this.chart.isPaneCollapsed(e.instanceId),
|
|
13124
13306
|
maximized: c === e.instanceId,
|
|
@@ -13126,7 +13308,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
13126
13308
|
canMoveDown: this.chart.canMovePane(e.instanceId, 1)
|
|
13127
13309
|
}));
|
|
13128
13310
|
this.indicatorLegend.update(o, {
|
|
13129
|
-
left: s.x +
|
|
13311
|
+
left: s.x + Cl,
|
|
13130
13312
|
top: this.chart.getLegendBottom() + 1
|
|
13131
13313
|
}, u);
|
|
13132
13314
|
}
|
|
@@ -13172,11 +13354,11 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
13172
13354
|
let u = this.chart.getActiveIndicators().find((t) => t.instanceId === e)?.id ?? "", d = this.options.indicatorMenuItems?.({
|
|
13173
13355
|
instanceId: e,
|
|
13174
13356
|
indicatorId: u
|
|
13175
|
-
}) ?? [], f =
|
|
13357
|
+
}) ?? [], f = rl(c, d);
|
|
13176
13358
|
if (f.length === 0) return;
|
|
13177
13359
|
let p = t.getBoundingClientRect(), m = this.root.getBoundingClientRect();
|
|
13178
13360
|
n.open(f, p.left - m.left, p.bottom - m.top + 2, (t) => {
|
|
13179
|
-
|
|
13361
|
+
il(t, d) || (t === "settings" ? this.openIndicatorSettings(e) : t === "remove" ? this.handleRemoveIndicator(e) : t.startsWith("move:") && this.chart.moveIndicatorToPane(e, t.slice(5)), this.scheduleLegend());
|
|
13180
13362
|
}, t);
|
|
13181
13363
|
}
|
|
13182
13364
|
updateUI() {
|
|
@@ -13201,7 +13383,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
13201
13383
|
return !0;
|
|
13202
13384
|
}
|
|
13203
13385
|
};
|
|
13204
|
-
function
|
|
13386
|
+
function Il(t, n) {
|
|
13205
13387
|
let r = (e) => {
|
|
13206
13388
|
let t = We(e.descriptor);
|
|
13207
13389
|
return t && pe(e.params[t])?.instanceId || null;
|
|
@@ -13224,42 +13406,42 @@ function kl(t, n) {
|
|
|
13224
13406
|
}
|
|
13225
13407
|
return a;
|
|
13226
13408
|
}
|
|
13227
|
-
var
|
|
13228
|
-
function
|
|
13409
|
+
var Ll = "tcw:recentCommands", Rl = 10;
|
|
13410
|
+
function zl() {
|
|
13229
13411
|
try {
|
|
13230
|
-
let e = JSON.parse(
|
|
13231
|
-
return Array.isArray(e) ? e.filter((e) => typeof e == "string").slice(0,
|
|
13412
|
+
let e = JSON.parse(Wl()?.getItem(Ll) ?? "[]");
|
|
13413
|
+
return Array.isArray(e) ? e.filter((e) => typeof e == "string").slice(0, Rl) : [];
|
|
13232
13414
|
} catch {
|
|
13233
13415
|
return [];
|
|
13234
13416
|
}
|
|
13235
13417
|
}
|
|
13236
|
-
function
|
|
13418
|
+
function Bl(e) {
|
|
13237
13419
|
try {
|
|
13238
|
-
|
|
13420
|
+
Wl()?.setItem(Ll, JSON.stringify(e.slice(0, Rl)));
|
|
13239
13421
|
} catch {}
|
|
13240
13422
|
}
|
|
13241
|
-
var
|
|
13242
|
-
function
|
|
13423
|
+
var Vl = "tcw:dockWidth";
|
|
13424
|
+
function Hl() {
|
|
13243
13425
|
try {
|
|
13244
|
-
let e = Number(
|
|
13426
|
+
let e = Number(Wl()?.getItem(Vl) ?? NaN);
|
|
13245
13427
|
return Number.isFinite(e) && e > 0 ? e : null;
|
|
13246
13428
|
} catch {
|
|
13247
13429
|
return null;
|
|
13248
13430
|
}
|
|
13249
13431
|
}
|
|
13250
|
-
function
|
|
13432
|
+
function Ul(e) {
|
|
13251
13433
|
try {
|
|
13252
|
-
|
|
13434
|
+
Wl()?.setItem(Vl, String(e));
|
|
13253
13435
|
} catch {}
|
|
13254
13436
|
}
|
|
13255
|
-
function
|
|
13437
|
+
function Wl() {
|
|
13256
13438
|
try {
|
|
13257
13439
|
return typeof localStorage < "u" ? localStorage : null;
|
|
13258
13440
|
} catch {
|
|
13259
13441
|
return null;
|
|
13260
13442
|
}
|
|
13261
13443
|
}
|
|
13262
|
-
function
|
|
13444
|
+
function Gl(e) {
|
|
13263
13445
|
let t = e.filter((e) => e !== null);
|
|
13264
13446
|
if (t.length === 0) return null;
|
|
13265
13447
|
let n = Math.min(...t.map((e) => e.x)), r = Math.min(...t.map((e) => e.y)), i = Math.max(...t.map((e) => e.x + e.width)), a = Math.max(...t.map((e) => e.y + e.height));
|
|
@@ -13270,26 +13452,26 @@ function Rl(e) {
|
|
|
13270
13452
|
height: a - r
|
|
13271
13453
|
};
|
|
13272
13454
|
}
|
|
13273
|
-
function
|
|
13455
|
+
function Kl(e) {
|
|
13274
13456
|
return !!e && /^(ar|he|iw|fa|ur|ps|yi|dv|ckb|sd|ug)(-|$)/i.test(e);
|
|
13275
13457
|
}
|
|
13276
13458
|
//#endregion
|
|
13277
13459
|
//#region src/widget/ChartWidgetGrid.ts
|
|
13278
|
-
var
|
|
13460
|
+
var ql = {
|
|
13279
13461
|
symbol: !1,
|
|
13280
13462
|
interval: !1,
|
|
13281
13463
|
crosshair: !0,
|
|
13282
13464
|
time: !1,
|
|
13283
13465
|
drawings: !1,
|
|
13284
13466
|
replay: !1
|
|
13285
|
-
},
|
|
13467
|
+
}, Jl = [
|
|
13286
13468
|
"symbol",
|
|
13287
13469
|
"interval",
|
|
13288
13470
|
"crosshair",
|
|
13289
13471
|
"time",
|
|
13290
13472
|
"drawings",
|
|
13291
13473
|
"replay"
|
|
13292
|
-
],
|
|
13474
|
+
], Yl = {
|
|
13293
13475
|
"1x1": {
|
|
13294
13476
|
cols: 1,
|
|
13295
13477
|
rows: 1
|
|
@@ -13323,25 +13505,25 @@ var Bl = {
|
|
|
13323
13505
|
rows: 3
|
|
13324
13506
|
}
|
|
13325
13507
|
};
|
|
13326
|
-
function
|
|
13327
|
-
return typeof e == "string" && Object.prototype.hasOwnProperty.call(
|
|
13508
|
+
function Xl(e) {
|
|
13509
|
+
return typeof e == "string" && Object.prototype.hasOwnProperty.call(Yl, e);
|
|
13328
13510
|
}
|
|
13329
|
-
function
|
|
13511
|
+
function Zl(e) {
|
|
13330
13512
|
return JSON.parse(JSON.stringify(e));
|
|
13331
13513
|
}
|
|
13332
|
-
function
|
|
13514
|
+
function Ql(e, t, n = 16) {
|
|
13333
13515
|
let r = (20 - 2 * (e - 1)) / e, i = (20 - 2 * (t - 1)) / t, a = "";
|
|
13334
13516
|
for (let n = 0; n < t; n++) for (let t = 0; t < e; t++) a += `<rect x="${2 + t * (r + 2)}" y="${2 + n * (i + 2)}" width="${r}" height="${i}" rx="1"/>`;
|
|
13335
13517
|
return `<svg width="${n}" height="${n}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true">${a}</svg>`;
|
|
13336
13518
|
}
|
|
13337
|
-
function
|
|
13519
|
+
function $l(e) {
|
|
13338
13520
|
if (typeof e != "object" || !e) return null;
|
|
13339
13521
|
let t = e;
|
|
13340
|
-
if (t.v !== 1 || t.kind !== "grid" || !
|
|
13341
|
-
let n = t.cells.map(
|
|
13522
|
+
if (t.v !== 1 || t.kind !== "grid" || !Xl(t.layout) || !Array.isArray(t.cells)) return null;
|
|
13523
|
+
let n = t.cells.map(Js);
|
|
13342
13524
|
if (n.some((e) => e === null)) return null;
|
|
13343
|
-
let r = typeof t.sync == "object" && t.sync !== null ? t.sync : {}, i = { ...
|
|
13344
|
-
for (let e of
|
|
13525
|
+
let r = typeof t.sync == "object" && t.sync !== null ? t.sync : {}, i = { ...ql };
|
|
13526
|
+
for (let e of Jl) typeof r[e] == "boolean" && (i[e] = r[e]);
|
|
13345
13527
|
let a = typeof t.active == "number" && Number.isInteger(t.active) ? t.active : 0;
|
|
13346
13528
|
return {
|
|
13347
13529
|
v: 1,
|
|
@@ -13352,7 +13534,7 @@ function Kl(e) {
|
|
|
13352
13534
|
cells: n
|
|
13353
13535
|
};
|
|
13354
13536
|
}
|
|
13355
|
-
var
|
|
13537
|
+
var eu = class {
|
|
13356
13538
|
root;
|
|
13357
13539
|
cellsEl;
|
|
13358
13540
|
cells = [];
|
|
@@ -13378,17 +13560,17 @@ var ql = class {
|
|
|
13378
13560
|
destroyed = !1;
|
|
13379
13561
|
unregisterKeys = () => {};
|
|
13380
13562
|
onKeyDown = (e) => {
|
|
13381
|
-
!(e.ctrlKey || e.metaKey) || e.altKey || e.shiftKey || e.key !== "s" && e.key !== "S" || !this.layoutsUI || X() || !
|
|
13563
|
+
!(e.ctrlKey || e.metaKey) || e.altKey || e.shiftKey || e.key !== "s" && e.key !== "S" || !this.layoutsUI || X() || !Ws(this.root, !0) || (e.preventDefault(), this.layoutsUI.save());
|
|
13382
13564
|
};
|
|
13383
13565
|
constructor(e, t = {}) {
|
|
13384
|
-
this.options = t, this.layout =
|
|
13385
|
-
...
|
|
13566
|
+
this.options = t, this.layout = Xl(t.layout) ? t.layout : "1x2", this.sync = {
|
|
13567
|
+
...ql,
|
|
13386
13568
|
...t.sync
|
|
13387
|
-
}, this.t = d(f(t.widget?.locale, t.widget?.messages)), rn(), this.root = document.createElement("div"), this.root.className = "tcw-root tcw-grid", this.root.dataset.tcwTheme = t.widget?.theme === "light" ? "light" : "dark", K(this.root, G(t.widget?.ui), { variables: t.widget?.ui !== void 0 }), t.bar !== !1 && this.root.appendChild(this.buildBar()), this.cellsEl = document.createElement("div"), this.cellsEl.className = "tcw-grid-cells", this.root.appendChild(this.cellsEl), e.appendChild(this.root), this.stopNarrow =
|
|
13569
|
+
}, this.t = d(f(t.widget?.locale, t.widget?.messages)), rn(), this.root = document.createElement("div"), this.root.className = "tcw-root tcw-grid", this.root.dataset.tcwTheme = t.widget?.theme === "light" ? "light" : "dark", K(this.root, G(t.widget?.ui), { variables: t.widget?.ui !== void 0 }), t.bar !== !1 && this.root.appendChild(this.buildBar()), this.cellsEl = document.createElement("div"), this.cellsEl.className = "tcw-grid-cells", this.root.appendChild(this.cellsEl), e.appendChild(this.root), this.stopNarrow = $s(this.root), this.applyShape();
|
|
13388
13570
|
for (let e = 0; e < this.shapeCount(); e++) this.cells.push(this.createCell(e));
|
|
13389
13571
|
this.markActive();
|
|
13390
13572
|
let n = this.cells[0]?.el.querySelector(".tcw-root")?.dataset.tcwTheme;
|
|
13391
|
-
n && (this.root.dataset.tcwTheme = n), t.layouts !== !1 && this.setupLayouts(t.layouts === !0 || t.layouts === void 0 ? {} : t.layouts), this.unregisterKeys =
|
|
13573
|
+
n && (this.root.dataset.tcwTheme = n), t.layouts !== !1 && this.setupLayouts(t.layouts === !0 || t.layouts === void 0 ? {} : t.layouts), this.unregisterKeys = Us(this.root), document.addEventListener("keydown", this.onKeyDown);
|
|
13392
13574
|
}
|
|
13393
13575
|
get relaying() {
|
|
13394
13576
|
return this.relayDepth > 0;
|
|
@@ -13420,7 +13602,7 @@ var ql = class {
|
|
|
13420
13602
|
return this.layout;
|
|
13421
13603
|
}
|
|
13422
13604
|
setLayout(e) {
|
|
13423
|
-
if (e === this.layout || !
|
|
13605
|
+
if (e === this.layout || !Xl(e)) return;
|
|
13424
13606
|
this.layout = e;
|
|
13425
13607
|
let t = this.shapeCount();
|
|
13426
13608
|
for (; this.cells.length > t;) {
|
|
@@ -13510,7 +13692,7 @@ var ql = class {
|
|
|
13510
13692
|
return JSON.stringify(this.captureLayout());
|
|
13511
13693
|
}
|
|
13512
13694
|
async applyLayoutContent(e) {
|
|
13513
|
-
let t =
|
|
13695
|
+
let t = $l(Ys(e));
|
|
13514
13696
|
return t ? (await this.restoreLayout(t), !0) : !1;
|
|
13515
13697
|
}
|
|
13516
13698
|
destroy() {
|
|
@@ -13521,17 +13703,17 @@ var ql = class {
|
|
|
13521
13703
|
}
|
|
13522
13704
|
}
|
|
13523
13705
|
shapeCount() {
|
|
13524
|
-
let { cols: e, rows: t } =
|
|
13706
|
+
let { cols: e, rows: t } = Yl[this.layout];
|
|
13525
13707
|
return e * t;
|
|
13526
13708
|
}
|
|
13527
13709
|
applyShape() {
|
|
13528
|
-
let { cols: e, rows: t } =
|
|
13710
|
+
let { cols: e, rows: t } = Yl[this.layout];
|
|
13529
13711
|
this.cellsEl.style.gridTemplateColumns = `repeat(${e}, minmax(0, 1fr))`, this.cellsEl.style.gridTemplateRows = `repeat(${t}, minmax(0, 1fr))`;
|
|
13530
13712
|
}
|
|
13531
13713
|
createCell(e) {
|
|
13532
13714
|
let t = document.createElement("div");
|
|
13533
13715
|
t.className = "tcw-grid-cell", t.setAttribute("role", "region"), t.setAttribute("aria-label", p(this.t("grid.chart"), { n: e + 1 })), this.cellsEl.appendChild(t);
|
|
13534
|
-
let n = this.options.widget ?? {}, r = this.options.cells?.[e] ?? {}, i = this.cells[this.active]?.widget, a = {}, o = new
|
|
13716
|
+
let n = this.options.widget ?? {}, r = this.options.cells?.[e] ?? {}, i = this.cells[this.active]?.widget, a = {}, o = new Fl(t, {
|
|
13535
13717
|
...n,
|
|
13536
13718
|
...r,
|
|
13537
13719
|
...i && this.sync.symbol ? { symbol: i.getSymbol() } : {},
|
|
@@ -13585,7 +13767,7 @@ var ql = class {
|
|
|
13585
13767
|
t.replaySeekToTime(n);
|
|
13586
13768
|
return;
|
|
13587
13769
|
}
|
|
13588
|
-
let r =
|
|
13770
|
+
let r = tu(t.getData(), n);
|
|
13589
13771
|
r >= 0 && t.replayStart({
|
|
13590
13772
|
startIndex: r,
|
|
13591
13773
|
paused: !0
|
|
@@ -13630,7 +13812,7 @@ var ql = class {
|
|
|
13630
13812
|
copyDrawings(e) {
|
|
13631
13813
|
let t = e.widget.getSymbol(), n = e.widget.getChart().getDrawings();
|
|
13632
13814
|
this.quietly(() => {
|
|
13633
|
-
for (let r of this.cells) r !== e && r.widget.getSymbol() === t && r.widget.getChart().setDrawings(
|
|
13815
|
+
for (let r of this.cells) r !== e && r.widget.getSymbol() === t && r.widget.getChart().setDrawings(Zl(n));
|
|
13634
13816
|
});
|
|
13635
13817
|
}
|
|
13636
13818
|
mergeDrawings() {
|
|
@@ -13642,7 +13824,7 @@ var ql = class {
|
|
|
13642
13824
|
let e = /* @__PURE__ */ new Map();
|
|
13643
13825
|
for (let n of t) for (let t of n.widget.getChart().getDrawings()) e.has(t.id) || e.set(t.id, t);
|
|
13644
13826
|
let n = [...e.values()];
|
|
13645
|
-
for (let e of t) e.widget.getChart().setDrawings(
|
|
13827
|
+
for (let e of t) e.widget.getChart().setDrawings(Zl(n));
|
|
13646
13828
|
}
|
|
13647
13829
|
});
|
|
13648
13830
|
}
|
|
@@ -13678,20 +13860,20 @@ var ql = class {
|
|
|
13678
13860
|
e.className = "tcw-grid-bar", e.setAttribute("role", "toolbar"), e.setAttribute("aria-label", this.t("grid.bar")), this.tabsEl = document.createElement("div"), this.tabsEl.className = "tcw-grid-group tcw-grid-tabs", this.root.classList.add("tcw-grid-has-tabs"), this.tabsEl.setAttribute("role", "group"), this.tabsEl.setAttribute("aria-label", this.t("grid.charts")), e.appendChild(this.tabsEl);
|
|
13679
13861
|
let t = document.createElement("div");
|
|
13680
13862
|
t.className = "tcw-grid-group", t.setAttribute("role", "group"), t.setAttribute("aria-label", this.t("grid.layout"));
|
|
13681
|
-
let n = this.options.layoutChoices?.filter(
|
|
13863
|
+
let n = this.options.layoutChoices?.filter(Xl) ?? Object.keys(Yl);
|
|
13682
13864
|
for (let e of n) {
|
|
13683
|
-
let { cols: n, rows: r } =
|
|
13865
|
+
let { cols: n, rows: r } = Yl[e], i = n * r === 1 ? this.t("grid.single") : p(this.t("grid.layoutOption"), {
|
|
13684
13866
|
count: n * r,
|
|
13685
13867
|
cols: n,
|
|
13686
13868
|
rows: r
|
|
13687
13869
|
}), a = document.createElement("button");
|
|
13688
|
-
a.type = "button", a.className = "tcw-btn-icon", a.title = i, a.setAttribute("aria-label", i), a.innerHTML =
|
|
13870
|
+
a.type = "button", a.className = "tcw-btn-icon", a.title = i, a.setAttribute("aria-label", i), a.innerHTML = Ql(n, r), a.addEventListener("click", () => this.setLayout(e)), this.layoutButtons.set(e, a), t.appendChild(a);
|
|
13689
13871
|
}
|
|
13690
13872
|
let r = document.createElement("div");
|
|
13691
13873
|
r.className = "tcw-grid-group", r.setAttribute("role", "group"), r.setAttribute("aria-label", this.t("grid.sync"));
|
|
13692
13874
|
let i = document.createElement("span");
|
|
13693
13875
|
i.className = "tcw-grid-label", i.innerHTML = `${A("link", 13)}<span>${j(this.t("grid.sync"))}</span>`, r.appendChild(i);
|
|
13694
|
-
for (let e of
|
|
13876
|
+
for (let e of Jl) {
|
|
13695
13877
|
let t = document.createElement("button");
|
|
13696
13878
|
t.type = "button", t.className = "tcw-btn tcw-grid-sync", t.textContent = this.t(`grid.sync.${e}`), t.title = this.t(`grid.sync.${e}.hint`), t.addEventListener("click", () => this.setSync({ [e]: !this.sync[e] })), this.syncButtons.set(e, t), r.appendChild(t);
|
|
13697
13879
|
}
|
|
@@ -13738,7 +13920,7 @@ var ql = class {
|
|
|
13738
13920
|
onChange: () => this.renderLayoutsButton(),
|
|
13739
13921
|
onError: () => this.toast(this.t("layouts.saveFailed"), "error")
|
|
13740
13922
|
});
|
|
13741
|
-
this.session = t, this.layoutsUI = new
|
|
13923
|
+
this.session = t, this.layoutsUI = new Is(t, {
|
|
13742
13924
|
root: this.root,
|
|
13743
13925
|
t: this.t,
|
|
13744
13926
|
toast: (e, t) => this.toast(e, t),
|
|
@@ -13752,12 +13934,12 @@ var ql = class {
|
|
|
13752
13934
|
this.cells[this.active]?.widget.toast(e, t);
|
|
13753
13935
|
}
|
|
13754
13936
|
};
|
|
13755
|
-
function
|
|
13937
|
+
function tu(e, t) {
|
|
13756
13938
|
let n = -1;
|
|
13757
13939
|
for (let r = 0; r < e.length && e[r].time < t; r++) n = r;
|
|
13758
13940
|
return n;
|
|
13759
13941
|
}
|
|
13760
13942
|
//#endregion
|
|
13761
|
-
export { _ as CHART_TYPE_ICONS,
|
|
13943
|
+
export { _ as CHART_TYPE_ICONS, Fl as ChartWidget, eu as ChartWidgetGrid, ql as DEFAULT_GRID_SYNC, ee as DRAWING_TOOL_ICONS, l as EN_MESSAGES, Yl as GRID_SHAPES, s as LayoutSession, i as MAX_LAYOUT_NAME, ie as UI_ICONS, m as VI_MESSAGES, zt as WIDGET_FEATURES, Qi as WIDGET_UI_PRESETS, K as applyWidgetUI, o as cleanLayoutName, cn as createChartTypeIcon, A as createIcon, sn as createToolIcon, u as findWidgetLocale, se as iconSvg, r as localStorageLayouts, t as memoryLayouts, $l as readGridLayout, mi as readWatchlists, Js as readWidgetLayout, c as registerWidgetLocale, G as resolveWidgetUI, oa as widgetUIVariables };
|
|
13762
13944
|
|
|
13763
13945
|
//# sourceMappingURL=index.js.map
|