@tradecanvas/chart 1.43.0 → 1.44.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/{LayoutSession-PXegVR9P.cjs → LayoutSession-CvLuKb2X.cjs} +2 -2
- package/dist/{LayoutSession-PXegVR9P.cjs.map → LayoutSession-CvLuKb2X.cjs.map} +1 -1
- package/dist/{LayoutSession-Cg9dd59R.js → LayoutSession-Dh4Kqna4.js} +2 -2
- package/dist/{LayoutSession-Cg9dd59R.js.map → LayoutSession-Dh4Kqna4.js.map} +1 -1
- 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.js +1 -1
- package/dist/widget/ChartWidget.d.ts +6 -2
- 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/index.cjs +290 -145
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.js +682 -497
- 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/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-Dh4Kqna4.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",
|
|
@@ -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;
|
|
7809
|
+
}
|
|
7810
|
+
function fs(e) {
|
|
7811
|
+
let t = es(e);
|
|
7812
|
+
return t ? `tcw-account-${t}` : "";
|
|
7798
7813
|
}
|
|
7799
|
-
var
|
|
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);
|
|
9759
9892
|
}
|
|
9760
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;
|
|
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;
|
|
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);
|
|
@@ -10523,8 +10680,8 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10523
10680
|
onAuto: () => this.changeSettings({ autoScale: !this.chart.isAutoScale() })
|
|
10524
10681
|
}
|
|
10525
10682
|
}), this.clockTimer = setInterval(() => {
|
|
10526
|
-
!
|
|
10527
|
-
},
|
|
10683
|
+
!Nl() && this.featureState.statusBar && this.featureState["statusBar.clock"] && this.statusBar?.tick();
|
|
10684
|
+
}, jl), this.chart.on("priceRangeChange", () => this.refreshScaleSwitches()), this.refreshScaleSwitches(), this.goToDate = new ic(this.overlayHost, () => ({
|
|
10528
10685
|
title: this.t("goTo.title"),
|
|
10529
10686
|
date: this.t("range.date"),
|
|
10530
10687
|
range: this.t("goTo.range"),
|
|
@@ -10575,7 +10732,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10575
10732
|
eraser: t ?? this.state.eraser,
|
|
10576
10733
|
zoomArea: n ?? this.state.zoomArea
|
|
10577
10734
|
}, this.updateUI();
|
|
10578
|
-
}), this.chart.on("indicatorAdd", () => this.syncIndicatorsFromChart()), this.chart.on("indicatorRemove", () => this.syncIndicatorsFromChart()), this.chart.setPaneTitlesVisible(!this.featureState.indicatorLegend), this.indicatorLegend = new
|
|
10735
|
+
}), 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
10736
|
onToggleVisible: (e, t) => {
|
|
10580
10737
|
this.chart.setIndicatorVisible(e, t), this.scheduleLegend(), this.objectTree?.isOpen() && this.refreshObjects();
|
|
10581
10738
|
},
|
|
@@ -10630,7 +10787,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10630
10787
|
if (this.replayBar?.getMode() !== "select" || !this.replayBar.isMounted()) return;
|
|
10631
10788
|
let t = e.payload.point;
|
|
10632
10789
|
this.positionReplayShade(t?.x ?? null);
|
|
10633
|
-
}), this.dataWindow = new
|
|
10790
|
+
}), this.dataWindow = new zc(this.root, {
|
|
10634
10791
|
formatPrice: (e) => this.formatAlertPrice(e),
|
|
10635
10792
|
onClose: () => this.closePanelByHand("dataWindow")
|
|
10636
10793
|
}, this.t), this.chart.on("crosshairMove", (e) => {
|
|
@@ -10647,7 +10804,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10647
10804
|
},
|
|
10648
10805
|
toWallTime: (e) => Z(e * ae(this.chart.getData()), this.displayTimezone()),
|
|
10649
10806
|
fromWallTime: (e, t) => {
|
|
10650
|
-
let n =
|
|
10807
|
+
let n = nc(e, t, this.displayTimezone());
|
|
10651
10808
|
return n === null ? null : n / ae(this.chart.getData());
|
|
10652
10809
|
},
|
|
10653
10810
|
roundPrice: (e) => this.chart.roundPrice(e),
|
|
@@ -10740,12 +10897,12 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10740
10897
|
area: "priceAxisAdd",
|
|
10741
10898
|
price: i
|
|
10742
10899
|
});
|
|
10743
|
-
}), this.chart.on("signalMarkerHover", (e) => this.showMarkerTip(e.payload)), this.intervalInput = new
|
|
10900
|
+
}), this.chart.on("signalMarkerHover", (e) => this.showMarkerTip(e.payload)), this.intervalInput = new Rs(this.chartContainer, {
|
|
10744
10901
|
title: this.t("interval.title"),
|
|
10745
10902
|
hint: this.t("interval.hint"),
|
|
10746
10903
|
invalid: this.t("interval.invalid")
|
|
10747
10904
|
}, (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
|
|
10905
|
+
this.orderTicket = new Ds(this.root, {
|
|
10749
10906
|
onSubmit: (e) => {
|
|
10750
10907
|
this.chart.placeOrderIntent(e), this.say(p(this.t("ticket.sent"), {
|
|
10751
10908
|
side: this.t(e.side === "buy" ? "ticket.buy" : "ticket.sell"),
|
|
@@ -10756,7 +10913,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10756
10913
|
formatPrice: (e) => this.formatAlertPrice(e),
|
|
10757
10914
|
formatAmount: (e) => this.formatMoney(e),
|
|
10758
10915
|
formatNumber: (e, t) => this.formatNumber(e, t)
|
|
10759
|
-
}, this.t), this.accountPanel = new
|
|
10916
|
+
}, this.t), this.accountPanel = new ps(_, {
|
|
10760
10917
|
onClosePosition: (e) => this.chart.closePositionIntent(e),
|
|
10761
10918
|
onReversePosition: (e) => this.chart.reversePositionIntent(e),
|
|
10762
10919
|
onCancelOrder: (e) => this.chart.cancelOrderIntent(e),
|
|
@@ -10766,6 +10923,8 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10766
10923
|
let { date: t, time: n } = Z(e, this.displayTimezone());
|
|
10767
10924
|
return `${t} ${n}`;
|
|
10768
10925
|
},
|
|
10926
|
+
formatAmount: (e) => this.formatMoney(e),
|
|
10927
|
+
formatNumber: (e, t) => this.formatNumber(e, t),
|
|
10769
10928
|
onToggle: (e) => {
|
|
10770
10929
|
this.toolbar?.setActive("account", e), this.refreshAccount();
|
|
10771
10930
|
}
|
|
@@ -10778,28 +10937,38 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10778
10937
|
"indicatorUpdate"
|
|
10779
10938
|
]) this.chart.on(e, () => this.refreshAccountSoon());
|
|
10780
10939
|
}
|
|
10781
|
-
t.trading !== !1
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10940
|
+
if (t.trading !== !1) {
|
|
10941
|
+
if (this.bracketBar = new Mc(this.chartContainer, {
|
|
10942
|
+
onConfirm: () => this.chart.confirmBracket(),
|
|
10943
|
+
onCancel: () => {
|
|
10944
|
+
this.chart.cancelBracket(), this.bracketBar?.hide();
|
|
10945
|
+
}
|
|
10946
|
+
}, this.t), this.chart.on("bracketPlace", (e) => {
|
|
10947
|
+
let t = e.payload;
|
|
10948
|
+
this.bracketBar?.hide(), this.say(p(this.t(t.side === "buy" ? "bracket.longPlaced" : "bracket.shortPlaced"), { rr: t.riskReward.toFixed(2) }));
|
|
10949
|
+
}), t.depthLadder) {
|
|
10950
|
+
this.depthLadder = new Ic(this.root, {
|
|
10951
|
+
onTrade: (e, t) => {
|
|
10952
|
+
this.chart.placeOrderIntent({
|
|
10953
|
+
side: e,
|
|
10954
|
+
type: "limit",
|
|
10955
|
+
price: t
|
|
10956
|
+
}), this.say(p(this.t(e === "buy" ? "order.buyLimit" : "order.sellLimit"), { price: this.formatAlertPrice(t) }));
|
|
10957
|
+
},
|
|
10958
|
+
formatPrice: (e) => this.formatAlertPrice(e),
|
|
10959
|
+
priceStep: (e) => this.chart.getPriceStep(e),
|
|
10960
|
+
onToggle: (e) => this.toolbar?.setActive("ladder", e),
|
|
10961
|
+
onClose: () => this.closePanelByHand("depthLadder")
|
|
10962
|
+
}, void 0, this.t);
|
|
10963
|
+
let e = this.depthLadder;
|
|
10964
|
+
this.chart.on("ordersChange", () => e.setOrders(this.chart.getOrders()));
|
|
10785
10965
|
}
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
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, {
|
|
10966
|
+
this.chart.on("dataUpdate", (e) => {
|
|
10967
|
+
let t = e.payload;
|
|
10968
|
+
t && t.bracket === "cancelled" && this.bracketBar?.hide();
|
|
10969
|
+
});
|
|
10970
|
+
}
|
|
10971
|
+
this.alertsPanel = new Hi(this.root, {
|
|
10803
10972
|
onClose: () => this.closePanelByHand("alerts"),
|
|
10804
10973
|
onAdd: ({ price: e, condition: t, message: n, channel: r, label: i, options: a }) => {
|
|
10805
10974
|
try {
|
|
@@ -10819,7 +10988,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10819
10988
|
}, 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
10989
|
let t = e.payload;
|
|
10821
10990
|
this.refreshAlerts(), this.featureState.alerts && this.say(p(this.t("alerts.expiredToast"), { text: t.message ?? this.alertText(t) }));
|
|
10822
|
-
}), t.alertNotifications && (this.alertNotifier = new
|
|
10991
|
+
}), t.alertNotifications && (this.alertNotifier = new Nc(t.alertNotifications)), this.chart.on("alertTriggered", (e) => {
|
|
10823
10992
|
let t = e.payload;
|
|
10824
10993
|
if (this.refreshAlerts(), !this.featureState.alerts) return;
|
|
10825
10994
|
let n = `${this.alertText(t)}${t.message ? ` — ${t.message}` : ""}`;
|
|
@@ -10898,11 +11067,11 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10898
11067
|
onAction: (e) => this.handleAction(e),
|
|
10899
11068
|
onClose: () => {}
|
|
10900
11069
|
}, this.overlayHost, this.t, {
|
|
10901
|
-
list: () =>
|
|
10902
|
-
add: (e) =>
|
|
11070
|
+
list: () => zl(),
|
|
11071
|
+
add: (e) => Bl([e, ...zl().filter((t) => t !== e)])
|
|
10903
11072
|
}), this.boundGlobalKeydown = (e) => {
|
|
10904
11073
|
if (this.featureState.hotkeys && this.replayBar?.isMounted() && this.handleReplayKey(e) || this.handleHostHotkey(e)) return;
|
|
10905
|
-
let t =
|
|
11074
|
+
let t = Ws(this.root), n = (e) => this.featureState.hotkeys && this.featureState[e];
|
|
10906
11075
|
if ((e.ctrlKey || e.metaKey) && e.key === "k") {
|
|
10907
11076
|
if (!t || !n("hotkeys.commandPalette") || !this.featureState.commandPalette) return;
|
|
10908
11077
|
e.preventDefault(), this.toggleCommandPalette();
|
|
@@ -10910,21 +11079,21 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10910
11079
|
if (!t || !n("hotkeys.symbolSearch") || !this.featureState.symbolSearch) return;
|
|
10911
11080
|
e.preventDefault(), this.openSymbolSearch();
|
|
10912
11081
|
} 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() || !
|
|
11082
|
+
if (!this.layoutSession || !n("hotkeys.save") || !this.featureState.layouts || X() || !Ws(this.root, !0)) return;
|
|
10914
11083
|
e.preventDefault(), this.saveLayout();
|
|
10915
11084
|
} else if (e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey && Di[e.code]) {
|
|
10916
|
-
if (e.defaultPrevented || X() || !t ||
|
|
11085
|
+
if (e.defaultPrevented || X() || !t || kl() || !n("hotkeys.tools")) return;
|
|
10917
11086
|
e.preventDefault(), this.handleDrawingTool(Di[e.code]);
|
|
10918
11087
|
} else if (/^[0-9]$/.test(e.key) && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
10919
|
-
if (e.defaultPrevented || !this.intervalInput || !n("intervalTyping") || X() ||
|
|
11088
|
+
if (e.defaultPrevented || !this.intervalInput || !n("intervalTyping") || X() || kl() || !Ws(this.root, !0)) return;
|
|
10920
11089
|
let t = document.activeElement;
|
|
10921
11090
|
if (t && t !== document.body && !this.root.contains(t)) return;
|
|
10922
11091
|
e.preventDefault(), this.intervalInput.open(e.key);
|
|
10923
|
-
} else if (
|
|
10924
|
-
if (e.defaultPrevented || !n("symbolTyping") || !this.featureState.symbolSearch || X() ||
|
|
11092
|
+
} else if (Sl(e) !== null) {
|
|
11093
|
+
if (e.defaultPrevented || !n("symbolTyping") || !this.featureState.symbolSearch || X() || kl() || !Ws(this.root, !0)) return;
|
|
10925
11094
|
let t = document.activeElement;
|
|
10926
11095
|
if (t && t !== document.body && !this.root.contains(t)) return;
|
|
10927
|
-
e.preventDefault(), this.openSymbolSearch(
|
|
11096
|
+
e.preventDefault(), this.openSymbolSearch(Sl(e));
|
|
10928
11097
|
} else if (e.altKey && !e.ctrlKey && !e.metaKey && (e.code === "KeyI" || e.code === "KeyG" || e.code === "KeyR")) {
|
|
10929
11098
|
if (X() || !t) return;
|
|
10930
11099
|
if (e.code === "KeyI") {
|
|
@@ -10938,10 +11107,10 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10938
11107
|
if (X() || !t || !n("hotkeys.help") || !this.featureState.hotkeySheet) return;
|
|
10939
11108
|
e.preventDefault(), this.openHotkeySheet();
|
|
10940
11109
|
}
|
|
10941
|
-
}, document.addEventListener("keydown", this.boundGlobalKeydown), document.addEventListener("fullscreenchange", this.onFullscreenChange), this.unregisterKeys =
|
|
11110
|
+
}, 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
11111
|
this.destroyed || (this.toolbar?.tidy(), this.sidebar?.tidy());
|
|
10943
11112
|
}), this.refreshMarket(), this.updateUI(), t.onReady?.(this.chart), t.shareUrl && typeof location < "u") {
|
|
10944
|
-
let e =
|
|
11113
|
+
let e = Xc(location.hash);
|
|
10945
11114
|
e && this.importState(e);
|
|
10946
11115
|
}
|
|
10947
11116
|
}
|
|
@@ -10980,7 +11149,10 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10980
11149
|
return t ? { ...t } : null;
|
|
10981
11150
|
}
|
|
10982
11151
|
openPanel(e) {
|
|
10983
|
-
return !
|
|
11152
|
+
return !this.hasPanel(e) || !this.dock ? !1 : (this.dock.open(e), this.dock.current() === e);
|
|
11153
|
+
}
|
|
11154
|
+
hasPanel(e) {
|
|
11155
|
+
return e === "watchlist" ? this.watchlist !== null : e === "depthLadder" && this.depthLadder === null ? !1 : this.featureState[yl[e]];
|
|
10984
11156
|
}
|
|
10985
11157
|
closePanel() {
|
|
10986
11158
|
this.dock?.close();
|
|
@@ -10995,7 +11167,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
10995
11167
|
n && !this.featureState.symbolInfo || (n ? this.dock?.open("symbolInfo") : this.dock?.closePage("symbolInfo"));
|
|
10996
11168
|
}
|
|
10997
11169
|
refreshMarket() {
|
|
10998
|
-
if (
|
|
11170
|
+
if (Nl()) return;
|
|
10999
11171
|
let e = de(this.chart.getSymbolInfo(), Date.now());
|
|
11000
11172
|
this.statusBar?.setMarket(e.state, this.t(e.state === "open" ? "symbolInfo.open" : "symbolInfo.closed")), this.refreshSymbolInfo();
|
|
11001
11173
|
}
|
|
@@ -11030,7 +11202,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11030
11202
|
return this.options.locale || "en";
|
|
11031
11203
|
}
|
|
11032
11204
|
createWatchlist(e, t) {
|
|
11033
|
-
let n = t.persist ?
|
|
11205
|
+
let n = t.persist ? Wl() : null, r = new gi({
|
|
11034
11206
|
lists: t.lists,
|
|
11035
11207
|
activeList: t.activeList,
|
|
11036
11208
|
symbols: this.symbols,
|
|
@@ -11118,7 +11290,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11118
11290
|
t.refPrice !== void 0 && this.hostWatchlistRefPrice.set(e, t.refPrice), this.watchlist?.setEntry(e, t);
|
|
11119
11291
|
}
|
|
11120
11292
|
tickWatchlist() {
|
|
11121
|
-
if (!this.watchlist || this.quotes.has(this.state.symbol) ||
|
|
11293
|
+
if (!this.watchlist || this.quotes.has(this.state.symbol) || Nl()) return;
|
|
11122
11294
|
let e = this.chart.getData();
|
|
11123
11295
|
if (e.length === 0) return;
|
|
11124
11296
|
let t = e[e.length - 1], n = this.hostWatchlistRefPrice.get(this.state.symbol);
|
|
@@ -11229,7 +11401,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11229
11401
|
for (; o > 0 && n[o - 1].time * r >= a;) o--;
|
|
11230
11402
|
let s = this.displayTimezone();
|
|
11231
11403
|
return Vn({
|
|
11232
|
-
dayShare: n.slice(-
|
|
11404
|
+
dayShare: n.slice(-Pl).some((e) => {
|
|
11233
11405
|
let t = e.time * r, n = new Date(t + fe(s, t) * 6e4).getUTCDay();
|
|
11234
11406
|
return n === 0 || n === 6;
|
|
11235
11407
|
}) ? 1 : 5 / 7,
|
|
@@ -11287,7 +11459,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11287
11459
|
e.hide();
|
|
11288
11460
|
return;
|
|
11289
11461
|
}
|
|
11290
|
-
let i = this.chartOffset(), a = this.chart.getPlotRect(), o =
|
|
11462
|
+
let i = this.chartOffset(), a = this.chart.getPlotRect(), o = Gl(r.map((e) => this.chart.getDrawingRect(e.id))) ?? {
|
|
11291
11463
|
x: a.x + a.width / 2,
|
|
11292
11464
|
y: a.y,
|
|
11293
11465
|
width: 0,
|
|
@@ -11329,7 +11501,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11329
11501
|
});
|
|
11330
11502
|
}
|
|
11331
11503
|
promptSaveDrawingTemplate(e, t) {
|
|
11332
|
-
this.drawingTemplatePrompt ??= new
|
|
11504
|
+
this.drawingTemplatePrompt ??= new Ms(this.root, this.t), this.drawingTemplatePrompt.open({
|
|
11333
11505
|
title: this.t("drawingSettings.saveTemplateTitle"),
|
|
11334
11506
|
submitLabel: this.t("common.save"),
|
|
11335
11507
|
placeholder: this.drawingToolName(t.type),
|
|
@@ -11365,11 +11537,11 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11365
11537
|
id: e,
|
|
11366
11538
|
type: s.type,
|
|
11367
11539
|
selected: o
|
|
11368
|
-
}) ?? [] : [], l =
|
|
11540
|
+
}) ?? [] : [], l = rl(a, c);
|
|
11369
11541
|
if (l.length === 0) return;
|
|
11370
11542
|
let u = this.chartContainer.getBoundingClientRect(), d = this.root.getBoundingClientRect();
|
|
11371
11543
|
this.drawingMenu.open(l, u.left - d.left + t, u.top - d.top + n, (t) => {
|
|
11372
|
-
|
|
11544
|
+
il(t, c) || this.runDrawingMenuAction(e, o, t);
|
|
11373
11545
|
});
|
|
11374
11546
|
}
|
|
11375
11547
|
runDrawingMenuAction(e, t, n) {
|
|
@@ -11463,11 +11635,11 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11463
11635
|
}
|
|
11464
11636
|
openChartMenu(e, t, n, r) {
|
|
11465
11637
|
if (!this.chartMenu) return;
|
|
11466
|
-
let i = this.options.chartMenuItems?.(r) ?? [], a =
|
|
11638
|
+
let i = this.options.chartMenuItems?.(r) ?? [], a = rl(e, i);
|
|
11467
11639
|
if (a.length === 0) return;
|
|
11468
11640
|
let o = this.chartContainer.getBoundingClientRect(), s = this.root.getBoundingClientRect();
|
|
11469
11641
|
this.chartMenu.open(a, o.left - s.left + t, o.top - s.top + n, (e) => {
|
|
11470
|
-
|
|
11642
|
+
il(e, i) || (e.startsWith("tz:") ? this.changeSettings({ timezone: e.slice(3) }) : this.runChartMenuAction(e, r));
|
|
11471
11643
|
});
|
|
11472
11644
|
}
|
|
11473
11645
|
setFeatures(e) {
|
|
@@ -11499,7 +11671,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11499
11671
|
["dataWindow", () => this.dock?.closePage("dataWindow")],
|
|
11500
11672
|
["accountPanel", () => this.toggleAccountPanel(!1)],
|
|
11501
11673
|
["orderTicket", () => this.orderTicket?.close()],
|
|
11502
|
-
["depthLadder", () => this.
|
|
11674
|
+
["depthLadder", () => this.dock?.closePage("depthLadder")],
|
|
11503
11675
|
["goToDate", () => this.goToDate?.close()],
|
|
11504
11676
|
["settings", () => this.settings?.close()],
|
|
11505
11677
|
["indicatorSettings", () => this.indicatorSettings?.close()],
|
|
@@ -11521,9 +11693,9 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11521
11693
|
for (let [n, r] of t) e(n) && r();
|
|
11522
11694
|
}
|
|
11523
11695
|
addHotkey(e) {
|
|
11524
|
-
let t =
|
|
11696
|
+
let t = cl(e.keys);
|
|
11525
11697
|
if (!t) return console.warn(`[ChartWidget] Can't read the shortcut "${e.keys}": modifiers (Ctrl, Alt, Shift) and a key, joined by +.`), null;
|
|
11526
|
-
|
|
11698
|
+
dl(t) && console.warn(`[ChartWidget] The chart answers ${e.keys} itself (drawings, scrolling or zoom): both will run.`);
|
|
11527
11699
|
let n = {
|
|
11528
11700
|
spec: e,
|
|
11529
11701
|
parsed: t
|
|
@@ -11533,17 +11705,17 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11533
11705
|
} };
|
|
11534
11706
|
}
|
|
11535
11707
|
handleHostHotkey(e) {
|
|
11536
|
-
if (this.hostHotkeys.length === 0 || !this.featureState.hotkeys || e.isComposing || e.keyCode ===
|
|
11537
|
-
let t = this.hostHotkeys.find((t) =>
|
|
11708
|
+
if (this.hostHotkeys.length === 0 || !this.featureState.hotkeys || e.isComposing || e.keyCode === Al || e.getModifierState?.("AltGraph") || e.defaultPrevented || X() || fl(e) || kl()) return !1;
|
|
11709
|
+
let t = this.hostHotkeys.find((t) => ll(e, t.parsed));
|
|
11538
11710
|
if (!t) return !1;
|
|
11539
11711
|
let n = !t.parsed.ctrl && !t.parsed.alt;
|
|
11540
|
-
if (!
|
|
11712
|
+
if (!Ws(this.root, n)) return !1;
|
|
11541
11713
|
let r = document.activeElement;
|
|
11542
11714
|
return n && r && r !== document.body && !this.root.contains(r) ? !1 : (e.preventDefault(), t.spec.onPress(e), !0);
|
|
11543
11715
|
}
|
|
11544
11716
|
keepingLook(e) {
|
|
11545
11717
|
this.settingsEdit && this.settings?.close();
|
|
11546
|
-
let t = this.chart.getOverrides?.({ layer: "user" }) ?? {}, n = Object.fromEntries(
|
|
11718
|
+
let t = this.chart.getOverrides?.({ layer: "user" }) ?? {}, n = Object.fromEntries(Ml.filter((e) => t[e] !== void 0).map((e) => [e, t[e]]));
|
|
11547
11719
|
e(), Object.keys(n).length > 0 && this.chart.applyOverrides(n, { layer: "user" });
|
|
11548
11720
|
}
|
|
11549
11721
|
sheetKeyOn(e) {
|
|
@@ -11596,7 +11768,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11596
11768
|
let r = e.items();
|
|
11597
11769
|
if (r.length === 0) return;
|
|
11598
11770
|
let i = t.getBoundingClientRect(), a = this.root.getBoundingClientRect();
|
|
11599
|
-
n.open(
|
|
11771
|
+
n.open(rl([], r), i.left - a.left, i.bottom - a.top + 2, (e) => il(e, r), t);
|
|
11600
11772
|
}
|
|
11601
11773
|
});
|
|
11602
11774
|
return r.setAttribute("aria-haspopup", "menu"), r.setAttribute("aria-expanded", "false"), t.tidy(), {
|
|
@@ -11835,7 +12007,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11835
12007
|
from: r(a.from),
|
|
11836
12008
|
to: r(a.to)
|
|
11837
12009
|
},
|
|
11838
|
-
withTime: !(S(this.state.timeframe) >=
|
|
12010
|
+
withTime: !(S(this.state.timeframe) >= vl),
|
|
11839
12011
|
max: o,
|
|
11840
12012
|
today: o
|
|
11841
12013
|
});
|
|
@@ -11845,12 +12017,12 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11845
12017
|
if (t.length === 0) return;
|
|
11846
12018
|
let r = ae(t);
|
|
11847
12019
|
if (e.kind === "date") {
|
|
11848
|
-
let i =
|
|
12020
|
+
let i = nc(e.date, e.time, n);
|
|
11849
12021
|
if (i === null) return;
|
|
11850
12022
|
this.chart.goToTime(i / r), i / r < t[0].time && this.say(this.t("range.beforeData"));
|
|
11851
12023
|
return;
|
|
11852
12024
|
}
|
|
11853
|
-
let i =
|
|
12025
|
+
let i = nc(e.from.date, e.from.time, n), a = nc(e.to.date, e.to.time, n);
|
|
11854
12026
|
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
12027
|
}
|
|
11856
12028
|
pinnedTimeframes() {
|
|
@@ -11899,7 +12071,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11899
12071
|
this.say(this.t("templates.nothing"), "error");
|
|
11900
12072
|
return;
|
|
11901
12073
|
}
|
|
11902
|
-
this.templatePrompt ??= new
|
|
12074
|
+
this.templatePrompt ??= new Ms(this.root, this.t), this.templatePrompt.open({
|
|
11903
12075
|
title: this.t("templates.saveTitle"),
|
|
11904
12076
|
submitLabel: this.t("common.save"),
|
|
11905
12077
|
placeholder: this.t("templates.namePlaceholder"),
|
|
@@ -11925,9 +12097,9 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11925
12097
|
}
|
|
11926
12098
|
async switchLocalTimeframe() {
|
|
11927
12099
|
if (!this.baseSeries) return;
|
|
11928
|
-
let e = ++this.localSeq, t = this.lastLocalSwitchMs >=
|
|
12100
|
+
let e = ++this.localSeq, t = this.lastLocalSwitchMs >= pl || this.baseSeries.length >= ml;
|
|
11929
12101
|
try {
|
|
11930
|
-
if (t && (this.loading.begin(this.chart.getData().length > 0, !0), await
|
|
12102
|
+
if (t && (this.loading.begin(this.chart.getData().length > 0, !0), await gl(), e !== this.localSeq || this.destroyed)) return;
|
|
11931
12103
|
this.applyTimeframeData();
|
|
11932
12104
|
} finally {
|
|
11933
12105
|
e === this.localSeq && this.loading.end();
|
|
@@ -11972,6 +12144,9 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11972
12144
|
connectionMessage: t
|
|
11973
12145
|
}, this.updateUI();
|
|
11974
12146
|
}
|
|
12147
|
+
toggleLadder() {
|
|
12148
|
+
!this.depthLadder || !this.featureState.depthLadder || this.dock?.toggle("depthLadder");
|
|
12149
|
+
}
|
|
11975
12150
|
toggleAlerts() {
|
|
11976
12151
|
!this.alertsPanel || !this.featureState.alerts || this.dock?.toggle("alerts");
|
|
11977
12152
|
}
|
|
@@ -11984,7 +12159,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11984
12159
|
id: e.id,
|
|
11985
12160
|
params: e.params
|
|
11986
12161
|
}));
|
|
11987
|
-
return
|
|
12162
|
+
return qc({
|
|
11988
12163
|
v: 1,
|
|
11989
12164
|
symbol: this.state.symbol,
|
|
11990
12165
|
timeframe: this.state.timeframe,
|
|
@@ -11995,7 +12170,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
11995
12170
|
});
|
|
11996
12171
|
}
|
|
11997
12172
|
async importState(e) {
|
|
11998
|
-
let t =
|
|
12173
|
+
let t = Jc(e);
|
|
11999
12174
|
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
12175
|
id: e.id,
|
|
12001
12176
|
instanceId: `shared_${t}`,
|
|
@@ -12007,7 +12182,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12007
12182
|
this.say(e ? this.t("toast.imageCopied") : this.t("toast.imageCopyFailed"), e ? "info" : "error");
|
|
12008
12183
|
}
|
|
12009
12184
|
async copyShareLink() {
|
|
12010
|
-
let e =
|
|
12185
|
+
let e = Zc(typeof location < "u" ? location.href : "", this.exportState());
|
|
12011
12186
|
try {
|
|
12012
12187
|
await navigator.clipboard.writeText(e), this.say(this.t("toast.linkCopied"));
|
|
12013
12188
|
} catch {
|
|
@@ -12120,6 +12295,16 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12120
12295
|
parts: ["dock.symbolInfo", "symbolInfo"],
|
|
12121
12296
|
onShow: () => i.open(),
|
|
12122
12297
|
onHide: () => i.close()
|
|
12298
|
+
});
|
|
12299
|
+
let a = this.depthLadder;
|
|
12300
|
+
a && e.addPage({
|
|
12301
|
+
id: "depthLadder",
|
|
12302
|
+
label: this.t("ladder.title"),
|
|
12303
|
+
icon: "ladder",
|
|
12304
|
+
element: a.element,
|
|
12305
|
+
parts: ["dock.depthLadder", "depthLadder"],
|
|
12306
|
+
onShow: () => a.openPanel(),
|
|
12307
|
+
onHide: () => a.close()
|
|
12123
12308
|
}), this.syncRail(), this.fitDockToWidth(), typeof ResizeObserver < "u" && (this.dockObserver = new ResizeObserver(() => this.fitDockToWidth()), this.dockObserver.observe(this.root));
|
|
12124
12309
|
}
|
|
12125
12310
|
fitDockToWidth() {
|
|
@@ -12137,7 +12322,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12137
12322
|
this.toolbar?.setRailed("alerts", e && this.featureState["dock.alerts"]), this.toolbar?.setRailed("objects", e && this.featureState["dock.objectTree"]), this.toolbar?.fit();
|
|
12138
12323
|
}
|
|
12139
12324
|
panelFocusTarget(e) {
|
|
12140
|
-
let t =
|
|
12325
|
+
let t = xl[e], n = t ? this.root.querySelector(`.tcw-toolbar [data-role="${t}"]`) : null, r = this.root.hasAttribute("data-tcw-narrow");
|
|
12141
12326
|
return n && !n.hidden && !(r && n.classList.contains("tcw-toolbar-overflow")) ? n : this.root.querySelector(".tcw-toolbar-more") ?? this.chartContainer;
|
|
12142
12327
|
}
|
|
12143
12328
|
closePanelByHand(e) {
|
|
@@ -12155,7 +12340,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12155
12340
|
defaults: n.descriptor.defaultConfig,
|
|
12156
12341
|
params: n.params,
|
|
12157
12342
|
inputs: n.descriptor.inputs,
|
|
12158
|
-
lineSources:
|
|
12343
|
+
lineSources: Il(e, t),
|
|
12159
12344
|
plots: n.descriptor.plots,
|
|
12160
12345
|
colors: r?.colors,
|
|
12161
12346
|
lineWidth: r?.lineWidths[0],
|
|
@@ -12197,11 +12382,11 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12197
12382
|
symbols: this.symbols,
|
|
12198
12383
|
current: this.state.symbol,
|
|
12199
12384
|
search: this.symbolSearchFn(),
|
|
12200
|
-
ways:
|
|
12385
|
+
ways: dc(this.t),
|
|
12201
12386
|
way: this.compareWay,
|
|
12202
12387
|
compared: this.comparedNow(),
|
|
12203
12388
|
onAdd: (e, t) => {
|
|
12204
|
-
|
|
12389
|
+
uc(t) && (this.compareWay = t, this.addCompareSymbol(e, t));
|
|
12205
12390
|
},
|
|
12206
12391
|
onRemove: (e) => {
|
|
12207
12392
|
this.compares.some((t) => t.id === e) ? this.handleRemoveCompare(e) : this.chart.removeIndicator(e);
|
|
@@ -12211,7 +12396,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12211
12396
|
}
|
|
12212
12397
|
comparedNow() {
|
|
12213
12398
|
let e = new Set(this.chart.getIndicatorPanes().flatMap((e) => e.instanceIds));
|
|
12214
|
-
return
|
|
12399
|
+
return pc(this.compares, this.chart.getActiveIndicators(), e, this.t);
|
|
12215
12400
|
}
|
|
12216
12401
|
refreshCompareDialog() {
|
|
12217
12402
|
this.symbolSearch?.isComparing() && this.symbolSearch.setCompared(this.comparedNow());
|
|
@@ -12235,7 +12420,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12235
12420
|
try {
|
|
12236
12421
|
let t = await Ge(this.adapter).fetchHistory(e, this.state.timeframe, this.options.historyLimit ?? 500);
|
|
12237
12422
|
if (this.destroyed || this.compares.some((t) => t.symbol === e)) return;
|
|
12238
|
-
let r =
|
|
12423
|
+
let r = _l[this.compares.length % _l.length];
|
|
12239
12424
|
this.compares.length === 0 && this.chart.setCompareMode("percent"), this.chart.addCompareSymbol(n, e, t, r), this.compares = [...this.compares, {
|
|
12240
12425
|
id: n,
|
|
12241
12426
|
symbol: e,
|
|
@@ -12330,7 +12515,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12330
12515
|
return typeof a == "number" && Number.isFinite(a) ? a : null;
|
|
12331
12516
|
}
|
|
12332
12517
|
formatMoney(e) {
|
|
12333
|
-
return this.formatNumber(e, Math.min(Se(this.chart.getPriceStep()),
|
|
12518
|
+
return this.formatNumber(e, Math.min(Se(this.chart.getPriceStep()), bl));
|
|
12334
12519
|
}
|
|
12335
12520
|
formatNumber(e, t) {
|
|
12336
12521
|
let n = this.settingsState.numberLocale || void 0;
|
|
@@ -12658,7 +12843,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12658
12843
|
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
12844
|
}
|
|
12660
12845
|
promptSaveChartTemplate() {
|
|
12661
|
-
this.chartTemplatePrompt ??= new
|
|
12846
|
+
this.chartTemplatePrompt ??= new Ms(this.overlayHost(), this.t), this.chartTemplatePrompt.open({
|
|
12662
12847
|
title: this.t("settings.saveTemplateTitle"),
|
|
12663
12848
|
submitLabel: this.t("common.save"),
|
|
12664
12849
|
placeholder: this.t("settings.templatePlaceholder"),
|
|
@@ -12695,7 +12880,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12695
12880
|
return this.state.timeframe;
|
|
12696
12881
|
}
|
|
12697
12882
|
captureLayout() {
|
|
12698
|
-
let e = this.chart.saveState(), t = e ?
|
|
12883
|
+
let e = this.chart.saveState(), t = e ? Ys(e) : null, n = t && typeof t == "object" ? qs(t) : null;
|
|
12699
12884
|
return {
|
|
12700
12885
|
v: 1,
|
|
12701
12886
|
symbol: this.state.symbol,
|
|
@@ -12708,7 +12893,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12708
12893
|
async restoreLayout(e) {
|
|
12709
12894
|
if (e.symbol !== this.state.symbol && await this.setSymbol(e.symbol), e.timeframe !== this.state.timeframe && await this.setTimeframe(e.timeframe), !this.destroyed) {
|
|
12710
12895
|
if (e.chart) {
|
|
12711
|
-
this.chart.loadState(JSON.stringify(
|
|
12896
|
+
this.chart.loadState(JSON.stringify(qs(e.chart)));
|
|
12712
12897
|
let t = e.chart.chartType;
|
|
12713
12898
|
typeof t == "string" && (this.state = {
|
|
12714
12899
|
...this.state,
|
|
@@ -12725,7 +12910,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12725
12910
|
return JSON.stringify(this.captureLayout());
|
|
12726
12911
|
}
|
|
12727
12912
|
async applyLayoutContent(e) {
|
|
12728
|
-
let t =
|
|
12913
|
+
let t = Js(Ys(e));
|
|
12729
12914
|
return t ? (await this.restoreLayout(t), !0) : !1;
|
|
12730
12915
|
}
|
|
12731
12916
|
setupLayouts(e) {
|
|
@@ -12744,7 +12929,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12744
12929
|
onChange: () => this.toolbar?.setLayout(t.current()?.name ?? null, t.isDirty()),
|
|
12745
12930
|
onError: () => this.say(this.t("layouts.saveFailed"), "error")
|
|
12746
12931
|
});
|
|
12747
|
-
this.layoutSession = t, this.layoutsUI = new
|
|
12932
|
+
this.layoutSession = t, this.layoutsUI = new Is(t, {
|
|
12748
12933
|
root: this.root,
|
|
12749
12934
|
t: this.t,
|
|
12750
12935
|
saveKeys: () => this.keysShown("hotkeys.save", `${kr}+S`),
|
|
@@ -12918,7 +13103,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12918
13103
|
}
|
|
12919
13104
|
replayStepOptions() {
|
|
12920
13105
|
let e = S(this.state.timeframe);
|
|
12921
|
-
return
|
|
13106
|
+
return Dl.filter((t) => {
|
|
12922
13107
|
let n = S(t);
|
|
12923
13108
|
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
13109
|
});
|
|
@@ -12928,7 +13113,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
12928
13113
|
if (this.replayStepsCache?.key === t) return this.replayStepsCache.steps;
|
|
12929
13114
|
let n = null;
|
|
12930
13115
|
if (this.adapter) {
|
|
12931
|
-
let t = Math.max(1, Math.round(S(this.state.timeframe) / S(e))), r = Math.min(
|
|
13116
|
+
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
13117
|
try {
|
|
12933
13118
|
n = await Ge(this.adapter).fetchHistory(this.state.symbol, e, r);
|
|
12934
13119
|
} catch {
|
|
@@ -13099,26 +13284,26 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
13099
13284
|
row: n
|
|
13100
13285
|
}));
|
|
13101
13286
|
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 ? [] :
|
|
13287
|
+
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
13288
|
return {
|
|
13104
13289
|
instanceId: t.instanceId,
|
|
13105
13290
|
label: e(t.id, t.params, t.descriptor.defaultConfig, t.descriptor.shortName),
|
|
13106
13291
|
visible: t.visible,
|
|
13107
13292
|
offInterval: c,
|
|
13108
13293
|
values: l.map((e) => ({
|
|
13109
|
-
text: n ?
|
|
13294
|
+
text: n ? jc(e.value, a) : this.chart.formatPrice(e.value),
|
|
13110
13295
|
color: e.color
|
|
13111
13296
|
})),
|
|
13112
13297
|
pane: n ? {
|
|
13113
|
-
x: n.x +
|
|
13114
|
-
y: n.y + Math.min(
|
|
13115
|
-
width: n.width - 2 *
|
|
13298
|
+
x: n.x + Cl,
|
|
13299
|
+
y: n.y + Math.min(wl + n.row * Tl, Math.max(wl, n.height - Tl)),
|
|
13300
|
+
width: n.width - 2 * Cl
|
|
13116
13301
|
} : null
|
|
13117
13302
|
};
|
|
13118
13303
|
}), s = this.chart.getPlotRect(), c = this.chart.getMaximizedPane(), l = (e) => o.find((t) => t.instanceId === e)?.label ?? "", u = this.chart.getIndicatorPanes().map((e) => ({
|
|
13119
13304
|
instanceId: e.instanceId,
|
|
13120
|
-
x: e.rect.x + e.rect.width -
|
|
13121
|
-
y: e.rect.y +
|
|
13305
|
+
x: e.rect.x + e.rect.width - Cl,
|
|
13306
|
+
y: e.rect.y + El,
|
|
13122
13307
|
label: l(e.instanceId),
|
|
13123
13308
|
collapsed: this.chart.isPaneCollapsed(e.instanceId),
|
|
13124
13309
|
maximized: c === e.instanceId,
|
|
@@ -13126,7 +13311,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
13126
13311
|
canMoveDown: this.chart.canMovePane(e.instanceId, 1)
|
|
13127
13312
|
}));
|
|
13128
13313
|
this.indicatorLegend.update(o, {
|
|
13129
|
-
left: s.x +
|
|
13314
|
+
left: s.x + Cl,
|
|
13130
13315
|
top: this.chart.getLegendBottom() + 1
|
|
13131
13316
|
}, u);
|
|
13132
13317
|
}
|
|
@@ -13172,11 +13357,11 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
13172
13357
|
let u = this.chart.getActiveIndicators().find((t) => t.instanceId === e)?.id ?? "", d = this.options.indicatorMenuItems?.({
|
|
13173
13358
|
instanceId: e,
|
|
13174
13359
|
indicatorId: u
|
|
13175
|
-
}) ?? [], f =
|
|
13360
|
+
}) ?? [], f = rl(c, d);
|
|
13176
13361
|
if (f.length === 0) return;
|
|
13177
13362
|
let p = t.getBoundingClientRect(), m = this.root.getBoundingClientRect();
|
|
13178
13363
|
n.open(f, p.left - m.left, p.bottom - m.top + 2, (t) => {
|
|
13179
|
-
|
|
13364
|
+
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
13365
|
}, t);
|
|
13181
13366
|
}
|
|
13182
13367
|
updateUI() {
|
|
@@ -13201,7 +13386,7 @@ var gl = 4, _l = 7, vl = 17, yl = 3, bl = [
|
|
|
13201
13386
|
return !0;
|
|
13202
13387
|
}
|
|
13203
13388
|
};
|
|
13204
|
-
function
|
|
13389
|
+
function Il(t, n) {
|
|
13205
13390
|
let r = (e) => {
|
|
13206
13391
|
let t = We(e.descriptor);
|
|
13207
13392
|
return t && pe(e.params[t])?.instanceId || null;
|
|
@@ -13224,42 +13409,42 @@ function kl(t, n) {
|
|
|
13224
13409
|
}
|
|
13225
13410
|
return a;
|
|
13226
13411
|
}
|
|
13227
|
-
var
|
|
13228
|
-
function
|
|
13412
|
+
var Ll = "tcw:recentCommands", Rl = 10;
|
|
13413
|
+
function zl() {
|
|
13229
13414
|
try {
|
|
13230
|
-
let e = JSON.parse(
|
|
13231
|
-
return Array.isArray(e) ? e.filter((e) => typeof e == "string").slice(0,
|
|
13415
|
+
let e = JSON.parse(Wl()?.getItem(Ll) ?? "[]");
|
|
13416
|
+
return Array.isArray(e) ? e.filter((e) => typeof e == "string").slice(0, Rl) : [];
|
|
13232
13417
|
} catch {
|
|
13233
13418
|
return [];
|
|
13234
13419
|
}
|
|
13235
13420
|
}
|
|
13236
|
-
function
|
|
13421
|
+
function Bl(e) {
|
|
13237
13422
|
try {
|
|
13238
|
-
|
|
13423
|
+
Wl()?.setItem(Ll, JSON.stringify(e.slice(0, Rl)));
|
|
13239
13424
|
} catch {}
|
|
13240
13425
|
}
|
|
13241
|
-
var
|
|
13242
|
-
function
|
|
13426
|
+
var Vl = "tcw:dockWidth";
|
|
13427
|
+
function Hl() {
|
|
13243
13428
|
try {
|
|
13244
|
-
let e = Number(
|
|
13429
|
+
let e = Number(Wl()?.getItem(Vl) ?? NaN);
|
|
13245
13430
|
return Number.isFinite(e) && e > 0 ? e : null;
|
|
13246
13431
|
} catch {
|
|
13247
13432
|
return null;
|
|
13248
13433
|
}
|
|
13249
13434
|
}
|
|
13250
|
-
function
|
|
13435
|
+
function Ul(e) {
|
|
13251
13436
|
try {
|
|
13252
|
-
|
|
13437
|
+
Wl()?.setItem(Vl, String(e));
|
|
13253
13438
|
} catch {}
|
|
13254
13439
|
}
|
|
13255
|
-
function
|
|
13440
|
+
function Wl() {
|
|
13256
13441
|
try {
|
|
13257
13442
|
return typeof localStorage < "u" ? localStorage : null;
|
|
13258
13443
|
} catch {
|
|
13259
13444
|
return null;
|
|
13260
13445
|
}
|
|
13261
13446
|
}
|
|
13262
|
-
function
|
|
13447
|
+
function Gl(e) {
|
|
13263
13448
|
let t = e.filter((e) => e !== null);
|
|
13264
13449
|
if (t.length === 0) return null;
|
|
13265
13450
|
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 +13455,26 @@ function Rl(e) {
|
|
|
13270
13455
|
height: a - r
|
|
13271
13456
|
};
|
|
13272
13457
|
}
|
|
13273
|
-
function
|
|
13458
|
+
function Kl(e) {
|
|
13274
13459
|
return !!e && /^(ar|he|iw|fa|ur|ps|yi|dv|ckb|sd|ug)(-|$)/i.test(e);
|
|
13275
13460
|
}
|
|
13276
13461
|
//#endregion
|
|
13277
13462
|
//#region src/widget/ChartWidgetGrid.ts
|
|
13278
|
-
var
|
|
13463
|
+
var ql = {
|
|
13279
13464
|
symbol: !1,
|
|
13280
13465
|
interval: !1,
|
|
13281
13466
|
crosshair: !0,
|
|
13282
13467
|
time: !1,
|
|
13283
13468
|
drawings: !1,
|
|
13284
13469
|
replay: !1
|
|
13285
|
-
},
|
|
13470
|
+
}, Jl = [
|
|
13286
13471
|
"symbol",
|
|
13287
13472
|
"interval",
|
|
13288
13473
|
"crosshair",
|
|
13289
13474
|
"time",
|
|
13290
13475
|
"drawings",
|
|
13291
13476
|
"replay"
|
|
13292
|
-
],
|
|
13477
|
+
], Yl = {
|
|
13293
13478
|
"1x1": {
|
|
13294
13479
|
cols: 1,
|
|
13295
13480
|
rows: 1
|
|
@@ -13323,25 +13508,25 @@ var Bl = {
|
|
|
13323
13508
|
rows: 3
|
|
13324
13509
|
}
|
|
13325
13510
|
};
|
|
13326
|
-
function
|
|
13327
|
-
return typeof e == "string" && Object.prototype.hasOwnProperty.call(
|
|
13511
|
+
function Xl(e) {
|
|
13512
|
+
return typeof e == "string" && Object.prototype.hasOwnProperty.call(Yl, e);
|
|
13328
13513
|
}
|
|
13329
|
-
function
|
|
13514
|
+
function Zl(e) {
|
|
13330
13515
|
return JSON.parse(JSON.stringify(e));
|
|
13331
13516
|
}
|
|
13332
|
-
function
|
|
13517
|
+
function Ql(e, t, n = 16) {
|
|
13333
13518
|
let r = (20 - 2 * (e - 1)) / e, i = (20 - 2 * (t - 1)) / t, a = "";
|
|
13334
13519
|
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
13520
|
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
13521
|
}
|
|
13337
|
-
function
|
|
13522
|
+
function $l(e) {
|
|
13338
13523
|
if (typeof e != "object" || !e) return null;
|
|
13339
13524
|
let t = e;
|
|
13340
|
-
if (t.v !== 1 || t.kind !== "grid" || !
|
|
13341
|
-
let n = t.cells.map(
|
|
13525
|
+
if (t.v !== 1 || t.kind !== "grid" || !Xl(t.layout) || !Array.isArray(t.cells)) return null;
|
|
13526
|
+
let n = t.cells.map(Js);
|
|
13342
13527
|
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
|
|
13528
|
+
let r = typeof t.sync == "object" && t.sync !== null ? t.sync : {}, i = { ...ql };
|
|
13529
|
+
for (let e of Jl) typeof r[e] == "boolean" && (i[e] = r[e]);
|
|
13345
13530
|
let a = typeof t.active == "number" && Number.isInteger(t.active) ? t.active : 0;
|
|
13346
13531
|
return {
|
|
13347
13532
|
v: 1,
|
|
@@ -13352,7 +13537,7 @@ function Kl(e) {
|
|
|
13352
13537
|
cells: n
|
|
13353
13538
|
};
|
|
13354
13539
|
}
|
|
13355
|
-
var
|
|
13540
|
+
var eu = class {
|
|
13356
13541
|
root;
|
|
13357
13542
|
cellsEl;
|
|
13358
13543
|
cells = [];
|
|
@@ -13378,17 +13563,17 @@ var ql = class {
|
|
|
13378
13563
|
destroyed = !1;
|
|
13379
13564
|
unregisterKeys = () => {};
|
|
13380
13565
|
onKeyDown = (e) => {
|
|
13381
|
-
!(e.ctrlKey || e.metaKey) || e.altKey || e.shiftKey || e.key !== "s" && e.key !== "S" || !this.layoutsUI || X() || !
|
|
13566
|
+
!(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
13567
|
};
|
|
13383
13568
|
constructor(e, t = {}) {
|
|
13384
|
-
this.options = t, this.layout =
|
|
13385
|
-
...
|
|
13569
|
+
this.options = t, this.layout = Xl(t.layout) ? t.layout : "1x2", this.sync = {
|
|
13570
|
+
...ql,
|
|
13386
13571
|
...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 =
|
|
13572
|
+
}, 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
13573
|
for (let e = 0; e < this.shapeCount(); e++) this.cells.push(this.createCell(e));
|
|
13389
13574
|
this.markActive();
|
|
13390
13575
|
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 =
|
|
13576
|
+
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
13577
|
}
|
|
13393
13578
|
get relaying() {
|
|
13394
13579
|
return this.relayDepth > 0;
|
|
@@ -13420,7 +13605,7 @@ var ql = class {
|
|
|
13420
13605
|
return this.layout;
|
|
13421
13606
|
}
|
|
13422
13607
|
setLayout(e) {
|
|
13423
|
-
if (e === this.layout || !
|
|
13608
|
+
if (e === this.layout || !Xl(e)) return;
|
|
13424
13609
|
this.layout = e;
|
|
13425
13610
|
let t = this.shapeCount();
|
|
13426
13611
|
for (; this.cells.length > t;) {
|
|
@@ -13510,7 +13695,7 @@ var ql = class {
|
|
|
13510
13695
|
return JSON.stringify(this.captureLayout());
|
|
13511
13696
|
}
|
|
13512
13697
|
async applyLayoutContent(e) {
|
|
13513
|
-
let t =
|
|
13698
|
+
let t = $l(Ys(e));
|
|
13514
13699
|
return t ? (await this.restoreLayout(t), !0) : !1;
|
|
13515
13700
|
}
|
|
13516
13701
|
destroy() {
|
|
@@ -13521,17 +13706,17 @@ var ql = class {
|
|
|
13521
13706
|
}
|
|
13522
13707
|
}
|
|
13523
13708
|
shapeCount() {
|
|
13524
|
-
let { cols: e, rows: t } =
|
|
13709
|
+
let { cols: e, rows: t } = Yl[this.layout];
|
|
13525
13710
|
return e * t;
|
|
13526
13711
|
}
|
|
13527
13712
|
applyShape() {
|
|
13528
|
-
let { cols: e, rows: t } =
|
|
13713
|
+
let { cols: e, rows: t } = Yl[this.layout];
|
|
13529
13714
|
this.cellsEl.style.gridTemplateColumns = `repeat(${e}, minmax(0, 1fr))`, this.cellsEl.style.gridTemplateRows = `repeat(${t}, minmax(0, 1fr))`;
|
|
13530
13715
|
}
|
|
13531
13716
|
createCell(e) {
|
|
13532
13717
|
let t = document.createElement("div");
|
|
13533
13718
|
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
|
|
13719
|
+
let n = this.options.widget ?? {}, r = this.options.cells?.[e] ?? {}, i = this.cells[this.active]?.widget, a = {}, o = new Fl(t, {
|
|
13535
13720
|
...n,
|
|
13536
13721
|
...r,
|
|
13537
13722
|
...i && this.sync.symbol ? { symbol: i.getSymbol() } : {},
|
|
@@ -13585,7 +13770,7 @@ var ql = class {
|
|
|
13585
13770
|
t.replaySeekToTime(n);
|
|
13586
13771
|
return;
|
|
13587
13772
|
}
|
|
13588
|
-
let r =
|
|
13773
|
+
let r = tu(t.getData(), n);
|
|
13589
13774
|
r >= 0 && t.replayStart({
|
|
13590
13775
|
startIndex: r,
|
|
13591
13776
|
paused: !0
|
|
@@ -13630,7 +13815,7 @@ var ql = class {
|
|
|
13630
13815
|
copyDrawings(e) {
|
|
13631
13816
|
let t = e.widget.getSymbol(), n = e.widget.getChart().getDrawings();
|
|
13632
13817
|
this.quietly(() => {
|
|
13633
|
-
for (let r of this.cells) r !== e && r.widget.getSymbol() === t && r.widget.getChart().setDrawings(
|
|
13818
|
+
for (let r of this.cells) r !== e && r.widget.getSymbol() === t && r.widget.getChart().setDrawings(Zl(n));
|
|
13634
13819
|
});
|
|
13635
13820
|
}
|
|
13636
13821
|
mergeDrawings() {
|
|
@@ -13642,7 +13827,7 @@ var ql = class {
|
|
|
13642
13827
|
let e = /* @__PURE__ */ new Map();
|
|
13643
13828
|
for (let n of t) for (let t of n.widget.getChart().getDrawings()) e.has(t.id) || e.set(t.id, t);
|
|
13644
13829
|
let n = [...e.values()];
|
|
13645
|
-
for (let e of t) e.widget.getChart().setDrawings(
|
|
13830
|
+
for (let e of t) e.widget.getChart().setDrawings(Zl(n));
|
|
13646
13831
|
}
|
|
13647
13832
|
});
|
|
13648
13833
|
}
|
|
@@ -13678,20 +13863,20 @@ var ql = class {
|
|
|
13678
13863
|
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
13864
|
let t = document.createElement("div");
|
|
13680
13865
|
t.className = "tcw-grid-group", t.setAttribute("role", "group"), t.setAttribute("aria-label", this.t("grid.layout"));
|
|
13681
|
-
let n = this.options.layoutChoices?.filter(
|
|
13866
|
+
let n = this.options.layoutChoices?.filter(Xl) ?? Object.keys(Yl);
|
|
13682
13867
|
for (let e of n) {
|
|
13683
|
-
let { cols: n, rows: r } =
|
|
13868
|
+
let { cols: n, rows: r } = Yl[e], i = n * r === 1 ? this.t("grid.single") : p(this.t("grid.layoutOption"), {
|
|
13684
13869
|
count: n * r,
|
|
13685
13870
|
cols: n,
|
|
13686
13871
|
rows: r
|
|
13687
13872
|
}), a = document.createElement("button");
|
|
13688
|
-
a.type = "button", a.className = "tcw-btn-icon", a.title = i, a.setAttribute("aria-label", i), a.innerHTML =
|
|
13873
|
+
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
13874
|
}
|
|
13690
13875
|
let r = document.createElement("div");
|
|
13691
13876
|
r.className = "tcw-grid-group", r.setAttribute("role", "group"), r.setAttribute("aria-label", this.t("grid.sync"));
|
|
13692
13877
|
let i = document.createElement("span");
|
|
13693
13878
|
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
|
|
13879
|
+
for (let e of Jl) {
|
|
13695
13880
|
let t = document.createElement("button");
|
|
13696
13881
|
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
13882
|
}
|
|
@@ -13738,7 +13923,7 @@ var ql = class {
|
|
|
13738
13923
|
onChange: () => this.renderLayoutsButton(),
|
|
13739
13924
|
onError: () => this.toast(this.t("layouts.saveFailed"), "error")
|
|
13740
13925
|
});
|
|
13741
|
-
this.session = t, this.layoutsUI = new
|
|
13926
|
+
this.session = t, this.layoutsUI = new Is(t, {
|
|
13742
13927
|
root: this.root,
|
|
13743
13928
|
t: this.t,
|
|
13744
13929
|
toast: (e, t) => this.toast(e, t),
|
|
@@ -13752,12 +13937,12 @@ var ql = class {
|
|
|
13752
13937
|
this.cells[this.active]?.widget.toast(e, t);
|
|
13753
13938
|
}
|
|
13754
13939
|
};
|
|
13755
|
-
function
|
|
13940
|
+
function tu(e, t) {
|
|
13756
13941
|
let n = -1;
|
|
13757
13942
|
for (let r = 0; r < e.length && e[r].time < t; r++) n = r;
|
|
13758
13943
|
return n;
|
|
13759
13944
|
}
|
|
13760
13945
|
//#endregion
|
|
13761
|
-
export { _ as CHART_TYPE_ICONS,
|
|
13946
|
+
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
13947
|
|
|
13763
13948
|
//# sourceMappingURL=index.js.map
|