@tradecanvas/chart 1.78.0 → 1.79.1
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-BzJQfrYw.cjs → LayoutSession-2o_-ji7A.cjs} +2 -2
- package/dist/{LayoutSession-BzJQfrYw.cjs.map → LayoutSession-2o_-ji7A.cjs.map} +1 -1
- package/dist/{LayoutSession-CehL1zj4.js → LayoutSession-BJxMu1Df.js} +2 -2
- package/dist/{LayoutSession-CehL1zj4.js.map → LayoutSession-BJxMu1Df.js.map} +1 -1
- package/dist/{WidgetSettings-D1xKl3Gl.js → WidgetSettings-CkvK-3d9.js} +2 -2
- package/dist/{WidgetSettings-D1xKl3Gl.js.map → WidgetSettings-CkvK-3d9.js.map} +1 -1
- package/dist/{WidgetSettings-CL-sRVF2.cjs → WidgetSettings-bO72SYQ6.cjs} +2 -2
- package/dist/{WidgetSettings-CL-sRVF2.cjs.map → WidgetSettings-bO72SYQ6.cjs.map} +1 -1
- package/dist/{WidgetSymbolSearch-CrVAWg8Y.js → WidgetSymbolSearch-BWI3iNJM.js} +36 -23
- package/dist/WidgetSymbolSearch-BWI3iNJM.js.map +1 -0
- package/dist/WidgetSymbolSearch-CJeMSKtO.cjs +2 -0
- package/dist/WidgetSymbolSearch-CJeMSKtO.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/widget/ChartWidget.d.ts.map +1 -1
- package/dist/widget/WidgetDock.d.ts +4 -4
- package/dist/widget/WidgetDrawingSidebar.d.ts.map +1 -1
- package/dist/widget/WidgetSymbolInfo.d.ts.map +1 -1
- package/dist/widget/WidgetSymbolSearch.d.ts.map +1 -1
- package/dist/widget/WidgetToolbar.d.ts +6 -8
- package/dist/widget/WidgetToolbar.d.ts.map +1 -1
- package/dist/widget/WidgetWatchlist.d.ts +6 -0
- package/dist/widget/WidgetWatchlist.d.ts.map +1 -1
- package/dist/widget/index.cjs +49 -80
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.js +640 -631
- package/dist/widget/index.js.map +1 -1
- package/dist/widget/symbolCell.d.ts +6 -4
- package/dist/widget/symbolCell.d.ts.map +1 -1
- package/dist/widget/types.d.ts +6 -0
- package/dist/widget/types.d.ts.map +1 -1
- package/dist/widget/widgetConfig.d.ts +4 -2
- package/dist/widget/widgetConfig.d.ts.map +1 -1
- package/dist/widget/widgetLocales.d.ts.map +1 -1
- package/dist/widget/widgetUI.d.ts.map +1 -1
- package/dist/{widgetLocales-DgTR8JSu.js → widgetLocales-D-QYU_9U.js} +41 -67
- package/dist/widgetLocales-D-QYU_9U.js.map +1 -0
- package/dist/widgetLocales-fhdzLs5l.cjs +2 -0
- package/dist/widgetLocales-fhdzLs5l.cjs.map +1 -0
- package/package.json +3 -3
- package/dist/WidgetSymbolSearch-BFQsqzQD.cjs +0 -2
- package/dist/WidgetSymbolSearch-BFQsqzQD.cjs.map +0 -1
- package/dist/WidgetSymbolSearch-CrVAWg8Y.js.map +0 -1
- package/dist/widgetLocales-BPK5i0Ok.cjs +0 -2
- package/dist/widgetLocales-BPK5i0Ok.cjs.map +0 -1
- package/dist/widgetLocales-DgTR8JSu.js.map +0 -1
package/dist/widget/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as e, c as t, d as n, f as r, i, n as a, o, r as s, t as c } from "../LayoutSession-
|
|
2
|
-
import { _ as l, b as u, g as d, h as f, l as p, m, n as ee, t as h, v as g, y as te } from "../widgetLocales-
|
|
1
|
+
import { a as e, c as t, d as n, f as r, i, n as a, o, r as s, t as c } from "../LayoutSession-BJxMu1Df.js";
|
|
2
|
+
import { _ as l, b as u, g as d, h as f, l as p, m, n as ee, t as h, v as g, y as te } from "../widgetLocales-D-QYU_9U.js";
|
|
3
3
|
import { t as ne } from "../monthView-N8yDaTqZ.js";
|
|
4
4
|
import { a as _, c as re, d as ie, f as ae, i as oe, l as se, n as ce, o as v, r as le, s as ue, t as de, u as fe } from "../widgetFeatures-BM6u0u74.js";
|
|
5
5
|
import { a as y, c as pe, i as b, l as me, n as he, o as ge, r as _e, s as ve } from "../focusTrap-Br9Zfje0.js";
|
|
@@ -277,7 +277,7 @@ function Bt(e, t) {
|
|
|
277
277
|
}
|
|
278
278
|
//#endregion
|
|
279
279
|
//#region src/widget/WidgetStyles.css?raw
|
|
280
|
-
var Vt = "/* === 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: var(--tcw-font-features);\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 /* Clipped, not hidden: a box that hides its overflow still scrolls to what the keyboard lands on\n past its edge, and the whole widget slid aside until the next resize. Hidden where clip is unknown. */\n overflow: hidden;\n overflow: clip;\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: #918f8a;\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 /* The kinds of symbol in the symbol search (stock, futures, index, crypto, forex): hues as far\n * from the accent's blue and the up and down green and red as from each other (0.11 in OKLab at\n * the least, where 0.02 is a step the eye just sees), so a badge is never taken for the chart's\n * symbol, a match or a move; each readable on a tint of itself, on the selected row too. */\n --tcw-kind-1: #4cbedf;\n --tcw-kind-2: #e8a144;\n --tcw-kind-3: #ca8cff;\n --tcw-kind-4: #f387c1;\n --tcw-kind-5: #a5c45d;\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: 33px;\n --tcw-control-h-sm: 26px;\n --tcw-icon: 20px;\n --tcw-sidebar-w: 53px;\n --tcw-tool-h: 37px;\n --tcw-tool-icon: 26px;\n --tcw-menu-item-h: 33px;\n --tcw-icon-stroke: 1px;\n --tcw-font: -apple-system, BlinkMacSystemFont, 'Segoe UI Variable Text', '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: 500;\n --tcw-label-case: none;\n --tcw-label-tracking: 0em;\n --tcw-label-size: 11px;\n --tcw-border-w: 1px;\n --tcw-sep-w: 1px;\n --tcw-menu-shadow: 0 0 0 1px var(--tcw-divider), var(--tcw-shadow-lg);\n --tcw-dialog-shadow: 0 0 0 1px var(--tcw-divider), 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: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n /* The faces as drawn: a tag means something else in each face (in IBM Plex, ss01 is a one-storey a).\n * The `ui` option never sets it, so a rule of yours on .tcw-root turns on your face's own. */\n --tcw-font-features: normal;\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: #6a6e75;\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 /* The same hues, deep enough to read on paper. */\n --tcw-kind-1: #06596e;\n --tcw-kind-2: #855402;\n --tcw-kind-3: #8238b2;\n --tcw-kind-4: #a12673;\n --tcw-kind-5: #415500;\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/* With everything folded and still no room (a long symbol on a phone), the symbol gives way so\n \"more\" stays on the bar, a step at a time (`data-tcw-squeeze`). First its venue\n (\"HYPERLIQUID:xyz:\") is cut short before anything else shrinks, down to its first letter and an\n ellipsis, a gap keeping it off the ticker. That is 2em: a line's first letter is cut, never\n swapped for the ellipsis, so less shows a letter and a sliver (\"H.\"). The venue's column counts\n only those 2em in the button's smallest width, so the ticker stays whole and the buttons beside it\n give the rest. With room, the symbol shows as it always has. */\n.tcw-toolbar[data-tcw-squeeze='venue'] > .tcw-toolbar-symbol--venue {\n display: inline-grid;\n grid-template-columns: minmax(2em, max-content) auto;\n column-gap: var(--tcw-space-1);\n align-items: center;\n /* Shrinking is shared by width times this: the symbol takes it all until it is at its smallest. */\n flex-shrink: 1000;\n}\n\n.tcw-toolbar[data-tcw-squeeze='venue'] .tcw-toolbar-venue {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Then, with no room even for the ellipsis (a 320 phone in the Capsule look), the venue goes, the\n ticker whole; and last of all, the ticker is cut short. */\n.tcw-toolbar[data-tcw-squeeze='ticker'] .tcw-toolbar-venue,\n.tcw-toolbar[data-tcw-squeeze='cut'] .tcw-toolbar-venue {\n display: none;\n}\n\n.tcw-toolbar[data-tcw-squeeze='cut'] > .tcw-toolbar-symbol {\n min-width: 0;\n}\n\n.tcw-toolbar[data-tcw-squeeze='cut'] .tcw-toolbar-ticker {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\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 font-variant-numeric: tabular-nums;\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. Out to the menu's edges over\n its padding, and no further: past them, the menu scrolled a few px both ways. */\n.tcw-tf-custom {\n position: sticky;\n bottom: calc(-1 * var(--tcw-menu-pad));\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin: 4px calc(-1 * var(--tcw-menu-pad)) calc(-1 * var(--tcw-menu-pad));\n padding: 6px calc(var(--tcw-menu-pad) + 4px) 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-variant-numeric: tabular-nums;\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-label-size);\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 font-variant-numeric: tabular-nums;\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 white-space: nowrap;\n color: var(--tcw-text-dim);\n /* A see-through ground, as under the price legend's rows: lines across the plot run\n behind the text. A host sets --tcw-legend-ground (transparent: none). */\n background: var(--tcw-legend-ground, color-mix(in srgb, var(--tcw-bg) 72%, transparent));\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/* A compared symbol's name opens nothing. */\n.tcw-ind-legend-row--compare .tcw-ind-legend-name,\n.tcw-ind-legend-row--compare .tcw-ind-legend-name:hover {\n color: var(--tcw-text);\n cursor: default;\n}\n\n/* The values are one line of text: a narrow chart cuts the line, so the values\n before the cut stay whole and the one it falls in ends in an ellipsis. Values\n shrinking each on its own cut them all at once. */\n.tcw-ind-legend-values {\n display: block;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.tcw-ind-legend-values > * + * {\n margin-inline-start: var(--tcw-space-4);\n}\n\n/* Too narrow for a digit and an ellipsis (Bollinger's on a 320 phone, 6 px beside the buttons), the\n values would show a sliver: they hide, keeping their room so they come back with it, and the name\n reads alone. */\n.tcw-ind-legend-values--no-room {\n visibility: hidden;\n}\n\n/* A compare's line colour, as a short stroke of it before the name. */\n.tcw-ind-legend-swatch {\n flex: none;\n align-self: center;\n width: 10px;\n height: 3px;\n margin-inline-end: var(--tcw-space-2);\n border-radius: 1px;\n}\n\n.tcw-ind-legend-row--hidden .tcw-ind-legend-swatch,\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). Out of sight, not out of the\n page, so Tab reaches them in a row with nothing else to focus (a compare's) and a screen reader finds\n them; a button focused shows them all. */\n.tcw-ind-legend-actions {\n display: inline-flex;\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\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 position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip-path: none;\n}\n\n@media (hover: none) {\n .tcw-ind-legend-actions {\n position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip-path: none;\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/* The drawing tools' button and icon as drawn (the dock's rail has the same): never wider than\n their column less 8 px a side (a narrow `sizes.sidebar` of yours shrinks them), nor taller\n than a short column leaves room for (`--tcw-tool-fit`, set by toolFit.ts on the column); the\n icon at most four fifths of its button, as a compact look's 16 in 20. */\n.tcw-root, .tcw-sidebar {\n --tcw-tool-size: min(var(--tcw-tool-h), calc(var(--tcw-sidebar-w) - 16px), var(--tcw-tool-fit, 999px));\n --tcw-tool-icon-size: min(var(--tcw-tool-icon), calc(var(--tcw-tool-size) * 0.8));\n}\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 /* The buttons' own 1px margins at its ends make up the rest of the gap: as tall as its tools,\n 768 px high in the Print look, it doesn't scroll by those 2 px. */\n padding: calc(var(--tcw-space-3) - 1px) 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 /* The column's width, its button centred: the pointer on its way to the menu, which opens at\n the column's edge, stays over the group the whole way. */\n align-self: stretch;\n display: flex;\n justify-content: center;\n}\n\n.tcw-sidebar-btn {\n width: var(--tcw-tool-size);\n height: var(--tcw-tool-size);\n margin: 1px 0;\n /* The browser's button padding squeezed a glyph set straight in it (the cursor's) under its size. */\n padding: 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 flex: none;\n width: var(--tcw-tool-icon-size);\n height: var(--tcw-tool-icon-size);\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/* A group with more tools: a small triangle in the very corner of its button, pointing out. Not a\n dot, which the drawing tools' icons use for their anchors, and away from the icon, so it doesn't\n read as part of the tool. Right to left it sits in the other corner. */\n.tcw-multi-dot {\n position: absolute;\n inset-block-end: 1px;\n inset-inline-end: 1px;\n width: 5px;\n height: 5px;\n clip-path: polygon(100% 0, 100% 100%, 0 100%);\n background: var(--tcw-text-muted);\n opacity: 0.8;\n}\n[dir='rtl'] .tcw-multi-dot {\n clip-path: polygon(0 0, 100% 100%, 0 100%);\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: calc(var(--tcw-tool-size) * 0.618);\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 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-label-size);\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/* A text drawing's words typed in place, over its box on the chart; under any dialog. */\n.tcw-inline-text {\n position: fixed;\n inset: 0;\n z-index: 90;\n pointer-events: none;\n}\n.tcw-inline-text-input {\n position: absolute;\n box-sizing: border-box;\n margin: 0;\n border: 1px solid var(--tcw-accent);\n border-radius: var(--tcw-radius-xs);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n outline: none;\n overflow: hidden;\n resize: none;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n pointer-events: auto;\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/* The close sized from the title, so it holds its own beside it in every look: its target phi times\n the title (34 at 21), its icon root phi of it (27), whose cross, half the icon's grid, is about the\n title's capitals, its stroke near 2 px. At 16 the cross was 8 px of 1.2 px lines under a 21 px title.\n The negative margins keep the header as tall as before and the cross's edge at the text's edge. */\n.tcw-modal-close {\n --tcw-close-box: calc(var(--tcw-font-size-display) * 1.618);\n --tcw-close-icon: calc(var(--tcw-font-size-display) * 1.272);\n flex: none;\n width: var(--tcw-close-box);\n height: var(--tcw-close-box);\n margin-block: calc((var(--tcw-close-box) - var(--tcw-font-size-display) * 1.2) / -2);\n margin-inline-end: calc((var(--tcw-close-box) - var(--tcw-close-icon) / 2) / -2);\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-close:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-modal-close svg {\n width: var(--tcw-close-icon);\n height: var(--tcw-close-icon);\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-label-size);\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/* A number field's hint goes on a line of its own, under the field. */\n.tcw-settings-row--number {\n flex-wrap: wrap;\n}\n\n.tcw-settings-hint {\n flex-basis: 100%;\n padding-top: var(--tcw-space-2);\n color: var(--tcw-red);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.35;\n text-align: end;\n}\n\n/* Empty, it takes no room but stays rendered: a live region that appears with its text is often not read out. */\n.tcw-settings-hint:empty {\n padding-top: 0;\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 /* Hex letters vary in width in a sans face: a monospaced one keeps the codes one width. */\n font-family: ui-monospace, 'Cascadia Mono', 'SF Mono', Menlo, Consolas, monospace;\n font-variant-numeric: tabular-nums;\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}\n\n/* The bar holds the keyboard when a refit hides every button it could go to. */\n.tcw-statusbar:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-status-right {\n display: flex;\n align-items: center;\n gap: 14px;\n margin-inline-start: auto;\n /* Never narrower than what it holds, so the clock at its end stays whole: the range presets give way instead. */\n flex: none;\n white-space: nowrap;\n}\n\n/* Range presets + go to date, bottom left. The bar takes the room the rest leaves and\n clips what's past it; WidgetStatusBar.fit folds that under \"more\". Logical margins,\n so right to left it keeps its gap before the right group. */\n.tcw-range-bar {\n display: flex;\n align-items: center;\n gap: 1px;\n margin-block: -4px;\n margin-inline: -8px 12px;\n min-width: 0;\n overflow: hidden;\n}\n\n/* A narrow widget (a phone, a narrow column, a grid's cell): the range presets close up. */\n.tcw-root[data-tcw-narrow] .tcw-range-btn[data-range] {\n padding: 4px 5px;\n}\n\n/* What the bar has folded, and \"more\" while nothing is. */\n.tcw-statusbar [data-tcw-folded],\n.tcw-statusbar:not(.tcw-statusbar--folded) .tcw-range-more {\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.tcw-range-more {\n display: inline-grid;\n place-items: center;\n padding: 4px 6px;\n}\n\n.tcw-range-goto {\n margin-inline-start: 6px;\n}\n\n.tcw-range-goto svg,\n.tcw-range-more 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-variant-numeric: tabular-nums;\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 /* Across the list's grid: on its own it would land in the 2px gutter. */\n grid-column: 1 / -1;\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/*\n * A row's remove button shows on hover or focus, in a column of its own after\n * the numbers: over them, it hid the price and the change of the row the\n * keyboard was on.\n */\n.tcw-watchlist-remove {\n display: grid;\n place-items: center;\n width: var(--tcw-watchlist-remove);\n height: var(--tcw-watchlist-remove);\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 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/*\n * One grid for the head and the rows (each a subgrid of it), so the price,\n * the move and the change line up in columns from row to row. The columns\n * come from the script (`--tcw-watchlist-columns`): a sparkline and the\n * remove button each add one. The edges are columns too, a gutter each: a\n * subgrid's own padding would push its last cell past the panel.\n */\n.tcw-watchlist-list {\n --tcw-watchlist-remove: 20px;\n /* With the gap beside it, 12px from the panel's edge to the first and last cell. */\n --tcw-watchlist-gutter: 2px;\n flex: 1;\n overflow-y: auto;\n padding: 0 0 4px;\n display: grid;\n grid-template-columns: var(--tcw-watchlist-columns, var(--tcw-watchlist-gutter) minmax(0, 1fr) auto auto auto var(--tcw-watchlist-gutter));\n column-gap: 10px;\n align-content: start;\n}\n\n.tcw-watchlist-columns,\n.tcw-watchlist-row {\n grid-column: 1 / -1;\n display: grid;\n grid-template-columns: subgrid;\n align-items: center;\n}\n/* The cells start after the leading gutter; the rest follow in order. */\n.tcw-watchlist-columns > :first-child,\n.tcw-watchlist-row > :first-child {\n grid-column-start: 2;\n}\n\n/* The columns' names: small and quiet, held at the top as the rows scroll. */\n.tcw-watchlist-columns {\n position: sticky;\n top: 0;\n z-index: 1;\n height: 24px;\n background: var(--tcw-bg-surface);\n border-bottom: 1px solid var(--tcw-border);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n white-space: nowrap;\n}\n.tcw-watchlist-columns > :not(.tcw-watchlist-column-symbol) {\n text-align: end;\n}\n\n/* A line a symbol: its figures and nothing else. */\n.tcw-watchlist-row {\n position: relative;\n min-height: 28px;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n outline: none;\n}\n\n/* The mark of the row in use or under the keyboard: a bar at its start, in the leading gutter. */\n.tcw-watchlist-row::before {\n content: '';\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n width: 2px;\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}\n\n.tcw-watchlist-row.tcw-watchlist-active {\n background: var(--tcw-accent-soft);\n}\n\n.tcw-watchlist-row:focus-visible::before,\n.tcw-watchlist-row.tcw-watchlist-active::before {\n background: var(--tcw-accent);\n}\n\n.tcw-watchlist-symbol {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\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: 48px;\n height: 18px;\n align-self: center;\n}\n\n.tcw-watchlist-price,\n.tcw-watchlist-move,\n.tcw-watchlist-change {\n text-align: end;\n white-space: nowrap;\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight);\n color: var(--tcw-text-muted);\n}\n\n.tcw-watchlist-price {\n color: var(--tcw-text);\n}\n\n.tcw-watchlist-move.tcw-up,\n.tcw-watchlist-change.tcw-up {\n color: var(--tcw-green);\n}\n\n.tcw-watchlist-move.tcw-down,\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 bar ===\n * A transport over the foot of the main pane: step back / play / step\n * forward, where the replay is (its date and a track with the played part\n * filled), its pace (speed, step), and the ways out (pick another bar, back\n * to now). Only --tcw-* tokens; its sizes come from the look's own ladder.\n * The widget sets where it sits (--tcw-replay-foot, --tcw-replay-plot-*)\n * from the main pane, and the tier (data-fit) from the room it has.\n */\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-bar {\n /* Buttons are the look's controls; Play two small steps above them. */\n --tcw-replay-btn: var(--tcw-control-h);\n --tcw-replay-play: calc(var(--tcw-control-h) + 2 * var(--tcw-space-2));\n --tcw-replay-track-w: calc(var(--tcw-space-7) * 6);\n --tcw-replay-track-min: calc(var(--tcw-space-7) * 3);\n --tcw-replay-rail: var(--tcw-space-2);\n --tcw-replay-head-w: var(--tcw-space-2);\n --tcw-replay-head-h: var(--tcw-space-5);\n position: absolute;\n /* On the main pane's foot (over the volume, clear of the bottom panes), above the time axis without them. */\n bottom: calc(var(--tcw-replay-foot, 30px) + var(--tcw-space-4));\n inset-inline: var(--tcw-replay-plot-start, 0px) var(--tcw-replay-plot-end, 0px);\n /* Centred on the plot by its margins: an entrance on `transform` would undo a translate. */\n margin-inline: auto;\n box-sizing: border-box;\n width: max-content;\n max-width: calc(100% - var(--tcw-replay-plot-start, 0px) - var(--tcw-replay-plot-end, 0px) - 2 * var(--tcw-space-4));\n z-index: 25;\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n padding: var(--tcw-space-3);\n background: var(--tcw-bg-elevated);\n background: color-mix(in srgb, var(--tcw-bg-elevated) var(--tcw-surface-opacity, 100%), transparent);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n /* The look's menu shadow carries its hairline (Print, Terminal, Capsule): no border of its own on top. */\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.2;\n animation: tcw-sel-in var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n.tcw-replay-group,\n.tcw-replay-slot {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-2);\n min-width: 0;\n}\n.tcw-replay-bar [hidden] { display: none !important; }\n/* The step field on a single step: nothing there, no gap for it. */\n.tcw-replay-slot:empty { display: none; }\n\n/* Hairlines between the groups where the look draws separators (Print, Terminal); a gap in the others. */\n.tcw-replay-sep {\n flex: none;\n align-self: stretch;\n width: var(--tcw-sep-w);\n margin-block: var(--tcw-space-2);\n background: var(--tcw-divider);\n}\n\n/* --- Buttons --- */\n.tcw-replay-btn {\n flex: none;\n display: inline-grid;\n place-items: center;\n inline-size: var(--tcw-replay-btn);\n block-size: var(--tcw-replay-btn);\n padding: 0;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n cursor: pointer;\n transition:\n background-color 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}\n.tcw-replay-btn > svg,\n.tcw-replay-text-btn svg { width: var(--tcw-icon); height: var(--tcw-icon); flex: none; }\n.tcw-replay-btn:hover { background: var(--tcw-hover-bg); color: var(--tcw-text); }\n.tcw-replay-btn:active { background: var(--tcw-active-bg); transform: scale(0.94); }\n.tcw-replay-btn:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n\n/* Play: the one filled control. Its focus ring stands off the fill, or it would vanish into it. */\n.tcw-replay-btn.tcw-replay-play {\n inline-size: var(--tcw-replay-play);\n block-size: var(--tcw-replay-play);\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n}\n.tcw-replay-btn.tcw-replay-play:hover { background: var(--tcw-accent-hover); color: var(--tcw-accent-ink); }\n.tcw-replay-btn.tcw-replay-play:focus-visible {\n box-shadow: 0 0 0 var(--tcw-space-1) var(--tcw-bg-elevated), 0 0 0 calc(2 * var(--tcw-space-1)) var(--tcw-accent-line);\n}\n\n.tcw-replay-btn:disabled,\n.tcw-replay-text-btn:disabled,\n.tcw-replay-scrubber:disabled,\n.tcw-replay-speed:disabled { opacity: 0.4; cursor: default; transform: none; }\n/* Nothing left to play: a muted fill, not a faded accent that reads as pressed. */\n.tcw-replay-btn.tcw-replay-play:disabled { background: var(--tcw-active-bg); color: var(--tcw-text-muted); opacity: 1; }\n\n/* --- Where the replay is --- */\n.tcw-replay-timeline {\n flex: 1 1 auto;\n gap: var(--tcw-space-4);\n}\n.tcw-replay-time {\n flex: none;\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text);\n white-space: nowrap;\n}\n.tcw-replay-group[aria-busy='true'] .tcw-replay-time,\n.tcw-replay-group[aria-busy='true'] .tcw-replay-hint { color: var(--tcw-text-muted); }\n\n.tcw-root input[type='range'].tcw-replay-scrubber {\n --tcw-replay-rest: var(--tcw-border-strong);\n flex: 1 1 var(--tcw-replay-track-w);\n min-inline-size: var(--tcw-replay-track-min);\n inline-size: var(--tcw-replay-track-w);\n block-size: var(--tcw-replay-btn);\n margin: 0;\n padding: 0;\n appearance: none;\n -webkit-appearance: none;\n background: transparent;\n border: 0;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n/* Measured at its least: the bar's width with no slack in the track. */\n.tcw-replay-bar[data-measure] { max-width: none; animation: none; }\n.tcw-replay-bar[data-measure] input[type='range'].tcw-replay-scrubber { inline-size: var(--tcw-replay-track-min); flex: none; }\n.tcw-root input[type='range'].tcw-replay-scrubber:hover { --tcw-replay-rest: var(--tcw-text-muted); }\n.tcw-root input[type='range'].tcw-replay-scrubber:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n/* The played part in the accent, the rest a rail; Firefox fills it itself. */\n.tcw-root input[type='range'].tcw-replay-scrubber::-webkit-slider-runnable-track {\n block-size: var(--tcw-replay-rail);\n border-radius: var(--tcw-radius-xs);\n background: linear-gradient(to right, var(--tcw-accent) 0 var(--tcw-replay-done, 0%), var(--tcw-replay-rest) var(--tcw-replay-done, 0%) 100%);\n}\n.tcw-root input[type='range'].tcw-replay-scrubber::-moz-range-track { block-size: var(--tcw-replay-rail); border-radius: var(--tcw-radius-xs); background: var(--tcw-replay-rest); }\n.tcw-root input[type='range'].tcw-replay-scrubber::-moz-range-progress { block-size: var(--tcw-replay-rail); border-radius: var(--tcw-radius-xs); background: var(--tcw-accent); }\n/* A playhead, as the chart marks the replay's cut: a short upright in ink, rounded as the look rounds. */\n.tcw-root input[type='range'].tcw-replay-scrubber::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n inline-size: var(--tcw-replay-head-w);\n block-size: var(--tcw-replay-head-h);\n margin-top: calc((var(--tcw-replay-rail) - var(--tcw-replay-head-h)) / 2);\n border: 0;\n border-radius: var(--tcw-radius-xs);\n background: var(--tcw-text);\n box-shadow: 0 0 0 var(--tcw-space-1) var(--tcw-bg-elevated);\n transition: transform var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-root input[type='range'].tcw-replay-scrubber:hover::-webkit-slider-thumb,\n.tcw-root input[type='range'].tcw-replay-scrubber:active::-webkit-slider-thumb { transform: scaleY(1.25); }\n.tcw-root input[type='range'].tcw-replay-scrubber::-moz-range-thumb {\n inline-size: var(--tcw-replay-head-w);\n block-size: var(--tcw-replay-head-h);\n border: 0;\n border-radius: var(--tcw-radius-xs);\n background: var(--tcw-text);\n box-shadow: 0 0 0 var(--tcw-space-1) var(--tcw-bg-elevated);\n}\n\n/* --- Pace: speed and step, each a labelled field --- */\n.tcw-replay-chip {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-3);\n flex: none;\n}\n.tcw-replay-chip-label {\n font-size: var(--tcw-font-size-xs);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n white-space: nowrap;\n}\n.tcw-root .tcw-replay-chip select.tcw-replay-speed {\n block-size: var(--tcw-replay-btn);\n padding-block: 0;\n padding-inline-start: var(--tcw-space-4);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n}\n\n/* --- The ways out, and picking --- */\n.tcw-replay-text-btn {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-3);\n block-size: var(--tcw-replay-btn);\n padding-inline: var(--tcw-space-4);\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-weight: var(--tcw-weight);\n white-space: nowrap;\n cursor: pointer;\n transition: background-color var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease), transform var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-replay-text-btn:hover { background: var(--tcw-hover-bg); color: var(--tcw-text); }\n.tcw-replay-text-btn:active { background: var(--tcw-active-bg); transform: scale(0.97); }\n.tcw-replay-text-btn:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n/* Random bar: outlined, the one thing to press while picking. */\n.tcw-replay-text-btn.tcw-replay-ghost { border: var(--tcw-border-w) solid var(--tcw-border-strong); color: var(--tcw-text); }\n/* The close glyph is the phone's: on wider bars the words say it. */\n.tcw-replay-close-icon { display: none; }\n/* At the last bar, the way back to now is the next thing to do. */\n.tcw-replay-bar--ended .tcw-replay-realtime { background: var(--tcw-accent); color: var(--tcw-accent-ink); }\n.tcw-replay-bar--ended .tcw-replay-realtime:hover { background: var(--tcw-accent-hover); color: var(--tcw-accent-ink); }\n\n.tcw-replay-hint {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-3);\n padding-inline: var(--tcw-space-3);\n color: var(--tcw-text-dim);\n white-space: nowrap;\n}\n.tcw-replay-hint > svg { flex: none; width: var(--tcw-icon); height: var(--tcw-icon); color: var(--tcw-accent); }\n\n/* --- Narrower: the fields lose their captions (they stay their names) --- */\n.tcw-replay-bar:is([data-fit='compact'], [data-fit='stack']) .tcw-replay-chip-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/* --- A phone, or a narrow chart: two rows across the plot, where the replay is on top --- */\n.tcw-replay-bar[data-fit='stack'] {\n /* Touch targets: 40 px (44 for Play) at least, as the toolbar's on a phone. */\n --tcw-replay-btn: max(40px, var(--tcw-control-h));\n --tcw-replay-play: max(44px, calc(var(--tcw-control-h) + 2 * var(--tcw-space-2)));\n inset-inline: var(--tcw-space-4);\n width: auto;\n max-width: none;\n margin-inline: 0;\n flex-wrap: wrap;\n gap: var(--tcw-space-2);\n}\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-sep { display: none; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-timeline {\n order: -2;\n /* The first row, beside the close button; the rest wraps below. */\n flex: 1 1 calc(100% - var(--tcw-replay-btn) - 2 * var(--tcw-space-2));\n box-sizing: border-box;\n padding-inline-start: var(--tcw-space-3);\n}\n.tcw-replay-bar[data-fit='stack'] input[type='range'].tcw-replay-scrubber { block-size: var(--tcw-menu-item-h); min-inline-size: 0; }\n/* Back to realtime closes the bar from the first row, a glyph touch users know. */\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-exits { display: contents; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-realtime { order: -1; inline-size: var(--tcw-replay-btn); padding: 0; justify-content: center; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-realtime .tcw-replay-text { display: none; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-close-icon { display: inline-flex; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-transport { flex: 1 0 auto; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-hint { white-space: normal; flex: 1 0 100%; padding-block: var(--tcw-space-2); }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-picking { display: contents; }\n\n/* While the bar holds the plot's foot, what lives there makes room: the toasts and the phone's drawing button. */\n.tcw-root[data-tcw-replay] > .tcw-toast:not(.tcw-toast-over) {\n bottom: calc(var(--tcw-replay-lift, 0px) + var(--tcw-space-4));\n}\n.tcw-root[data-tcw-narrow][data-tcw-replay] > .tcw-body > .tcw-sidebar-fab {\n bottom: calc(var(--tcw-replay-lift, 0px) + var(--tcw-space-4));\n}\n\n@media (forced-colors: active) {\n .tcw-replay-bar { border: 1px solid CanvasText; }\n .tcw-replay-btn.tcw-replay-play { border: 1px solid ButtonText; }\n .tcw-root input[type='range'].tcw-replay-scrubber::-webkit-slider-runnable-track { background: GrayText; }\n .tcw-root input[type='range'].tcw-replay-scrubber::-webkit-slider-thumb { background: Highlight; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .tcw-replay-bar { animation: none; }\n .tcw-replay-btn,\n .tcw-replay-text-btn,\n .tcw-root input[type='range'].tcw-replay-scrubber::-webkit-slider-thumb { transition: none; }\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-tool-size));\n height: max(40px, var(--tcw-tool-size));\n }\n .tcw-modal {\n width: 94vw;\n border-radius: var(--tcw-dialog-radius);\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-root[data-tcw-replay] .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/* A compare: its colour and symbol, then how it is compared, taking the room left before its button. */\n.tcw-tree-compare {\n justify-content: flex-start;\n}\n.tcw-tree-compare .tcw-tree-name {\n flex: 0 1 auto;\n}\n.tcw-tree-compare .tcw-tree-del {\n flex: none;\n margin-inline-start: auto;\n}\n.tcw-tree-way {\n flex: 1 1 0;\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-text-dim);\n font-size: var(--tcw-font-size-xs);\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/* A drawing row's grip: dragged, it moves the drawing up or down the order. */\n.tcw-tree-btn.tcw-tree-grip {\n flex: none;\n cursor: grab;\n touch-action: none;\n}\n.tcw-tree-row:not(:hover) .tcw-tree-grip:not(:focus-visible) {\n opacity: 0.45;\n}\n/* The row a dragged drawing would take the place of. */\n.tcw-tree-row.tcw-tree-drop {\n box-shadow: inset 0 0 0 1px var(--tcw-accent);\n}\n/* A drawing's name selects it on the chart. */\n.tcw-tree-name.tcw-tree-pick {\n flex: 1 1 auto;\n cursor: pointer;\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 /* Frosted with the other menus (`ui.blur` above 0): the chart under it blurred, not sharp behind its words. */\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\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, a count, and the mark of a submenu, at the row's end. */\n.tcw-context-key, .tcw-context-count {\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/* The fill picker: a square, where the line colour is a dot. */\n.tcw-sel-fill { border-radius: 3px; }\n/* The text colour picker: a letter over a bar in the text's colour. */\n.tcw-sel-text {\n font-weight: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size-sm);\n line-height: 1;\n padding-bottom: 1px;\n border-bottom: 3px solid var(--c, currentColor);\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/* Your items keep their width (the range presets fold for them), and on the left a gap\n before the right group, whose auto margin closes up when the bar is full. */\n.tcw-status-host { display: flex; align-items: center; gap: 10px; flex: none; }\n.tcw-statusbar > .tcw-status-host { margin-inline-end: var(--tcw-space-5); }\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-move,\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/* The icons' lines (`ui.iconStroke`): one width at every icon size, on the widget and in its\n * portal, when the look sets one; otherwise as the icon set draws them. */\n[data-tcw-icon-stroke='set'] .tc-icon {\n stroke-width: var(--tcw-icon-stroke);\n}\n[data-tcw-icon-stroke='set'] .tc-icon > * {\n vector-effect: non-scaling-stroke;\n}\n/* Its filled dots (a drawing tool's anchors) were sized for the drawn line: smaller with the fine\n one, so they don't outweigh it. */\n[data-tcw-icon-stroke='set'] .tc-icon > circle[stroke='none'] {\n transform-box: fill-box;\n transform-origin: center;\n transform: scale(0.7);\n}\n/* A small icon (the legend's, a pin, 10 to 13 px) at most 1 px, so it isn't heavier than the\n rest: drawn as it is, its line was under 1 px. */\n[data-tcw-icon-stroke='set'] .tc-icon:is([width='10'], [width='11'], [width='12'], [width='13']) {\n stroke-width: min(var(--tcw-icon-stroke), 1px);\n}\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.tcw-dropdown-trigger[data-role='charttype'] svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\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 font-variant-numeric: tabular-nums;\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/* The market's status in a word (\"Closed\"), when even with everything folded under \"more\"\n the bar has no room: the full words are left to screen readers and the tooltip. */\n.tcw-status-market-short {\n display: none;\n}\n.tcw-statusbar--short-market .tcw-status-market-short {\n display: inline;\n}\n.tcw-root[data-tcw-narrow] .tcw-status-indicator > span:not(.tcw-status-dot),\n.tcw-statusbar--short-market .tcw-status-market-text {\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), a host's left-hand ones last, and `--icons` drops the menus'\n labels and the interval buttons. 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 /* Over the plot, in from its left edge (the widget sets where it starts): the\n price axis stays on the chart's right in either direction, so a\n right-to-left widget keeps the button on the left too, off the axis. */\n left: calc(var(--tcw-fab-plot-left, 0px) + 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", Ht = "/* === 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='%23918f8a' 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='%23918f8a' 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='%236a6e75' 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='%236a6e75' 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 * The browser's control font resets the OpenType features, so --tcw-font-features\n * set on .tcw-root reaches every button and field only through this. */\n:where(.tcw-root) :where(input, select, textarea, button) {\n font-family: inherit;\n font-weight: inherit;\n letter-spacing: inherit;\n font-feature-settings: 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:not([type='checkbox']),\n .tcw-settings-number\n):is([aria-invalid='true']):is(*, :hover, :focus) {\n /* As specific as the hover rule (its list holds the same :not) and later, so a wrong value stays red\n 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/* A select laid out left to right inside a right-to-left widget (the chart's\n * own area is LTR, the replay's figures too) keeps its chevron on the right,\n * where its padding is. */\n.tcw-root[dir='rtl'] [dir='ltr'] select:not([multiple]):not([size]),\n.tcw-root[dir='rtl'] select[dir='ltr']:not([multiple]):not([size]) {\n background-position: right 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", Ut = "/* === 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/* A dialog's search is a band across it, under its title, with a rule beneath: no box, no ring when\n focused. The caret and the dialog itself say where typing goes; a lit box around the one field a\n search dialog has only shouted it. As tall as the field and its margins were, set in as the title. */\n.tcw-ip-search,\n.tcw-ss-search {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n flex: none;\n height: calc(var(--tcw-control-h) + 2 * var(--tcw-space-4));\n margin: 0;\n padding: 0 var(--tcw-space-6);\n border: none;\n border-bottom: 1px solid var(--tcw-divider);\n border-radius: 0;\n background: transparent;\n color: var(--tcw-text-muted);\n transition: color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n/* Focused, only the magnifier takes the text's colour. */\n.tcw-ip-search:focus-within,\n.tcw-ss-search:focus-within {\n color: var(--tcw-text);\n}\n\n/* The magnifier root phi of the typed text (19 at 15), as the close is of the title. */\n.tcw-ip-search svg,\n.tcw-ss-search svg {\n flex: none;\n width: calc(var(--tcw-font-size-lg) * 1.272);\n height: calc(var(--tcw-font-size-lg) * 1.272);\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-lg);\n}\n\n/* In forced colours the muted and the text's colour may be one: the band keeps an outline there,\n so the field is still found. */\n@media (forced-colors: active) {\n .tcw-ip-search:focus-within,\n .tcw-ss-search:focus-within {\n outline: 2px solid Highlight;\n outline-offset: -2px;\n }\n}\n\n/* The browser's clear button for a search field (bold, and blue in Chrome's light scheme) as the\n icon set's close, in the muted text, the text's on hover. A mask, so it takes the colour. */\n.tcw-ip-search input::-webkit-search-cancel-button,\n.tcw-ss-search input::-webkit-search-cancel-button {\n -webkit-appearance: none;\n appearance: none;\n width: calc(var(--tcw-font-size-lg) * 1.272);\n height: calc(var(--tcw-font-size-lg) * 1.272);\n background: var(--tcw-text-muted);\n -webkit-mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 6L18 18M18 6L6 18' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='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 24 24'%3E%3Cpath d='M6 6L18 18M18 6L6 18' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round'/%3E%3C/svg%3E\") center / contain no-repeat;\n cursor: pointer;\n}\n\n.tcw-ip-search input::-webkit-search-cancel-button:hover,\n.tcw-ss-search input::-webkit-search-cancel-button:hover {\n background: var(--tcw-text);\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}\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-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/* A box ticked beside other controls in a row (bold, italics, a text box's background). */\n.tcw-inline-check {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-2);\n cursor: pointer;\n white-space: nowrap;\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 still as the indicators dialog: a fixed height while a search shortens the list. As wide as it,\n 610, up to a screen 1597 wide; past that a phi share of the screen (1 / phi^2), up to 987, the next\n Fibonacci number: about 733 at 1920, 978 at 2560, room for ids with a venue before the ticker. */\n.tcw-modal.tcw-ss {\n width: min(987px, max(610px, 38.2vw));\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 heads' height, which the rows scroll in below; the room after a symbol before its name. */\n.tcw-modal.tcw-ss {\n --tcw-ss-head-h: var(--tcw-control-h);\n --tcw-ss-name-gap: var(--tcw-space-4);\n}\n\n[dir='rtl'] .tcw-ss-symbol {\n padding-right: 0;\n padding-left: var(--tcw-ss-name-gap);\n}\n\n/* Over the list: the kinds the rows come in, and their exchanges once there are two. The exchanges sit\n on the tabs' first line when the tabs wrap, not between their lines. */\n.tcw-ss-filters {\n display: flex;\n align-items: flex-start;\n gap: var(--tcw-space-4);\n flex: none;\n margin: 0 var(--tcw-space-6) var(--tcw-space-4);\n}\n\n/* The kinds as tabs (All, stock, crypto…), showing the one picked as the look shows a choice. */\n.tcw-ss-kinds {\n display: flex;\n flex-wrap: wrap;\n flex: 1;\n min-width: 0;\n gap: var(--tcw-space-2);\n}\n\n/* Where they scroll in one line, the tabs fade out at an end with more past it, so a tab cut there\n reads as more to scroll to. A mask: only its alpha counts, so what shows is drawn in the text's\n colour, which is opaque, and what fades goes to transparent. */\n.tcw-ss-kinds[data-more] {\n --tcw-ss-shown: currentColor;\n --tcw-ss-fade-start: var(--tcw-ss-shown);\n --tcw-ss-fade-end: var(--tcw-ss-shown);\n -webkit-mask-image: linear-gradient(to right, var(--tcw-ss-fade-start), var(--tcw-ss-shown) var(--tcw-space-6), var(--tcw-ss-shown) calc(100% - var(--tcw-space-6)), var(--tcw-ss-fade-end));\n mask-image: linear-gradient(to right, var(--tcw-ss-fade-start), var(--tcw-ss-shown) var(--tcw-space-6), var(--tcw-ss-shown) calc(100% - var(--tcw-space-6)), var(--tcw-ss-fade-end));\n}\n\n[dir='rtl'] .tcw-ss-kinds[data-more] {\n -webkit-mask-image: linear-gradient(to left, var(--tcw-ss-fade-start), var(--tcw-ss-shown) var(--tcw-space-6), var(--tcw-ss-shown) calc(100% - var(--tcw-space-6)), var(--tcw-ss-fade-end));\n mask-image: linear-gradient(to left, var(--tcw-ss-fade-start), var(--tcw-ss-shown) var(--tcw-space-6), var(--tcw-ss-shown) calc(100% - var(--tcw-space-6)), var(--tcw-ss-fade-end));\n}\n\n.tcw-ss-kinds[data-more~='start'] {\n --tcw-ss-fade-start: transparent;\n}\n\n.tcw-ss-kinds[data-more~='end'] {\n --tcw-ss-fade-end: transparent;\n}\n\n.tcw-ss-type {\n flex: none;\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-5);\n border: none;\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 transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n/* A feed's words as it wrote them (\"Cổ phiếu\" stays so), only the first letter raised. */\n.tcw-ss-type::first-letter {\n text-transform: uppercase;\n}\n\n.tcw-ss-type:hover {\n background: var(--tcw-tab-hover);\n color: var(--tcw-text);\n}\n\n.tcw-ss-type[aria-pressed='true'] {\n background: var(--tcw-tab-on-bg);\n color: var(--tcw-tab-on-fg);\n box-shadow: inset 0 calc(-1 * var(--tcw-tab-line)) 0 var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\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 exchanges at the end of the row, as wide as the longest up to 144. */\n.tcw-root .tcw-ss-exchange-filter {\n flex: none;\n width: auto;\n max-width: 144px;\n height: var(--tcw-control-h);\n margin-inline-start: auto;\n padding-block: 0;\n font-size: var(--tcw-font-size-sm);\n}\n\n/* What scrolls is one grid, and the heads, the list and each row are its subgrids, so a column is\n as wide in every row: the badge, the symbol up to a quarter of the list (144 at 610, 233 in a wide\n dialog, the next Fibonacci number), the name the rest, the kind up to 89, the exchange up to 144\n ('XYZ · HYPERLIQUID' whole), the check. An empty cell keeps its column. */\n.tcw-ss-results {\n display: grid;\n grid-template-columns: max-content fit-content(clamp(144px, 25%, 233px)) minmax(0, 1fr) fit-content(89px) fit-content(144px) auto;\n align-content: start;\n column-gap: var(--tcw-space-4);\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n /* A row the arrows reach scrolls in below the heads, not under them. */\n scroll-padding-block-start: calc(var(--tcw-ss-head-h) + var(--tcw-space-2));\n padding: 0 var(--tcw-space-4) var(--tcw-space-5);\n}\n\n/* Comparing, under a heading of its own as well. */\n.tcw-ss--compare .tcw-ss-results {\n scroll-padding-block-start: calc(var(--tcw-ss-head-h) + var(--tcw-space-5) + var(--tcw-space-2) + var(--tcw-font-size-xs) * 1.5);\n}\n\n.tcw-ss-results > * {\n grid-column: 1 / -1;\n}\n\n.tcw-ss-columns,\n.tcw-ss-list,\n.tcw-ss-added,\n.tcw-ss-row,\n.tcw-ss-added-row {\n display: grid;\n grid-column: 1 / -1;\n /* Where subgrids aren't drawn: fixed columns, the rest sized row by row. */\n grid-template-columns: var(--tcw-control-h-sm) 89px minmax(0, 1fr) auto auto auto;\n grid-template-columns: subgrid;\n align-items: center;\n column-gap: inherit;\n}\n\n/* The heads stay at the top while the rows scroll under them. */\n.tcw-ss-columns {\n position: sticky;\n top: 0;\n z-index: 2;\n height: var(--tcw-ss-head-h);\n margin-bottom: var(--tcw-space-2);\n padding: 0 var(--tcw-space-4);\n background: var(--tcw-bg-elevated);\n box-shadow: 0 1px 0 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 white-space: nowrap;\n}\n\n.tcw-ss-head {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.tcw-ss-head:nth-child(1) { grid-column: 1; }\n.tcw-ss-head:nth-child(2) { grid-column: 2; }\n.tcw-ss-head:nth-child(3) { grid-column: 3; }\n.tcw-ss-head:nth-child(4) { grid-column: 4; justify-self: end; }\n.tcw-ss-head:nth-child(5) { grid-column: 5; justify-self: end; }\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 logo, or the ticker's first letter on a tint of its kind's colour, cornered as the look's tags. */\n.tcw-ss-badge {\n --tcw-ss-kind: var(--tcw-text-dim);\n grid-column: 1;\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n overflow: hidden;\n border-radius: var(--tcw-tag-radius);\n background: color-mix(in srgb, var(--tcw-ss-kind) 16%, transparent);\n color: var(--tcw-ss-kind);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n line-height: 1;\n}\n\n.tcw-ss-badge[data-kind='1'] { --tcw-ss-kind: var(--tcw-kind-1); }\n.tcw-ss-badge[data-kind='2'] { --tcw-ss-kind: var(--tcw-kind-2); }\n.tcw-ss-badge[data-kind='3'] { --tcw-ss-kind: var(--tcw-kind-3); }\n.tcw-ss-badge[data-kind='4'] { --tcw-ss-kind: var(--tcw-kind-4); }\n.tcw-ss-badge[data-kind='5'] { --tcw-ss-kind: var(--tcw-kind-5); }\n\nimg.tcw-ss-badge {\n background: transparent;\n object-fit: cover;\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. Padding on the name's side, counted in the column, keeps the longest id a\n gap twice the columns' from the name (\"BINANCE:BTCUSDT\" ran into \"BTC perpetual\"). The cell is\n left to right itself, so the side is named, not its end. */\n.tcw-ss-symbol {\n grid-column: 2;\n display: flex;\n justify-self: start;\n max-width: 100%;\n min-width: 0;\n padding-right: var(--tcw-ss-name-gap);\n overflow: hidden;\n color: var(--tcw-text);\n font-family: var(--tcw-font-mono);\n font-weight: var(--tcw-weight-strong);\n white-space: nowrap;\n}\n\n/* A venue before the ticker (\"BINANCE:\"), dim, is what a narrow column shortens; the ticker never\n shrinks (a share of a pixel would end it in an ellipsis), and is cut only when it alone is wider.\n A gap keeps the venue's ellipsis off the ticker (\"HYPERLIQ… GOLD\"). */\n.tcw-ss-venue {\n flex: 0 1 auto;\n min-width: 0;\n margin-inline-end: var(--tcw-space-1);\n overflow: hidden;\n color: var(--tcw-text-muted);\n font-weight: var(--tcw-weight);\n text-overflow: ellipsis;\n}\n\n.tcw-ss-ticker {\n flex: none;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\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 grid-column: 3;\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/* The kind as the feed wrote it, and the exchange, each at the end of its column. */\n.tcw-ss-kind,\n.tcw-ss-exchange {\n justify-self: end;\n max-width: 100%;\n min-width: 0;\n overflow: hidden;\n font-size: var(--tcw-font-size-xs);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-ss-kind {\n grid-column: 4;\n color: var(--tcw-text-muted);\n}\n\n.tcw-ss-exchange {\n grid-column: 5;\n color: var(--tcw-text-dim);\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 in the last column. */\n.tcw-ss-check {\n grid-column: 6;\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\", under the heads while their rows scroll. */\n.tcw-ss-heading {\n position: sticky;\n top: var(--tcw-ss-head-h);\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 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, across the name, kind and exchange; the line's colour, where it has one of its own, where the badges are. */\n.tcw-ss-way-cell {\n grid-column: 3 / 6;\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n min-width: 0;\n}\n\n.tcw-ss-swatch {\n grid-column: 1;\n justify-self: center;\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 grid-column: 6;\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/* Under a list cut short: how many more match, for typing to narrow. */\n.tcw-ss-more {\n padding: var(--tcw-space-4);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.5;\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 up to 89\n wide. The kind's column goes (the badge's colour still tells it), the tabs scroll in one line, and\n a row is a finger's height. */\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 /* The column's room goes to the ticker; the columns' own gap is enough here. */\n --tcw-ss-name-gap: 0px;\n }\n\n .tcw-ss-way,\n .tcw-ss-filters {\n margin-inline: var(--tcw-space-4);\n }\n\n .tcw-ss-kinds {\n flex-wrap: nowrap;\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n .tcw-ss-kinds::-webkit-scrollbar {\n display: none;\n }\n\n .tcw-root .tcw-ss-exchange-filter {\n max-width: 110px;\n }\n\n /* The ticker is the row's key: its column as wide as the widest ticker, up to 144 or 38.2% of the\n row, and the name gives way first. The exchange's up to 55, each cut in its own row. */\n .tcw-ss-results {\n grid-template-columns: max-content fit-content(min(144px, 38.2%)) minmax(0, 1fr) fit-content(55px) auto;\n }\n\n /* A venue counts for nothing in that width (its own is 0): it shows, dim and shortened, in what\n its ticker leaves, if that is 2em, a letter and an ellipsis as on the toolbar. With less, it\n wraps to a second line the cell clips, never a sliver (\"H.GOLD\"). The ticker comes first in the\n line, laid from the end, so it is the one that stays, at the column's start when alone. */\n .tcw-ss-symbol {\n justify-self: stretch;\n flex-direction: row-reverse;\n flex-wrap: wrap;\n justify-content: flex-end;\n align-content: flex-start;\n height: 1lh;\n }\n\n .tcw-ss-ticker {\n order: -1;\n }\n\n .tcw-ss-venue {\n flex: 1 1 2em;\n width: 0;\n }\n\n /* The head over the exchanges reads whole, over the gap before it if it must. */\n .tcw-ss-head:nth-child(5) {\n overflow: visible;\n }\n\n .tcw-ss-columns,\n .tcw-ss-list,\n .tcw-ss-added,\n .tcw-ss-row,\n .tcw-ss-added-row {\n grid-template-columns: var(--tcw-control-h-sm) 89px minmax(0, 1fr) auto auto;\n grid-template-columns: subgrid;\n }\n\n .tcw-ss-kind,\n .tcw-ss-head:nth-child(4) {\n display: none;\n }\n\n .tcw-ss-exchange,\n .tcw-ss-head:nth-child(5) {\n grid-column: 4;\n }\n\n .tcw-ss-check,\n .tcw-ss-remove {\n grid-column: 5;\n }\n\n .tcw-ss-way-cell {\n grid-column: 3 / 5;\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}\n\n/* Two columns as tall as their groups, inside the box that scrolls: on the box itself, of a fixed\n height, the groups past its foot went into columns to the side, out of reach. */\n.tcw-hotkey-columns {\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-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}\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}\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 /* The accent fill's ink reads on the red too: dark on the dark theme's, white on the light's. */\n color: var(--tcw-accent-ink);\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 padding-inline: var(--tcw-space-4);\n }\n\n .tcw-hotkey-columns {\n columns: 1;\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-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", Wt = "/* === 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-tool-size);\n height: var(--tcw-tool-size);\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-tool-icon-size);\n height: var(--tcw-tool-icon-size);\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's header: 34 tall (21 + 13), or a control's height where that is more, and the rule under\n it. Its height and the page's scroll padding are both these, so they never part. */\n.tcw-dock-page {\n --tcw-dock-head-h: max(calc(var(--tcw-space-6) + var(--tcw-space-5)), var(--tcw-control-h));\n --tcw-dock-head-rule: 1px;\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 /* A row the keyboard moves to scrolls in below the header and its rule, not under them. */\n scroll-padding-block-start: calc(var(--tcw-dock-head-h) + var(--tcw-dock-head-rule));\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. */\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: var(--tcw-dock-head-h);\n margin: 0;\n padding-block: 0;\n padding-inline: var(--tcw-space-5) var(--tcw-space-3);\n border-bottom: var(--tcw-dock-head-rule) 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. It scrolls as a page\n (no overflow of its own here: this rule, as specific as the page's and later, would win). */\n.tcw-dock-panel > .tcw-watchlist {\n width: auto;\n border-inline-start: none;\n box-shadow: none;\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", Gt = 0, Kt = "tcw-styles";
|
|
280
|
+
var Vt = "/* === 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: var(--tcw-font-features);\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 /* Clipped, not hidden: a box that hides its overflow still scrolls to what the keyboard lands on\n past its edge, and the whole widget slid aside until the next resize. Hidden where clip is unknown. */\n overflow: hidden;\n overflow: clip;\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: #918f8a;\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 /* The kinds of symbol in the symbol search (stock, futures, index, crypto, forex): hues as far\n * from the accent's blue and the up and down green and red as from each other (0.11 in OKLab at\n * the least, where 0.02 is a step the eye just sees), so a badge is never taken for the chart's\n * symbol, a match or a move; each readable on a tint of itself, on the selected row too. */\n --tcw-kind-1: #4cbedf;\n --tcw-kind-2: #e8a144;\n --tcw-kind-3: #ca8cff;\n --tcw-kind-4: #f387c1;\n --tcw-kind-5: #a5c45d;\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: 33px;\n --tcw-control-h-sm: 26px;\n --tcw-icon: 20px;\n --tcw-sidebar-w: 42px;\n --tcw-tool-h: 36px;\n --tcw-tool-icon: 26px;\n --tcw-menu-item-h: 33px;\n --tcw-icon-stroke: 1px;\n --tcw-font: -apple-system, BlinkMacSystemFont, 'Segoe UI Variable Text', '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: 500;\n --tcw-label-case: none;\n --tcw-label-tracking: 0em;\n --tcw-label-size: 11px;\n --tcw-border-w: 1px;\n --tcw-sep-w: 1px;\n --tcw-menu-shadow: 0 0 0 1px var(--tcw-divider), var(--tcw-shadow-lg);\n --tcw-dialog-shadow: 0 0 0 1px var(--tcw-divider), 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: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n /* The faces as drawn: a tag means something else in each face (in IBM Plex, ss01 is a one-storey a).\n * The `ui` option never sets it, so a rule of yours on .tcw-root turns on your face's own. */\n --tcw-font-features: normal;\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: #6a6e75;\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 /* The same hues, deep enough to read on paper. */\n --tcw-kind-1: #06596e;\n --tcw-kind-2: #855402;\n --tcw-kind-3: #8238b2;\n --tcw-kind-4: #a12673;\n --tcw-kind-5: #415500;\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/* With everything folded and still no room (a long ticker on a phone), the ticker is cut short so\n \"more\" stays on the bar (`data-tcw-squeeze`). The button shows the ticker alone: a venue before it\n (\"HYPERLIQUID:xyz:\") is the legend's and the tooltip's to name. */\n.tcw-toolbar[data-tcw-squeeze='cut'] > .tcw-toolbar-symbol {\n min-width: 0;\n}\n\n.tcw-toolbar[data-tcw-squeeze='cut'] .tcw-toolbar-ticker {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\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 font-variant-numeric: tabular-nums;\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. Out to the menu's edges over\n its padding, and no further: past them, the menu scrolled a few px both ways. */\n.tcw-tf-custom {\n position: sticky;\n bottom: calc(-1 * var(--tcw-menu-pad));\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin: 4px calc(-1 * var(--tcw-menu-pad)) calc(-1 * var(--tcw-menu-pad));\n padding: 6px calc(var(--tcw-menu-pad) + 4px) 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-variant-numeric: tabular-nums;\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-label-size);\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 font-variant-numeric: tabular-nums;\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 white-space: nowrap;\n color: var(--tcw-text-dim);\n /* A see-through ground, as under the price legend's rows: lines across the plot run\n behind the text. A host sets --tcw-legend-ground (transparent: none). */\n background: var(--tcw-legend-ground, color-mix(in srgb, var(--tcw-bg) 72%, transparent));\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/* A compared symbol's name opens nothing. */\n.tcw-ind-legend-row--compare .tcw-ind-legend-name,\n.tcw-ind-legend-row--compare .tcw-ind-legend-name:hover {\n color: var(--tcw-text);\n cursor: default;\n}\n\n/* The values are one line of text: a narrow chart cuts the line, so the values\n before the cut stay whole and the one it falls in ends in an ellipsis. Values\n shrinking each on its own cut them all at once. */\n.tcw-ind-legend-values {\n display: block;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.tcw-ind-legend-values > * + * {\n margin-inline-start: var(--tcw-space-4);\n}\n\n/* Too narrow for a digit and an ellipsis (Bollinger's on a 320 phone, 6 px beside the buttons), the\n values would show a sliver: they hide, keeping their room so they come back with it, and the name\n reads alone. */\n.tcw-ind-legend-values--no-room {\n visibility: hidden;\n}\n\n/* A compare's line colour, as a short stroke of it before the name. */\n.tcw-ind-legend-swatch {\n flex: none;\n align-self: center;\n width: 10px;\n height: 3px;\n margin-inline-end: var(--tcw-space-2);\n border-radius: 1px;\n}\n\n.tcw-ind-legend-row--hidden .tcw-ind-legend-swatch,\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). Out of sight, not out of the\n page, so Tab reaches them in a row with nothing else to focus (a compare's) and a screen reader finds\n them; a button focused shows them all. */\n.tcw-ind-legend-actions {\n display: inline-flex;\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\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 position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip-path: none;\n}\n\n@media (hover: none) {\n .tcw-ind-legend-actions {\n position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip-path: none;\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/* The drawing tools' button and icon as drawn (the dock's rail has the same): never wider than\n their column less 3 px a side (a narrow `sizes.sidebar` of yours shrinks them), nor taller\n than a short column leaves room for (`--tcw-tool-fit`, set by toolFit.ts on the column); the\n icon at most four fifths of its button, as a compact look's 16 in 20. */\n.tcw-root, .tcw-sidebar {\n --tcw-tool-size: min(var(--tcw-tool-h), calc(var(--tcw-sidebar-w) - 6px), var(--tcw-tool-fit, 999px));\n --tcw-tool-icon-size: min(var(--tcw-tool-icon), calc(var(--tcw-tool-size) * 0.8));\n}\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 /* The buttons' own 1px margins at its ends make up the rest of the gap: as tall as its tools,\n 768 px high in the Print look, it doesn't scroll by those 2 px. */\n padding: calc(var(--tcw-space-3) - 1px) 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 /* The column's width, its button centred: the pointer on its way to the menu, which opens at\n the column's edge, stays over the group the whole way. */\n align-self: stretch;\n display: flex;\n justify-content: center;\n}\n\n.tcw-sidebar-btn {\n width: var(--tcw-tool-size);\n height: var(--tcw-tool-size);\n margin: 1px 0;\n /* The browser's button padding squeezed a glyph set straight in it (the cursor's) under its size. */\n padding: 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 flex: none;\n width: var(--tcw-tool-icon-size);\n height: var(--tcw-tool-icon-size);\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/* A group with more tools: a small triangle in the very corner of its button, pointing out. Not a\n dot, which the drawing tools' icons use for their anchors, and away from the icon, so it doesn't\n read as part of the tool. Right to left it sits in the other corner. */\n.tcw-multi-dot {\n position: absolute;\n inset-block-end: 1px;\n inset-inline-end: 1px;\n width: 5px;\n height: 5px;\n clip-path: polygon(100% 0, 100% 100%, 0 100%);\n background: var(--tcw-text-muted);\n opacity: 0.8;\n}\n[dir='rtl'] .tcw-multi-dot {\n clip-path: polygon(0 0, 100% 100%, 0 100%);\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: calc(var(--tcw-tool-size) * 0.618);\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 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-label-size);\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/* A kind's name in a menu of several, set as a menu's own name is. */\n.tcw-flyout-heading {\n text-transform: var(--tcw-label-case);\n font-size: var(--tcw-label-size);\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/* A hairline over each kind but the first sets them apart. */\n.tcw-flyout-row + .tcw-flyout-heading {\n border-top: 1px solid var(--tcw-border);\n margin-top: var(--tcw-space-2);\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/* A text drawing's words typed in place, over its box on the chart; under any dialog. */\n.tcw-inline-text {\n position: fixed;\n inset: 0;\n z-index: 90;\n pointer-events: none;\n}\n.tcw-inline-text-input {\n position: absolute;\n box-sizing: border-box;\n margin: 0;\n border: 1px solid var(--tcw-accent);\n border-radius: var(--tcw-radius-xs);\n background: var(--tcw-bg-elevated);\n box-shadow: var(--tcw-menu-shadow);\n outline: none;\n overflow: hidden;\n resize: none;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n pointer-events: auto;\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/* The close sized from the title, so it holds its own beside it in every look: its target phi times\n the title (34 at 21), its icon root phi of it (27), whose cross, half the icon's grid, is about the\n title's capitals, its stroke near 2 px. At 16 the cross was 8 px of 1.2 px lines under a 21 px title.\n The negative margins keep the header as tall as before and the cross's edge at the text's edge. */\n.tcw-modal-close {\n --tcw-close-box: calc(var(--tcw-font-size-display) * 1.618);\n --tcw-close-icon: calc(var(--tcw-font-size-display) * 1.272);\n flex: none;\n width: var(--tcw-close-box);\n height: var(--tcw-close-box);\n margin-block: calc((var(--tcw-close-box) - var(--tcw-font-size-display) * 1.2) / -2);\n margin-inline-end: calc((var(--tcw-close-box) - var(--tcw-close-icon) / 2) / -2);\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-close:focus-visible {\n outline: none;\n box-shadow: var(--tcw-ring);\n}\n\n.tcw-modal-close svg {\n width: var(--tcw-close-icon);\n height: var(--tcw-close-icon);\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-label-size);\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/* A number field's hint goes on a line of its own, under the field. */\n.tcw-settings-row--number {\n flex-wrap: wrap;\n}\n\n.tcw-settings-hint {\n flex-basis: 100%;\n padding-top: var(--tcw-space-2);\n color: var(--tcw-red);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.35;\n text-align: end;\n}\n\n/* Empty, it takes no room but stays rendered: a live region that appears with its text is often not read out. */\n.tcw-settings-hint:empty {\n padding-top: 0;\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 /* Hex letters vary in width in a sans face: a monospaced one keeps the codes one width. */\n font-family: ui-monospace, 'Cascadia Mono', 'SF Mono', Menlo, Consolas, monospace;\n font-variant-numeric: tabular-nums;\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}\n\n/* The bar holds the keyboard when a refit hides every button it could go to. */\n.tcw-statusbar:focus-visible {\n outline: 2px solid var(--tcw-accent);\n outline-offset: -2px;\n}\n\n.tcw-status-right {\n display: flex;\n align-items: center;\n gap: 14px;\n margin-inline-start: auto;\n /* Never narrower than what it holds, so the clock at its end stays whole: the range presets give way instead. */\n flex: none;\n white-space: nowrap;\n}\n\n/* Range presets + go to date, bottom left. The bar takes the room the rest leaves and\n clips what's past it; WidgetStatusBar.fit folds that under \"more\". Logical margins,\n so right to left it keeps its gap before the right group. */\n.tcw-range-bar {\n display: flex;\n align-items: center;\n gap: 1px;\n margin-block: -4px;\n margin-inline: -8px 12px;\n min-width: 0;\n overflow: hidden;\n}\n\n/* A narrow widget (a phone, a narrow column, a grid's cell): the range presets close up. */\n.tcw-root[data-tcw-narrow] .tcw-range-btn[data-range] {\n padding: 4px 5px;\n}\n\n/* What the bar has folded, and \"more\" while nothing is. */\n.tcw-statusbar [data-tcw-folded],\n.tcw-statusbar:not(.tcw-statusbar--folded) .tcw-range-more {\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.tcw-range-more {\n display: inline-grid;\n place-items: center;\n padding: 4px 6px;\n}\n\n.tcw-range-goto {\n margin-inline-start: 6px;\n}\n\n.tcw-range-goto svg,\n.tcw-range-more 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 /* The dock's width to start (a panel of the dock takes the panel's): four figures fit. */\n width: 262px;\n flex-shrink: 0;\n /* Its rows read its width: a narrow panel drops a column (see the move, below). */\n container: tcw-watchlist / inline-size;\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-variant-numeric: tabular-nums;\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 /* Across the list's grid: on its own it would land in the 2px gutter. */\n grid-column: 1 / -1;\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/*\n * A row's remove button shows on hover or focus, in a column of its own after\n * the numbers: over them, it hid the price and the change of the row the\n * keyboard was on.\n */\n.tcw-watchlist-remove {\n display: grid;\n place-items: center;\n width: var(--tcw-watchlist-remove);\n height: var(--tcw-watchlist-remove);\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 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/*\n * One grid for the head and the rows (each a subgrid of it), so the price,\n * the move and the change line up in columns from row to row. The columns\n * come from the script (`--tcw-watchlist-columns`): a sparkline and the\n * remove button each add one. The edges are columns too, a gutter each: a\n * subgrid's own padding would push its last cell past the panel.\n */\n.tcw-watchlist-list {\n --tcw-watchlist-remove: 20px;\n /* With the gap beside it, 10px from the panel's edge to the first and last cell. */\n --tcw-watchlist-gutter: 2px;\n flex: 1;\n overflow-y: auto;\n padding: 0 0 4px;\n display: grid;\n grid-template-columns: var(--tcw-watchlist-columns, var(--tcw-watchlist-gutter) minmax(0, 1fr) auto auto auto var(--tcw-watchlist-gutter));\n column-gap: 8px;\n align-content: start;\n}\n\n.tcw-watchlist-columns,\n.tcw-watchlist-row {\n grid-column: 1 / -1;\n display: grid;\n grid-template-columns: subgrid;\n align-items: center;\n}\n/* The cells start after the leading gutter; the rest follow in order. */\n.tcw-watchlist-columns > :first-child,\n.tcw-watchlist-row > :first-child {\n grid-column-start: 2;\n}\n\n/* The columns' names: small and quiet, held at the top as the rows scroll. */\n.tcw-watchlist-columns {\n position: sticky;\n top: 0;\n z-index: 1;\n height: 20px;\n background: var(--tcw-bg-surface);\n border-bottom: 1px solid var(--tcw-border);\n font-size: var(--tcw-font-size-xs);\n color: var(--tcw-text-muted);\n white-space: nowrap;\n}\n.tcw-watchlist-columns > :not(.tcw-watchlist-column-symbol) {\n text-align: end;\n}\n\n/* A line a symbol, as short as its figures read: more of the list in sight. */\n.tcw-watchlist-row {\n position: relative;\n min-height: 24px;\n cursor: pointer;\n transition: background var(--tcw-dur-fast) var(--tcw-ease);\n outline: none;\n}\n\n/* The mark of the row in use or under the keyboard: a bar at its start, in the leading gutter. */\n.tcw-watchlist-row::before {\n content: '';\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n width: 2px;\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}\n\n.tcw-watchlist-row.tcw-watchlist-active {\n background: var(--tcw-accent-soft);\n}\n\n.tcw-watchlist-row:focus-visible::before,\n.tcw-watchlist-row.tcw-watchlist-active::before {\n background: var(--tcw-accent);\n}\n\n.tcw-watchlist-symbol {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\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: 48px;\n height: 18px;\n align-self: center;\n}\n\n.tcw-watchlist-price,\n.tcw-watchlist-move,\n.tcw-watchlist-change {\n text-align: end;\n white-space: nowrap;\n font-family: var(--tcw-font-mono);\n font-variant-numeric: tabular-nums;\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight);\n color: var(--tcw-text-muted);\n}\n\n.tcw-watchlist-price {\n color: var(--tcw-text);\n}\n\n/* A panel too narrow for four figures drops the move first: the price and the % still read, and the\n name keeps its room. 300 holds the longest a row's figures run to, a price of 0.00000528 and a\n move of -0.00000003, beside \"DOGE/USDT\"; the dock opens narrower, so it starts with three. */\n@container tcw-watchlist (width < 300px) {\n .tcw-watchlist-move,\n .tcw-watchlist-column-move {\n display: none;\n }\n}\n\n.tcw-watchlist-move.tcw-up,\n.tcw-watchlist-change.tcw-up {\n color: var(--tcw-green);\n}\n\n.tcw-watchlist-move.tcw-down,\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 bar ===\n * A transport over the foot of the main pane: step back / play / step\n * forward, where the replay is (its date and a track with the played part\n * filled), its pace (speed, step), and the ways out (pick another bar, back\n * to now). Only --tcw-* tokens; its sizes come from the look's own ladder.\n * The widget sets where it sits (--tcw-replay-foot, --tcw-replay-plot-*)\n * from the main pane, and the tier (data-fit) from the room it has.\n */\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-bar {\n /* Buttons are the look's controls; Play two small steps above them. */\n --tcw-replay-btn: var(--tcw-control-h);\n --tcw-replay-play: calc(var(--tcw-control-h) + 2 * var(--tcw-space-2));\n --tcw-replay-track-w: calc(var(--tcw-space-7) * 6);\n --tcw-replay-track-min: calc(var(--tcw-space-7) * 3);\n --tcw-replay-rail: var(--tcw-space-2);\n --tcw-replay-head-w: var(--tcw-space-2);\n --tcw-replay-head-h: var(--tcw-space-5);\n position: absolute;\n /* On the main pane's foot (over the volume, clear of the bottom panes), above the time axis without them. */\n bottom: calc(var(--tcw-replay-foot, 30px) + var(--tcw-space-4));\n inset-inline: var(--tcw-replay-plot-start, 0px) var(--tcw-replay-plot-end, 0px);\n /* Centred on the plot by its margins: an entrance on `transform` would undo a translate. */\n margin-inline: auto;\n box-sizing: border-box;\n width: max-content;\n max-width: calc(100% - var(--tcw-replay-plot-start, 0px) - var(--tcw-replay-plot-end, 0px) - 2 * var(--tcw-space-4));\n z-index: 25;\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n padding: var(--tcw-space-3);\n background: var(--tcw-bg-elevated);\n background: color-mix(in srgb, var(--tcw-bg-elevated) var(--tcw-surface-opacity, 100%), transparent);\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\n /* The look's menu shadow carries its hairline (Print, Terminal, Capsule): no border of its own on top. */\n border-radius: var(--tcw-panel-radius);\n box-shadow: var(--tcw-menu-shadow);\n color: var(--tcw-text);\n font-size: var(--tcw-font-size-sm);\n line-height: 1.2;\n animation: tcw-sel-in var(--tcw-dur-normal) var(--tcw-ease-out);\n}\n\n.tcw-replay-group,\n.tcw-replay-slot {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-2);\n min-width: 0;\n}\n.tcw-replay-bar [hidden] { display: none !important; }\n/* The step field on a single step: nothing there, no gap for it. */\n.tcw-replay-slot:empty { display: none; }\n\n/* Hairlines between the groups where the look draws separators (Print, Terminal); a gap in the others. */\n.tcw-replay-sep {\n flex: none;\n align-self: stretch;\n width: var(--tcw-sep-w);\n margin-block: var(--tcw-space-2);\n background: var(--tcw-divider);\n}\n\n/* --- Buttons --- */\n.tcw-replay-btn {\n flex: none;\n display: inline-grid;\n place-items: center;\n inline-size: var(--tcw-replay-btn);\n block-size: var(--tcw-replay-btn);\n padding: 0;\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n cursor: pointer;\n transition:\n background-color 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}\n.tcw-replay-btn > svg,\n.tcw-replay-text-btn svg { width: var(--tcw-icon); height: var(--tcw-icon); flex: none; }\n.tcw-replay-btn:hover { background: var(--tcw-hover-bg); color: var(--tcw-text); }\n.tcw-replay-btn:active { background: var(--tcw-active-bg); transform: scale(0.94); }\n.tcw-replay-btn:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n\n/* Play: the one filled control. Its focus ring stands off the fill, or it would vanish into it. */\n.tcw-replay-btn.tcw-replay-play {\n inline-size: var(--tcw-replay-play);\n block-size: var(--tcw-replay-play);\n background: var(--tcw-accent);\n color: var(--tcw-accent-ink);\n}\n.tcw-replay-btn.tcw-replay-play:hover { background: var(--tcw-accent-hover); color: var(--tcw-accent-ink); }\n.tcw-replay-btn.tcw-replay-play:focus-visible {\n box-shadow: 0 0 0 var(--tcw-space-1) var(--tcw-bg-elevated), 0 0 0 calc(2 * var(--tcw-space-1)) var(--tcw-accent-line);\n}\n\n.tcw-replay-btn:disabled,\n.tcw-replay-text-btn:disabled,\n.tcw-replay-scrubber:disabled,\n.tcw-replay-speed:disabled { opacity: 0.4; cursor: default; transform: none; }\n/* Nothing left to play: a muted fill, not a faded accent that reads as pressed. */\n.tcw-replay-btn.tcw-replay-play:disabled { background: var(--tcw-active-bg); color: var(--tcw-text-muted); opacity: 1; }\n\n/* --- Where the replay is --- */\n.tcw-replay-timeline {\n flex: 1 1 auto;\n gap: var(--tcw-space-4);\n}\n.tcw-replay-time {\n flex: none;\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n color: var(--tcw-text);\n white-space: nowrap;\n}\n.tcw-replay-group[aria-busy='true'] .tcw-replay-time,\n.tcw-replay-group[aria-busy='true'] .tcw-replay-hint { color: var(--tcw-text-muted); }\n\n.tcw-root input[type='range'].tcw-replay-scrubber {\n --tcw-replay-rest: var(--tcw-border-strong);\n flex: 1 1 var(--tcw-replay-track-w);\n min-inline-size: var(--tcw-replay-track-min);\n inline-size: var(--tcw-replay-track-w);\n block-size: var(--tcw-replay-btn);\n margin: 0;\n padding: 0;\n appearance: none;\n -webkit-appearance: none;\n background: transparent;\n border: 0;\n border-radius: var(--tcw-control-radius);\n cursor: pointer;\n}\n/* Measured at its least: the bar's width with no slack in the track. */\n.tcw-replay-bar[data-measure] { max-width: none; animation: none; }\n.tcw-replay-bar[data-measure] input[type='range'].tcw-replay-scrubber { inline-size: var(--tcw-replay-track-min); flex: none; }\n.tcw-root input[type='range'].tcw-replay-scrubber:hover { --tcw-replay-rest: var(--tcw-text-muted); }\n.tcw-root input[type='range'].tcw-replay-scrubber:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n/* The played part in the accent, the rest a rail; Firefox fills it itself. */\n.tcw-root input[type='range'].tcw-replay-scrubber::-webkit-slider-runnable-track {\n block-size: var(--tcw-replay-rail);\n border-radius: var(--tcw-radius-xs);\n background: linear-gradient(to right, var(--tcw-accent) 0 var(--tcw-replay-done, 0%), var(--tcw-replay-rest) var(--tcw-replay-done, 0%) 100%);\n}\n.tcw-root input[type='range'].tcw-replay-scrubber::-moz-range-track { block-size: var(--tcw-replay-rail); border-radius: var(--tcw-radius-xs); background: var(--tcw-replay-rest); }\n.tcw-root input[type='range'].tcw-replay-scrubber::-moz-range-progress { block-size: var(--tcw-replay-rail); border-radius: var(--tcw-radius-xs); background: var(--tcw-accent); }\n/* A playhead, as the chart marks the replay's cut: a short upright in ink, rounded as the look rounds. */\n.tcw-root input[type='range'].tcw-replay-scrubber::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n inline-size: var(--tcw-replay-head-w);\n block-size: var(--tcw-replay-head-h);\n margin-top: calc((var(--tcw-replay-rail) - var(--tcw-replay-head-h)) / 2);\n border: 0;\n border-radius: var(--tcw-radius-xs);\n background: var(--tcw-text);\n box-shadow: 0 0 0 var(--tcw-space-1) var(--tcw-bg-elevated);\n transition: transform var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-root input[type='range'].tcw-replay-scrubber:hover::-webkit-slider-thumb,\n.tcw-root input[type='range'].tcw-replay-scrubber:active::-webkit-slider-thumb { transform: scaleY(1.25); }\n.tcw-root input[type='range'].tcw-replay-scrubber::-moz-range-thumb {\n inline-size: var(--tcw-replay-head-w);\n block-size: var(--tcw-replay-head-h);\n border: 0;\n border-radius: var(--tcw-radius-xs);\n background: var(--tcw-text);\n box-shadow: 0 0 0 var(--tcw-space-1) var(--tcw-bg-elevated);\n}\n\n/* --- Pace: speed and step, each a labelled field --- */\n.tcw-replay-chip {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-3);\n flex: none;\n}\n.tcw-replay-chip-label {\n font-size: var(--tcw-font-size-xs);\n text-transform: var(--tcw-label-case);\n letter-spacing: var(--tcw-label-tracking);\n color: var(--tcw-text-muted);\n white-space: nowrap;\n}\n.tcw-root .tcw-replay-chip select.tcw-replay-speed {\n block-size: var(--tcw-replay-btn);\n padding-block: 0;\n padding-inline-start: var(--tcw-space-4);\n font-family: var(--tcw-font-mono);\n font-size: var(--tcw-font-size-sm);\n font-variant-numeric: tabular-nums;\n}\n\n/* --- The ways out, and picking --- */\n.tcw-replay-text-btn {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-3);\n block-size: var(--tcw-replay-btn);\n padding-inline: var(--tcw-space-4);\n border: 0;\n border-radius: var(--tcw-control-radius);\n background: transparent;\n color: var(--tcw-text-dim);\n font: inherit;\n font-weight: var(--tcw-weight);\n white-space: nowrap;\n cursor: pointer;\n transition: background-color var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease), transform var(--tcw-dur-fast) var(--tcw-ease);\n}\n.tcw-replay-text-btn:hover { background: var(--tcw-hover-bg); color: var(--tcw-text); }\n.tcw-replay-text-btn:active { background: var(--tcw-active-bg); transform: scale(0.97); }\n.tcw-replay-text-btn:focus-visible { outline: none; box-shadow: var(--tcw-ring); }\n/* Random bar: outlined, the one thing to press while picking. */\n.tcw-replay-text-btn.tcw-replay-ghost { border: var(--tcw-border-w) solid var(--tcw-border-strong); color: var(--tcw-text); }\n/* The close glyph is the phone's: on wider bars the words say it. */\n.tcw-replay-close-icon { display: none; }\n/* At the last bar, the way back to now is the next thing to do. */\n.tcw-replay-bar--ended .tcw-replay-realtime { background: var(--tcw-accent); color: var(--tcw-accent-ink); }\n.tcw-replay-bar--ended .tcw-replay-realtime:hover { background: var(--tcw-accent-hover); color: var(--tcw-accent-ink); }\n\n.tcw-replay-hint {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-3);\n padding-inline: var(--tcw-space-3);\n color: var(--tcw-text-dim);\n white-space: nowrap;\n}\n.tcw-replay-hint > svg { flex: none; width: var(--tcw-icon); height: var(--tcw-icon); color: var(--tcw-accent); }\n\n/* --- Narrower: the fields lose their captions (they stay their names) --- */\n.tcw-replay-bar:is([data-fit='compact'], [data-fit='stack']) .tcw-replay-chip-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/* --- A phone, or a narrow chart: two rows across the plot, where the replay is on top --- */\n.tcw-replay-bar[data-fit='stack'] {\n /* Touch targets: 40 px (44 for Play) at least, as the toolbar's on a phone. */\n --tcw-replay-btn: max(40px, var(--tcw-control-h));\n --tcw-replay-play: max(44px, calc(var(--tcw-control-h) + 2 * var(--tcw-space-2)));\n inset-inline: var(--tcw-space-4);\n width: auto;\n max-width: none;\n margin-inline: 0;\n flex-wrap: wrap;\n gap: var(--tcw-space-2);\n}\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-sep { display: none; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-timeline {\n order: -2;\n /* The first row, beside the close button; the rest wraps below. */\n flex: 1 1 calc(100% - var(--tcw-replay-btn) - 2 * var(--tcw-space-2));\n box-sizing: border-box;\n padding-inline-start: var(--tcw-space-3);\n}\n.tcw-replay-bar[data-fit='stack'] input[type='range'].tcw-replay-scrubber { block-size: var(--tcw-menu-item-h); min-inline-size: 0; }\n/* Back to realtime closes the bar from the first row, a glyph touch users know. */\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-exits { display: contents; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-realtime { order: -1; inline-size: var(--tcw-replay-btn); padding: 0; justify-content: center; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-realtime .tcw-replay-text { display: none; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-close-icon { display: inline-flex; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-transport { flex: 1 0 auto; }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-hint { white-space: normal; flex: 1 0 100%; padding-block: var(--tcw-space-2); }\n.tcw-replay-bar[data-fit='stack'] .tcw-replay-picking { display: contents; }\n\n/* While the bar holds the plot's foot, what lives there makes room: the toasts and the phone's drawing button. */\n.tcw-root[data-tcw-replay] > .tcw-toast:not(.tcw-toast-over) {\n bottom: calc(var(--tcw-replay-lift, 0px) + var(--tcw-space-4));\n}\n.tcw-root[data-tcw-narrow][data-tcw-replay] > .tcw-body > .tcw-sidebar-fab {\n bottom: calc(var(--tcw-replay-lift, 0px) + var(--tcw-space-4));\n}\n\n@media (forced-colors: active) {\n .tcw-replay-bar { border: 1px solid CanvasText; }\n .tcw-replay-btn.tcw-replay-play { border: 1px solid ButtonText; }\n .tcw-root input[type='range'].tcw-replay-scrubber::-webkit-slider-runnable-track { background: GrayText; }\n .tcw-root input[type='range'].tcw-replay-scrubber::-webkit-slider-thumb { background: Highlight; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .tcw-replay-bar { animation: none; }\n .tcw-replay-btn,\n .tcw-replay-text-btn,\n .tcw-root input[type='range'].tcw-replay-scrubber::-webkit-slider-thumb { transition: none; }\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-tool-size));\n height: max(40px, var(--tcw-tool-size));\n }\n .tcw-modal {\n width: 94vw;\n border-radius: var(--tcw-dialog-radius);\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-root[data-tcw-replay] .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/* A compare: its colour and symbol, then how it is compared, taking the room left before its button. */\n.tcw-tree-compare {\n justify-content: flex-start;\n}\n.tcw-tree-compare .tcw-tree-name {\n flex: 0 1 auto;\n}\n.tcw-tree-compare .tcw-tree-del {\n flex: none;\n margin-inline-start: auto;\n}\n.tcw-tree-way {\n flex: 1 1 0;\n min-width: 0;\n overflow: hidden;\n color: var(--tcw-text-dim);\n font-size: var(--tcw-font-size-xs);\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/* A drawing row's grip: dragged, it moves the drawing up or down the order. */\n.tcw-tree-btn.tcw-tree-grip {\n flex: none;\n cursor: grab;\n touch-action: none;\n}\n.tcw-tree-row:not(:hover) .tcw-tree-grip:not(:focus-visible) {\n opacity: 0.45;\n}\n/* The row a dragged drawing would take the place of. */\n.tcw-tree-row.tcw-tree-drop {\n box-shadow: inset 0 0 0 1px var(--tcw-accent);\n}\n/* A drawing's name selects it on the chart. */\n.tcw-tree-name.tcw-tree-pick {\n flex: 1 1 auto;\n cursor: pointer;\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 /* Frosted with the other menus (`ui.blur` above 0): the chart under it blurred, not sharp behind its words. */\n backdrop-filter: blur(var(--tcw-blur));\n -webkit-backdrop-filter: blur(var(--tcw-blur));\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, a count, and the mark of a submenu, at the row's end. */\n.tcw-context-key, .tcw-context-count {\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/* The fill picker: a square, where the line colour is a dot. */\n.tcw-sel-fill { border-radius: 3px; }\n/* The text colour picker: a letter over a bar in the text's colour. */\n.tcw-sel-text {\n font-weight: var(--tcw-weight-strong);\n font-size: var(--tcw-font-size-sm);\n line-height: 1;\n padding-bottom: 1px;\n border-bottom: 3px solid var(--c, currentColor);\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/* Your items keep their width (the range presets fold for them), and on the left a gap\n before the right group, whose auto margin closes up when the bar is full. */\n.tcw-status-host { display: flex; align-items: center; gap: 10px; flex: none; }\n.tcw-statusbar > .tcw-status-host { margin-inline-end: var(--tcw-space-5); }\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-move,\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/* The icons' lines (`ui.iconStroke`): one width at every icon size, on the widget and in its\n * portal, when the look sets one; otherwise as the icon set draws them. */\n[data-tcw-icon-stroke='set'] .tc-icon {\n stroke-width: var(--tcw-icon-stroke);\n}\n[data-tcw-icon-stroke='set'] .tc-icon > * {\n vector-effect: non-scaling-stroke;\n}\n/* Its filled dots (a drawing tool's anchors) were sized for the drawn line: smaller with the fine\n one, so they don't outweigh it. */\n[data-tcw-icon-stroke='set'] .tc-icon > circle[stroke='none'] {\n transform-box: fill-box;\n transform-origin: center;\n transform: scale(0.7);\n}\n/* A small icon (the legend's, a pin, 10 to 13 px) at most 1 px, so it isn't heavier than the\n rest: drawn as it is, its line was under 1 px. */\n[data-tcw-icon-stroke='set'] .tc-icon:is([width='10'], [width='11'], [width='12'], [width='13']) {\n stroke-width: min(var(--tcw-icon-stroke), 1px);\n}\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.tcw-dropdown-trigger[data-role='charttype'] svg {\n width: var(--tcw-icon);\n height: var(--tcw-icon);\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 font-variant-numeric: tabular-nums;\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/* The market's status in a word (\"Closed\"), when even with everything folded under \"more\"\n the bar has no room: the full words are left to screen readers and the tooltip. */\n.tcw-status-market-short {\n display: none;\n}\n.tcw-statusbar--short-market .tcw-status-market-short {\n display: inline;\n}\n.tcw-root[data-tcw-narrow] .tcw-status-indicator > span:not(.tcw-status-dot),\n.tcw-statusbar--short-market .tcw-status-market-text {\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), a host's left-hand ones last, and `--icons` drops the menus'\n labels and the interval buttons. 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 /* Over the plot, in from its left edge (the widget sets where it starts): the\n price axis stays on the chart's right in either direction, so a\n right-to-left widget keeps the button on the left too, off the axis. */\n left: calc(var(--tcw-fab-plot-left, 0px) + 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", Ht = "/* === 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='%23918f8a' 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='%23918f8a' 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='%236a6e75' 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='%236a6e75' 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 * The browser's control font resets the OpenType features, so --tcw-font-features\n * set on .tcw-root reaches every button and field only through this. */\n:where(.tcw-root) :where(input, select, textarea, button) {\n font-family: inherit;\n font-weight: inherit;\n letter-spacing: inherit;\n font-feature-settings: 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:not([type='checkbox']),\n .tcw-settings-number\n):is([aria-invalid='true']):is(*, :hover, :focus) {\n /* As specific as the hover rule (its list holds the same :not) and later, so a wrong value stays red\n 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/* A select laid out left to right inside a right-to-left widget (the chart's\n * own area is LTR, the replay's figures too) keeps its chevron on the right,\n * where its padding is. */\n.tcw-root[dir='rtl'] [dir='ltr'] select:not([multiple]):not([size]),\n.tcw-root[dir='rtl'] select[dir='ltr']:not([multiple]):not([size]) {\n background-position: right 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", Ut = "/* === 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/* A dialog's search is a band across it, under its title, with a rule beneath: no box, no ring when\n focused. The caret and the dialog itself say where typing goes; a lit box around the one field a\n search dialog has only shouted it. As tall as the field and its margins were, set in as the title. */\n.tcw-ip-search,\n.tcw-ss-search {\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n flex: none;\n height: calc(var(--tcw-control-h) + 2 * var(--tcw-space-4));\n margin: 0;\n padding: 0 var(--tcw-space-6);\n border: none;\n border-bottom: 1px solid var(--tcw-divider);\n border-radius: 0;\n background: transparent;\n color: var(--tcw-text-muted);\n transition: color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n/* Focused, only the magnifier takes the text's colour. */\n.tcw-ip-search:focus-within,\n.tcw-ss-search:focus-within {\n color: var(--tcw-text);\n}\n\n/* The magnifier root phi of the typed text (19 at 15), as the close is of the title. */\n.tcw-ip-search svg,\n.tcw-ss-search svg {\n flex: none;\n width: calc(var(--tcw-font-size-lg) * 1.272);\n height: calc(var(--tcw-font-size-lg) * 1.272);\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-lg);\n}\n\n/* In forced colours the muted and the text's colour may be one: the band keeps an outline there,\n so the field is still found. */\n@media (forced-colors: active) {\n .tcw-ip-search:focus-within,\n .tcw-ss-search:focus-within {\n outline: 2px solid Highlight;\n outline-offset: -2px;\n }\n}\n\n/* The browser's clear button for a search field (bold, and blue in Chrome's light scheme) as the\n icon set's close, in the muted text, the text's on hover. A mask, so it takes the colour. */\n.tcw-ip-search input::-webkit-search-cancel-button,\n.tcw-ss-search input::-webkit-search-cancel-button {\n -webkit-appearance: none;\n appearance: none;\n width: calc(var(--tcw-font-size-lg) * 1.272);\n height: calc(var(--tcw-font-size-lg) * 1.272);\n background: var(--tcw-text-muted);\n -webkit-mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 6L18 18M18 6L6 18' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='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 24 24'%3E%3Cpath d='M6 6L18 18M18 6L6 18' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round'/%3E%3C/svg%3E\") center / contain no-repeat;\n cursor: pointer;\n}\n\n.tcw-ip-search input::-webkit-search-cancel-button:hover,\n.tcw-ss-search input::-webkit-search-cancel-button:hover {\n background: var(--tcw-text);\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}\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-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/* A box ticked beside other controls in a row (bold, italics, a text box's background). */\n.tcw-inline-check {\n display: inline-flex;\n align-items: center;\n gap: var(--tcw-space-2);\n cursor: pointer;\n white-space: nowrap;\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 still as the indicators dialog: a fixed height while a search shortens the list. As wide as it,\n 610, up to a screen 1597 wide; past that a phi share of the screen (1 / phi^2), up to 987, the next\n Fibonacci number: about 733 at 1920, 978 at 2560, room for ids with a venue before the ticker. */\n.tcw-modal.tcw-ss {\n width: min(987px, max(610px, 38.2vw));\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 heads' height, which the rows scroll in below; the room after a symbol before its name. */\n.tcw-modal.tcw-ss {\n --tcw-ss-head-h: var(--tcw-control-h);\n --tcw-ss-name-gap: var(--tcw-space-4);\n}\n\n[dir='rtl'] .tcw-ss-symbol {\n padding-right: 0;\n padding-left: var(--tcw-ss-name-gap);\n}\n\n/* Over the list: the kinds the rows come in, and their exchanges once there are two. The exchanges sit\n on the tabs' first line when the tabs wrap, not between their lines. */\n.tcw-ss-filters {\n display: flex;\n align-items: flex-start;\n gap: var(--tcw-space-4);\n flex: none;\n margin: 0 var(--tcw-space-6) var(--tcw-space-4);\n}\n\n/* The kinds as tabs (All, stock, crypto…), showing the one picked as the look shows a choice. */\n.tcw-ss-kinds {\n display: flex;\n flex-wrap: wrap;\n flex: 1;\n min-width: 0;\n gap: var(--tcw-space-2);\n}\n\n/* Where they scroll in one line, the tabs fade out at an end with more past it, so a tab cut there\n reads as more to scroll to. A mask: only its alpha counts, so what shows is drawn in the text's\n colour, which is opaque, and what fades goes to transparent. */\n.tcw-ss-kinds[data-more] {\n --tcw-ss-shown: currentColor;\n --tcw-ss-fade-start: var(--tcw-ss-shown);\n --tcw-ss-fade-end: var(--tcw-ss-shown);\n -webkit-mask-image: linear-gradient(to right, var(--tcw-ss-fade-start), var(--tcw-ss-shown) var(--tcw-space-6), var(--tcw-ss-shown) calc(100% - var(--tcw-space-6)), var(--tcw-ss-fade-end));\n mask-image: linear-gradient(to right, var(--tcw-ss-fade-start), var(--tcw-ss-shown) var(--tcw-space-6), var(--tcw-ss-shown) calc(100% - var(--tcw-space-6)), var(--tcw-ss-fade-end));\n}\n\n[dir='rtl'] .tcw-ss-kinds[data-more] {\n -webkit-mask-image: linear-gradient(to left, var(--tcw-ss-fade-start), var(--tcw-ss-shown) var(--tcw-space-6), var(--tcw-ss-shown) calc(100% - var(--tcw-space-6)), var(--tcw-ss-fade-end));\n mask-image: linear-gradient(to left, var(--tcw-ss-fade-start), var(--tcw-ss-shown) var(--tcw-space-6), var(--tcw-ss-shown) calc(100% - var(--tcw-space-6)), var(--tcw-ss-fade-end));\n}\n\n.tcw-ss-kinds[data-more~='start'] {\n --tcw-ss-fade-start: transparent;\n}\n\n.tcw-ss-kinds[data-more~='end'] {\n --tcw-ss-fade-end: transparent;\n}\n\n.tcw-ss-type {\n flex: none;\n height: var(--tcw-control-h);\n padding: 0 var(--tcw-space-5);\n border: none;\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 transition: background var(--tcw-dur-fast) var(--tcw-ease), color var(--tcw-dur-fast) var(--tcw-ease);\n}\n\n/* A feed's words as it wrote them (\"Cổ phiếu\" stays so), only the first letter raised. */\n.tcw-ss-type::first-letter {\n text-transform: uppercase;\n}\n\n.tcw-ss-type:hover {\n background: var(--tcw-tab-hover);\n color: var(--tcw-text);\n}\n\n.tcw-ss-type[aria-pressed='true'] {\n background: var(--tcw-tab-on-bg);\n color: var(--tcw-tab-on-fg);\n box-shadow: inset 0 calc(-1 * var(--tcw-tab-line)) 0 var(--tcw-accent);\n font-weight: var(--tcw-weight-strong);\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 exchanges at the end of the row, as wide as the longest up to 144. */\n.tcw-root .tcw-ss-exchange-filter {\n flex: none;\n width: auto;\n max-width: 144px;\n height: var(--tcw-control-h);\n margin-inline-start: auto;\n padding-block: 0;\n font-size: var(--tcw-font-size-sm);\n}\n\n/* What scrolls is one grid, and the heads, the list and each row are its subgrids, so a column is\n as wide in every row: the badge, the symbol up to a quarter of the list (144 at 610, 233 in a wide\n dialog, the next Fibonacci number), the name the rest, the kind up to 89, the exchange up to 144\n ('XYZ · HYPERLIQUID' whole), the check. An empty cell keeps its column. */\n.tcw-ss-results {\n display: grid;\n grid-template-columns: max-content fit-content(clamp(144px, 25%, 233px)) minmax(0, 1fr) fit-content(89px) fit-content(144px) auto;\n align-content: start;\n column-gap: var(--tcw-space-4);\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n /* A row the arrows reach scrolls in below the heads, not under them. */\n scroll-padding-block-start: calc(var(--tcw-ss-head-h) + var(--tcw-space-2));\n padding: 0 var(--tcw-space-4) var(--tcw-space-5);\n}\n\n/* Comparing, under a heading of its own as well. */\n.tcw-ss--compare .tcw-ss-results {\n scroll-padding-block-start: calc(var(--tcw-ss-head-h) + var(--tcw-space-5) + var(--tcw-space-2) + var(--tcw-font-size-xs) * 1.5);\n}\n\n.tcw-ss-results > * {\n grid-column: 1 / -1;\n}\n\n.tcw-ss-columns,\n.tcw-ss-list,\n.tcw-ss-added,\n.tcw-ss-row,\n.tcw-ss-added-row {\n display: grid;\n grid-column: 1 / -1;\n /* Where subgrids aren't drawn: fixed columns, the rest sized row by row. */\n grid-template-columns: var(--tcw-control-h-sm) 89px minmax(0, 1fr) auto auto auto;\n grid-template-columns: subgrid;\n align-items: center;\n column-gap: inherit;\n}\n\n/* The heads stay at the top while the rows scroll under them. */\n.tcw-ss-columns {\n position: sticky;\n top: 0;\n z-index: 2;\n height: var(--tcw-ss-head-h);\n margin-bottom: var(--tcw-space-2);\n padding: 0 var(--tcw-space-4);\n background: var(--tcw-bg-elevated);\n box-shadow: 0 1px 0 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 white-space: nowrap;\n}\n\n.tcw-ss-head {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.tcw-ss-head:nth-child(1) { grid-column: 1; }\n.tcw-ss-head:nth-child(2) { grid-column: 2; }\n.tcw-ss-head:nth-child(3) { grid-column: 3; }\n.tcw-ss-head:nth-child(4) { grid-column: 4; justify-self: end; }\n.tcw-ss-head:nth-child(5) { grid-column: 5; justify-self: end; }\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 logo, or the ticker's first letter on a tint of its kind's colour, cornered as the look's tags. */\n.tcw-ss-badge {\n --tcw-ss-kind: var(--tcw-text-dim);\n grid-column: 1;\n display: inline-grid;\n place-items: center;\n width: var(--tcw-control-h-sm);\n height: var(--tcw-control-h-sm);\n overflow: hidden;\n border-radius: var(--tcw-tag-radius);\n background: color-mix(in srgb, var(--tcw-ss-kind) 16%, transparent);\n color: var(--tcw-ss-kind);\n font-size: var(--tcw-font-size-xs);\n font-weight: var(--tcw-weight-strong);\n line-height: 1;\n}\n\n.tcw-ss-badge[data-kind='1'] { --tcw-ss-kind: var(--tcw-kind-1); }\n.tcw-ss-badge[data-kind='2'] { --tcw-ss-kind: var(--tcw-kind-2); }\n.tcw-ss-badge[data-kind='3'] { --tcw-ss-kind: var(--tcw-kind-3); }\n.tcw-ss-badge[data-kind='4'] { --tcw-ss-kind: var(--tcw-kind-4); }\n.tcw-ss-badge[data-kind='5'] { --tcw-ss-kind: var(--tcw-kind-5); }\n\nimg.tcw-ss-badge {\n background: transparent;\n object-fit: cover;\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. Padding on the name's side, counted in the column, keeps the longest id a\n gap twice the columns' from the name (\"BINANCE:BTCUSDT\" ran into \"BTC perpetual\"). The cell is\n left to right itself, so the side is named, not its end. */\n.tcw-ss-symbol {\n grid-column: 2;\n display: flex;\n justify-self: start;\n max-width: 100%;\n min-width: 0;\n padding-right: var(--tcw-ss-name-gap);\n overflow: hidden;\n color: var(--tcw-text);\n font-family: var(--tcw-font-mono);\n font-weight: var(--tcw-weight-strong);\n white-space: nowrap;\n}\n\n/* The ticker alone (a venue before it is the exchange column's): cut only when it is wider than its column. */\n.tcw-ss-ticker {\n flex: none;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\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 grid-column: 3;\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/* The kind as the feed wrote it, and the exchange, each at the end of its column. */\n.tcw-ss-kind,\n.tcw-ss-exchange {\n justify-self: end;\n max-width: 100%;\n min-width: 0;\n overflow: hidden;\n font-size: var(--tcw-font-size-xs);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tcw-ss-kind {\n grid-column: 4;\n color: var(--tcw-text-muted);\n}\n\n.tcw-ss-exchange {\n grid-column: 5;\n color: var(--tcw-text-dim);\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 in the last column. */\n.tcw-ss-check {\n grid-column: 6;\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\", under the heads while their rows scroll. */\n.tcw-ss-heading {\n position: sticky;\n top: var(--tcw-ss-head-h);\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 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, across the name, kind and exchange; the line's colour, where it has one of its own, where the badges are. */\n.tcw-ss-way-cell {\n grid-column: 3 / 6;\n display: flex;\n align-items: center;\n gap: var(--tcw-space-4);\n min-width: 0;\n}\n\n.tcw-ss-swatch {\n grid-column: 1;\n justify-self: center;\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 grid-column: 6;\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/* Under a list cut short: how many more match, for typing to narrow. */\n.tcw-ss-more {\n padding: var(--tcw-space-4);\n color: var(--tcw-text-muted);\n font-size: var(--tcw-font-size-xs);\n line-height: 1.5;\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 up to 89\n wide. The kind's column goes (the badge's colour still tells it), the tabs scroll in one line, and\n a row is a finger's height. */\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 /* The column's room goes to the ticker; the columns' own gap is enough here. */\n --tcw-ss-name-gap: 0px;\n }\n\n .tcw-ss-way,\n .tcw-ss-filters {\n margin-inline: var(--tcw-space-4);\n }\n\n .tcw-ss-kinds {\n flex-wrap: nowrap;\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n .tcw-ss-kinds::-webkit-scrollbar {\n display: none;\n }\n\n .tcw-root .tcw-ss-exchange-filter {\n max-width: 110px;\n }\n\n /* The ticker is the row's key: its column as wide as the widest ticker, up to 144 or 38.2% of the\n row, and the name gives way first. The exchange's up to 55, each cut in its own row. */\n .tcw-ss-results {\n grid-template-columns: max-content fit-content(min(144px, 38.2%)) minmax(0, 1fr) fit-content(55px) auto;\n }\n\n /* The head over the exchanges reads whole, over the gap before it if it must. */\n .tcw-ss-head:nth-child(5) {\n overflow: visible;\n }\n\n .tcw-ss-columns,\n .tcw-ss-list,\n .tcw-ss-added,\n .tcw-ss-row,\n .tcw-ss-added-row {\n grid-template-columns: var(--tcw-control-h-sm) 89px minmax(0, 1fr) auto auto;\n grid-template-columns: subgrid;\n }\n\n .tcw-ss-kind,\n .tcw-ss-head:nth-child(4) {\n display: none;\n }\n\n .tcw-ss-exchange,\n .tcw-ss-head:nth-child(5) {\n grid-column: 4;\n }\n\n .tcw-ss-check,\n .tcw-ss-remove {\n grid-column: 5;\n }\n\n .tcw-ss-way-cell {\n grid-column: 3 / 5;\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}\n\n/* Two columns as tall as their groups, inside the box that scrolls: on the box itself, of a fixed\n height, the groups past its foot went into columns to the side, out of reach. */\n.tcw-hotkey-columns {\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-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}\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}\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 /* The accent fill's ink reads on the red too: dark on the dark theme's, white on the light's. */\n color: var(--tcw-accent-ink);\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 padding-inline: var(--tcw-space-4);\n }\n\n .tcw-hotkey-columns {\n columns: 1;\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-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", Wt = "/* === 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-tool-size);\n height: var(--tcw-tool-size);\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-tool-icon-size);\n height: var(--tcw-tool-icon-size);\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: 262 wide to start (233 x phi^(1/4)), from 233 to 377. */\n.tcw-dock-panel {\n position: relative;\n display: flex;\n flex-direction: column;\n width: var(--tcw-dock-w, 262px);\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's header: 34 tall (21 + 13), or a control's height where that is more, and the rule under\n it. Its height and the page's scroll padding are both these, so they never part. */\n.tcw-dock-page {\n --tcw-dock-head-h: max(calc(var(--tcw-space-6) + var(--tcw-space-5)), var(--tcw-control-h));\n --tcw-dock-head-rule: 1px;\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 /* A row the keyboard moves to scrolls in below the header and its rule, not under them. */\n scroll-padding-block-start: calc(var(--tcw-dock-head-h) + var(--tcw-dock-head-rule));\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. */\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: var(--tcw-dock-head-h);\n margin: 0;\n padding-block: 0;\n padding-inline: var(--tcw-space-5) var(--tcw-space-3);\n border-bottom: var(--tcw-dock-head-rule) 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. It scrolls as a page\n (no overflow of its own here: this rule, as specific as the page's and later, would win). */\n.tcw-dock-panel > .tcw-watchlist {\n width: auto;\n border-inline-start: none;\n box-shadow: none;\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", Gt = 0, Kt = "tcw-styles";
|
|
281
281
|
function qt() {
|
|
282
282
|
if (Gt++, Gt > 1 || document.getElementById(Kt)) return;
|
|
283
283
|
let e = document.createElement("style");
|
|
@@ -543,11 +543,7 @@ var vn = class e {
|
|
|
543
543
|
t.find((t) => t.id === e)?.run();
|
|
544
544
|
});
|
|
545
545
|
}
|
|
546
|
-
}, yn = 0, k = "data-tcw-folded", bn = 1 / 64, xn = [
|
|
547
|
-
"venue",
|
|
548
|
-
"ticker",
|
|
549
|
-
"cut"
|
|
550
|
-
], Sn = {
|
|
546
|
+
}, yn = 0, k = "data-tcw-folded", bn = 1 / 64, xn = ["cut"], Sn = {
|
|
551
547
|
T: "toolbar.timeframes.ticks",
|
|
552
548
|
s: "toolbar.timeframes.seconds",
|
|
553
549
|
m: "toolbar.timeframes.minutes",
|
|
@@ -877,11 +873,8 @@ var wn = class {
|
|
|
877
873
|
let t = this.el.querySelector("[data-role=\"symbol\"]");
|
|
878
874
|
if (!t || this.symbolShown === e) return;
|
|
879
875
|
this.symbolShown = e;
|
|
880
|
-
let
|
|
881
|
-
|
|
882
|
-
return n.className = e, n.textContent = t, n;
|
|
883
|
-
};
|
|
884
|
-
t.replaceChildren(...n ? [i("tcw-toolbar-venue", n)] : [], i("tcw-toolbar-ticker", r)), t.classList.toggle("tcw-toolbar-symbol--venue", n !== ""), t.setAttribute("aria-label", e);
|
|
876
|
+
let n = document.createElement("span");
|
|
877
|
+
n.className = "tcw-toolbar-ticker", n.textContent = be(e).ticker, t.replaceChildren(n), t.setAttribute("aria-label", e);
|
|
885
878
|
}
|
|
886
879
|
update(e) {
|
|
887
880
|
this.renderSymbol(e.symbol), this.renderTimeframes(e.timeframe);
|
|
@@ -1298,31 +1291,36 @@ var tr = "--tcw-fab-plot-left", nr = class {
|
|
|
1298
1291
|
}
|
|
1299
1292
|
this.hideFlyout();
|
|
1300
1293
|
let n = document.createElement("div");
|
|
1301
|
-
n.className = "tcw-flyout", n.setAttribute("role", "menu"), n.setAttribute("aria-label", t.label), n.addEventListener("keydown", (t) => this.onFlyoutKey(t, e))
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1294
|
+
if (n.className = "tcw-flyout", n.setAttribute("role", "menu"), n.setAttribute("aria-label", t.label), n.addEventListener("keydown", (t) => this.onFlyoutKey(t, e)), t.tools[0]?.heading === void 0) {
|
|
1295
|
+
let e = document.createElement("div");
|
|
1296
|
+
e.className = "tcw-flyout-header", e.textContent = t.label, n.appendChild(e);
|
|
1297
|
+
}
|
|
1298
|
+
let r = this.t("drawing.pinFavorite");
|
|
1305
1299
|
for (let e of t.tools) {
|
|
1300
|
+
if (e.heading !== void 0) {
|
|
1301
|
+
let t = document.createElement("div");
|
|
1302
|
+
t.className = "tcw-flyout-heading", t.setAttribute("role", "presentation"), t.textContent = e.heading, n.appendChild(t);
|
|
1303
|
+
}
|
|
1306
1304
|
let t = document.createElement("div");
|
|
1307
1305
|
t.className = "tcw-flyout-row", t.setAttribute("role", "none"), t.dataset.toolValue = e.value;
|
|
1308
|
-
let
|
|
1309
|
-
|
|
1306
|
+
let i = document.createElement("button");
|
|
1307
|
+
i.className = "tcw-flyout-item", i.setAttribute("role", "menuitem"), i.tabIndex = -1, i.innerHTML = y(e.value, Xn);
|
|
1310
1308
|
let a = document.createElement("span");
|
|
1311
|
-
a.className = "tcw-flyout-name", a.textContent = e.label,
|
|
1309
|
+
a.className = "tcw-flyout-name", a.textContent = e.label, i.appendChild(a);
|
|
1312
1310
|
let o = this.config.shortcuts?.[e.value];
|
|
1313
1311
|
if (o) {
|
|
1314
1312
|
let e = document.createElement("kbd");
|
|
1315
|
-
e.className = "tcw-flyout-key", e.textContent = o, v(e, "hotkeys", "hotkeys.tools"),
|
|
1313
|
+
e.className = "tcw-flyout-key", e.textContent = o, v(e, "hotkeys", "hotkeys.tools"), i.appendChild(e);
|
|
1316
1314
|
}
|
|
1317
|
-
if (
|
|
1315
|
+
if (i.dataset.toolValue = e.value, i.addEventListener("click", () => {
|
|
1318
1316
|
this.hideFlyout(), this.pick(e.value);
|
|
1319
|
-
}), t.appendChild(
|
|
1317
|
+
}), t.appendChild(i), this.callbacks.onToggleFavorite) {
|
|
1320
1318
|
let n = this.favorites.includes(e.value);
|
|
1321
1319
|
t.classList.toggle("tcw-flyout-faved", n);
|
|
1322
1320
|
let a = document.createElement("button");
|
|
1323
|
-
a.type = "button", a.className = "tcw-flyout-pin", a.dataset.pin = e.value, a.tabIndex = -1, a.title =
|
|
1321
|
+
a.type = "button", a.className = "tcw-flyout-pin", a.dataset.pin = e.value, a.tabIndex = -1, a.title = r, a.setAttribute("aria-label", `${r}: ${e.label}`), a.setAttribute("aria-pressed", String(n)), a.innerHTML = b("star", 12), a.addEventListener("click", (t) => {
|
|
1324
1322
|
t.stopPropagation(), this.callbacks.onToggleFavorite?.(e.value);
|
|
1325
|
-
}), t.appendChild(a),
|
|
1323
|
+
}), t.appendChild(a), i.addEventListener("contextmenu", (t) => {
|
|
1326
1324
|
t.preventDefault(), this.callbacks.onToggleFavorite?.(e.value);
|
|
1327
1325
|
});
|
|
1328
1326
|
}
|
|
@@ -1684,13 +1682,13 @@ function F() {
|
|
|
1684
1682
|
let e = document.activeElement;
|
|
1685
1683
|
return !!e && (e.tagName === "INPUT" || e.tagName === "TEXTAREA" || e.tagName === "SELECT" || e.isContentEditable);
|
|
1686
1684
|
}
|
|
1687
|
-
function
|
|
1685
|
+
function I() {
|
|
1688
1686
|
let e = document.activeElement;
|
|
1689
1687
|
return e instanceof Element && e.closest("[role=\"dialog\"], [aria-modal=\"true\"], [role=\"menu\"]") !== null;
|
|
1690
1688
|
}
|
|
1691
1689
|
//#endregion
|
|
1692
1690
|
//#region src/widget/WidgetReplayBar.ts
|
|
1693
|
-
var
|
|
1691
|
+
var gr = {
|
|
1694
1692
|
selectHint: "Click a bar to start the replay",
|
|
1695
1693
|
random: "Random bar",
|
|
1696
1694
|
realtime: "Back to realtime",
|
|
@@ -1710,7 +1708,7 @@ var _r = {
|
|
|
1710
1708
|
playingAt: "Playing at {rate}",
|
|
1711
1709
|
pausedAt: "Paused at {time}",
|
|
1712
1710
|
endedAt: "Replay ended at {time}"
|
|
1713
|
-
},
|
|
1711
|
+
}, _r = [
|
|
1714
1712
|
.1,
|
|
1715
1713
|
.2,
|
|
1716
1714
|
.3,
|
|
@@ -1723,18 +1721,18 @@ var _r = {
|
|
|
1723
1721
|
20,
|
|
1724
1722
|
30,
|
|
1725
1723
|
50
|
|
1726
|
-
],
|
|
1724
|
+
], vr = [
|
|
1727
1725
|
"full",
|
|
1728
1726
|
"compact",
|
|
1729
1727
|
"stack"
|
|
1730
|
-
],
|
|
1728
|
+
], yr = 300, br = 2, xr = [
|
|
1731
1729
|
"random",
|
|
1732
1730
|
"stepBack",
|
|
1733
1731
|
"stepForward",
|
|
1734
1732
|
"seek",
|
|
1735
1733
|
"step",
|
|
1736
1734
|
"selectBar"
|
|
1737
|
-
],
|
|
1735
|
+
], Sr = class {
|
|
1738
1736
|
root = null;
|
|
1739
1737
|
scrubber = null;
|
|
1740
1738
|
timeLabel = null;
|
|
@@ -1758,7 +1756,7 @@ var _r = {
|
|
|
1758
1756
|
labels;
|
|
1759
1757
|
constructor(e, t = {}) {
|
|
1760
1758
|
this.callbacks = e, this.labels = {
|
|
1761
|
-
...
|
|
1759
|
+
...gr,
|
|
1762
1760
|
...t
|
|
1763
1761
|
}, this.formatRate = (e) => this.labels.rate.replace("{rate}", String(e));
|
|
1764
1762
|
}
|
|
@@ -1791,7 +1789,7 @@ var _r = {
|
|
|
1791
1789
|
if (this.pending === e) return;
|
|
1792
1790
|
this.pending = e;
|
|
1793
1791
|
let t = document.activeElement;
|
|
1794
|
-
e && t && t !== this.playBtn && this.root?.contains(t) &&
|
|
1792
|
+
e && t && t !== this.playBtn && this.root?.contains(t) && xr.includes(t.dataset.act ?? "") && this.playBtn?.focus(), this.syncUi(), e && this.mode === "replay" && this.announce(this.labels.loading);
|
|
1795
1793
|
}
|
|
1796
1794
|
isPending() {
|
|
1797
1795
|
return this.pending;
|
|
@@ -1807,7 +1805,7 @@ var _r = {
|
|
|
1807
1805
|
if (this.where = r, this.scrubber) {
|
|
1808
1806
|
this.scrubber.max = String(Math.max(0, t - 1)), this.scrubber.value = String(e), this.scrubber.setAttribute("aria-valuetext", r);
|
|
1809
1807
|
let n = t > 1 ? Math.min(e, t - 1) / (t - 1) * 100 : 0;
|
|
1810
|
-
this.scrubber.style.setProperty("--tcw-replay-done", `${Number(n.toFixed(
|
|
1808
|
+
this.scrubber.style.setProperty("--tcw-replay-done", `${Number(n.toFixed(br))}%`);
|
|
1811
1809
|
}
|
|
1812
1810
|
if (this.timeLabel) {
|
|
1813
1811
|
this.timeLabel.textContent = r;
|
|
@@ -1820,7 +1818,7 @@ var _r = {
|
|
|
1820
1818
|
setRoom(e) {
|
|
1821
1819
|
let t = this.root;
|
|
1822
1820
|
if (t) {
|
|
1823
|
-
for (let n of
|
|
1821
|
+
for (let n of vr) if (n === "stack" || this.widthIn(n) <= e) {
|
|
1824
1822
|
t.dataset.fit = n, this.orderFor(n);
|
|
1825
1823
|
return;
|
|
1826
1824
|
}
|
|
@@ -1849,7 +1847,7 @@ var _r = {
|
|
|
1849
1847
|
return delete t.dataset.measure, i && (t.dataset.fit = i), a > 0 && this.widths.set(n, a), a;
|
|
1850
1848
|
}
|
|
1851
1849
|
markup() {
|
|
1852
|
-
let e = this.labels, t = `dir="${this.dir}"`, n =
|
|
1850
|
+
let e = this.labels, t = `dir="${this.dir}"`, n = _r.map((e) => `<option value="${e}"${e === this.rate ? " selected" : ""}>${x(this.formatRate(e))}</option>`).join(""), r = (e, t, n, r = "tcw-replay-btn", i = "") => `<button type="button" class="${r}" data-act="${e}" title="${x(t)}" aria-label="${x(t)}"${i}>${n}</button>`;
|
|
1853
1851
|
return `
|
|
1854
1852
|
<span class="tcw-replay-group tcw-replay-picking" data-mode="select">
|
|
1855
1853
|
<span class="tcw-replay-hint" ${t}>${b("cursor", 14)}<span data-tcw="hint">${x(e.selectHint)}</span></span>
|
|
@@ -1914,7 +1912,7 @@ var _r = {
|
|
|
1914
1912
|
announce(e) {
|
|
1915
1913
|
this.announceTimer && clearTimeout(this.announceTimer), this.announceTimer = setTimeout(() => {
|
|
1916
1914
|
this.announceTimer = null, this.liveRegion && (this.liveRegion.textContent = e);
|
|
1917
|
-
},
|
|
1915
|
+
}, yr);
|
|
1918
1916
|
}
|
|
1919
1917
|
syncUi() {
|
|
1920
1918
|
let e = this.root;
|
|
@@ -1931,12 +1929,12 @@ var _r = {
|
|
|
1931
1929
|
syncPending(e) {
|
|
1932
1930
|
for (let t of e.querySelectorAll(".tcw-replay-group")) this.pending ? t.setAttribute("aria-busy", "true") : t.removeAttribute("aria-busy");
|
|
1933
1931
|
this.hintText && (this.hintText.textContent = this.pending ? this.labels.loading : this.labels.selectHint);
|
|
1934
|
-
for (let t of
|
|
1932
|
+
for (let t of xr) {
|
|
1935
1933
|
let n = e.querySelector(`[data-act="${t}"]`);
|
|
1936
1934
|
n && (n.disabled = this.pending);
|
|
1937
1935
|
}
|
|
1938
1936
|
}
|
|
1939
|
-
},
|
|
1937
|
+
}, Cr = 864e5, wr = 6e4, Tr = 1e3, Er = 150, Dr = 5e3, Or = 8, kr = class {
|
|
1940
1938
|
replayBar = null;
|
|
1941
1939
|
replayPollInterval = null;
|
|
1942
1940
|
replaySpeed = 1;
|
|
@@ -2012,7 +2010,7 @@ var _r = {
|
|
|
2012
2010
|
enterReplay() {
|
|
2013
2011
|
if (this.replayTotal() < 2) return;
|
|
2014
2012
|
let e = this.t;
|
|
2015
|
-
this.replayBar = new
|
|
2013
|
+
this.replayBar = new Sr({
|
|
2016
2014
|
onPlay: () => {
|
|
2017
2015
|
if (this.replayBar?.getMode() === "select") {
|
|
2018
2016
|
this.seriesPending() || this.startReplayAt(Math.max(1, this.replayTotal() - 100), !0);
|
|
@@ -2100,7 +2098,7 @@ var _r = {
|
|
|
2100
2098
|
let e = this.replayBar?.element();
|
|
2101
2099
|
if (!e || !this.replayBar) return;
|
|
2102
2100
|
let t = this.chart.getPlotRect(), n = this.chartContainer, r = (e) => `${Math.max(0, Math.round(e))}px`;
|
|
2103
|
-
e.style.setProperty("--tcw-replay-foot", r(n.clientHeight - (t.y + t.height))), e.style.setProperty("--tcw-replay-plot-start", r(t.x)), e.style.setProperty("--tcw-replay-plot-end", r(n.clientWidth - (t.x + t.width))), this.replayBar.setRoom(t.width - 2 *
|
|
2101
|
+
e.style.setProperty("--tcw-replay-foot", r(n.clientHeight - (t.y + t.height))), e.style.setProperty("--tcw-replay-plot-start", r(t.x)), e.style.setProperty("--tcw-replay-plot-end", r(n.clientWidth - (t.x + t.width))), this.replayBar.setRoom(t.width - 2 * Or), this.liftOverReplayBar();
|
|
2104
2102
|
}
|
|
2105
2103
|
liftOverReplayBar() {
|
|
2106
2104
|
let e = this.replayBar?.element();
|
|
@@ -2121,13 +2119,13 @@ var _r = {
|
|
|
2121
2119
|
};
|
|
2122
2120
|
a(t) !== a(Date.now()) && (o.year = "numeric");
|
|
2123
2121
|
let s = ft(n, o, r)(t);
|
|
2124
|
-
if (Number.isFinite(i) && i >=
|
|
2122
|
+
if (Number.isFinite(i) && i >= Cr) return s;
|
|
2125
2123
|
let c = {
|
|
2126
2124
|
hour: "2-digit",
|
|
2127
2125
|
minute: "2-digit",
|
|
2128
2126
|
hourCycle: "h23"
|
|
2129
2127
|
};
|
|
2130
|
-
return (!Number.isFinite(i) || i <
|
|
2128
|
+
return (!Number.isFinite(i) || i < wr) && (c.second = "2-digit"), `${s} · ${ft(n, c, r)(t)}`;
|
|
2131
2129
|
}
|
|
2132
2130
|
replayBarCount() {
|
|
2133
2131
|
return this.chart.isReplayActive() && this.replayBarsTotal !== null ? this.replayBarsTotal : this.chart.getData().length;
|
|
@@ -2172,7 +2170,7 @@ var _r = {
|
|
|
2172
2170
|
if (this.seriesPending()) return;
|
|
2173
2171
|
this.replayPickTime = null;
|
|
2174
2172
|
let t = this.chart.getData();
|
|
2175
|
-
if (!
|
|
2173
|
+
if (!Ar(t, e)) return;
|
|
2176
2174
|
let n = 0;
|
|
2177
2175
|
for (; n + 1 < t.length && t[n + 1].time <= e;) n++;
|
|
2178
2176
|
this.startReplayAt(n, !1, !0);
|
|
@@ -2181,7 +2179,7 @@ var _r = {
|
|
|
2181
2179
|
return this.host.loading.isActive() && !this.host.loading.hasFailed();
|
|
2182
2180
|
}
|
|
2183
2181
|
watchReplayBar() {
|
|
2184
|
-
this.replayPollInterval && clearInterval(this.replayPollInterval), this.replayPollInterval = setInterval(() => this.syncReplayBar(),
|
|
2182
|
+
this.replayPollInterval && clearInterval(this.replayPollInterval), this.replayPollInterval = setInterval(() => this.syncReplayBar(), Er);
|
|
2185
2183
|
}
|
|
2186
2184
|
startReplayAt(e, t = !1, n = !1) {
|
|
2187
2185
|
let r = this.replayBar;
|
|
@@ -2193,7 +2191,7 @@ var _r = {
|
|
|
2193
2191
|
let c = this.host.options.replayAnimate !== !1, l = this.chartFetchesReplaySteps(), u = (e) => {
|
|
2194
2192
|
this.host.isDestroyed() || this.replayBar !== r || !r.isMounted() || s !== this.replayStartSeq || (this.replayStartPending = !1, this.replayStepsKey = e ? this.replayStepsKeyNow() : null, this.chart.replayStart({
|
|
2195
2193
|
speed: this.replaySpeed,
|
|
2196
|
-
interval: c ?
|
|
2194
|
+
interval: c ? Tr : Tr / this.replayStepsPerBar(e ? d : null),
|
|
2197
2195
|
...o === void 0 ? { startIndex: a } : { startTime: o },
|
|
2198
2196
|
paused: !0,
|
|
2199
2197
|
revealMarks: this.host.options.replayRevealMarks !== !1,
|
|
@@ -2239,7 +2237,7 @@ var _r = {
|
|
|
2239
2237
|
if (this.replayStepsCache?.key === i()) return this.replayStepsCache.steps;
|
|
2240
2238
|
let a = null, o = this.host.adapter(), s = this.host.baseSeries();
|
|
2241
2239
|
if (o) {
|
|
2242
|
-
let t = Math.max(1, Math.round(D(r) / D(e))), i = Math.min(
|
|
2240
|
+
let t = Math.max(1, Math.round(D(r) / D(e))), i = Math.min(Dr, Math.max(this.chart.getData().length, 100) * t);
|
|
2243
2241
|
try {
|
|
2244
2242
|
a = await O(o).fetchHistory(n, e, i);
|
|
2245
2243
|
} catch {
|
|
@@ -2282,7 +2280,7 @@ var _r = {
|
|
|
2282
2280
|
this.chart.replaySeek(Math.max(0, Math.min(t.total - 1, n))), this.replayBar.setState("paused"), this.syncReplayBar();
|
|
2283
2281
|
}
|
|
2284
2282
|
handleReplayKey(e) {
|
|
2285
|
-
if (e.defaultPrevented || e.isComposing || e.keyCode === 229 || F() ||
|
|
2283
|
+
if (e.defaultPrevented || e.isComposing || e.keyCode === 229 || F() || I() || !P(this.root, !0)) return !1;
|
|
2286
2284
|
let t = document.activeElement;
|
|
2287
2285
|
if (t && t !== document.body && !this.root.contains(t) || t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.tagName === "SELECT" || t.isContentEditable)) return !1;
|
|
2288
2286
|
let n = this.replayBar?.getMode();
|
|
@@ -2325,7 +2323,7 @@ var _r = {
|
|
|
2325
2323
|
(e(t) ? t : e(n) ? n : this.chartContainer)?.focus();
|
|
2326
2324
|
}
|
|
2327
2325
|
};
|
|
2328
|
-
function
|
|
2326
|
+
function Ar(e, t) {
|
|
2329
2327
|
let n = e.length;
|
|
2330
2328
|
if (n === 0 || t < e[0].time) return !1;
|
|
2331
2329
|
let r = e[n - 1].time;
|
|
@@ -2333,8 +2331,8 @@ function jr(e, t) {
|
|
|
2333
2331
|
}
|
|
2334
2332
|
//#endregion
|
|
2335
2333
|
//#region src/widget/pageEnv.ts
|
|
2336
|
-
var
|
|
2337
|
-
function
|
|
2334
|
+
var jr = () => typeof document < "u" && document.hidden;
|
|
2335
|
+
function L() {
|
|
2338
2336
|
try {
|
|
2339
2337
|
return typeof localStorage < "u" ? localStorage : null;
|
|
2340
2338
|
} catch {
|
|
@@ -2343,7 +2341,7 @@ function I() {
|
|
|
2343
2341
|
}
|
|
2344
2342
|
//#endregion
|
|
2345
2343
|
//#region src/widget/WidgetWatchlist.ts
|
|
2346
|
-
var
|
|
2344
|
+
var Mr = class {
|
|
2347
2345
|
el;
|
|
2348
2346
|
headerEl;
|
|
2349
2347
|
nameBtn;
|
|
@@ -2426,6 +2424,15 @@ var Nr = class {
|
|
|
2426
2424
|
}
|
|
2427
2425
|
this.active && this.setActive(this.active);
|
|
2428
2426
|
}
|
|
2427
|
+
place(e, t) {
|
|
2428
|
+
let n = [
|
|
2429
|
+
"symbol",
|
|
2430
|
+
...this.options.sparkline ? ["spark", "price"] : ["price", "move"],
|
|
2431
|
+
"change",
|
|
2432
|
+
...this.callbacks.onRemove ? ["remove"] : []
|
|
2433
|
+
];
|
|
2434
|
+
e.style.gridColumnStart = String(n.indexOf(t) + 2);
|
|
2435
|
+
}
|
|
2429
2436
|
makeHead() {
|
|
2430
2437
|
let e = this.labels.columns;
|
|
2431
2438
|
if (!e) return null;
|
|
@@ -2433,7 +2440,7 @@ var Nr = class {
|
|
|
2433
2440
|
t.className = "tcw-watchlist-columns", t.setAttribute("aria-hidden", "true");
|
|
2434
2441
|
let n = (e, n) => {
|
|
2435
2442
|
let r = document.createElement("span");
|
|
2436
|
-
r.className = `tcw-watchlist-column-${n}`, r.textContent = e, t.appendChild(r);
|
|
2443
|
+
r.className = `tcw-watchlist-column-${n}`, r.textContent = e, this.place(r, n), t.appendChild(r);
|
|
2437
2444
|
};
|
|
2438
2445
|
return n(e.symbol, "symbol"), this.options.sparkline && n("", "spark"), n(e.price, "price"), this.options.sparkline || n(e.move, "move"), n(e.change, "change"), this.callbacks.onRemove && n("", "remove"), t;
|
|
2439
2446
|
}
|
|
@@ -2441,12 +2448,12 @@ var Nr = class {
|
|
|
2441
2448
|
let t = document.createElement("div");
|
|
2442
2449
|
t.className = "tcw-watchlist-row", t.setAttribute("role", "listitem"), t.dataset.symbol = e, t.tabIndex = 0, t.draggable = !!this.callbacks.onMove;
|
|
2443
2450
|
let n = document.createElement("div");
|
|
2444
|
-
n.className = "tcw-watchlist-symbol", n.textContent =
|
|
2451
|
+
n.className = "tcw-watchlist-symbol", n.textContent = Nr(e), e.includes(":") && (n.title = e), this.place(n, "symbol"), t.appendChild(n);
|
|
2445
2452
|
let r = null;
|
|
2446
|
-
this.options.sparkline && (r = document.createElement("canvas"), r.className = "tcw-watchlist-spark", r.width = 64, r.height = 22, t.appendChild(r));
|
|
2453
|
+
this.options.sparkline && (r = document.createElement("canvas"), r.className = "tcw-watchlist-spark", r.width = 64, r.height = 22, this.place(r, "spark"), t.appendChild(r));
|
|
2447
2454
|
let i = (e, n = "") => {
|
|
2448
2455
|
let r = document.createElement("span");
|
|
2449
|
-
return r.className = `tcw-watchlist-${e}`, r.textContent = n, t.appendChild(r), r;
|
|
2456
|
+
return r.className = `tcw-watchlist-${e}`, r.textContent = n, this.place(r, e), t.appendChild(r), r;
|
|
2450
2457
|
}, a = i("price", "—"), o = this.options.sparkline ? null : i("move"), s = i("change");
|
|
2451
2458
|
if (this.callbacks.onRemove) {
|
|
2452
2459
|
t.classList.add("tcw-watchlist-removable");
|
|
@@ -2455,7 +2462,7 @@ var Nr = class {
|
|
|
2455
2462
|
let r = C(this.labels.remove, { symbol: e });
|
|
2456
2463
|
n.title = r, n.setAttribute("aria-label", r), n.addEventListener("click", (t) => {
|
|
2457
2464
|
t.stopPropagation(), this.callbacks.onRemove?.(e);
|
|
2458
|
-
}), t.appendChild(n);
|
|
2465
|
+
}), this.place(n, "remove"), t.appendChild(n);
|
|
2459
2466
|
}
|
|
2460
2467
|
t.addEventListener("click", () => this.callbacks.onSelect(e)), t.addEventListener("keydown", (t) => this.onRowKey(t, e)), t.addEventListener("dragstart", (n) => {
|
|
2461
2468
|
this.dragging = e, n.dataTransfer?.setData("text/plain", e), n.dataTransfer && (n.dataTransfer.effectAllowed = "move"), t.classList.add("tcw-watchlist-dragging");
|
|
@@ -2501,14 +2508,14 @@ var Nr = class {
|
|
|
2501
2508
|
renderRow(e) {
|
|
2502
2509
|
let t = this.rowMap.get(e), n = this.entries.get(e);
|
|
2503
2510
|
if (!(!t || !n)) {
|
|
2504
|
-
if (n.lastPrice !== void 0 && (t.priceEl.textContent =
|
|
2511
|
+
if (n.lastPrice !== void 0 && (t.priceEl.textContent = Pr(n.lastPrice, this.locale)), n.lastPrice !== void 0 && n.refPrice !== void 0 && n.refPrice !== 0) {
|
|
2505
2512
|
let e = n.lastPrice - n.refPrice, r = e / n.refPrice * 100, i = e >= 0 ? "+" : "-", a = e >= 0 ? "tcw-up" : "tcw-down", o = Math.abs(r).toLocaleString(this.locale, {
|
|
2506
2513
|
minimumFractionDigits: 2,
|
|
2507
2514
|
maximumFractionDigits: 2
|
|
2508
2515
|
});
|
|
2509
|
-
t.moveEl && (t.moveEl.textContent = `${i}${
|
|
2516
|
+
t.moveEl && (t.moveEl.textContent = `${i}${Fr(Math.abs(e), n.lastPrice, this.locale)}`, t.moveEl.className = `tcw-watchlist-move ${a}`), t.changeEl.textContent = `${i}${o}%`, t.changeEl.className = `tcw-watchlist-change ${a}`;
|
|
2510
2517
|
} else t.moveEl && (t.moveEl.textContent = ""), t.changeEl.textContent = "";
|
|
2511
|
-
t.sparkCanvas && n.sparkline && n.sparkline.length >= 2 &&
|
|
2518
|
+
t.sparkCanvas && n.sparkline && n.sparkline.length >= 2 && Ir(t.sparkCanvas, n.sparkline, n.refPrice ?? n.sparkline[0]);
|
|
2512
2519
|
}
|
|
2513
2520
|
}
|
|
2514
2521
|
openMenu() {
|
|
@@ -2567,7 +2574,7 @@ var Nr = class {
|
|
|
2567
2574
|
}), n.addEventListener("blur", () => i(!1)), n.focus();
|
|
2568
2575
|
}
|
|
2569
2576
|
};
|
|
2570
|
-
function
|
|
2577
|
+
function Nr(e) {
|
|
2571
2578
|
let t = e.slice(e.lastIndexOf(":") + 1) || e;
|
|
2572
2579
|
for (let e of [
|
|
2573
2580
|
"USDT",
|
|
@@ -2578,7 +2585,7 @@ function Pr(e) {
|
|
|
2578
2585
|
]) if (t.length > e.length && t.endsWith(e)) return t.slice(0, -e.length) + "/" + e;
|
|
2579
2586
|
return t;
|
|
2580
2587
|
}
|
|
2581
|
-
function
|
|
2588
|
+
function Pr(e, t) {
|
|
2582
2589
|
if (e === 0) return "0";
|
|
2583
2590
|
let n = Math.abs(e);
|
|
2584
2591
|
return n >= 1e3 ? e.toLocaleString(t, {
|
|
@@ -2589,7 +2596,7 @@ function Fr(e, t) {
|
|
|
2589
2596
|
maximumFractionDigits: 4
|
|
2590
2597
|
}) : Number(e.toPrecision(4)).toLocaleString(t, { maximumFractionDigits: 10 });
|
|
2591
2598
|
}
|
|
2592
|
-
function
|
|
2599
|
+
function Fr(e, t, n) {
|
|
2593
2600
|
let r = Math.abs(t);
|
|
2594
2601
|
if (r >= 1e3) return e.toLocaleString(n, {
|
|
2595
2602
|
minimumFractionDigits: 2,
|
|
@@ -2602,7 +2609,7 @@ function Ir(e, t, n) {
|
|
|
2602
2609
|
let i = r > 0 ? Math.min(10, Math.max(0, 3 - Math.floor(Math.log10(r)))) : 4;
|
|
2603
2610
|
return e.toLocaleString(n, { maximumFractionDigits: i });
|
|
2604
2611
|
}
|
|
2605
|
-
function
|
|
2612
|
+
function Ir(e, t, n) {
|
|
2606
2613
|
let r = e.getContext("2d");
|
|
2607
2614
|
if (!r) return;
|
|
2608
2615
|
let i = window.devicePixelRatio || 1;
|
|
@@ -2620,28 +2627,28 @@ function Lr(e, t, n) {
|
|
|
2620
2627
|
}
|
|
2621
2628
|
//#endregion
|
|
2622
2629
|
//#region src/widget/WatchlistStore.ts
|
|
2623
|
-
var
|
|
2624
|
-
function
|
|
2630
|
+
var Lr = 50, Rr = 500, zr = 60, Br = (e) => typeof e == "string" && e.trim().slice(0, zr) || null;
|
|
2631
|
+
function Vr(e) {
|
|
2625
2632
|
let t = [];
|
|
2626
2633
|
for (let n of e) {
|
|
2627
2634
|
let e = Se(n);
|
|
2628
|
-
if (e && !t.includes(e) && t.push(e), t.length ===
|
|
2635
|
+
if (e && !t.includes(e) && t.push(e), t.length === Rr) break;
|
|
2629
2636
|
}
|
|
2630
2637
|
return t;
|
|
2631
2638
|
}
|
|
2632
|
-
function
|
|
2639
|
+
function Hr(e) {
|
|
2633
2640
|
if (!e || typeof e != "object") return null;
|
|
2634
2641
|
let t = e;
|
|
2635
2642
|
if (!Array.isArray(t.lists)) return null;
|
|
2636
2643
|
let n = [];
|
|
2637
2644
|
for (let e of t.lists) {
|
|
2638
|
-
if (n.length ===
|
|
2645
|
+
if (n.length === Lr) break;
|
|
2639
2646
|
if (!e || typeof e != "object") continue;
|
|
2640
|
-
let t = e, r = typeof t.id == "string" && t.id && t.id.length <= 64 ? t.id : null, i =
|
|
2647
|
+
let t = e, r = typeof t.id == "string" && t.id && t.id.length <= 64 ? t.id : null, i = Br(t.name);
|
|
2641
2648
|
!r || !i || n.some((e) => e.id === r) || n.push({
|
|
2642
2649
|
id: r,
|
|
2643
2650
|
name: i,
|
|
2644
|
-
symbols: Array.isArray(t.symbols) ?
|
|
2651
|
+
symbols: Array.isArray(t.symbols) ? Vr(t.symbols) : []
|
|
2645
2652
|
});
|
|
2646
2653
|
}
|
|
2647
2654
|
return n.length === 0 ? null : {
|
|
@@ -2649,10 +2656,10 @@ function Ur(e) {
|
|
|
2649
2656
|
active: typeof t.active == "string" && n.some((e) => e.id === t.active) ? t.active : n[0].id
|
|
2650
2657
|
};
|
|
2651
2658
|
}
|
|
2652
|
-
var
|
|
2659
|
+
var Ur = (e) => ({
|
|
2653
2660
|
...e,
|
|
2654
2661
|
symbols: [...e.symbols]
|
|
2655
|
-
}),
|
|
2662
|
+
}), Wr = class {
|
|
2656
2663
|
lists;
|
|
2657
2664
|
active;
|
|
2658
2665
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -2660,38 +2667,38 @@ var Wr = (e) => ({
|
|
|
2660
2667
|
storageKey;
|
|
2661
2668
|
constructor(e) {
|
|
2662
2669
|
this.storage = e.storage ?? null, this.storageKey = e.storageKey ?? "tcw:watchlists";
|
|
2663
|
-
let t = this.load(), n = e.lists ?
|
|
2670
|
+
let t = this.load(), n = e.lists ? Hr({
|
|
2664
2671
|
lists: e.lists,
|
|
2665
2672
|
active: e.activeList
|
|
2666
2673
|
}) : null, r = t ?? n ?? {
|
|
2667
2674
|
lists: [{
|
|
2668
2675
|
id: "default",
|
|
2669
|
-
name:
|
|
2670
|
-
symbols:
|
|
2676
|
+
name: Br(e.defaultName) ?? "Watchlist",
|
|
2677
|
+
symbols: Vr(e.symbols ?? [])
|
|
2671
2678
|
}],
|
|
2672
2679
|
active: "default"
|
|
2673
2680
|
};
|
|
2674
2681
|
this.lists = r.lists, this.active = r.active;
|
|
2675
2682
|
}
|
|
2676
2683
|
getLists() {
|
|
2677
|
-
return this.lists.map(
|
|
2684
|
+
return this.lists.map(Ur);
|
|
2678
2685
|
}
|
|
2679
2686
|
getActive() {
|
|
2680
|
-
return
|
|
2687
|
+
return Ur(this.activeList());
|
|
2681
2688
|
}
|
|
2682
2689
|
setActive(e) {
|
|
2683
2690
|
e === this.active || !this.lists.some((t) => t.id === e) || (this.active = e, this.changed());
|
|
2684
2691
|
}
|
|
2685
2692
|
replace(e, t) {
|
|
2686
|
-
let n =
|
|
2693
|
+
let n = Hr({
|
|
2687
2694
|
lists: e,
|
|
2688
2695
|
active: t ?? this.active
|
|
2689
2696
|
});
|
|
2690
2697
|
n && (this.lists = n.lists, this.active = n.active, this.changed());
|
|
2691
2698
|
}
|
|
2692
2699
|
create(e) {
|
|
2693
|
-
let t =
|
|
2694
|
-
if (!t || this.lists.length >=
|
|
2700
|
+
let t = Br(e);
|
|
2701
|
+
if (!t || this.lists.length >= Lr) return null;
|
|
2695
2702
|
let n = this.lists.length + 1;
|
|
2696
2703
|
for (; this.lists.some((e) => e.id === `list-${n}`);) n++;
|
|
2697
2704
|
let r = {
|
|
@@ -2699,10 +2706,10 @@ var Wr = (e) => ({
|
|
|
2699
2706
|
name: t,
|
|
2700
2707
|
symbols: []
|
|
2701
2708
|
};
|
|
2702
|
-
return this.lists = [...this.lists, r], this.active = r.id, this.changed(),
|
|
2709
|
+
return this.lists = [...this.lists, r], this.active = r.id, this.changed(), Ur(r);
|
|
2703
2710
|
}
|
|
2704
2711
|
rename(e, t) {
|
|
2705
|
-
let n =
|
|
2712
|
+
let n = Br(t);
|
|
2706
2713
|
n && this.update(e, (e) => ({
|
|
2707
2714
|
...e,
|
|
2708
2715
|
name: n
|
|
@@ -2713,7 +2720,7 @@ var Wr = (e) => ({
|
|
|
2713
2720
|
}
|
|
2714
2721
|
add(e, t = this.active) {
|
|
2715
2722
|
let n = Se(e), r = this.lists.find((e) => e.id === t);
|
|
2716
|
-
return !n || !r || r.symbols.includes(n) || r.symbols.length >=
|
|
2723
|
+
return !n || !r || r.symbols.includes(n) || r.symbols.length >= Rr ? !1 : (this.update(t, (e) => ({
|
|
2717
2724
|
...e,
|
|
2718
2725
|
symbols: [...e.symbols, n]
|
|
2719
2726
|
})), !0);
|
|
@@ -2756,7 +2763,7 @@ var Wr = (e) => ({
|
|
|
2756
2763
|
if (!this.storage) return null;
|
|
2757
2764
|
try {
|
|
2758
2765
|
let e = this.storage.getItem(this.storageKey);
|
|
2759
|
-
return e ?
|
|
2766
|
+
return e ? Hr(JSON.parse(e)) : null;
|
|
2760
2767
|
} catch {
|
|
2761
2768
|
return null;
|
|
2762
2769
|
}
|
|
@@ -2769,7 +2776,7 @@ var Wr = (e) => ({
|
|
|
2769
2776
|
}));
|
|
2770
2777
|
} catch {}
|
|
2771
2778
|
}
|
|
2772
|
-
},
|
|
2779
|
+
}, Gr = class {
|
|
2773
2780
|
el;
|
|
2774
2781
|
bodyEl;
|
|
2775
2782
|
newsEl;
|
|
@@ -2800,31 +2807,33 @@ var Wr = (e) => ({
|
|
|
2800
2807
|
}
|
|
2801
2808
|
render(e) {
|
|
2802
2809
|
let t = document.createElement("div");
|
|
2803
|
-
t.className = "tcw-syminfo-head"
|
|
2804
|
-
let n =
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
let
|
|
2812
|
-
|
|
2810
|
+
t.className = "tcw-syminfo-head";
|
|
2811
|
+
let { venue: n, ticker: r } = be(e.symbol), i = R("div", "tcw-syminfo-symbol", r);
|
|
2812
|
+
n && (i.title = e.symbol), t.append(i), e.description && t.append(R("div", "tcw-syminfo-desc", e.description)), e.meta && t.append(R("div", "tcw-syminfo-meta", e.meta));
|
|
2813
|
+
let a = document.createElement("div");
|
|
2814
|
+
if (a.className = "tcw-syminfo-quote", e.price && a.append(R("span", "tcw-syminfo-price", e.price)), e.change) {
|
|
2815
|
+
let t = R("span", "tcw-syminfo-change", e.change.text);
|
|
2816
|
+
t.classList.add(e.change.up ? "tcw-up" : "tcw-down"), a.append(t);
|
|
2817
|
+
}
|
|
2818
|
+
let o = R("div", "tcw-syminfo-status", e.status.text);
|
|
2819
|
+
o.dataset.state = e.status.state;
|
|
2820
|
+
let s = document.createElement("dl");
|
|
2821
|
+
s.className = "tcw-syminfo-stats";
|
|
2813
2822
|
for (let t of e.stats) {
|
|
2814
2823
|
let e = document.createElement("div");
|
|
2815
|
-
e.className = "tcw-syminfo-stat", e.append(
|
|
2824
|
+
e.className = "tcw-syminfo-stat", e.append(R("dt", "", t.label), R("dd", "", t.value)), s.append(e);
|
|
2816
2825
|
}
|
|
2817
|
-
this.bodyEl.replaceChildren(t,
|
|
2826
|
+
this.bodyEl.replaceChildren(t, a, o, s);
|
|
2818
2827
|
}
|
|
2819
2828
|
renderNews(e) {
|
|
2820
2829
|
if (this.newsEl.hidden = e.kind === "none", e.kind === "none") {
|
|
2821
2830
|
this.newsEl.replaceChildren();
|
|
2822
2831
|
return;
|
|
2823
2832
|
}
|
|
2824
|
-
let t =
|
|
2833
|
+
let t = R("div", "tcw-syminfo-news-title", this.t("symbolInfo.news"));
|
|
2825
2834
|
if (e.kind === "loading" || e.kind === "failed" || e.items.length === 0) {
|
|
2826
2835
|
let t = e.kind === "loading" ? "symbolInfo.loading" : e.kind === "failed" ? "symbolInfo.newsFailed" : "symbolInfo.noNews";
|
|
2827
|
-
this.newsEl.replaceChildren(
|
|
2836
|
+
this.newsEl.replaceChildren(R("div", "tcw-syminfo-news-note", this.t(t)));
|
|
2828
2837
|
return;
|
|
2829
2838
|
}
|
|
2830
2839
|
let n = document.createElement("ul");
|
|
@@ -2834,8 +2843,8 @@ var Wr = (e) => ({
|
|
|
2834
2843
|
if (e.className = "tcw-syminfo-news-item", t.url) {
|
|
2835
2844
|
let n = document.createElement("a");
|
|
2836
2845
|
n.href = t.url, n.target = "_blank", n.rel = "noopener noreferrer", n.textContent = t.title, e.append(n);
|
|
2837
|
-
} else e.append(
|
|
2838
|
-
t.meta && e.append(
|
|
2846
|
+
} else e.append(R("span", "", t.title));
|
|
2847
|
+
t.meta && e.append(R("div", "tcw-syminfo-news-meta", t.meta)), n.append(e);
|
|
2839
2848
|
}
|
|
2840
2849
|
this.newsEl.replaceChildren(t, n);
|
|
2841
2850
|
}
|
|
@@ -2843,17 +2852,17 @@ var Wr = (e) => ({
|
|
|
2843
2852
|
this.el.remove();
|
|
2844
2853
|
}
|
|
2845
2854
|
};
|
|
2846
|
-
function
|
|
2855
|
+
function R(e, t, n) {
|
|
2847
2856
|
let r = document.createElement(e);
|
|
2848
2857
|
return t && (r.className = t), r.textContent = n, r;
|
|
2849
2858
|
}
|
|
2850
2859
|
//#endregion
|
|
2851
2860
|
//#region src/widget/symbolInfoView.ts
|
|
2852
|
-
var
|
|
2853
|
-
function
|
|
2854
|
-
let { info: t, quote: n, t: r, textLocale: i } = e, a = ot(t), o =
|
|
2861
|
+
var Kr = 10, qr = 5 * 6e4, Jr = 864e5, Yr = 2;
|
|
2862
|
+
function Xr(e) {
|
|
2863
|
+
let { info: t, quote: n, t: r, textLocale: i } = e, a = ot(t), o = Qr(e.bars, a), s = e.formatPrice, c = n?.last ?? o?.close, l = n?.prevClose ?? o?.prevClose, u = n?.change ?? (c !== void 0 && l !== void 0 ? c - l : void 0), d = c !== void 0 && u !== void 0 ? c - u : void 0, f = n?.changePercent ?? (u !== void 0 && d ? u / d * 100 : void 0), p = qe(t, e.now), m = r(p.state === "open" ? "symbolInfo.open" : p.state === "closed" ? "symbolInfo.closed" : "symbolInfo.always");
|
|
2855
2864
|
if (p.state !== "always" && p.next !== null) {
|
|
2856
|
-
let t =
|
|
2865
|
+
let t = $r(p.next - e.now, i);
|
|
2857
2866
|
m += ` · ${C(r(p.state === "open" ? "symbolInfo.closesIn" : "symbolInfo.opensIn"), { when: t })}`;
|
|
2858
2867
|
}
|
|
2859
2868
|
let ee = [], h = (e, t) => {
|
|
@@ -2864,7 +2873,7 @@ function Zr(e) {
|
|
|
2864
2873
|
}, g = (e) => e === void 0 ? void 0 : s(e);
|
|
2865
2874
|
h(r("dataWindow.open"), g(n?.open ?? o?.open)), h(r("dataWindow.high"), g(n?.high ?? o?.high)), h(r("dataWindow.low"), g(n?.low ?? o?.low)), h(r("symbolInfo.prevClose"), g(l));
|
|
2866
2875
|
let te = n?.volume ?? o?.volume;
|
|
2867
|
-
h(r("dataWindow.volume"), te === void 0 ? void 0 :
|
|
2876
|
+
h(r("dataWindow.volume"), te === void 0 ? void 0 : ti(te, e.numberLocale)), h(r("symbolInfo.bid"), g(n?.bid)), h(r("symbolInfo.ask"), g(n?.ask)), h(r("symbolInfo.tick"), t?.minTick === void 0 ? void 0 : String(t.minTick)), h(r("symbolInfo.currency"), t?.currency), h(r("symbolInfo.timezone"), a), h(r("symbolInfo.hours"), ni(t, i));
|
|
2868
2877
|
let ne = (u ?? 0) >= 0 ? "+" : "-", _ = e.names === void 0 ? t : e.names;
|
|
2869
2878
|
return {
|
|
2870
2879
|
symbol: e.symbol,
|
|
@@ -2872,7 +2881,7 @@ function Zr(e) {
|
|
|
2872
2881
|
meta: [_?.exchange, _?.type].filter(Boolean).join(" · ") || void 0,
|
|
2873
2882
|
price: c === void 0 ? void 0 : s(c),
|
|
2874
2883
|
change: u === void 0 ? void 0 : {
|
|
2875
|
-
text: `${ne}${s(Math.abs(u))}${f === void 0 ? "" : ` (${ne}${
|
|
2884
|
+
text: `${ne}${s(Math.abs(u))}${f === void 0 ? "" : ` (${ne}${ei(Math.abs(f), Yr, e.numberLocale)}%)`}`,
|
|
2876
2885
|
up: u >= 0
|
|
2877
2886
|
},
|
|
2878
2887
|
status: {
|
|
@@ -2882,7 +2891,7 @@ function Zr(e) {
|
|
|
2882
2891
|
stats: ee
|
|
2883
2892
|
};
|
|
2884
2893
|
}
|
|
2885
|
-
var
|
|
2894
|
+
var Zr = class {
|
|
2886
2895
|
request = 0;
|
|
2887
2896
|
cache = /* @__PURE__ */ new Map();
|
|
2888
2897
|
load(e, t, n, r, i) {
|
|
@@ -2898,17 +2907,17 @@ var Qr = class {
|
|
|
2898
2907
|
items: e.map((e) => ({
|
|
2899
2908
|
title: e.title,
|
|
2900
2909
|
url: e.url,
|
|
2901
|
-
meta: [e.source,
|
|
2910
|
+
meta: [e.source, $r(e.time - t, r)].filter(Boolean).join(" · ")
|
|
2902
2911
|
}))
|
|
2903
2912
|
});
|
|
2904
2913
|
}, s = this.cache.get(e);
|
|
2905
|
-
if (s && Date.now() - s.at <
|
|
2914
|
+
if (s && Date.now() - s.at < qr) {
|
|
2906
2915
|
o(s.items);
|
|
2907
2916
|
return;
|
|
2908
2917
|
}
|
|
2909
|
-
n({ kind: "loading" }), Promise.resolve().then(() => t(e,
|
|
2918
|
+
n({ kind: "loading" }), Promise.resolve().then(() => t(e, Kr)).then((t) => {
|
|
2910
2919
|
if (a !== this.request || i()) return;
|
|
2911
|
-
let n = tt(t,
|
|
2920
|
+
let n = tt(t, Kr);
|
|
2912
2921
|
this.cache.set(e, {
|
|
2913
2922
|
at: Date.now(),
|
|
2914
2923
|
items: n
|
|
@@ -2918,11 +2927,11 @@ var Qr = class {
|
|
|
2918
2927
|
});
|
|
2919
2928
|
}
|
|
2920
2929
|
};
|
|
2921
|
-
function
|
|
2930
|
+
function Qr(e, t) {
|
|
2922
2931
|
if (e.length === 0) return null;
|
|
2923
2932
|
let n = t && Ke(t) ? t : null, r = T(e), i = (e) => {
|
|
2924
2933
|
let t = e * r;
|
|
2925
|
-
return Math.floor((t + (n ? dt(n, t) * 6e4 : 0)) /
|
|
2934
|
+
return Math.floor((t + (n ? dt(n, t) * 6e4 : 0)) / Jr);
|
|
2926
2935
|
}, a = e[e.length - 1], o = i(a.time), s = e.length - 1;
|
|
2927
2936
|
for (; s > 0 && i(e[s - 1].time) === o;) s--;
|
|
2928
2937
|
let c = -Infinity, l = Infinity, u = 0;
|
|
@@ -2936,7 +2945,7 @@ function $r(e, t) {
|
|
|
2936
2945
|
prevClose: s > 0 ? e[s - 1].close : void 0
|
|
2937
2946
|
};
|
|
2938
2947
|
}
|
|
2939
|
-
function
|
|
2948
|
+
function $r(e, t) {
|
|
2940
2949
|
let n = e / 6e4, [r, i] = Math.abs(n) < 60 ? [Math.round(n) || Math.sign(n) || 1, "minute"] : Math.abs(n) < 1440 ? [Math.round(n / 60), "hour"] : [Math.round(n / 1440), "day"];
|
|
2941
2950
|
try {
|
|
2942
2951
|
return new Intl.RelativeTimeFormat(t, { numeric: "auto" }).format(r, i);
|
|
@@ -2944,14 +2953,14 @@ function ei(e, t) {
|
|
|
2944
2953
|
return new Intl.RelativeTimeFormat("en", { numeric: "auto" }).format(r, i);
|
|
2945
2954
|
}
|
|
2946
2955
|
}
|
|
2947
|
-
function
|
|
2956
|
+
function ei(e, t, n) {
|
|
2948
2957
|
try {
|
|
2949
2958
|
return He(e, t, n);
|
|
2950
2959
|
} catch {
|
|
2951
2960
|
return e.toFixed(t);
|
|
2952
2961
|
}
|
|
2953
2962
|
}
|
|
2954
|
-
function
|
|
2963
|
+
function ti(e, t) {
|
|
2955
2964
|
try {
|
|
2956
2965
|
return new Intl.NumberFormat(t, {
|
|
2957
2966
|
notation: "compact",
|
|
@@ -2961,7 +2970,7 @@ function ni(e, t) {
|
|
|
2961
2970
|
return String(e);
|
|
2962
2971
|
}
|
|
2963
2972
|
}
|
|
2964
|
-
function
|
|
2973
|
+
function ni(e, t) {
|
|
2965
2974
|
let n = e?.sessions ?? [];
|
|
2966
2975
|
if (n.length === 0) return;
|
|
2967
2976
|
let r;
|
|
@@ -2990,7 +2999,7 @@ function ri(e, t) {
|
|
|
2990
2999
|
}
|
|
2991
3000
|
//#endregion
|
|
2992
3001
|
//#region src/widget/drawingHotkeys.ts
|
|
2993
|
-
var
|
|
3002
|
+
var ri = {
|
|
2994
3003
|
KeyT: "trendLine",
|
|
2995
3004
|
KeyH: "horizontalLine",
|
|
2996
3005
|
KeyJ: "horizontalRay",
|
|
@@ -2998,14 +3007,14 @@ var ii = {
|
|
|
2998
3007
|
KeyC: "crossLine",
|
|
2999
3008
|
KeyF: "fibRetracement"
|
|
3000
3009
|
};
|
|
3001
|
-
function
|
|
3010
|
+
function ii() {
|
|
3002
3011
|
let e = {};
|
|
3003
|
-
for (let [t, n] of Object.entries(
|
|
3012
|
+
for (let [t, n] of Object.entries(ri)) e[n] = `Alt+${t.replace(/^Key/, "")}`;
|
|
3004
3013
|
return e;
|
|
3005
3014
|
}
|
|
3006
3015
|
//#endregion
|
|
3007
3016
|
//#region src/widget/WidgetChartNav.ts
|
|
3008
|
-
var
|
|
3017
|
+
var ai = 300, oi = 80, si = Be ** -3, ci = 80, li = class {
|
|
3009
3018
|
el;
|
|
3010
3019
|
holdTimer = null;
|
|
3011
3020
|
repeatTimer = null;
|
|
@@ -3103,7 +3112,7 @@ var oi = 300, si = 80, ci = Be ** -3, li = 80, ui = class {
|
|
|
3103
3112
|
this.stopHold(), this.host.removeEventListener("pointermove", this.onMove), this.host.removeEventListener("pointerleave", this.onLeave), this.el.remove();
|
|
3104
3113
|
}
|
|
3105
3114
|
nearBottom(e) {
|
|
3106
|
-
let t = this.actions.plotRect(), n = this.host.getBoundingClientRect(), r = e.clientX - n.left, i = e.clientY - n.top, a = Math.max(
|
|
3115
|
+
let t = this.actions.plotRect(), n = this.host.getBoundingClientRect(), r = e.clientX - n.left, i = e.clientY - n.top, a = Math.max(ci, t.height * si);
|
|
3107
3116
|
return r >= t.x && r <= t.x + t.width && i <= t.y + t.height && i >= t.y + t.height - a;
|
|
3108
3117
|
}
|
|
3109
3118
|
place() {
|
|
@@ -3112,8 +3121,8 @@ var oi = 300, si = 80, ci = Be ** -3, li = 80, ui = class {
|
|
|
3112
3121
|
}
|
|
3113
3122
|
startHold(e) {
|
|
3114
3123
|
this.stopHold(), this.actions.scroll(e), this.holdTimer = setTimeout(() => {
|
|
3115
|
-
this.repeatTimer = setInterval(() => this.actions.scroll(e),
|
|
3116
|
-
},
|
|
3124
|
+
this.repeatTimer = setInterval(() => this.actions.scroll(e), oi);
|
|
3125
|
+
}, ai);
|
|
3117
3126
|
}
|
|
3118
3127
|
stopHold() {
|
|
3119
3128
|
this.holdTimer && clearTimeout(this.holdTimer), this.repeatTimer && clearInterval(this.repeatTimer), this.holdTimer = null, this.repeatTimer = null;
|
|
@@ -3121,17 +3130,17 @@ var oi = 300, si = 80, ci = Be ** -3, li = 80, ui = class {
|
|
|
3121
3130
|
};
|
|
3122
3131
|
//#endregion
|
|
3123
3132
|
//#region src/widget/WidgetAlertsPanel.ts
|
|
3124
|
-
function
|
|
3125
|
-
let i = e.label ?? t("alerts.source.price"), a =
|
|
3126
|
-
if (
|
|
3133
|
+
function ui(e, t, n, r = !1) {
|
|
3134
|
+
let i = e.label ?? t("alerts.source.price"), a = hi.get(e.condition), o = a ? t(a) : e.condition;
|
|
3135
|
+
if (fi.includes(e.condition)) return `${i} ${o} ${C(t("alerts.moveSummary"), {
|
|
3127
3136
|
percent: e.percent ?? 0,
|
|
3128
3137
|
bars: e.bars ?? 0
|
|
3129
3138
|
})}`;
|
|
3130
3139
|
if (e.target) return `${i} ${o} ${e.targetLabel ?? e.target}`;
|
|
3131
|
-
let s = e.channel && e.channel !== "price", c = Number.isFinite(e.price) ? s ?
|
|
3140
|
+
let s = e.channel && e.channel !== "price", c = Number.isFinite(e.price) ? s ? _i(e.price) : n(e.price) : "—";
|
|
3132
3141
|
return `${(s || e.drawingId) && e.label ? `${e.label} ` : r ? `${i} ` : ""}${o} ${c}`;
|
|
3133
3142
|
}
|
|
3134
|
-
var
|
|
3143
|
+
var di = [
|
|
3135
3144
|
{
|
|
3136
3145
|
value: "crossing",
|
|
3137
3146
|
key: "alerts.condition.crossing"
|
|
@@ -3160,20 +3169,20 @@ var fi = [
|
|
|
3160
3169
|
value: "movesDown",
|
|
3161
3170
|
key: "alerts.condition.movesDown"
|
|
3162
3171
|
}
|
|
3163
|
-
],
|
|
3172
|
+
], fi = ["movesUp", "movesDown"], pi = {
|
|
3164
3173
|
hour: 36e5,
|
|
3165
3174
|
day: 864e5,
|
|
3166
3175
|
week: 7 * 864e5,
|
|
3167
3176
|
month: 30 * 864e5
|
|
3168
|
-
},
|
|
3169
|
-
function
|
|
3177
|
+
}, mi = "", hi = new Map(di.map((e) => [e.value, e.key]));
|
|
3178
|
+
function gi(e) {
|
|
3170
3179
|
return Math.round(e * 1e6) / 1e6;
|
|
3171
3180
|
}
|
|
3172
|
-
function
|
|
3181
|
+
function _i(e) {
|
|
3173
3182
|
let t = Math.abs(e);
|
|
3174
3183
|
return t >= 1e3 || t >= 1 ? e.toFixed(2) : e.toPrecision(4);
|
|
3175
3184
|
}
|
|
3176
|
-
var
|
|
3185
|
+
var vi = class {
|
|
3177
3186
|
el;
|
|
3178
3187
|
listEl;
|
|
3179
3188
|
priceInput;
|
|
@@ -3207,7 +3216,7 @@ var yi = class {
|
|
|
3207
3216
|
o.className = "tcw-alerts-form", o.noValidate = !0, this.sourceSelect = document.createElement("select"), this.sourceSelect.className = "tcw-alerts-source", this.sourceSelect.setAttribute("aria-label", this.t("alerts.source")), this.sourceSelect.addEventListener("change", () => {
|
|
3208
3217
|
this.renderTargets(), this.prefillPrice();
|
|
3209
3218
|
}), this.conditionSelect = document.createElement("select"), this.conditionSelect.className = "tcw-alerts-condition", this.conditionSelect.setAttribute("aria-label", this.t("alerts.conditionLabel"));
|
|
3210
|
-
for (let e of
|
|
3219
|
+
for (let e of di) {
|
|
3211
3220
|
let t = document.createElement("option");
|
|
3212
3221
|
t.value = e.value, t.textContent = this.t(e.key), this.conditionSelect.appendChild(t);
|
|
3213
3222
|
}
|
|
@@ -3237,20 +3246,20 @@ var yi = class {
|
|
|
3237
3246
|
return i.type = "number", i.step = r, i.min = "0", i.value = n, i.className = e, i.placeholder = t, i.setAttribute("aria-label", t), i;
|
|
3238
3247
|
}
|
|
3239
3248
|
showFields() {
|
|
3240
|
-
let e =
|
|
3241
|
-
this.moveRow.hidden = !e, this.levelRow.hidden = e, this.priceInput.hidden = this.targetSelect.value !==
|
|
3249
|
+
let e = fi.includes(this.conditionSelect.value);
|
|
3250
|
+
this.moveRow.hidden = !e, this.levelRow.hidden = e, this.priceInput.hidden = this.targetSelect.value !== mi;
|
|
3242
3251
|
}
|
|
3243
3252
|
renderTargets() {
|
|
3244
3253
|
let e = this.targetSelect.value, t = this.sourceSelect.value || "price";
|
|
3245
3254
|
this.targetSelect.replaceChildren();
|
|
3246
3255
|
let n = document.createElement("option");
|
|
3247
|
-
n.value =
|
|
3256
|
+
n.value = mi, n.textContent = this.t("alerts.compare.value"), this.targetSelect.appendChild(n);
|
|
3248
3257
|
for (let e of this.sources) {
|
|
3249
3258
|
if (e.channel === t) continue;
|
|
3250
3259
|
let n = document.createElement("option");
|
|
3251
3260
|
n.value = e.channel, n.textContent = e.label, this.targetSelect.appendChild(n);
|
|
3252
3261
|
}
|
|
3253
|
-
this.targetSelect.value = [...this.targetSelect.options].some((t) => t.value === e) ? e :
|
|
3262
|
+
this.targetSelect.value = [...this.targetSelect.options].some((t) => t.value === e) ? e : mi, this.showFields();
|
|
3254
3263
|
}
|
|
3255
3264
|
setSources(e) {
|
|
3256
3265
|
this.sources = e.length > 0 ? e : [{
|
|
@@ -3281,7 +3290,7 @@ var yi = class {
|
|
|
3281
3290
|
}
|
|
3282
3291
|
prefillPrice() {
|
|
3283
3292
|
let e = this.callbacks.getChannelValue(this.sourceSelect.value || "price");
|
|
3284
|
-
this.priceInput.value = e === null ? "" : String(
|
|
3293
|
+
this.priceInput.value = e === null ? "" : String(gi(e));
|
|
3285
3294
|
}
|
|
3286
3295
|
close() {
|
|
3287
3296
|
this.open = !1, this.el.hidden = !0;
|
|
@@ -3294,20 +3303,20 @@ var yi = class {
|
|
|
3294
3303
|
}
|
|
3295
3304
|
submitForm() {
|
|
3296
3305
|
let e = this.conditionSelect.value, t = this.messageInput.value.trim() || void 0, n = this.sourceSelect.value || "price", r = this.sources.find((e) => e.channel === n)?.label ?? this.t("alerts.source.price"), i = {}, a = NaN;
|
|
3297
|
-
if (
|
|
3306
|
+
if (fi.includes(e)) {
|
|
3298
3307
|
i.percent = Number(this.percentInput.value), i.bars = Number(this.barsInput.value);
|
|
3299
3308
|
let e = Number.isInteger(i.bars) && i.bars >= ht && i.bars <= mt;
|
|
3300
3309
|
if (!(i.percent > 0) || !e) {
|
|
3301
3310
|
this.markInvalid(i.percent > 0 ? this.barsInput : this.percentInput);
|
|
3302
3311
|
return;
|
|
3303
3312
|
}
|
|
3304
|
-
} else if (this.targetSelect.value !==
|
|
3313
|
+
} else if (this.targetSelect.value !== mi) i.target = this.targetSelect.value;
|
|
3305
3314
|
else if (a = Number(this.priceInput.value), this.priceInput.value.trim() === "" || !Number.isFinite(a)) {
|
|
3306
3315
|
this.markInvalid(this.priceInput);
|
|
3307
3316
|
return;
|
|
3308
3317
|
}
|
|
3309
3318
|
this.closeCheck.checked && (i.onBarClose = !0);
|
|
3310
|
-
let o =
|
|
3319
|
+
let o = pi[this.expirySelect.value];
|
|
3311
3320
|
o && (i.expiresAt = (this.callbacks.now ?? Date.now)() + o), this.callbacks.onAdd({
|
|
3312
3321
|
price: a,
|
|
3313
3322
|
condition: e,
|
|
@@ -3321,7 +3330,7 @@ var yi = class {
|
|
|
3321
3330
|
e.setAttribute("aria-invalid", "true"), e.focus(), e.addEventListener("input", () => e.removeAttribute("aria-invalid"), { once: !0 });
|
|
3322
3331
|
}
|
|
3323
3332
|
describe(e) {
|
|
3324
|
-
return
|
|
3333
|
+
return ui(e, this.t, this.callbacks.formatPrice);
|
|
3325
3334
|
}
|
|
3326
3335
|
renderList() {
|
|
3327
3336
|
if (this.listEl.replaceChildren(), this.alerts.length === 0) {
|
|
@@ -3356,16 +3365,16 @@ var yi = class {
|
|
|
3356
3365
|
a.type = "button", a.className = "tcw-alerts-del", a.setAttribute("aria-label", this.t("alerts.delete")), a.innerHTML = b("trash", 14), a.addEventListener("click", () => this.callbacks.onRemove(e.id)), t.appendChild(n), t.appendChild(a), this.listEl.appendChild(t);
|
|
3357
3366
|
}
|
|
3358
3367
|
}
|
|
3359
|
-
},
|
|
3368
|
+
}, yi = "print", bi = 3, xi = 10, Si = [
|
|
3360
3369
|
[3400, 1 / 2],
|
|
3361
3370
|
[2560, 1 / 3],
|
|
3362
3371
|
[1800, 1 / 6]
|
|
3363
|
-
],
|
|
3364
|
-
function
|
|
3365
|
-
let t =
|
|
3372
|
+
], Ci = Math.sqrt(Be), wi = 3, Ti = .5, Ei = 3, Di = .75, Oi = 2;
|
|
3373
|
+
function ki(e) {
|
|
3374
|
+
let t = Si.find(([t]) => e >= t);
|
|
3366
3375
|
return t ? Be ** t[1] : 1;
|
|
3367
3376
|
}
|
|
3368
|
-
function
|
|
3377
|
+
function Ai(e, t) {
|
|
3369
3378
|
if (t === 1) return e;
|
|
3370
3379
|
let n = e.sizes, r = (e) => Math.round(e * t);
|
|
3371
3380
|
return {
|
|
@@ -3384,10 +3393,10 @@ function ji(e, t) {
|
|
|
3384
3393
|
}
|
|
3385
3394
|
};
|
|
3386
3395
|
}
|
|
3387
|
-
function
|
|
3388
|
-
return Math.max(
|
|
3396
|
+
function z(e, t) {
|
|
3397
|
+
return Math.max(xi, Ze(e, t, bi));
|
|
3389
3398
|
}
|
|
3390
|
-
var
|
|
3399
|
+
var ji = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", Mi = "'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', 'Consolas', ui-monospace, monospace", Ni = Ve.replace("'Segoe UI'", "'Segoe UI Variable Text', 'Segoe UI'"), Pi = "'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif", Fi = "Tahoma, Verdana, 'Segoe UI', 'DejaVu Sans', sans-serif", Ii = {
|
|
3391
3400
|
print: {
|
|
3392
3401
|
radius: {
|
|
3393
3402
|
xs: 1,
|
|
@@ -3406,7 +3415,7 @@ var Mi = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", Ni = "'JetB
|
|
|
3406
3415
|
control: 33,
|
|
3407
3416
|
controlSmall: 26,
|
|
3408
3417
|
icon: 20,
|
|
3409
|
-
sidebar:
|
|
3418
|
+
sidebar: 42,
|
|
3410
3419
|
menuItem: 33
|
|
3411
3420
|
},
|
|
3412
3421
|
density: {
|
|
@@ -3415,7 +3424,7 @@ var Mi = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", Ni = "'JetB
|
|
|
3415
3424
|
control: 26,
|
|
3416
3425
|
controlSmall: 20,
|
|
3417
3426
|
icon: 16,
|
|
3418
|
-
sidebar:
|
|
3427
|
+
sidebar: 32,
|
|
3419
3428
|
menuItem: 26
|
|
3420
3429
|
},
|
|
3421
3430
|
spacious: {
|
|
@@ -3423,13 +3432,13 @@ var Mi = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", Ni = "'JetB
|
|
|
3423
3432
|
control: 42,
|
|
3424
3433
|
controlSmall: 33,
|
|
3425
3434
|
icon: 26,
|
|
3426
|
-
sidebar:
|
|
3435
|
+
sidebar: 59,
|
|
3427
3436
|
menuItem: 42
|
|
3428
3437
|
}
|
|
3429
3438
|
},
|
|
3430
3439
|
font: {
|
|
3431
|
-
family:
|
|
3432
|
-
mono:
|
|
3440
|
+
family: Ni,
|
|
3441
|
+
mono: Pi,
|
|
3433
3442
|
size: 13,
|
|
3434
3443
|
weight: 400,
|
|
3435
3444
|
strongWeight: 500,
|
|
@@ -3470,12 +3479,12 @@ var Mi = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", Ni = "'JetB
|
|
|
3470
3479
|
control: 30,
|
|
3471
3480
|
controlSmall: 24,
|
|
3472
3481
|
icon: 18,
|
|
3473
|
-
sidebar:
|
|
3482
|
+
sidebar: 44,
|
|
3474
3483
|
menuItem: 30
|
|
3475
3484
|
},
|
|
3476
3485
|
font: {
|
|
3477
|
-
family: `'Manrope', 'Inter', ${
|
|
3478
|
-
mono:
|
|
3486
|
+
family: `'Manrope', 'Inter', ${ji}`,
|
|
3487
|
+
mono: Mi,
|
|
3479
3488
|
size: 13,
|
|
3480
3489
|
weight: 500,
|
|
3481
3490
|
strongWeight: 600,
|
|
@@ -3517,11 +3526,11 @@ var Mi = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", Ni = "'JetB
|
|
|
3517
3526
|
control: 26,
|
|
3518
3527
|
controlSmall: 20,
|
|
3519
3528
|
icon: 16,
|
|
3520
|
-
sidebar:
|
|
3529
|
+
sidebar: 39,
|
|
3521
3530
|
menuItem: 26
|
|
3522
3531
|
},
|
|
3523
3532
|
font: {
|
|
3524
|
-
family: `'IBM Plex Sans Condensed', 'Roboto Condensed', 'Arial Narrow', ${
|
|
3533
|
+
family: `'IBM Plex Sans Condensed', 'Roboto Condensed', 'Arial Narrow', ${ji}`,
|
|
3525
3534
|
mono: "'IBM Plex Mono', ui-monospace, monospace",
|
|
3526
3535
|
size: 12,
|
|
3527
3536
|
weight: 500,
|
|
@@ -3566,12 +3575,12 @@ var Mi = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", Ni = "'JetB
|
|
|
3566
3575
|
control: 32,
|
|
3567
3576
|
controlSmall: 26,
|
|
3568
3577
|
icon: 18,
|
|
3569
|
-
sidebar:
|
|
3578
|
+
sidebar: 47,
|
|
3570
3579
|
menuItem: 34
|
|
3571
3580
|
},
|
|
3572
3581
|
font: {
|
|
3573
|
-
family: `'Sora', 'Manrope', ${
|
|
3574
|
-
mono:
|
|
3582
|
+
family: `'Sora', 'Manrope', ${ji}`,
|
|
3583
|
+
mono: Mi,
|
|
3575
3584
|
size: 13,
|
|
3576
3585
|
weight: 500,
|
|
3577
3586
|
strongWeight: 600,
|
|
@@ -3613,12 +3622,12 @@ var Mi = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", Ni = "'JetB
|
|
|
3613
3622
|
control: 24,
|
|
3614
3623
|
controlSmall: 20,
|
|
3615
3624
|
icon: 16,
|
|
3616
|
-
sidebar:
|
|
3625
|
+
sidebar: 37,
|
|
3617
3626
|
menuItem: 24
|
|
3618
3627
|
},
|
|
3619
3628
|
font: {
|
|
3620
|
-
family:
|
|
3621
|
-
mono:
|
|
3629
|
+
family: Fi,
|
|
3630
|
+
mono: Fi,
|
|
3622
3631
|
size: 12,
|
|
3623
3632
|
weight: 400,
|
|
3624
3633
|
strongWeight: 700,
|
|
@@ -3642,13 +3651,13 @@ var Mi = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", Ni = "'JetB
|
|
|
3642
3651
|
tagRadius: 0,
|
|
3643
3652
|
iconStroke: 0
|
|
3644
3653
|
}
|
|
3645
|
-
},
|
|
3654
|
+
}, Li = {
|
|
3646
3655
|
compact: {
|
|
3647
3656
|
toolbar: 38,
|
|
3648
3657
|
control: 26,
|
|
3649
3658
|
controlSmall: 20,
|
|
3650
3659
|
icon: 16,
|
|
3651
|
-
sidebar:
|
|
3660
|
+
sidebar: 32,
|
|
3652
3661
|
menuItem: 26
|
|
3653
3662
|
},
|
|
3654
3663
|
spacious: {
|
|
@@ -3656,11 +3665,11 @@ var Mi = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", Ni = "'JetB
|
|
|
3656
3665
|
control: 34,
|
|
3657
3666
|
controlSmall: 28,
|
|
3658
3667
|
icon: 20,
|
|
3659
|
-
sidebar:
|
|
3668
|
+
sidebar: 49,
|
|
3660
3669
|
menuItem: 34
|
|
3661
3670
|
}
|
|
3662
3671
|
};
|
|
3663
|
-
function
|
|
3672
|
+
function Ri(e, t) {
|
|
3664
3673
|
return {
|
|
3665
3674
|
control: e.md,
|
|
3666
3675
|
input: e.md,
|
|
@@ -3675,28 +3684,28 @@ function zi(e, t) {
|
|
|
3675
3684
|
...t
|
|
3676
3685
|
};
|
|
3677
3686
|
}
|
|
3678
|
-
var
|
|
3679
|
-
function
|
|
3680
|
-
let { density: t, ...n } =
|
|
3687
|
+
var zi = Object.freeze(Object.fromEntries(Object.keys(Ii).map((e) => [e, Vi(Bi(e))])));
|
|
3688
|
+
function Bi(e) {
|
|
3689
|
+
let { density: t, ...n } = Ii[e];
|
|
3681
3690
|
return {
|
|
3682
3691
|
...n,
|
|
3683
3692
|
preset: e,
|
|
3684
3693
|
density: "comfortable",
|
|
3685
3694
|
scale: "auto",
|
|
3686
3695
|
radius: { ...n.radius },
|
|
3687
|
-
components:
|
|
3696
|
+
components: Ri(n.radius, n.components),
|
|
3688
3697
|
sizes: { ...n.sizes },
|
|
3689
3698
|
font: { ...n.font },
|
|
3690
3699
|
borders: { ...n.borders },
|
|
3691
3700
|
shadows: { ...n.shadows }
|
|
3692
3701
|
};
|
|
3693
3702
|
}
|
|
3694
|
-
function
|
|
3695
|
-
for (let t of Object.values(e)) t && typeof t == "object" &&
|
|
3703
|
+
function Vi(e) {
|
|
3704
|
+
for (let t of Object.values(e)) t && typeof t == "object" && Vi(t);
|
|
3696
3705
|
return Object.freeze(e);
|
|
3697
3706
|
}
|
|
3698
|
-
var
|
|
3699
|
-
function
|
|
3707
|
+
var Hi = (e) => typeof e == "string" && Object.prototype.hasOwnProperty.call(Ii, e), B = (e, t, n) => typeof e == "number" && Number.isFinite(e) && e >= t && e <= n, Ui = (e) => typeof e == "string" && e.trim().length > 0 && e.length <= 300 && !/[;{}<>\\]|url\s*\(|expression\s*\(|\/\*/i.test(e) && Wi(e);
|
|
3708
|
+
function Wi(e) {
|
|
3700
3709
|
let t = 0, n = "";
|
|
3701
3710
|
for (let r of e) if (n) r === n && (n = "");
|
|
3702
3711
|
else if (r === "\"" || r === "'") n = r;
|
|
@@ -3704,8 +3713,8 @@ function Gi(e) {
|
|
|
3704
3713
|
else if (r === ")" && --t < 0) return !1;
|
|
3705
3714
|
return t === 0 && !n;
|
|
3706
3715
|
}
|
|
3707
|
-
var
|
|
3708
|
-
function
|
|
3716
|
+
var Gi = (e, t) => typeof e == "string" && t.includes(e);
|
|
3717
|
+
function V(e, t, n) {
|
|
3709
3718
|
let r = { ...e };
|
|
3710
3719
|
if (!t || typeof t != "object") return r;
|
|
3711
3720
|
for (let i of Object.keys(e)) {
|
|
@@ -3714,13 +3723,13 @@ function B(e, t, n) {
|
|
|
3714
3723
|
}
|
|
3715
3724
|
return r;
|
|
3716
3725
|
}
|
|
3717
|
-
function
|
|
3718
|
-
let t = typeof e == "string" ? { preset: e } : e ?? {}, n =
|
|
3726
|
+
function H(e) {
|
|
3727
|
+
let t = typeof e == "string" ? { preset: e } : e ?? {}, n = Hi(t.preset) ? t.preset : yi, r = Ii[n], i = V(r.radius, t.radius, (e, t) => B(t, 0, 999)), a = Gi(t.density, [
|
|
3719
3728
|
"compact",
|
|
3720
3729
|
"comfortable",
|
|
3721
3730
|
"spacious",
|
|
3722
3731
|
"airy"
|
|
3723
|
-
]) ? t.density : "comfortable", o = a === "airy" ? "spacious" : a, s =
|
|
3732
|
+
]) ? t.density : "comfortable", o = a === "airy" ? "spacious" : a, s = V(o === "compact" || o === "spacious" ? (r.density ?? Li)[o] : r.sizes, t.sizes, (e, t) => e === "icon" ? B(t, 10, 32) : B(t, 16, 80)), c = V(r.font, t.font, (e, t) => e === "family" || e === "mono" ? Ui(t) : e === "size" ? B(t, 11, 20) : e === "weight" || e === "strongWeight" ? B(t, 100, 900) : e === "labelCase" ? t === "none" || t === "uppercase" : B(t, 0, .5)), l = c.family === Ni ? Ve : c.family, u = a === "airy" && t.font?.mono === void 0 ? {
|
|
3724
3733
|
...c,
|
|
3725
3734
|
mono: l
|
|
3726
3735
|
} : c;
|
|
@@ -3728,27 +3737,27 @@ function V(e) {
|
|
|
3728
3737
|
preset: n,
|
|
3729
3738
|
density: a,
|
|
3730
3739
|
radius: i,
|
|
3731
|
-
components:
|
|
3740
|
+
components: V(Ri(i, r.components), t.components, (e, t) => B(t, 0, 999)),
|
|
3732
3741
|
sizes: s,
|
|
3733
3742
|
font: u,
|
|
3734
|
-
borders:
|
|
3735
|
-
shadows:
|
|
3736
|
-
blur:
|
|
3737
|
-
active:
|
|
3743
|
+
borders: V(r.borders, t.borders, (e, t) => e === "width" ? B(t, 0, 4) : typeof t == "boolean"),
|
|
3744
|
+
shadows: V(r.shadows, t.shadows, (e, t) => Ui(t)),
|
|
3745
|
+
blur: B(t.blur, 0, 40) ? t.blur : r.blur,
|
|
3746
|
+
active: Gi(t.active, [
|
|
3738
3747
|
"tint",
|
|
3739
3748
|
"solid",
|
|
3740
3749
|
"underline"
|
|
3741
3750
|
]) ? t.active : r.active,
|
|
3742
|
-
toolbar:
|
|
3743
|
-
sidebar:
|
|
3744
|
-
intervals:
|
|
3745
|
-
tagRadius:
|
|
3746
|
-
iconStroke: t.iconStroke === 0 ||
|
|
3747
|
-
scale: typeof t.scale == "number" && Number.isFinite(t.scale) && t.scale >=
|
|
3751
|
+
toolbar: Gi(t.toolbar, ["docked", "floating"]) ? t.toolbar : r.toolbar,
|
|
3752
|
+
sidebar: Gi(t.sidebar, ["docked", "floating"]) ? t.sidebar : r.sidebar,
|
|
3753
|
+
intervals: Gi(t.intervals, ["plain", "segmented"]) ? t.intervals : r.intervals,
|
|
3754
|
+
tagRadius: B(t.tagRadius, 0, 999) ? t.tagRadius : r.tagRadius,
|
|
3755
|
+
iconStroke: t.iconStroke === 0 || B(t.iconStroke, Ti, Ei) ? t.iconStroke : r.iconStroke,
|
|
3756
|
+
scale: typeof t.scale == "number" && Number.isFinite(t.scale) && t.scale >= Di && t.scale <= Oi ? t.scale : "auto"
|
|
3748
3757
|
};
|
|
3749
3758
|
}
|
|
3750
|
-
function
|
|
3751
|
-
let t = (e) => `${e}px`, n = e.radius, r = e.components, i = e.sizes, a = e.font, o = e.density === "compact", s = o ? 1 :
|
|
3759
|
+
function Ki(e) {
|
|
3760
|
+
let t = (e) => `${e}px`, n = e.radius, r = e.components, i = e.sizes, a = e.font, o = e.density === "compact", s = o ? 1 : Ci, c = o ? i.control : Math.min(Math.round(i.control * Ci), i.sidebar - 2 * wi);
|
|
3752
3761
|
return {
|
|
3753
3762
|
"--tcw-radius-xs": t(n.xs),
|
|
3754
3763
|
"--tcw-radius-sm": t(n.sm),
|
|
@@ -3777,16 +3786,16 @@ function qi(e) {
|
|
|
3777
3786
|
"--tcw-font": a.family,
|
|
3778
3787
|
"--tcw-font-mono": a.mono,
|
|
3779
3788
|
"--tcw-font-size": t(a.size),
|
|
3780
|
-
"--tcw-font-size-sm": t(
|
|
3781
|
-
"--tcw-font-size-xs": t(
|
|
3782
|
-
"--tcw-font-size-lg": t(
|
|
3783
|
-
"--tcw-font-size-xl": t(
|
|
3784
|
-
"--tcw-font-size-display": t(
|
|
3789
|
+
"--tcw-font-size-sm": t(z(a.size, -1)),
|
|
3790
|
+
"--tcw-font-size-xs": t(z(a.size, -2)),
|
|
3791
|
+
"--tcw-font-size-lg": t(z(a.size, 1)),
|
|
3792
|
+
"--tcw-font-size-xl": t(z(a.size, 2)),
|
|
3793
|
+
"--tcw-font-size-display": t(z(a.size, 3)),
|
|
3785
3794
|
"--tcw-weight": String(a.weight),
|
|
3786
3795
|
"--tcw-weight-strong": String(a.strongWeight),
|
|
3787
3796
|
"--tcw-label-case": a.labelCase,
|
|
3788
3797
|
"--tcw-label-tracking": `${a.labelTracking}em`,
|
|
3789
|
-
"--tcw-label-size": t(
|
|
3798
|
+
"--tcw-label-size": t(z(a.size, a.labelCase === "uppercase" ? -2 : -1)),
|
|
3790
3799
|
"--tcw-border-w": t(e.borders.width),
|
|
3791
3800
|
"--tcw-sep-w": e.borders.separators ? t(Math.max(1, e.borders.width)) : "0px",
|
|
3792
3801
|
"--tcw-menu-shadow": e.shadows.menu,
|
|
@@ -3796,14 +3805,14 @@ function qi(e) {
|
|
|
3796
3805
|
"--tcw-surface-opacity": e.blur > 0 ? "82%" : "100%"
|
|
3797
3806
|
};
|
|
3798
3807
|
}
|
|
3799
|
-
function
|
|
3808
|
+
function qi(e, t, n = {}) {
|
|
3800
3809
|
let r = n.variables !== !1;
|
|
3801
|
-
for (let [n, i] of Object.entries(
|
|
3810
|
+
for (let [n, i] of Object.entries(Ki(t))) r ? e.style.setProperty(n, i) : e.style.removeProperty(n);
|
|
3802
3811
|
e.dataset.tcwUi = t.preset, e.dataset.tcwActive = t.active, e.dataset.tcwToolbar = t.toolbar, e.dataset.tcwSidebar = t.sidebar, e.dataset.tcwIntervals = t.intervals, e.dataset.tcwSeparators = t.borders.separators ? "on" : "off", e.dataset.tcwIconStroke = (t.iconStroke ?? 0) > 0 ? "set" : "drawn";
|
|
3803
3812
|
}
|
|
3804
3813
|
//#endregion
|
|
3805
3814
|
//#region src/widget/WidgetObjectTree.ts
|
|
3806
|
-
var
|
|
3815
|
+
var Ji = class {
|
|
3807
3816
|
el;
|
|
3808
3817
|
indicatorsEl;
|
|
3809
3818
|
drawingsEl;
|
|
@@ -3936,7 +3945,7 @@ var Yi = class {
|
|
|
3936
3945
|
if (!e.isConnected) return;
|
|
3937
3946
|
this.renaming = !0;
|
|
3938
3947
|
let i = document.createElement("input");
|
|
3939
|
-
i.type = "text", i.className = "tcw-tree-rename", i.value = t, i.maxLength =
|
|
3948
|
+
i.type = "text", i.className = "tcw-tree-rename", i.value = t, i.maxLength = Yi, i.setAttribute("aria-label", n);
|
|
3940
3949
|
let a = !1, o = (t) => {
|
|
3941
3950
|
if (a) return;
|
|
3942
3951
|
a = !0;
|
|
@@ -4028,7 +4037,7 @@ var Yi = class {
|
|
|
4028
4037
|
let i = document.createElement("button");
|
|
4029
4038
|
return i.type = "button", i.className = `tcw-tree-btn ${n}`.trim(), i.setAttribute("aria-label", t), i.title = t, i.innerHTML = b(e, 14), i.addEventListener("click", r), i;
|
|
4030
4039
|
}
|
|
4031
|
-
},
|
|
4040
|
+
}, Yi = 80, Xi = {
|
|
4032
4041
|
trendLine: "Trend Line",
|
|
4033
4042
|
ray: "Ray",
|
|
4034
4043
|
extendedLine: "Extended Line",
|
|
@@ -4075,25 +4084,25 @@ var Yi = class {
|
|
|
4075
4084
|
anchoredText: "Anchored Text",
|
|
4076
4085
|
anchoredNote: "Anchored Note"
|
|
4077
4086
|
};
|
|
4078
|
-
function
|
|
4087
|
+
function Zi(e, t) {
|
|
4079
4088
|
let n = `tool.${e}`, r = t?.(n);
|
|
4080
|
-
return r && r !== n ? r :
|
|
4089
|
+
return r && r !== n ? r : Xi[e] ?? e;
|
|
4081
4090
|
}
|
|
4082
4091
|
//#endregion
|
|
4083
4092
|
//#region src/widget/indicatorDefaults.ts
|
|
4084
|
-
function
|
|
4093
|
+
function Qi() {
|
|
4085
4094
|
try {
|
|
4086
4095
|
return typeof localStorage < "u" ? localStorage : null;
|
|
4087
4096
|
} catch {
|
|
4088
4097
|
return null;
|
|
4089
4098
|
}
|
|
4090
4099
|
}
|
|
4091
|
-
var
|
|
4092
|
-
function
|
|
4093
|
-
return
|
|
4100
|
+
var $i = (e) => typeof e == "object" && !!e && !Array.isArray(e);
|
|
4101
|
+
function ea(e) {
|
|
4102
|
+
return $i(e) ? Object.fromEntries(Object.entries(e).filter(([, e]) => typeof e == "number" && Number.isFinite(e) || typeof e == "string" && !Xe(e) || typeof e == "boolean")) : {};
|
|
4094
4103
|
}
|
|
4095
|
-
function
|
|
4096
|
-
if (
|
|
4104
|
+
function ta(e) {
|
|
4105
|
+
if (!$i(e)) return {};
|
|
4097
4106
|
let t = {};
|
|
4098
4107
|
if (Array.isArray(e.colors)) {
|
|
4099
4108
|
let n = e.colors.filter((e) => typeof e == "string" && e.trim() !== "");
|
|
@@ -4106,8 +4115,8 @@ function na(e) {
|
|
|
4106
4115
|
let n = et(e.plots);
|
|
4107
4116
|
return n && (t.plots = n), t;
|
|
4108
4117
|
}
|
|
4109
|
-
var
|
|
4110
|
-
constructor(e = "tcw:indicator-defaults", t =
|
|
4118
|
+
var na = class {
|
|
4119
|
+
constructor(e = "tcw:indicator-defaults", t = Qi()) {
|
|
4111
4120
|
this.key = e, this.storage = t;
|
|
4112
4121
|
}
|
|
4113
4122
|
all() {
|
|
@@ -4117,10 +4126,10 @@ var ra = class {
|
|
|
4117
4126
|
} catch {
|
|
4118
4127
|
return e;
|
|
4119
4128
|
}
|
|
4120
|
-
if (
|
|
4121
|
-
for (let [n, r] of Object.entries(t))
|
|
4122
|
-
params:
|
|
4123
|
-
style:
|
|
4129
|
+
if (!$i(t)) return e;
|
|
4130
|
+
for (let [n, r] of Object.entries(t)) $i(r) && e.set(n, {
|
|
4131
|
+
params: ea(r.params),
|
|
4132
|
+
style: ta(r.style)
|
|
4124
4133
|
});
|
|
4125
4134
|
return e;
|
|
4126
4135
|
}
|
|
@@ -4130,8 +4139,8 @@ var ra = class {
|
|
|
4130
4139
|
save(e, t) {
|
|
4131
4140
|
if (!this.storage) return !1;
|
|
4132
4141
|
let n = Object.fromEntries([...this.all(), [e, {
|
|
4133
|
-
params:
|
|
4134
|
-
style:
|
|
4142
|
+
params: ea(t.params),
|
|
4143
|
+
style: ta(t.style)
|
|
4135
4144
|
}]]);
|
|
4136
4145
|
try {
|
|
4137
4146
|
return this.storage.setItem(this.key, JSON.stringify(n)), !0;
|
|
@@ -4139,33 +4148,33 @@ var ra = class {
|
|
|
4139
4148
|
return !1;
|
|
4140
4149
|
}
|
|
4141
4150
|
}
|
|
4142
|
-
},
|
|
4151
|
+
}, ra = 1, ia = ["logScale", "autoScale"], aa = new Set(["timezone", "numberLocale"]), oa = new Set([...ia, "chartTypeOptions"]), sa = new Set([
|
|
4152
|
+
...ia,
|
|
4143
4153
|
...aa,
|
|
4144
|
-
...oa,
|
|
4145
4154
|
"scaleMode",
|
|
4146
4155
|
"invertScale",
|
|
4147
4156
|
"chartTypeOptions"
|
|
4148
|
-
]),
|
|
4157
|
+
]), ca = new Set([
|
|
4158
|
+
...ia,
|
|
4149
4159
|
...aa,
|
|
4150
|
-
...oa,
|
|
4151
4160
|
"scaleMode"
|
|
4152
|
-
]),
|
|
4161
|
+
]), la = /* @__PURE__ */ new Set(), ua = [
|
|
4153
4162
|
"renko",
|
|
4154
4163
|
"lineBreak",
|
|
4155
4164
|
"kagi",
|
|
4156
4165
|
"pointAndFigure",
|
|
4157
4166
|
"rangeBars"
|
|
4158
4167
|
];
|
|
4159
|
-
function
|
|
4160
|
-
return
|
|
4168
|
+
function da(e) {
|
|
4169
|
+
return ua.includes(e);
|
|
4161
4170
|
}
|
|
4162
|
-
function
|
|
4163
|
-
return Object.fromEntries(Object.entries(e).filter(([, e]) =>
|
|
4171
|
+
function fa(e) {
|
|
4172
|
+
return Object.fromEntries(Object.entries(e).filter(([, e]) => ga(e) && Object.keys(e).length > 0));
|
|
4164
4173
|
}
|
|
4165
|
-
function
|
|
4166
|
-
return Object.fromEntries(
|
|
4174
|
+
function pa() {
|
|
4175
|
+
return Object.fromEntries(ua.map((e) => [e, {}]));
|
|
4167
4176
|
}
|
|
4168
|
-
var
|
|
4177
|
+
var ma = {
|
|
4169
4178
|
crosshairMode: [
|
|
4170
4179
|
"normal",
|
|
4171
4180
|
"magnet",
|
|
@@ -4178,7 +4187,7 @@ var ha = {
|
|
|
4178
4187
|
"indexedTo100"
|
|
4179
4188
|
],
|
|
4180
4189
|
periodLevelsPeriod: ["day", "week"]
|
|
4181
|
-
},
|
|
4190
|
+
}, ha = {
|
|
4182
4191
|
marketProfileBuckets: {
|
|
4183
4192
|
min: 8,
|
|
4184
4193
|
max: 200,
|
|
@@ -4197,66 +4206,66 @@ var ha = {
|
|
|
4197
4206
|
max: 20,
|
|
4198
4207
|
whole: !0
|
|
4199
4208
|
}
|
|
4200
|
-
},
|
|
4201
|
-
function
|
|
4209
|
+
}, ga = (e) => typeof e == "object" && !!e && !Array.isArray(e);
|
|
4210
|
+
function _a(e) {
|
|
4202
4211
|
return e === "local" || g(e) !== null;
|
|
4203
4212
|
}
|
|
4204
|
-
function
|
|
4213
|
+
function va(e) {
|
|
4205
4214
|
try {
|
|
4206
4215
|
return Intl.NumberFormat.supportedLocalesOf(e).length > 0;
|
|
4207
4216
|
} catch {
|
|
4208
4217
|
return !1;
|
|
4209
4218
|
}
|
|
4210
4219
|
}
|
|
4211
|
-
function
|
|
4220
|
+
function ya(e, t) {
|
|
4212
4221
|
let n = f[e];
|
|
4213
|
-
if (e === "chartTypeOptions") return
|
|
4222
|
+
if (e === "chartTypeOptions") return ga(t) ? $e(t) : void 0;
|
|
4214
4223
|
if (typeof t != typeof n) return;
|
|
4215
4224
|
if (typeof t == "number") {
|
|
4216
4225
|
if (!Number.isFinite(t)) return;
|
|
4217
|
-
let n =
|
|
4226
|
+
let n = ha[e];
|
|
4218
4227
|
if (!n) return t;
|
|
4219
4228
|
let r = Math.min(n.max, Math.max(n.min, t));
|
|
4220
4229
|
return n.whole ? Math.round(r) : r;
|
|
4221
4230
|
}
|
|
4222
4231
|
if (typeof t != "string") return t;
|
|
4223
|
-
let r =
|
|
4224
|
-
return r ? r.includes(t) ? t : void 0 : e === "timezone" ?
|
|
4232
|
+
let r = ma[e];
|
|
4233
|
+
return r ? r.includes(t) ? t : void 0 : e === "timezone" ? _a(t) ? t : void 0 : e === "numberLocale" ? va(t) ? t : void 0 : t;
|
|
4225
4234
|
}
|
|
4226
|
-
function
|
|
4227
|
-
if (!
|
|
4235
|
+
function U(e, t = la) {
|
|
4236
|
+
if (!ga(e)) return {};
|
|
4228
4237
|
let n = {};
|
|
4229
4238
|
for (let r of Object.keys(f)) {
|
|
4230
4239
|
if (t.has(r) || !Object.prototype.hasOwnProperty.call(e, r)) continue;
|
|
4231
|
-
let i =
|
|
4240
|
+
let i = ya(r, e[r]);
|
|
4232
4241
|
i !== void 0 && (n[r] = i);
|
|
4233
4242
|
}
|
|
4234
4243
|
return n;
|
|
4235
4244
|
}
|
|
4236
|
-
function
|
|
4245
|
+
function ba(e, t) {
|
|
4237
4246
|
return Object.fromEntries(Object.keys(e).filter((e) => !t.has(e)).map((t) => [t, e[t]]));
|
|
4238
4247
|
}
|
|
4239
|
-
function
|
|
4248
|
+
function xa(e, t, n) {
|
|
4240
4249
|
return Object.fromEntries(Object.keys(e).filter((r) => !n.has(r) && JSON.stringify(e[r]) !== JSON.stringify(t[r])).map((t) => [t, e[t]]));
|
|
4241
4250
|
}
|
|
4242
|
-
function
|
|
4243
|
-
return
|
|
4251
|
+
function Sa(e, t) {
|
|
4252
|
+
return xa({
|
|
4244
4253
|
...e,
|
|
4245
|
-
chartTypeOptions:
|
|
4246
|
-
}, t,
|
|
4254
|
+
chartTypeOptions: fa(e.chartTypeOptions)
|
|
4255
|
+
}, t, ca);
|
|
4247
4256
|
}
|
|
4248
|
-
function
|
|
4257
|
+
function Ca(e) {
|
|
4249
4258
|
return e ? (e === !0 ? void 0 : e.key) || "tcw:chart-settings" : null;
|
|
4250
4259
|
}
|
|
4251
|
-
function
|
|
4260
|
+
function wa() {
|
|
4252
4261
|
try {
|
|
4253
4262
|
return typeof localStorage < "u" ? localStorage : null;
|
|
4254
4263
|
} catch {
|
|
4255
4264
|
return null;
|
|
4256
4265
|
}
|
|
4257
4266
|
}
|
|
4258
|
-
var
|
|
4259
|
-
constructor(e, t =
|
|
4267
|
+
var Ta = class {
|
|
4268
|
+
constructor(e, t = wa()) {
|
|
4260
4269
|
this.key = e, this.storage = t;
|
|
4261
4270
|
}
|
|
4262
4271
|
load() {
|
|
@@ -4266,56 +4275,56 @@ var Ea = class {
|
|
|
4266
4275
|
} catch {
|
|
4267
4276
|
return {};
|
|
4268
4277
|
}
|
|
4269
|
-
return !
|
|
4278
|
+
return !ga(e) || e.v !== ra ? {} : U(e.settings, oa);
|
|
4270
4279
|
}
|
|
4271
4280
|
save(e, t) {
|
|
4272
4281
|
try {
|
|
4273
4282
|
this.storage?.setItem(this.key, JSON.stringify({
|
|
4274
|
-
v:
|
|
4275
|
-
settings:
|
|
4283
|
+
v: ra,
|
|
4284
|
+
settings: xa(e, t, oa)
|
|
4276
4285
|
}));
|
|
4277
4286
|
} catch {}
|
|
4278
4287
|
}
|
|
4279
4288
|
};
|
|
4280
4289
|
//#endregion
|
|
4281
4290
|
//#region src/widget/DrawingTemplateStore.ts
|
|
4282
|
-
function
|
|
4291
|
+
function Ea() {
|
|
4283
4292
|
try {
|
|
4284
4293
|
return typeof localStorage < "u" ? localStorage : null;
|
|
4285
4294
|
} catch {
|
|
4286
4295
|
return null;
|
|
4287
4296
|
}
|
|
4288
4297
|
}
|
|
4289
|
-
var
|
|
4290
|
-
function
|
|
4298
|
+
var Da = 80;
|
|
4299
|
+
function Oa(e) {
|
|
4291
4300
|
let { text: t, ...n } = it(e);
|
|
4292
4301
|
return n;
|
|
4293
4302
|
}
|
|
4294
|
-
function
|
|
4303
|
+
function ka(e) {
|
|
4295
4304
|
let t = {
|
|
4296
4305
|
name: e.name,
|
|
4297
4306
|
style: { ...e.style }
|
|
4298
4307
|
};
|
|
4299
4308
|
return e.type && (t.type = e.type), e.options && (t.options = structuredClone(e.options)), t;
|
|
4300
4309
|
}
|
|
4301
|
-
var
|
|
4310
|
+
var Aa = class {
|
|
4302
4311
|
templates = [];
|
|
4303
|
-
constructor(e = "tcw:draw-templates", t =
|
|
4312
|
+
constructor(e = "tcw:draw-templates", t = Ea()) {
|
|
4304
4313
|
this.storageKey = e, this.storage = t, this.load();
|
|
4305
4314
|
}
|
|
4306
4315
|
list(e) {
|
|
4307
|
-
return this.templates.filter((t) => !t.type || t.type === e).map(
|
|
4316
|
+
return this.templates.filter((t) => !t.type || t.type === e).map(ka);
|
|
4308
4317
|
}
|
|
4309
4318
|
get(e, t) {
|
|
4310
4319
|
let n = this.templates.find((n) => n.name === e && n.type === t);
|
|
4311
|
-
return n ?
|
|
4320
|
+
return n ? ka(n) : null;
|
|
4312
4321
|
}
|
|
4313
4322
|
save(e, t, n) {
|
|
4314
|
-
let r = e.trim().slice(0,
|
|
4323
|
+
let r = e.trim().slice(0, Da);
|
|
4315
4324
|
if (!r) return;
|
|
4316
4325
|
let i = {
|
|
4317
4326
|
name: r,
|
|
4318
|
-
style:
|
|
4327
|
+
style: Oa(t)
|
|
4319
4328
|
};
|
|
4320
4329
|
n && (i.type = n.type, i.options = structuredClone(n.options)), this.templates = this.templates.filter((e) => !(e.name === r && e.type === i.type)), this.templates.push(i), this.persist();
|
|
4321
4330
|
}
|
|
@@ -4333,8 +4342,8 @@ var ja = class {
|
|
|
4333
4342
|
if (!Array.isArray(t)) return;
|
|
4334
4343
|
this.templates = t.filter((e) => e && typeof e.name == "string" && e.name.trim() !== "").map((e) => {
|
|
4335
4344
|
let t = {
|
|
4336
|
-
name: e.name.trim().slice(0,
|
|
4337
|
-
style:
|
|
4345
|
+
name: e.name.trim().slice(0, Da),
|
|
4346
|
+
style: Oa(e.style)
|
|
4338
4347
|
};
|
|
4339
4348
|
return typeof e.type == "string" && (t.type = e.type), e.options && typeof e.options == "object" && !Array.isArray(e.options) && (t.options = e.options), t;
|
|
4340
4349
|
});
|
|
@@ -4345,9 +4354,9 @@ var ja = class {
|
|
|
4345
4354
|
this.storage.setItem(this.storageKey, JSON.stringify(this.templates));
|
|
4346
4355
|
} catch {}
|
|
4347
4356
|
}
|
|
4348
|
-
},
|
|
4357
|
+
}, ja = class {
|
|
4349
4358
|
defaults = {};
|
|
4350
|
-
constructor(e = "tcw:drawing-defaults", t =
|
|
4359
|
+
constructor(e = "tcw:drawing-defaults", t = Ea()) {
|
|
4351
4360
|
this.storageKey = e, this.storage = t;
|
|
4352
4361
|
try {
|
|
4353
4362
|
let e = this.storage?.getItem(this.storageKey), t = e ? JSON.parse(e) : null;
|
|
@@ -4363,7 +4372,7 @@ var ja = class {
|
|
|
4363
4372
|
this.storage?.setItem(this.storageKey, JSON.stringify(this.defaults));
|
|
4364
4373
|
} catch {}
|
|
4365
4374
|
}
|
|
4366
|
-
},
|
|
4375
|
+
}, Ma = [
|
|
4367
4376
|
"#4c8dff",
|
|
4368
4377
|
"#1fa874",
|
|
4369
4378
|
"#e8505b",
|
|
@@ -4372,16 +4381,16 @@ var ja = class {
|
|
|
4372
4381
|
"#1398a8",
|
|
4373
4382
|
"#ffffff",
|
|
4374
4383
|
"#7d8696"
|
|
4375
|
-
],
|
|
4384
|
+
], Na = [
|
|
4376
4385
|
1,
|
|
4377
4386
|
2,
|
|
4378
4387
|
3,
|
|
4379
4388
|
4
|
|
4380
|
-
],
|
|
4389
|
+
], Pa = [
|
|
4381
4390
|
"solid",
|
|
4382
4391
|
"dashed",
|
|
4383
4392
|
"dotted"
|
|
4384
|
-
],
|
|
4393
|
+
], Fa = class {
|
|
4385
4394
|
el;
|
|
4386
4395
|
templatesEl;
|
|
4387
4396
|
nameInput;
|
|
@@ -4421,7 +4430,7 @@ var ja = class {
|
|
|
4421
4430
|
colorRow() {
|
|
4422
4431
|
let e = document.createElement("div");
|
|
4423
4432
|
e.className = "tcw-style-row tcw-style-colors";
|
|
4424
|
-
for (let t of
|
|
4433
|
+
for (let t of Ma) {
|
|
4425
4434
|
let n = document.createElement("button");
|
|
4426
4435
|
n.type = "button", n.className = "tcw-style-swatch", n.style.background = t, n.dataset.color = t, n.setAttribute("aria-label", t), n.addEventListener("click", () => this.applyStyle({ color: t })), e.appendChild(n);
|
|
4427
4436
|
}
|
|
@@ -4431,7 +4440,7 @@ var ja = class {
|
|
|
4431
4440
|
widthRow() {
|
|
4432
4441
|
let e = document.createElement("div");
|
|
4433
4442
|
e.className = "tcw-style-row tcw-style-widths";
|
|
4434
|
-
for (let t of
|
|
4443
|
+
for (let t of Na) {
|
|
4435
4444
|
let n = document.createElement("button");
|
|
4436
4445
|
n.type = "button", n.className = "tcw-style-width", n.dataset.width = String(t);
|
|
4437
4446
|
let r = document.createElement("span");
|
|
@@ -4442,7 +4451,7 @@ var ja = class {
|
|
|
4442
4451
|
lineStyleRow() {
|
|
4443
4452
|
let e = document.createElement("div");
|
|
4444
4453
|
e.className = "tcw-style-row tcw-style-dashes";
|
|
4445
|
-
for (let t of
|
|
4454
|
+
for (let t of Pa) {
|
|
4446
4455
|
let n = document.createElement("button");
|
|
4447
4456
|
n.type = "button", n.className = "tcw-style-dash", n.dataset.linestyle = t, n.textContent = t === "solid" ? "──" : t === "dashed" ? "╌╌" : "┄┄", n.title = t, n.addEventListener("click", () => this.applyStyle({ lineStyle: t })), e.appendChild(n);
|
|
4448
4457
|
}
|
|
@@ -4490,22 +4499,22 @@ var ja = class {
|
|
|
4490
4499
|
}), e.appendChild(n), e.appendChild(a), this.templatesEl.appendChild(e);
|
|
4491
4500
|
}
|
|
4492
4501
|
}
|
|
4493
|
-
},
|
|
4502
|
+
}, Ia = {
|
|
4494
4503
|
color: "color",
|
|
4495
4504
|
fill: "fillColor",
|
|
4496
4505
|
textColor: "textColor"
|
|
4497
|
-
},
|
|
4498
|
-
function
|
|
4499
|
-
return typeof e == "string" &&
|
|
4506
|
+
}, La = 10, W = 4, Ra = 4, za = 20, Ba = /^(#[0-9a-f]{3,8}|(rgb|hsl)a?\([\d\s.,%/+-]+\)|[a-z]+)$/i;
|
|
4507
|
+
function Va(e) {
|
|
4508
|
+
return typeof e == "string" && Ba.test(e.trim()) ? e.trim() : "#7d8696";
|
|
4500
4509
|
}
|
|
4501
|
-
function
|
|
4510
|
+
function Ha(e) {
|
|
4502
4511
|
let t = Number(e);
|
|
4503
|
-
return Number.isFinite(t) && t > 0 ? Math.min(t,
|
|
4512
|
+
return Number.isFinite(t) && t > 0 ? Math.min(t, za) : 1;
|
|
4504
4513
|
}
|
|
4505
|
-
function
|
|
4506
|
-
return
|
|
4514
|
+
function Ua(e) {
|
|
4515
|
+
return Pa.includes(e) ? e : "solid";
|
|
4507
4516
|
}
|
|
4508
|
-
var
|
|
4517
|
+
var Wa = class {
|
|
4509
4518
|
el;
|
|
4510
4519
|
pop;
|
|
4511
4520
|
target = null;
|
|
@@ -4547,9 +4556,9 @@ var Ga = class {
|
|
|
4547
4556
|
show(e) {
|
|
4548
4557
|
this.target = e;
|
|
4549
4558
|
let t = e.style, n = [
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4559
|
+
Va(t.color),
|
|
4560
|
+
Ha(t.lineWidth),
|
|
4561
|
+
Ua(t.lineStyle),
|
|
4553
4562
|
e.locked,
|
|
4554
4563
|
e.canDelete,
|
|
4555
4564
|
e.canSettings,
|
|
@@ -4571,14 +4580,14 @@ var Ga = class {
|
|
|
4571
4580
|
this.onDragEnd(), document.removeEventListener("pointerdown", this.onDocDown, !0), this.el.remove(), this.pop.remove();
|
|
4572
4581
|
}
|
|
4573
4582
|
render(e) {
|
|
4574
|
-
let t = this.t, n =
|
|
4583
|
+
let t = this.t, n = Va(e.style.color), r = Ha(e.style.lineWidth), i = Ua(e.style.lineStyle), a = e.locked, o = this.el.contains(document.activeElement) ? document.activeElement.dataset.action : void 0, s = (e, t, n, r = "") => `<button type="button" class="tcw-sel-btn${r}" data-action="${e}" aria-label="${x(t)}" title="${x(t)}">${n}</button>`, c = (e, t, n) => s(e, t, n, " tcw-sel-has-pop").replace("<button ", "<button aria-haspopup=\"dialog\" aria-expanded=\"false\" ");
|
|
4575
4584
|
this.el.innerHTML = [
|
|
4576
4585
|
"<span class=\"tcw-sel-grip\" aria-hidden=\"true\"></span>",
|
|
4577
4586
|
c("color", t("drawingSettings.color"), `<span class="tcw-sel-color" style="background:${x(n)}"></span>`),
|
|
4578
4587
|
c("width", t("drawingSettings.lineWidth"), `<span class="tcw-sel-width" style="--w:${r}px"></span><span class="tcw-sel-num">${r}px</span>`),
|
|
4579
|
-
c("lineStyle", t("drawingSettings.lineStyle"),
|
|
4580
|
-
e.canFill ? c("fill", t("drawingSettings.fill"), `<span class="tcw-sel-color tcw-sel-fill" style="background:${x(
|
|
4581
|
-
e.canText ? c("textColor", t("drawingSettings.textColor"), `<span class="tcw-sel-text" style="--c:${x(
|
|
4588
|
+
c("lineStyle", t("drawingSettings.lineStyle"), Ga(i)),
|
|
4589
|
+
e.canFill ? c("fill", t("drawingSettings.fill"), `<span class="tcw-sel-color tcw-sel-fill" style="background:${x(Va(Ye(e.style) ?? n))}"></span>`) : "",
|
|
4590
|
+
e.canText ? c("textColor", t("drawingSettings.textColor"), `<span class="tcw-sel-text" style="--c:${x(Va(e.style.textColor ?? n))}">T</span>`) : "",
|
|
4582
4591
|
"<span class=\"tcw-sel-sep\" aria-hidden=\"true\"></span>",
|
|
4583
4592
|
e.canSettings ? s("settings", t("legend.settings"), b("settings", 15)) : "",
|
|
4584
4593
|
e.canAlert ? s("alert", t("drawingSettings.addAlert"), b("bell", 15)) : "",
|
|
@@ -4602,14 +4611,14 @@ var Ga = class {
|
|
|
4602
4611
|
h: 0
|
|
4603
4612
|
};
|
|
4604
4613
|
if (this.pinned) {
|
|
4605
|
-
let e = Math.max(n.x +
|
|
4614
|
+
let e = Math.max(n.x + W, Math.min(this.pinned.left, n.x + n.width - r - W)), t = Math.max(n.y + W, Math.min(this.pinned.top, n.y + n.height - i - W));
|
|
4606
4615
|
this.el.style.left = `${Math.round(e)}px`, this.el.style.top = `${Math.round(t)}px`;
|
|
4607
4616
|
return;
|
|
4608
4617
|
}
|
|
4609
4618
|
let a = t.x + t.width / 2 - r / 2;
|
|
4610
|
-
a = Math.max(n.x +
|
|
4611
|
-
let o = t.y - i -
|
|
4612
|
-
o < n.y +
|
|
4619
|
+
a = Math.max(n.x + W, Math.min(a, n.x + n.width - r - W));
|
|
4620
|
+
let o = t.y - i - La;
|
|
4621
|
+
o < n.y + W && (o = Math.min(t.y + t.height + La, n.y + n.height - i - W)), o = Math.max(o, n.y + W), this.el.style.left = `${Math.round(a)}px`, this.el.style.top = `${Math.round(o)}px`;
|
|
4613
4622
|
}
|
|
4614
4623
|
onClick(e) {
|
|
4615
4624
|
let t = e.target.closest("[data-action]");
|
|
@@ -4626,7 +4635,7 @@ var Ga = class {
|
|
|
4626
4635
|
else if (n === "delete") this.callbacks.onDelete();
|
|
4627
4636
|
else if (n === "more") {
|
|
4628
4637
|
let e = t.getBoundingClientRect(), n = this.host.getBoundingClientRect();
|
|
4629
|
-
this.callbacks.onMore(e.left - n.left, e.bottom - n.top +
|
|
4638
|
+
this.callbacks.onMore(e.left - n.left, e.bottom - n.top + W);
|
|
4630
4639
|
}
|
|
4631
4640
|
}
|
|
4632
4641
|
onKey(e) {
|
|
@@ -4640,8 +4649,8 @@ var Ga = class {
|
|
|
4640
4649
|
r < 0 || (e.preventDefault(), this.rove(t[r], !0));
|
|
4641
4650
|
}
|
|
4642
4651
|
openPopover(e, t) {
|
|
4643
|
-
let n = this.target.style, r =
|
|
4644
|
-
this.openPop = e, e === "color" || e === "fill" || e === "textColor" ? this.pop.innerHTML =
|
|
4652
|
+
let n = this.target.style, r = Va(e === "fill" ? Ye(n) ?? n.color : e === "textColor" ? n.textColor ?? n.color : n.color).toLowerCase(), i = Ha(n.lineWidth), a = Ua(n.lineStyle), o = (e, t, n, r = "") => `<button type="button" class="${e}${t ? " tcw-sel-on" : ""}" aria-pressed="${t}" ${n}>${r}</button>`;
|
|
4653
|
+
this.openPop = e, e === "color" || e === "fill" || e === "textColor" ? this.pop.innerHTML = Ma.map((e) => o("tcw-sel-swatch", e.toLowerCase() === r, `data-color="${e}" style="background:${e}" aria-label="${e}"`)).join("") : e === "width" ? this.pop.innerHTML = Na.map((e) => o("tcw-sel-option", e === i, `data-width="${e}"`, `<span class="tcw-sel-width" style="--w:${e}px"></span>${e}px`)).join("") : this.pop.innerHTML = Pa.map((e) => o("tcw-sel-option", e === a, `data-style="${e}"`, Ga(e) + x(this.t(`drawingSettings.lineStyle.${e}`)))).join(""), this.pop.className = `tcw-sel-pop tcw-sel-pop--${e}`, this.pop.setAttribute("aria-label", t.getAttribute("aria-label") ?? ""), this.pop.hidden = !1;
|
|
4645
4654
|
for (let e of this.el.querySelectorAll("[aria-expanded=\"true\"]")) e.setAttribute("aria-expanded", "false");
|
|
4646
4655
|
t.setAttribute("aria-expanded", "true"), this.placePop(), this.pop.querySelector(".tcw-sel-on, button")?.focus();
|
|
4647
4656
|
}
|
|
@@ -4652,7 +4661,7 @@ var Ga = class {
|
|
|
4652
4661
|
}
|
|
4653
4662
|
let t = [...this.pop.querySelectorAll("button")], n = t.indexOf(document.activeElement);
|
|
4654
4663
|
if (n < 0) return;
|
|
4655
|
-
let r = this.openPop === "color" || this.openPop === "fill" || this.openPop === "textColor" ?
|
|
4664
|
+
let r = this.openPop === "color" || this.openPop === "fill" || this.openPop === "textColor" ? Ra : 1, i = e.key === "ArrowRight" ? 1 : e.key === "ArrowLeft" ? -1 : e.key === "ArrowDown" ? r : e.key === "ArrowUp" ? -r : 0;
|
|
4656
4665
|
i && (e.preventDefault(), t[(n + i + t.length) % t.length].focus());
|
|
4657
4666
|
}
|
|
4658
4667
|
placePop() {
|
|
@@ -4662,8 +4671,8 @@ var Ga = class {
|
|
|
4662
4671
|
onPick(e) {
|
|
4663
4672
|
let t = e.target.closest("button");
|
|
4664
4673
|
if (!t) return;
|
|
4665
|
-
let n = this.openPop && this.openPop in
|
|
4666
|
-
t.dataset.color ? this.callbacks.onStyle({ [n]: t.dataset.color }) : t.dataset.width ? this.callbacks.onStyle({ lineWidth: Number(t.dataset.width) }) : t.dataset.style && this.callbacks.onStyle({ lineStyle:
|
|
4674
|
+
let n = this.openPop && this.openPop in Ia ? Ia[this.openPop] : "color";
|
|
4675
|
+
t.dataset.color ? this.callbacks.onStyle({ [n]: t.dataset.color }) : t.dataset.width ? this.callbacks.onStyle({ lineWidth: Number(t.dataset.width) }) : t.dataset.style && this.callbacks.onStyle({ lineStyle: Ua(t.dataset.style) }), this.closePop(!0);
|
|
4667
4676
|
}
|
|
4668
4677
|
closePop(e = !1) {
|
|
4669
4678
|
if (!this.openPop) return;
|
|
@@ -4671,12 +4680,12 @@ var Ga = class {
|
|
|
4671
4680
|
t?.setAttribute("aria-expanded", "false"), this.openPop = null, this.pop.hidden = !0, e && t?.focus();
|
|
4672
4681
|
}
|
|
4673
4682
|
};
|
|
4674
|
-
function
|
|
4683
|
+
function Ga(e) {
|
|
4675
4684
|
return `<svg class="tcw-sel-line" width="22" height="10" viewBox="0 0 22 10" aria-hidden="true"><line x1="1" y1="5" x2="21" y2="5" stroke="currentColor" stroke-width="2"${e === "dashed" ? " stroke-dasharray=\"4 3\"" : e === "dotted" ? " stroke-dasharray=\"1 3\" stroke-linecap=\"round\"" : ""}/></svg>`;
|
|
4676
4685
|
}
|
|
4677
4686
|
//#endregion
|
|
4678
4687
|
//#region src/widget/drawingText.ts
|
|
4679
|
-
var
|
|
4688
|
+
var G = {
|
|
4680
4689
|
text: {
|
|
4681
4690
|
box: !1,
|
|
4682
4691
|
border: !1,
|
|
@@ -4719,7 +4728,7 @@ var W = {
|
|
|
4719
4728
|
wrap: 240,
|
|
4720
4729
|
fontSize: 14
|
|
4721
4730
|
}
|
|
4722
|
-
},
|
|
4731
|
+
}, Ka = new Set([
|
|
4723
4732
|
"trendLine",
|
|
4724
4733
|
"ray",
|
|
4725
4734
|
"extendedLine",
|
|
@@ -4730,7 +4739,7 @@ var W = {
|
|
|
4730
4739
|
"horizontalRay",
|
|
4731
4740
|
"verticalLine",
|
|
4732
4741
|
"rectangle"
|
|
4733
|
-
]),
|
|
4742
|
+
]), qa = { priceLabel: "#ffffff" }, Ja = 8, Ya = 6, Xa = 1.3, Za = 120, Qa = 229, $a = 500, eo = 8, to = 400, no = class {
|
|
4734
4743
|
wrap = null;
|
|
4735
4744
|
area = null;
|
|
4736
4745
|
target = null;
|
|
@@ -4740,7 +4749,7 @@ var W = {
|
|
|
4740
4749
|
offSince = 0;
|
|
4741
4750
|
onPressAway = (e) => {
|
|
4742
4751
|
if (!(!this.area || e.target === this.area)) {
|
|
4743
|
-
if (this.area.value === this.target?.text && performance.now() - this.openedAt <
|
|
4752
|
+
if (this.area.value === this.target?.text && performance.now() - this.openedAt < $a) {
|
|
4744
4753
|
e.preventDefault(), e.stopPropagation();
|
|
4745
4754
|
return;
|
|
4746
4755
|
}
|
|
@@ -4768,15 +4777,15 @@ var W = {
|
|
|
4768
4777
|
fontWeight: a ? "bold" : "normal",
|
|
4769
4778
|
fontStyle: o ? "italic" : "normal",
|
|
4770
4779
|
fontFamily: s,
|
|
4771
|
-
lineHeight: String(
|
|
4780
|
+
lineHeight: String(Xa),
|
|
4772
4781
|
color: e.color,
|
|
4773
|
-
padding: `${
|
|
4782
|
+
padding: `${Ya}px ${Ja}px`
|
|
4774
4783
|
}), r.addEventListener("input", () => {
|
|
4775
4784
|
this.fit(), this.target?.onInput(r.value);
|
|
4776
4785
|
let e = this.target?.rect();
|
|
4777
4786
|
e && this.place(e);
|
|
4778
4787
|
}), r.addEventListener("keydown", (e) => {
|
|
4779
|
-
e.stopPropagation(), !(e.isComposing || e.keyCode ===
|
|
4788
|
+
e.stopPropagation(), !(e.isComposing || e.keyCode === Qa) && (e.key === "Escape" ? (e.preventDefault(), this.finish(!1, !0)) : e.key === "Enter" && !e.shiftKey && (e.preventDefault(), this.finish(!0, !0)));
|
|
4780
4789
|
}), r.addEventListener("blur", () => this.finish(!0, !1)), n.appendChild(r), this.layer().appendChild(n), this.wrap = n, this.area = r, this.place(t), this.fit(), r.focus(), r.select(), this.openedAt = performance.now(), this.offSince = 0, document.addEventListener("pointerdown", this.onPressAway, !0), document.addEventListener("mousedown", this.onPressAway, !0), this.follow(), !0;
|
|
4781
4790
|
}
|
|
4782
4791
|
commit() {
|
|
@@ -4797,10 +4806,10 @@ var W = {
|
|
|
4797
4806
|
place(e) {
|
|
4798
4807
|
let t = this.area;
|
|
4799
4808
|
if (!t) return;
|
|
4800
|
-
let n = Math.max(
|
|
4801
|
-
t.style.maxWidth = `${n}px`, t.style.width = `${Math.min(n, Math.max(
|
|
4802
|
-
let r = t.offsetWidth || Math.max(
|
|
4803
|
-
t.style.left = `${Math.max(
|
|
4809
|
+
let n = Math.max(Za, window.innerWidth - eo * 2);
|
|
4810
|
+
t.style.maxWidth = `${n}px`, t.style.width = `${Math.min(n, Math.max(Za, e.width))}px`, t.style.minHeight = `${e.height}px`;
|
|
4811
|
+
let r = t.offsetWidth || Math.max(Za, e.width), i = t.offsetHeight || e.height;
|
|
4812
|
+
t.style.left = `${Math.max(eo, Math.min(e.x, window.innerWidth - eo - r))}px`, t.style.top = `${Math.max(eo, Math.min(e.y, window.innerHeight - eo - i))}px`;
|
|
4804
4813
|
}
|
|
4805
4814
|
offWindow(e) {
|
|
4806
4815
|
return e.x > window.innerWidth || e.x + e.width < 0 || e.y > window.innerHeight || e.y + e.height < 0;
|
|
@@ -4813,14 +4822,14 @@ var W = {
|
|
|
4813
4822
|
this.frame = requestAnimationFrame(() => {
|
|
4814
4823
|
if (!this.target || this.done) return;
|
|
4815
4824
|
let e = this.target.rect(), t = e !== null && this.offWindow(e);
|
|
4816
|
-
if (t ? this.offSince === 0 && (this.offSince = performance.now()) : this.offSince = 0, !e || t && performance.now() - this.offSince >
|
|
4825
|
+
if (t ? this.offSince === 0 && (this.offSince = performance.now()) : this.offSince = 0, !e || t && performance.now() - this.offSince > to) {
|
|
4817
4826
|
this.finish(!0, !1);
|
|
4818
4827
|
return;
|
|
4819
4828
|
}
|
|
4820
4829
|
this.place(e), this.follow();
|
|
4821
4830
|
});
|
|
4822
4831
|
}
|
|
4823
|
-
},
|
|
4832
|
+
}, ro = [
|
|
4824
4833
|
{
|
|
4825
4834
|
id: "regularScale",
|
|
4826
4835
|
mode: "regular",
|
|
@@ -4841,7 +4850,7 @@ var W = {
|
|
|
4841
4850
|
mode: "indexedTo100",
|
|
4842
4851
|
label: "settings.scale.indexedTo100"
|
|
4843
4852
|
}
|
|
4844
|
-
],
|
|
4853
|
+
], io = [
|
|
4845
4854
|
{
|
|
4846
4855
|
action: "resetView",
|
|
4847
4856
|
keys: "Alt+R",
|
|
@@ -4858,20 +4867,20 @@ var W = {
|
|
|
4858
4867
|
feature: "hotkeys.goToDate"
|
|
4859
4868
|
}
|
|
4860
4869
|
];
|
|
4861
|
-
function
|
|
4862
|
-
return
|
|
4870
|
+
function ao(e) {
|
|
4871
|
+
return ro.find((t) => t.id === e)?.mode;
|
|
4863
4872
|
}
|
|
4864
|
-
function
|
|
4873
|
+
function oo(...e) {
|
|
4865
4874
|
return e.filter((e) => e.length > 0).flatMap((e, t) => t === 0 ? [...e] : ["separator", ...e]);
|
|
4866
4875
|
}
|
|
4867
|
-
function
|
|
4876
|
+
function so(e, t) {
|
|
4868
4877
|
let n = t.keys[e.id];
|
|
4869
4878
|
return n ? {
|
|
4870
4879
|
...e,
|
|
4871
4880
|
shortcut: n
|
|
4872
4881
|
} : e;
|
|
4873
4882
|
}
|
|
4874
|
-
function
|
|
4883
|
+
function co(e, t) {
|
|
4875
4884
|
if (e.price === void 0 || !Number.isFinite(e.price)) return [];
|
|
4876
4885
|
let n = e.formatPrice(e.price), r = [];
|
|
4877
4886
|
if (e.canAlert && r.push({
|
|
@@ -4908,13 +4917,13 @@ function lo(e, t) {
|
|
|
4908
4917
|
icon: "minus"
|
|
4909
4918
|
}), r;
|
|
4910
4919
|
}
|
|
4911
|
-
var
|
|
4920
|
+
var lo = (e) => ({
|
|
4912
4921
|
id: "settings",
|
|
4913
4922
|
label: e("chartMenu.settings"),
|
|
4914
4923
|
icon: "settings"
|
|
4915
4924
|
});
|
|
4916
|
-
function
|
|
4917
|
-
let n = [
|
|
4925
|
+
function uo(e, t) {
|
|
4926
|
+
let n = [so({
|
|
4918
4927
|
id: "resetView",
|
|
4919
4928
|
label: t("chartMenu.resetView")
|
|
4920
4929
|
}, e)];
|
|
@@ -4947,9 +4956,9 @@ function fo(e, t) {
|
|
|
4947
4956
|
label: t("chartMenu.exportData"),
|
|
4948
4957
|
icon: "save"
|
|
4949
4958
|
}] : [];
|
|
4950
|
-
return
|
|
4959
|
+
return oo(co(e, t), n, r, [...i, lo(t)]);
|
|
4951
4960
|
}
|
|
4952
|
-
function
|
|
4961
|
+
function fo(e, t) {
|
|
4953
4962
|
let n = [
|
|
4954
4963
|
{
|
|
4955
4964
|
id: "resetPriceScale",
|
|
@@ -4960,7 +4969,7 @@ function po(e, t) {
|
|
|
4960
4969
|
label: t("settings.autoScale"),
|
|
4961
4970
|
checked: e.autoScale
|
|
4962
4971
|
},
|
|
4963
|
-
|
|
4972
|
+
so({
|
|
4964
4973
|
id: "invertScale",
|
|
4965
4974
|
label: t("chartMenu.invertScale"),
|
|
4966
4975
|
checked: e.inverted
|
|
@@ -4970,7 +4979,7 @@ function po(e, t) {
|
|
|
4970
4979
|
label: t("settings.leftScale"),
|
|
4971
4980
|
checked: e.leftScale
|
|
4972
4981
|
}
|
|
4973
|
-
], r =
|
|
4982
|
+
], r = ro.filter((t) => t.mode !== "logarithmic" || e.canLog).map((n) => ({
|
|
4974
4983
|
id: n.id,
|
|
4975
4984
|
label: t(n.label),
|
|
4976
4985
|
radio: !0,
|
|
@@ -4998,7 +5007,7 @@ function po(e, t) {
|
|
|
4998
5007
|
label: t("chartMenu.lastPriceLine"),
|
|
4999
5008
|
checked: e.lines.lastPrice
|
|
5000
5009
|
}];
|
|
5001
|
-
return
|
|
5010
|
+
return oo(n, r, [{
|
|
5002
5011
|
id: "labels",
|
|
5003
5012
|
label: t("chartMenu.labels"),
|
|
5004
5013
|
submenu: i
|
|
@@ -5006,18 +5015,18 @@ function po(e, t) {
|
|
|
5006
5015
|
id: "lines",
|
|
5007
5016
|
label: t("chartMenu.lines"),
|
|
5008
5017
|
submenu: a
|
|
5009
|
-
}],
|
|
5018
|
+
}], co({
|
|
5010
5019
|
...e,
|
|
5011
5020
|
canTrade: !1,
|
|
5012
5021
|
canDraw: !1
|
|
5013
|
-
}, t), [
|
|
5022
|
+
}, t), [lo(t)]);
|
|
5014
5023
|
}
|
|
5015
|
-
function
|
|
5016
|
-
let n = [
|
|
5024
|
+
function po(e, t) {
|
|
5025
|
+
let n = [so({
|
|
5017
5026
|
id: "resetView",
|
|
5018
5027
|
label: t("chartMenu.resetTimeScale")
|
|
5019
5028
|
}, e)];
|
|
5020
|
-
e.canGoToDate && n.push(
|
|
5029
|
+
e.canGoToDate && n.push(so({
|
|
5021
5030
|
id: "goToDate",
|
|
5022
5031
|
label: t("chartMenu.goToDate"),
|
|
5023
5032
|
icon: "calendar"
|
|
@@ -5028,13 +5037,13 @@ function mo(e, t) {
|
|
|
5028
5037
|
radio: !0,
|
|
5029
5038
|
checked: t.value === e.timezone.current
|
|
5030
5039
|
}));
|
|
5031
|
-
return
|
|
5040
|
+
return oo(n, r.length > 0 ? [{
|
|
5032
5041
|
id: "timezone",
|
|
5033
5042
|
label: t("settings.timezone"),
|
|
5034
5043
|
submenu: r
|
|
5035
5044
|
}] : []);
|
|
5036
5045
|
}
|
|
5037
|
-
function
|
|
5046
|
+
function mo(e, t) {
|
|
5038
5047
|
let n = e.pane ? [
|
|
5039
5048
|
{
|
|
5040
5049
|
id: "paneLog",
|
|
@@ -5052,53 +5061,53 @@ function ho(e, t) {
|
|
|
5052
5061
|
checked: e.pane.percent
|
|
5053
5062
|
}
|
|
5054
5063
|
] : [];
|
|
5055
|
-
return
|
|
5064
|
+
return oo([so({
|
|
5056
5065
|
id: "resetView",
|
|
5057
5066
|
label: t("chartMenu.resetView")
|
|
5058
|
-
}, e)], n, [
|
|
5067
|
+
}, e)], n, [lo(t)]);
|
|
5059
5068
|
}
|
|
5060
|
-
function
|
|
5069
|
+
function ho(e, t, n) {
|
|
5061
5070
|
switch (e) {
|
|
5062
|
-
case "priceAxis": return
|
|
5063
|
-
case "timeAxis": return
|
|
5064
|
-
case "pane": return
|
|
5065
|
-
default: return
|
|
5071
|
+
case "priceAxis": return fo(t, n);
|
|
5072
|
+
case "timeAxis": return po(t, n);
|
|
5073
|
+
case "pane": return mo(t, n);
|
|
5074
|
+
default: return uo(t, n);
|
|
5066
5075
|
}
|
|
5067
5076
|
}
|
|
5068
5077
|
//#endregion
|
|
5069
5078
|
//#region src/widget/signedFigure.ts
|
|
5070
|
-
var
|
|
5071
|
-
function
|
|
5072
|
-
let r = e.replace(
|
|
5073
|
-
return r === n.replace(
|
|
5079
|
+
var go = /^[-+−]/;
|
|
5080
|
+
function _o(e, t, n) {
|
|
5081
|
+
let r = e.replace(go, "");
|
|
5082
|
+
return r === n.replace(go, "") ? r : t > 0 ? `+${r}` : t < 0 ? `-${r}` : r;
|
|
5074
5083
|
}
|
|
5075
|
-
function
|
|
5084
|
+
function vo(e) {
|
|
5076
5085
|
return e.startsWith("+") ? "up" : e.startsWith("-") ? "down" : null;
|
|
5077
5086
|
}
|
|
5078
5087
|
//#endregion
|
|
5079
5088
|
//#region src/widget/WidgetAccountPanel.ts
|
|
5080
|
-
var
|
|
5089
|
+
var yo = [
|
|
5081
5090
|
"positions",
|
|
5082
5091
|
"orders",
|
|
5083
5092
|
"history"
|
|
5084
|
-
],
|
|
5093
|
+
], bo = [
|
|
5085
5094
|
"order",
|
|
5086
5095
|
"close",
|
|
5087
5096
|
"reverse",
|
|
5088
5097
|
"stopLoss",
|
|
5089
5098
|
"takeProfit"
|
|
5090
|
-
],
|
|
5099
|
+
], xo = [
|
|
5091
5100
|
"market",
|
|
5092
5101
|
"limit",
|
|
5093
5102
|
"stop"
|
|
5094
|
-
],
|
|
5095
|
-
function
|
|
5103
|
+
], So = ["gtc", "day"], K = "—", Co = "{pnl}", wo = 3;
|
|
5104
|
+
function To(e, t, n) {
|
|
5096
5105
|
return e.includes(t ?? "") ? t : n;
|
|
5097
5106
|
}
|
|
5098
|
-
function
|
|
5107
|
+
function Eo(e, t) {
|
|
5099
5108
|
return e.length === t.length && e.every((e, n) => e === t[n]);
|
|
5100
5109
|
}
|
|
5101
|
-
function
|
|
5110
|
+
function Do(e, t) {
|
|
5102
5111
|
if (t === null) return null;
|
|
5103
5112
|
let n = e.quantity - (e.closedQuantity ?? 0), r = e.side === "buy" ? 1 : -1;
|
|
5104
5113
|
return {
|
|
@@ -5106,15 +5115,15 @@ function Oo(e, t) {
|
|
|
5106
5115
|
pct: e.entryPrice === 0 ? 0 : (t - e.entryPrice) / e.entryPrice * 100 * r
|
|
5107
5116
|
};
|
|
5108
5117
|
}
|
|
5109
|
-
function
|
|
5118
|
+
function Oo(e) {
|
|
5110
5119
|
let t = document.createElement("span");
|
|
5111
5120
|
return t.dir = "ltr", t.textContent = e, t;
|
|
5112
5121
|
}
|
|
5113
|
-
function
|
|
5114
|
-
let t =
|
|
5122
|
+
function ko(e) {
|
|
5123
|
+
let t = vo(e);
|
|
5115
5124
|
return t ? `tcw-account-${t}` : "";
|
|
5116
5125
|
}
|
|
5117
|
-
var
|
|
5126
|
+
var Ao = class {
|
|
5118
5127
|
el;
|
|
5119
5128
|
tabButtons = /* @__PURE__ */ new Map();
|
|
5120
5129
|
tabLabels = /* @__PURE__ */ new Map();
|
|
@@ -5136,7 +5145,7 @@ var jo = class {
|
|
|
5136
5145
|
r.className = "tcw-account-head";
|
|
5137
5146
|
let i = document.createElement("div");
|
|
5138
5147
|
i.className = "tcw-account-tabs", i.setAttribute("role", "tablist"), i.addEventListener("keydown", (e) => this.onTabKey(e));
|
|
5139
|
-
for (let e of
|
|
5148
|
+
for (let e of yo) {
|
|
5140
5149
|
let t = document.createElement("button");
|
|
5141
5150
|
t.type = "button", t.className = "tcw-account-tab", t.setAttribute("role", "tab"), t.id = `tcw-account-tab-${e}`;
|
|
5142
5151
|
let n = document.createElement("span");
|
|
@@ -5164,7 +5173,7 @@ var jo = class {
|
|
|
5164
5173
|
}
|
|
5165
5174
|
update(e) {
|
|
5166
5175
|
let t = this.snapshot;
|
|
5167
|
-
if (this.snapshot = e,
|
|
5176
|
+
if (this.snapshot = e, Eo(t.positions, e.positions) && Eo(t.orders, e.orders) && Eo(t.fills, e.fills) && t.realisedPnl === e.realisedPnl) {
|
|
5168
5177
|
t.price !== e.price && (this.renderTotals(), this.open && this.tab === "positions" && this.patchPrices());
|
|
5169
5178
|
return;
|
|
5170
5179
|
}
|
|
@@ -5177,10 +5186,10 @@ var jo = class {
|
|
|
5177
5186
|
this.tab = e, this.renderTabs(), this.render();
|
|
5178
5187
|
}
|
|
5179
5188
|
onTabKey(e) {
|
|
5180
|
-
let t =
|
|
5189
|
+
let t = yo.indexOf(this.tab), n = e.key === "ArrowRight" ? t + 1 : e.key === "ArrowLeft" ? t - 1 : -2;
|
|
5181
5190
|
if (n === -2) return;
|
|
5182
5191
|
e.preventDefault();
|
|
5183
|
-
let r =
|
|
5192
|
+
let r = yo[(n + yo.length) % yo.length];
|
|
5184
5193
|
this.selectTab(r), this.tabButtons.get(r)?.focus();
|
|
5185
5194
|
}
|
|
5186
5195
|
renderTabs() {
|
|
@@ -5197,15 +5206,15 @@ var jo = class {
|
|
|
5197
5206
|
}
|
|
5198
5207
|
renderTotals() {
|
|
5199
5208
|
let { positions: e, price: t, fills: n, realisedPnl: r } = this.snapshot, i = [], a = e.reduce((e, n) => {
|
|
5200
|
-
let r =
|
|
5209
|
+
let r = Do(n, t);
|
|
5201
5210
|
return r === null ? e : (e ?? 0) + r.pnl;
|
|
5202
5211
|
}, null);
|
|
5203
5212
|
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);
|
|
5204
5213
|
}
|
|
5205
5214
|
total(e, t) {
|
|
5206
5215
|
let n = document.createElement("span"), r = this.amount(t);
|
|
5207
|
-
n.className = `tcw-account-total ${
|
|
5208
|
-
let i = this.t(e), a = i.indexOf(
|
|
5216
|
+
n.className = `tcw-account-total ${ko(r)}`.trim();
|
|
5217
|
+
let i = this.t(e), a = i.indexOf(Co), o = Oo(r);
|
|
5209
5218
|
return a < 0 ? n.append(`${i} `, o) : n.append(i.slice(0, a), o, i.slice(a + 5)), n;
|
|
5210
5219
|
}
|
|
5211
5220
|
render() {
|
|
@@ -5214,25 +5223,25 @@ var jo = class {
|
|
|
5214
5223
|
}
|
|
5215
5224
|
patchPrices() {
|
|
5216
5225
|
let { price: e } = this.snapshot;
|
|
5217
|
-
for (let t of this.live) t.price.textContent = e === null ?
|
|
5226
|
+
for (let t of this.live) t.price.textContent = e === null ? K : this.callbacks.formatPrice(e), this.writePnl(t.pnl, Do(t.position, e));
|
|
5218
5227
|
}
|
|
5219
5228
|
amount(e) {
|
|
5220
|
-
return
|
|
5229
|
+
return _o(this.money(Math.abs(e)), e, this.money(0));
|
|
5221
5230
|
}
|
|
5222
5231
|
money(e) {
|
|
5223
5232
|
return this.callbacks.formatAmount ? this.callbacks.formatAmount(e) : e.toFixed(2);
|
|
5224
5233
|
}
|
|
5225
5234
|
percent(e) {
|
|
5226
5235
|
let t = (e) => this.callbacks.formatNumber ? this.callbacks.formatNumber(e, 2) : e.toFixed(2);
|
|
5227
|
-
return `${
|
|
5236
|
+
return `${_o(t(Math.abs(e)), e, t(0))}%`;
|
|
5228
5237
|
}
|
|
5229
5238
|
writePnl(e, t) {
|
|
5230
5239
|
if (t === null) {
|
|
5231
|
-
e.className = "", e.textContent =
|
|
5240
|
+
e.className = "", e.textContent = K;
|
|
5232
5241
|
return;
|
|
5233
5242
|
}
|
|
5234
5243
|
let n = this.amount(t.pnl);
|
|
5235
|
-
e.className =
|
|
5244
|
+
e.className = ko(n), e.textContent = `${n} · ${this.percent(t.pct)}`;
|
|
5236
5245
|
}
|
|
5237
5246
|
table(e, t, n) {
|
|
5238
5247
|
if (t.length === 0) {
|
|
@@ -5273,18 +5282,18 @@ var jo = class {
|
|
|
5273
5282
|
return t;
|
|
5274
5283
|
}
|
|
5275
5284
|
price(e) {
|
|
5276
|
-
return e === void 0 ?
|
|
5285
|
+
return e === void 0 ? K : this.callbacks.formatPrice(e);
|
|
5277
5286
|
}
|
|
5278
5287
|
renderPositions() {
|
|
5279
5288
|
let { formatPrice: e } = this.callbacks, { price: t } = this.snapshot, n = [], r = this.snapshot.positions.map((r) => {
|
|
5280
|
-
let i = r.quantity - (r.closedQuantity ?? 0), a =
|
|
5281
|
-
this.writePnl(a,
|
|
5289
|
+
let i = r.quantity - (r.closedQuantity ?? 0), a = Oo("");
|
|
5290
|
+
this.writePnl(a, Do(r, t)), n.push(a);
|
|
5282
5291
|
let o = `${this.sideText(r.side, "position")} ${i} @ ${e(r.entryPrice)}`;
|
|
5283
5292
|
return [
|
|
5284
5293
|
this.sideCell(r.side),
|
|
5285
5294
|
String(i),
|
|
5286
5295
|
e(r.entryPrice),
|
|
5287
|
-
t === null ?
|
|
5296
|
+
t === null ? K : e(t),
|
|
5288
5297
|
a,
|
|
5289
5298
|
this.price(r.stopLoss),
|
|
5290
5299
|
this.price(r.takeProfit),
|
|
@@ -5333,13 +5342,13 @@ var jo = class {
|
|
|
5333
5342
|
let a = [...i.tBodies[0].rows];
|
|
5334
5343
|
this.snapshot.positions.forEach((e, t) => this.live.push({
|
|
5335
5344
|
position: e,
|
|
5336
|
-
price: a[t].cells[
|
|
5345
|
+
price: a[t].cells[wo],
|
|
5337
5346
|
pnl: n[t]
|
|
5338
5347
|
}));
|
|
5339
5348
|
}
|
|
5340
5349
|
renderOrders() {
|
|
5341
5350
|
let { formatPrice: e } = this.callbacks, t = this.snapshot.orders.map((t) => {
|
|
5342
|
-
let n =
|
|
5351
|
+
let n = To(xo, t.type === "stopLimit" ? "stop" : t.type, "limit"), r = `${this.sideText(t.side, "trade")} ${t.quantity} @ ${e(t.price)}`;
|
|
5343
5352
|
return [
|
|
5344
5353
|
this.sideCell(t.side, "trade"),
|
|
5345
5354
|
this.t(`ticket.type.${n}`),
|
|
@@ -5347,7 +5356,7 @@ var jo = class {
|
|
|
5347
5356
|
e(t.price),
|
|
5348
5357
|
this.price(t.stopLoss),
|
|
5349
5358
|
this.price(t.takeProfit),
|
|
5350
|
-
t.timeInForce ? this.t(`ticket.tif.${
|
|
5359
|
+
t.timeInForce ? this.t(`ticket.tif.${To(So, t.timeInForce, "gtc")}`) : K,
|
|
5351
5360
|
this.actions({
|
|
5352
5361
|
icon: "x",
|
|
5353
5362
|
label: `${this.t("account.cancelOrder")}: ${r}`,
|
|
@@ -5382,13 +5391,13 @@ var jo = class {
|
|
|
5382
5391
|
}
|
|
5383
5392
|
renderHistory() {
|
|
5384
5393
|
let { formatPrice: e, formatTime: t } = this.callbacks, n = [...this.snapshot.fills].reverse().map((n) => {
|
|
5385
|
-
let r =
|
|
5386
|
-
return n.pnl === void 0 ? r.textContent =
|
|
5394
|
+
let r = Oo("");
|
|
5395
|
+
return n.pnl === void 0 ? r.textContent = K : (r.textContent = this.amount(n.pnl), r.className = ko(r.textContent)), [
|
|
5387
5396
|
t(n.time),
|
|
5388
5397
|
this.sideCell(n.side, "trade"),
|
|
5389
5398
|
String(n.quantity),
|
|
5390
5399
|
e(n.price),
|
|
5391
|
-
this.t(`account.reason.${
|
|
5400
|
+
this.t(`account.reason.${To(bo, n.reason, "order")}`),
|
|
5392
5401
|
r
|
|
5393
5402
|
];
|
|
5394
5403
|
});
|
|
@@ -5410,11 +5419,11 @@ var jo = class {
|
|
|
5410
5419
|
}
|
|
5411
5420
|
], n, "account.noFills");
|
|
5412
5421
|
}
|
|
5413
|
-
},
|
|
5414
|
-
function
|
|
5422
|
+
}, jo = 1e-9;
|
|
5423
|
+
function Mo(e, t) {
|
|
5415
5424
|
return e.type === "market" ? t : e.price;
|
|
5416
5425
|
}
|
|
5417
|
-
function
|
|
5426
|
+
function No(e, t, n = {}) {
|
|
5418
5427
|
let r = [];
|
|
5419
5428
|
(!(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");
|
|
5420
5429
|
let i = e.side === "buy";
|
|
@@ -5424,18 +5433,18 @@ function Po(e, t, n = {}) {
|
|
|
5424
5433
|
}
|
|
5425
5434
|
let a = (e) => e === null || Number.isFinite(e) && e > 0;
|
|
5426
5435
|
a(e.stopLoss) || r.push("stopLoss"), a(e.takeProfit) || r.push("takeProfit");
|
|
5427
|
-
let o =
|
|
5428
|
-
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, ...
|
|
5436
|
+
let o = Mo(e, t);
|
|
5437
|
+
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, ...Po(e, n)];
|
|
5429
5438
|
}
|
|
5430
|
-
function
|
|
5439
|
+
function Po(e, t) {
|
|
5431
5440
|
let n = [], r = e.type === "market" ? null : e.price, i = [
|
|
5432
5441
|
r,
|
|
5433
5442
|
e.stopLoss,
|
|
5434
5443
|
e.takeProfit
|
|
5435
5444
|
].filter((e) => e !== null && Number.isFinite(e) && e > 0), { roundPrice: a, limits: o, lot: s } = t;
|
|
5436
|
-
return a && i.some((e) => Math.abs(a(e) - e) >
|
|
5445
|
+
return a && i.some((e) => Math.abs(a(e) - e) > jo) && n.push("priceStep"), o && r !== null && r > 0 && (r > o.ceiling + jo || r < o.floor - jo) && n.push("priceLimits"), s !== void 0 && s > 1 && e.quantity > s && e.quantity % s !== 0 && n.push("lot"), n;
|
|
5437
5446
|
}
|
|
5438
|
-
function
|
|
5447
|
+
function Fo(e, t) {
|
|
5439
5448
|
let n = {
|
|
5440
5449
|
side: e.side,
|
|
5441
5450
|
type: e.type,
|
|
@@ -5444,14 +5453,14 @@ function Io(e, t) {
|
|
|
5444
5453
|
};
|
|
5445
5454
|
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;
|
|
5446
5455
|
}
|
|
5447
|
-
function
|
|
5448
|
-
let n =
|
|
5456
|
+
function Io(e, t) {
|
|
5457
|
+
let n = Mo(e, t);
|
|
5449
5458
|
if (n === null || e.stopLoss === null || e.takeProfit === null) return null;
|
|
5450
5459
|
let r = Math.abs(n - e.stopLoss);
|
|
5451
5460
|
return r > 0 ? Math.abs(e.takeProfit - n) / r : null;
|
|
5452
5461
|
}
|
|
5453
|
-
function
|
|
5454
|
-
let i =
|
|
5462
|
+
function Lo(e, t, n, r = 1) {
|
|
5463
|
+
let i = Mo(e, t);
|
|
5455
5464
|
if (i === null || !(i > 0) || !Number.isFinite(n) || !(e.quantity > 0)) return null;
|
|
5456
5465
|
let a = e.side === "buy" ? 1 : -1;
|
|
5457
5466
|
return {
|
|
@@ -5459,18 +5468,18 @@ function Ro(e, t, n, r = 1) {
|
|
|
5459
5468
|
amount: (n - i) * e.quantity * a * r
|
|
5460
5469
|
};
|
|
5461
5470
|
}
|
|
5462
|
-
function
|
|
5463
|
-
let r = n.multiplier !== void 0 && n.multiplier > 0 ? n.multiplier : 1, i =
|
|
5471
|
+
function Ro(e, t, n = {}) {
|
|
5472
|
+
let r = n.multiplier !== void 0 && n.multiplier > 0 ? n.multiplier : 1, i = Mo(e, t), a = i !== null && i > 0 && e.quantity > 0 ? i * e.quantity * r : null, o = No(e, t), s = (n, i) => n === null || o.includes(i) ? null : Lo(e, t, n, r)?.amount ?? null, c = s(e.stopLoss, "stopLossSide"), l = s(e.takeProfit, "takeProfitSide");
|
|
5464
5473
|
return {
|
|
5465
5474
|
value: a,
|
|
5466
5475
|
risk: c,
|
|
5467
5476
|
reward: l,
|
|
5468
|
-
ratio: c !== null && l !== null ?
|
|
5477
|
+
ratio: c !== null && l !== null ? Io(e, t) : null
|
|
5469
5478
|
};
|
|
5470
5479
|
}
|
|
5471
5480
|
//#endregion
|
|
5472
5481
|
//#region src/widget/WidgetOrderTicket.ts
|
|
5473
|
-
var
|
|
5482
|
+
var zo = 229, Bo = 1, Vo = 2, Ho = .999999999, Uo = 0, Wo = class {
|
|
5474
5483
|
backdrop;
|
|
5475
5484
|
modal;
|
|
5476
5485
|
symbolEl;
|
|
@@ -5481,11 +5490,11 @@ var Bo = 229, Vo = 1, Ho = 2, Uo = .999999999, Wo = 0, Go = class {
|
|
|
5481
5490
|
draft = null;
|
|
5482
5491
|
lastPrice = null;
|
|
5483
5492
|
rules = {};
|
|
5484
|
-
step =
|
|
5485
|
-
round = (e) =>
|
|
5493
|
+
step = Ko;
|
|
5494
|
+
round = (e) => qo(e, e);
|
|
5486
5495
|
typed = /* @__PURE__ */ new Map();
|
|
5487
5496
|
returnFocus = null;
|
|
5488
|
-
uid = ++
|
|
5497
|
+
uid = ++Uo;
|
|
5489
5498
|
constructor(e, t, n = w) {
|
|
5490
5499
|
this.callbacks = t, this.t = n, this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.hidden = !0;
|
|
5491
5500
|
let r = !1;
|
|
@@ -5494,7 +5503,7 @@ var Bo = 229, Vo = 1, Ho = 2, Uo = .999999999, Wo = 0, Go = class {
|
|
|
5494
5503
|
}), this.backdrop.addEventListener("click", (e) => {
|
|
5495
5504
|
e.target === this.backdrop && r && this.close(), r = !1;
|
|
5496
5505
|
}), 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) => {
|
|
5497
|
-
if (e.key === "Escape" && !e.isComposing && e.keyCode !==
|
|
5506
|
+
if (e.key === "Escape" && !e.isComposing && e.keyCode !== zo) {
|
|
5498
5507
|
e.stopPropagation(), this.close();
|
|
5499
5508
|
return;
|
|
5500
5509
|
}
|
|
@@ -5516,7 +5525,7 @@ var Bo = 229, Vo = 1, Ho = 2, Uo = .999999999, Wo = 0, Go = class {
|
|
|
5516
5525
|
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);
|
|
5517
5526
|
}
|
|
5518
5527
|
open(e) {
|
|
5519
|
-
this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null, this.lastPrice = e.lastPrice, this.rules = e.rules ?? {}, this.step = e.step ??
|
|
5528
|
+
this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null, this.lastPrice = e.lastPrice, this.rules = e.rules ?? {}, this.step = e.step ?? Ko, this.round = e.round ?? ((e) => qo(e, e)), this.typed.clear(), this.symbolEl.textContent = e.symbol ?? "";
|
|
5520
5529
|
let t = this.round(e.price ?? e.lastPrice ?? 0), n = e.side ?? "buy", r = "market";
|
|
5521
5530
|
e.price !== void 0 && e.lastPrice !== null && t !== e.lastPrice && (r = t < e.lastPrice == (n === "buy") ? "limit" : "stop"), this.draft = {
|
|
5522
5531
|
side: n,
|
|
@@ -5552,14 +5561,14 @@ var Bo = 229, Vo = 1, Ho = 2, Uo = .999999999, Wo = 0, Go = class {
|
|
|
5552
5561
|
return t > 0 ? Number((10 ** -t).toFixed(t)) : 1;
|
|
5553
5562
|
}
|
|
5554
5563
|
priceStep(e, t) {
|
|
5555
|
-
return this.step(t > 0 ? e : e *
|
|
5564
|
+
return this.step(t > 0 ? e : e * Ho);
|
|
5556
5565
|
}
|
|
5557
5566
|
writePrice(e) {
|
|
5558
|
-
return Number.isFinite(e) ? this.step ===
|
|
5567
|
+
return Number.isFinite(e) ? this.step === Ko ? String(e) : e.toFixed(at(this.step(e))) : "";
|
|
5559
5568
|
}
|
|
5560
5569
|
place() {
|
|
5561
5570
|
let e = this.draft;
|
|
5562
|
-
!e ||
|
|
5571
|
+
!e || No(e, this.lastPrice, this.rules).length > 0 || (this.callbacks.onSubmit(Fo(e, this.lastPrice)), this.close());
|
|
5563
5572
|
}
|
|
5564
5573
|
set(e, t = !1) {
|
|
5565
5574
|
this.draft && (this.draft = {
|
|
@@ -5594,7 +5603,7 @@ var Bo = 229, Vo = 1, Ho = 2, Uo = .999999999, Wo = 0, Go = class {
|
|
|
5594
5603
|
return r.className = "tcw-settings-label", r.textContent = this.t(e), n.append(r, t), n;
|
|
5595
5604
|
}
|
|
5596
5605
|
choices(e, t, n, r, i) {
|
|
5597
|
-
let a = e === "type" ? "ticket.type" : "ticket.tif", o =
|
|
5606
|
+
let a = e === "type" ? "ticket.type" : "ticket.tif", o = Go(e, Ee(t.map((e) => ({
|
|
5598
5607
|
value: e,
|
|
5599
5608
|
label: this.t(`${a}.${e}`)
|
|
5600
5609
|
})), n, i, this.t(r)));
|
|
@@ -5627,7 +5636,7 @@ var Bo = 229, Vo = 1, Ho = 2, Uo = .999999999, Wo = 0, Go = class {
|
|
|
5627
5636
|
return this.stepped(e, t, (e, t) => this.priceStep(e, t), () => this.lastPrice ?? this.draft?.price ?? 0, (e) => this.writePrice(e), n);
|
|
5628
5637
|
}
|
|
5629
5638
|
stepped(e, t, n, r, i, a) {
|
|
5630
|
-
let o =
|
|
5639
|
+
let o = Go(e, document.createElement("input"));
|
|
5631
5640
|
o.type = "number", o.className = "tcw-indi-input", o.step = "any", o.min = "0", o.value = this.typed.get(e) ?? i(t);
|
|
5632
5641
|
let s = this.t(`ticket.${e}`);
|
|
5633
5642
|
o.setAttribute("aria-label", s), o.addEventListener("input", () => {
|
|
@@ -5665,25 +5674,25 @@ var Bo = 229, Vo = 1, Ho = 2, Uo = .999999999, Wo = 0, Go = class {
|
|
|
5665
5674
|
if (!t) return NaN;
|
|
5666
5675
|
let n = t.type === "market" ? this.lastPrice ?? t.price : t.price;
|
|
5667
5676
|
if (!(n > 0)) return NaN;
|
|
5668
|
-
let r = e === "stopLoss" ? -
|
|
5677
|
+
let r = e === "stopLoss" ? -Bo : Vo;
|
|
5669
5678
|
return this.round(n * (1 + (t.side === "buy" ? r : -r) / 100));
|
|
5670
5679
|
}
|
|
5671
5680
|
check() {
|
|
5672
5681
|
let e = this.draft;
|
|
5673
5682
|
if (!e) return;
|
|
5674
|
-
let t =
|
|
5683
|
+
let t = No(e, this.lastPrice, this.rules), n = t.map((e) => this.problemText(e));
|
|
5675
5684
|
n.join("\n") !== [...this.problemsEl.children].map((e) => e.textContent).join("\n") && this.problemsEl.replaceChildren(...n.map((e) => {
|
|
5676
5685
|
let t = document.createElement("p");
|
|
5677
5686
|
return t.textContent = e, t;
|
|
5678
5687
|
}));
|
|
5679
5688
|
for (let t of ["stopLoss", "takeProfit"]) {
|
|
5680
|
-
let n = this.body.querySelector(`.tcw-ticket-away[data-for="${t}"]`), r = e[t], i = r === null ? null :
|
|
5689
|
+
let n = this.body.querySelector(`.tcw-ticket-away[data-for="${t}"]`), r = e[t], i = r === null ? null : Lo(e, this.lastPrice, r, this.rules.multiplier);
|
|
5681
5690
|
n && (n.textContent = i ? `${this.signedNumber(i.pct, 2)}% · ${this.amount(i.amount)}` : "");
|
|
5682
5691
|
}
|
|
5683
5692
|
this.renderSummary(e), this.submit.disabled = t.length > 0, this.submit.textContent = this.t(e.side === "buy" ? "ticket.placeBuy" : "ticket.placeSell");
|
|
5684
5693
|
}
|
|
5685
5694
|
renderSummary(e) {
|
|
5686
|
-
let t =
|
|
5695
|
+
let t = Ro(e, this.lastPrice, this.rules), n = t.risk === null ? null : this.amount(t.risk), r = t.reward === null ? null : this.amount(t.reward), i = [
|
|
5687
5696
|
[
|
|
5688
5697
|
"value",
|
|
5689
5698
|
"ticket.value",
|
|
@@ -5694,13 +5703,13 @@ var Bo = 229, Vo = 1, Ho = 2, Uo = .999999999, Wo = 0, Go = class {
|
|
|
5694
5703
|
"risk",
|
|
5695
5704
|
"ticket.risk",
|
|
5696
5705
|
n,
|
|
5697
|
-
n === null ? null :
|
|
5706
|
+
n === null ? null : vo(n)
|
|
5698
5707
|
],
|
|
5699
5708
|
[
|
|
5700
5709
|
"reward",
|
|
5701
5710
|
"ticket.reward",
|
|
5702
5711
|
r,
|
|
5703
|
-
r === null ? null :
|
|
5712
|
+
r === null ? null : vo(r)
|
|
5704
5713
|
],
|
|
5705
5714
|
[
|
|
5706
5715
|
"ratio",
|
|
@@ -5722,10 +5731,10 @@ var Bo = 229, Vo = 1, Ho = 2, Uo = .999999999, Wo = 0, Go = class {
|
|
|
5722
5731
|
return this.callbacks.formatNumber ? this.callbacks.formatNumber(e, t) : e.toFixed(t);
|
|
5723
5732
|
}
|
|
5724
5733
|
signedNumber(e, t) {
|
|
5725
|
-
return
|
|
5734
|
+
return _o(this.number(Math.abs(e), t), e, this.number(0, t));
|
|
5726
5735
|
}
|
|
5727
5736
|
amount(e) {
|
|
5728
|
-
return
|
|
5737
|
+
return _o(this.money(Math.abs(e)), e, this.money(0));
|
|
5729
5738
|
}
|
|
5730
5739
|
money(e) {
|
|
5731
5740
|
return (this.callbacks.formatAmount ?? this.callbacks.formatPrice)(e);
|
|
@@ -5738,20 +5747,20 @@ var Bo = 229, Vo = 1, Ho = 2, Uo = .999999999, Wo = 0, Go = class {
|
|
|
5738
5747
|
}) : e === "lot" ? C(t, { lot: r ?? 1 }) : t;
|
|
5739
5748
|
}
|
|
5740
5749
|
};
|
|
5741
|
-
function
|
|
5750
|
+
function Go(e, t) {
|
|
5742
5751
|
return t.dataset.ticketField = e, t;
|
|
5743
5752
|
}
|
|
5744
|
-
function
|
|
5753
|
+
function Ko(e) {
|
|
5745
5754
|
let t = Math.abs(e);
|
|
5746
5755
|
return t > 0 ? 10 ** Math.floor(Math.log10(t / 100)) : 1;
|
|
5747
5756
|
}
|
|
5748
|
-
function
|
|
5757
|
+
function qo(e, t) {
|
|
5749
5758
|
let n = Math.abs(t), r = n >= 10 || n === 0 ? 2 : n >= 1 ? 4 : Math.min(10, Math.ceil(-Math.log10(n)) + 3);
|
|
5750
5759
|
return Number(e.toFixed(r));
|
|
5751
5760
|
}
|
|
5752
5761
|
//#endregion
|
|
5753
5762
|
//#region src/widget/WidgetNamePrompt.ts
|
|
5754
|
-
var
|
|
5763
|
+
var Jo = 0, Yo = class {
|
|
5755
5764
|
backdrop;
|
|
5756
5765
|
titleEl;
|
|
5757
5766
|
input;
|
|
@@ -5759,7 +5768,7 @@ var Yo = 0, Xo = class {
|
|
|
5759
5768
|
request = null;
|
|
5760
5769
|
returnFocus = null;
|
|
5761
5770
|
busy = !1;
|
|
5762
|
-
uid = ++
|
|
5771
|
+
uid = ++Jo;
|
|
5763
5772
|
constructor(e, t = w) {
|
|
5764
5773
|
this.t = t, this.backdrop = document.createElement("div"), this.backdrop.className = "tcw-modal-backdrop", this.backdrop.hidden = !0;
|
|
5765
5774
|
let n = !1;
|
|
@@ -5819,13 +5828,13 @@ var Yo = 0, Xo = class {
|
|
|
5819
5828
|
}
|
|
5820
5829
|
}
|
|
5821
5830
|
}
|
|
5822
|
-
},
|
|
5831
|
+
}, Xo = 0, Zo = class {
|
|
5823
5832
|
el;
|
|
5824
5833
|
input;
|
|
5825
5834
|
hint;
|
|
5826
5835
|
returnFocus = null;
|
|
5827
5836
|
constructor(e, t, n) {
|
|
5828
|
-
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-${++
|
|
5837
|
+
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-${++Xo}`, 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) => {
|
|
5829
5838
|
e.key === "Enter" ? (e.preventDefault(), e.stopPropagation(), this.apply()) : e.key === "Escape" && (e.preventDefault(), e.stopPropagation(), this.close());
|
|
5830
5839
|
}), this.input.addEventListener("blur", () => this.close(!1));
|
|
5831
5840
|
}
|
|
@@ -5856,7 +5865,7 @@ var Yo = 0, Xo = class {
|
|
|
5856
5865
|
}
|
|
5857
5866
|
this.input.setAttribute("aria-invalid", "true"), this.hint.textContent = this.labels.invalid;
|
|
5858
5867
|
}
|
|
5859
|
-
},
|
|
5868
|
+
}, Qo = class {
|
|
5860
5869
|
constructor(e = "tcw:indicator-templates") {
|
|
5861
5870
|
this.key = e;
|
|
5862
5871
|
}
|
|
@@ -5901,28 +5910,28 @@ var Yo = 0, Xo = class {
|
|
|
5901
5910
|
localStorage.setItem(this.key, JSON.stringify(this.list().filter((t) => t.name !== e)));
|
|
5902
5911
|
} catch {}
|
|
5903
5912
|
}
|
|
5904
|
-
},
|
|
5913
|
+
}, $o = [
|
|
5905
5914
|
"regular",
|
|
5906
5915
|
"logarithmic",
|
|
5907
5916
|
"percentage",
|
|
5908
5917
|
"indexedTo100"
|
|
5909
|
-
],
|
|
5910
|
-
function
|
|
5918
|
+
], es = (e) => typeof e == "object" && !!e && !Array.isArray(e);
|
|
5919
|
+
function ts(e) {
|
|
5911
5920
|
let { theme: t, timestamp: n, ...r } = e;
|
|
5912
5921
|
return r;
|
|
5913
5922
|
}
|
|
5914
|
-
function
|
|
5915
|
-
return !
|
|
5923
|
+
function ns(e) {
|
|
5924
|
+
return !es(e) || e.v !== 1 || typeof e.symbol != "string" || !e.symbol || typeof e.timeframe != "string" || !(Ge(e.timeframe) || E(e.timeframe) !== null) ? null : {
|
|
5916
5925
|
v: 1,
|
|
5917
5926
|
symbol: e.symbol,
|
|
5918
5927
|
timeframe: e.timeframe,
|
|
5919
|
-
scaleMode:
|
|
5928
|
+
scaleMode: $o.find((t) => t === e.scaleMode) ?? "regular",
|
|
5920
5929
|
invertScale: e.invertScale === !0,
|
|
5921
|
-
chart:
|
|
5922
|
-
...
|
|
5930
|
+
chart: es(e.chart) ? ts(e.chart) : null,
|
|
5931
|
+
...es(e.settings) ? { settings: U(e.settings, sa) } : {}
|
|
5923
5932
|
};
|
|
5924
5933
|
}
|
|
5925
|
-
function
|
|
5934
|
+
function rs(e) {
|
|
5926
5935
|
try {
|
|
5927
5936
|
return JSON.parse(e);
|
|
5928
5937
|
} catch {
|
|
@@ -5931,16 +5940,16 @@ function is(e) {
|
|
|
5931
5940
|
}
|
|
5932
5941
|
//#endregion
|
|
5933
5942
|
//#region src/widget/DrawingFavoritesStore.ts
|
|
5934
|
-
function
|
|
5943
|
+
function is() {
|
|
5935
5944
|
try {
|
|
5936
5945
|
return typeof localStorage < "u" ? localStorage : null;
|
|
5937
5946
|
} catch {
|
|
5938
5947
|
return null;
|
|
5939
5948
|
}
|
|
5940
5949
|
}
|
|
5941
|
-
var
|
|
5950
|
+
var as = class {
|
|
5942
5951
|
favorites = [];
|
|
5943
|
-
constructor(e = "tcw:draw-favorites", t =
|
|
5952
|
+
constructor(e = "tcw:draw-favorites", t = is()) {
|
|
5944
5953
|
this.storageKey = e, this.storage = t, this.load();
|
|
5945
5954
|
}
|
|
5946
5955
|
list() {
|
|
@@ -5977,7 +5986,7 @@ var os = class {
|
|
|
5977
5986
|
};
|
|
5978
5987
|
//#endregion
|
|
5979
5988
|
//#region src/widget/keyboardInset.ts
|
|
5980
|
-
function
|
|
5989
|
+
function os(e) {
|
|
5981
5990
|
let t = typeof window < "u" ? window.visualViewport : null;
|
|
5982
5991
|
if (!t) return () => {};
|
|
5983
5992
|
let n = -1, r = () => {
|
|
@@ -5991,7 +6000,7 @@ function ss(e) {
|
|
|
5991
6000
|
t.removeEventListener("resize", r), t.removeEventListener("scroll", r);
|
|
5992
6001
|
};
|
|
5993
6002
|
}
|
|
5994
|
-
function
|
|
6003
|
+
function ss(e, t) {
|
|
5995
6004
|
let n = null, r = () => {
|
|
5996
6005
|
let r = e.clientWidth;
|
|
5997
6006
|
if (r === 0 && n !== null) return;
|
|
@@ -6004,7 +6013,7 @@ function cs(e, t) {
|
|
|
6004
6013
|
}
|
|
6005
6014
|
//#endregion
|
|
6006
6015
|
//#region src/widget/lazyPart.ts
|
|
6007
|
-
function
|
|
6016
|
+
function q(e) {
|
|
6008
6017
|
let t = null, n = null;
|
|
6009
6018
|
return {
|
|
6010
6019
|
get: () => t,
|
|
@@ -6015,7 +6024,7 @@ function K(e) {
|
|
|
6015
6024
|
}
|
|
6016
6025
|
};
|
|
6017
6026
|
}
|
|
6018
|
-
var
|
|
6027
|
+
var cs = class {
|
|
6019
6028
|
part = null;
|
|
6020
6029
|
loading = null;
|
|
6021
6030
|
gone = !1;
|
|
@@ -6040,24 +6049,24 @@ var ls = class {
|
|
|
6040
6049
|
destroy() {
|
|
6041
6050
|
this.gone = !0, this.part && this.dispose(this.part), this.part = null;
|
|
6042
6051
|
}
|
|
6043
|
-
},
|
|
6044
|
-
settings:
|
|
6045
|
-
indicatorSettings:
|
|
6046
|
-
drawingSettings:
|
|
6047
|
-
goToDate:
|
|
6048
|
-
hotkeySheet:
|
|
6049
|
-
indicatorPicker:
|
|
6050
|
-
commandPalette:
|
|
6051
|
-
symbolSearch:
|
|
6052
|
+
}, J = {
|
|
6053
|
+
settings: q(() => import("../WidgetSettings-CkvK-3d9.js")),
|
|
6054
|
+
indicatorSettings: q(() => import("../WidgetIndicatorSettings-C4S0QgW-.js")),
|
|
6055
|
+
drawingSettings: q(() => import("../WidgetDrawingSettings-CsR3GuFG.js")),
|
|
6056
|
+
goToDate: q(() => import("../WidgetGoToDate-hcDtezRm.js")),
|
|
6057
|
+
hotkeySheet: q(() => import("../WidgetHotkeySheet-1lRFSdvt.js")),
|
|
6058
|
+
indicatorPicker: q(() => import("../WidgetIndicatorPicker-Cb2m62oH.js")),
|
|
6059
|
+
commandPalette: q(() => import("../WidgetCommandPalette-Bvr6Od3p.js")),
|
|
6060
|
+
symbolSearch: q(() => import("../WidgetSymbolSearch-BWI3iNJM.js"))
|
|
6052
6061
|
};
|
|
6053
|
-
async function
|
|
6054
|
-
await Promise.all(Object.values(
|
|
6062
|
+
async function ls() {
|
|
6063
|
+
await Promise.all(Object.values(J).map((e) => e.load().catch(() => null)));
|
|
6055
6064
|
}
|
|
6056
6065
|
//#endregion
|
|
6057
6066
|
//#region src/widget/wallTime.ts
|
|
6058
|
-
var
|
|
6059
|
-
function
|
|
6060
|
-
let r =
|
|
6067
|
+
var us = /^(\d{4})-(\d{2})-(\d{2})$/, ds = /^(\d{2}):(\d{2})$/;
|
|
6068
|
+
function fs(e, t, n) {
|
|
6069
|
+
let r = us.exec(e), i = t ? ds.exec(t) : [
|
|
6061
6070
|
"",
|
|
6062
6071
|
"00",
|
|
6063
6072
|
"00"
|
|
@@ -6074,7 +6083,7 @@ function ps(e, t, n) {
|
|
|
6074
6083
|
let u = Date.UTC(a, o - 1, s, c, l);
|
|
6075
6084
|
return new Date(u).getUTCDate() === s ? ut(u, n) : null;
|
|
6076
6085
|
}
|
|
6077
|
-
function
|
|
6086
|
+
function Y(e, t) {
|
|
6078
6087
|
let n = (e) => String(e).padStart(2, "0"), r = st(e, t);
|
|
6079
6088
|
return {
|
|
6080
6089
|
date: `${r.year}-${n(r.month)}-${n(r.day)}`,
|
|
@@ -6083,11 +6092,11 @@ function J(e, t) {
|
|
|
6083
6092
|
}
|
|
6084
6093
|
//#endregion
|
|
6085
6094
|
//#region src/widget/WidgetDock.ts
|
|
6086
|
-
var
|
|
6095
|
+
var X = {
|
|
6087
6096
|
min: 233,
|
|
6088
|
-
default:
|
|
6097
|
+
default: 262,
|
|
6089
6098
|
max: 377
|
|
6090
|
-
},
|
|
6099
|
+
}, ps = .382, ms = (e) => !e.hidden && getComputedStyle(e).display !== "none", hs = class {
|
|
6091
6100
|
element;
|
|
6092
6101
|
panel;
|
|
6093
6102
|
rail;
|
|
@@ -6110,9 +6119,9 @@ var Y = {
|
|
|
6110
6119
|
let r = document.createElement("div");
|
|
6111
6120
|
r.className = "tcw-dock-panel", r.hidden = !0, r.addEventListener("keydown", (e) => this.onPanelKey(e));
|
|
6112
6121
|
let i = document.createElement("div");
|
|
6113
|
-
i.className = "tcw-dock-resize", i.setAttribute("role", "separator"), i.setAttribute("aria-orientation", "vertical"), i.setAttribute("aria-label", t.labels.resize), i.setAttribute("aria-valuemin", String(
|
|
6122
|
+
i.className = "tcw-dock-resize", i.setAttribute("role", "separator"), i.setAttribute("aria-orientation", "vertical"), i.setAttribute("aria-label", t.labels.resize), i.setAttribute("aria-valuemin", String(X.min)), i.tabIndex = 0, i.addEventListener("pointerdown", (e) => this.startDrag(e)), i.addEventListener("keydown", (e) => this.onHandleKey(e)), r.appendChild(i);
|
|
6114
6123
|
let a = document.createElement("div");
|
|
6115
|
-
a.className = "tcw-dock-rail", a.setAttribute("role", "toolbar"), a.setAttribute("aria-orientation", "vertical"), a.setAttribute("aria-label", t.labels.rail), v(a, "dock"), a.addEventListener("keydown", (e) => this.onRailKey(e)), n.append(r, a), e.appendChild(n), this.element = n, this.panel = r, this.rail = a, this.handle = i, this.width = this.clamp(t.savedWidth?.() ??
|
|
6124
|
+
a.className = "tcw-dock-rail", a.setAttribute("role", "toolbar"), a.setAttribute("aria-orientation", "vertical"), a.setAttribute("aria-label", t.labels.rail), v(a, "dock"), a.addEventListener("keydown", (e) => this.onRailKey(e)), n.append(r, a), e.appendChild(n), this.element = n, this.panel = r, this.rail = a, this.handle = i, this.width = this.clamp(t.savedWidth?.() ?? X.default, X.max), this.applyWidth(), t.room && typeof ResizeObserver < "u" && (this.observer = new ResizeObserver(() => this.fit()), this.observer.observe(e));
|
|
6116
6125
|
}
|
|
6117
6126
|
addPage(e) {
|
|
6118
6127
|
let t = document.createElement("button");
|
|
@@ -6133,7 +6142,7 @@ var Y = {
|
|
|
6133
6142
|
let t = this.panel.contains(document.activeElement);
|
|
6134
6143
|
if (this.hideCurrent(), this.panel.hidden = !0, t) {
|
|
6135
6144
|
let t = this.pages.get(e)?.button;
|
|
6136
|
-
(t && (this.options.railShown?.() ?? !0) &&
|
|
6145
|
+
(t && (this.options.railShown?.() ?? !0) && ms(t) ? t : this.options.focusAfterClose?.(e))?.focus();
|
|
6137
6146
|
}
|
|
6138
6147
|
this.options.onChange?.(null);
|
|
6139
6148
|
}
|
|
@@ -6150,7 +6159,7 @@ var Y = {
|
|
|
6150
6159
|
return this.open_ === e;
|
|
6151
6160
|
}
|
|
6152
6161
|
syncRail() {
|
|
6153
|
-
let e = [...this.pages.values()].map((e) => e.button), t = e.filter(
|
|
6162
|
+
let e = [...this.pages.values()].map((e) => e.button), t = e.filter(ms), n = e.find((e) => e.tabIndex === 0);
|
|
6154
6163
|
if (n && t.includes(n)) return;
|
|
6155
6164
|
let r = t.find((e) => e.getAttribute("aria-pressed") === "true") ?? t[0];
|
|
6156
6165
|
for (let t of e) t.tabIndex = t === r ? 0 : -1;
|
|
@@ -6167,10 +6176,10 @@ var Y = {
|
|
|
6167
6176
|
}
|
|
6168
6177
|
maxNow() {
|
|
6169
6178
|
let e = this.options.room?.() ?? 0;
|
|
6170
|
-
return e <= 0 ?
|
|
6179
|
+
return e <= 0 ? X.max : Math.max(X.min, Math.min(X.max, Math.floor(e * ps)));
|
|
6171
6180
|
}
|
|
6172
6181
|
clamp(e, t = this.maxNow()) {
|
|
6173
|
-
return Math.round(Math.min(t, Math.max(
|
|
6182
|
+
return Math.round(Math.min(t, Math.max(X.min, e)));
|
|
6174
6183
|
}
|
|
6175
6184
|
shownWidth() {
|
|
6176
6185
|
return this.clamp(this.width);
|
|
@@ -6201,7 +6210,7 @@ var Y = {
|
|
|
6201
6210
|
document.removeEventListener("pointermove", this.onMove), document.removeEventListener("pointerup", this.onUp), document.removeEventListener("pointercancel", this.onUp);
|
|
6202
6211
|
}
|
|
6203
6212
|
onHandleKey(e) {
|
|
6204
|
-
let [t, n] = this.element.closest("[dir]")?.getAttribute("dir") === "rtl" ? ["ArrowRight", "ArrowLeft"] : ["ArrowLeft", "ArrowRight"], r = this.shownWidth(), i = e.key === t ? r + 13 : e.key === n ? r - 13 : e.key === "Home" ?
|
|
6213
|
+
let [t, n] = this.element.closest("[dir]")?.getAttribute("dir") === "rtl" ? ["ArrowRight", "ArrowLeft"] : ["ArrowLeft", "ArrowRight"], r = this.shownWidth(), i = e.key === t ? r + 13 : e.key === n ? r - 13 : e.key === "Home" ? X.min : e.key === "End" ? X.max : null;
|
|
6205
6214
|
i !== null && (e.preventDefault(), this.setWidth(i), this.options.saveWidth?.(this.width));
|
|
6206
6215
|
}
|
|
6207
6216
|
onPanelKey(e) {
|
|
@@ -6211,12 +6220,12 @@ var Y = {
|
|
|
6211
6220
|
for (let { button: t } of this.pages.values()) t.tabIndex = t === e ? 0 : -1;
|
|
6212
6221
|
}
|
|
6213
6222
|
onRailKey(e) {
|
|
6214
|
-
let t = [...this.pages.values()].map((e) => e.button).filter(
|
|
6223
|
+
let t = [...this.pages.values()].map((e) => e.button).filter(ms), n = t.indexOf(e.target);
|
|
6215
6224
|
if (n < 0) return;
|
|
6216
6225
|
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;
|
|
6217
6226
|
r < 0 || (e.preventDefault(), t[r].focus());
|
|
6218
6227
|
}
|
|
6219
|
-
},
|
|
6228
|
+
}, gs = [
|
|
6220
6229
|
"percent",
|
|
6221
6230
|
"scale",
|
|
6222
6231
|
"pane",
|
|
@@ -6224,7 +6233,7 @@ var Y = {
|
|
|
6224
6233
|
"ratio",
|
|
6225
6234
|
"correlation",
|
|
6226
6235
|
"correlationLog"
|
|
6227
|
-
],
|
|
6236
|
+
], _s = {
|
|
6228
6237
|
percent: "compare.percent",
|
|
6229
6238
|
scale: "compare.ownScale",
|
|
6230
6239
|
pane: "compare.ownPane",
|
|
@@ -6233,24 +6242,24 @@ var Y = {
|
|
|
6233
6242
|
correlation: "compare.way.correlation",
|
|
6234
6243
|
correlationLog: "compare.way.correlationLog"
|
|
6235
6244
|
};
|
|
6236
|
-
function
|
|
6237
|
-
return
|
|
6245
|
+
function vs(e) {
|
|
6246
|
+
return gs.includes(e);
|
|
6238
6247
|
}
|
|
6239
|
-
function
|
|
6240
|
-
return
|
|
6248
|
+
function ys(e) {
|
|
6249
|
+
return gs.map((t) => ({
|
|
6241
6250
|
id: t,
|
|
6242
|
-
label: e(
|
|
6251
|
+
label: e(_s[t])
|
|
6243
6252
|
}));
|
|
6244
6253
|
}
|
|
6245
|
-
function
|
|
6254
|
+
function bs(e, t) {
|
|
6246
6255
|
let n = e.findIndex((e) => e.time >= t);
|
|
6247
6256
|
return n < 0 ? e.length : n;
|
|
6248
6257
|
}
|
|
6249
|
-
function
|
|
6258
|
+
function xs(e, t) {
|
|
6250
6259
|
let n = e[0]?.time ?? Infinity, r = t.filter((e) => e.time < n);
|
|
6251
6260
|
return r.length > 0 ? [...r, ...e] : null;
|
|
6252
6261
|
}
|
|
6253
|
-
function
|
|
6262
|
+
function Ss(e, t) {
|
|
6254
6263
|
switch (e.id) {
|
|
6255
6264
|
case "compareSymbol": return t ? "pane" : "scale";
|
|
6256
6265
|
case "compareSymbolPane": return "pane";
|
|
@@ -6260,24 +6269,24 @@ function Cs(e, t) {
|
|
|
6260
6269
|
default: return null;
|
|
6261
6270
|
}
|
|
6262
6271
|
}
|
|
6263
|
-
function
|
|
6272
|
+
function Cs(e, t, n, r) {
|
|
6264
6273
|
let i = e.map((e) => ({
|
|
6265
6274
|
id: e.id,
|
|
6266
6275
|
symbol: e.symbol,
|
|
6267
|
-
way: r(
|
|
6276
|
+
way: r(_s.percent),
|
|
6268
6277
|
color: e.color
|
|
6269
6278
|
}));
|
|
6270
6279
|
for (let e of t) {
|
|
6271
|
-
let t = e.params.symbol, a =
|
|
6280
|
+
let t = e.params.symbol, a = Ss(e, n.has(e.instanceId));
|
|
6272
6281
|
!a || typeof t != "string" || !t || i.push({
|
|
6273
6282
|
id: e.instanceId,
|
|
6274
6283
|
symbol: t,
|
|
6275
|
-
way: r(
|
|
6284
|
+
way: r(_s[a])
|
|
6276
6285
|
});
|
|
6277
6286
|
}
|
|
6278
6287
|
return i;
|
|
6279
6288
|
}
|
|
6280
|
-
var
|
|
6289
|
+
var Z = 8, ws = 4, Ts = 3, Es = "[title]:not([title=\"\"]), [data-tip]:not([data-tip=\"\"])", Ds = class {
|
|
6281
6290
|
el;
|
|
6282
6291
|
target = null;
|
|
6283
6292
|
source = null;
|
|
@@ -6288,9 +6297,9 @@ var X = 8, Ts = 4, Es = 3, Ds = "[title]:not([title=\"\"]), [data-tip]:not([data
|
|
|
6288
6297
|
observer;
|
|
6289
6298
|
constructor(e) {
|
|
6290
6299
|
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(() => {
|
|
6291
|
-
this.pressed?.hasAttribute("title") &&
|
|
6300
|
+
this.pressed?.hasAttribute("title") && Os(this.pressed);
|
|
6292
6301
|
let e = this.target;
|
|
6293
|
-
!e || this.source !== "pointer" || !e.hasAttribute("title") || (
|
|
6302
|
+
!e || this.source !== "pointer" || !e.hasAttribute("title") || (Os(e), this.isVisible() && this.show(e));
|
|
6294
6303
|
}), this.observer.observe(e, {
|
|
6295
6304
|
subtree: !0,
|
|
6296
6305
|
attributes: !0,
|
|
@@ -6298,20 +6307,20 @@ var X = 8, Ts = 4, Es = 3, Ds = "[title]:not([title=\"\"]), [data-tip]:not([data
|
|
|
6298
6307
|
});
|
|
6299
6308
|
}
|
|
6300
6309
|
destroy() {
|
|
6301
|
-
this.hide(), this.pressed &&
|
|
6310
|
+
this.hide(), this.pressed && ks(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();
|
|
6302
6311
|
}
|
|
6303
6312
|
onOver = (e) => {
|
|
6304
6313
|
if (e.pointerType === "touch") return;
|
|
6305
6314
|
let t = this.tipTarget(e.target);
|
|
6306
|
-
!t || t === this.pressed || t === this.target && this.source === "pointer" || (
|
|
6315
|
+
!t || t === this.pressed || t === this.target && this.source === "pointer" || (Os(t), this.schedule(t, "pointer", Date.now() < this.warmUntil || this.isVisible()));
|
|
6307
6316
|
};
|
|
6308
6317
|
onOut = (e) => {
|
|
6309
6318
|
let t = e.relatedTarget, n = (e) => !!e && !!t && e.contains(t);
|
|
6310
|
-
this.pressed && !n(this.pressed) && (
|
|
6319
|
+
this.pressed && !n(this.pressed) && (ks(this.pressed), this.pressed = null), this.source === "pointer" && !n(this.target) && this.hide();
|
|
6311
6320
|
};
|
|
6312
6321
|
onPress = () => {
|
|
6313
6322
|
let e = this.target, t = this.source === "pointer";
|
|
6314
|
-
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 &&
|
|
6323
|
+
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 && ks(this.pressed), this.pressed = t ? e : null;
|
|
6315
6324
|
};
|
|
6316
6325
|
onFocus = (e) => {
|
|
6317
6326
|
let t = this.tipTarget(e.target);
|
|
@@ -6323,16 +6332,16 @@ var X = 8, Ts = 4, Es = 3, Ds = "[title]:not([title=\"\"]), [data-tip]:not([data
|
|
|
6323
6332
|
this.target && t && this.target.contains(t) || this.hide();
|
|
6324
6333
|
};
|
|
6325
6334
|
hide = () => {
|
|
6326
|
-
this.clearTimer(), cancelAnimationFrame(this.watchFrame), this.isVisible() && (this.warmUntil = Date.now() + 500), this.el.classList.remove("tcw-tooltip--visible"), this.target && this.source === "pointer" &&
|
|
6335
|
+
this.clearTimer(), cancelAnimationFrame(this.watchFrame), this.isVisible() && (this.warmUntil = Date.now() + 500), this.el.classList.remove("tcw-tooltip--visible"), this.target && this.source === "pointer" && ks(this.target), this.target = null, this.source = null;
|
|
6327
6336
|
};
|
|
6328
6337
|
tipTarget(e) {
|
|
6329
6338
|
if (!(e instanceof Element)) return null;
|
|
6330
|
-
let t = e.closest(
|
|
6339
|
+
let t = e.closest(Es);
|
|
6331
6340
|
return t && t !== this.el && this.root.contains(t) ? t : null;
|
|
6332
6341
|
}
|
|
6333
6342
|
schedule(e, t, n) {
|
|
6334
6343
|
let r = this.target;
|
|
6335
|
-
if (this.clearTimer(), cancelAnimationFrame(this.watchFrame), r && r !== e && this.source === "pointer" &&
|
|
6344
|
+
if (this.clearTimer(), cancelAnimationFrame(this.watchFrame), r && r !== e && this.source === "pointer" && ks(r), this.target = e, this.source = t, n) {
|
|
6336
6345
|
this.show(e);
|
|
6337
6346
|
return;
|
|
6338
6347
|
}
|
|
@@ -6354,14 +6363,14 @@ var X = 8, Ts = 4, Es = 3, Ds = "[title]:not([title=\"\"]), [data-tip]:not([data
|
|
|
6354
6363
|
}
|
|
6355
6364
|
place(e) {
|
|
6356
6365
|
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 = Ns(e);
|
|
6357
|
-
s === "bottom" && o + n.height +
|
|
6366
|
+
s === "bottom" && o + n.height + Z + i > t.height ? s = "top" : s === "top" && o - Z - i < 0 ? s = "bottom" : s === "right" && a + n.width + Z + r > t.width && (s = "left");
|
|
6358
6367
|
let c, l;
|
|
6359
|
-
s === "top" || s === "bottom" ? (c = a + n.width / 2 - r / 2, l = s === "bottom" ? o + n.height +
|
|
6368
|
+
s === "top" || s === "bottom" ? (c = a + n.width / 2 - r / 2, l = s === "bottom" ? o + n.height + Z : o - Z - i) : (c = s === "right" ? a + n.width + Z : a - Z - r, l = o + n.height / 2 - i / 2), c = Math.max(ws, Math.min(t.width - r - ws, c)), l = Math.max(ws, Math.min(t.height - i - ws, l)), this.el.style.left = `${Math.round(c)}px`, this.el.style.top = `${Math.round(l)}px`;
|
|
6360
6369
|
let u = {
|
|
6361
|
-
top: [0,
|
|
6362
|
-
bottom: [0, -
|
|
6363
|
-
left: [
|
|
6364
|
-
right: [-
|
|
6370
|
+
top: [0, Ts],
|
|
6371
|
+
bottom: [0, -Ts],
|
|
6372
|
+
left: [Ts, 0],
|
|
6373
|
+
right: [-Ts, 0]
|
|
6365
6374
|
}[s];
|
|
6366
6375
|
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;
|
|
6367
6376
|
}
|
|
@@ -6372,11 +6381,11 @@ var X = 8, Ts = 4, Es = 3, Ds = "[title]:not([title=\"\"]), [data-tip]:not([data
|
|
|
6372
6381
|
this.showTimer !== null && (clearTimeout(this.showTimer), this.showTimer = null);
|
|
6373
6382
|
}
|
|
6374
6383
|
};
|
|
6375
|
-
function
|
|
6384
|
+
function Os(e) {
|
|
6376
6385
|
let t = e.getAttribute("title");
|
|
6377
6386
|
t !== null && (e.dataset.tip = t, e.removeAttribute("title"));
|
|
6378
6387
|
}
|
|
6379
|
-
function
|
|
6388
|
+
function ks(e) {
|
|
6380
6389
|
e.dataset.tip !== void 0 && !e.hasAttribute("title") && (e.setAttribute("title", e.dataset.tip), delete e.dataset.tip);
|
|
6381
6390
|
}
|
|
6382
6391
|
function As(e) {
|
|
@@ -7188,11 +7197,11 @@ var gc = [
|
|
|
7188
7197
|
symbols: this.host.symbolEntries(),
|
|
7189
7198
|
current: this.host.state.symbol,
|
|
7190
7199
|
search: this.host.symbolSearchFn(),
|
|
7191
|
-
ways:
|
|
7200
|
+
ways: ys(this.host.t),
|
|
7192
7201
|
way: this.compareWay,
|
|
7193
7202
|
compared: this.comparedNow(),
|
|
7194
7203
|
onAdd: (e, t) => {
|
|
7195
|
-
|
|
7204
|
+
vs(t) && (this.compareWay = t, this.addCompareSymbol(e, t));
|
|
7196
7205
|
},
|
|
7197
7206
|
onRemove: (e) => this.removeCompared(e)
|
|
7198
7207
|
}));
|
|
@@ -7200,7 +7209,7 @@ var gc = [
|
|
|
7200
7209
|
}
|
|
7201
7210
|
comparedNow() {
|
|
7202
7211
|
let e = new Set(this.host.chart.getIndicatorPanes().flatMap((e) => e.instanceIds));
|
|
7203
|
-
return
|
|
7212
|
+
return Cs(this.compares, this.host.chart.getActiveIndicators(), e, this.host.t);
|
|
7204
7213
|
}
|
|
7205
7214
|
refreshCompareDialog() {
|
|
7206
7215
|
this.host.symbolSearch?.isComparing() && this.host.symbolSearch.setCompared(this.comparedNow());
|
|
@@ -7348,7 +7357,7 @@ var gc = [
|
|
|
7348
7357
|
}
|
|
7349
7358
|
let i = r.bars[0]?.time;
|
|
7350
7359
|
if (i === void 0 || r.atStart) continue;
|
|
7351
|
-
let a =
|
|
7360
|
+
let a = bs(this.host.chart.getData(), i);
|
|
7352
7361
|
if (a !== 0) try {
|
|
7353
7362
|
if (e.fetchHistoryBefore) {
|
|
7354
7363
|
let o = await e.fetchHistoryBefore(r.symbol, n, i, a);
|
|
@@ -7371,7 +7380,7 @@ var gc = [
|
|
|
7371
7380
|
prependCompareBars(e, t, n) {
|
|
7372
7381
|
let r = this.compares.find((t) => t.id === e);
|
|
7373
7382
|
if (!r) return;
|
|
7374
|
-
let i =
|
|
7383
|
+
let i = xs(r.bars, t);
|
|
7375
7384
|
i ? this.setCompareBars(e, i, n) : this.compares = this.compares.map((t) => t.id === e ? {
|
|
7376
7385
|
...t,
|
|
7377
7386
|
atStart: !0
|
|
@@ -7433,7 +7442,7 @@ var gc = [
|
|
|
7433
7442
|
return t ? { ...t } : null;
|
|
7434
7443
|
}
|
|
7435
7444
|
createWatchlist(e, t) {
|
|
7436
|
-
let n = t.persist ?
|
|
7445
|
+
let n = t.persist ? L() : null, r = new Wr({
|
|
7437
7446
|
lists: t.lists,
|
|
7438
7447
|
activeList: t.activeList,
|
|
7439
7448
|
symbols: this.host.symbols,
|
|
@@ -7443,7 +7452,7 @@ var gc = [
|
|
|
7443
7452
|
});
|
|
7444
7453
|
this.watchlistStore = r, this.watchlistFromSymbols = !t.lists && !t.persist, this.quoteSource = t.quotes === !1 ? null : t.quotes ?? (this.host.options.adapter?.subscribeQuotes ? this.host.options.adapter : null);
|
|
7445
7454
|
let i = (e) => this.host.t(e);
|
|
7446
|
-
this.watchlist = new
|
|
7455
|
+
this.watchlist = new Mr(e, {
|
|
7447
7456
|
onSelect: (e) => {
|
|
7448
7457
|
this.host.setSymbol(e);
|
|
7449
7458
|
},
|
|
@@ -7522,7 +7531,7 @@ var gc = [
|
|
|
7522
7531
|
t.refPrice !== void 0 && this.hostWatchlistRefPrice.set(e, t.refPrice), this.watchlist?.setEntry(e, t);
|
|
7523
7532
|
}
|
|
7524
7533
|
tickWatchlist() {
|
|
7525
|
-
if (!this.watchlist || this.quotes.has(this.host.state.symbol) ||
|
|
7534
|
+
if (!this.watchlist || this.quotes.has(this.host.state.symbol) || jr()) return;
|
|
7526
7535
|
let e = this.host.chart.getData();
|
|
7527
7536
|
if (e.length === 0) return;
|
|
7528
7537
|
let t = e[e.length - 1], n = this.hostWatchlistRefPrice.get(this.host.state.symbol);
|
|
@@ -7573,7 +7582,7 @@ var gc = [
|
|
|
7573
7582
|
};
|
|
7574
7583
|
}
|
|
7575
7584
|
alertText(e) {
|
|
7576
|
-
return
|
|
7585
|
+
return ui(this.alertListItem(e, this.buildAlertSources()), this.host.t, (e) => this.host.formatAlertPrice(e), !0);
|
|
7577
7586
|
}
|
|
7578
7587
|
buildAlertSources() {
|
|
7579
7588
|
let e = [{
|
|
@@ -7842,7 +7851,7 @@ var Sc = class {
|
|
|
7842
7851
|
current: r.timezone,
|
|
7843
7852
|
options: this.timezoneChoices()
|
|
7844
7853
|
},
|
|
7845
|
-
keys: Object.fromEntries(
|
|
7854
|
+
keys: Object.fromEntries(io.filter((e) => this.host.featureState.hotkeys && this.host.featureState[e.feature]).map((e) => [e.action, e.keys]))
|
|
7846
7855
|
};
|
|
7847
7856
|
}
|
|
7848
7857
|
removableIndicators() {
|
|
@@ -7871,7 +7880,7 @@ var Sc = class {
|
|
|
7871
7880
|
});
|
|
7872
7881
|
}
|
|
7873
7882
|
runChartMenuAction(e, t) {
|
|
7874
|
-
let { price: n } = t, r = n ?? NaN, i = this.host.settingsState, a =
|
|
7883
|
+
let { price: n } = t, r = n ?? NaN, i = this.host.settingsState, a = ao(e);
|
|
7875
7884
|
if (a) {
|
|
7876
7885
|
this.host.changeSettings({ scaleMode: a });
|
|
7877
7886
|
return;
|
|
@@ -7997,7 +8006,7 @@ function Tc(e, t = "en-US") {
|
|
|
7997
8006
|
return He(e, Math.max(Cc, xt(e)), t);
|
|
7998
8007
|
}
|
|
7999
8008
|
function Ec(e, t = "en-US") {
|
|
8000
|
-
return `${
|
|
8009
|
+
return `${_o(He(Math.abs(e), wc, t), e, He(0, wc, t))}%`;
|
|
8001
8010
|
}
|
|
8002
8011
|
function Dc(e, t = "en-US", n = !0) {
|
|
8003
8012
|
return e.map((e) => ({
|
|
@@ -8155,7 +8164,7 @@ var Nc = class {
|
|
|
8155
8164
|
category: "chartType",
|
|
8156
8165
|
active: this.host.state.chartType === t.value
|
|
8157
8166
|
});
|
|
8158
|
-
let t =
|
|
8167
|
+
let t = ii();
|
|
8159
8168
|
for (let n of ee(l, this.host.t)) for (let r of n.tools) e.push({
|
|
8160
8169
|
id: r.value,
|
|
8161
8170
|
label: r.label,
|
|
@@ -8455,7 +8464,7 @@ var Nc = class {
|
|
|
8455
8464
|
constructor(e, t) {
|
|
8456
8465
|
this.session = e, this.host = t;
|
|
8457
8466
|
let { root: n, t: r } = t;
|
|
8458
|
-
this.menu = new S(n, r("toolbar.layouts")), this.prompt = new
|
|
8467
|
+
this.menu = new S(n, r("toolbar.layouts")), this.prompt = new Yo(n, r), this.dialog = new Ic(n, {
|
|
8459
8468
|
list: () => e.list(),
|
|
8460
8469
|
currentId: () => e.current()?.id ?? null,
|
|
8461
8470
|
onOpen: (e) => void this.open(e),
|
|
@@ -8601,10 +8610,10 @@ function Kc(e) {
|
|
|
8601
8610
|
symbol: n.symbol,
|
|
8602
8611
|
timeframe: n.timeframe,
|
|
8603
8612
|
chartType: n.chartType,
|
|
8604
|
-
scaleMode:
|
|
8613
|
+
scaleMode: $o.find((e) => e === n.scaleMode) ?? "regular",
|
|
8605
8614
|
indicators: Array.isArray(n.indicators) ? n.indicators : [],
|
|
8606
8615
|
drawings: Array.isArray(n.drawings) ? n.drawings : [],
|
|
8607
|
-
...zc(n.settings) ? { settings:
|
|
8616
|
+
...zc(n.settings) ? { settings: U(n.settings, ca) } : {}
|
|
8608
8617
|
};
|
|
8609
8618
|
} catch {
|
|
8610
8619
|
return null;
|
|
@@ -8653,7 +8662,7 @@ var Xc = [
|
|
|
8653
8662
|
let e = this.host.chart.getActiveIndicators().map((e) => ({
|
|
8654
8663
|
id: e.id,
|
|
8655
8664
|
params: e.params
|
|
8656
|
-
})), t = this.host.getSettings(), n =
|
|
8665
|
+
})), t = this.host.getSettings(), n = Sa(t, {
|
|
8657
8666
|
...f,
|
|
8658
8667
|
...Object.fromEntries(Xc.map((e) => [e, this.host.settingsDefaults[e]]))
|
|
8659
8668
|
});
|
|
@@ -8674,7 +8683,7 @@ var Xc = [
|
|
|
8674
8683
|
t.symbol && t.symbol !== this.host.state.symbol && await this.host.setSymbol(t.symbol), t.timeframe && t.timeframe !== this.host.state.timeframe && await this.host.setTimeframe(t.timeframe), t.chartType && this.host.applyChartType(t.chartType);
|
|
8675
8684
|
let { chartTypeOptions: n, ...r } = this.host.allowedSettings({
|
|
8676
8685
|
scaleMode: t.scaleMode,
|
|
8677
|
-
...
|
|
8686
|
+
...U(t.settings, ca)
|
|
8678
8687
|
}), i = this.host.overViewerTypeOptions(t.chartType, n);
|
|
8679
8688
|
return this.host.showLinkSettings(i ? {
|
|
8680
8689
|
...r,
|
|
@@ -8697,7 +8706,7 @@ var Xc = [
|
|
|
8697
8706
|
return this.layoutSession;
|
|
8698
8707
|
}
|
|
8699
8708
|
captureLayout() {
|
|
8700
|
-
let e = this.host.getSettings(), t = this.host.chart.saveState(), n = t ?
|
|
8709
|
+
let e = this.host.getSettings(), t = this.host.chart.saveState(), n = t ? rs(t) : null, r = n && typeof n == "object" ? ts(n) : null;
|
|
8701
8710
|
return {
|
|
8702
8711
|
v: 1,
|
|
8703
8712
|
symbol: this.host.state.symbol,
|
|
@@ -8705,13 +8714,13 @@ var Xc = [
|
|
|
8705
8714
|
scaleMode: e.scaleMode,
|
|
8706
8715
|
invertScale: e.invertScale,
|
|
8707
8716
|
chart: r,
|
|
8708
|
-
settings:
|
|
8717
|
+
settings: ba(e, sa)
|
|
8709
8718
|
};
|
|
8710
8719
|
}
|
|
8711
8720
|
async restoreLayout(e) {
|
|
8712
8721
|
if (e.symbol !== this.host.state.symbol && await this.host.setSymbol(e.symbol), e.timeframe !== this.host.state.timeframe && await this.host.setTimeframe(e.timeframe), this.host.destroyed) return;
|
|
8713
8722
|
if (e.chart) {
|
|
8714
|
-
this.host.chart.loadState(JSON.stringify(
|
|
8723
|
+
this.host.chart.loadState(JSON.stringify(ts(e.chart)));
|
|
8715
8724
|
let t = e.chart.chartType;
|
|
8716
8725
|
typeof t == "string" && (this.host.state = {
|
|
8717
8726
|
...this.host.state,
|
|
@@ -8721,7 +8730,7 @@ var Xc = [
|
|
|
8721
8730
|
let t = this.host.allowedSettings({
|
|
8722
8731
|
scaleMode: e.scaleMode,
|
|
8723
8732
|
invertScale: e.invertScale,
|
|
8724
|
-
...
|
|
8733
|
+
...U(e.settings, sa)
|
|
8725
8734
|
});
|
|
8726
8735
|
this.host.claimSettings(Object.keys(t)), this.host.applySettings(t), this.host.syncIndicatorsFromChart(), this.host.updateUI(), this.host.settings?.refresh(this.host.shownSettings(), this.host.state.chartType);
|
|
8727
8736
|
}
|
|
@@ -8729,7 +8738,7 @@ var Xc = [
|
|
|
8729
8738
|
return JSON.stringify(this.captureLayout());
|
|
8730
8739
|
}
|
|
8731
8740
|
async applyLayoutContent(e) {
|
|
8732
|
-
let t = rs(
|
|
8741
|
+
let t = ns(rs(e));
|
|
8733
8742
|
return t ? (await this.restoreLayout(t), !0) : !1;
|
|
8734
8743
|
}
|
|
8735
8744
|
setupLayouts(e) {
|
|
@@ -8754,7 +8763,7 @@ var Xc = [
|
|
|
8754
8763
|
saveKeys: () => this.host.keysShown("hotkeys.save", `${Ie}+S`),
|
|
8755
8764
|
toast: (e, t) => this.host.say(e, t),
|
|
8756
8765
|
formatTime: (e) => {
|
|
8757
|
-
let { date: t, time: n } =
|
|
8766
|
+
let { date: t, time: n } = Y(e, this.host.displayTimezone());
|
|
8758
8767
|
return `${t} ${n}`;
|
|
8759
8768
|
}
|
|
8760
8769
|
}), this.host.chart.on("stateChange", () => t.changed()), e.openLast && t.list().then(([e]) => e && !this.host.destroyed ? this.openLayout(e.id) : void 0, () => void 0);
|
|
@@ -8982,7 +8991,7 @@ var Xc = [
|
|
|
8982
8991
|
visible: e.visible
|
|
8983
8992
|
})), t = this.host.chart.getDrawings().map((e) => ({
|
|
8984
8993
|
id: e.id,
|
|
8985
|
-
label: e.name ||
|
|
8994
|
+
label: e.name || Zi(e.type, this.host.t),
|
|
8986
8995
|
visible: e.visible,
|
|
8987
8996
|
offInterval: e.visible && !this.host.chart.isDrawingShown(e.id),
|
|
8988
8997
|
locked: e.locked,
|
|
@@ -9003,7 +9012,7 @@ var Xc = [
|
|
|
9003
9012
|
"autoScale"
|
|
9004
9013
|
]), nl = 80, rl = (e) => typeof e == "object" && !!e && !Array.isArray(e);
|
|
9005
9014
|
function il(e) {
|
|
9006
|
-
return
|
|
9015
|
+
return U(e, tl);
|
|
9007
9016
|
}
|
|
9008
9017
|
function al(e) {
|
|
9009
9018
|
let { overrides: t } = Qe(e);
|
|
@@ -9058,7 +9067,7 @@ var sl = class {
|
|
|
9058
9067
|
this.storage?.setItem(this.key, JSON.stringify(this.list().filter((t) => t.name !== e)));
|
|
9059
9068
|
} catch {}
|
|
9060
9069
|
}
|
|
9061
|
-
}, cl = new Set([...
|
|
9070
|
+
}, cl = new Set([...aa, "autoScale"]), ll = class {
|
|
9062
9071
|
constructor(e) {
|
|
9063
9072
|
this.host = e;
|
|
9064
9073
|
}
|
|
@@ -9179,7 +9188,7 @@ var sl = class {
|
|
|
9179
9188
|
this.touchSettings(Object.keys(n), p), this.applySettings(n), this.host.chart.resetOverrides([...p], { layer: "user" }), this.host.chart.applyOverrides(t.style, { layer: "user" }), this.host.settings?.refresh(this.shownSettings()), this.host.say(C(this.host.t("templates.applied"), { name: e }));
|
|
9180
9189
|
}
|
|
9181
9190
|
promptSaveChartTemplate() {
|
|
9182
|
-
this.chartTemplatePrompt ??= new
|
|
9191
|
+
this.chartTemplatePrompt ??= new Yo(this.host.overlayHost(), this.host.t), this.chartTemplatePrompt.open({
|
|
9183
9192
|
title: this.host.t("settings.saveTemplateTitle"),
|
|
9184
9193
|
submitLabel: this.host.t("common.save"),
|
|
9185
9194
|
placeholder: this.host.t("settings.templatePlaceholder"),
|
|
@@ -9193,7 +9202,7 @@ var sl = class {
|
|
|
9193
9202
|
return this.syncSettingsFromChart(), JSON.parse(JSON.stringify(this.settingsState));
|
|
9194
9203
|
}
|
|
9195
9204
|
setSettings(e) {
|
|
9196
|
-
let t = this.allowedSettings(this.withoutEarlyFreeze(
|
|
9205
|
+
let t = this.allowedSettings(this.withoutEarlyFreeze(U(e)));
|
|
9197
9206
|
this.claimSettings(Object.keys(t)), this.applySettings(t);
|
|
9198
9207
|
}
|
|
9199
9208
|
withoutEarlyFreeze(e) {
|
|
@@ -9205,7 +9214,7 @@ var sl = class {
|
|
|
9205
9214
|
};
|
|
9206
9215
|
}
|
|
9207
9216
|
syncSettingsFromChart() {
|
|
9208
|
-
let e = this.host.chart, t = e.getTimeZone?.(), n = e.getMarketProfileConfig?.(), r = e.getPivotMarkersConfig?.(), i = this.allowedSettings(
|
|
9217
|
+
let e = this.host.chart, t = e.getTimeZone?.(), n = e.getMarketProfileConfig?.(), r = e.getPivotMarkersConfig?.(), i = this.allowedSettings(U({
|
|
9209
9218
|
gridVisible: e.isGridVisible?.(),
|
|
9210
9219
|
volumeVisible: e.isVolumeVisible?.(),
|
|
9211
9220
|
legendVisible: e.isLegendVisible?.(),
|
|
@@ -9237,7 +9246,7 @@ var sl = class {
|
|
|
9237
9246
|
extendedHours: e.isExtendedHoursVisible?.(),
|
|
9238
9247
|
mainSeriesVisible: e.isMainSeriesVisible?.(),
|
|
9239
9248
|
chartTypeOptions: e.getChartTypeOptions?.()
|
|
9240
|
-
})), a = i.scaleMode ? { logScale: i.scaleMode === "logarithmic" } : {}, o = i.chartTypeOptions ? { chartTypeOptions:
|
|
9249
|
+
})), a = i.scaleMode ? { logScale: i.scaleMode === "logarithmic" } : {}, o = i.chartTypeOptions ? { chartTypeOptions: fa(i.chartTypeOptions) } : {};
|
|
9241
9250
|
this.settingsState = {
|
|
9242
9251
|
...this.settingsState,
|
|
9243
9252
|
...i,
|
|
@@ -9298,7 +9307,7 @@ var sl = class {
|
|
|
9298
9307
|
...this.settingsState,
|
|
9299
9308
|
logScale: e.scaleMode === "logarithmic"
|
|
9300
9309
|
}, this.showScaleMode()), e.numberLocale !== void 0 && (this.host.chart.setNumberLocale(e.numberLocale), this.host.watching.watchlist?.setLocale(e.numberLocale || void 0)), e.timezone !== void 0 && this.host.chart.setTimeZone(g(e.timezone)), e.highLowLines !== void 0 && this.host.chart.setHighLowLines(e.highLowLines), e.extendedHours !== void 0 && this.host.chart.setExtendedHours(e.extendedHours), e.mainSeriesVisible !== void 0 && this.host.chart.setMainSeriesVisible(e.mainSeriesVisible), e.chartTypeOptions !== void 0 && this.host.chart.setChartTypeOptions({
|
|
9301
|
-
...
|
|
9310
|
+
...pa(),
|
|
9302
9311
|
...e.chartTypeOptions
|
|
9303
9312
|
}), t && !this.settingsEdit && this.publishSettings();
|
|
9304
9313
|
}
|
|
@@ -9425,7 +9434,7 @@ var fl = class {
|
|
|
9425
9434
|
if (e === this.inlineTextId && this.inlineText?.isOpen()) return !0;
|
|
9426
9435
|
let n = this.host.chart.getDrawings().find((t) => t.id === e), r = this.inlineText;
|
|
9427
9436
|
if (!n || !r || n.locked || !t && !this.host.chart.beginDrawingEdit(e)) return !1;
|
|
9428
|
-
let i =
|
|
9437
|
+
let i = G[n.type], a = n.style, o = a.text ?? "", s = (n) => {
|
|
9429
9438
|
this.inlineTextId = null, t ? n || this.host.chart.takeBackDrawing(e) : this.host.chart.endDrawingEdit(e, { cancel: !n }), this.host.docking.refreshObjects();
|
|
9430
9439
|
};
|
|
9431
9440
|
return r.open({
|
|
@@ -9447,7 +9456,7 @@ var fl = class {
|
|
|
9447
9456
|
italic: a.italic === !0,
|
|
9448
9457
|
family: this.host.chart.getFont?.()?.family ?? this.host.ui.font.family
|
|
9449
9458
|
},
|
|
9450
|
-
color: a.textColor ??
|
|
9459
|
+
color: a.textColor ?? qa[n.type] ?? a.color,
|
|
9451
9460
|
label: this.host.t("drawingSettings.text"),
|
|
9452
9461
|
onInput: (n) => t ? this.host.chart.amendNewDrawing(e, { style: { text: n } }) : this.host.chart.updateDrawing(e, { style: { text: n } }),
|
|
9453
9462
|
onCommit: (n) => {
|
|
@@ -9473,15 +9482,15 @@ var fl = class {
|
|
|
9473
9482
|
anchors: r.anchors.map((e) => ({ ...e })),
|
|
9474
9483
|
fill: i.fill === !0,
|
|
9475
9484
|
text: i.text === !0,
|
|
9476
|
-
textLayout:
|
|
9477
|
-
textColor:
|
|
9478
|
-
textPlace:
|
|
9485
|
+
textLayout: G[r.type],
|
|
9486
|
+
textColor: qa[r.type],
|
|
9487
|
+
textPlace: Ka.has(r.type),
|
|
9479
9488
|
coordinates: i.anchoring !== "screen",
|
|
9480
9489
|
intervals: r.intervals ?? null
|
|
9481
9490
|
}, { tab: n.tab }), n.justDrawn && e.isOpen() && (this.justDrawnText = t));
|
|
9482
9491
|
}
|
|
9483
9492
|
promptSaveDrawingTemplate(e, t) {
|
|
9484
|
-
this.drawingTemplatePrompt ??= new
|
|
9493
|
+
this.drawingTemplatePrompt ??= new Yo(this.host.root, this.host.t), this.drawingTemplatePrompt.open({
|
|
9485
9494
|
title: this.host.t("drawingSettings.saveTemplateTitle"),
|
|
9486
9495
|
submitLabel: this.host.t("common.save"),
|
|
9487
9496
|
placeholder: this.host.drawingToolName(t.type),
|
|
@@ -9698,7 +9707,7 @@ var Pl = class {
|
|
|
9698
9707
|
uiVariables = !1;
|
|
9699
9708
|
chartFontBase = null;
|
|
9700
9709
|
scaleObserver = null;
|
|
9701
|
-
templates = new
|
|
9710
|
+
templates = new Qo();
|
|
9702
9711
|
templatePrompt = null;
|
|
9703
9712
|
markerTip = null;
|
|
9704
9713
|
dataWindow = null;
|
|
@@ -9707,15 +9716,15 @@ var Pl = class {
|
|
|
9707
9716
|
lastHoverPrevClose = null;
|
|
9708
9717
|
legendHoverIndex = null;
|
|
9709
9718
|
pointerOnChart = !1;
|
|
9710
|
-
favoritesStore = new
|
|
9711
|
-
indicatorFavorites = new
|
|
9712
|
-
indicatorDefaults = new
|
|
9713
|
-
timeframeFavorites = new
|
|
9714
|
-
customTimeframes = new
|
|
9719
|
+
favoritesStore = new as();
|
|
9720
|
+
indicatorFavorites = new as("tcw:indicator-favorites");
|
|
9721
|
+
indicatorDefaults = new na();
|
|
9722
|
+
timeframeFavorites = new as("tcw:tf-favorites");
|
|
9723
|
+
customTimeframes = new as("tcw:tf-custom");
|
|
9715
9724
|
timeframes = [];
|
|
9716
9725
|
sessionRefPrice = null;
|
|
9717
9726
|
symbolInfoPanel = null;
|
|
9718
|
-
news = new
|
|
9727
|
+
news = new Zr();
|
|
9719
9728
|
marketTimer = null;
|
|
9720
9729
|
clockTimer = null;
|
|
9721
9730
|
onPageShown = null;
|
|
@@ -9778,8 +9787,8 @@ var Pl = class {
|
|
|
9778
9787
|
let t = e.persistLayouts === !0 ? {} : e.persistLayouts;
|
|
9779
9788
|
this.layouts.layoutKeyPrefix = t.keyPrefix ?? "tcw:layout:", this.layouts.layoutDebounceMs = t.debounceMs ?? 1500;
|
|
9780
9789
|
}
|
|
9781
|
-
let r =
|
|
9782
|
-
r && (this.chartSettings.settingsStore = new
|
|
9790
|
+
let r = Ca(e.persistSettings);
|
|
9791
|
+
r && (this.chartSettings.settingsStore = new Ta(r));
|
|
9783
9792
|
let i = this.resolveIsDark(e.theme), a = this.resolveTheme(e.theme);
|
|
9784
9793
|
this.themeOf = {
|
|
9785
9794
|
...this.themeOf,
|
|
@@ -9846,7 +9855,7 @@ var Pl = class {
|
|
|
9846
9855
|
buildRoot(e, t, n, r) {
|
|
9847
9856
|
qt(), this.root = document.createElement("div"), this.root.className = "tcw-root";
|
|
9848
9857
|
let i = t.dir === "ltr" || t.dir === "rtl" ? t.dir : Ul(t.locale) ? "rtl" : "ltr";
|
|
9849
|
-
this.root.dir = i, this.portal.dir = i, e.appendChild(this.root), this.tooltip = new
|
|
9858
|
+
this.root.dir = i, this.portal.dir = i, e.appendChild(this.root), this.tooltip = new Ds(this.root), this.portal.className = "tcw-root tcw-portal", this.look = Bn({
|
|
9850
9859
|
dark: n,
|
|
9851
9860
|
theme: r
|
|
9852
9861
|
});
|
|
@@ -9854,9 +9863,9 @@ var Pl = class {
|
|
|
9854
9863
|
this.scope.run(() => Vn(() => {
|
|
9855
9864
|
let { dark: e, theme: t } = this.look.get();
|
|
9856
9865
|
this.root.dataset.tcwTheme = this.portal.dataset.tcwTheme = e ? "dark" : "light", a && (this.keepingLook(() => this.chart.setTheme(t)), this.paintWatermark());
|
|
9857
|
-
})), a = !0, this.stopKeyboardInset =
|
|
9866
|
+
})), a = !0, this.stopKeyboardInset = os([this.root, this.portal]), this.stopNarrow = ss(this.root, (e) => {
|
|
9858
9867
|
this.toolbar?.fit(), e || this.sidebar?.closeOverlay(), this.docking.syncRail();
|
|
9859
|
-
}), this.ui =
|
|
9868
|
+
}), this.ui = H(t.ui), this.uiVariables = t.ui !== void 0, this.uiScale = this.scaleNow(), this.applyLookTokens(), typeof ResizeObserver < "u" && (this.scaleObserver = new ResizeObserver(() => this.fitScale()), this.scaleObserver.observe(this.root)), this.markSwitchedOff(), this.stopFormControls = Bt([this.root, this.portal], {
|
|
9860
9869
|
layer: this.overlayHost,
|
|
9861
9870
|
labels: () => ({
|
|
9862
9871
|
prevMonth: this.t("calendar.prevMonth"),
|
|
@@ -9909,7 +9918,7 @@ var Pl = class {
|
|
|
9909
9918
|
n.className = "tcw-body", e.drawingFavorites && this.favoritesStore.seedDefaults(e.drawingFavorites), this.sidebar = new nr(n, {
|
|
9910
9919
|
drawingToolGroups: ee(l, this.t),
|
|
9911
9920
|
favorites: this.favoritesStore.list(),
|
|
9912
|
-
shortcuts:
|
|
9921
|
+
shortcuts: ii()
|
|
9913
9922
|
}, {
|
|
9914
9923
|
onDrawingTool: (e) => this.handleDrawingTool(e),
|
|
9915
9924
|
onCancelDrawing: () => this.handleCancelDrawing(),
|
|
@@ -9929,7 +9938,7 @@ var Pl = class {
|
|
|
9929
9938
|
}, this.t), this.chartContainer = document.createElement("div"), this.chartContainer.className = "tcw-chart-container", this.chartContainer.dir = "ltr", n.appendChild(this.chartContainer), this.loading = new nc(this.chartContainer, this.t("status.loading")), this.historyPill = new ic(this.chartContainer, {
|
|
9930
9939
|
loading: this.t("history.loading"),
|
|
9931
9940
|
failed: this.t("history.failed")
|
|
9932
|
-
}), this.docking.dock = new
|
|
9941
|
+
}), this.docking.dock = new hs(n, {
|
|
9933
9942
|
labels: {
|
|
9934
9943
|
rail: this.t("dock.rail"),
|
|
9935
9944
|
resize: this.t("dock.resize")
|
|
@@ -9968,7 +9977,7 @@ var Pl = class {
|
|
|
9968
9977
|
this.chart.on("visibleRangeChange", (e) => {
|
|
9969
9978
|
let { from: t, to: n } = e.payload;
|
|
9970
9979
|
Number.isFinite(t) && Number.isFinite(n) && (this.visibleBarCount = Math.max(1, n - t));
|
|
9971
|
-
}), this.chartNav = new
|
|
9980
|
+
}), this.chartNav = new li(this.chartContainer, {
|
|
9972
9981
|
zoomIn: () => this.chart.zoomIn(),
|
|
9973
9982
|
zoomOut: () => this.chart.zoomOut(),
|
|
9974
9983
|
scroll: (e) => this.chart.scrollBars(e * Math.max(1, Math.round(this.visibleBarCount / 10))),
|
|
@@ -9979,13 +9988,13 @@ var Pl = class {
|
|
|
9979
9988
|
this.historyPill.update(t), t.state === "loaded" && this.comparing.extendPercentCompares();
|
|
9980
9989
|
}), this.chart.on("symbolInfoChange", () => {
|
|
9981
9990
|
this.refreshSymbolTitle(), this.refreshMarket(), this.rebuildForZone(), this.refreshPriceTexts();
|
|
9982
|
-
}), this.chart.on("marketChange", () => this.rebuildForZone()), this.refreshSymbolTitle(), this.symbolInfoPanel = new
|
|
9991
|
+
}), this.chart.on("marketChange", () => this.rebuildForZone()), this.refreshSymbolTitle(), this.symbolInfoPanel = new Gr(this.root, this.t, {
|
|
9983
9992
|
onClose: () => this.docking.closePanelByHand("symbolInfo"),
|
|
9984
9993
|
onToggle: (e) => {
|
|
9985
9994
|
this.markOpen("symbolInfo", e), e && (this.refreshSymbolInfo(), this.loadNews());
|
|
9986
9995
|
}
|
|
9987
9996
|
}), this.marketTimer = setInterval(() => this.refreshMarket(), 3e4), this.onPageShown = () => {
|
|
9988
|
-
|
|
9997
|
+
jr() || this.refreshMarket();
|
|
9989
9998
|
}, document.addEventListener("visibilitychange", this.onPageShown), this.dragDrop = new o(this.chartContainer, {
|
|
9990
9999
|
onData: (e, t, n) => {
|
|
9991
10000
|
this.setData(e);
|
|
@@ -10037,8 +10046,8 @@ var Pl = class {
|
|
|
10037
10046
|
onAuto: () => this.chartSettings.changeSettings({ autoScale: !this.chart.isAutoScale() })
|
|
10038
10047
|
}
|
|
10039
10048
|
}), this.clockTimer = setInterval(() => {
|
|
10040
|
-
!
|
|
10041
|
-
}, Al), this.chart.on("priceRangeChange", () => this.chartSettings.refreshScaleSwitches()), this.chartSettings.refreshScaleSwitches(), this.goToDatePart = this.lazyPart(
|
|
10049
|
+
!jr() && this.featureState.statusBar && this.featureState["statusBar.clock"] && this.statusBar?.tick();
|
|
10050
|
+
}, Al), this.chart.on("priceRangeChange", () => this.chartSettings.refreshScaleSwitches()), this.chartSettings.refreshScaleSwitches(), this.goToDatePart = this.lazyPart(J.goToDate, ({ WidgetGoToDate: e }) => new e(this.overlayHost, () => ({
|
|
10042
10051
|
title: this.t("goTo.title"),
|
|
10043
10052
|
date: this.t("range.date"),
|
|
10044
10053
|
range: this.t("goTo.range"),
|
|
@@ -10056,7 +10065,7 @@ var Pl = class {
|
|
|
10056
10065
|
}), () => this.intlLocale(), (e) => this.goTo(e)));
|
|
10057
10066
|
}
|
|
10058
10067
|
buildDialogs(e) {
|
|
10059
|
-
this.settingsPart = this.lazyPart(
|
|
10068
|
+
this.settingsPart = this.lazyPart(J.settings, ({ WidgetSettings: t }) => new t({
|
|
10060
10069
|
onChange: (e) => this.chartSettings.changeFromDialog(e),
|
|
10061
10070
|
onReset: () => this.chartSettings.resetSettings(),
|
|
10062
10071
|
onClose: () => this.chartSettings.endSettingsEdit(!0),
|
|
@@ -10076,12 +10085,12 @@ var Pl = class {
|
|
|
10076
10085
|
volume: e.volume,
|
|
10077
10086
|
trading: e.trading !== !1,
|
|
10078
10087
|
exchangeZone: () => this.menus.exchangeChoice()?.zone
|
|
10079
|
-
}, this.overlayHost)), this.symbolSearchPart = this.lazyPart(
|
|
10088
|
+
}, this.overlayHost)), this.symbolSearchPart = this.lazyPart(J.symbolSearch, ({ WidgetSymbolSearch: e }) => new e({
|
|
10080
10089
|
onPick: (e) => {
|
|
10081
10090
|
this.setSymbol(e);
|
|
10082
10091
|
},
|
|
10083
10092
|
onClose: () => {}
|
|
10084
|
-
}, this.overlayHost, this.t)), this.hotkeySheetPart = this.lazyPart(
|
|
10093
|
+
}, this.overlayHost, this.t)), this.hotkeySheetPart = this.lazyPart(J.hotkeySheet, ({ WidgetHotkeySheet: e }) => new e({ onClose: () => {} }, this.t, this.overlayHost)), this.scope.run(() => this.chartSettings.followSettings());
|
|
10085
10094
|
}
|
|
10086
10095
|
followChart() {
|
|
10087
10096
|
this.chart.on("drawingToolChange", (e) => {
|
|
@@ -10153,7 +10162,7 @@ var Pl = class {
|
|
|
10153
10162
|
]) this.chart.on(e, () => this.legend.scheduleLegend());
|
|
10154
10163
|
this.chart.on("chartTypeChange", () => {
|
|
10155
10164
|
this.comparing.compareScaleHeld && this.comparing.showHeldScale(), this.legend.scheduleLegend();
|
|
10156
|
-
}), this.replay = new
|
|
10165
|
+
}), this.replay = new kr(this.replayHost()), this.replay.attach();
|
|
10157
10166
|
for (let e of [
|
|
10158
10167
|
"resize",
|
|
10159
10168
|
"dataUpdate",
|
|
@@ -10174,17 +10183,17 @@ var Pl = class {
|
|
|
10174
10183
|
});
|
|
10175
10184
|
}
|
|
10176
10185
|
wireDrawingEditing() {
|
|
10177
|
-
let e = new
|
|
10186
|
+
let e = new Aa(), t = new ja();
|
|
10178
10187
|
for (let [e, n] of Object.entries(t.all())) this.chart.setDrawingToolDefaults(e, n ?? null);
|
|
10179
|
-
this.drawingSettingsPart = this.lazyPart(
|
|
10188
|
+
this.drawingSettingsPart = this.lazyPart(J.drawingSettings, ({ WidgetDrawingSettings: n }) => new n(this.root, {
|
|
10180
10189
|
onBegin: (e) => this.chart.beginDrawingEdit(e),
|
|
10181
10190
|
onChange: (e, t) => this.chart.updateDrawing(e, t),
|
|
10182
10191
|
onEnd: (e, t) => {
|
|
10183
10192
|
this.chart.endDrawingEdit(e, { cancel: t }), t && e === this.drawingEdit.justDrawnText && this.chart.takeBackDrawing(e), this.drawingEdit.justDrawnText = null, this.docking.refreshObjects();
|
|
10184
10193
|
},
|
|
10185
|
-
toWallTime: (e) =>
|
|
10194
|
+
toWallTime: (e) => Y(e * T(this.chart.getData()), this.displayTimezone()),
|
|
10186
10195
|
fromWallTime: (e, t) => {
|
|
10187
|
-
let n =
|
|
10196
|
+
let n = fs(e, t, this.displayTimezone());
|
|
10188
10197
|
return n === null ? null : n / T(this.chart.getData());
|
|
10189
10198
|
},
|
|
10190
10199
|
roundPrice: (e) => this.chart.roundPrice(e),
|
|
@@ -10197,15 +10206,15 @@ var Pl = class {
|
|
|
10197
10206
|
save: (t) => this.drawingEdit.promptSaveDrawingTemplate(e, t),
|
|
10198
10207
|
remove: (t, n) => e.remove(t, n)
|
|
10199
10208
|
}
|
|
10200
|
-
}, this.t)), this.drawingEdit.inlineText = new
|
|
10209
|
+
}, this.t)), this.drawingEdit.inlineText = new no(this.overlayHost), this.chart.on("drawingDoubleClick", (e) => {
|
|
10201
10210
|
let t = e.payload.id, n = this.chart.getDrawings().find((e) => e.id === t)?.type;
|
|
10202
|
-
n &&
|
|
10211
|
+
n && G[n] && this.drawingEdit.editTextInPlace(t, !1) || this.drawingEdit.openDrawingSettings(t, n && G[n] ? { tab: "text" } : {});
|
|
10203
10212
|
}), this.chart.on("drawingRemove", (e) => {
|
|
10204
10213
|
let t = e.payload.id;
|
|
10205
10214
|
t === this.drawingEdit.inlineTextId && (this.drawingEdit.inlineText?.close(), this.drawingEdit.inlineTextNew || this.chart.endDrawingEdit(t), this.drawingEdit.inlineTextId = null);
|
|
10206
10215
|
}), this.chart.on("drawingCreate", (e) => {
|
|
10207
10216
|
let { id: t, type: n, drawn: r } = e.payload;
|
|
10208
|
-
if (!r || !
|
|
10217
|
+
if (!r || !G[n]) return;
|
|
10209
10218
|
this.drawingEdit.cancelTextPrompt?.();
|
|
10210
10219
|
let i = 0, a = () => {
|
|
10211
10220
|
window.removeEventListener("pointerup", s), window.removeEventListener("pointercancel", s), clearTimeout(i), this.drawingEdit.cancelTextPrompt = null;
|
|
@@ -10216,7 +10225,7 @@ var Pl = class {
|
|
|
10216
10225
|
}));
|
|
10217
10226
|
}, s = () => setTimeout(o, 0);
|
|
10218
10227
|
window.addEventListener("pointerup", s), window.addEventListener("pointercancel", s), i = window.setTimeout(o, hl), this.drawingEdit.cancelTextPrompt = a;
|
|
10219
|
-
}), this.drawingStyle = new
|
|
10228
|
+
}), this.drawingStyle = new Fa(this.root, {
|
|
10220
10229
|
onStyleChange: (e) => {
|
|
10221
10230
|
this.chart.setDrawingStyle(e), this.chart.setSelectedDrawingStyle(e);
|
|
10222
10231
|
},
|
|
@@ -10227,10 +10236,10 @@ var Pl = class {
|
|
|
10227
10236
|
this.menus.drawingMenu = new S(this.root, this.t("drawingMenu.label")), this.chart.on("drawingContextMenu", (e) => {
|
|
10228
10237
|
let { id: t, x: n, y: r } = e.payload;
|
|
10229
10238
|
this.menus.openDrawingMenu(t, n, r);
|
|
10230
|
-
}), this.drawingEdit.selectionToolbar = new
|
|
10239
|
+
}), this.drawingEdit.selectionToolbar = new Wa(this.root, {
|
|
10231
10240
|
onStyle: (e) => {
|
|
10232
10241
|
for (let t of this.chart.getSelectedDrawingIds()) {
|
|
10233
|
-
let n = this.chart.getDrawings().find((e) => e.id === t)?.type, r = n ?
|
|
10242
|
+
let n = this.chart.getDrawings().find((e) => e.id === t)?.type, r = n ? G[n] : void 0, i = e.fillColor !== void 0 && r && !r.box ? {
|
|
10234
10243
|
...e,
|
|
10235
10244
|
textBackground: !0
|
|
10236
10245
|
} : e;
|
|
@@ -10293,19 +10302,19 @@ var Pl = class {
|
|
|
10293
10302
|
...this.menus.chartMenuContext(s),
|
|
10294
10303
|
...o ? { pane: this.chart.getPaneScale(o) } : {}
|
|
10295
10304
|
};
|
|
10296
|
-
this.menus.menuPane = o ?? null, this.menus.openChartMenu(_(
|
|
10305
|
+
this.menus.menuPane = o ?? null, this.menus.openChartMenu(_(ho(t, c, this.t), de, this.featureState), n, r, {
|
|
10297
10306
|
area: t,
|
|
10298
10307
|
price: s,
|
|
10299
10308
|
time: a
|
|
10300
10309
|
});
|
|
10301
10310
|
}), this.chart.on("priceAxisAdd", (e) => {
|
|
10302
10311
|
if (!this.featureState["menu.priceAxisAdd"]) return;
|
|
10303
|
-
let { price: t, x: n, y: r } = e.payload, i = this.chart.roundPrice(t), a = _(
|
|
10312
|
+
let { price: t, x: n, y: r } = e.payload, i = this.chart.roundPrice(t), a = _(co(this.menus.chartMenuContext(i), this.t), de, this.featureState);
|
|
10304
10313
|
this.menus.openChartMenu(a, n, r, {
|
|
10305
10314
|
area: "priceAxisAdd",
|
|
10306
10315
|
price: i
|
|
10307
10316
|
});
|
|
10308
|
-
}), this.chart.on("signalMarkerHover", (e) => this.showMarkerTip(e.payload)), this.intervals.intervalInput = new
|
|
10317
|
+
}), this.chart.on("signalMarkerHover", (e) => this.showMarkerTip(e.payload)), this.intervals.intervalInput = new Zo(this.chartContainer, {
|
|
10309
10318
|
title: this.t("interval.title"),
|
|
10310
10319
|
hint: this.t("interval.hint"),
|
|
10311
10320
|
invalid: this.t("interval.invalid")
|
|
@@ -10313,7 +10322,7 @@ var Pl = class {
|
|
|
10313
10322
|
}
|
|
10314
10323
|
buildTrading(e, t) {
|
|
10315
10324
|
if (e.layouts !== !1 && this.layouts.setupLayouts(e.layouts === !0 || e.layouts === void 0 ? {} : e.layouts), e.trading !== !1) {
|
|
10316
|
-
this.trading.orderTicket = new
|
|
10325
|
+
this.trading.orderTicket = new Wo(this.root, {
|
|
10317
10326
|
onSubmit: (e) => {
|
|
10318
10327
|
this.chart.placeOrderIntent(e), this.say(C(this.t("ticket.sent"), {
|
|
10319
10328
|
side: this.t(e.side === "buy" ? "ticket.buy" : "ticket.sell"),
|
|
@@ -10324,14 +10333,14 @@ var Pl = class {
|
|
|
10324
10333
|
formatPrice: (e) => this.formatAlertPrice(e),
|
|
10325
10334
|
formatAmount: (e) => this.formatMoney(e),
|
|
10326
10335
|
formatNumber: (e, t) => this.formatNumber(e, t)
|
|
10327
|
-
}, this.t), this.trading.accountPanel = new
|
|
10336
|
+
}, this.t), this.trading.accountPanel = new Ao(t, {
|
|
10328
10337
|
onClosePosition: (e) => this.chart.closePositionIntent(e),
|
|
10329
10338
|
onReversePosition: (e) => this.chart.reversePositionIntent(e),
|
|
10330
10339
|
onCancelOrder: (e) => this.chart.cancelOrderIntent(e),
|
|
10331
10340
|
onNewOrder: () => this.trading.openOrderTicket(),
|
|
10332
10341
|
formatPrice: (e) => this.formatAlertPrice(e),
|
|
10333
10342
|
formatTime: (e) => {
|
|
10334
|
-
let { date: t, time: n } =
|
|
10343
|
+
let { date: t, time: n } = Y(e, this.displayTimezone());
|
|
10335
10344
|
return `${t} ${n}`;
|
|
10336
10345
|
},
|
|
10337
10346
|
formatAmount: (e) => this.formatMoney(e),
|
|
@@ -10380,7 +10389,7 @@ var Pl = class {
|
|
|
10380
10389
|
}
|
|
10381
10390
|
}
|
|
10382
10391
|
buildAlerts(e) {
|
|
10383
|
-
this.alerting.alertsPanel = new
|
|
10392
|
+
this.alerting.alertsPanel = new vi(this.root, {
|
|
10384
10393
|
onClose: () => this.docking.closePanelByHand("alerts"),
|
|
10385
10394
|
onAdd: ({ price: e, condition: t, message: n, channel: r, label: i, options: a }) => {
|
|
10386
10395
|
try {
|
|
@@ -10390,7 +10399,7 @@ var Pl = class {
|
|
|
10390
10399
|
}
|
|
10391
10400
|
},
|
|
10392
10401
|
formatTime: (e) => {
|
|
10393
|
-
let { date: t, time: n } =
|
|
10402
|
+
let { date: t, time: n } = Y(e, this.displayTimezone());
|
|
10394
10403
|
return `${t} ${n}`;
|
|
10395
10404
|
},
|
|
10396
10405
|
onRemove: (e) => this.chart.removeAlert(e),
|
|
@@ -10405,7 +10414,7 @@ var Pl = class {
|
|
|
10405
10414
|
if (this.alerting.refreshAlerts(), !this.featureState.alerts) return;
|
|
10406
10415
|
let n = `${this.alerting.alertText(t)}${t.message ? ` — ${t.message}` : ""}`;
|
|
10407
10416
|
this.say(C(this.t("alerts.fired"), { text: n }), "info", "bell"), this.alerting.alertNotifier?.notify(n);
|
|
10408
|
-
}), this.indicatorPickerPart = this.lazyPart(
|
|
10417
|
+
}), this.indicatorPickerPart = this.lazyPart(J.indicatorPicker, ({ WidgetIndicatorPicker: e }) => new e(this.overlayHost, {
|
|
10409
10418
|
onAdd: (e) => this.handleAddIndicator(e),
|
|
10410
10419
|
onFavorite: (e, t) => t ? this.indicatorFavorites.add(e) : this.indicatorFavorites.remove(e),
|
|
10411
10420
|
templates: {
|
|
@@ -10419,7 +10428,7 @@ var Pl = class {
|
|
|
10419
10428
|
}, this.t));
|
|
10420
10429
|
}
|
|
10421
10430
|
buildPanels(e) {
|
|
10422
|
-
this.indicatorSettingsPart = this.lazyPart(
|
|
10431
|
+
this.indicatorSettingsPart = this.lazyPart(J.indicatorSettings, ({ WidgetIndicatorSettings: e }) => new e(this.root, {
|
|
10423
10432
|
onApply: (e, t) => {
|
|
10424
10433
|
this.chart.updateIndicator(e, t), this.syncIndicatorsFromChart();
|
|
10425
10434
|
},
|
|
@@ -10429,7 +10438,7 @@ var Pl = class {
|
|
|
10429
10438
|
onIntervals: (e, t) => this.chart.setIndicatorIntervals(e, t),
|
|
10430
10439
|
onSaveDefault: (e, t) => this.saveIndicatorDefault(e, t),
|
|
10431
10440
|
onClose: () => this.chart.endIndicatorEdit()
|
|
10432
|
-
}, this.t)), this.objectTree = new
|
|
10441
|
+
}, this.t)), this.objectTree = new Ji(this.root, {
|
|
10433
10442
|
onClose: () => this.docking.closePanelByHand("objectTree"),
|
|
10434
10443
|
onRemoveIndicator: (e) => this.handleRemoveIndicator(e),
|
|
10435
10444
|
onConfigureIndicator: (e) => this.openIndicatorSettings(e),
|
|
@@ -10487,7 +10496,7 @@ var Pl = class {
|
|
|
10487
10496
|
this.docking.setupDock();
|
|
10488
10497
|
}
|
|
10489
10498
|
buildCommandPalette() {
|
|
10490
|
-
this.commandPalettePart = this.lazyPart(
|
|
10499
|
+
this.commandPalettePart = this.lazyPart(J.commandPalette, ({ WidgetCommandPalette: e }) => new e({
|
|
10491
10500
|
onIndicator: (e) => this.handleAddIndicator(e),
|
|
10492
10501
|
onChartType: (e) => this.handleChartType(e),
|
|
10493
10502
|
onDrawingTool: (e) => this.handleDrawingTool(e),
|
|
@@ -10509,16 +10518,16 @@ var Pl = class {
|
|
|
10509
10518
|
} else if ((e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey && (e.key === "s" || e.key === "S")) {
|
|
10510
10519
|
if (!this.layouts.layoutSession || !n("hotkeys.save") || !this.featureState.layouts || F() || !P(this.root, !0)) return;
|
|
10511
10520
|
e.preventDefault(), this.layouts.saveLayout();
|
|
10512
|
-
} else if (e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey &&
|
|
10513
|
-
if (e.defaultPrevented || F() || !t ||
|
|
10514
|
-
e.preventDefault(), this.handleDrawingTool(
|
|
10521
|
+
} else if (e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey && ri[e.code]) {
|
|
10522
|
+
if (e.defaultPrevented || F() || !t || I() || !n("hotkeys.tools")) return;
|
|
10523
|
+
e.preventDefault(), this.handleDrawingTool(ri[e.code]);
|
|
10515
10524
|
} else if (/^[0-9]$/.test(e.key) && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
10516
|
-
if (e.defaultPrevented || !this.intervals.intervalInput || !n("intervalTyping") || F() ||
|
|
10525
|
+
if (e.defaultPrevented || !this.intervals.intervalInput || !n("intervalTyping") || F() || I() || !P(this.root, !0)) return;
|
|
10517
10526
|
let t = document.activeElement;
|
|
10518
10527
|
if (t && t !== document.body && !this.root.contains(t)) return;
|
|
10519
10528
|
e.preventDefault(), this.intervals.intervalInput.open(e.key);
|
|
10520
10529
|
} else if (kl(e) !== null) {
|
|
10521
|
-
if (e.defaultPrevented || !n("symbolTyping") || !this.featureState.symbolSearch || F() ||
|
|
10530
|
+
if (e.defaultPrevented || !n("symbolTyping") || !this.featureState.symbolSearch || F() || I() || !P(this.root, !0)) return;
|
|
10522
10531
|
let t = document.activeElement;
|
|
10523
10532
|
if (t && t !== document.body && !this.root.contains(t)) return;
|
|
10524
10533
|
e.preventDefault(), this.openSymbolSearch(kl(e));
|
|
@@ -10550,7 +10559,7 @@ var Pl = class {
|
|
|
10550
10559
|
}
|
|
10551
10560
|
preloadDialogsWhenIdle() {
|
|
10552
10561
|
let e = () => {
|
|
10553
|
-
this.destroyed ||
|
|
10562
|
+
this.destroyed || ls();
|
|
10554
10563
|
}, t = globalThis;
|
|
10555
10564
|
if (t.requestIdleCallback && t.cancelIdleCallback) {
|
|
10556
10565
|
let n = t.requestIdleCallback(e, { timeout: Cl }), r = t.cancelIdleCallback;
|
|
@@ -10622,7 +10631,7 @@ var Pl = class {
|
|
|
10622
10631
|
n && !this.featureState.symbolInfo || (n ? this.docking.dock?.open("symbolInfo") : this.docking.dock?.closePage("symbolInfo"));
|
|
10623
10632
|
}
|
|
10624
10633
|
refreshMarket() {
|
|
10625
|
-
if (
|
|
10634
|
+
if (jr()) return;
|
|
10626
10635
|
let e = qe(this.chart.getSymbolInfo(), Date.now()), t = e.state === "open";
|
|
10627
10636
|
this.statusBar?.setMarket(e.state, this.t(t ? "symbolInfo.open" : "symbolInfo.closed"), this.t(t ? "statusBar.marketOpen" : "statusBar.marketClosed")), this.refreshSymbolInfo();
|
|
10628
10637
|
}
|
|
@@ -10632,7 +10641,7 @@ var Pl = class {
|
|
|
10632
10641
|
}
|
|
10633
10642
|
symbolInfoView() {
|
|
10634
10643
|
let e = this.state.symbol;
|
|
10635
|
-
return
|
|
10644
|
+
return Xr({
|
|
10636
10645
|
symbol: e,
|
|
10637
10646
|
info: this.chart.getSymbolInfo(),
|
|
10638
10647
|
names: this.displayInfo(),
|
|
@@ -10702,18 +10711,18 @@ var Pl = class {
|
|
|
10702
10711
|
return this.chart;
|
|
10703
10712
|
}
|
|
10704
10713
|
setUI(e) {
|
|
10705
|
-
this.ui =
|
|
10714
|
+
this.ui = H(e), this.uiVariables = !0, this.uiScale = this.scaleNow(), this.applyLookTokens(), this.applyChartShapes(), this.applyLegendFont(), this.applyChartLook();
|
|
10706
10715
|
}
|
|
10707
10716
|
scaleNow() {
|
|
10708
10717
|
if (this.ui.scale !== "auto" && this.ui.scale !== void 0) return this.ui.scale;
|
|
10709
10718
|
let e = this.root.clientWidth;
|
|
10710
|
-
return e > 0 ?
|
|
10719
|
+
return e > 0 ? ki(e) : 1;
|
|
10711
10720
|
}
|
|
10712
10721
|
applyLookTokens() {
|
|
10713
|
-
let e =
|
|
10722
|
+
let e = Ai(this.ui, this.uiScale);
|
|
10714
10723
|
for (let t of [this.root, this.portal]) {
|
|
10715
|
-
if (
|
|
10716
|
-
let n =
|
|
10724
|
+
if (qi(t, e, { variables: this.uiVariables }), this.uiVariables) continue;
|
|
10725
|
+
let n = Ki(e);
|
|
10717
10726
|
for (let e of _l) this.uiScale === 1 ? t.style.removeProperty(e) : t.style.setProperty(e, n[e]);
|
|
10718
10727
|
}
|
|
10719
10728
|
}
|
|
@@ -10723,18 +10732,18 @@ var Pl = class {
|
|
|
10723
10732
|
if (e !== this.uiScale) {
|
|
10724
10733
|
if (this.ui.scale === "auto") {
|
|
10725
10734
|
let t = this.root.clientWidth;
|
|
10726
|
-
if ((e > this.uiScale ?
|
|
10735
|
+
if ((e > this.uiScale ? ki(t - gl) : ki(t + gl)) === this.uiScale) return;
|
|
10727
10736
|
}
|
|
10728
10737
|
this.uiScale = e, this.applyLookTokens(), this.applyLegendFont(), this.applyChartLook(), this.toolbar?.fit();
|
|
10729
10738
|
}
|
|
10730
10739
|
}
|
|
10731
10740
|
getUI() {
|
|
10732
|
-
return
|
|
10741
|
+
return H({ ...this.ui });
|
|
10733
10742
|
}
|
|
10734
10743
|
applyLegendFont() {
|
|
10735
10744
|
this.chart.setLegend({
|
|
10736
10745
|
fontFamily: this.ui.font.mono,
|
|
10737
|
-
fontSize:
|
|
10746
|
+
fontSize: z(Math.round(this.ui.font.size * this.uiScale), -1)
|
|
10738
10747
|
});
|
|
10739
10748
|
}
|
|
10740
10749
|
applyChartLook() {
|
|
@@ -10888,7 +10897,7 @@ var Pl = class {
|
|
|
10888
10897
|
} };
|
|
10889
10898
|
}
|
|
10890
10899
|
handleHostHotkey(e) {
|
|
10891
|
-
if (this.hostHotkeys.length === 0 || !this.featureState.hotkeys || e.isComposing || e.keyCode === 229 || e.getModifierState?.("AltGraph") || e.defaultPrevented || F() || hc(e) ||
|
|
10900
|
+
if (this.hostHotkeys.length === 0 || !this.featureState.hotkeys || e.isComposing || e.keyCode === 229 || e.getModifierState?.("AltGraph") || e.defaultPrevented || F() || hc(e) || I()) return !1;
|
|
10892
10901
|
let t = this.hostHotkeys.find((t) => fc(e, t.parsed));
|
|
10893
10902
|
if (!t) return !1;
|
|
10894
10903
|
let n = !t.parsed.ctrl && !t.parsed.alt;
|
|
@@ -10897,7 +10906,7 @@ var Pl = class {
|
|
|
10897
10906
|
return n && r && r !== document.body && !this.root.contains(r) ? !1 : (e.preventDefault(), t.spec.onPress(e), !0);
|
|
10898
10907
|
}
|
|
10899
10908
|
paintWatermark() {
|
|
10900
|
-
this.chart.setWatermark(this.state.symbol.replace("USDT", " / USDT"), {
|
|
10909
|
+
this.chart.setWatermark(be(this.state.symbol).ticker.replace("USDT", " / USDT"), {
|
|
10901
10910
|
fontSize: Tl,
|
|
10902
10911
|
color: this.state.isDark ? El : Dl
|
|
10903
10912
|
});
|
|
@@ -11006,7 +11015,7 @@ var Pl = class {
|
|
|
11006
11015
|
return this.trading.toggleAccountPanel(e);
|
|
11007
11016
|
}
|
|
11008
11017
|
clockNow() {
|
|
11009
|
-
let e = Date.now(), t = this.displayTimezone(), n = (e) => String(e).padStart(2, "0"), { time: r } =
|
|
11018
|
+
let e = Date.now(), t = this.displayTimezone(), n = (e) => String(e).padStart(2, "0"), { time: r } = Y(e, t);
|
|
11010
11019
|
return {
|
|
11011
11020
|
time: `${r}:${n(new Date(e).getUTCSeconds())}`,
|
|
11012
11021
|
zone: lt(Je(t, e))
|
|
@@ -11033,10 +11042,10 @@ var Pl = class {
|
|
|
11033
11042
|
}
|
|
11034
11043
|
let t = this.chart.getData();
|
|
11035
11044
|
if (t.length === 0) return;
|
|
11036
|
-
let n = this.displayTimezone(), r = T(t), i = (e) =>
|
|
11045
|
+
let n = this.displayTimezone(), r = T(t), i = (e) => Y(e * r, n), a = t[t.length - 1].time, o = this.chart.getVisibleTimeRange() ?? {
|
|
11037
11046
|
from: t[0].time,
|
|
11038
11047
|
to: a
|
|
11039
|
-
}, s =
|
|
11048
|
+
}, s = Y(Date.now(), n).date;
|
|
11040
11049
|
e.open({
|
|
11041
11050
|
date: i(a),
|
|
11042
11051
|
range: {
|
|
@@ -11053,12 +11062,12 @@ var Pl = class {
|
|
|
11053
11062
|
if (t.length === 0) return;
|
|
11054
11063
|
let r = T(t);
|
|
11055
11064
|
if (e.kind === "date") {
|
|
11056
|
-
let i =
|
|
11065
|
+
let i = fs(e.date, e.time, n);
|
|
11057
11066
|
if (i === null) return;
|
|
11058
11067
|
this.chart.goToTime(i / r), i / r < t[0].time && this.say(this.t("range.beforeData"));
|
|
11059
11068
|
return;
|
|
11060
11069
|
}
|
|
11061
|
-
let i =
|
|
11070
|
+
let i = fs(e.from.date, e.from.time, n), a = fs(e.to.date, e.to.time, n);
|
|
11062
11071
|
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")));
|
|
11063
11072
|
}
|
|
11064
11073
|
showMarkerTip(e) {
|
|
@@ -11072,7 +11081,7 @@ var Pl = class {
|
|
|
11072
11081
|
r.textContent = t.label ? `${t.label} · ${t.source}` : t.source;
|
|
11073
11082
|
let i = document.createElement("div");
|
|
11074
11083
|
i.textContent = `${n} · ${this.formatAlertPrice(t.price)} · ${C(this.t("markers.confidence"), { pct: Math.round(t.confidence * 100) })}`;
|
|
11075
|
-
let a = document.createElement("div"), { date: o, time: s } =
|
|
11084
|
+
let a = document.createElement("div"), { date: o, time: s } = Y(t.time, this.displayTimezone());
|
|
11076
11085
|
a.textContent = `${o} ${s}`, this.markerTip.replaceChildren(r, i, a), this.markerTip.hidden = !1;
|
|
11077
11086
|
let c = this.chartContainer.getBoundingClientRect(), l = Math.min(e.x + 12, Math.max(0, c.width - this.markerTip.offsetWidth - 4)), u = Math.max(0, e.y - this.markerTip.offsetHeight - 10);
|
|
11078
11087
|
this.markerTip.style.left = `${l}px`, this.markerTip.style.top = `${u}px`;
|
|
@@ -11088,7 +11097,7 @@ var Pl = class {
|
|
|
11088
11097
|
this.say(this.t("templates.nothing"), "error");
|
|
11089
11098
|
return;
|
|
11090
11099
|
}
|
|
11091
|
-
this.templatePrompt ??= new
|
|
11100
|
+
this.templatePrompt ??= new Yo(this.root, this.t), this.templatePrompt.open({
|
|
11092
11101
|
title: this.t("templates.saveTitle"),
|
|
11093
11102
|
submitLabel: this.t("common.save"),
|
|
11094
11103
|
placeholder: this.t("templates.namePlaceholder"),
|
|
@@ -11189,7 +11198,7 @@ var Pl = class {
|
|
|
11189
11198
|
}
|
|
11190
11199
|
overViewerTypeOptions(e, t) {
|
|
11191
11200
|
let n = {
|
|
11192
|
-
...
|
|
11201
|
+
...da(e) ? { [e]: {} } : {},
|
|
11193
11202
|
...t
|
|
11194
11203
|
};
|
|
11195
11204
|
if (Object.keys(n).length !== 0) return {
|
|
@@ -11349,7 +11358,7 @@ var Pl = class {
|
|
|
11349
11358
|
}), this.updateUI();
|
|
11350
11359
|
}
|
|
11351
11360
|
lazyPart(e, t) {
|
|
11352
|
-
return new
|
|
11361
|
+
return new cs(e, t, (e) => e.destroy(), () => this.say(this.t("common.partFailed"), "error"));
|
|
11353
11362
|
}
|
|
11354
11363
|
whenLoaded(e, t, n) {
|
|
11355
11364
|
if (!e || !t()) return;
|
|
@@ -12142,7 +12151,7 @@ function Fl(e, t, n) {
|
|
|
12142
12151
|
var Il = "tcw:recentCommands", Ll = 10;
|
|
12143
12152
|
function Rl() {
|
|
12144
12153
|
try {
|
|
12145
|
-
let e = JSON.parse(
|
|
12154
|
+
let e = JSON.parse(L()?.getItem(Il) ?? "[]");
|
|
12146
12155
|
return Array.isArray(e) ? e.filter((e) => typeof e == "string").slice(0, Ll) : [];
|
|
12147
12156
|
} catch {
|
|
12148
12157
|
return [];
|
|
@@ -12150,13 +12159,13 @@ function Rl() {
|
|
|
12150
12159
|
}
|
|
12151
12160
|
function zl(e) {
|
|
12152
12161
|
try {
|
|
12153
|
-
|
|
12162
|
+
L()?.setItem(Il, JSON.stringify(e.slice(0, Ll)));
|
|
12154
12163
|
} catch {}
|
|
12155
12164
|
}
|
|
12156
12165
|
var Bl = "tcw:dockWidth";
|
|
12157
12166
|
function Vl() {
|
|
12158
12167
|
try {
|
|
12159
|
-
let e = Number(
|
|
12168
|
+
let e = Number(L()?.getItem(Bl) ?? NaN);
|
|
12160
12169
|
return Number.isFinite(e) && e > 0 ? e : null;
|
|
12161
12170
|
} catch {
|
|
12162
12171
|
return null;
|
|
@@ -12164,7 +12173,7 @@ function Vl() {
|
|
|
12164
12173
|
}
|
|
12165
12174
|
function Hl(e) {
|
|
12166
12175
|
try {
|
|
12167
|
-
|
|
12176
|
+
L()?.setItem(Bl, String(e));
|
|
12168
12177
|
} catch {}
|
|
12169
12178
|
}
|
|
12170
12179
|
function Ul(e) {
|
|
@@ -12235,7 +12244,7 @@ function Yl(e) {
|
|
|
12235
12244
|
if (typeof e != "object" || !e) return null;
|
|
12236
12245
|
let t = e;
|
|
12237
12246
|
if (t.v !== 1 || t.kind !== "grid" || !Kl(t.layout) || !Array.isArray(t.cells)) return null;
|
|
12238
|
-
let n = t.cells.map(
|
|
12247
|
+
let n = t.cells.map(ns);
|
|
12239
12248
|
if (n.some((e) => e === null)) return null;
|
|
12240
12249
|
let r = typeof t.sync == "object" && t.sync !== null ? t.sync : {}, i = { ...Wl };
|
|
12241
12250
|
for (let e of Gl) typeof r[e] == "boolean" && (i[e] = r[e]);
|
|
@@ -12281,7 +12290,7 @@ var Xl = class {
|
|
|
12281
12290
|
this.options = t, this.layout = Kl(t.layout) ? t.layout : "1x2", this.sync = {
|
|
12282
12291
|
...Wl,
|
|
12283
12292
|
...t.sync
|
|
12284
|
-
}, this.t = Me(Ne(t.widget?.locale, t.widget?.messages)), qt(), this.root = document.createElement("div"), this.root.className = "tcw-root tcw-grid", this.root.dataset.tcwTheme = t.widget?.theme === "light" ? "light" : "dark",
|
|
12293
|
+
}, this.t = Me(Ne(t.widget?.locale, t.widget?.messages)), qt(), this.root = document.createElement("div"), this.root.className = "tcw-root tcw-grid", this.root.dataset.tcwTheme = t.widget?.theme === "light" ? "light" : "dark", qi(this.root, H(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 = ss(this.root), this.applyShape();
|
|
12285
12294
|
for (let e = 0; e < this.shapeCount(); e++) this.cells.push(this.createCell(e));
|
|
12286
12295
|
this.markActive();
|
|
12287
12296
|
let n = this.cells[0]?.el.querySelector(".tcw-root")?.dataset.tcwTheme;
|
|
@@ -12335,13 +12344,13 @@ var Xl = class {
|
|
|
12335
12344
|
return { ...this.sync };
|
|
12336
12345
|
}
|
|
12337
12346
|
setUI(e) {
|
|
12338
|
-
let t =
|
|
12339
|
-
|
|
12347
|
+
let t = H(e);
|
|
12348
|
+
qi(this.root, t);
|
|
12340
12349
|
for (let e of this.cells) e.widget.setUI(t);
|
|
12341
12350
|
this.uiTheme = t;
|
|
12342
12351
|
}
|
|
12343
12352
|
getUI() {
|
|
12344
|
-
return
|
|
12353
|
+
return H(this.uiTheme ?? this.options.widget?.ui);
|
|
12345
12354
|
}
|
|
12346
12355
|
setSync(e) {
|
|
12347
12356
|
let t = this.sync;
|
|
@@ -12407,7 +12416,7 @@ var Xl = class {
|
|
|
12407
12416
|
return JSON.stringify(this.captureLayout());
|
|
12408
12417
|
}
|
|
12409
12418
|
async applyLayoutContent(e) {
|
|
12410
|
-
let t = Yl(
|
|
12419
|
+
let t = Yl(rs(e));
|
|
12411
12420
|
return t ? (await this.restoreLayout(t), !0) : !1;
|
|
12412
12421
|
}
|
|
12413
12422
|
destroy() {
|
|
@@ -12438,7 +12447,7 @@ var Xl = class {
|
|
|
12438
12447
|
...this.options.adapter && !r.adapter && !r.feed && !n.feed ? { adapter: this.options.adapter(e) } : {},
|
|
12439
12448
|
...this.uiTheme ? { ui: this.uiTheme } : {},
|
|
12440
12449
|
layouts: !1,
|
|
12441
|
-
...r.persistSettings === void 0 && n.persistSettings ? { persistSettings: { key: `${
|
|
12450
|
+
...r.persistSettings === void 0 && n.persistSettings ? { persistSettings: { key: `${Ca(n.persistSettings)}:${e}` } } : {},
|
|
12442
12451
|
features: {
|
|
12443
12452
|
dock: !1,
|
|
12444
12453
|
...n.features,
|
|
@@ -12643,7 +12652,7 @@ var Xl = class {
|
|
|
12643
12652
|
t: this.t,
|
|
12644
12653
|
toast: (e, t) => this.toast(e, t),
|
|
12645
12654
|
formatTime: (e) => {
|
|
12646
|
-
let { date: t, time: n } =
|
|
12655
|
+
let { date: t, time: n } = Y(e, null);
|
|
12647
12656
|
return `${t} ${n}`;
|
|
12648
12657
|
}
|
|
12649
12658
|
}), this.renderLayoutsButton(), e.openLast && t.list().then(([e]) => e && !this.destroyed ? this.layoutsUI?.open(e.id) : void 0, () => void 0);
|
|
@@ -12658,6 +12667,6 @@ function Zl(e, t) {
|
|
|
12658
12667
|
return n;
|
|
12659
12668
|
}
|
|
12660
12669
|
//#endregion
|
|
12661
|
-
export { ge as CHART_TYPE_ICONS, Pl as ChartWidget, Xl as ChartWidgetGrid, Wl as DEFAULT_GRID_SYNC, ve as DRAWING_TOOL_ICONS, Ae as EN_MESSAGES, $ as GRID_SHAPES, c as LayoutSession, a as MAX_LAYOUT_NAME, pe as UI_ICONS, Pe as VI_MESSAGES, le as WIDGET_FEATURES,
|
|
12670
|
+
export { ge as CHART_TYPE_ICONS, Pl as ChartWidget, Xl as ChartWidgetGrid, Wl as DEFAULT_GRID_SYNC, ve as DRAWING_TOOL_ICONS, Ae as EN_MESSAGES, $ as GRID_SHAPES, c as LayoutSession, a as MAX_LAYOUT_NAME, pe as UI_ICONS, Pe as VI_MESSAGES, le as WIDGET_FEATURES, zi as WIDGET_UI_PRESETS, qi as applyWidgetUI, s as cleanLayoutName, _e as createChartTypeIcon, b as createIcon, y as createToolIcon, je as findWidgetLocale, me as iconSvg, i as localStorageLayouts, e as memoryLayouts, Yl as readGridLayout, Hr as readWatchlists, ns as readWidgetLayout, ke as registerWidgetLocale, H as resolveWidgetUI, Ki as widgetUIVariables };
|
|
12662
12671
|
|
|
12663
12672
|
//# sourceMappingURL=index.js.map
|