@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.151 → 2.0.0-next.152

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/.storybook/vitest.setup.ts +12 -1
  2. package/bundle/openbridge-webcomponents.bundle.js +989 -319
  3. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  4. package/custom-elements.json +1514 -77
  5. package/dist/alert-severity.d.ts +12 -9
  6. package/dist/alert-severity.d.ts.map +1 -1
  7. package/dist/alert-severity.js +30 -38
  8. package/dist/alert-severity.js.map +1 -1
  9. package/dist/building-blocks/bar-horizontal/bar-horizontal.d.ts +6 -0
  10. package/dist/building-blocks/bar-horizontal/bar-horizontal.d.ts.map +1 -1
  11. package/dist/building-blocks/bar-horizontal/bar-horizontal.js +6 -1
  12. package/dist/building-blocks/bar-horizontal/bar-horizontal.js.map +1 -1
  13. package/dist/building-blocks/bar-vertical/bar-vertical.d.ts +6 -0
  14. package/dist/building-blocks/bar-vertical/bar-vertical.d.ts.map +1 -1
  15. package/dist/building-blocks/bar-vertical/bar-vertical.js +6 -1
  16. package/dist/building-blocks/bar-vertical/bar-vertical.js.map +1 -1
  17. package/dist/building-blocks/chart-line/chart-line-base.d.ts +129 -0
  18. package/dist/building-blocks/chart-line/chart-line-base.d.ts.map +1 -1
  19. package/dist/building-blocks/chart-line/chart-line-base.js +464 -79
  20. package/dist/building-blocks/chart-line/chart-line-base.js.map +1 -1
  21. package/dist/building-blocks/external-scale/external-scale.d.ts +11 -0
  22. package/dist/building-blocks/external-scale/external-scale.d.ts.map +1 -1
  23. package/dist/building-blocks/external-scale/external-scale.js +45 -12
  24. package/dist/building-blocks/external-scale/external-scale.js.map +1 -1
  25. package/dist/charthelpers/index.d.ts +1 -0
  26. package/dist/charthelpers/index.d.ts.map +1 -1
  27. package/dist/charthelpers/index.js +7 -1
  28. package/dist/charthelpers/index.js.map +1 -1
  29. package/dist/charthelpers/range-labels.d.ts +55 -0
  30. package/dist/charthelpers/range-labels.d.ts.map +1 -0
  31. package/dist/charthelpers/range-labels.js +36 -0
  32. package/dist/charthelpers/range-labels.js.map +1 -0
  33. package/dist/components/alert-button/alert-button.css.js +13 -21
  34. package/dist/components/alert-button/alert-button.css.js.map +1 -1
  35. package/dist/components/alert-button/alert-button.d.ts +9 -4
  36. package/dist/components/alert-button/alert-button.d.ts.map +1 -1
  37. package/dist/components/alert-button/alert-button.js +24 -15
  38. package/dist/components/alert-button/alert-button.js.map +1 -1
  39. package/dist/components/alert-frame/alert-frame.css.js +109 -33
  40. package/dist/components/alert-frame/alert-frame.css.js.map +1 -1
  41. package/dist/components/alert-frame/alert-frame.d.ts +34 -7
  42. package/dist/components/alert-frame/alert-frame.d.ts.map +1 -1
  43. package/dist/components/alert-frame/alert-frame.js +134 -30
  44. package/dist/components/alert-frame/alert-frame.js.map +1 -1
  45. package/dist/components/alert-icon/alert-icon.d.ts +10 -7
  46. package/dist/components/alert-icon/alert-icon.d.ts.map +1 -1
  47. package/dist/components/alert-icon/alert-icon.js +37 -60
  48. package/dist/components/alert-icon/alert-icon.js.map +1 -1
  49. package/dist/components/alert-menu-item/alert-menu-item.css.js +1 -4
  50. package/dist/components/alert-menu-item/alert-menu-item.css.js.map +1 -1
  51. package/dist/components/date-item/date-item.css.js +3 -3
  52. package/dist/components/keyboard-full/keyboard-full.css.js +4 -4
  53. package/dist/components/message-menu-item/message-menu-item.css.js +2 -6
  54. package/dist/components/message-menu-item/message-menu-item.css.js.map +1 -1
  55. package/dist/components/sequence-toolbar/sequence-toolbar.css.js +1 -2
  56. package/dist/components/sequence-toolbar/sequence-toolbar.css.js.map +1 -1
  57. package/dist/index.js +2 -1
  58. package/dist/navigation-instruments/gauge-trend/gauge-trend.d.ts +6 -0
  59. package/dist/navigation-instruments/gauge-trend/gauge-trend.d.ts.map +1 -1
  60. package/dist/navigation-instruments/gauge-trend/gauge-trend.js +8 -0
  61. package/dist/navigation-instruments/gauge-trend/gauge-trend.js.map +1 -1
  62. package/dist/navigation-instruments/instrument-field/instrument-field.css.js +2 -2
  63. package/dist/navigation-instruments/readout/readout.d.ts.map +1 -1
  64. package/dist/navigation-instruments/readout/readout.js +2 -1
  65. package/dist/navigation-instruments/readout/readout.js.map +1 -1
  66. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
  67. package/dist/navigation-instruments/readout-list-item/readout-list-item.js +2 -1
  68. package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
  69. package/dist/openbridge.css +19 -4
  70. package/dist/palettes/blinking.d.ts +14 -4
  71. package/dist/palettes/blinking.d.ts.map +1 -1
  72. package/dist/palettes/blinking.js +41 -35
  73. package/dist/palettes/blinking.js.map +1 -1
  74. package/dist/palettes/flashing-controller.d.ts +21 -0
  75. package/dist/palettes/flashing-controller.d.ts.map +1 -0
  76. package/dist/palettes/flashing-controller.js +45 -0
  77. package/dist/palettes/flashing-controller.js.map +1 -0
  78. package/dist/svghelpers/index.d.ts +1 -0
  79. package/dist/svghelpers/index.d.ts.map +1 -1
  80. package/dist/svghelpers/index.js +2 -0
  81. package/dist/svghelpers/index.js.map +1 -1
  82. package/dist/svghelpers/rounded-rect.d.ts +15 -0
  83. package/dist/svghelpers/rounded-rect.d.ts.map +1 -0
  84. package/dist/svghelpers/rounded-rect.js +29 -0
  85. package/dist/svghelpers/rounded-rect.js.map +1 -0
  86. package/dist/types.d.ts +14 -0
  87. package/dist/types.d.ts.map +1 -1
  88. package/dist/types.js +9 -0
  89. package/dist/types.js.map +1 -1
  90. package/package.json +1 -1
  91. package/script/check-css-variables.ts +2 -15
  92. package/src/alert-severity.spec.ts +56 -0
  93. package/src/alert-severity.ts +45 -43
  94. package/src/bars-graphs/area-graph/area-graph.stories.ts +235 -1
  95. package/src/bars-graphs/line-graph/line-graph.stories.ts +24 -0
  96. package/src/building-blocks/bar-horizontal/bar-horizontal.ts +7 -0
  97. package/src/building-blocks/bar-vertical/bar-vertical.ts +7 -0
  98. package/src/building-blocks/chart-line/chart-line-base.spec.ts +767 -0
  99. package/src/building-blocks/chart-line/chart-line-base.stories.ts +124 -0
  100. package/src/building-blocks/chart-line/chart-line-base.ts +671 -97
  101. package/src/building-blocks/chart-line/chart-sizing-battleground.stories.ts +17 -0
  102. package/src/building-blocks/external-scale/external-scale.spec.ts +154 -0
  103. package/src/building-blocks/external-scale/external-scale.ts +78 -20
  104. package/src/charthelpers/index.ts +1 -0
  105. package/src/charthelpers/range-labels.spec.ts +46 -0
  106. package/src/charthelpers/range-labels.ts +93 -0
  107. package/src/components/alert-button/alert-button.css +10 -23
  108. package/src/components/alert-button/alert-button.spec.ts +56 -15
  109. package/src/components/alert-button/alert-button.stories.ts +5 -1
  110. package/src/components/alert-button/alert-button.ts +33 -24
  111. package/src/components/alert-frame/alert-flash-scenario.stories.ts +669 -0
  112. package/src/components/alert-frame/alert-frame.css +106 -33
  113. package/src/components/alert-frame/alert-frame.spec.ts +176 -17
  114. package/src/components/alert-frame/alert-frame.stories.ts +61 -0
  115. package/src/components/alert-frame/alert-frame.ts +179 -41
  116. package/src/components/alert-icon/alert-icon.spec.ts +82 -27
  117. package/src/components/alert-icon/alert-icon.stories.ts +7 -1
  118. package/src/components/alert-icon/alert-icon.ts +48 -74
  119. package/src/components/alert-menu-item/alert-menu-item.css +1 -4
  120. package/src/components/date-item/date-item.css +3 -3
  121. package/src/components/keyboard-full/keyboard-full.css +4 -4
  122. package/src/components/message-menu-item/message-menu-item.css +2 -6
  123. package/src/components/sequence-toolbar/sequence-toolbar.css +1 -2
  124. package/src/navigation-instruments/gauge-trend/gauge-trend.stories.ts +29 -0
  125. package/src/navigation-instruments/gauge-trend/gauge-trend.ts +11 -0
  126. package/src/navigation-instruments/instrument-field/instrument-field.css +2 -2
  127. package/src/navigation-instruments/readout/readout.ts +2 -1
  128. package/src/navigation-instruments/readout-list-item/readout-list-item.ts +2 -1
  129. package/src/palettes/blinking.spec.ts +83 -0
  130. package/src/palettes/blinking.ts +47 -35
  131. package/src/palettes/flashing-controller.ts +62 -0
  132. package/src/palettes/manual.css +18 -4
  133. package/src/svghelpers/index.ts +1 -0
  134. package/src/svghelpers/rounded-rect.spec.ts +47 -0
  135. package/src/svghelpers/rounded-rect.ts +42 -0
  136. package/src/types.ts +20 -0
@@ -1 +1 @@
1
- {"version":3,"file":"external-scale.js","sources":["../../../src/building-blocks/external-scale/external-scale.ts"],"sourcesContent":["/**\n * @module External Scale\n *\n * # External Scale renderer (pure SVG building block)\n *\n * This module provides a side-aware, orientation-aware SVG “ruler/axis” renderer that can be used standalone, as an overlay axis for charts, or composed inside other components.\n *\n * Unlike Lit components, this file exports **pure functions** that return `SVGTemplateResult` fragments. Consumers are responsible for creating the outer `<svg>` element (including `viewBox`, sizing, and `preserveAspectRatio`).\n *\n * The module also exports a few small DOM helpers the web-component wrappers use to read CSS variables (border radius) and observe theme and size changes.\n *\n * ## What it renders\n * - **Bar container**: a rounded rectangle band (optional)\n * - **Bar fill**: value fill (0→value) or tinted range fill (fillMin→fillMax)\n * - **Tickmarks**: main + primary + secondary + tertiary tick lines (optional)\n * - **Labels**: numeric labels at primary tick interval (optional)\n * - **Advice overlays**: alert/advice/caution ranges with canonical dashed bounds\n * - **Setpoint marker**: a triangular marker that flips by side and scales when “at setpoint”\n *\n * ## Layout model\n * - `orientation`: `'vertical' | 'horizontal'` controls value→coordinate mapping\n * - `side`: where the scale attaches to the chart edge\n * - vertical: `'left' | 'right'`\n * - horizontal: `'top' | 'bottom'`\n * - The **chart edge is always at perpendicular coordinate `0`**. The scale expands outward into positive or negative perpendicular space depending on `side`.\n *\n * Use `computeExternalScaleLayout()` to compute the minimal viewBox thickness for the selected bands (bar/ticks/labels).\n *\n * ## Theming & responsive sizing\n * This renderer uses CSS variables directly in SVG attributes.\n *\n * It is designed to inherit theme and sizing variables from parent containers (e.g. `.obc-component-size-*` wrappers) the same way web components do.\n *\n * Common variables involved:\n * - `--global-typography-ui-label-font-size`\n * - `--instrument-frame-*-color`, `--instrument-*-*-color`\n * - `--instrument-components-watchface-frame-regular-border-radius`\n *\n * **Browser note (SVG geometry + CSS variables):**\n * Some browsers (notably Chrome) do not reliably resolve `var(--...)` inside SVG geometry attributes like `rx`/`ry`. The bar container and fill masks therefore provide numeric fallbacks and also set `rx`/`ry` via CSS geometry properties to allow theme overrides where supported.\n *\n * ## Usage examples\n *\n * ### Standalone usage\n * ```ts\n * import {html} from 'lit';\n * import {\n * computeExternalScaleLayout,\n * renderExternalScale,\n * ExternalScaleOrientation,\n * ExternalScaleSide,\n * ScaleType,\n * FillMode,\n * AdvicePosition,\n * type ExternalScaleConfig,\n * } from './external-scale.js';\n * import {FrameStyle, InstrumentState, Priority} from '../../navigation-instruments/types.js';\n * import {AdviceType} from '../../navigation-instruments/watch/advice.js';\n *\n * const config: ExternalScaleConfig = {\n * orientation: ExternalScaleOrientation.vertical,\n * side: ExternalScaleSide.right,\n * length: 320,\n * paddingStart: 32,\n * paddingEnd: 32,\n * minValue: 0,\n * maxValue: 100,\n * hasBar: true,\n * hasScale: true,\n * labels: true,\n * scaleBackground: false,\n * barThickness: 24,\n * tickThickness: 24,\n * labelThickness: 60,\n * mainTickmarks: [],\n * primaryTickmarkInterval: 20,\n * secondaryTickmarkInterval: 10,\n * tertiaryTickmarkInterval: 2,\n * scaleType: ScaleType.regular,\n * frameStyle: FrameStyle.regular,\n * priority: Priority.enhanced,\n * fillMode: FillMode.fill,\n * fillMin: 0,\n * fillMax: 40,\n * value: 40,\n * setpoint: 50,\n * atSetpoint: false,\n * autoAtSetpoint: true,\n * autoAtSetpointDeadband: 1,\n * setpointAtZeroDeadband: 0.5,\n * state: InstrumentState.active,\n * advicePosition: AdvicePosition.inner,\n * advices: [{min: 60, max: 80, type: AdviceType.caution, hinted: true}],\n * };\n *\n * const layout = computeExternalScaleLayout(config);\n * const parts = renderExternalScale(config);\n *\n * // Wrap returned fragments in an SVG.\n * const tpl = html`<svg\n * width=\"${layout.viewBoxThickness}px\"\n * height=\"${config.length}px\"\n * viewBox=\"${layout.viewBoxPerpStart} ${-config.length / 2} ${layout.viewBoxThickness} ${config.length}\"\n * preserveAspectRatio=\"none\"\n * >\n * ${parts.barContainer}\n * ${parts.barFill}\n * ${parts.scaleBackground}\n * ${parts.tickmarks}\n * ${parts.labels}\n * ${parts.adviceOverlays}\n * ${parts.setpoint}\n * </svg>`;\n * ```\n *\n * ### Web component wrappers\n * For common usage, prefer the thin wrappers:\n * - `obc-bar-vertical` (sets up vertical viewBox)\n * - `obc-bar-horizontal` (sets up horizontal viewBox)\n *\n * Source of truth: `packages/openbridge-webcomponents/src/building-blocks/external-scale/external-scale.ts`\n *\n * @experimental\n */\nimport {SVGTemplateResult, nothing, svg} from 'lit';\nimport {\n InstrumentState,\n Priority,\n FrameStyle,\n BorderRadiusPosition,\n} from '../../navigation-instruments/types.js';\nimport {\n AdviceState,\n AdviceType,\n} from '../../navigation-instruments/watch/advice.js';\nimport {\n tickmarkColor,\n TickmarkStyle,\n} from '../../navigation-instruments/watch/tickmark.js';\nimport {\n adjustRectWidthForStroke,\n adjustRectHeightForStroke,\n valueToX,\n valueToY,\n} from '../../svghelpers/stroke-aware.js';\nimport {\n SetpointVisualState,\n SetpointColorMode,\n drawSetpointMarker,\n generateSetpointId,\n getSetpointOutwardOffset,\n computeAtSetpoint,\n SETPOINT_ANIMATION_CSS_VAR,\n SETPOINT_ANIMATION_DURATION_DEFAULT,\n SETPOINT_HEIGHT,\n SETPOINT_ZERO_OFFSET,\n} from '../../svghelpers/setpoint.js';\n\n/** Main axis orientation for the external scale renderer. */\nexport enum ExternalScaleOrientation {\n vertical = 'vertical',\n horizontal = 'horizontal',\n}\n\n/** Which side of the chart area the scale is attached to. */\nexport enum ExternalScaleSide {\n left = 'left',\n right = 'right',\n top = 'top',\n bottom = 'bottom',\n}\n\n/** Tick density preset */\nexport enum ScaleType {\n regular = 'regular',\n condensed = 'condensed',\n}\n\n/** Fill visualization mode */\nexport enum FillMode {\n fill = 'fill',\n tint = 'tint',\n}\n\n/** Advice overlay position */\nexport enum AdvicePosition {\n center = 'center',\n inner = 'inner',\n outer = 'outer',\n}\n\n/**\n * Bar container background style.\n * Controls the background color of the bar container independently of scaleBackground.\n */\nexport enum BarContainerStyle {\n /** Use lighter primary color (--instrument-frame-primary-color) */\n primary = 'primary',\n /** Use darker secondary color (--instrument-frame-secondary-color) */\n secondary = 'secondary',\n}\n\n/** CSS variable used by component-size wrappers to define frame corner rounding. */\nexport const EXTERNAL_SCALE_BORDER_RADIUS_CSS_VAR =\n '--instrument-components-watchface-frame-regular-border-radius';\n\n/**\n * Parse a CSS length into pixels.\n *\n * Supports: `px`, `rem`, `em`, and unitless values (treated as px).\n * Returns `undefined` when parsing fails.\n */\nexport function parseCssLengthToPx(\n value: string,\n context?: {element?: Element; documentElement?: Element}\n): number | undefined {\n if (!value) return undefined;\n\n const v = value.trim();\n const n = Number.parseFloat(v);\n if (!Number.isFinite(n)) return undefined;\n\n if (v.endsWith('px')) return n;\n\n // Avoid throwing in non-DOM contexts (SSR/tests)\n const canComputeStyles = typeof getComputedStyle === 'function';\n\n if (v.endsWith('rem')) {\n if (!canComputeStyles) return undefined;\n const docEl =\n context?.documentElement ??\n (typeof document !== 'undefined' ? document.documentElement : undefined);\n if (!docEl) return undefined;\n const rootFontSize = Number.parseFloat(getComputedStyle(docEl).fontSize);\n return Number.isFinite(rootFontSize) ? n * rootFontSize : undefined;\n }\n\n if (v.endsWith('em')) {\n if (!canComputeStyles) return undefined;\n const el = context?.element;\n if (!el) return undefined;\n const fontSize = Number.parseFloat(getComputedStyle(el).fontSize);\n return Number.isFinite(fontSize) ? n * fontSize : undefined;\n }\n\n // If unitless or an unsupported unit, assume px.\n return n;\n}\n\n/**\n * Read the external scale border radius CSS variable from an element and return\n * a numeric pixel value suitable for path-based selective corner rounding.\n *\n * Falls back to 4px for condensed and 8px for regular when CSS/DOM is unavailable.\n */\nexport function readExternalScaleBorderRadiusPx(\n host: Element,\n scaleType: ScaleType,\n cssVarName: string = EXTERNAL_SCALE_BORDER_RADIUS_CSS_VAR\n): number {\n const fallback = scaleType === ScaleType.condensed ? 4 : 8;\n\n if (typeof getComputedStyle !== 'function') return fallback;\n\n const raw = getComputedStyle(host).getPropertyValue(cssVarName).trim();\n const parsed = parseCssLengthToPx(raw, {\n element: host,\n documentElement:\n // Prefer the element's owning document to support iframes/shadow contexts.\n (host as HTMLElement).ownerDocument?.documentElement ??\n (typeof document !== 'undefined' ? document.documentElement : undefined),\n });\n\n return parsed ?? fallback;\n}\n\n/**\n * Start observing likely style-change sources (host + ancestors + documentElement)\n * and call `onChange` when class/style attributes change.\n *\n * Returns the MutationObserver instance, or `undefined` when MutationObserver/DOM\n * is unavailable.\n */\nexport function startExternalScaleBorderRadiusObserver(\n host: HTMLElement,\n onChange: () => void\n): MutationObserver | undefined {\n if (typeof MutationObserver === 'undefined') return undefined;\n\n const observer = new MutationObserver(() => onChange());\n\n const targets: Element[] = [host];\n let current: Element | null = host.parentElement;\n while (current) {\n targets.push(current);\n current = current.parentElement;\n }\n\n const docEl = host.ownerDocument?.documentElement;\n if (docEl) targets.push(docEl);\n\n for (const t of targets) {\n observer.observe(t, {\n attributes: true,\n attributeFilter: ['class', 'style'],\n });\n }\n\n return observer;\n}\n\n/** Default border radius (px) used when `ExternalScaleConfig.borderRadius` is not provided. */\nexport function defaultExternalScaleBorderRadiusPx(\n scaleType: ScaleType\n): number {\n return scaleType === ScaleType.condensed ? 4 : 8;\n}\n\n/**\n * Compute a safe, numeric border radius (px) for geometry calculations.\n *\n * When `borderRadius` is undefined/invalid, falls back to a scaleType-based default.\n */\nexport function computeExternalScaleEffectiveBorderRadiusPx(\n config: Pick<ExternalScaleConfig, 'borderRadius' | 'scaleType'>\n): number {\n const fallback = defaultExternalScaleBorderRadiusPx(config.scaleType);\n const r = config.borderRadius;\n return typeof r === 'number' && Number.isFinite(r) && r >= 0 ? r : fallback;\n}\n\n/**\n * Compute the effective bar thickness.\n *\n * To keep rounded corners visually correct, the bar band must be at least\n * `2 * borderRadius` thick (otherwise the rounding geometry self-intersects).\n */\nexport function computeExternalScaleEffectiveBarThickness(\n config: Pick<\n ExternalScaleConfig,\n 'hasBar' | 'barThickness' | 'borderRadius' | 'scaleType'\n >\n): number {\n const bt = Number.isFinite(config.barThickness) ? config.barThickness : 0;\n if (!config.hasBar) return bt;\n\n const r = computeExternalScaleEffectiveBorderRadiusPx(config);\n return Math.max(bt, r * 2);\n}\n\n/**\n * Compute the effective tick band thickness based on scale type.\n *\n * In condensed mode, ticks are shorter (max 10px for primary/main + 4px gap = 14px),\n * so the tick band doesn't need to be as thick as in regular mode (20px + 4px = 24px).\n *\n * This function ensures that:\n * - In regular mode: tickThickness is used as-is (minimum 24px for full-length ticks)\n * - In condensed mode: tickThickness is capped at 14px (10px tick + 4px gap)\n *\n * This allows wrappers to use a single default tickThickness (24px) while the layout\n * automatically adjusts for condensed mode.\n *\n * @param config - Configuration with tickThickness and scaleType\n * @returns Effective tick band thickness in pixels\n */\nexport function computeExternalScaleEffectiveTickThickness(\n config: Pick<ExternalScaleConfig, 'tickThickness' | 'scaleType'>\n): number {\n const tt = Number.isFinite(config.tickThickness) ? config.tickThickness : 0;\n\n // In condensed mode, the longest tick is 10px, plus 4px gap = 14px max needed\n // Cap the tick thickness to avoid wasted space between ticks and labels\n if (config.scaleType === ScaleType.condensed) {\n const condensedMaxThickness = 14; // 10px tick + 4px gap\n return Math.min(tt, condensedMaxThickness);\n }\n\n return tt;\n}\n\nexport interface ExternalScaleAdvice {\n /** Range start value (in scale units). */\n min: number;\n /** Range end value (in scale units). */\n max: number;\n type: AdviceType;\n /** When true, renders in a \"hinted\" state unless the setpoint is inside the range. */\n hinted: boolean;\n}\n\nexport interface ExternalScaleAdviceRaw {\n min: number;\n max: number;\n type: AdviceType;\n state: AdviceState;\n}\n\nexport interface ExternalScaleConfig {\n /** Main axis orientation used for value-to-coordinate mapping. */\n orientation: ExternalScaleOrientation;\n /**\n * Which side of the chart area this scale lives on.\n * - vertical: 'left' | 'right'\n * - horizontal: 'top' | 'bottom'\n */\n side: ExternalScaleSide;\n\n /** Total length in pixels (vertical: height, horizontal: width), including padding. */\n length: number;\n\n /** Padding at start of main axis (top for vertical, left for horizontal). */\n paddingStart: number;\n /** Padding at end of main axis (bottom for vertical, right for horizontal). */\n paddingEnd: number;\n\n /** Minimum scale value. */\n minValue: number;\n /** Maximum scale value. */\n maxValue: number;\n\n // Layout bands (thickness, in px)\n /** Show scale tickmarks. */\n hasScale: boolean;\n /** Show labels at primary tickmark intervals. */\n labels?: boolean;\n /** Show bar. */\n hasBar: boolean;\n /** Show background behind the scale tickmarks. */\n scaleBackground: boolean;\n\n /** Bar band thickness in pixels (the container / fill area). */\n barThickness: number;\n /**\n * Bar container background style.\n * When undefined, defaults based on scaleBackground:\n * - scaleBackground=true: secondary (gray)\n * - scaleBackground=false: primary (lighter)\n * Set explicitly to override this default behavior.\n */\n barContainerStyle?: BarContainerStyle;\n /** Tickmark band thickness in pixels (space reserved for tick lines). */\n tickThickness: number;\n /** Label band thickness in pixels (space reserved for numbers). */\n labelThickness: number;\n\n // Tick configuration\n /** Array of values for main tickmarks. Defaults to [minValue, 0, maxValue] if empty. */\n mainTickmarks?: number[];\n /**\n * Interval for primary tickmarks. When undefined, no primary tickmarks are shown.\n * When a positive number, primary tickmarks are shown at that interval.\n */\n primaryTickmarkInterval?: number;\n /**\n * Interval for secondary tickmarks. When undefined, no secondary tickmarks are shown.\n * When a positive number, secondary tickmarks are shown at that interval.\n */\n secondaryTickmarkInterval?: number;\n /**\n * Interval for tertiary tickmarks. When undefined, no tertiary tickmarks are shown.\n * When a positive number, tertiary tickmarks are shown at that interval.\n */\n tertiaryTickmarkInterval?: number;\n /**\n * Tick density preset.\n * - ScaleType.regular: longer ticks\n * - ScaleType.condensed: shorter ticks\n */\n scaleType: ScaleType;\n /**\n * Frame style preset.\n * - FrameStyle.regular: all ticks offset from bar edge by a gap\n * - FrameStyle.flat: main ticks touch the bar edge\n * - FrameStyle.framed: framed appearance\n * - FrameStyle.instrument: instrument-style appearance\n */\n frameStyle: FrameStyle;\n /**\n * Border radius position based on component layout.\n * Determines which corners receive rounded borders.\n */\n borderRadiusPosition?: BorderRadiusPosition;\n /**\n * Override border radius value (in pixels).\n * When undefined, uses default based on scaleType (4px for condensed, 8px for regular).\n * Set this to the computed CSS variable value to make path-based selective corner\n * rounding respond to theme changes.\n */\n borderRadius?: number;\n\n // Visual state\n /**\n * Color priority mode.\n * - `Priority.enhanced`: Use enhanced (blue) color palette\n * - `Priority.regular`: Use regular (gray) color palette\n */\n priority: Priority;\n /**\n * When true, the setpoint color is derived from `priority` regardless of\n * instrument state (loading/off). This prevents the setpoint from being\n * rendered in disabled (tertiary) color when the instrument is loading or off.\n *\n * - `false` / `undefined`: default behavior — loading/off → disabled color\n * - `true`: color derived from `priority`, never disabled\n *\n * @default false\n */\n setpointOverride?: boolean;\n\n /**\n * Explicit disabled state override for setpoint marker.\n * When true, the setpoint uses tertiary/disabled colors.\n * When undefined, disabled state is auto-derived from `state` (loading/off = disabled).\n *\n * @default undefined (auto-derived from state)\n */\n setpointDisabled?: boolean;\n /**\n * Fill visualization mode.\n * - FillMode.fill: bar fill from fillMin to fillMax\n * - FillMode.tint: bar fill from fillMin to fillMax with marker at value position\n */\n fillMode: FillMode;\n fillMin?: number;\n fillMax?: number;\n /** Current value used for fill and/or marker rendering. */\n value?: number;\n\n // Setpoint\n /**\n * Setpoint value. When undefined, no setpoint marker is shown.\n * When a number, the setpoint marker is shown at that value.\n */\n setpoint?: number;\n /**\n * New setpoint value being adjusted (focus mode).\n * When defined, renders a second setpoint marker in 'focus' visual state.\n * The original `setpoint` marker is dimmed (0.5 opacity) while `newSetpoint` is active.\n * This enables the \"adjustment preview\" UX where users can see both the current\n * and proposed setpoint positions simultaneously.\n */\n newSetpoint?: number;\n /** Manual override used when autoAtSetpoint=false. */\n atSetpoint: boolean;\n /** When true, at-setpoint is derived from value/setpoint and deadband. */\n autoAtSetpoint: boolean;\n /** Deadband used for automatic at-setpoint detection. */\n autoAtSetpointDeadband: number;\n /** Deadband around 0 where the setpoint indicator snaps to exactly 0. */\n setpointAtZeroDeadband: number;\n state: InstrumentState;\n\n // Advice\n /** Where advice overlays are drawn relative to the bar/tick bands. */\n advicePosition: AdvicePosition;\n /** Array of advice ranges (min/max/type/hinted). */\n advices?: ExternalScaleAdvice[];\n\n /**\n * When true, freezes all internal calculations and scales the entire component\n * proportionally (like CSS transform:scale), except label font-size remains constant.\n * When false (default), dimensions react to component properties.\n * @default false\n */\n fixedAspectRatio?: boolean;\n\n /**\n * Reference size for proportional scaling when fixedAspectRatio is true.\n * At this size, the scale renders at native 1:1 (matches Figma design).\n * Above this size, the scale grows proportionally; below, it shrinks.\n * Applied to the main axis dimension (height for vertical, width for horizontal).\n * @default 384\n */\n scaleReferenceSize?: number;\n\n /**\n * When true, the component is used inside an instrument (e.g., gauge-trend).\n * In this mode, only label font size responds to .obc-component-size-* CSS classes.\n * Border radius uses the explicit `borderRadius` property value (or defaults to 8px regular / 4px condensed),\n * rather than reading from CSS variables.\n *\n * Wrappers should:\n * - Skip CSS variable observers when instrumentMode=true\n * - Use explicit borderRadius value or scaleType-based defaults\n *\n * @default false\n */\n instrumentMode?: boolean;\n\n /**\n * When true, displays a dot indicator at the current value position.\n * The dot is rendered in the scale band, touching its inner edge (towards the chart).\n * This provides an alternative to bar fill for highlighting the current value.\n *\n * The dot is:\n * - 12x12px filled circle with 2px stroke (16px total visual size)\n * - Fill: --instrument-regular-secondary-color (or enhanced variant when priority=enhanced)\n * - Stroke: --instrument-frame-primary-color\n *\n * @default false\n */\n highlightCurrentValue?: boolean;\n\n /**\n * User is physically interacting with the control (e.g. lever/slider touch).\n *\n * When true:\n * - `calculateAtSetpoint()` returns false (suppressed)\n * - Single setpoint marker renders in focus visual state\n *\n * @default false\n */\n touching?: boolean;\n\n // Animation\n /**\n * Enable CSS-animated confirm transition for setpoint markers.\n * When true, the original setpoint marker uses CSS `transition` for smooth movement\n * and opacity changes. The departing new-setpoint marker fades out.\n *\n * Duration is configurable via CSS: `--setpoint-animation-duration: 300ms`.\n * @default false\n */\n animateSetpoint?: boolean;\n\n /**\n * Value of the departing new-setpoint during confirm animation.\n * When defined, renders the new-setpoint marker at this position with `opacity: 0`\n * (CSS-transitioned from 1), keeping it in the DOM during its fade-out.\n *\n * Managed by SetpointMixin / SetpointBundle — cleared after animation completes.\n */\n departingNewSetpoint?: number;\n}\n\nexport interface ExternalScaleLayout {\n /** Total thickness (vertical: width, horizontal: height) */\n thickness: number;\n /** Where the viewBox begins on the perpendicular axis (chart-edge is always 0) */\n viewBoxPerpStart: number;\n /** viewBox length (main axis) */\n viewBoxLength: number;\n /** viewBox thickness (perpendicular axis) */\n viewBoxThickness: number;\n}\n\nexport type ExternalScaleLayoutConfig = Pick<\n ExternalScaleConfig,\n | 'orientation'\n | 'side'\n | 'hasBar'\n | 'hasScale'\n | 'labels'\n | 'barThickness'\n | 'tickThickness'\n | 'labelThickness'\n | 'length'\n | 'scaleType'\n> & {\n /**\n * Position of advice overlay pills relative to the bar band. Only used when\n * `hasAdvice` is true; defaults to `AdvicePosition.inner` if omitted.\n */\n advicePosition?: AdvicePosition;\n /**\n * Whether any advice overlays are present.\n *\n * Advice pills render in perpendicular space outside the bar band\n * (8px wide, plus a 4px offset from the bar edge or tick base). When the\n * scale/label bands don't already provide enough room, the layout reserves\n * an extra band so the pill is not clipped by the viewBox. This also makes\n * the reported scale thickness include the advice band, so parent charts\n * inset correctly to keep the pill visible inside the cell.\n */\n hasAdvice?: boolean;\n /**\n * Whether a setpoint marker (original, new, or departing) is present.\n *\n * The setpoint marker renders in perpendicular space outside the bar band\n * (tip at `tickBase + 4` plus a state offset of up to 8, body extending a\n * further 21 outward). When the scale/label bands don't already provide\n * enough room — e.g. `hasScale=false` side bars — the layout reserves an\n * extra band so the marker is not clipped by the viewBox.\n */\n hasSetpoint?: boolean;\n};\n\nexport interface ExternalScaleViewBox {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** Convenience helper for producing the `computeExternalScaleLayout()` input from a full config. */\nexport function toExternalScaleLayoutConfig(\n config: ExternalScaleConfig\n): ExternalScaleLayoutConfig {\n return {\n orientation: config.orientation,\n side: config.side,\n hasBar: config.hasBar,\n hasScale: config.hasScale,\n labels: config.labels,\n barThickness: computeExternalScaleEffectiveBarThickness(config),\n tickThickness: computeExternalScaleEffectiveTickThickness(config),\n labelThickness: config.labelThickness,\n length: config.length,\n scaleType: config.scaleType,\n advicePosition: config.advicePosition,\n hasAdvice: !!config.advices && config.advices.length > 0,\n hasSetpoint:\n config.setpoint !== undefined ||\n config.newSetpoint !== undefined ||\n config.departingNewSetpoint !== undefined,\n };\n}\n\n/**\n * Compute the outer SVG viewBox for a scale given layout.\n * Wrappers can use this to avoid duplicating orientation-specific math.\n */\nexport function computeExternalScaleViewBox(\n config: Pick<ExternalScaleConfig, 'orientation' | 'length'>,\n layout: ExternalScaleLayout\n): ExternalScaleViewBox {\n if (config.orientation === 'vertical') {\n return {\n x: layout.viewBoxPerpStart,\n y: -config.length / 2,\n width: layout.viewBoxThickness,\n height: config.length,\n };\n }\n\n return {\n x: 0,\n y: layout.viewBoxPerpStart,\n width: config.length,\n height: layout.viewBoxThickness,\n };\n}\n\n/**\n * Compute the effective `preserveAspectRatio=\"xMidYMid meet\"` uniform scale factor.\n *\n * Returns 1 when inputs are invalid (e.g. 0-sized viewBox).\n */\nexport function computeMeetScale(\n viewBoxWidth: number,\n viewBoxHeight: number,\n containerWidth: number,\n containerHeight: number\n): number {\n const widthScale = viewBoxWidth > 0 ? containerWidth / viewBoxWidth : 1;\n const heightScale = viewBoxHeight > 0 ? containerHeight / viewBoxHeight : 1;\n return Math.min(widthScale, heightScale);\n}\n\n/**\n * Configuration for computing fixed aspect ratio scale factor.\n */\nexport interface FixedAspectRatioScaleConfig {\n /** Main axis orientation: 'vertical' or 'horizontal' */\n orientation: ExternalScaleOrientation;\n /** Actual main axis size of the container (height for vertical, width for horizontal) */\n containerMainAxisSize: number;\n /** Reference size at which the scale renders at 1:1 (default: 384) */\n scaleReferenceSize: number;\n}\n\n/**\n * Compute the scale factor for fixed aspect ratio mode.\n *\n * In fixed aspect ratio mode, the scale component determines its zoom level based on\n * comparing the container's main axis size against a reference size (typically 384px).\n * - If container is larger than reference: scale > 1 (zoom in)\n * - If container is smaller than reference: scale < 1 (zoom out)\n * - If container equals reference: scale = 1 (native size)\n *\n * This scale factor is applied to SVG rendering while keeping text labels at constant size\n * by using the CSS variable `--scale` to counter-scale font sizes.\n *\n * Works for all orientations and sides:\n * - Vertical scales (left/right): compare container height vs reference\n * - Horizontal scales (top/bottom): compare container width vs reference\n *\n * @param config Configuration with orientation, container size, and reference size\n * @returns Scale factor (> 0), defaults to 1 if container size is invalid\n */\nexport function computeFixedAspectRatioScale(\n config: FixedAspectRatioScaleConfig\n): number {\n const {containerMainAxisSize, scaleReferenceSize} = config;\n\n // Guard against zero or negative sizes\n if (containerMainAxisSize <= 0 || scaleReferenceSize <= 0) {\n return 1;\n }\n\n // Scale = container size / reference size\n // e.g., container=480px, reference=384px => scale=1.25 (zoom in)\n // e.g., container=288px, reference=384px => scale=0.75 (zoom out)\n return containerMainAxisSize / scaleReferenceSize;\n}\n\n/**\n * Compute scaled dimensions for reporting when in fixed aspect ratio mode.\n *\n * When fixedAspectRatio is true, the reported thickness should be scaled\n * proportionally to match the visual output.\n *\n * @param baseThickness The unscaled thickness from layout computation\n * @param scale The current scale factor from computeFixedAspectRatioScale\n * @returns Scaled thickness value\n */\nexport function computeScaledThickness(\n baseThickness: number,\n scale: number\n): number {\n return baseThickness * scale;\n}\n\n/**\n * Compute a minimal viewBox layout for an external scale.\n *\n * The chart edge is always at perpendicular coordinate 0, and the scale expands\n * outward from that edge based on which bands are enabled (bar/ticks/labels).\n *\n * When scaleType is 'condensed', tick thickness is automatically reduced to match\n * the shorter tick lengths (14px max instead of 24px for regular).\n */\nexport function computeExternalScaleLayout(\n config: ExternalScaleLayoutConfig\n): ExternalScaleLayout {\n const barSpace = config.hasBar ? config.barThickness : 0;\n // Use effective tick thickness based on scaleType\n const effectiveTickThickness =\n computeExternalScaleEffectiveTickThickness(config);\n const scaleSpace = config.hasScale ? effectiveTickThickness : 0;\n const labelSpace = config.labels ? config.labelThickness : 0;\n\n // Advice pills render outside the bar band. When the scale/label bands\n // collapse (e.g. hasLabelPadding=false on the parent chart, or hasScale=false),\n // reserve a minimum perpendicular band so the pill is not clipped. The pill\n // is 8px wide with a 4px offset from its anchor edge, plus a small visual\n // buffer so the pill doesn't touch the viewBox edge.\n const adviceSpace = computeAdviceBandThickness(config);\n const setpointSpace = computeSetpointBandThickness(config);\n const outsideBarSpace = Math.max(\n scaleSpace + labelSpace,\n adviceSpace,\n setpointSpace\n );\n const thickness = barSpace + outsideBarSpace;\n\n const isOutwardPositive =\n (config.orientation === 'vertical' && config.side === 'right') ||\n (config.orientation === 'horizontal' && config.side === 'bottom');\n\n const viewBoxPerpStart = isOutwardPositive ? 0 : -thickness;\n\n return {\n thickness,\n viewBoxPerpStart,\n viewBoxLength: config.length,\n viewBoxThickness: thickness,\n };\n}\n\n/**\n * Compute the minimum perpendicular band thickness required to render advice\n * pills without clipping. Returns 0 when no advices are present.\n *\n * Pill geometry (see `advicePill` / `renderAdvice`):\n * - `inner` (default when no bar): pill at `tickBase + 4` to `tickBase + 12`\n * from the bar edge → needs 12px + 4px buffer = 16px outside the bar.\n * - `outer`: pill at `barThickness + 10 + 4` to `barThickness + 10 + 12`\n * → needs 22px + 2px buffer = 24px outside the bar.\n * - `center`: pill straddles the bar band; no extra perpendicular space needed.\n *\n * NOTE: `renderAdvice()` coerces `advicePosition` to `inner` when `hasBar=false`\n * (no bar area to straddle/sit-outside). Mirror that coercion here so the\n * reserved space matches the rendered geometry — otherwise `hasBar=false +\n * advicePosition='center'` would reserve 0 while the pill renders at inner\n * geometry and clips.\n */\nfunction computeAdviceBandThickness(\n config: Pick<\n ExternalScaleLayoutConfig,\n 'hasAdvice' | 'advicePosition' | 'hasBar'\n >\n): number {\n if (!config.hasAdvice) return 0;\n const position = config.hasBar\n ? (config.advicePosition ?? AdvicePosition.inner)\n : AdvicePosition.inner;\n if (position === AdvicePosition.center) return 0;\n if (position === AdvicePosition.outer) return 24;\n return 16;\n}\n\n/**\n * Perpendicular band needed to keep a setpoint marker inside the viewBox\n * when no scale/label bands reserve the space.\n *\n * Worst case, measured outward from the bar edge (`tickBasePerp`):\n * `tickGap()` + max state offset (`equalZero`, `SETPOINT_ZERO_OFFSET`) +\n * marker body (`SETPOINT_HEIGHT`). See `renderSingleSetpoint()` for the\n * geometry.\n */\nexport function computeSetpointBandThickness(\n config: Pick<ExternalScaleLayoutConfig, 'hasSetpoint'>\n): number {\n if (!config.hasSetpoint) return 0;\n return tickGap() + SETPOINT_ZERO_OFFSET + SETPOINT_HEIGHT;\n}\n\nfunction isVertical(config: ExternalScaleConfig): boolean {\n return config.orientation === 'vertical';\n}\n\nfunction isOutwardPositive(config: ExternalScaleConfig): boolean {\n return (\n (config.orientation === 'vertical' && config.side === 'right') ||\n (config.orientation === 'horizontal' && config.side === 'bottom')\n );\n}\n\nfunction rangeIncludesZero(minValue: number, maxValue: number): boolean {\n return minValue <= 0 && maxValue >= 0;\n}\n\nfunction calculateAtSetpoint(config: ExternalScaleConfig): boolean {\n const isTouching = config.touching ?? false;\n return computeAtSetpoint({\n value: config.value,\n setpoint: config.setpoint,\n touching: isTouching,\n auto: config.autoAtSetpoint,\n deadband: config.autoAtSetpointDeadband,\n atSetpointManual: config.atSetpoint,\n });\n}\n\n// ============================================================================\n// Setpoint Visual State Derivation\n// ============================================================================\n\n/**\n * Derive the SetpointVisualState from ExternalScaleConfig.\n *\n * This maps the instrument's API (state, atSetpoint, value, setpoint, etc.)\n * to the design-only visual state enum.\n *\n * Priority order:\n * 1. focus (touching property is true - user actively adjusting)\n * 2. equalZero (at setpoint AND setpoint is at zero)\n * 3. equal (at setpoint)\n * 4. notEqual (default)\n *\n * NOTE: Disabled states (loading, off) are handled via deriveSetpointDisabled(),\n * which returns a boolean flag, not via a separate visual state.\n *\n * State mapping:\n * - InstrumentState.active → notEqual/equal/equalZero (based on deadband)\n * - InstrumentState.loading → disabled=true (via deriveSetpointDisabled)\n * - InstrumentState.off → disabled=true (via deriveSetpointDisabled)\n *\n * Note: `focus` visual state is only triggered by the `touching` property\n * (user actively adjusting via touch/drag), not by InstrumentState.\n */\nexport function deriveSetpointVisualState(\n config: ExternalScaleConfig\n): SetpointVisualState {\n // Priority 1: Focus state\n // - When `touching` property is true (user is actively adjusting)\n // - BUT only when newSetpoint is not defined (otherwise original should be dimmed)\n const isTouching = config.touching ?? false;\n if (isTouching && config.newSetpoint === undefined) {\n return SetpointVisualState.focus;\n }\n\n // For enhanced and active states, check deadband-based states\n // Check if at setpoint\n const isAt = calculateAtSetpoint(config);\n\n if (isAt) {\n // Check if setpoint is at zero (using setpointAtZeroDeadband)\n const setpointAtZero =\n config.setpoint !== undefined &&\n Math.abs(config.setpoint) < config.setpointAtZeroDeadband;\n\n if (setpointAtZero) {\n return SetpointVisualState.equalZero;\n }\n return SetpointVisualState.equal;\n }\n\n // Default: not at setpoint\n return SetpointVisualState.notEqual;\n}\n\n/**\n * Derive the SetpointColorMode from ExternalScaleConfig.\n *\n * Maps `config.priority` to enhanced/regular color palette.\n *\n * Note: Disabled state is handled separately via deriveSetpointDisabled().\n */\nfunction deriveSetpointColorMode(\n config: ExternalScaleConfig\n): SetpointColorMode {\n // Map priority to color mode\n return config.priority === Priority.enhanced\n ? SetpointColorMode.enhanced\n : SetpointColorMode.regular;\n}\n\n/**\n * Derive the disabled state for setpoint rendering.\n *\n * Priority:\n * 1. Explicit setpointDisabled takes precedence\n * 2. When setpointOverride is true, never auto-disable\n * 3. Instrument states (loading, off) are treated as disabled\n * 4. Otherwise, not disabled\n */\nfunction deriveSetpointDisabled(config: ExternalScaleConfig): boolean {\n // Explicit setpointDisabled takes precedence\n if (config.setpointDisabled !== undefined) {\n return config.setpointDisabled;\n }\n\n // When override is active, don't auto-disable for loading/off\n if (config.setpointOverride) {\n return false;\n }\n\n // Disabled states (loading, off) use disabled color mode\n if (\n config.state === InstrumentState.loading ||\n config.state === InstrumentState.off\n ) {\n return true;\n }\n\n return false;\n}\n\nfunction colors(config: ExternalScaleConfig): {\n barFillColor: string;\n markerFillColor: string;\n markerStrokeColor: string;\n setpointColor: string;\n} {\n // TODO(theming): extend the color resolution to support domain-specific\n // palettes (e.g. automation medium / fuel colors used by `obc-automation-tank`'s\n // legacy CSS bar — `--automation-medium-fuel`, `--automation-fresh-water`,\n // etc.). Today the bar fill is locked to the instrument regular/enhanced\n // palette; tanks rendered through this renderer therefore lose their\n // per-`medium` coloring. A new optional `colorVariant` (or similar) on\n // `ExternalScaleConfig`, plumbed through `obc-bar-vertical` /\n // `obc-bar-horizontal`, would let the tank pass its medium token and\n // restore the legacy look without forking the renderer.\n const isEnhanced = config.priority === Priority.enhanced;\n // Fill mode uses secondary color, tint mode uses tertiary color\n let barFillColor =\n config.fillMode === 'tint'\n ? isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)'\n : isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n\n let markerFillColor = isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n\n let markerStrokeColor = isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n\n let setpointColor = isEnhanced\n ? 'var(--instrument-enhanced-primary-color)'\n : 'var(--instrument-regular-primary-color)';\n\n if (\n config.state === InstrumentState.loading ||\n config.state === InstrumentState.off\n ) {\n barFillColor = 'transparent';\n markerFillColor = 'var(--instrument-frame-tertiary-color)';\n markerStrokeColor = 'var(--instrument-frame-tertiary-color)';\n setpointColor = 'var(--instrument-frame-tertiary-color)';\n }\n\n return {barFillColor, markerFillColor, markerStrokeColor, setpointColor};\n}\n\nfunction convertAdvices(\n advices: ExternalScaleAdvice[],\n setpoint: number | undefined\n): ExternalScaleAdviceRaw[] {\n return advices.map((a) => {\n const triggered =\n setpoint !== undefined && setpoint >= a.min && setpoint <= a.max;\n\n const state = triggered\n ? AdviceState.triggered\n : a.hinted\n ? AdviceState.hinted\n : AdviceState.regular;\n\n return {min: a.min, max: a.max, type: a.type, state};\n });\n}\n\nfunction mainAxisOffset(config: ExternalScaleConfig): number {\n if (isVertical(config)) {\n // viewBox y is centered at 0: [-length/2 .. length/2]\n // paddingStart=top, paddingEnd=bottom\n return (config.paddingStart - config.paddingEnd) / 2;\n }\n // horizontal viewBox x starts at 0\n return config.paddingStart;\n}\n\nfunction drawingLength(config: ExternalScaleConfig): number {\n return Math.max(0, config.length - config.paddingStart - config.paddingEnd);\n}\n\nfunction valueToMainAxis(config: ExternalScaleConfig, value: number): number {\n const dLen = drawingLength(config);\n if (isVertical(config)) {\n return (\n valueToY(value, config.minValue, config.maxValue, dLen) +\n mainAxisOffset(config)\n );\n }\n return (\n valueToX(value, config.minValue, config.maxValue, dLen) +\n mainAxisOffset(config)\n );\n}\n\nfunction getTickThicknesses(scaleType: ScaleType) {\n const isCondensed = scaleType === 'condensed';\n return {\n primary: isCondensed ? 10 : 20,\n secondary: isCondensed ? 4 : 8,\n tertiary: isCondensed ? 2 : 4,\n main: isCondensed ? 10 : 20,\n };\n}\n\nfunction tickBasePerp(config: ExternalScaleConfig): number {\n // Chart edge is always at perp=0.\n // Bar band touches chart edge.\n return config.hasBar\n ? isOutwardPositive(config)\n ? config.barThickness\n : -config.barThickness\n : 0;\n}\n\nfunction tickGap(): number {\n return 4;\n}\n\nfunction labelGap(): number {\n return 8;\n}\n\nfunction buildTickLine(\n config: ExternalScaleConfig,\n mainPos: number,\n perpStart: number,\n perpLen: number\n): SVGTemplateResult {\n const stroke = 'var(--instrument-frame-tertiary-color)';\n const strokeWidth = 1;\n\n if (isVertical(config)) {\n const x1 = perpStart;\n const x2 = perpStart + perpLen;\n const y = mainPos;\n return svg`<line x1=${x1} x2=${x2} y1=${y} y2=${y} stroke=${stroke} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n const y1 = perpStart;\n const y2 = perpStart + perpLen;\n const x = mainPos;\n return svg`<line x1=${x} x2=${x} y1=${y1} y2=${y2} stroke=${stroke} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>`;\n}\n\nfunction generateTickmarksAtInterval(\n config: ExternalScaleConfig,\n interval: number,\n perpStart: number,\n perpLen: number,\n skipValues: number[]\n): {svgs: SVGTemplateResult[]; values: number[]} {\n const svgs: SVGTemplateResult[] = [];\n const values: number[] = [];\n\n if (interval <= 0 || !Number.isFinite(interval)) return {svgs, values};\n\n const includesZero = rangeIncludesZero(config.minValue, config.maxValue);\n\n const pushTick = (v: number) => {\n if (skipValues.includes(v)) return;\n values.push(v);\n svgs.push(\n buildTickLine(config, valueToMainAxis(config, v), perpStart, perpLen)\n );\n };\n\n if (includesZero) {\n for (let v = interval; v <= config.maxValue; v += interval) pushTick(v);\n for (let v = -interval; v >= config.minValue; v -= interval) pushTick(v);\n } else {\n const startValue = Math.ceil(config.minValue / interval) * interval;\n for (let v = startValue; v <= config.maxValue; v += interval) pushTick(v);\n }\n\n return {svgs, values};\n}\n\nfunction generateTickmarks(config: ExternalScaleConfig): SVGTemplateResult[] {\n if (!config.hasScale) return [];\n\n const svgs: SVGTemplateResult[] = [];\n const skipValues: number[] = [];\n\n const base = tickBasePerp(config);\n const gap = tickGap();\n\n const tickmarksStart = isOutwardPositive(config) ? base + gap : base - gap;\n\n const {primary, secondary, tertiary, main} = getTickThicknesses(\n config.scaleType\n );\n\n // Zero tick (skip if at min/max with scaleBackground enabled)\n if (rangeIncludesZero(config.minValue, config.maxValue)) {\n const isAtBoundary = 0 === config.minValue || 0 === config.maxValue;\n const shouldSkip = config.scaleBackground && isAtBoundary;\n\n if (!shouldSkip) {\n const perpLen = primary;\n const perpStart = tickmarksStart;\n svgs.push(\n buildTickLine(\n config,\n valueToMainAxis(config, 0),\n perpStart,\n isOutwardPositive(config) ? perpLen : -perpLen\n )\n );\n }\n skipValues.push(0);\n }\n\n // Main tickmarks - show when mainTickmarks is defined (array presence means enabled)\n // Use defensive guard to handle null/undefined/empty the same way as advices\n if (config.mainTickmarks) {\n const start = config.frameStyle === 'flat' ? base : tickmarksStart;\n const mainLen = config.frameStyle === 'flat' ? main + 4 : main;\n const dirLen = isOutwardPositive(config) ? mainLen : -mainLen;\n\n // Use provided array or default to [minValue, 0, maxValue]\n const mainTickValues =\n config.mainTickmarks.length > 0\n ? config.mainTickmarks\n : [config.minValue, 0, config.maxValue];\n\n for (const value of mainTickValues) {\n // Skip if outside range\n if (value < config.minValue || value > config.maxValue) continue;\n\n // Skip min/max tickmarks when scaleBackground is enabled (they align with the background edges)\n if (\n config.scaleBackground &&\n (value === config.minValue || value === config.maxValue)\n ) {\n skipValues.push(value);\n continue;\n }\n\n svgs.push(\n buildTickLine(config, valueToMainAxis(config, value), start, dirLen)\n );\n skipValues.push(value);\n }\n }\n\n // Primary - show when interval is defined and > 0\n if (\n config.primaryTickmarkInterval !== undefined &&\n config.primaryTickmarkInterval > 0\n ) {\n const {svgs: s, values} = generateTickmarksAtInterval(\n config,\n config.primaryTickmarkInterval,\n tickmarksStart,\n isOutwardPositive(config) ? primary : -primary,\n skipValues\n );\n svgs.push(...s);\n skipValues.push(...values);\n }\n\n // Secondary - show when interval is defined and > 0\n if (\n config.secondaryTickmarkInterval !== undefined &&\n config.secondaryTickmarkInterval > 0\n ) {\n const {svgs: s} = generateTickmarksAtInterval(\n config,\n config.secondaryTickmarkInterval,\n tickmarksStart,\n isOutwardPositive(config) ? secondary : -secondary,\n skipValues\n );\n svgs.push(...s);\n }\n\n // Tertiary - show when interval is defined and > 0\n if (\n config.tertiaryTickmarkInterval !== undefined &&\n config.tertiaryTickmarkInterval > 0\n ) {\n const {svgs: s} = generateTickmarksAtInterval(\n config,\n config.tertiaryTickmarkInterval,\n tickmarksStart,\n isOutwardPositive(config) ? tertiary : -tertiary,\n skipValues\n );\n svgs.push(...s);\n }\n\n return svgs;\n}\n\nfunction generateLabels(config: ExternalScaleConfig): SVGTemplateResult[] {\n if (!config.labels || config.primaryTickmarkInterval === undefined) return [];\n\n const interval = config.primaryTickmarkInterval;\n if (interval <= 0 || !Number.isFinite(interval)) return [];\n\n const fontFamily = 'var(--font-family-main)';\n const fontColor = 'var(--instrument-tick-mark-label-secondary-color)';\n const fontSize =\n 'calc(var(--global-typography-ui-label-font-size) / var(--scale, 1))';\n\n const base = tickBasePerp(config);\n // Use effective tick thickness to position labels closer to ticks in condensed mode\n const effectiveTickThickness =\n computeExternalScaleEffectiveTickThickness(config);\n const labelPos = isOutwardPositive(config)\n ? base + (config.hasScale ? effectiveTickThickness : 0) + labelGap()\n : base - (config.hasScale ? effectiveTickThickness : 0) - labelGap();\n\n const includesZero = rangeIncludesZero(config.minValue, config.maxValue);\n\n const labels: SVGTemplateResult[] = [];\n\n const push = (v: number) => {\n const main = valueToMainAxis(config, v);\n if (isVertical(config)) {\n const x = labelPos;\n const y = main;\n const anchor = isOutwardPositive(config) ? 'start' : 'end';\n labels.push(\n svg`<text x=${x} y=${y} text-anchor=${anchor} dominant-baseline=\"middle\" font-family=${fontFamily} style=\"font-size: ${fontSize}\" fill=${fontColor}>${v}</text>`\n );\n return;\n }\n\n const y = labelPos;\n const x = main;\n const baseline = isOutwardPositive(config) ? 'hanging' : 'auto';\n labels.push(\n svg`<text x=${x} y=${y} text-anchor=\"middle\" dominant-baseline=${baseline} font-family=${fontFamily} style=\"font-size: ${fontSize}\" fill=${fontColor}>${v}</text>`\n );\n };\n\n if (includesZero) {\n for (let v = 0; v <= config.maxValue; v += interval) push(v);\n for (let v = -interval; v >= config.minValue; v -= interval) push(v);\n } else {\n const startValue = Math.ceil(config.minValue / interval) * interval;\n for (let v = startValue; v <= config.maxValue; v += interval) push(v);\n }\n\n return labels;\n}\n\nfunction generateBarContainer(\n config: ExternalScaleConfig\n): SVGTemplateResult | typeof nothing {\n if (!config.hasBar) return nothing;\n\n const borderRadiusFallback = config.scaleType === 'condensed' ? 4 : 8;\n const borderRadiusValue = config.borderRadius ?? borderRadiusFallback;\n const strokeWidth = 1;\n // Determine bar container fill color:\n // 1. If barContainerStyle is explicitly set, use it\n // 2. Otherwise, fall back to scaleBackground-based default\n let fillColor: string;\n if (config.barContainerStyle !== undefined) {\n fillColor =\n config.barContainerStyle === BarContainerStyle.secondary\n ? 'var(--instrument-frame-secondary-color)'\n : 'var(--instrument-frame-primary-color)';\n } else {\n fillColor = config.scaleBackground\n ? 'var(--instrument-frame-secondary-color)'\n : 'var(--instrument-frame-primary-color)';\n }\n const strokeColor = 'var(--instrument-frame-tertiary-color)';\n\n const dLen = drawingLength(config);\n const axisShift = mainAxisOffset(config);\n\n // Determine which corners should be rounded based on borderRadiusPosition\n // innerFirstChild: corners on the inner/chart edge\n // middleChild: no corners\n // middleRoundedChild: chart-only (ignored here, treated as middleChild)\n // outerLastChild: corners on the outer edge (away from chart)\n let shouldRoundTopLeft = true;\n let shouldRoundTopRight = true;\n let shouldRoundBottomLeft = true;\n let shouldRoundBottomRight = true;\n\n if (config.borderRadiusPosition) {\n if (\n config.borderRadiusPosition === BorderRadiusPosition.middleChild ||\n config.borderRadiusPosition === BorderRadiusPosition.middleRoundedChild\n ) {\n // No rounded corners for middle child\n // (middleRoundedChild is chart-canvas-only; ignored for external scales)\n shouldRoundTopLeft = false;\n shouldRoundTopRight = false;\n shouldRoundBottomLeft = false;\n shouldRoundBottomRight = false;\n } else if (isVertical(config)) {\n // Vertical orientation\n const isRight = config.side === 'right';\n const isInner =\n config.borderRadiusPosition === BorderRadiusPosition.innerFirstChild;\n\n if (isRight) {\n // Right side: inner = left, outer = right\n shouldRoundTopLeft = isInner;\n shouldRoundBottomLeft = isInner;\n shouldRoundTopRight = !isInner;\n shouldRoundBottomRight = !isInner;\n } else {\n // Left side: inner = right, outer = left\n shouldRoundTopLeft = !isInner;\n shouldRoundBottomLeft = !isInner;\n shouldRoundTopRight = isInner;\n shouldRoundBottomRight = isInner;\n }\n } else {\n // Horizontal orientation\n const isBottom = config.side === 'bottom';\n const isInner =\n config.borderRadiusPosition === BorderRadiusPosition.innerFirstChild;\n\n if (isBottom) {\n // Bottom side: inner = top, outer = bottom\n shouldRoundTopLeft = isInner;\n shouldRoundTopRight = isInner;\n shouldRoundBottomLeft = !isInner;\n shouldRoundBottomRight = !isInner;\n } else {\n // Top side: inner = bottom, outer = top\n shouldRoundTopLeft = !isInner;\n shouldRoundTopRight = !isInner;\n shouldRoundBottomLeft = isInner;\n shouldRoundBottomRight = isInner;\n }\n }\n }\n\n const r = borderRadiusValue;\n const allCornersRounded =\n shouldRoundTopLeft &&\n shouldRoundTopRight &&\n shouldRoundBottomLeft &&\n shouldRoundBottomRight;\n const noCornersRounded =\n !shouldRoundTopLeft &&\n !shouldRoundTopRight &&\n !shouldRoundBottomLeft &&\n !shouldRoundBottomRight;\n\n if (isVertical(config)) {\n let rectX = isOutwardPositive(config) ? 0 : -config.barThickness;\n let rectY = -dLen / 2 + axisShift;\n let rectWidth = config.barThickness;\n let rectHeight = dLen;\n\n // The edge touching the scale is not adjusted inward for stroke: it\n // isn't a true viewBox boundary, since the scale covers it.\n const isRight = config.side === 'right';\n let viewBoxMinX: number;\n let viewBoxMaxX: number;\n if (config.scaleBackground) {\n // Exclude the edge that touches the scale from stroke adjustment\n if (isRight) {\n // Right side: bar is at x=0..barThickness, scale touches right edge\n // Only adjust left edge (viewBoxMinX=0), don't adjust right edge\n viewBoxMinX = 0;\n viewBoxMaxX = config.barThickness + 1; // +1 so rectX+rectWidth won't match\n } else {\n // Left side: bar is at x=-barThickness..0, scale touches left edge\n // Only adjust right edge (viewBoxMaxX=0), don't adjust left edge\n viewBoxMinX = -config.barThickness - 1; // -1 so rectX won't match\n viewBoxMaxX = 0;\n }\n } else {\n viewBoxMinX = isRight ? 0 : -config.barThickness;\n viewBoxMaxX = isRight ? config.barThickness : 0;\n }\n\n const adjustedX = adjustRectWidthForStroke(\n rectX,\n rectWidth,\n viewBoxMinX,\n viewBoxMaxX,\n strokeWidth\n );\n rectX = adjustedX.x;\n rectWidth = adjustedX.width;\n\n const adjustedY = adjustRectHeightForStroke(\n rectY,\n rectHeight,\n -dLen / 2 + axisShift,\n dLen / 2 + axisShift,\n strokeWidth\n );\n rectY = adjustedY.y;\n rectHeight = adjustedY.height;\n\n // Use simple rect when all corners or no corners are rounded\n if (allCornersRounded || noCornersRounded) {\n const rx = allCornersRounded ? r : 0;\n const ry = allCornersRounded ? r : 0;\n\n if (config.scaleBackground) {\n // When scaleBackground=true, draw fill and stroke separately to exclude edge touching scale\n const isRight = config.side === 'right';\n\n // Stroke path excludes the edge touching the scale\n let strokePath: string;\n if (isRight) {\n // Exclude right edge (touching scale on right side)\n strokePath = `M ${rectX} ${rectY + (noCornersRounded ? 0 : r)} L ${rectX} ${rectY + rectHeight - (noCornersRounded ? 0 : r)}`; // Left edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY + rectHeight} ${rectX + r} ${rectY + rectHeight}`; // Bottom-left corner\n strokePath += ` L ${rectX + rectWidth - (noCornersRounded ? 0 : r)} ${rectY + rectHeight}`; // Bottom edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY + rectHeight} ${rectX + rectWidth} ${rectY + rectHeight - r}`; // Bottom-right corner (no stroke)\n strokePath += ` M ${rectX + rectWidth} ${rectY + (noCornersRounded ? 0 : r)}`; // Move to top-right (no stroke on right edge)\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY} ${rectX + rectWidth - r} ${rectY}`; // Top-right corner (no stroke)\n strokePath += ` L ${rectX + (noCornersRounded ? 0 : r)} ${rectY}`; // Top edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY} ${rectX} ${rectY + r}`; // Top-left corner\n } else {\n // Exclude left edge (touching scale on left side)\n strokePath = `M ${rectX + (noCornersRounded ? 0 : r)} ${rectY}`; // Top edge start\n strokePath += ` L ${rectX + rectWidth - (noCornersRounded ? 0 : r)} ${rectY}`; // Top edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY} ${rectX + rectWidth} ${rectY + r}`; // Top-right corner\n strokePath += ` L ${rectX + rectWidth} ${rectY + rectHeight - (noCornersRounded ? 0 : r)}`; // Right edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY + rectHeight} ${rectX + rectWidth - r} ${rectY + rectHeight}`; // Bottom-right corner\n strokePath += ` L ${rectX + (noCornersRounded ? 0 : r)} ${rectY + rectHeight}`; // Bottom edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY + rectHeight} ${rectX} ${rectY + rectHeight - r}`; // Bottom-left corner (no stroke)\n strokePath += ` M ${rectX} ${rectY + (noCornersRounded ? 0 : r)}`; // Move to left edge start (no stroke on left edge)\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY} ${rectX + r} ${rectY}`; // Top-left corner (no stroke)\n }\n\n return svg`\n <rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${rx} ry=${ry} fill=${fillColor} stroke=\"none\"/>\n <path d=\"${strokePath}\" fill=\"none\" stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n `;\n }\n\n return svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${rx} ry=${ry} fill=${fillColor} stroke=${strokeColor} vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n // Use path for selective corner rounding\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n let path = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n\n // When scaleBackground=true, draw fill and stroke separately to exclude edge touching scale\n if (config.scaleBackground) {\n const isRight = config.side === 'right';\n\n // Stroke path excludes the edge touching the scale\n let strokePath: string;\n if (isRight) {\n // Exclude right edge\n strokePath = `M ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) strokePath += ` Q ${x} ${y} ${x + r} ${y}`;\n strokePath += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight)\n strokePath += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n strokePath += ` M ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight)\n strokePath += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n strokePath += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft)\n strokePath += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n strokePath += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n } else {\n // Exclude left edge\n strokePath = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n strokePath += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight)\n strokePath += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n strokePath += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight)\n strokePath += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n strokePath += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft)\n strokePath += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n strokePath += ` M ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) strokePath += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n\n return svg`\n <path d=${path} fill=${fillColor} stroke=\"none\"/>\n <path d=\"${strokePath}\" fill=\"none\" stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n `;\n }\n\n return svg`<path d=${path} fill=${fillColor} stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n // Horizontal: bar spans full drawing length (x), thickness is y\n let rectX = mainAxisOffset(config);\n let rectY = isOutwardPositive(config) ? 0 : -config.barThickness;\n let rectWidth = dLen;\n let rectHeight = config.barThickness;\n\n const isBottom = config.side === 'bottom';\n let viewBoxMinY: number;\n let viewBoxMaxY: number;\n if (config.scaleBackground) {\n // Exclude the edge that touches the scale from stroke adjustment\n if (isBottom) {\n // Bottom side: bar is at y=0..barThickness, scale touches bottom edge\n // Only adjust top edge (viewBoxMinY=0), don't adjust bottom edge\n viewBoxMinY = 0;\n viewBoxMaxY = config.barThickness + 1; // +1 so rectY+rectHeight won't match\n } else {\n // Top side: bar is at y=-barThickness..0, scale touches top edge\n // Only adjust bottom edge (viewBoxMaxY=0), don't adjust top edge\n viewBoxMinY = -config.barThickness - 1; // -1 so rectY won't match\n viewBoxMaxY = 0;\n }\n } else {\n viewBoxMinY = isBottom ? 0 : -config.barThickness;\n viewBoxMaxY = isBottom ? config.barThickness : 0;\n }\n\n // Adjust along x boundaries using adjustRectWidthForStroke (x=0..dLen in local band)\n const adjustedX = adjustRectWidthForStroke(\n rectX,\n rectWidth,\n rectX,\n rectX + rectWidth,\n strokeWidth\n );\n rectX = adjustedX.x;\n rectWidth = adjustedX.width;\n\n const adjustedY = adjustRectHeightForStroke(\n rectY,\n rectHeight,\n viewBoxMinY,\n viewBoxMaxY,\n strokeWidth\n );\n rectY = adjustedY.y;\n rectHeight = adjustedY.height;\n\n // Use simple rect when all corners or no corners are rounded\n if (allCornersRounded || noCornersRounded) {\n const rx = allCornersRounded ? r : 0;\n const ry = allCornersRounded ? r : 0;\n\n if (config.scaleBackground) {\n // When scaleBackground=true, draw fill and stroke separately to exclude edge touching scale\n const isBottom = config.side === 'bottom';\n\n // Stroke path excludes the edge touching the scale\n let strokePath: string;\n if (isBottom) {\n // Exclude bottom edge (touching scale on bottom side)\n strokePath = `M ${rectX + (noCornersRounded ? 0 : r)} ${rectY}`; // Top edge start\n strokePath += ` L ${rectX + rectWidth - (noCornersRounded ? 0 : r)} ${rectY}`; // Top edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY} ${rectX + rectWidth} ${rectY + r}`; // Top-right corner\n strokePath += ` L ${rectX + rectWidth} ${rectY + rectHeight - (noCornersRounded ? 0 : r)}`; // Right edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY + rectHeight} ${rectX + rectWidth - r} ${rectY + rectHeight}`; // Bottom-right corner (no stroke)\n strokePath += ` M ${rectX + (noCornersRounded ? 0 : r)} ${rectY + rectHeight}`; // Move to bottom-left (no stroke on bottom edge)\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY + rectHeight} ${rectX} ${rectY + rectHeight - r}`; // Bottom-left corner (no stroke)\n strokePath += ` L ${rectX} ${rectY + (noCornersRounded ? 0 : r)}`; // Left edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY} ${rectX + r} ${rectY}`; // Top-left corner\n } else {\n // Exclude top edge (touching scale on top side)\n strokePath = `M ${rectX} ${rectY + (noCornersRounded ? 0 : r)}`; // Left edge start\n strokePath += ` L ${rectX} ${rectY + rectHeight - (noCornersRounded ? 0 : r)}`; // Left edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY + rectHeight} ${rectX + r} ${rectY + rectHeight}`; // Bottom-left corner\n strokePath += ` L ${rectX + rectWidth - (noCornersRounded ? 0 : r)} ${rectY + rectHeight}`; // Bottom edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY + rectHeight} ${rectX + rectWidth} ${rectY + rectHeight - r}`; // Bottom-right corner\n strokePath += ` L ${rectX + rectWidth} ${rectY + (noCornersRounded ? 0 : r)}`; // Right edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY} ${rectX + rectWidth - r} ${rectY}`; // Top-right corner (no stroke)\n strokePath += ` M ${rectX + (noCornersRounded ? 0 : r)} ${rectY}`; // Move to top edge start (no stroke on top edge)\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY} ${rectX} ${rectY + r}`; // Top-left corner (no stroke)\n }\n\n return svg`\n <rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${rx} ry=${ry} fill=${fillColor} stroke=\"none\"/>\n <path d=\"${strokePath}\" fill=\"none\" stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n `;\n }\n\n return svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${rx} ry=${ry} fill=${fillColor} stroke=${strokeColor} vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n // Use path for selective corner rounding\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n let path = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n\n // When scaleBackground=true, draw fill and stroke separately to exclude edge touching scale\n if (config.scaleBackground) {\n const isBottom = config.side === 'bottom';\n\n // Stroke path excludes the edge touching the scale\n let strokePath: string;\n if (isBottom) {\n // Exclude bottom edge\n strokePath = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n strokePath += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight)\n strokePath += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n strokePath += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight)\n strokePath += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n strokePath += ` M ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft)\n strokePath += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n strokePath += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) strokePath += ` Q ${x} ${y} ${x + r} ${y}`;\n } else {\n // Exclude top edge\n strokePath = `M ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) strokePath += ` Q ${x} ${y} ${x + r} ${y}`;\n strokePath += ` M ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight)\n strokePath += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n strokePath += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight)\n strokePath += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n strokePath += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft)\n strokePath += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n strokePath += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n }\n\n return svg`\n <path d=${path} fill=${fillColor} stroke=\"none\"/>\n <path d=\"${strokePath}\" fill=\"none\" stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n `;\n }\n\n return svg`<path d=${path} fill=${fillColor} stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>`;\n}\n\nfunction generateBarFill(\n config: ExternalScaleConfig\n): SVGTemplateResult | typeof nothing {\n if (!config.hasBar || config.value === undefined) return nothing;\n\n // NOTE:\n // The bar container can have a larger radius (driven by component size CSS vars).\n // When the fill segment is short, rounding the fill geometry directly must clamp the\n // radius to avoid self-intersection, which makes the fill appear to ignore the larger\n // radius. Instead, render the fill as a plain rect and clip it with the exact same\n // shape as the bar container so the visible corners always match.\n\n // Clip-path id: only needs to be unique within the current <svg>.\n const clipId = `obc-bar-fill-clip-${Math.random().toString(36).slice(2)}`;\n\n const borderRadiusFallback = config.scaleType === 'condensed' ? 4 : 8;\n const borderRadiusValue = config.borderRadius ?? borderRadiusFallback;\n const r = borderRadiusValue;\n\n const c = colors(config);\n\n // Always use fillMin → fillMax range (defaults to 0 → value if not specified)\n const fillMin = config.fillMin ?? 0;\n const fillMax = config.fillMax ?? config.value;\n\n const v0 = Math.max(Math.min(fillMin, config.maxValue), config.minValue);\n const v1 = Math.max(Math.min(fillMax, config.maxValue), config.minValue);\n\n const a0 = valueToMainAxis(config, v0);\n const a1 = valueToMainAxis(config, v1);\n\n const markerSize = 8;\n const markerR = 4;\n\n // Build the same bar container shape (radius-position aware) for clipping.\n // Keep this logic aligned with generateBarContainer(), but do not modify the container.\n // Note: No stroke adjustment needed - fill should span the entire bar including borders.\n const dLen = drawingLength(config);\n const axisShift = mainAxisOffset(config);\n\n let barRoundTopLeft = true;\n let barRoundTopRight = true;\n let barRoundBottomLeft = true;\n let barRoundBottomRight = true;\n\n if (config.borderRadiusPosition) {\n if (\n config.borderRadiusPosition === BorderRadiusPosition.middleChild ||\n config.borderRadiusPosition === BorderRadiusPosition.middleRoundedChild\n ) {\n // No rounded corners for middle child\n // (middleRoundedChild is chart-canvas-only; ignored for external scales)\n barRoundTopLeft = false;\n barRoundTopRight = false;\n barRoundBottomLeft = false;\n barRoundBottomRight = false;\n } else if (isVertical(config)) {\n const isRight = config.side === 'right';\n const isInner =\n config.borderRadiusPosition === BorderRadiusPosition.innerFirstChild;\n\n if (isRight) {\n barRoundTopLeft = isInner;\n barRoundBottomLeft = isInner;\n barRoundTopRight = !isInner;\n barRoundBottomRight = !isInner;\n } else {\n barRoundTopLeft = !isInner;\n barRoundBottomLeft = !isInner;\n barRoundTopRight = isInner;\n barRoundBottomRight = isInner;\n }\n } else {\n const isBottom = config.side === 'bottom';\n const isInner =\n config.borderRadiusPosition === BorderRadiusPosition.innerFirstChild;\n\n if (isBottom) {\n barRoundTopLeft = isInner;\n barRoundTopRight = isInner;\n barRoundBottomLeft = !isInner;\n barRoundBottomRight = !isInner;\n } else {\n barRoundTopLeft = !isInner;\n barRoundTopRight = !isInner;\n barRoundBottomLeft = isInner;\n barRoundBottomRight = isInner;\n }\n }\n }\n\n const barAllCornersRounded =\n barRoundTopLeft &&\n barRoundTopRight &&\n barRoundBottomLeft &&\n barRoundBottomRight;\n const barNoCornersRounded =\n !barRoundTopLeft &&\n !barRoundTopRight &&\n !barRoundBottomLeft &&\n !barRoundBottomRight;\n\n if (isVertical(config)) {\n const boxX = isOutwardPositive(config) ? 0 : -config.barThickness;\n const boxWidth = config.barThickness;\n const y = Math.min(a0, a1);\n const h = Math.abs(a1 - a0);\n\n // Clip shape for the full bar container (no stroke adjustment - fill should\n // span the entire bar including borders, the clip constrains it visually)\n const rectX = isOutwardPositive(config) ? 0 : -config.barThickness;\n const rectY = -dLen / 2 + axisShift;\n const rectWidth = config.barThickness;\n const rectHeight = dLen;\n\n const barClipShape = barNoCornersRounded\n ? svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${0} ry=${0}/>`\n : barAllCornersRounded\n ? svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${r} ry=${r}/>`\n : svg`<path d=${(() => {\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n let path = `M ${x + (barRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (barRoundTopRight ? r : 0)} ${y}`;\n if (barRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (barRoundBottomRight ? r : 0)}`;\n if (barRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (barRoundBottomLeft ? r : 0)} ${y + h}`;\n if (barRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (barRoundTopLeft ? r : 0)}`;\n if (barRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n return path;\n })()}/>`;\n\n const fillRect = svg`<rect x=${boxX} y=${y} width=${boxWidth} height=${h} fill=${c.barFillColor} stroke=\"none\"/>`;\n\n // For tint mode, render marker at value position\n if (config.fillMode === 'tint') {\n const markerY = valueToMainAxis(config, config.value) - markerSize / 2;\n const marker = svg`<rect x=${boxX} y=${markerY} width=${boxWidth} height=${markerSize} rx=${markerR} fill=${c.markerFillColor} stroke=${c.markerStrokeColor} vector-effect=\"non-scaling-stroke\"/>`;\n\n return svg`<defs>\n <clipPath id=${clipId} clipPathUnits=\"userSpaceOnUse\">${barClipShape}</clipPath>\n </defs>\n <g clip-path=${`url(#${clipId})`}>\n ${fillRect}\n ${marker}\n </g>`;\n }\n\n return svg`<defs>\n <clipPath id=${clipId} clipPathUnits=\"userSpaceOnUse\">${barClipShape}</clipPath>\n </defs>\n <g clip-path=${`url(#${clipId})`}>\n ${fillRect}\n </g>`;\n }\n\n // Horizontal orientation\n const boxY = isOutwardPositive(config) ? 0 : -config.barThickness;\n const boxHeight = config.barThickness;\n const x = Math.min(a0, a1);\n const w = Math.abs(a1 - a0);\n\n // Clip shape for the full bar container (no stroke adjustment - fill should\n // span the entire bar including borders, the clip constrains it visually)\n const rectX = mainAxisOffset(config);\n const rectY = isOutwardPositive(config) ? 0 : -config.barThickness;\n const rectWidth = dLen;\n const rectHeight = config.barThickness;\n\n const barClipShape = barNoCornersRounded\n ? svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${0} ry=${0}/>`\n : barAllCornersRounded\n ? svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${r} ry=${r}/>`\n : svg`<path d=${(() => {\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n let path = `M ${x + (barRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (barRoundTopRight ? r : 0)} ${y}`;\n if (barRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (barRoundBottomRight ? r : 0)}`;\n if (barRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (barRoundBottomLeft ? r : 0)} ${y + h}`;\n if (barRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (barRoundTopLeft ? r : 0)}`;\n if (barRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n return path;\n })()}/>`;\n\n const fillRect = svg`<rect x=${x} y=${boxY} width=${w} height=${boxHeight} fill=${c.barFillColor} stroke=\"none\"/>`;\n\n // For tint mode, render marker at value position\n if (config.fillMode === 'tint') {\n const markerX = valueToMainAxis(config, config.value) - markerSize / 2;\n const marker = svg`<rect x=${markerX} y=${boxY} width=${markerSize} height=${boxHeight} rx=${markerR} fill=${c.markerFillColor} stroke=${c.markerStrokeColor} vector-effect=\"non-scaling-stroke\"/>`;\n return svg`<defs>\n <clipPath id=${clipId} clipPathUnits=\"userSpaceOnUse\">${barClipShape}</clipPath>\n </defs>\n <g clip-path=${`url(#${clipId})`}>\n ${fillRect}\n ${marker}\n </g>`;\n }\n\n return svg`<defs>\n <clipPath id=${clipId} clipPathUnits=\"userSpaceOnUse\">${barClipShape}</clipPath>\n </defs>\n <g clip-path=${`url(#${clipId})`}>\n ${fillRect}\n </g>`;\n}\n\nfunction generateScaleBackground(\n config: ExternalScaleConfig\n): SVGTemplateResult | typeof nothing {\n if (!config.scaleBackground) return nothing;\n\n const borderRadiusFallback = config.scaleType === 'condensed' ? 4 : 8;\n const borderRadiusValue = config.borderRadius ?? borderRadiusFallback;\n const strokeWidth = 1;\n const fillColor = 'var(--instrument-frame-primary-color)';\n const strokeColor = 'var(--instrument-frame-tertiary-color)';\n\n // Calculate thickness: main tick length + 4px gap\n const {main} = getTickThicknesses(config.scaleType);\n const backgroundThickness = main + tickGap();\n\n const dLen = drawingLength(config);\n const axisShift = mainAxisOffset(config);\n\n // Determine which corners should be rounded (outer corners only)\n const shouldRoundTopLeft =\n (config.orientation === 'vertical' && config.side === 'left') ||\n (config.orientation === 'horizontal' && config.side === 'top');\n const shouldRoundTopRight =\n (config.orientation === 'vertical' && config.side === 'right') ||\n (config.orientation === 'horizontal' && config.side === 'top');\n const shouldRoundBottomLeft =\n (config.orientation === 'vertical' && config.side === 'left') ||\n (config.orientation === 'horizontal' && config.side === 'bottom');\n const shouldRoundBottomRight =\n (config.orientation === 'vertical' && config.side === 'right') ||\n (config.orientation === 'horizontal' && config.side === 'bottom');\n\n const r = borderRadiusValue;\n\n if (isVertical(config)) {\n // Start at bar's outer edge if bar exists, otherwise at chart edge (0)\n const startPerp = config.hasBar\n ? isOutwardPositive(config)\n ? config.barThickness\n : -config.barThickness\n : 0;\n\n let rectX = isOutwardPositive(config)\n ? startPerp\n : startPerp - backgroundThickness;\n let rectY = -dLen / 2 + axisShift;\n let rectWidth = backgroundThickness;\n let rectHeight = dLen;\n\n const isRight = config.side === 'right';\n let viewBoxMinX: number;\n let viewBoxMaxX: number;\n if (config.hasBar) {\n // Exclude the inner edge (touching bar) from stroke adjustment\n if (isRight) {\n // Right side: scale is at x=barThickness..(barThickness+backgroundThickness)\n // Inner edge is left (at barThickness), don't adjust it\n viewBoxMinX = rectX - 1; // -1 so rectX won't match\n viewBoxMaxX = rectX + rectWidth;\n } else {\n // Left side: scale is at x=(-barThickness-backgroundThickness)..(-barThickness)\n // Inner edge is right (at -barThickness), don't adjust it\n viewBoxMinX = rectX;\n viewBoxMaxX = rectX + rectWidth + 1; // +1 so rectX+rectWidth won't match\n }\n } else {\n viewBoxMinX = rectX;\n viewBoxMaxX = rectX + rectWidth;\n }\n\n const adjustedX = adjustRectWidthForStroke(\n rectX,\n rectWidth,\n viewBoxMinX,\n viewBoxMaxX,\n strokeWidth\n );\n rectX = adjustedX.x;\n rectWidth = adjustedX.width;\n\n const adjustedY = adjustRectHeightForStroke(\n rectY,\n rectHeight,\n -dLen / 2 + axisShift,\n dLen / 2 + axisShift,\n strokeWidth\n );\n rectY = adjustedY.y;\n rectHeight = adjustedY.height;\n\n // Build path with selective rounded corners\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n // Path construction: start top-left, go clockwise\n let path = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n\n // Stroke the entire path, then cover the inner edge with a line\n // Line is shortened by half-stroke on each end to avoid overlapping with top/bottom strokes\n const innerX = isRight ? x : x + w;\n const halfStroke = strokeWidth / 2;\n\n return svg`<path d=${path} fill=${fillColor} stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n <line x1=${innerX} x2=${innerX} y1=${y + halfStroke} y2=${y + h - halfStroke} stroke=${fillColor} stroke-width=${strokeWidth + 0.5} vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n // Horizontal: background spans full drawing length (x), thickness is y\n const startPerp = config.hasBar\n ? isOutwardPositive(config)\n ? config.barThickness\n : -config.barThickness\n : 0;\n\n let rectX = mainAxisOffset(config);\n let rectY = isOutwardPositive(config)\n ? startPerp\n : startPerp - backgroundThickness;\n let rectWidth = dLen;\n let rectHeight = backgroundThickness;\n\n const isBottom = config.side === 'bottom';\n let viewBoxMinY: number;\n let viewBoxMaxY: number;\n if (config.hasBar) {\n // Exclude the inner edge (touching bar) from stroke adjustment\n if (isBottom) {\n // Bottom side: scale is at y=barThickness..(barThickness+backgroundThickness)\n // Inner edge is top (at barThickness), don't adjust it\n viewBoxMinY = rectY - 1; // -1 so rectY won't match\n viewBoxMaxY = rectY + rectHeight;\n } else {\n // Top side: scale is at y=(-barThickness-backgroundThickness)..(-barThickness)\n // Inner edge is bottom (at -barThickness), don't adjust it\n viewBoxMinY = rectY;\n viewBoxMaxY = rectY + rectHeight + 1; // +1 so rectY+rectHeight won't match\n }\n } else {\n viewBoxMinY = rectY;\n viewBoxMaxY = rectY + rectHeight;\n }\n\n // Adjust along x boundaries\n const adjustedX = adjustRectWidthForStroke(\n rectX,\n rectWidth,\n rectX,\n rectX + rectWidth,\n strokeWidth\n );\n rectX = adjustedX.x;\n rectWidth = adjustedX.width;\n\n const adjustedY = adjustRectHeightForStroke(\n rectY,\n rectHeight,\n viewBoxMinY,\n viewBoxMaxY,\n strokeWidth\n );\n rectY = adjustedY.y;\n rectHeight = adjustedY.height;\n\n // Build path with selective rounded corners\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n // Path construction: start top-left, go clockwise\n let path = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n\n // Stroke the entire path, then cover the inner edge with a line\n // Line is shortened by half-stroke on each end to avoid overlapping with left/right strokes\n const innerY = isBottom ? y : y + h;\n const halfStroke = strokeWidth / 2;\n\n return svg`<path d=${path} fill=${fillColor} stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n <line x1=${x + halfStroke} x2=${x + w - halfStroke} y1=${innerY} y2=${innerY} stroke=${fillColor} stroke-width=${strokeWidth + 0.5} vector-effect=\"non-scaling-stroke\"/>`;\n}\n\n// ============================================================================\n// Setpoint Marker (uses unified setpoint interface from svghelpers/setpoint.ts)\n// ============================================================================\n\n/**\n * Calculate the rotation angle needed for the setpoint marker based on\n * orientation and side.\n *\n * The `drawSetpointMarker()` renders the marker with tip at origin pointing\n * down (positive Y direction). We need to rotate it so the tip points toward\n * the bar/chart area.\n *\n * Transform table:\n * | Orientation | Side | Marker Points | Rotation |\n * |-------------|--------|---------------|----------|\n * | vertical | right | ← (left) | 90° |\n * | vertical | left | → (right) | -90° |\n * | horizontal | bottom | ↑ (up) | 180° |\n * | horizontal | top | ↓ (down) | 0° |\n */\nfunction getSetpointRotation(config: ExternalScaleConfig): number {\n if (isVertical(config)) {\n // Vertical: right side points left (90°), left side points right (-90°)\n return config.side === 'right' ? 90 : -90;\n }\n // Horizontal: bottom points up (180°), top points down (0°)\n return config.side === 'bottom' ? 180 : 0;\n}\n\n/**\n * Helper to render a single setpoint marker at a given value.\n *\n * @param config - Scale configuration\n * @param setpointValue - The value to position the marker at\n * @param visualState - The visual state for the marker\n * @param colorMode - The color mode for the marker\n * @param disabled - Whether the setpoint is in disabled state\n * @param idSuffix - Suffix for the unique ID\n * @param opacity - Optional opacity (default 1)\n * @param animate - Whether to apply CSS transition for smooth movement\n */\nfunction renderSingleSetpoint(\n config: ExternalScaleConfig,\n setpointValue: number,\n visualState: SetpointVisualState,\n colorMode: SetpointColorMode,\n disabled: boolean,\n idSuffix: string,\n opacity: number = 1,\n animate: boolean = false\n): SVGTemplateResult {\n // Generate unique ID to avoid conflicts with multiple instruments on page\n const baseId = generateSetpointId(`external-scale-setpoint-${idSuffix}`);\n\n // Get outward offset based on visual state (drawSetpointMarker handles scaling internally)\n const stateOffset = getSetpointOutwardOffset(visualState);\n\n // Check if setpoint snaps to zero\n const setpointAtZero =\n Math.abs(setpointValue) < config.setpointAtZeroDeadband;\n\n // Main axis position (where the marker sits along the scale)\n // Always use valueToMainAxis — even for zero-snap, since coordinate 0\n // only equals value 0 for symmetric bipolar scales (e.g. -100..+100).\n // For non-symmetric scales (e.g. 0..100), value 0 maps to a non-zero coordinate.\n const mainAxisPos = setpointAtZero\n ? valueToMainAxis(config, 0)\n : valueToMainAxis(config, setpointValue);\n\n // Perpendicular axis position (distance from chart edge)\n const base = tickBasePerp(config);\n const outwardOffset = tickGap(); // Base offset from tick area\n\n // Add state-based offset (shifts marker further outward for notEqual/focus/equalZero states)\n const totalOutwardOffset = outwardOffset + stateOffset;\n\n const perpAxisPos = isOutwardPositive(config)\n ? base + totalOutwardOffset\n : base - totalOutwardOffset;\n\n // Get rotation angle for this orientation/side\n const rotation = getSetpointRotation(config);\n\n // Build the transform string\n // Position first, then rotate around the tip (which is at origin after drawSetpointMarker)\n const x = isVertical(config) ? perpAxisPos : mainAxisPos;\n const y = isVertical(config) ? mainAxisPos : perpAxisPos;\n\n // Note: drawSetpointMarker() handles scaling internally based on visualState\n if (animate) {\n // Use CSS style transform + transition for animated movement.\n // CSS `transform` on SVG elements uses the local coordinate system\n // (1px = 1 SVG user unit). `transform-origin: 0 0` is the default for\n // SVG elements per spec, matching SVG attribute behavior.\n const duration = `var(${SETPOINT_ANIMATION_CSS_VAR}, ${SETPOINT_ANIMATION_DURATION_DEFAULT})`;\n return svg`\n <g style=\"transform: translate(${x}px, ${y}px) rotate(${rotation}deg); opacity: ${opacity}; transition: transform ${duration} ease-out, opacity ${duration} ease-out;\">\n ${drawSetpointMarker({visualState, colorMode, disabled, id: baseId})}\n </g>\n `;\n }\n\n return svg`\n <g transform=\"translate(${x}, ${y}) rotate(${rotation})\" opacity=\"${opacity}\">\n ${drawSetpointMarker({visualState, colorMode, disabled, id: baseId})}\n </g>\n `;\n}\n\n/**\n * Render the setpoint marker(s) using the unified interface from setpoint.ts.\n *\n * When `newSetpoint` is defined, renders two markers:\n * 1. Original setpoint at 0.75 opacity (dimmed)\n * 2. New setpoint in 'focus' visual state at full opacity (on top)\n *\n * When `animateSetpoint` is true:\n * - The original marker uses CSS `transition` for smooth position/opacity changes\n * - During confirm (newSetpoint → undefined), the departing new-setpoint marker\n * fades out via CSS transition (opacity 1 → 0) over the animation duration\n *\n * The marker is positioned on the scale based on the setpoint value,\n * with transforms applied for orientation/side.\n */\nfunction setpointMarker(\n config: ExternalScaleConfig\n): SVGTemplateResult | typeof nothing {\n const hasOriginalSetpoint = config.setpoint !== undefined;\n const hasNewSetpoint = config.newSetpoint !== undefined;\n const hasDepartingNewSetpoint = config.departingNewSetpoint !== undefined;\n const animate = config.animateSetpoint === true;\n\n // If neither setpoint is defined (and no departing animation), render nothing\n if (!hasOriginalSetpoint && !hasNewSetpoint && !hasDepartingNewSetpoint)\n return nothing;\n\n const markers: SVGTemplateResult[] = [];\n\n // Render original setpoint (dimmed when newSetpoint is active)\n if (hasOriginalSetpoint) {\n const visualState = deriveSetpointVisualState(config);\n const colorMode = deriveSetpointColorMode(config);\n const disabled = deriveSetpointDisabled(config);\n const opacity = hasNewSetpoint ? 0.75 : 1;\n\n markers.push(\n renderSingleSetpoint(\n config,\n config.setpoint!,\n visualState,\n colorMode,\n disabled,\n 'original',\n opacity,\n animate\n )\n );\n }\n\n // Render newSetpoint in focus state (always on top)\n // OR render departing newSetpoint during confirm animation (fading to 0 opacity)\n if (hasNewSetpoint || hasDepartingNewSetpoint) {\n const isActive = hasNewSetpoint;\n const value = isActive ? config.newSetpoint! : config.departingNewSetpoint!;\n const targetOpacity = isActive ? 1 : 0; // fade to 0 during confirm animation\n\n // newSetpoint always renders in focus visual state\n const visualState = SetpointVisualState.focus;\n // Use the same color mode derivation for new setpoint\n const colorMode = deriveSetpointColorMode(config);\n // newSetpoint is never disabled (it's the active adjustment target)\n const disabled = false;\n\n markers.push(\n renderSingleSetpoint(\n config,\n value,\n visualState,\n colorMode,\n disabled,\n 'new',\n targetOpacity,\n animate\n )\n );\n }\n\n return svg`${markers}`;\n}\n\n/**\n * Generate a dot indicator at the current value position.\n *\n * The dot is:\n * - 12x12px filled circle with 2px stroke (16px total visual size)\n * - Positioned in the scale band, touching its inner edge (towards the chart)\n * - Fill uses secondary color (enhanced or regular based on config.priority)\n * - Stroke uses --instrument-frame-primary-color\n *\n * @param config - Scale configuration\n * @returns SVG template for the current value dot, or nothing if disabled/no value\n */\nfunction generateCurrentValueDot(\n config: ExternalScaleConfig\n): SVGTemplateResult | typeof nothing {\n // The dot is positioned in the scale band. When hasScale=false, the layout\n // thickness excludes the scale band, so the dot would render outside the\n // viewBox and be clipped. Skip rendering in that case.\n if (\n !config.highlightCurrentValue ||\n config.value === undefined ||\n !config.hasScale\n ) {\n return nothing;\n }\n\n const dotDiameter = 12; // Inner fill diameter\n const strokeWidth = 2;\n // Total visual size: stroke is centered on path, so adds strokeWidth/2 to each side\n // Visual radius = fillRadius + strokeWidth/2 = 6 + 1 = 7\n const visualRadius = dotDiameter / 2 + strokeWidth / 2;\n const dotRadius = dotDiameter / 2;\n\n // Position on main axis (value to coordinate)\n const pos = valueToMainAxis(config, config.value);\n\n // Position on perpendicular axis:\n // The dot should be in the scale band, touching its inner edge (towards the chart/bar)\n //\n // The scale background (when shown) spans from barEdge to barEdge+backgroundThickness\n // where backgroundThickness = mainTickLength + gap (e.g., 10+4=14 for condensed)\n //\n // For the dot to touch the INNER edge (toward chart) and stay INSIDE the scale band:\n // - Inner edge of scale background = barEdge (or 0 if no bar)\n // - Dot's inner edge should be at the inner edge of the scale band\n // - So dot center = innerEdge + visualRadius\n const base = tickBasePerp(config);\n\n // Dot center should be positioned so the dot's inner edge touches the scale band's inner edge\n const perpCenter = isOutwardPositive(config)\n ? base + visualRadius\n : base - visualRadius;\n\n const c = colors(config);\n // Use secondary color for fill (same as markerFillColor from colors function)\n const fillColor = c.markerFillColor;\n const strokeColor = 'var(--instrument-frame-primary-color)';\n\n // Render the dot\n if (isVertical(config)) {\n return svg`\n <circle\n cx=${perpCenter}\n cy=${pos}\n r=${dotRadius}\n fill=${fillColor}\n stroke=${strokeColor}\n stroke-width=${strokeWidth}\n vector-effect=\"non-scaling-stroke\"\n />\n `;\n }\n\n // Horizontal orientation\n return svg`\n <circle\n cx=${pos}\n cy=${perpCenter}\n r=${dotRadius}\n fill=${fillColor}\n stroke=${strokeColor}\n stroke-width=${strokeWidth}\n vector-effect=\"non-scaling-stroke\"\n />\n `;\n}\n\nfunction singleSidedTickmark(\n config: ExternalScaleConfig,\n value: number,\n style: TickmarkStyle,\n tickBase: number\n): SVGTemplateResult | null {\n if (value >= config.maxValue || value <= config.minValue) return null;\n\n const color = tickmarkColor(style);\n const pos = valueToMainAxis(config, value);\n\n const gap = tickGap();\n const start = isOutwardPositive(config) ? tickBase + gap : tickBase - gap;\n const len = computeExternalScaleEffectiveTickThickness(config);\n const end = isOutwardPositive(config) ? start + len : start - len;\n\n if (isVertical(config)) {\n return svg`<line x1=${start} x2=${end} y1=${pos} y2=${pos} stroke=${color} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n return svg`<line x1=${pos} x2=${pos} y1=${start} y2=${end} stroke=${color} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\"/>`;\n}\n\nfunction advicePill(\n config: ExternalScaleConfig,\n advice: ExternalScaleAdviceRaw,\n x1: number,\n fill: string,\n stroke: string\n): SVGTemplateResult {\n const width = 8;\n const offset = 4;\n const r = width / 2;\n const inset = 4;\n\n if (isVertical(config)) {\n const yMin = valueToMainAxis(config, advice.min);\n const yMax = valueToMainAxis(config, advice.max);\n const yL = Math.min(yMin, yMax);\n const yH = Math.max(yMin, yMax);\n\n const x = x1 + offset;\n const y = yL + inset;\n const h = Math.max(0, yH - yL - inset * 2);\n\n return svg`<rect x=${x} y=${y} width=${width} height=${h} rx=${r} ry=${r} fill=${fill} stroke=${stroke} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n const xMin = valueToMainAxis(config, advice.min);\n const xMax = valueToMainAxis(config, advice.max);\n const xL = Math.min(xMin, xMax);\n const xH = Math.max(xMin, xMax);\n\n const x = xL + inset;\n const y = x1 + offset;\n const w = Math.max(0, xH - xL - inset * 2);\n\n return svg`<rect x=${x} y=${y} width=${w} height=${width} rx=${r} ry=${r} fill=${fill} stroke=${stroke} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\"/>`;\n}\n\nfunction renderAdvice(\n config: ExternalScaleConfig,\n advice: ExternalScaleAdviceRaw\n): SVGTemplateResult {\n const tickBase = tickBasePerp(config);\n const hasBarArea = config.hasBar;\n const effectiveAdvicePosition = hasBarArea ? config.advicePosition : 'inner';\n\n // Determine x1 (perpendicular) position for the 8px mask\n let x1: number;\n\n if (effectiveAdvicePosition === 'center') {\n const adviceWidth = 8;\n const centerOffset = config.barThickness / 2 - adviceWidth / 2;\n\n if (isVertical(config)) {\n x1 = isOutwardPositive(config)\n ? centerOffset - 4\n : -config.barThickness + centerOffset - 4;\n } else {\n x1 = isOutwardPositive(config)\n ? centerOffset - 4\n : -config.barThickness + centerOffset - 4;\n }\n } else if (effectiveAdvicePosition === 'inner') {\n x1 = isOutwardPositive(config) ? tickBase : tickBase - 16;\n } else {\n x1 = isOutwardPositive(config)\n ? config.barThickness + 10\n : -config.barThickness -\n computeExternalScaleEffectiveTickThickness(config) +\n 14;\n }\n\n // Dashed boundary tickmarks across the bar band\n const ticks: SVGTemplateResult[] = [];\n\n const dashStroke = 'var(--instrument-frame-tertiary-color)';\n\n const minBound = advice.min > config.minValue;\n const maxBound = advice.max < config.maxValue;\n\n const barStart = isOutwardPositive(config) ? 0 : -config.barThickness;\n const barEnd = isOutwardPositive(config) ? config.barThickness : 0;\n\n const dash = (v: number) => {\n const p = valueToMainAxis(config, v);\n if (isVertical(config)) {\n ticks.push(\n svg`<line x1=${barStart} x2=${barEnd} y1=${p} y2=${p} stroke=${dashStroke} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\" stroke-dasharray=\"4 4\"/>`\n );\n } else {\n ticks.push(\n svg`<line x1=${p} x2=${p} y1=${barStart} y2=${barEnd} stroke=${dashStroke} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\" stroke-dasharray=\"4 4\"/>`\n );\n }\n };\n\n if (minBound) dash(advice.min);\n if (maxBound) dash(advice.max);\n\n if (advice.type === AdviceType.caution) {\n let mainColor: string;\n let fillColor: string = 'var(--instrument-frame-primary-color)';\n\n if (advice.state === AdviceState.hinted) {\n mainColor = 'var(--instrument-frame-tertiary-color)';\n } else if (advice.state === AdviceState.regular) {\n mainColor = 'var(--instrument-tick-mark-tertiary-color)';\n } else {\n mainColor = 'var(--on-caution-active-color)';\n fillColor = 'var(--alert-caution-color)';\n }\n\n const pattern: SVGTemplateResult[] = [];\n const ypattern = 50;\n\n const aMin = valueToMainAxis(config, advice.min);\n const aMax = valueToMainAxis(config, advice.max);\n const mainMin = Math.min(aMin, aMax);\n const mainMax = Math.max(aMin, aMax);\n const span = mainMax - mainMin;\n\n // Tile across the advice's main-axis span so hatch reaches the full advice region.\n if (isVertical(config)) {\n // Center the 50px tile on the 8px pill thickness.\n const xOffset = x1 + 8 - 25;\n // Start a bit before the advice, then tile across its full height.\n const yStart = mainMin - 25;\n\n for (let i = -64; i < span + 64; i += 16) {\n const transform = `translate(${xOffset} ${yStart + i})`;\n const path = `M 50 0 L 0 ${ypattern}`;\n pattern.push(\n svg`<g transform=${transform}><path d=${path} stroke=${mainColor} stroke-width=\"6\"/></g>`\n );\n }\n } else {\n // Center the 50px tile on the 8px pill thickness.\n const yOffset = x1 + 8 - 25;\n // Start a bit before the advice, then tile across its full width.\n const xStart = mainMin - 25;\n\n for (let i = -64; i < span + 64; i += 16) {\n const transform = `translate(${xStart + i} ${yOffset})`;\n const path = `M 0 50 L ${ypattern} 0`;\n pattern.push(\n svg`<g transform=${transform}><path d=${path} stroke=${mainColor} stroke-width=\"6\"/></g>`\n );\n }\n }\n\n const maskId = `externalScaleAdviceMask-${advice.min}-${advice.max}-${Math.random().toString(36).slice(2)}`;\n\n let tickmarkStyle = TickmarkStyle.regular;\n if (advice.state === AdviceState.regular)\n tickmarkStyle = TickmarkStyle.regular;\n else if (advice.state === AdviceState.triggered)\n tickmarkStyle = TickmarkStyle.enhanced;\n\n return svg`\n <defs>\n <mask id=${maskId} maskUnits=\"userSpaceOnUse\" maskContentUnits=\"userSpaceOnUse\" x=\"-4096\" y=\"-4096\" width=\"8192\" height=\"8192\">\n ${advicePill(config, advice, x1, 'white', 'none')}\n </mask>\n </defs>\n <g mask=\"url(#${maskId})\">\n ${\n fillColor\n ? svg`<rect x=\"-2048\" y=\"-2048\" width=\"4096\" height=\"4096\" fill=${fillColor}/>`\n : nothing\n }\n ${pattern}\n </g>\n ${advicePill(config, advice, x1, 'none', mainColor)}\n ${singleSidedTickmark(config, advice.min, tickmarkStyle, tickBase) ?? nothing}\n ${singleSidedTickmark(config, advice.max, tickmarkStyle, tickBase) ?? nothing}\n ${ticks}\n `;\n }\n\n // Advice type\n let strokeColor: string;\n let tickmarkStyle: TickmarkStyle;\n let fillColor: string;\n\n if (advice.state === AdviceState.hinted) {\n strokeColor = 'var(--instrument-frame-tertiary-color)';\n fillColor = 'var(--instrument-frame-primary-color)';\n tickmarkStyle = TickmarkStyle.regular;\n } else if (advice.state === AdviceState.regular) {\n strokeColor = 'var(--instrument-regular-secondary-color)';\n fillColor = 'var(--instrument-frame-primary-color)';\n tickmarkStyle = TickmarkStyle.regular;\n } else {\n strokeColor = 'var(--instrument-enhanced-secondary-color)';\n fillColor = strokeColor;\n tickmarkStyle = TickmarkStyle.regular;\n }\n\n return svg`\n ${advicePill(config, advice, x1, fillColor, strokeColor)}\n ${singleSidedTickmark(config, advice.min, tickmarkStyle, tickBase) ?? nothing}\n ${singleSidedTickmark(config, advice.max, tickmarkStyle, tickBase) ?? nothing}\n ${ticks}\n `;\n}\n\nfunction generateAdviceOverlays(\n config: ExternalScaleConfig\n): SVGTemplateResult[] {\n if (!config.advices || !config.advices.length) return [];\n const raw = convertAdvices(config.advices, config.setpoint);\n return raw.map((a) => renderAdvice(config, a));\n}\n\n/**\n * Helper for web components to compute dimensions for reporting to parent charts.\n *\n * This calculates the minimal configuration needed to determine the scale's thickness,\n * avoiding the need to pass full configs with many irrelevant properties.\n *\n * @param config - Minimal layout configuration\n * @returns Object with side and thickness for event dispatching\n */\nexport function computeScaleDimensionsForReport(\n config: ExternalScaleLayoutConfig\n): {side: ExternalScaleSide; thickness: number} {\n const layout = computeExternalScaleLayout(config);\n const viewBox = computeExternalScaleViewBox(\n {orientation: config.orientation, length: config.length},\n layout\n );\n\n // For vertical scales, thickness is width; for horizontal, it's height\n const thickness =\n config.orientation === 'vertical' ? viewBox.width : viewBox.height;\n\n return {\n side: config.side,\n thickness,\n };\n}\n\n/**\n * Render the external scale as SVG fragments.\n *\n * This is a pure renderer: it does not touch DOM state and expects the caller\n * to place the returned fragments inside an `<svg>` with an appropriate viewBox.\n *\n * @param config - Scale configuration\n */\nexport function renderExternalScale(config: ExternalScaleConfig): {\n barContainer: SVGTemplateResult | typeof nothing;\n barFill: SVGTemplateResult | typeof nothing;\n scaleBackground: SVGTemplateResult | typeof nothing;\n tickmarks: SVGTemplateResult[];\n labels: SVGTemplateResult[];\n adviceOverlays: SVGTemplateResult[];\n currentValueDot: SVGTemplateResult | typeof nothing;\n setpoint: SVGTemplateResult | typeof nothing;\n} {\n const effectiveBarThickness =\n computeExternalScaleEffectiveBarThickness(config);\n const effectiveConfig: ExternalScaleConfig =\n effectiveBarThickness === config.barThickness\n ? config\n : {...config, barThickness: effectiveBarThickness};\n\n const parts: {\n barContainer: SVGTemplateResult | typeof nothing;\n barFill: SVGTemplateResult | typeof nothing;\n scaleBackground: SVGTemplateResult | typeof nothing;\n tickmarks: SVGTemplateResult[];\n labels: SVGTemplateResult[];\n adviceOverlays: SVGTemplateResult[];\n currentValueDot: SVGTemplateResult | typeof nothing;\n setpoint: SVGTemplateResult | typeof nothing;\n } = {\n barContainer: generateBarContainer(effectiveConfig),\n barFill: generateBarFill(effectiveConfig),\n scaleBackground: generateScaleBackground(effectiveConfig),\n tickmarks: generateTickmarks(effectiveConfig),\n labels: generateLabels(effectiveConfig),\n adviceOverlays: generateAdviceOverlays(effectiveConfig),\n currentValueDot: generateCurrentValueDot(effectiveConfig),\n setpoint: setpointMarker(effectiveConfig),\n };\n\n return parts;\n}\n"],"names":["ExternalScaleOrientation","ExternalScaleSide","ScaleType","FillMode","AdvicePosition","BarContainerStyle","isOutwardPositive","x","y","isBottom","rectX","rectY","rectWidth","rectHeight","adjustedX","adjustedY","isRight","w","h","path","barClipShape","fillRect","startPerp","halfStroke","fillColor","tickmarkStyle"],"mappings":"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"}
1
+ {"version":3,"file":"external-scale.js","sources":["../../../src/building-blocks/external-scale/external-scale.ts"],"sourcesContent":["/**\n * @module External Scale\n *\n * # External Scale renderer (pure SVG building block)\n *\n * This module provides a side-aware, orientation-aware SVG “ruler/axis” renderer that can be used standalone, as an overlay axis for charts, or composed inside other components.\n *\n * Unlike Lit components, this file exports **pure functions** that return `SVGTemplateResult` fragments. Consumers are responsible for creating the outer `<svg>` element (including `viewBox`, sizing, and `preserveAspectRatio`).\n *\n * The module also exports a few small DOM helpers the web-component wrappers use to read CSS variables (border radius) and observe theme and size changes.\n *\n * ## What it renders\n * - **Bar container**: a rounded rectangle band (optional)\n * - **Bar fill**: value fill (0→value) or tinted range fill (fillMin→fillMax)\n * - **Tickmarks**: main + primary + secondary + tertiary tick lines (optional)\n * - **Labels**: numeric labels at primary tick interval (optional)\n * - **Advice overlays**: alert/advice/caution ranges with canonical dashed bounds\n * - **Setpoint marker**: a triangular marker that flips by side and scales when “at setpoint”\n *\n * ## Layout model\n * - `orientation`: `'vertical' | 'horizontal'` controls value→coordinate mapping\n * - `side`: where the scale attaches to the chart edge\n * - vertical: `'left' | 'right'`\n * - horizontal: `'top' | 'bottom'`\n * - The **chart edge is always at perpendicular coordinate `0`**. The scale expands outward into positive or negative perpendicular space depending on `side`.\n *\n * Use `computeExternalScaleLayout()` to compute the minimal viewBox thickness for the selected bands (bar/ticks/labels).\n *\n * ## Theming & responsive sizing\n * This renderer uses CSS variables directly in SVG attributes.\n *\n * It is designed to inherit theme and sizing variables from parent containers (e.g. `.obc-component-size-*` wrappers) the same way web components do.\n *\n * Common variables involved:\n * - `--global-typography-ui-label-font-size`\n * - `--instrument-frame-*-color`, `--instrument-*-*-color`\n * - `--instrument-components-watchface-frame-regular-border-radius`\n *\n * **Browser note (SVG geometry + CSS variables):**\n * Some browsers (notably Chrome) do not reliably resolve `var(--...)` inside SVG geometry attributes like `rx`/`ry`. The bar container and fill masks therefore provide numeric fallbacks and also set `rx`/`ry` via CSS geometry properties to allow theme overrides where supported.\n *\n * ## Usage examples\n *\n * ### Standalone usage\n * ```ts\n * import {html} from 'lit';\n * import {\n * computeExternalScaleLayout,\n * renderExternalScale,\n * ExternalScaleOrientation,\n * ExternalScaleSide,\n * ScaleType,\n * FillMode,\n * AdvicePosition,\n * type ExternalScaleConfig,\n * } from './external-scale.js';\n * import {FrameStyle, InstrumentState, Priority} from '../../navigation-instruments/types.js';\n * import {AdviceType} from '../../navigation-instruments/watch/advice.js';\n *\n * const config: ExternalScaleConfig = {\n * orientation: ExternalScaleOrientation.vertical,\n * side: ExternalScaleSide.right,\n * length: 320,\n * paddingStart: 32,\n * paddingEnd: 32,\n * minValue: 0,\n * maxValue: 100,\n * hasBar: true,\n * hasScale: true,\n * labels: true,\n * scaleBackground: false,\n * barThickness: 24,\n * tickThickness: 24,\n * labelThickness: 60,\n * mainTickmarks: [],\n * primaryTickmarkInterval: 20,\n * secondaryTickmarkInterval: 10,\n * tertiaryTickmarkInterval: 2,\n * scaleType: ScaleType.regular,\n * frameStyle: FrameStyle.regular,\n * priority: Priority.enhanced,\n * fillMode: FillMode.fill,\n * fillMin: 0,\n * fillMax: 40,\n * value: 40,\n * setpoint: 50,\n * atSetpoint: false,\n * autoAtSetpoint: true,\n * autoAtSetpointDeadband: 1,\n * setpointAtZeroDeadband: 0.5,\n * state: InstrumentState.active,\n * advicePosition: AdvicePosition.inner,\n * advices: [{min: 60, max: 80, type: AdviceType.caution, hinted: true}],\n * };\n *\n * const layout = computeExternalScaleLayout(config);\n * const parts = renderExternalScale(config);\n *\n * // Wrap returned fragments in an SVG.\n * const tpl = html`<svg\n * width=\"${layout.viewBoxThickness}px\"\n * height=\"${config.length}px\"\n * viewBox=\"${layout.viewBoxPerpStart} ${-config.length / 2} ${layout.viewBoxThickness} ${config.length}\"\n * preserveAspectRatio=\"none\"\n * >\n * ${parts.barContainer}\n * ${parts.barFill}\n * ${parts.scaleBackground}\n * ${parts.tickmarks}\n * ${parts.labels}\n * ${parts.adviceOverlays}\n * ${parts.setpoint}\n * </svg>`;\n * ```\n *\n * ### Web component wrappers\n * For common usage, prefer the thin wrappers:\n * - `obc-bar-vertical` (sets up vertical viewBox)\n * - `obc-bar-horizontal` (sets up horizontal viewBox)\n *\n * Source of truth: `packages/openbridge-webcomponents/src/building-blocks/external-scale/external-scale.ts`\n *\n * @experimental\n */\nimport {SVGTemplateResult, nothing, svg} from 'lit';\nimport {\n InstrumentState,\n Priority,\n FrameStyle,\n BorderRadiusPosition,\n} from '../../navigation-instruments/types.js';\nimport {\n AdviceState,\n AdviceType,\n} from '../../navigation-instruments/watch/advice.js';\nimport {\n tickmarkColor,\n TickmarkStyle,\n} from '../../navigation-instruments/watch/tickmark.js';\nimport {\n adjustRectWidthForStroke,\n adjustRectHeightForStroke,\n valueToX,\n valueToY,\n} from '../../svghelpers/stroke-aware.js';\nimport {\n SetpointVisualState,\n SetpointColorMode,\n drawSetpointMarker,\n generateSetpointId,\n getSetpointOutwardOffset,\n computeAtSetpoint,\n SETPOINT_ANIMATION_CSS_VAR,\n SETPOINT_ANIMATION_DURATION_DEFAULT,\n SETPOINT_HEIGHT,\n SETPOINT_ZERO_OFFSET,\n} from '../../svghelpers/setpoint.js';\n\n/** Main axis orientation for the external scale renderer. */\nexport enum ExternalScaleOrientation {\n vertical = 'vertical',\n horizontal = 'horizontal',\n}\n\n/** Which side of the chart area the scale is attached to. */\nexport enum ExternalScaleSide {\n left = 'left',\n right = 'right',\n top = 'top',\n bottom = 'bottom',\n}\n\n/** Tick density preset */\nexport enum ScaleType {\n regular = 'regular',\n condensed = 'condensed',\n}\n\n/** Fill visualization mode */\nexport enum FillMode {\n fill = 'fill',\n tint = 'tint',\n}\n\n/** Advice overlay position */\nexport enum AdvicePosition {\n center = 'center',\n inner = 'inner',\n outer = 'outer',\n}\n\n/**\n * Bar container background style.\n * Controls the background color of the bar container independently of scaleBackground.\n */\nexport enum BarContainerStyle {\n /** Use lighter primary color (--instrument-frame-primary-color) */\n primary = 'primary',\n /** Use darker secondary color (--instrument-frame-secondary-color) */\n secondary = 'secondary',\n}\n\n/** CSS variable used by component-size wrappers to define frame corner rounding. */\nexport const EXTERNAL_SCALE_BORDER_RADIUS_CSS_VAR =\n '--instrument-components-watchface-frame-regular-border-radius';\n\n/**\n * Parse a CSS length into pixels.\n *\n * Supports: `px`, `rem`, `em`, and unitless values (treated as px).\n * Returns `undefined` when parsing fails.\n */\nexport function parseCssLengthToPx(\n value: string,\n context?: {element?: Element; documentElement?: Element}\n): number | undefined {\n if (!value) return undefined;\n\n const v = value.trim();\n const n = Number.parseFloat(v);\n if (!Number.isFinite(n)) return undefined;\n\n if (v.endsWith('px')) return n;\n\n // Avoid throwing in non-DOM contexts (SSR/tests)\n const canComputeStyles = typeof getComputedStyle === 'function';\n\n if (v.endsWith('rem')) {\n if (!canComputeStyles) return undefined;\n const docEl =\n context?.documentElement ??\n (typeof document !== 'undefined' ? document.documentElement : undefined);\n if (!docEl) return undefined;\n const rootFontSize = Number.parseFloat(getComputedStyle(docEl).fontSize);\n return Number.isFinite(rootFontSize) ? n * rootFontSize : undefined;\n }\n\n if (v.endsWith('em')) {\n if (!canComputeStyles) return undefined;\n const el = context?.element;\n if (!el) return undefined;\n const fontSize = Number.parseFloat(getComputedStyle(el).fontSize);\n return Number.isFinite(fontSize) ? n * fontSize : undefined;\n }\n\n // If unitless or an unsupported unit, assume px.\n return n;\n}\n\n/**\n * Read the external scale border radius CSS variable from an element and return\n * a numeric pixel value suitable for path-based selective corner rounding.\n *\n * Falls back to 4px for condensed and 8px for regular when CSS/DOM is unavailable.\n */\nexport function readExternalScaleBorderRadiusPx(\n host: Element,\n scaleType: ScaleType,\n cssVarName: string = EXTERNAL_SCALE_BORDER_RADIUS_CSS_VAR\n): number {\n const fallback = scaleType === ScaleType.condensed ? 4 : 8;\n\n if (typeof getComputedStyle !== 'function') return fallback;\n\n const raw = getComputedStyle(host).getPropertyValue(cssVarName).trim();\n const parsed = parseCssLengthToPx(raw, {\n element: host,\n documentElement:\n // Prefer the element's owning document to support iframes/shadow contexts.\n (host as HTMLElement).ownerDocument?.documentElement ??\n (typeof document !== 'undefined' ? document.documentElement : undefined),\n });\n\n return parsed ?? fallback;\n}\n\n/**\n * Start observing likely style-change sources (host + ancestors + documentElement)\n * and call `onChange` when class/style attributes change.\n *\n * Returns the MutationObserver instance, or `undefined` when MutationObserver/DOM\n * is unavailable.\n */\nexport function startExternalScaleBorderRadiusObserver(\n host: HTMLElement,\n onChange: () => void\n): MutationObserver | undefined {\n if (typeof MutationObserver === 'undefined') return undefined;\n\n const observer = new MutationObserver(() => onChange());\n\n const targets: Element[] = [host];\n let current: Element | null = host.parentElement;\n while (current) {\n targets.push(current);\n current = current.parentElement;\n }\n\n const docEl = host.ownerDocument?.documentElement;\n if (docEl) targets.push(docEl);\n\n for (const t of targets) {\n observer.observe(t, {\n attributes: true,\n attributeFilter: ['class', 'style'],\n });\n }\n\n return observer;\n}\n\n/** Default border radius (px) used when `ExternalScaleConfig.borderRadius` is not provided. */\nexport function defaultExternalScaleBorderRadiusPx(\n scaleType: ScaleType\n): number {\n return scaleType === ScaleType.condensed ? 4 : 8;\n}\n\n/**\n * Compute a safe, numeric border radius (px) for geometry calculations.\n *\n * When `borderRadius` is undefined/invalid, falls back to a scaleType-based default.\n */\nexport function computeExternalScaleEffectiveBorderRadiusPx(\n config: Pick<ExternalScaleConfig, 'borderRadius' | 'scaleType'>\n): number {\n const fallback = defaultExternalScaleBorderRadiusPx(config.scaleType);\n const r = config.borderRadius;\n return typeof r === 'number' && Number.isFinite(r) && r >= 0 ? r : fallback;\n}\n\n/**\n * Compute the effective bar thickness.\n *\n * To keep rounded corners visually correct, the bar band must be at least\n * `2 * borderRadius` thick (otherwise the rounding geometry self-intersects).\n */\nexport function computeExternalScaleEffectiveBarThickness(\n config: Pick<\n ExternalScaleConfig,\n 'hasBar' | 'barThickness' | 'borderRadius' | 'scaleType'\n >\n): number {\n const bt = Number.isFinite(config.barThickness) ? config.barThickness : 0;\n if (!config.hasBar) return bt;\n\n const r = computeExternalScaleEffectiveBorderRadiusPx(config);\n return Math.max(bt, r * 2);\n}\n\n/**\n * Compute the effective tick band thickness based on scale type.\n *\n * In condensed mode, ticks are shorter (max 10px for primary/main + 4px gap = 14px),\n * so the tick band doesn't need to be as thick as in regular mode (20px + 4px = 24px).\n *\n * This function ensures that:\n * - In regular mode: tickThickness is used as-is (minimum 24px for full-length ticks)\n * - In condensed mode: tickThickness is capped at 14px (10px tick + 4px gap)\n *\n * This allows wrappers to use a single default tickThickness (24px) while the layout\n * automatically adjusts for condensed mode.\n *\n * @param config - Configuration with tickThickness and scaleType\n * @returns Effective tick band thickness in pixels\n */\nexport function computeExternalScaleEffectiveTickThickness(\n config: Pick<ExternalScaleConfig, 'tickThickness' | 'scaleType'>\n): number {\n const tt = Number.isFinite(config.tickThickness) ? config.tickThickness : 0;\n\n // In condensed mode, the longest tick is 10px, plus 4px gap = 14px max needed\n // Cap the tick thickness to avoid wasted space between ticks and labels\n if (config.scaleType === ScaleType.condensed) {\n const condensedMaxThickness = 14; // 10px tick + 4px gap\n return Math.min(tt, condensedMaxThickness);\n }\n\n return tt;\n}\n\nexport interface ExternalScaleAdvice {\n /** Range start value (in scale units). */\n min: number;\n /** Range end value (in scale units). */\n max: number;\n type: AdviceType;\n /** When true, renders in a \"hinted\" state unless the setpoint is inside the range. */\n hinted: boolean;\n}\n\nexport interface ExternalScaleAdviceRaw {\n min: number;\n max: number;\n type: AdviceType;\n state: AdviceState;\n}\n\nexport interface ExternalScaleConfig {\n /** Main axis orientation used for value-to-coordinate mapping. */\n orientation: ExternalScaleOrientation;\n /**\n * Which side of the chart area this scale lives on.\n * - vertical: 'left' | 'right'\n * - horizontal: 'top' | 'bottom'\n */\n side: ExternalScaleSide;\n\n /** Total length in pixels (vertical: height, horizontal: width), including padding. */\n length: number;\n\n /** Padding at start of main axis (top for vertical, left for horizontal). */\n paddingStart: number;\n /** Padding at end of main axis (bottom for vertical, right for horizontal). */\n paddingEnd: number;\n\n /** Minimum scale value. */\n minValue: number;\n /** Maximum scale value. */\n maxValue: number;\n\n // Layout bands (thickness, in px)\n /** Show scale tickmarks. */\n hasScale: boolean;\n /** Show labels at primary tickmark intervals. */\n labels?: boolean;\n /**\n * Label the main tickmarks (`mainTickmarks`, or min / 0 / max) instead of\n * the primary interval ladder. For scales too short for a ladder.\n */\n mainTickmarkLabels?: boolean;\n /** Show bar. */\n hasBar: boolean;\n /** Show background behind the scale tickmarks. */\n scaleBackground: boolean;\n\n /** Bar band thickness in pixels (the container / fill area). */\n barThickness: number;\n /**\n * Bar container background style.\n * When undefined, defaults based on scaleBackground:\n * - scaleBackground=true: secondary (gray)\n * - scaleBackground=false: primary (lighter)\n * Set explicitly to override this default behavior.\n */\n barContainerStyle?: BarContainerStyle;\n /** Tickmark band thickness in pixels (space reserved for tick lines). */\n tickThickness: number;\n /** Label band thickness in pixels (space reserved for numbers). */\n labelThickness: number;\n\n // Tick configuration\n /** Array of values for main tickmarks. Defaults to [minValue, 0, maxValue] if empty. */\n mainTickmarks?: number[];\n /**\n * Interval for primary tickmarks. When undefined, no primary tickmarks are shown.\n * When a positive number, primary tickmarks are shown at that interval.\n */\n primaryTickmarkInterval?: number;\n /**\n * Interval for secondary tickmarks. When undefined, no secondary tickmarks are shown.\n * When a positive number, secondary tickmarks are shown at that interval.\n */\n secondaryTickmarkInterval?: number;\n /**\n * Interval for tertiary tickmarks. When undefined, no tertiary tickmarks are shown.\n * When a positive number, tertiary tickmarks are shown at that interval.\n */\n tertiaryTickmarkInterval?: number;\n /**\n * Tick density preset.\n * - ScaleType.regular: longer ticks\n * - ScaleType.condensed: shorter ticks\n */\n scaleType: ScaleType;\n /**\n * Frame style preset.\n * - FrameStyle.regular: all ticks offset from bar edge by a gap\n * - FrameStyle.flat: main ticks touch the bar edge\n * - FrameStyle.framed: framed appearance\n * - FrameStyle.instrument: instrument-style appearance\n */\n frameStyle: FrameStyle;\n /**\n * Border radius position based on component layout.\n * Determines which corners receive rounded borders.\n */\n borderRadiusPosition?: BorderRadiusPosition;\n /**\n * Override border radius value (in pixels).\n * When undefined, uses default based on scaleType (4px for condensed, 8px for regular).\n * Set this to the computed CSS variable value to make path-based selective corner\n * rounding respond to theme changes.\n */\n borderRadius?: number;\n\n // Visual state\n /**\n * Color priority mode.\n * - `Priority.enhanced`: Use enhanced (blue) color palette\n * - `Priority.regular`: Use regular (gray) color palette\n */\n priority: Priority;\n /**\n * When true, the setpoint color is derived from `priority` regardless of\n * instrument state (loading/off). This prevents the setpoint from being\n * rendered in disabled (tertiary) color when the instrument is loading or off.\n *\n * - `false` / `undefined`: default behavior — loading/off → disabled color\n * - `true`: color derived from `priority`, never disabled\n *\n * @default false\n */\n setpointOverride?: boolean;\n\n /**\n * Explicit disabled state override for setpoint marker.\n * When true, the setpoint uses tertiary/disabled colors.\n * When undefined, disabled state is auto-derived from `state` (loading/off = disabled).\n *\n * @default undefined (auto-derived from state)\n */\n setpointDisabled?: boolean;\n /**\n * Fill visualization mode.\n * - FillMode.fill: bar fill from fillMin to fillMax\n * - FillMode.tint: bar fill from fillMin to fillMax with marker at value position\n */\n fillMode: FillMode;\n fillMin?: number;\n fillMax?: number;\n /** Current value used for fill and/or marker rendering. */\n value?: number;\n\n // Setpoint\n /**\n * Setpoint value. When undefined, no setpoint marker is shown.\n * When a number, the setpoint marker is shown at that value.\n */\n setpoint?: number;\n /**\n * New setpoint value being adjusted (focus mode).\n * When defined, renders a second setpoint marker in 'focus' visual state.\n * The original `setpoint` marker is dimmed (0.5 opacity) while `newSetpoint` is active.\n * This enables the \"adjustment preview\" UX where users can see both the current\n * and proposed setpoint positions simultaneously.\n */\n newSetpoint?: number;\n /** Manual override used when autoAtSetpoint=false. */\n atSetpoint: boolean;\n /** When true, at-setpoint is derived from value/setpoint and deadband. */\n autoAtSetpoint: boolean;\n /** Deadband used for automatic at-setpoint detection. */\n autoAtSetpointDeadband: number;\n /** Deadband around 0 where the setpoint indicator snaps to exactly 0. */\n setpointAtZeroDeadband: number;\n state: InstrumentState;\n\n // Advice\n /** Where advice overlays are drawn relative to the bar/tick bands. */\n advicePosition: AdvicePosition;\n /** Array of advice ranges (min/max/type/hinted). */\n advices?: ExternalScaleAdvice[];\n\n /**\n * When true, freezes all internal calculations and scales the entire component\n * proportionally (like CSS transform:scale), except label font-size remains constant.\n * When false (default), dimensions react to component properties.\n * @default false\n */\n fixedAspectRatio?: boolean;\n\n /**\n * Reference size for proportional scaling when fixedAspectRatio is true.\n * At this size, the scale renders at native 1:1 (matches Figma design).\n * Above this size, the scale grows proportionally; below, it shrinks.\n * Applied to the main axis dimension (height for vertical, width for horizontal).\n * @default 384\n */\n scaleReferenceSize?: number;\n\n /**\n * When true, the component is used inside an instrument (e.g., gauge-trend).\n * In this mode, only label font size responds to .obc-component-size-* CSS classes.\n * Border radius uses the explicit `borderRadius` property value (or defaults to 8px regular / 4px condensed),\n * rather than reading from CSS variables.\n *\n * Wrappers should:\n * - Skip CSS variable observers when instrumentMode=true\n * - Use explicit borderRadius value or scaleType-based defaults\n *\n * @default false\n */\n instrumentMode?: boolean;\n\n /**\n * When true, displays a dot indicator at the current value position.\n * The dot is rendered in the scale band, touching its inner edge (towards the chart).\n * This provides an alternative to bar fill for highlighting the current value.\n *\n * The dot is:\n * - 12x12px filled circle with 2px stroke (16px total visual size)\n * - Fill: --instrument-regular-secondary-color (or enhanced variant when priority=enhanced)\n * - Stroke: --instrument-frame-primary-color\n *\n * @default false\n */\n highlightCurrentValue?: boolean;\n\n /**\n * User is physically interacting with the control (e.g. lever/slider touch).\n *\n * When true:\n * - `calculateAtSetpoint()` returns false (suppressed)\n * - Single setpoint marker renders in focus visual state\n *\n * @default false\n */\n touching?: boolean;\n\n // Animation\n /**\n * Enable CSS-animated confirm transition for setpoint markers.\n * When true, the original setpoint marker uses CSS `transition` for smooth movement\n * and opacity changes. The departing new-setpoint marker fades out.\n *\n * Duration is configurable via CSS: `--setpoint-animation-duration: 300ms`.\n * @default false\n */\n animateSetpoint?: boolean;\n\n /**\n * Value of the departing new-setpoint during confirm animation.\n * When defined, renders the new-setpoint marker at this position with `opacity: 0`\n * (CSS-transitioned from 1), keeping it in the DOM during its fade-out.\n *\n * Managed by SetpointMixin / SetpointBundle — cleared after animation completes.\n */\n departingNewSetpoint?: number;\n}\n\nexport interface ExternalScaleLayout {\n /** Total thickness (vertical: width, horizontal: height) */\n thickness: number;\n /** Where the viewBox begins on the perpendicular axis (chart-edge is always 0) */\n viewBoxPerpStart: number;\n /** viewBox length (main axis) */\n viewBoxLength: number;\n /** viewBox thickness (perpendicular axis) */\n viewBoxThickness: number;\n}\n\nexport type ExternalScaleLayoutConfig = Pick<\n ExternalScaleConfig,\n | 'orientation'\n | 'side'\n | 'hasBar'\n | 'hasScale'\n | 'labels'\n | 'barThickness'\n | 'tickThickness'\n | 'labelThickness'\n | 'length'\n | 'scaleType'\n> & {\n /**\n * Position of advice overlay pills relative to the bar band. Only used when\n * `hasAdvice` is true; defaults to `AdvicePosition.inner` if omitted.\n */\n advicePosition?: AdvicePosition;\n /**\n * Whether any advice overlays are present.\n *\n * Advice pills render in perpendicular space outside the bar band\n * (8px wide, plus a 4px offset from the bar edge or tick base). When the\n * scale/label bands don't already provide enough room, the layout reserves\n * an extra band so the pill is not clipped by the viewBox. This also makes\n * the reported scale thickness include the advice band, so parent charts\n * inset correctly to keep the pill visible inside the cell.\n */\n hasAdvice?: boolean;\n /**\n * Whether a setpoint marker (original, new, or departing) is present.\n *\n * The setpoint marker renders in perpendicular space outside the bar band\n * (tip at `tickBase + 4` plus a state offset of up to 8, body extending a\n * further 21 outward). When the scale/label bands don't already provide\n * enough room — e.g. `hasScale=false` side bars — the layout reserves an\n * extra band so the marker is not clipped by the viewBox.\n */\n hasSetpoint?: boolean;\n};\n\nexport interface ExternalScaleViewBox {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** Convenience helper for producing the `computeExternalScaleLayout()` input from a full config. */\nexport function toExternalScaleLayoutConfig(\n config: ExternalScaleConfig\n): ExternalScaleLayoutConfig {\n return {\n orientation: config.orientation,\n side: config.side,\n hasBar: config.hasBar,\n hasScale: config.hasScale,\n labels: config.labels,\n barThickness: computeExternalScaleEffectiveBarThickness(config),\n tickThickness: computeExternalScaleEffectiveTickThickness(config),\n labelThickness: config.labelThickness,\n length: config.length,\n scaleType: config.scaleType,\n advicePosition: config.advicePosition,\n hasAdvice: !!config.advices && config.advices.length > 0,\n hasSetpoint:\n config.setpoint !== undefined ||\n config.newSetpoint !== undefined ||\n config.departingNewSetpoint !== undefined,\n };\n}\n\n/**\n * Compute the outer SVG viewBox for a scale given layout.\n * Wrappers can use this to avoid duplicating orientation-specific math.\n */\nexport function computeExternalScaleViewBox(\n config: Pick<ExternalScaleConfig, 'orientation' | 'length'>,\n layout: ExternalScaleLayout\n): ExternalScaleViewBox {\n if (config.orientation === 'vertical') {\n return {\n x: layout.viewBoxPerpStart,\n y: -config.length / 2,\n width: layout.viewBoxThickness,\n height: config.length,\n };\n }\n\n return {\n x: 0,\n y: layout.viewBoxPerpStart,\n width: config.length,\n height: layout.viewBoxThickness,\n };\n}\n\n/**\n * Compute the effective `preserveAspectRatio=\"xMidYMid meet\"` uniform scale factor.\n *\n * Returns 1 when inputs are invalid (e.g. 0-sized viewBox).\n */\nexport function computeMeetScale(\n viewBoxWidth: number,\n viewBoxHeight: number,\n containerWidth: number,\n containerHeight: number\n): number {\n const widthScale = viewBoxWidth > 0 ? containerWidth / viewBoxWidth : 1;\n const heightScale = viewBoxHeight > 0 ? containerHeight / viewBoxHeight : 1;\n return Math.min(widthScale, heightScale);\n}\n\n/**\n * Configuration for computing fixed aspect ratio scale factor.\n */\nexport interface FixedAspectRatioScaleConfig {\n /** Main axis orientation: 'vertical' or 'horizontal' */\n orientation: ExternalScaleOrientation;\n /** Actual main axis size of the container (height for vertical, width for horizontal) */\n containerMainAxisSize: number;\n /** Reference size at which the scale renders at 1:1 (default: 384) */\n scaleReferenceSize: number;\n}\n\n/**\n * Compute the scale factor for fixed aspect ratio mode.\n *\n * In fixed aspect ratio mode, the scale component determines its zoom level based on\n * comparing the container's main axis size against a reference size (typically 384px).\n * - If container is larger than reference: scale > 1 (zoom in)\n * - If container is smaller than reference: scale < 1 (zoom out)\n * - If container equals reference: scale = 1 (native size)\n *\n * This scale factor is applied to SVG rendering while keeping text labels at constant size\n * by using the CSS variable `--scale` to counter-scale font sizes.\n *\n * Works for all orientations and sides:\n * - Vertical scales (left/right): compare container height vs reference\n * - Horizontal scales (top/bottom): compare container width vs reference\n *\n * @param config Configuration with orientation, container size, and reference size\n * @returns Scale factor (> 0), defaults to 1 if container size is invalid\n */\nexport function computeFixedAspectRatioScale(\n config: FixedAspectRatioScaleConfig\n): number {\n const {containerMainAxisSize, scaleReferenceSize} = config;\n\n // Guard against zero or negative sizes\n if (containerMainAxisSize <= 0 || scaleReferenceSize <= 0) {\n return 1;\n }\n\n // Scale = container size / reference size\n // e.g., container=480px, reference=384px => scale=1.25 (zoom in)\n // e.g., container=288px, reference=384px => scale=0.75 (zoom out)\n return containerMainAxisSize / scaleReferenceSize;\n}\n\n/**\n * Compute scaled dimensions for reporting when in fixed aspect ratio mode.\n *\n * When fixedAspectRatio is true, the reported thickness should be scaled\n * proportionally to match the visual output.\n *\n * @param baseThickness The unscaled thickness from layout computation\n * @param scale The current scale factor from computeFixedAspectRatioScale\n * @returns Scaled thickness value\n */\nexport function computeScaledThickness(\n baseThickness: number,\n scale: number\n): number {\n return baseThickness * scale;\n}\n\n/**\n * Compute a minimal viewBox layout for an external scale.\n *\n * The chart edge is always at perpendicular coordinate 0, and the scale expands\n * outward from that edge based on which bands are enabled (bar/ticks/labels).\n *\n * When scaleType is 'condensed', tick thickness is automatically reduced to match\n * the shorter tick lengths (14px max instead of 24px for regular).\n */\nexport function computeExternalScaleLayout(\n config: ExternalScaleLayoutConfig\n): ExternalScaleLayout {\n const barSpace = config.hasBar ? config.barThickness : 0;\n // Use effective tick thickness based on scaleType\n const effectiveTickThickness =\n computeExternalScaleEffectiveTickThickness(config);\n const scaleSpace = config.hasScale ? effectiveTickThickness : 0;\n const labelSpace = config.labels ? config.labelThickness : 0;\n\n // Advice pills render outside the bar band. When the scale/label bands\n // collapse (e.g. hasLabelPadding=false on the parent chart, or hasScale=false),\n // reserve a minimum perpendicular band so the pill is not clipped. The pill\n // is 8px wide with a 4px offset from its anchor edge, plus a small visual\n // buffer so the pill doesn't touch the viewBox edge.\n const adviceSpace = computeAdviceBandThickness(config);\n const setpointSpace = computeSetpointBandThickness(config);\n const outsideBarSpace = Math.max(\n scaleSpace + labelSpace,\n adviceSpace,\n setpointSpace\n );\n const thickness = barSpace + outsideBarSpace;\n\n const isOutwardPositive =\n (config.orientation === 'vertical' && config.side === 'right') ||\n (config.orientation === 'horizontal' && config.side === 'bottom');\n\n const viewBoxPerpStart = isOutwardPositive ? 0 : -thickness;\n\n return {\n thickness,\n viewBoxPerpStart,\n viewBoxLength: config.length,\n viewBoxThickness: thickness,\n };\n}\n\n/**\n * Compute the minimum perpendicular band thickness required to render advice\n * pills without clipping. Returns 0 when no advices are present.\n *\n * Pill geometry (see `advicePill` / `renderAdvice`):\n * - `inner` (default when no bar): pill at `tickBase + 4` to `tickBase + 12`\n * from the bar edge → needs 12px + 4px buffer = 16px outside the bar.\n * - `outer`: pill at `barThickness + 10 + 4` to `barThickness + 10 + 12`\n * → needs 22px + 2px buffer = 24px outside the bar.\n * - `center`: pill straddles the bar band; no extra perpendicular space needed.\n *\n * NOTE: `renderAdvice()` coerces `advicePosition` to `inner` when `hasBar=false`\n * (no bar area to straddle/sit-outside). Mirror that coercion here so the\n * reserved space matches the rendered geometry — otherwise `hasBar=false +\n * advicePosition='center'` would reserve 0 while the pill renders at inner\n * geometry and clips.\n */\nfunction computeAdviceBandThickness(\n config: Pick<\n ExternalScaleLayoutConfig,\n 'hasAdvice' | 'advicePosition' | 'hasBar'\n >\n): number {\n if (!config.hasAdvice) return 0;\n const position = config.hasBar\n ? (config.advicePosition ?? AdvicePosition.inner)\n : AdvicePosition.inner;\n if (position === AdvicePosition.center) return 0;\n if (position === AdvicePosition.outer) return 24;\n return 16;\n}\n\n/**\n * Perpendicular band needed to keep a setpoint marker inside the viewBox\n * when no scale/label bands reserve the space.\n *\n * Worst case, measured outward from the bar edge (`tickBasePerp`):\n * `tickGap()` + max state offset (`equalZero`, `SETPOINT_ZERO_OFFSET`) +\n * marker body (`SETPOINT_HEIGHT`). See `renderSingleSetpoint()` for the\n * geometry.\n */\nexport function computeSetpointBandThickness(\n config: Pick<ExternalScaleLayoutConfig, 'hasSetpoint'>\n): number {\n if (!config.hasSetpoint) return 0;\n return tickGap() + SETPOINT_ZERO_OFFSET + SETPOINT_HEIGHT;\n}\n\nfunction isVertical(config: ExternalScaleConfig): boolean {\n return config.orientation === 'vertical';\n}\n\nfunction isOutwardPositive(config: ExternalScaleConfig): boolean {\n return (\n (config.orientation === 'vertical' && config.side === 'right') ||\n (config.orientation === 'horizontal' && config.side === 'bottom')\n );\n}\n\nfunction rangeIncludesZero(minValue: number, maxValue: number): boolean {\n return minValue <= 0 && maxValue >= 0;\n}\n\n/** The main tickmark values inside the range, ascending, without repeats. */\nfunction resolveMainTickmarkValues(\n config: Pick<ExternalScaleConfig, 'mainTickmarks' | 'minValue' | 'maxValue'>\n): number[] {\n const source = config.mainTickmarks?.length\n ? config.mainTickmarks\n : [config.minValue, 0, config.maxValue];\n return [...new Set(source)]\n .filter((v) => v >= config.minValue && v <= config.maxValue)\n .sort((a, b) => a - b);\n}\n\n/**\n * Ticks one ladder (primary, secondary, tertiary or labels) may hold. A\n * denser ladder cannot be read on any scale length, and building it would\n * exhaust the call stack.\n */\nexport const EXTERNAL_SCALE_MAX_TICKS = 1000;\n\n// Bounded: a scale re-renders on every property change, and a live range\n// that stays dense would otherwise grow this without limit.\nconst DENSE_LADDER_WARNINGS_KEPT = 64;\nconst warnedDenseLadders = new Set<string>();\n\n/** True when `interval` would put more than the cap on the range; warns once per pair. */\nfunction isLadderTooDense(\n config: Pick<ExternalScaleConfig, 'minValue' | 'maxValue'>,\n interval: number\n): boolean {\n const count = Math.floor((config.maxValue - config.minValue) / interval) + 1;\n if (!(count > EXTERNAL_SCALE_MAX_TICKS)) return false;\n const key = `${config.minValue}/${config.maxValue}/${interval}`;\n if (!warnedDenseLadders.has(key)) {\n if (warnedDenseLadders.size >= DENSE_LADDER_WARNINGS_KEPT) {\n warnedDenseLadders.clear();\n }\n warnedDenseLadders.add(key);\n console.warn(\n `[external-scale] tick interval ${interval} over the range ${config.minValue}…${config.maxValue} is ${count} ticks; the ladder is not drawn (limit ${EXTERNAL_SCALE_MAX_TICKS}). A range in epoch milliseconds needs an interval in milliseconds.`\n );\n }\n return true;\n}\n\nfunction calculateAtSetpoint(config: ExternalScaleConfig): boolean {\n const isTouching = config.touching ?? false;\n return computeAtSetpoint({\n value: config.value,\n setpoint: config.setpoint,\n touching: isTouching,\n auto: config.autoAtSetpoint,\n deadband: config.autoAtSetpointDeadband,\n atSetpointManual: config.atSetpoint,\n });\n}\n\n// ============================================================================\n// Setpoint Visual State Derivation\n// ============================================================================\n\n/**\n * Derive the SetpointVisualState from ExternalScaleConfig.\n *\n * This maps the instrument's API (state, atSetpoint, value, setpoint, etc.)\n * to the design-only visual state enum.\n *\n * Priority order:\n * 1. focus (touching property is true - user actively adjusting)\n * 2. equalZero (at setpoint AND setpoint is at zero)\n * 3. equal (at setpoint)\n * 4. notEqual (default)\n *\n * NOTE: Disabled states (loading, off) are handled via deriveSetpointDisabled(),\n * which returns a boolean flag, not via a separate visual state.\n *\n * State mapping:\n * - InstrumentState.active → notEqual/equal/equalZero (based on deadband)\n * - InstrumentState.loading → disabled=true (via deriveSetpointDisabled)\n * - InstrumentState.off → disabled=true (via deriveSetpointDisabled)\n *\n * Note: `focus` visual state is only triggered by the `touching` property\n * (user actively adjusting via touch/drag), not by InstrumentState.\n */\nexport function deriveSetpointVisualState(\n config: ExternalScaleConfig\n): SetpointVisualState {\n // Priority 1: Focus state\n // - When `touching` property is true (user is actively adjusting)\n // - BUT only when newSetpoint is not defined (otherwise original should be dimmed)\n const isTouching = config.touching ?? false;\n if (isTouching && config.newSetpoint === undefined) {\n return SetpointVisualState.focus;\n }\n\n // For enhanced and active states, check deadband-based states\n // Check if at setpoint\n const isAt = calculateAtSetpoint(config);\n\n if (isAt) {\n // Check if setpoint is at zero (using setpointAtZeroDeadband)\n const setpointAtZero =\n config.setpoint !== undefined &&\n Math.abs(config.setpoint) < config.setpointAtZeroDeadband;\n\n if (setpointAtZero) {\n return SetpointVisualState.equalZero;\n }\n return SetpointVisualState.equal;\n }\n\n // Default: not at setpoint\n return SetpointVisualState.notEqual;\n}\n\n/**\n * Derive the SetpointColorMode from ExternalScaleConfig.\n *\n * Maps `config.priority` to enhanced/regular color palette.\n *\n * Note: Disabled state is handled separately via deriveSetpointDisabled().\n */\nfunction deriveSetpointColorMode(\n config: ExternalScaleConfig\n): SetpointColorMode {\n // Map priority to color mode\n return config.priority === Priority.enhanced\n ? SetpointColorMode.enhanced\n : SetpointColorMode.regular;\n}\n\n/**\n * Derive the disabled state for setpoint rendering.\n *\n * Priority:\n * 1. Explicit setpointDisabled takes precedence\n * 2. When setpointOverride is true, never auto-disable\n * 3. Instrument states (loading, off) are treated as disabled\n * 4. Otherwise, not disabled\n */\nfunction deriveSetpointDisabled(config: ExternalScaleConfig): boolean {\n // Explicit setpointDisabled takes precedence\n if (config.setpointDisabled !== undefined) {\n return config.setpointDisabled;\n }\n\n // When override is active, don't auto-disable for loading/off\n if (config.setpointOverride) {\n return false;\n }\n\n // Disabled states (loading, off) use disabled color mode\n if (\n config.state === InstrumentState.loading ||\n config.state === InstrumentState.off\n ) {\n return true;\n }\n\n return false;\n}\n\nfunction colors(config: ExternalScaleConfig): {\n barFillColor: string;\n markerFillColor: string;\n markerStrokeColor: string;\n setpointColor: string;\n} {\n // TODO(theming): extend the color resolution to support domain-specific\n // palettes (e.g. automation medium / fuel colors used by `obc-automation-tank`'s\n // legacy CSS bar — `--automation-medium-fuel`, `--automation-fresh-water`,\n // etc.). Today the bar fill is locked to the instrument regular/enhanced\n // palette; tanks rendered through this renderer therefore lose their\n // per-`medium` coloring. A new optional `colorVariant` (or similar) on\n // `ExternalScaleConfig`, plumbed through `obc-bar-vertical` /\n // `obc-bar-horizontal`, would let the tank pass its medium token and\n // restore the legacy look without forking the renderer.\n const isEnhanced = config.priority === Priority.enhanced;\n // Fill mode uses secondary color, tint mode uses tertiary color\n let barFillColor =\n config.fillMode === 'tint'\n ? isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)'\n : isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n\n let markerFillColor = isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n\n let markerStrokeColor = isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n\n let setpointColor = isEnhanced\n ? 'var(--instrument-enhanced-primary-color)'\n : 'var(--instrument-regular-primary-color)';\n\n if (\n config.state === InstrumentState.loading ||\n config.state === InstrumentState.off\n ) {\n barFillColor = 'transparent';\n markerFillColor = 'var(--instrument-frame-tertiary-color)';\n markerStrokeColor = 'var(--instrument-frame-tertiary-color)';\n setpointColor = 'var(--instrument-frame-tertiary-color)';\n }\n\n return {barFillColor, markerFillColor, markerStrokeColor, setpointColor};\n}\n\nfunction convertAdvices(\n advices: ExternalScaleAdvice[],\n setpoint: number | undefined\n): ExternalScaleAdviceRaw[] {\n return advices.map((a) => {\n const triggered =\n setpoint !== undefined && setpoint >= a.min && setpoint <= a.max;\n\n const state = triggered\n ? AdviceState.triggered\n : a.hinted\n ? AdviceState.hinted\n : AdviceState.regular;\n\n return {min: a.min, max: a.max, type: a.type, state};\n });\n}\n\nfunction mainAxisOffset(config: ExternalScaleConfig): number {\n if (isVertical(config)) {\n // viewBox y is centered at 0: [-length/2 .. length/2]\n // paddingStart=top, paddingEnd=bottom\n return (config.paddingStart - config.paddingEnd) / 2;\n }\n // horizontal viewBox x starts at 0\n return config.paddingStart;\n}\n\nfunction drawingLength(config: ExternalScaleConfig): number {\n return Math.max(0, config.length - config.paddingStart - config.paddingEnd);\n}\n\nfunction valueToMainAxis(config: ExternalScaleConfig, value: number): number {\n const dLen = drawingLength(config);\n if (isVertical(config)) {\n return (\n valueToY(value, config.minValue, config.maxValue, dLen) +\n mainAxisOffset(config)\n );\n }\n return (\n valueToX(value, config.minValue, config.maxValue, dLen) +\n mainAxisOffset(config)\n );\n}\n\nfunction getTickThicknesses(scaleType: ScaleType) {\n const isCondensed = scaleType === 'condensed';\n return {\n primary: isCondensed ? 10 : 20,\n secondary: isCondensed ? 4 : 8,\n tertiary: isCondensed ? 2 : 4,\n main: isCondensed ? 10 : 20,\n };\n}\n\nfunction tickBasePerp(config: ExternalScaleConfig): number {\n // Chart edge is always at perp=0.\n // Bar band touches chart edge.\n return config.hasBar\n ? isOutwardPositive(config)\n ? config.barThickness\n : -config.barThickness\n : 0;\n}\n\nfunction tickGap(): number {\n return 4;\n}\n\nfunction labelGap(): number {\n return 8;\n}\n\nfunction buildTickLine(\n config: ExternalScaleConfig,\n mainPos: number,\n perpStart: number,\n perpLen: number\n): SVGTemplateResult {\n const stroke = 'var(--instrument-frame-tertiary-color)';\n const strokeWidth = 1;\n\n if (isVertical(config)) {\n const x1 = perpStart;\n const x2 = perpStart + perpLen;\n const y = mainPos;\n return svg`<line x1=${x1} x2=${x2} y1=${y} y2=${y} stroke=${stroke} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n const y1 = perpStart;\n const y2 = perpStart + perpLen;\n const x = mainPos;\n return svg`<line x1=${x} x2=${x} y1=${y1} y2=${y2} stroke=${stroke} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>`;\n}\n\nfunction generateTickmarksAtInterval(\n config: ExternalScaleConfig,\n interval: number,\n perpStart: number,\n perpLen: number,\n skipValues: number[]\n): {svgs: SVGTemplateResult[]; values: number[]} {\n const svgs: SVGTemplateResult[] = [];\n const values: number[] = [];\n\n if (interval <= 0 || !Number.isFinite(interval)) return {svgs, values};\n if (isLadderTooDense(config, interval)) return {svgs, values};\n\n const includesZero = rangeIncludesZero(config.minValue, config.maxValue);\n\n const pushTick = (v: number) => {\n if (skipValues.includes(v)) return;\n values.push(v);\n svgs.push(\n buildTickLine(config, valueToMainAxis(config, v), perpStart, perpLen)\n );\n };\n\n if (includesZero) {\n for (let v = interval; v <= config.maxValue; v += interval) pushTick(v);\n for (let v = -interval; v >= config.minValue; v -= interval) pushTick(v);\n } else {\n const startValue = Math.ceil(config.minValue / interval) * interval;\n for (let v = startValue; v <= config.maxValue; v += interval) pushTick(v);\n }\n\n return {svgs, values};\n}\n\nfunction generateTickmarks(config: ExternalScaleConfig): SVGTemplateResult[] {\n if (!config.hasScale) return [];\n\n const svgs: SVGTemplateResult[] = [];\n const skipValues: number[] = [];\n\n const base = tickBasePerp(config);\n const gap = tickGap();\n\n const tickmarksStart = isOutwardPositive(config) ? base + gap : base - gap;\n\n const {primary, secondary, tertiary, main} = getTickThicknesses(\n config.scaleType\n );\n\n // Zero tick (skip if at min/max with scaleBackground enabled)\n if (rangeIncludesZero(config.minValue, config.maxValue)) {\n const isAtBoundary = 0 === config.minValue || 0 === config.maxValue;\n const shouldSkip = config.scaleBackground && isAtBoundary;\n\n if (!shouldSkip) {\n const perpLen = primary;\n const perpStart = tickmarksStart;\n svgs.push(\n buildTickLine(\n config,\n valueToMainAxis(config, 0),\n perpStart,\n isOutwardPositive(config) ? perpLen : -perpLen\n )\n );\n }\n skipValues.push(0);\n }\n\n // Main tickmarks - show when mainTickmarks is defined (array presence means enabled)\n // Use defensive guard to handle null/undefined/empty the same way as advices\n if (config.mainTickmarks) {\n const start = config.frameStyle === 'flat' ? base : tickmarksStart;\n const mainLen = config.frameStyle === 'flat' ? main + 4 : main;\n const dirLen = isOutwardPositive(config) ? mainLen : -mainLen;\n\n for (const value of resolveMainTickmarkValues(config)) {\n // Skip min/max tickmarks when scaleBackground is enabled (they align with the background edges)\n if (\n config.scaleBackground &&\n (value === config.minValue || value === config.maxValue)\n ) {\n skipValues.push(value);\n continue;\n }\n\n svgs.push(\n buildTickLine(config, valueToMainAxis(config, value), start, dirLen)\n );\n skipValues.push(value);\n }\n }\n\n // Primary - show when interval is defined and > 0\n if (\n config.primaryTickmarkInterval !== undefined &&\n config.primaryTickmarkInterval > 0\n ) {\n const {svgs: s, values} = generateTickmarksAtInterval(\n config,\n config.primaryTickmarkInterval,\n tickmarksStart,\n isOutwardPositive(config) ? primary : -primary,\n skipValues\n );\n svgs.push(...s);\n skipValues.push(...values);\n }\n\n // Secondary - show when interval is defined and > 0\n if (\n config.secondaryTickmarkInterval !== undefined &&\n config.secondaryTickmarkInterval > 0\n ) {\n const {svgs: s} = generateTickmarksAtInterval(\n config,\n config.secondaryTickmarkInterval,\n tickmarksStart,\n isOutwardPositive(config) ? secondary : -secondary,\n skipValues\n );\n svgs.push(...s);\n }\n\n // Tertiary - show when interval is defined and > 0\n if (\n config.tertiaryTickmarkInterval !== undefined &&\n config.tertiaryTickmarkInterval > 0\n ) {\n const {svgs: s} = generateTickmarksAtInterval(\n config,\n config.tertiaryTickmarkInterval,\n tickmarksStart,\n isOutwardPositive(config) ? tertiary : -tertiary,\n skipValues\n );\n svgs.push(...s);\n }\n\n return svgs;\n}\n\nfunction generateLabels(config: ExternalScaleConfig): SVGTemplateResult[] {\n if (!config.labels) return [];\n\n const fontFamily = 'var(--font-family-main)';\n const fontColor = 'var(--instrument-tick-mark-label-secondary-color)';\n const fontSize =\n 'calc(var(--global-typography-ui-label-font-size) / var(--scale, 1))';\n\n const base = tickBasePerp(config);\n // Use effective tick thickness to position labels closer to ticks in condensed mode\n const effectiveTickThickness =\n computeExternalScaleEffectiveTickThickness(config);\n const labelPos = isOutwardPositive(config)\n ? base + (config.hasScale ? effectiveTickThickness : 0) + labelGap()\n : base - (config.hasScale ? effectiveTickThickness : 0) - labelGap();\n\n const labels: SVGTemplateResult[] = [];\n\n const push = (v: number, edge?: {anchor: string; baseline: string}) => {\n const main = valueToMainAxis(config, v);\n if (isVertical(config)) {\n const x = labelPos;\n const y = main;\n const anchor = isOutwardPositive(config) ? 'start' : 'end';\n const baseline = edge?.baseline ?? 'middle';\n labels.push(\n svg`<text x=${x} y=${y} text-anchor=${anchor} dominant-baseline=${baseline} font-family=${fontFamily} style=\"font-size: ${fontSize}\" fill=${fontColor}>${v}</text>`\n );\n return;\n }\n\n const y = labelPos;\n const x = main;\n const baseline = isOutwardPositive(config) ? 'hanging' : 'auto';\n const anchor = edge?.anchor ?? 'middle';\n labels.push(\n svg`<text x=${x} y=${y} text-anchor=${anchor} dominant-baseline=${baseline} font-family=${fontFamily} style=\"font-size: ${fontSize}\" fill=${fontColor}>${v}</text>`\n );\n };\n\n if (config.mainTickmarkLabels) {\n // The end labels turn inward so they stay inside the drawing length.\n for (const v of resolveMainTickmarkValues(config)) {\n const edge =\n v === config.minValue\n ? {anchor: 'start', baseline: 'auto'}\n : v === config.maxValue\n ? {anchor: 'end', baseline: 'hanging'}\n : undefined;\n push(v, edge);\n }\n return labels;\n }\n\n const interval = config.primaryTickmarkInterval;\n if (interval === undefined || interval <= 0 || !Number.isFinite(interval)) {\n return [];\n }\n if (isLadderTooDense(config, interval)) return [];\n\n if (rangeIncludesZero(config.minValue, config.maxValue)) {\n for (let v = 0; v <= config.maxValue; v += interval) push(v);\n for (let v = -interval; v >= config.minValue; v -= interval) push(v);\n } else {\n const startValue = Math.ceil(config.minValue / interval) * interval;\n for (let v = startValue; v <= config.maxValue; v += interval) push(v);\n }\n\n return labels;\n}\n\nfunction generateBarContainer(\n config: ExternalScaleConfig\n): SVGTemplateResult | typeof nothing {\n if (!config.hasBar) return nothing;\n\n const borderRadiusFallback = config.scaleType === 'condensed' ? 4 : 8;\n const borderRadiusValue = config.borderRadius ?? borderRadiusFallback;\n const strokeWidth = 1;\n // Determine bar container fill color:\n // 1. If barContainerStyle is explicitly set, use it\n // 2. Otherwise, fall back to scaleBackground-based default\n let fillColor: string;\n if (config.barContainerStyle !== undefined) {\n fillColor =\n config.barContainerStyle === BarContainerStyle.secondary\n ? 'var(--instrument-frame-secondary-color)'\n : 'var(--instrument-frame-primary-color)';\n } else {\n fillColor = config.scaleBackground\n ? 'var(--instrument-frame-secondary-color)'\n : 'var(--instrument-frame-primary-color)';\n }\n const strokeColor = 'var(--instrument-frame-tertiary-color)';\n\n const dLen = drawingLength(config);\n const axisShift = mainAxisOffset(config);\n\n // Determine which corners should be rounded based on borderRadiusPosition\n // innerFirstChild: corners on the inner/chart edge\n // middleChild: no corners\n // middleRoundedChild: chart-only (ignored here, treated as middleChild)\n // outerLastChild: corners on the outer edge (away from chart)\n let shouldRoundTopLeft = true;\n let shouldRoundTopRight = true;\n let shouldRoundBottomLeft = true;\n let shouldRoundBottomRight = true;\n\n if (config.borderRadiusPosition) {\n if (\n config.borderRadiusPosition === BorderRadiusPosition.middleChild ||\n config.borderRadiusPosition === BorderRadiusPosition.middleRoundedChild\n ) {\n // No rounded corners for middle child\n // (middleRoundedChild is chart-canvas-only; ignored for external scales)\n shouldRoundTopLeft = false;\n shouldRoundTopRight = false;\n shouldRoundBottomLeft = false;\n shouldRoundBottomRight = false;\n } else if (isVertical(config)) {\n // Vertical orientation\n const isRight = config.side === 'right';\n const isInner =\n config.borderRadiusPosition === BorderRadiusPosition.innerFirstChild;\n\n if (isRight) {\n // Right side: inner = left, outer = right\n shouldRoundTopLeft = isInner;\n shouldRoundBottomLeft = isInner;\n shouldRoundTopRight = !isInner;\n shouldRoundBottomRight = !isInner;\n } else {\n // Left side: inner = right, outer = left\n shouldRoundTopLeft = !isInner;\n shouldRoundBottomLeft = !isInner;\n shouldRoundTopRight = isInner;\n shouldRoundBottomRight = isInner;\n }\n } else {\n // Horizontal orientation\n const isBottom = config.side === 'bottom';\n const isInner =\n config.borderRadiusPosition === BorderRadiusPosition.innerFirstChild;\n\n if (isBottom) {\n // Bottom side: inner = top, outer = bottom\n shouldRoundTopLeft = isInner;\n shouldRoundTopRight = isInner;\n shouldRoundBottomLeft = !isInner;\n shouldRoundBottomRight = !isInner;\n } else {\n // Top side: inner = bottom, outer = top\n shouldRoundTopLeft = !isInner;\n shouldRoundTopRight = !isInner;\n shouldRoundBottomLeft = isInner;\n shouldRoundBottomRight = isInner;\n }\n }\n }\n\n const r = borderRadiusValue;\n const allCornersRounded =\n shouldRoundTopLeft &&\n shouldRoundTopRight &&\n shouldRoundBottomLeft &&\n shouldRoundBottomRight;\n const noCornersRounded =\n !shouldRoundTopLeft &&\n !shouldRoundTopRight &&\n !shouldRoundBottomLeft &&\n !shouldRoundBottomRight;\n\n if (isVertical(config)) {\n let rectX = isOutwardPositive(config) ? 0 : -config.barThickness;\n let rectY = -dLen / 2 + axisShift;\n let rectWidth = config.barThickness;\n let rectHeight = dLen;\n\n // The edge touching the scale is not adjusted inward for stroke: it\n // isn't a true viewBox boundary, since the scale covers it.\n const isRight = config.side === 'right';\n let viewBoxMinX: number;\n let viewBoxMaxX: number;\n if (config.scaleBackground) {\n // Exclude the edge that touches the scale from stroke adjustment\n if (isRight) {\n // Right side: bar is at x=0..barThickness, scale touches right edge\n // Only adjust left edge (viewBoxMinX=0), don't adjust right edge\n viewBoxMinX = 0;\n viewBoxMaxX = config.barThickness + 1; // +1 so rectX+rectWidth won't match\n } else {\n // Left side: bar is at x=-barThickness..0, scale touches left edge\n // Only adjust right edge (viewBoxMaxX=0), don't adjust left edge\n viewBoxMinX = -config.barThickness - 1; // -1 so rectX won't match\n viewBoxMaxX = 0;\n }\n } else {\n viewBoxMinX = isRight ? 0 : -config.barThickness;\n viewBoxMaxX = isRight ? config.barThickness : 0;\n }\n\n const adjustedX = adjustRectWidthForStroke(\n rectX,\n rectWidth,\n viewBoxMinX,\n viewBoxMaxX,\n strokeWidth\n );\n rectX = adjustedX.x;\n rectWidth = adjustedX.width;\n\n const adjustedY = adjustRectHeightForStroke(\n rectY,\n rectHeight,\n -dLen / 2 + axisShift,\n dLen / 2 + axisShift,\n strokeWidth\n );\n rectY = adjustedY.y;\n rectHeight = adjustedY.height;\n\n // Use simple rect when all corners or no corners are rounded\n if (allCornersRounded || noCornersRounded) {\n const rx = allCornersRounded ? r : 0;\n const ry = allCornersRounded ? r : 0;\n\n if (config.scaleBackground) {\n // When scaleBackground=true, draw fill and stroke separately to exclude edge touching scale\n const isRight = config.side === 'right';\n\n // Stroke path excludes the edge touching the scale\n let strokePath: string;\n if (isRight) {\n // Exclude right edge (touching scale on right side)\n strokePath = `M ${rectX} ${rectY + (noCornersRounded ? 0 : r)} L ${rectX} ${rectY + rectHeight - (noCornersRounded ? 0 : r)}`; // Left edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY + rectHeight} ${rectX + r} ${rectY + rectHeight}`; // Bottom-left corner\n strokePath += ` L ${rectX + rectWidth - (noCornersRounded ? 0 : r)} ${rectY + rectHeight}`; // Bottom edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY + rectHeight} ${rectX + rectWidth} ${rectY + rectHeight - r}`; // Bottom-right corner (no stroke)\n strokePath += ` M ${rectX + rectWidth} ${rectY + (noCornersRounded ? 0 : r)}`; // Move to top-right (no stroke on right edge)\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY} ${rectX + rectWidth - r} ${rectY}`; // Top-right corner (no stroke)\n strokePath += ` L ${rectX + (noCornersRounded ? 0 : r)} ${rectY}`; // Top edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY} ${rectX} ${rectY + r}`; // Top-left corner\n } else {\n // Exclude left edge (touching scale on left side)\n strokePath = `M ${rectX + (noCornersRounded ? 0 : r)} ${rectY}`; // Top edge start\n strokePath += ` L ${rectX + rectWidth - (noCornersRounded ? 0 : r)} ${rectY}`; // Top edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY} ${rectX + rectWidth} ${rectY + r}`; // Top-right corner\n strokePath += ` L ${rectX + rectWidth} ${rectY + rectHeight - (noCornersRounded ? 0 : r)}`; // Right edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY + rectHeight} ${rectX + rectWidth - r} ${rectY + rectHeight}`; // Bottom-right corner\n strokePath += ` L ${rectX + (noCornersRounded ? 0 : r)} ${rectY + rectHeight}`; // Bottom edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY + rectHeight} ${rectX} ${rectY + rectHeight - r}`; // Bottom-left corner (no stroke)\n strokePath += ` M ${rectX} ${rectY + (noCornersRounded ? 0 : r)}`; // Move to left edge start (no stroke on left edge)\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY} ${rectX + r} ${rectY}`; // Top-left corner (no stroke)\n }\n\n return svg`\n <rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${rx} ry=${ry} fill=${fillColor} stroke=\"none\"/>\n <path d=\"${strokePath}\" fill=\"none\" stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n `;\n }\n\n return svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${rx} ry=${ry} fill=${fillColor} stroke=${strokeColor} vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n // Use path for selective corner rounding\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n let path = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n\n // When scaleBackground=true, draw fill and stroke separately to exclude edge touching scale\n if (config.scaleBackground) {\n const isRight = config.side === 'right';\n\n // Stroke path excludes the edge touching the scale\n let strokePath: string;\n if (isRight) {\n // Exclude right edge\n strokePath = `M ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) strokePath += ` Q ${x} ${y} ${x + r} ${y}`;\n strokePath += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight)\n strokePath += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n strokePath += ` M ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight)\n strokePath += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n strokePath += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft)\n strokePath += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n strokePath += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n } else {\n // Exclude left edge\n strokePath = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n strokePath += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight)\n strokePath += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n strokePath += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight)\n strokePath += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n strokePath += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft)\n strokePath += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n strokePath += ` M ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) strokePath += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n\n return svg`\n <path d=${path} fill=${fillColor} stroke=\"none\"/>\n <path d=\"${strokePath}\" fill=\"none\" stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n `;\n }\n\n return svg`<path d=${path} fill=${fillColor} stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n // Horizontal: bar spans full drawing length (x), thickness is y\n let rectX = mainAxisOffset(config);\n let rectY = isOutwardPositive(config) ? 0 : -config.barThickness;\n let rectWidth = dLen;\n let rectHeight = config.barThickness;\n\n const isBottom = config.side === 'bottom';\n let viewBoxMinY: number;\n let viewBoxMaxY: number;\n if (config.scaleBackground) {\n // Exclude the edge that touches the scale from stroke adjustment\n if (isBottom) {\n // Bottom side: bar is at y=0..barThickness, scale touches bottom edge\n // Only adjust top edge (viewBoxMinY=0), don't adjust bottom edge\n viewBoxMinY = 0;\n viewBoxMaxY = config.barThickness + 1; // +1 so rectY+rectHeight won't match\n } else {\n // Top side: bar is at y=-barThickness..0, scale touches top edge\n // Only adjust bottom edge (viewBoxMaxY=0), don't adjust top edge\n viewBoxMinY = -config.barThickness - 1; // -1 so rectY won't match\n viewBoxMaxY = 0;\n }\n } else {\n viewBoxMinY = isBottom ? 0 : -config.barThickness;\n viewBoxMaxY = isBottom ? config.barThickness : 0;\n }\n\n // Adjust along x boundaries using adjustRectWidthForStroke (x=0..dLen in local band)\n const adjustedX = adjustRectWidthForStroke(\n rectX,\n rectWidth,\n rectX,\n rectX + rectWidth,\n strokeWidth\n );\n rectX = adjustedX.x;\n rectWidth = adjustedX.width;\n\n const adjustedY = adjustRectHeightForStroke(\n rectY,\n rectHeight,\n viewBoxMinY,\n viewBoxMaxY,\n strokeWidth\n );\n rectY = adjustedY.y;\n rectHeight = adjustedY.height;\n\n // Use simple rect when all corners or no corners are rounded\n if (allCornersRounded || noCornersRounded) {\n const rx = allCornersRounded ? r : 0;\n const ry = allCornersRounded ? r : 0;\n\n if (config.scaleBackground) {\n // When scaleBackground=true, draw fill and stroke separately to exclude edge touching scale\n const isBottom = config.side === 'bottom';\n\n // Stroke path excludes the edge touching the scale\n let strokePath: string;\n if (isBottom) {\n // Exclude bottom edge (touching scale on bottom side)\n strokePath = `M ${rectX + (noCornersRounded ? 0 : r)} ${rectY}`; // Top edge start\n strokePath += ` L ${rectX + rectWidth - (noCornersRounded ? 0 : r)} ${rectY}`; // Top edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY} ${rectX + rectWidth} ${rectY + r}`; // Top-right corner\n strokePath += ` L ${rectX + rectWidth} ${rectY + rectHeight - (noCornersRounded ? 0 : r)}`; // Right edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY + rectHeight} ${rectX + rectWidth - r} ${rectY + rectHeight}`; // Bottom-right corner (no stroke)\n strokePath += ` M ${rectX + (noCornersRounded ? 0 : r)} ${rectY + rectHeight}`; // Move to bottom-left (no stroke on bottom edge)\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY + rectHeight} ${rectX} ${rectY + rectHeight - r}`; // Bottom-left corner (no stroke)\n strokePath += ` L ${rectX} ${rectY + (noCornersRounded ? 0 : r)}`; // Left edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY} ${rectX + r} ${rectY}`; // Top-left corner\n } else {\n // Exclude top edge (touching scale on top side)\n strokePath = `M ${rectX} ${rectY + (noCornersRounded ? 0 : r)}`; // Left edge start\n strokePath += ` L ${rectX} ${rectY + rectHeight - (noCornersRounded ? 0 : r)}`; // Left edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY + rectHeight} ${rectX + r} ${rectY + rectHeight}`; // Bottom-left corner\n strokePath += ` L ${rectX + rectWidth - (noCornersRounded ? 0 : r)} ${rectY + rectHeight}`; // Bottom edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY + rectHeight} ${rectX + rectWidth} ${rectY + rectHeight - r}`; // Bottom-right corner\n strokePath += ` L ${rectX + rectWidth} ${rectY + (noCornersRounded ? 0 : r)}`; // Right edge\n if (!noCornersRounded)\n strokePath += ` Q ${rectX + rectWidth} ${rectY} ${rectX + rectWidth - r} ${rectY}`; // Top-right corner (no stroke)\n strokePath += ` M ${rectX + (noCornersRounded ? 0 : r)} ${rectY}`; // Move to top edge start (no stroke on top edge)\n if (!noCornersRounded)\n strokePath += ` Q ${rectX} ${rectY} ${rectX} ${rectY + r}`; // Top-left corner (no stroke)\n }\n\n return svg`\n <rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${rx} ry=${ry} fill=${fillColor} stroke=\"none\"/>\n <path d=\"${strokePath}\" fill=\"none\" stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n `;\n }\n\n return svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${rx} ry=${ry} fill=${fillColor} stroke=${strokeColor} vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n // Use path for selective corner rounding\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n let path = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n\n // When scaleBackground=true, draw fill and stroke separately to exclude edge touching scale\n if (config.scaleBackground) {\n const isBottom = config.side === 'bottom';\n\n // Stroke path excludes the edge touching the scale\n let strokePath: string;\n if (isBottom) {\n // Exclude bottom edge\n strokePath = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n strokePath += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight)\n strokePath += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n strokePath += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight)\n strokePath += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n strokePath += ` M ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft)\n strokePath += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n strokePath += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) strokePath += ` Q ${x} ${y} ${x + r} ${y}`;\n } else {\n // Exclude top edge\n strokePath = `M ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) strokePath += ` Q ${x} ${y} ${x + r} ${y}`;\n strokePath += ` M ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight)\n strokePath += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n strokePath += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight)\n strokePath += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n strokePath += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft)\n strokePath += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n strokePath += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n }\n\n return svg`\n <path d=${path} fill=${fillColor} stroke=\"none\"/>\n <path d=\"${strokePath}\" fill=\"none\" stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n `;\n }\n\n return svg`<path d=${path} fill=${fillColor} stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>`;\n}\n\nfunction generateBarFill(\n config: ExternalScaleConfig\n): SVGTemplateResult | typeof nothing {\n if (!config.hasBar || config.value === undefined) return nothing;\n\n // NOTE:\n // The bar container can have a larger radius (driven by component size CSS vars).\n // When the fill segment is short, rounding the fill geometry directly must clamp the\n // radius to avoid self-intersection, which makes the fill appear to ignore the larger\n // radius. Instead, render the fill as a plain rect and clip it with the exact same\n // shape as the bar container so the visible corners always match.\n\n // Clip-path id: only needs to be unique within the current <svg>.\n const clipId = `obc-bar-fill-clip-${Math.random().toString(36).slice(2)}`;\n\n const borderRadiusFallback = config.scaleType === 'condensed' ? 4 : 8;\n const borderRadiusValue = config.borderRadius ?? borderRadiusFallback;\n const r = borderRadiusValue;\n\n const c = colors(config);\n\n // Always use fillMin → fillMax range (defaults to 0 → value if not specified)\n const fillMin = config.fillMin ?? 0;\n const fillMax = config.fillMax ?? config.value;\n\n const v0 = Math.max(Math.min(fillMin, config.maxValue), config.minValue);\n const v1 = Math.max(Math.min(fillMax, config.maxValue), config.minValue);\n\n const a0 = valueToMainAxis(config, v0);\n const a1 = valueToMainAxis(config, v1);\n\n const markerSize = 8;\n const markerR = 4;\n\n // Build the same bar container shape (radius-position aware) for clipping.\n // Keep this logic aligned with generateBarContainer(), but do not modify the container.\n // Note: No stroke adjustment needed - fill should span the entire bar including borders.\n const dLen = drawingLength(config);\n const axisShift = mainAxisOffset(config);\n\n let barRoundTopLeft = true;\n let barRoundTopRight = true;\n let barRoundBottomLeft = true;\n let barRoundBottomRight = true;\n\n if (config.borderRadiusPosition) {\n if (\n config.borderRadiusPosition === BorderRadiusPosition.middleChild ||\n config.borderRadiusPosition === BorderRadiusPosition.middleRoundedChild\n ) {\n // No rounded corners for middle child\n // (middleRoundedChild is chart-canvas-only; ignored for external scales)\n barRoundTopLeft = false;\n barRoundTopRight = false;\n barRoundBottomLeft = false;\n barRoundBottomRight = false;\n } else if (isVertical(config)) {\n const isRight = config.side === 'right';\n const isInner =\n config.borderRadiusPosition === BorderRadiusPosition.innerFirstChild;\n\n if (isRight) {\n barRoundTopLeft = isInner;\n barRoundBottomLeft = isInner;\n barRoundTopRight = !isInner;\n barRoundBottomRight = !isInner;\n } else {\n barRoundTopLeft = !isInner;\n barRoundBottomLeft = !isInner;\n barRoundTopRight = isInner;\n barRoundBottomRight = isInner;\n }\n } else {\n const isBottom = config.side === 'bottom';\n const isInner =\n config.borderRadiusPosition === BorderRadiusPosition.innerFirstChild;\n\n if (isBottom) {\n barRoundTopLeft = isInner;\n barRoundTopRight = isInner;\n barRoundBottomLeft = !isInner;\n barRoundBottomRight = !isInner;\n } else {\n barRoundTopLeft = !isInner;\n barRoundTopRight = !isInner;\n barRoundBottomLeft = isInner;\n barRoundBottomRight = isInner;\n }\n }\n }\n\n const barAllCornersRounded =\n barRoundTopLeft &&\n barRoundTopRight &&\n barRoundBottomLeft &&\n barRoundBottomRight;\n const barNoCornersRounded =\n !barRoundTopLeft &&\n !barRoundTopRight &&\n !barRoundBottomLeft &&\n !barRoundBottomRight;\n\n if (isVertical(config)) {\n const boxX = isOutwardPositive(config) ? 0 : -config.barThickness;\n const boxWidth = config.barThickness;\n const y = Math.min(a0, a1);\n const h = Math.abs(a1 - a0);\n\n // Clip shape for the full bar container (no stroke adjustment - fill should\n // span the entire bar including borders, the clip constrains it visually)\n const rectX = isOutwardPositive(config) ? 0 : -config.barThickness;\n const rectY = -dLen / 2 + axisShift;\n const rectWidth = config.barThickness;\n const rectHeight = dLen;\n\n const barClipShape = barNoCornersRounded\n ? svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${0} ry=${0}/>`\n : barAllCornersRounded\n ? svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${r} ry=${r}/>`\n : svg`<path d=${(() => {\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n let path = `M ${x + (barRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (barRoundTopRight ? r : 0)} ${y}`;\n if (barRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (barRoundBottomRight ? r : 0)}`;\n if (barRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (barRoundBottomLeft ? r : 0)} ${y + h}`;\n if (barRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (barRoundTopLeft ? r : 0)}`;\n if (barRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n return path;\n })()}/>`;\n\n const fillRect = svg`<rect x=${boxX} y=${y} width=${boxWidth} height=${h} fill=${c.barFillColor} stroke=\"none\"/>`;\n\n // For tint mode, render marker at value position\n if (config.fillMode === 'tint') {\n const markerY = valueToMainAxis(config, config.value) - markerSize / 2;\n const marker = svg`<rect x=${boxX} y=${markerY} width=${boxWidth} height=${markerSize} rx=${markerR} fill=${c.markerFillColor} stroke=${c.markerStrokeColor} vector-effect=\"non-scaling-stroke\"/>`;\n\n return svg`<defs>\n <clipPath id=${clipId} clipPathUnits=\"userSpaceOnUse\">${barClipShape}</clipPath>\n </defs>\n <g clip-path=${`url(#${clipId})`}>\n ${fillRect}\n ${marker}\n </g>`;\n }\n\n return svg`<defs>\n <clipPath id=${clipId} clipPathUnits=\"userSpaceOnUse\">${barClipShape}</clipPath>\n </defs>\n <g clip-path=${`url(#${clipId})`}>\n ${fillRect}\n </g>`;\n }\n\n // Horizontal orientation\n const boxY = isOutwardPositive(config) ? 0 : -config.barThickness;\n const boxHeight = config.barThickness;\n const x = Math.min(a0, a1);\n const w = Math.abs(a1 - a0);\n\n // Clip shape for the full bar container (no stroke adjustment - fill should\n // span the entire bar including borders, the clip constrains it visually)\n const rectX = mainAxisOffset(config);\n const rectY = isOutwardPositive(config) ? 0 : -config.barThickness;\n const rectWidth = dLen;\n const rectHeight = config.barThickness;\n\n const barClipShape = barNoCornersRounded\n ? svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${0} ry=${0}/>`\n : barAllCornersRounded\n ? svg`<rect x=${rectX} y=${rectY} width=${rectWidth} height=${rectHeight} rx=${r} ry=${r}/>`\n : svg`<path d=${(() => {\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n let path = `M ${x + (barRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (barRoundTopRight ? r : 0)} ${y}`;\n if (barRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (barRoundBottomRight ? r : 0)}`;\n if (barRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (barRoundBottomLeft ? r : 0)} ${y + h}`;\n if (barRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (barRoundTopLeft ? r : 0)}`;\n if (barRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n return path;\n })()}/>`;\n\n const fillRect = svg`<rect x=${x} y=${boxY} width=${w} height=${boxHeight} fill=${c.barFillColor} stroke=\"none\"/>`;\n\n // For tint mode, render marker at value position\n if (config.fillMode === 'tint') {\n const markerX = valueToMainAxis(config, config.value) - markerSize / 2;\n const marker = svg`<rect x=${markerX} y=${boxY} width=${markerSize} height=${boxHeight} rx=${markerR} fill=${c.markerFillColor} stroke=${c.markerStrokeColor} vector-effect=\"non-scaling-stroke\"/>`;\n return svg`<defs>\n <clipPath id=${clipId} clipPathUnits=\"userSpaceOnUse\">${barClipShape}</clipPath>\n </defs>\n <g clip-path=${`url(#${clipId})`}>\n ${fillRect}\n ${marker}\n </g>`;\n }\n\n return svg`<defs>\n <clipPath id=${clipId} clipPathUnits=\"userSpaceOnUse\">${barClipShape}</clipPath>\n </defs>\n <g clip-path=${`url(#${clipId})`}>\n ${fillRect}\n </g>`;\n}\n\nfunction generateScaleBackground(\n config: ExternalScaleConfig\n): SVGTemplateResult | typeof nothing {\n if (!config.scaleBackground) return nothing;\n\n const borderRadiusFallback = config.scaleType === 'condensed' ? 4 : 8;\n const borderRadiusValue = config.borderRadius ?? borderRadiusFallback;\n const strokeWidth = 1;\n const fillColor = 'var(--instrument-frame-primary-color)';\n const strokeColor = 'var(--instrument-frame-tertiary-color)';\n\n // Calculate thickness: main tick length + 4px gap\n const {main} = getTickThicknesses(config.scaleType);\n const backgroundThickness = main + tickGap();\n\n const dLen = drawingLength(config);\n const axisShift = mainAxisOffset(config);\n\n // Determine which corners should be rounded (outer corners only)\n const shouldRoundTopLeft =\n (config.orientation === 'vertical' && config.side === 'left') ||\n (config.orientation === 'horizontal' && config.side === 'top');\n const shouldRoundTopRight =\n (config.orientation === 'vertical' && config.side === 'right') ||\n (config.orientation === 'horizontal' && config.side === 'top');\n const shouldRoundBottomLeft =\n (config.orientation === 'vertical' && config.side === 'left') ||\n (config.orientation === 'horizontal' && config.side === 'bottom');\n const shouldRoundBottomRight =\n (config.orientation === 'vertical' && config.side === 'right') ||\n (config.orientation === 'horizontal' && config.side === 'bottom');\n\n const r = borderRadiusValue;\n\n if (isVertical(config)) {\n // Start at bar's outer edge if bar exists, otherwise at chart edge (0)\n const startPerp = config.hasBar\n ? isOutwardPositive(config)\n ? config.barThickness\n : -config.barThickness\n : 0;\n\n let rectX = isOutwardPositive(config)\n ? startPerp\n : startPerp - backgroundThickness;\n let rectY = -dLen / 2 + axisShift;\n let rectWidth = backgroundThickness;\n let rectHeight = dLen;\n\n const isRight = config.side === 'right';\n let viewBoxMinX: number;\n let viewBoxMaxX: number;\n if (config.hasBar) {\n // Exclude the inner edge (touching bar) from stroke adjustment\n if (isRight) {\n // Right side: scale is at x=barThickness..(barThickness+backgroundThickness)\n // Inner edge is left (at barThickness), don't adjust it\n viewBoxMinX = rectX - 1; // -1 so rectX won't match\n viewBoxMaxX = rectX + rectWidth;\n } else {\n // Left side: scale is at x=(-barThickness-backgroundThickness)..(-barThickness)\n // Inner edge is right (at -barThickness), don't adjust it\n viewBoxMinX = rectX;\n viewBoxMaxX = rectX + rectWidth + 1; // +1 so rectX+rectWidth won't match\n }\n } else {\n viewBoxMinX = rectX;\n viewBoxMaxX = rectX + rectWidth;\n }\n\n const adjustedX = adjustRectWidthForStroke(\n rectX,\n rectWidth,\n viewBoxMinX,\n viewBoxMaxX,\n strokeWidth\n );\n rectX = adjustedX.x;\n rectWidth = adjustedX.width;\n\n const adjustedY = adjustRectHeightForStroke(\n rectY,\n rectHeight,\n -dLen / 2 + axisShift,\n dLen / 2 + axisShift,\n strokeWidth\n );\n rectY = adjustedY.y;\n rectHeight = adjustedY.height;\n\n // Build path with selective rounded corners\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n // Path construction: start top-left, go clockwise\n let path = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n\n // Stroke the entire path, then cover the inner edge with a line\n // Line is shortened by half-stroke on each end to avoid overlapping with top/bottom strokes\n const innerX = isRight ? x : x + w;\n const halfStroke = strokeWidth / 2;\n\n return svg`<path d=${path} fill=${fillColor} stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n <line x1=${innerX} x2=${innerX} y1=${y + halfStroke} y2=${y + h - halfStroke} stroke=${fillColor} stroke-width=${strokeWidth + 0.5} vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n // Horizontal: background spans full drawing length (x), thickness is y\n const startPerp = config.hasBar\n ? isOutwardPositive(config)\n ? config.barThickness\n : -config.barThickness\n : 0;\n\n let rectX = mainAxisOffset(config);\n let rectY = isOutwardPositive(config)\n ? startPerp\n : startPerp - backgroundThickness;\n let rectWidth = dLen;\n let rectHeight = backgroundThickness;\n\n const isBottom = config.side === 'bottom';\n let viewBoxMinY: number;\n let viewBoxMaxY: number;\n if (config.hasBar) {\n // Exclude the inner edge (touching bar) from stroke adjustment\n if (isBottom) {\n // Bottom side: scale is at y=barThickness..(barThickness+backgroundThickness)\n // Inner edge is top (at barThickness), don't adjust it\n viewBoxMinY = rectY - 1; // -1 so rectY won't match\n viewBoxMaxY = rectY + rectHeight;\n } else {\n // Top side: scale is at y=(-barThickness-backgroundThickness)..(-barThickness)\n // Inner edge is bottom (at -barThickness), don't adjust it\n viewBoxMinY = rectY;\n viewBoxMaxY = rectY + rectHeight + 1; // +1 so rectY+rectHeight won't match\n }\n } else {\n viewBoxMinY = rectY;\n viewBoxMaxY = rectY + rectHeight;\n }\n\n // Adjust along x boundaries\n const adjustedX = adjustRectWidthForStroke(\n rectX,\n rectWidth,\n rectX,\n rectX + rectWidth,\n strokeWidth\n );\n rectX = adjustedX.x;\n rectWidth = adjustedX.width;\n\n const adjustedY = adjustRectHeightForStroke(\n rectY,\n rectHeight,\n viewBoxMinY,\n viewBoxMaxY,\n strokeWidth\n );\n rectY = adjustedY.y;\n rectHeight = adjustedY.height;\n\n // Build path with selective rounded corners\n const x = rectX;\n const y = rectY;\n const w = rectWidth;\n const h = rectHeight;\n\n // Path construction: start top-left, go clockwise\n let path = `M ${x + (shouldRoundTopLeft ? r : 0)} ${y}`;\n path += ` L ${x + w - (shouldRoundTopRight ? r : 0)} ${y}`;\n if (shouldRoundTopRight) {\n path += ` Q ${x + w} ${y} ${x + w} ${y + r}`;\n }\n path += ` L ${x + w} ${y + h - (shouldRoundBottomRight ? r : 0)}`;\n if (shouldRoundBottomRight) {\n path += ` Q ${x + w} ${y + h} ${x + w - r} ${y + h}`;\n }\n path += ` L ${x + (shouldRoundBottomLeft ? r : 0)} ${y + h}`;\n if (shouldRoundBottomLeft) {\n path += ` Q ${x} ${y + h} ${x} ${y + h - r}`;\n }\n path += ` L ${x} ${y + (shouldRoundTopLeft ? r : 0)}`;\n if (shouldRoundTopLeft) {\n path += ` Q ${x} ${y} ${x + r} ${y}`;\n }\n path += ` Z`;\n\n // Stroke the entire path, then cover the inner edge with a line\n // Line is shortened by half-stroke on each end to avoid overlapping with left/right strokes\n const innerY = isBottom ? y : y + h;\n const halfStroke = strokeWidth / 2;\n\n return svg`<path d=${path} fill=${fillColor} stroke=${strokeColor} stroke-width=${strokeWidth} vector-effect=\"non-scaling-stroke\"/>\n <line x1=${x + halfStroke} x2=${x + w - halfStroke} y1=${innerY} y2=${innerY} stroke=${fillColor} stroke-width=${strokeWidth + 0.5} vector-effect=\"non-scaling-stroke\"/>`;\n}\n\n// ============================================================================\n// Setpoint Marker (uses unified setpoint interface from svghelpers/setpoint.ts)\n// ============================================================================\n\n/**\n * Calculate the rotation angle needed for the setpoint marker based on\n * orientation and side.\n *\n * The `drawSetpointMarker()` renders the marker with tip at origin pointing\n * down (positive Y direction). We need to rotate it so the tip points toward\n * the bar/chart area.\n *\n * Transform table:\n * | Orientation | Side | Marker Points | Rotation |\n * |-------------|--------|---------------|----------|\n * | vertical | right | ← (left) | 90° |\n * | vertical | left | → (right) | -90° |\n * | horizontal | bottom | ↑ (up) | 180° |\n * | horizontal | top | ↓ (down) | 0° |\n */\nfunction getSetpointRotation(config: ExternalScaleConfig): number {\n if (isVertical(config)) {\n // Vertical: right side points left (90°), left side points right (-90°)\n return config.side === 'right' ? 90 : -90;\n }\n // Horizontal: bottom points up (180°), top points down (0°)\n return config.side === 'bottom' ? 180 : 0;\n}\n\n/**\n * Helper to render a single setpoint marker at a given value.\n *\n * @param config - Scale configuration\n * @param setpointValue - The value to position the marker at\n * @param visualState - The visual state for the marker\n * @param colorMode - The color mode for the marker\n * @param disabled - Whether the setpoint is in disabled state\n * @param idSuffix - Suffix for the unique ID\n * @param opacity - Optional opacity (default 1)\n * @param animate - Whether to apply CSS transition for smooth movement\n */\nfunction renderSingleSetpoint(\n config: ExternalScaleConfig,\n setpointValue: number,\n visualState: SetpointVisualState,\n colorMode: SetpointColorMode,\n disabled: boolean,\n idSuffix: string,\n opacity: number = 1,\n animate: boolean = false\n): SVGTemplateResult {\n // Generate unique ID to avoid conflicts with multiple instruments on page\n const baseId = generateSetpointId(`external-scale-setpoint-${idSuffix}`);\n\n // Get outward offset based on visual state (drawSetpointMarker handles scaling internally)\n const stateOffset = getSetpointOutwardOffset(visualState);\n\n // Check if setpoint snaps to zero\n const setpointAtZero =\n Math.abs(setpointValue) < config.setpointAtZeroDeadband;\n\n // Main axis position (where the marker sits along the scale)\n // Always use valueToMainAxis — even for zero-snap, since coordinate 0\n // only equals value 0 for symmetric bipolar scales (e.g. -100..+100).\n // For non-symmetric scales (e.g. 0..100), value 0 maps to a non-zero coordinate.\n const mainAxisPos = setpointAtZero\n ? valueToMainAxis(config, 0)\n : valueToMainAxis(config, setpointValue);\n\n // Perpendicular axis position (distance from chart edge)\n const base = tickBasePerp(config);\n const outwardOffset = tickGap(); // Base offset from tick area\n\n // Add state-based offset (shifts marker further outward for notEqual/focus/equalZero states)\n const totalOutwardOffset = outwardOffset + stateOffset;\n\n const perpAxisPos = isOutwardPositive(config)\n ? base + totalOutwardOffset\n : base - totalOutwardOffset;\n\n // Get rotation angle for this orientation/side\n const rotation = getSetpointRotation(config);\n\n // Build the transform string\n // Position first, then rotate around the tip (which is at origin after drawSetpointMarker)\n const x = isVertical(config) ? perpAxisPos : mainAxisPos;\n const y = isVertical(config) ? mainAxisPos : perpAxisPos;\n\n // Note: drawSetpointMarker() handles scaling internally based on visualState\n if (animate) {\n // Use CSS style transform + transition for animated movement.\n // CSS `transform` on SVG elements uses the local coordinate system\n // (1px = 1 SVG user unit). `transform-origin: 0 0` is the default for\n // SVG elements per spec, matching SVG attribute behavior.\n const duration = `var(${SETPOINT_ANIMATION_CSS_VAR}, ${SETPOINT_ANIMATION_DURATION_DEFAULT})`;\n return svg`\n <g style=\"transform: translate(${x}px, ${y}px) rotate(${rotation}deg); opacity: ${opacity}; transition: transform ${duration} ease-out, opacity ${duration} ease-out;\">\n ${drawSetpointMarker({visualState, colorMode, disabled, id: baseId})}\n </g>\n `;\n }\n\n return svg`\n <g transform=\"translate(${x}, ${y}) rotate(${rotation})\" opacity=\"${opacity}\">\n ${drawSetpointMarker({visualState, colorMode, disabled, id: baseId})}\n </g>\n `;\n}\n\n/**\n * Render the setpoint marker(s) using the unified interface from setpoint.ts.\n *\n * When `newSetpoint` is defined, renders two markers:\n * 1. Original setpoint at 0.75 opacity (dimmed)\n * 2. New setpoint in 'focus' visual state at full opacity (on top)\n *\n * When `animateSetpoint` is true:\n * - The original marker uses CSS `transition` for smooth position/opacity changes\n * - During confirm (newSetpoint → undefined), the departing new-setpoint marker\n * fades out via CSS transition (opacity 1 → 0) over the animation duration\n *\n * The marker is positioned on the scale based on the setpoint value,\n * with transforms applied for orientation/side.\n */\nfunction setpointMarker(\n config: ExternalScaleConfig\n): SVGTemplateResult | typeof nothing {\n const hasOriginalSetpoint = config.setpoint !== undefined;\n const hasNewSetpoint = config.newSetpoint !== undefined;\n const hasDepartingNewSetpoint = config.departingNewSetpoint !== undefined;\n const animate = config.animateSetpoint === true;\n\n // If neither setpoint is defined (and no departing animation), render nothing\n if (!hasOriginalSetpoint && !hasNewSetpoint && !hasDepartingNewSetpoint)\n return nothing;\n\n const markers: SVGTemplateResult[] = [];\n\n // Render original setpoint (dimmed when newSetpoint is active)\n if (hasOriginalSetpoint) {\n const visualState = deriveSetpointVisualState(config);\n const colorMode = deriveSetpointColorMode(config);\n const disabled = deriveSetpointDisabled(config);\n const opacity = hasNewSetpoint ? 0.75 : 1;\n\n markers.push(\n renderSingleSetpoint(\n config,\n config.setpoint!,\n visualState,\n colorMode,\n disabled,\n 'original',\n opacity,\n animate\n )\n );\n }\n\n // Render newSetpoint in focus state (always on top)\n // OR render departing newSetpoint during confirm animation (fading to 0 opacity)\n if (hasNewSetpoint || hasDepartingNewSetpoint) {\n const isActive = hasNewSetpoint;\n const value = isActive ? config.newSetpoint! : config.departingNewSetpoint!;\n const targetOpacity = isActive ? 1 : 0; // fade to 0 during confirm animation\n\n // newSetpoint always renders in focus visual state\n const visualState = SetpointVisualState.focus;\n // Use the same color mode derivation for new setpoint\n const colorMode = deriveSetpointColorMode(config);\n // newSetpoint is never disabled (it's the active adjustment target)\n const disabled = false;\n\n markers.push(\n renderSingleSetpoint(\n config,\n value,\n visualState,\n colorMode,\n disabled,\n 'new',\n targetOpacity,\n animate\n )\n );\n }\n\n return svg`${markers}`;\n}\n\n/**\n * Generate a dot indicator at the current value position.\n *\n * The dot is:\n * - 12x12px filled circle with 2px stroke (16px total visual size)\n * - Positioned in the scale band, touching its inner edge (towards the chart)\n * - Fill uses secondary color (enhanced or regular based on config.priority)\n * - Stroke uses --instrument-frame-primary-color\n *\n * @param config - Scale configuration\n * @returns SVG template for the current value dot, or nothing if disabled/no value\n */\nfunction generateCurrentValueDot(\n config: ExternalScaleConfig\n): SVGTemplateResult | typeof nothing {\n // The dot is positioned in the scale band. When hasScale=false, the layout\n // thickness excludes the scale band, so the dot would render outside the\n // viewBox and be clipped. Skip rendering in that case.\n if (\n !config.highlightCurrentValue ||\n config.value === undefined ||\n !config.hasScale\n ) {\n return nothing;\n }\n\n const dotDiameter = 12; // Inner fill diameter\n const strokeWidth = 2;\n // Total visual size: stroke is centered on path, so adds strokeWidth/2 to each side\n // Visual radius = fillRadius + strokeWidth/2 = 6 + 1 = 7\n const visualRadius = dotDiameter / 2 + strokeWidth / 2;\n const dotRadius = dotDiameter / 2;\n\n // Position on main axis (value to coordinate)\n const pos = valueToMainAxis(config, config.value);\n\n // Position on perpendicular axis:\n // The dot should be in the scale band, touching its inner edge (towards the chart/bar)\n //\n // The scale background (when shown) spans from barEdge to barEdge+backgroundThickness\n // where backgroundThickness = mainTickLength + gap (e.g., 10+4=14 for condensed)\n //\n // For the dot to touch the INNER edge (toward chart) and stay INSIDE the scale band:\n // - Inner edge of scale background = barEdge (or 0 if no bar)\n // - Dot's inner edge should be at the inner edge of the scale band\n // - So dot center = innerEdge + visualRadius\n const base = tickBasePerp(config);\n\n // Dot center should be positioned so the dot's inner edge touches the scale band's inner edge\n const perpCenter = isOutwardPositive(config)\n ? base + visualRadius\n : base - visualRadius;\n\n const c = colors(config);\n // Use secondary color for fill (same as markerFillColor from colors function)\n const fillColor = c.markerFillColor;\n const strokeColor = 'var(--instrument-frame-primary-color)';\n\n // Render the dot\n if (isVertical(config)) {\n return svg`\n <circle\n cx=${perpCenter}\n cy=${pos}\n r=${dotRadius}\n fill=${fillColor}\n stroke=${strokeColor}\n stroke-width=${strokeWidth}\n vector-effect=\"non-scaling-stroke\"\n />\n `;\n }\n\n // Horizontal orientation\n return svg`\n <circle\n cx=${pos}\n cy=${perpCenter}\n r=${dotRadius}\n fill=${fillColor}\n stroke=${strokeColor}\n stroke-width=${strokeWidth}\n vector-effect=\"non-scaling-stroke\"\n />\n `;\n}\n\nfunction singleSidedTickmark(\n config: ExternalScaleConfig,\n value: number,\n style: TickmarkStyle,\n tickBase: number\n): SVGTemplateResult | null {\n if (value >= config.maxValue || value <= config.minValue) return null;\n\n const color = tickmarkColor(style);\n const pos = valueToMainAxis(config, value);\n\n const gap = tickGap();\n const start = isOutwardPositive(config) ? tickBase + gap : tickBase - gap;\n const len = computeExternalScaleEffectiveTickThickness(config);\n const end = isOutwardPositive(config) ? start + len : start - len;\n\n if (isVertical(config)) {\n return svg`<line x1=${start} x2=${end} y1=${pos} y2=${pos} stroke=${color} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n return svg`<line x1=${pos} x2=${pos} y1=${start} y2=${end} stroke=${color} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\"/>`;\n}\n\nfunction advicePill(\n config: ExternalScaleConfig,\n advice: ExternalScaleAdviceRaw,\n x1: number,\n fill: string,\n stroke: string\n): SVGTemplateResult {\n const width = 8;\n const offset = 4;\n const r = width / 2;\n const inset = 4;\n\n if (isVertical(config)) {\n const yMin = valueToMainAxis(config, advice.min);\n const yMax = valueToMainAxis(config, advice.max);\n const yL = Math.min(yMin, yMax);\n const yH = Math.max(yMin, yMax);\n\n const x = x1 + offset;\n const y = yL + inset;\n const h = Math.max(0, yH - yL - inset * 2);\n\n return svg`<rect x=${x} y=${y} width=${width} height=${h} rx=${r} ry=${r} fill=${fill} stroke=${stroke} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\"/>`;\n }\n\n const xMin = valueToMainAxis(config, advice.min);\n const xMax = valueToMainAxis(config, advice.max);\n const xL = Math.min(xMin, xMax);\n const xH = Math.max(xMin, xMax);\n\n const x = xL + inset;\n const y = x1 + offset;\n const w = Math.max(0, xH - xL - inset * 2);\n\n return svg`<rect x=${x} y=${y} width=${w} height=${width} rx=${r} ry=${r} fill=${fill} stroke=${stroke} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\"/>`;\n}\n\nfunction renderAdvice(\n config: ExternalScaleConfig,\n advice: ExternalScaleAdviceRaw\n): SVGTemplateResult {\n const tickBase = tickBasePerp(config);\n const hasBarArea = config.hasBar;\n const effectiveAdvicePosition = hasBarArea ? config.advicePosition : 'inner';\n\n // Determine x1 (perpendicular) position for the 8px mask\n let x1: number;\n\n if (effectiveAdvicePosition === 'center') {\n const adviceWidth = 8;\n const centerOffset = config.barThickness / 2 - adviceWidth / 2;\n\n if (isVertical(config)) {\n x1 = isOutwardPositive(config)\n ? centerOffset - 4\n : -config.barThickness + centerOffset - 4;\n } else {\n x1 = isOutwardPositive(config)\n ? centerOffset - 4\n : -config.barThickness + centerOffset - 4;\n }\n } else if (effectiveAdvicePosition === 'inner') {\n x1 = isOutwardPositive(config) ? tickBase : tickBase - 16;\n } else {\n x1 = isOutwardPositive(config)\n ? config.barThickness + 10\n : -config.barThickness -\n computeExternalScaleEffectiveTickThickness(config) +\n 14;\n }\n\n // Dashed boundary tickmarks across the bar band\n const ticks: SVGTemplateResult[] = [];\n\n const dashStroke = 'var(--instrument-frame-tertiary-color)';\n\n const minBound = advice.min > config.minValue;\n const maxBound = advice.max < config.maxValue;\n\n const barStart = isOutwardPositive(config) ? 0 : -config.barThickness;\n const barEnd = isOutwardPositive(config) ? config.barThickness : 0;\n\n const dash = (v: number) => {\n const p = valueToMainAxis(config, v);\n if (isVertical(config)) {\n ticks.push(\n svg`<line x1=${barStart} x2=${barEnd} y1=${p} y2=${p} stroke=${dashStroke} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\" stroke-dasharray=\"4 4\"/>`\n );\n } else {\n ticks.push(\n svg`<line x1=${p} x2=${p} y1=${barStart} y2=${barEnd} stroke=${dashStroke} stroke-width=\"1\" vector-effect=\"non-scaling-stroke\" stroke-dasharray=\"4 4\"/>`\n );\n }\n };\n\n if (minBound) dash(advice.min);\n if (maxBound) dash(advice.max);\n\n if (advice.type === AdviceType.caution) {\n let mainColor: string;\n let fillColor: string = 'var(--instrument-frame-primary-color)';\n\n if (advice.state === AdviceState.hinted) {\n mainColor = 'var(--instrument-frame-tertiary-color)';\n } else if (advice.state === AdviceState.regular) {\n mainColor = 'var(--instrument-tick-mark-tertiary-color)';\n } else {\n mainColor = 'var(--on-caution-active-color)';\n fillColor = 'var(--alert-caution-color)';\n }\n\n const pattern: SVGTemplateResult[] = [];\n const ypattern = 50;\n\n const aMin = valueToMainAxis(config, advice.min);\n const aMax = valueToMainAxis(config, advice.max);\n const mainMin = Math.min(aMin, aMax);\n const mainMax = Math.max(aMin, aMax);\n const span = mainMax - mainMin;\n\n // Tile across the advice's main-axis span so hatch reaches the full advice region.\n if (isVertical(config)) {\n // Center the 50px tile on the 8px pill thickness.\n const xOffset = x1 + 8 - 25;\n // Start a bit before the advice, then tile across its full height.\n const yStart = mainMin - 25;\n\n for (let i = -64; i < span + 64; i += 16) {\n const transform = `translate(${xOffset} ${yStart + i})`;\n const path = `M 50 0 L 0 ${ypattern}`;\n pattern.push(\n svg`<g transform=${transform}><path d=${path} stroke=${mainColor} stroke-width=\"6\"/></g>`\n );\n }\n } else {\n // Center the 50px tile on the 8px pill thickness.\n const yOffset = x1 + 8 - 25;\n // Start a bit before the advice, then tile across its full width.\n const xStart = mainMin - 25;\n\n for (let i = -64; i < span + 64; i += 16) {\n const transform = `translate(${xStart + i} ${yOffset})`;\n const path = `M 0 50 L ${ypattern} 0`;\n pattern.push(\n svg`<g transform=${transform}><path d=${path} stroke=${mainColor} stroke-width=\"6\"/></g>`\n );\n }\n }\n\n const maskId = `externalScaleAdviceMask-${advice.min}-${advice.max}-${Math.random().toString(36).slice(2)}`;\n\n let tickmarkStyle = TickmarkStyle.regular;\n if (advice.state === AdviceState.regular)\n tickmarkStyle = TickmarkStyle.regular;\n else if (advice.state === AdviceState.triggered)\n tickmarkStyle = TickmarkStyle.enhanced;\n\n return svg`\n <defs>\n <mask id=${maskId} maskUnits=\"userSpaceOnUse\" maskContentUnits=\"userSpaceOnUse\" x=\"-4096\" y=\"-4096\" width=\"8192\" height=\"8192\">\n ${advicePill(config, advice, x1, 'white', 'none')}\n </mask>\n </defs>\n <g mask=\"url(#${maskId})\">\n ${\n fillColor\n ? svg`<rect x=\"-2048\" y=\"-2048\" width=\"4096\" height=\"4096\" fill=${fillColor}/>`\n : nothing\n }\n ${pattern}\n </g>\n ${advicePill(config, advice, x1, 'none', mainColor)}\n ${singleSidedTickmark(config, advice.min, tickmarkStyle, tickBase) ?? nothing}\n ${singleSidedTickmark(config, advice.max, tickmarkStyle, tickBase) ?? nothing}\n ${ticks}\n `;\n }\n\n // Advice type\n let strokeColor: string;\n let tickmarkStyle: TickmarkStyle;\n let fillColor: string;\n\n if (advice.state === AdviceState.hinted) {\n strokeColor = 'var(--instrument-frame-tertiary-color)';\n fillColor = 'var(--instrument-frame-primary-color)';\n tickmarkStyle = TickmarkStyle.regular;\n } else if (advice.state === AdviceState.regular) {\n strokeColor = 'var(--instrument-regular-secondary-color)';\n fillColor = 'var(--instrument-frame-primary-color)';\n tickmarkStyle = TickmarkStyle.regular;\n } else {\n strokeColor = 'var(--instrument-enhanced-secondary-color)';\n fillColor = strokeColor;\n tickmarkStyle = TickmarkStyle.regular;\n }\n\n return svg`\n ${advicePill(config, advice, x1, fillColor, strokeColor)}\n ${singleSidedTickmark(config, advice.min, tickmarkStyle, tickBase) ?? nothing}\n ${singleSidedTickmark(config, advice.max, tickmarkStyle, tickBase) ?? nothing}\n ${ticks}\n `;\n}\n\nfunction generateAdviceOverlays(\n config: ExternalScaleConfig\n): SVGTemplateResult[] {\n if (!config.advices || !config.advices.length) return [];\n const raw = convertAdvices(config.advices, config.setpoint);\n return raw.map((a) => renderAdvice(config, a));\n}\n\n/**\n * Helper for web components to compute dimensions for reporting to parent charts.\n *\n * This calculates the minimal configuration needed to determine the scale's thickness,\n * avoiding the need to pass full configs with many irrelevant properties.\n *\n * @param config - Minimal layout configuration\n * @returns Object with side and thickness for event dispatching\n */\nexport function computeScaleDimensionsForReport(\n config: ExternalScaleLayoutConfig\n): {side: ExternalScaleSide; thickness: number} {\n const layout = computeExternalScaleLayout(config);\n const viewBox = computeExternalScaleViewBox(\n {orientation: config.orientation, length: config.length},\n layout\n );\n\n // For vertical scales, thickness is width; for horizontal, it's height\n const thickness =\n config.orientation === 'vertical' ? viewBox.width : viewBox.height;\n\n return {\n side: config.side,\n thickness,\n };\n}\n\n/**\n * Render the external scale as SVG fragments.\n *\n * This is a pure renderer: it does not touch DOM state and expects the caller\n * to place the returned fragments inside an `<svg>` with an appropriate viewBox.\n *\n * @param config - Scale configuration\n */\nexport function renderExternalScale(config: ExternalScaleConfig): {\n barContainer: SVGTemplateResult | typeof nothing;\n barFill: SVGTemplateResult | typeof nothing;\n scaleBackground: SVGTemplateResult | typeof nothing;\n tickmarks: SVGTemplateResult[];\n labels: SVGTemplateResult[];\n adviceOverlays: SVGTemplateResult[];\n currentValueDot: SVGTemplateResult | typeof nothing;\n setpoint: SVGTemplateResult | typeof nothing;\n} {\n const effectiveBarThickness =\n computeExternalScaleEffectiveBarThickness(config);\n const effectiveConfig: ExternalScaleConfig =\n effectiveBarThickness === config.barThickness\n ? config\n : {...config, barThickness: effectiveBarThickness};\n\n const parts: {\n barContainer: SVGTemplateResult | typeof nothing;\n barFill: SVGTemplateResult | typeof nothing;\n scaleBackground: SVGTemplateResult | typeof nothing;\n tickmarks: SVGTemplateResult[];\n labels: SVGTemplateResult[];\n adviceOverlays: SVGTemplateResult[];\n currentValueDot: SVGTemplateResult | typeof nothing;\n setpoint: SVGTemplateResult | typeof nothing;\n } = {\n barContainer: generateBarContainer(effectiveConfig),\n barFill: generateBarFill(effectiveConfig),\n scaleBackground: generateScaleBackground(effectiveConfig),\n tickmarks: generateTickmarks(effectiveConfig),\n labels: generateLabels(effectiveConfig),\n adviceOverlays: generateAdviceOverlays(effectiveConfig),\n currentValueDot: generateCurrentValueDot(effectiveConfig),\n setpoint: setpointMarker(effectiveConfig),\n };\n\n return parts;\n}\n"],"names":["ExternalScaleOrientation","ExternalScaleSide","ScaleType","FillMode","AdvicePosition","BarContainerStyle","isOutwardPositive","x","y","anchor","baseline","isBottom","rectX","rectY","rectWidth","rectHeight","adjustedX","adjustedY","isRight","w","h","path","barClipShape","fillRect","startPerp","halfStroke","fillColor","tickmarkStyle"],"mappings":"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"}