{"version":3,"sources":["../src/index-core.ts","../src/core.ts","../src/types/base.ts","../src/types/xy.ts","../src/types/map.ts","../src/types/pie.ts","../src/types/gauge.ts","../src/types/liquid-progress.ts","../src/types/sankey.ts","../src/types/chord.ts","../src/types/radar.ts","../src/types/network.ts","../src/types/tree.ts","../src/types/treemap.ts","../src/types/word-cloud.ts","../src/themes/index.ts","../src/adapters/common/text-measure.ts","../src/themes/echarts-theme.ts","../src/themes/presets.ts","../src/registry.ts","../src/themes/palette-registry.ts","../src/config.ts","../src/utils.ts","../src/adapters/common/defaults.ts","../src/adapters/common/shared.ts","../src/adapters/common/title.ts","../src/adapters/common/rich-text.ts","../src/adapters/common/legend.ts","../src/adapters/common/layout.ts","../src/adapters/common/stacked-text.ts","../src/adapters/common/date-utils.ts","../src/adapters/common/axis.ts","../src/async-tooltip.ts","../src/adapters/common/tooltip.ts","../src/adapters/common/font-family.ts","../src/adapters/common/icon-symbol.ts","../src/adapters/common/race-utils.ts","../src/adapters/common/series-utils.ts","../src/adapters/line.ts","../src/adapters/bar.ts","../src/adapters/map.ts","../src/tooltip-context.ts","../src/adapters/pie.ts","../src/adapters/gauge.ts","../src/adapters/liquid-progress.ts","../src/adapters/common/graph-colors.ts","../src/adapters/sankey.ts","../src/adapters/chord.ts","../src/adapters/radar.ts","../src/adapters/network.ts","../src/adapters/tree.ts","../src/adapters/treemap.ts","../src/adapters/word-cloud.ts","../src/adapters/index.ts","../src/disconnect-sentinel.ts","../src/api.ts","../src/map-registry.ts","../src/ssr-render.ts","../src/ssr-plugins.ts"],"sourcesContent":["// SSR-safe entry: same public API as `./index.js`, minus the\n// `<i-chart>` web component side-effect.\n//\n// Import this entry from server-side runtimes (Next.js, Nuxt, Astro,\n// SvelteKit, Vite SSR…) where the module graph must not touch Lit's\n// custom-element registry. Chart instances are still created\n// client-side via `createChart()` / `new IChart()` inside\n// `onMounted` / `useEffect` / `'use client'` blocks.\n\n// Core chart class\nexport { IChart } from './core.js';\n\n// Imperative API\nexport { createChart } from './api.js';\n\n// Map resource registration for `type: 'map'`.\nexport { registerMap, type MapGeoJsonSource, type MapSourceObject } from './map-registry.js';\n\n// Server-side rendering — produces a complete `<svg>...</svg>` string\n// from `(type, data, options)` without touching `window` / `document`\n// / `customElements` / `<canvas>`. Pair with `sharp` or\n// `@resvg/resvg-js` if you need PNG output. See `src/ssr-render.ts`\n// for the full plugin / fallback contract.\nexport {\n  renderChartToSVGString,\n  type RenderChartToSVGStringOptions,\n} from './ssr-render.js';\n\n// SSR-safe plugin installers. Server consumers call these once before\n// rendering plugin-backed chart types, instead of importing `echarts`\n// + `@echarts-x/*` directly. Today only `installLiquidProgress()`\n// ships — wordcloud is browser-only because the `@echarts-x/custom-\n// word-cloud` package isn't SSR-renderable (see `src/ssr-plugins.ts`\n// for the full rationale).\nexport { installLiquidProgress } from './ssr-plugins.js';\n\n// Tooltip helpers (any chart type via echarts.tooltip.formatter)\nexport {\n  createAsyncTooltipFormatter,\n  escapeTooltipHtml,\n} from './async-tooltip.js';\n\nexport {\n  pieParamsToTooltipContext,\n  sankeyChordParamsToTooltipContext,\n  formatPieTooltipSyncHtml,\n} from './tooltip-context.js';\n\nexport {\n  formatAxisTooltipSyncHtml,\n  buildAxisTooltipContext,\n  getTitleReserve,\n  getLegendReserve,\n  compileRichText,\n  getLabelFontSize,\n  DEFAULT_LABEL_FONT_SIZE,\n  LEGEND_RESERVE,\n  computeStackedTextOffsets,\n  STACKED_TEXT_DEFAULT_VISIBLE_GAP_PX,\n  STACKED_TEXT_DEFAULT_GLYPH_PADDING_EM,\n  type EdgeReserves,\n  type CompiledRichText,\n  type StackedTextOffsetsOptions,\n  type StackedTextOffsets,\n} from './adapters/common/index.js';\n\n// Adapter registry (extensibility)\nexport {\n  registerAdapter,\n  getAdapter,\n  hasAdapter,\n  listAdapters,\n  unregisterAdapter,\n  type ChartAdapter,\n  type ChartSetupResult,\n  type ChartTeardown,\n} from './adapters/index.js';\n\n// Types\nexport {\n  ChartType,\n  type ChartData,\n  type ChartOptions,\n  type AnyChartOptions,\n  type IChartInstance,\n  type ChartTypeRegistry,\n  type RegisteredChartType,\n  type ChartDataFor,\n  type ChartOptionsFor,\n  // Data shapes (per-chart aliases; `LineData`/`BarData`/`AreaData` all alias XYData)\n  type XYData,\n  type XYDataSeries,\n  type LineData,\n  type BarData,\n  type AreaData,\n  type MapDataItem,\n  type MapData,\n  type PieData,\n  type PieDataItem,\n  type GaugeData,\n  type LiquidProgressData,\n  type SankeyData,\n  type SankeyNode,\n  type SankeyLink,\n  type ChordData,\n  type ChordNode,\n  type ChordLink,\n  type RadarData,\n  type RadarIndicator,\n  type RadarDataSeries,\n  type NetworkData,\n  type NetworkNode,\n  type NetworkLink,\n  type TreeData,\n  type TreeNode,\n  type TreeDirection,\n  type TreeLabelFormatterContext,\n  type TreeNodeIconSpec,\n  type TreemapData,\n  type TreemapDataItem,\n  type WordCloudData,\n  type WordCloudDataItem,\n  // Per-chart options (each extends ChartOptions / XYChartOptions)\n  type XYChartOptions,\n  type LineChartOptions,\n  type BarChartOptions,\n  type AreaChartOptions,\n  type MapVisualMapOptions,\n  type MapChartOptions,\n  type PieChartOptions,\n  type GaugeChartOptions,\n  type LiquidProgressChartOptions,\n  type SankeyChartOptions,\n  type ChordChartOptions,\n  type RadarChartOptions,\n  type NetworkChartOptions,\n  type TreeChartOptions,\n  type TreemapChartOptions,\n  type WordCloudChartOptions,\n  // Shared option building blocks\n  type SeriesOptions,\n  type LegendOptions,\n  type RichTextInput,\n  type RichTextSpec,\n  type RichTextSegment,\n  type RichTextStyle,\n  type GridOptions,\n  type AxisOptions,\n  type TooltipOptions,\n  type TooltipContext,\n  type TooltipContextAxis,\n  type TooltipContextItem,\n  type TooltipContextEdge,\n  type ChartEventContext,\n  type ChartEventType,\n  type ChartEventHandler,\n  type ChartEventHandlers,\n  type CreateAsyncTooltipFormatterOptions,\n  type BarRaceOptions,\n  type LineRaceOptions,\n  type ChartVariant,\n  type LineVariant,\n  type BarVariant,\n  type AreaVariant,\n  type PieVariant,\n  type GaugeVariant,\n  type LiquidProgressVariant,\n  type SankeyVariant,\n  type RadarVariant,\n  type NetworkVariant,\n  type WordCloudVariant,\n  isSankeyData,\n  isChordData,\n  isRadarData,\n  isNetworkData,\n  isTreeData,\n  isTreemapData,\n  isWordCloudData,\n  isLiquidProgressData,\n  isMapData,\n  mergeLiquidProgressData,\n} from './types.js';\n\n// Configuration\nexport { configure, resetConfiguration, type IChartsConfig } from './config.js';\n\n// Number + color helpers.\n// Adapters call these directly to obtain colors; the result is then attached\n// to whichever ECharts option field makes sense for the chart type.\nexport {\n  formatNumber,\n  type FormatNumberOptions,\n  resolveColors,\n  resolveColorsForNodes,\n} from './utils.js';\n\n// Theme utilities\nexport {\n  switchTheme,\n  registerTheme,\n  getSeriesColor,\n  getCurrentTheme,\n  getThemeColors,\n  setColorMap,\n  resetColorMap,\n  type ChartThemeConfig,\n} from './themes/index.js';\n","import * as echarts from 'echarts';\nimport type { ChartData, AnyChartOptions, IChartInstance } from './types.js';\nimport {\n  resolveEChartsOption,\n  getAdapter,\n  type RenderContext,\n} from './adapters/index.js';\nimport { getConfig } from './config.js';\nimport { buildChartEventContext } from './tooltip-context.js';\nimport type { ChartEventType, ChartEventHandler } from './types.js';\nimport { applyConfiguredFontFamilyToOption } from './adapters/common/font-family.js';\nimport {\n  ensureThemesRegistered,\n  resolveThemeName,\n  beginColorRender,\n  endColorRender,\n  releaseColorOwner,\n} from './themes/index.js';\nimport { chartRegistry } from './registry.js';\nimport { installSentinel, type SentinelHandle } from './disconnect-sentinel.js';\n\n// NOTE: `@echarts-x/custom-word-cloud` + `@echarts-x/custom-liquid-fill`\n// are NOT imported here. Both packages touch `window` / `document` at\n// module-load time, which would break the SSR-safe\n// `@bndynet/icharts/core` subpath. Their `echarts.use(...)`\n// registration is performed by `./installers/index.ts`, which is\n// imported as a side-effect *only* from the browser-first main entry\n// (`src/index.ts`). `echarts.use(...)` is idempotent, so this engine\n// happily renders wordcloud / liquid-progress charts whenever the\n// installers have been registered ahead of time on the active\n// `echarts` global.\n\n/**\n * Core chart engine that manages an ECharts instance and provides the\n * full {@link IChartInstance} contract.  Used by both the `<i-chart>`\n * web component and the imperative `createChart` helper.\n */\nexport class IChart implements IChartInstance {\n  private ecInstance: echarts.ECharts;\n  private _type: string;\n  private _data: ChartData;\n  private _options: AnyChartOptions;\n  private _activeTheme: string;\n  /**\n   * Wall-clock time (ms since page-load) of the previous `update()` call.\n   * Used to compute `RenderContext.observedFrameMs` so race / streaming\n   * adapters can auto-size their animation duration to the consumer's\n   * actual tick cadence — no need for the caller to mirror their\n   * `setInterval` value as `race.frameDuration`.\n   *\n   * `null` until the first `update()`. Reset never; the timer reflects the\n   * actual rendering pipeline regardless of theme switches or option merges.\n   */\n  private _lastUpdateAt: number | null = null;\n  /**\n   * Largest `grid.right` (px) any frame's resolved option has emitted on\n   * this chart. Fed to the adapter via `RenderContext.maxRaceGridRight` so\n   * race adapters can keep the value/end-label headroom monotonic across\n   * frames (see `resolveRaceLabelHeadroom`). Without this, every tick that\n   * grew or shrank a digit would relayout the plot area and jitter the\n   * line/bar positions.\n   *\n   * Tracked for every chart type (not just race) because the field lives\n   * on the resolved option, not on the adapter contract — non-race\n   * adapters simply emit the same value each frame, so the high-water\n   * mark equals the current value, and nothing changes.\n   */\n  private _maxGridRight = 0;\n  /**\n   * `true` when the chart container's root is a `ShadowRoot` (i.e. the\n   * `<i-chart>` web component path; plain `createChart(divEl, ...)`\n   * leaves this `false`).\n   *\n   * Sampled once at construction time because:\n   *   - `getRootNode()` is the only cheap way to ask this question\n   *     (\"am I in shadow DOM?\") and the answer doesn't change for a\n   *     given mounted instance — moving the host element between\n   *     shadow / light DOM after `echarts.init` isn't a supported\n   *     scenario (ECharts would need a re-init anyway).\n   *   - Doing it once avoids paying the cost every `update()` /\n   *     `setTheme()` call when the value can never change.\n   *\n   * Threaded through every `_apply()` call via {@link RenderContext}.\n   * Adapters consume it from `buildTooltip` / `buildSparkTooltip` (and\n   * the inline tooltip blocks in pie / sankey / chord / radar) to\n   * default `tooltip.appendToBody`: `true` in light DOM so the tooltip\n   * escapes `overflow: hidden` ancestors like cards / dialogs, `false`\n   * inside shadow DOM so the tooltip stays inside the web component\n   * for style encapsulation. Users can still override via\n   * `options.tooltip.appendToBody`.\n   *\n   * Conservative on non-DOM platforms (SSR / tests without\n   * `ShadowRoot`): when the `ShadowRoot` global is undefined we treat\n   * the container as light DOM, which matches the dominant CSR path\n   * and keeps tooltips functional.\n   */\n  private _inShadowDom: boolean;\n  /**\n   * Set to `true` by the first successful {@link dispose} call. Guards\n   * the dispose body against double-execution — necessary because the\n   * `<i-chart>` web component's `disconnectedCallback` and our own\n   * sentinel-driven auto-dispose can both race to tear down the same\n   * instance when an `<i-chart>` element is removed from the document.\n   * ECharts' own dispose is idempotent internally but emits a console\n   * warning on the second call; skipping the redundant work is cleaner.\n   */\n  private _disposed = false;\n  /**\n   * Sentinel handle returned by {@link installSentinel}; held so\n   * {@link dispose} can detach the sentinel without triggering its own\n   * disconnect callback (which would re-enter dispose). `null` in\n   * environments without `customElements` / `document` — those rely on\n   * the registry's `pruneDetachedCharts` walk during the next theme or\n   * `consistentColors` change.\n   */\n  private _sentinel: SentinelHandle | null = null;\n  /**\n   * Reference to the async-tooltip `dismiss` callback currently bound to\n   * the ECharts `hideTip` event. Re-bound on every `_apply()` because the\n   * adapter pipeline creates a fresh formatter closure (and a fresh\n   * `dismiss`) each resolve — we have to `off()` the previous reference\n   * before `on()`-ing the new one to avoid stacking listeners.\n   *\n   * When set, ECharts fires this on every tooltip dismissal so the\n   * formatter's HTML cache lives exactly for the duration of one\n   * tooltip session — a new hover after dismissal re-fetches fresh\n   * data, while rapid cursor motion within a session still dedupes\n   * down to a single `customHtml` call.\n   *\n   * `null` when the resolved option has no async-tooltip formatter\n   * (e.g. spark charts, gauge, or chart types whose adapter doesn't\n   * call `createAsyncTooltipFormatter`).\n   */\n  private _asyncTooltipDismiss: (() => void) | null = null;\n  /**\n   * Teardown callback returned by the adapter's most recent `onInit`\n   * (see {@link ChartTeardown}). The engine owns its lifecycle so adapters\n   * that wire `ResizeObserver` / listeners / timers in `onInit` get a\n   * deterministic cleanup point: we run it before the next `_apply()`'s\n   * `onInit` and once more on `dispose()`. `null` when the last `onInit`\n   * returned nothing (or no adapter wires one).\n   */\n  private _applyCleanup: (() => void) | null = null;\n  /**\n   * ECharts event wrappers currently bound for `options.events` handlers.\n   * Re-derived on every `_apply()` (handlers can change via `update`), so we\n   * detach the previous wrappers before attaching new ones to avoid stacking\n   * listeners. Each entry pairs the ECharts event name with the wrapper we\n   * registered so we can `off()` exactly what we `on()`-ed.\n   */\n  private _boundEvents: Array<{\n    event: ChartEventType;\n    handler: (params: unknown) => void;\n  }> = [];\n\n  constructor(\n    container: HTMLElement,\n    type: string,\n    data: ChartData,\n    options: AnyChartOptions = {},\n  ) {\n    ensureThemesRegistered();\n    this._type = type;\n    this._data = data;\n    this._options = options;\n    this._activeTheme = resolveThemeName(options.theme);\n    this._inShadowDom =\n      typeof ShadowRoot !== 'undefined' &&\n      container.getRootNode() instanceof ShadowRoot;\n    this.ecInstance = echarts.init(container, this._activeTheme);\n    chartRegistry.add(this);\n    this._apply();\n    // Auto-dispose on container detach. Installed AFTER `_apply()` so a\n    // throwing adapter doesn't leave behind a sentinel whose disposer\n    // would race a half-initialized chart through `dispose()`. See\n    // disconnect-sentinel.ts for the full rationale (Vue Teleport\n    // self-healing, HMR, `<i-chart>` double-dispose ordering).\n    this._sentinel = installSentinel(container, () => this.dispose());\n  }\n\n  update(newData?: ChartData, newOptions?: AnyChartOptions): void {\n    if (newData !== undefined) {\n      // Live-updating adapters (gauge, liquid-progress, or any custom type)\n      // opt into cross-frame data merging via `adapter.mergeData`. Only fold\n      // when both the prior and incoming data pass the adapter's own guard,\n      // so a partial `{ value }` patch carries `max` / `label` forward;\n      // everything else replaces wholesale (the default).\n      const adapter = getAdapter(this._type);\n      this._data =\n        adapter?.mergeData &&\n        adapter.validate(this._data) &&\n        adapter.validate(newData)\n          ? adapter.mergeData(this._data, newData)\n          : newData;\n    }\n    if (newOptions) this._options = { ...this._options, ...newOptions };\n\n    // Sample the inter-update interval BEFORE re-rendering so adapters can\n    // use it as a default for their per-frame animation duration. The first\n    // call has nothing to measure against — adapters fall back to their\n    // own defaults in that case.\n    const now = performance.now();\n    const observedFrameMs =\n      this._lastUpdateAt !== null ? now - this._lastUpdateAt : undefined;\n    this._lastUpdateAt = now;\n\n    this._apply({\n      observedFrameMs,\n      maxRaceGridRight: this._maxGridRight || undefined,\n    });\n  }\n\n  setTheme(theme: string): void {\n    this._options = { ...this._options, theme };\n    const name = resolveThemeName(theme);\n    if (this._activeTheme !== name) {\n      this._activeTheme = name;\n      // Some custom-series renderers (e.g. wordcloud) leave stale display\n      // elements in place during ECharts' diff/merge on a theme switch,\n      // which shows up as duplicated/overlapped marks. Adapters opt into a\n      // pre-repaint clear via `clearOnThemeChange`; the engine no longer\n      // hardcodes per-type behavior here.\n      if (getAdapter(this._type)?.clearOnThemeChange) {\n        this.ecInstance.clear?.();\n      }\n      this.ecInstance.setTheme(name);\n    }\n    // Theme switches don't represent a frame tick — don't poison the\n    // observed interval with the (potentially long) time since the last\n    // user-driven update.\n    this._apply();\n  }\n\n  resize(): void {\n    this.ecInstance.resize();\n    // Re-invoke the adapter so container-aware sizing (e.g. gauge\n    // `percentage` ring thickness / inner font size, both computed from\n    // `min(containerWidth, containerHeight)` in `RenderContext`) re-flows\n    // against the new viewport. Other adapters' resolved options don't\n    // depend on container dims, so this is a deterministic no-op for\n    // them. Race-frame timing (`_lastUpdateAt`) is intentionally\n    // untouched — only `update()` advances it — so a flurry of resize\n    // events can't poison `observedFrameMs`.\n    this._apply();\n  }\n\n  dispose(): void {\n    // Idempotent: see `_disposed` above. Both `<i-chart>`'s Lit\n    // disconnect path and our sentinel can fire dispose for the same\n    // instance during the same teardown — exit early on the second\n    // call rather than asking ECharts to dispose twice.\n    if (this._disposed) return;\n    this._disposed = true;\n    // Detach the sentinel first, *before* anything else can throw —\n    // its `remove()` clears the callback so the synchronous\n    // `disconnectedCallback` it triggers is a no-op. If we did this\n    // last, an `ecInstance.dispose()` throw would leak the sentinel\n    // (still living in `container`, still holding a closure over a\n    // disposed-but-still-registered chart).\n    this._sentinel?.remove();\n    this._sentinel = null;\n    // ECharts' own `dispose()` clears every listener internally, so we\n    // only need to drop our local reference — no `off('hideTip', ...)`\n    // call here (which would throw post-dispose on some ECharts builds).\n    this._asyncTooltipDismiss = null;\n    // ECharts' dispose() clears its own listeners; just drop our references\n    // to the event wrappers so they (and the options closure they hold) can\n    // be collected.\n    this._boundEvents = [];\n    // Run the adapter's final teardown (e.g. disconnect a ResizeObserver)\n    // before ECharts tears down the instance.\n    this._runApplyCleanup();\n    // Release this chart's consistentColors name lease so any auto-assigned\n    // palette slot it was the last holder of is recycled. This is the primary\n    // cleanup path that makes the registry / sentinel sweeps a fallback rather\n    // than load-bearing — see `releaseColorOwner` / `PaletteRegistry`.\n    releaseColorOwner(this);\n    chartRegistry.delete(this);\n    this.ecInstance.dispose();\n  }\n\n  getEChartsInstance(): echarts.ECharts {\n    return this.ecInstance;\n  }\n\n  /** Change the chart type (used by the web component when the `type` property changes). */\n  setType(type: string): void {\n    this._type = type;\n  }\n\n  private _apply(ctx?: RenderContext): void {\n    // `inShadowDom` and container dims are engine-owned: every render\n    // path must see them, even the ones (constructor, `setTheme`,\n    // `resize`) that pass no caller ctx. Merging here keeps each call\n    // site terse and prevents the flags from being silently dropped\n    // when a future code path forgets to forward them.\n    //\n    // Container dims are sampled fresh each render so resize-triggered\n    // re-renders pick up the new viewport. Non-finite / zero readings\n    // (SSR, `display:none` ancestor, jsdom without layout) are\n    // surfaced as `undefined` so adapters can fall back to their\n    // static defaults rather than emit garbage sizes. `getWidth` /\n    // `getHeight` are probed defensively (optional call) so test\n    // doubles that don't bother implementing the full ECharts surface\n    // — see `src/core.test.ts` — keep working; real ECharts instances\n    // always implement them.\n    const w = this.ecInstance.getWidth?.();\n    const h = this.ecInstance.getHeight?.();\n    const fullCtx: RenderContext = {\n      ...ctx,\n      inShadowDom: this._inShadowDom,\n      containerWidth:\n        typeof w === 'number' && Number.isFinite(w) && w > 0 ? w : undefined,\n      containerHeight:\n        typeof h === 'number' && Number.isFinite(h) && h > 0 ? h : undefined,\n    };\n    // Bracket the adapter resolve with a color render session so the names it\n    // resolves (via `resolveColors`, when `consistentColors` is on) become a\n    // refcounted lease owned by this chart. `dispose()` releases the lease and\n    // recycles freed palette slots — see `releaseColorOwner` below and\n    // `PaletteRegistry`. The session wraps only the resolve (where colors are\n    // computed); `try/finally` guarantees the session closes even if an\n    // adapter throws, and keeps `onInit` / `setOption` outside the session so\n    // a re-entrant render (e.g. an `onInit` calling `resize()`) can't nest.\n    const renderThemeName = resolveThemeName(this._options.theme);\n    let resolved: ReturnType<typeof resolveEChartsOption>;\n    beginColorRender(this, renderThemeName);\n    try {\n      resolved = resolveEChartsOption(\n        this._type,\n        this._data,\n        this._options,\n        fullCtx,\n      );\n    } finally {\n      endColorRender(this);\n    }\n    const { option, onInit, notMerge } = resolved;\n    applyConfiguredFontFamilyToOption(option, getConfig().fontFamily);\n    this._observeGridRight(option);\n    this.ecInstance.setOption(option, notMerge ?? true);\n    this._rebindAsyncTooltipDismiss(option);\n    this._rebindEvents();\n    // Tear down the previous render's adapter effect before re-running\n    // `onInit` so each pass starts from a clean slate (no stacked\n    // observers / listeners). The adapter may return a fresh teardown.\n    this._runApplyCleanup();\n    const cleanup = onInit?.(this.ecInstance);\n    this._applyCleanup = typeof cleanup === 'function' ? cleanup : null;\n  }\n\n  /**\n   * Bind `options.events` handlers to the underlying ECharts instance,\n   * normalizing each raw `params` into a {@link ChartEventContext} via\n   * {@link buildChartEventContext}. Mirrors `_rebindAsyncTooltipDismiss`:\n   * re-derived on every `_apply()` (handlers can change via `update`), so we\n   * detach the previous wrappers first and never stack listeners. A throwing\n   * user handler is swallowed so one bad callback can't break ECharts'\n   * internal event dispatch.\n   */\n  private _rebindEvents(): void {\n    const ec = this.ecInstance as unknown as {\n      on?: (event: string, handler: (...args: unknown[]) => void) => void;\n      off?: (event: string, handler: (...args: unknown[]) => void) => void;\n    };\n    if (this._boundEvents.length && typeof ec.off === 'function') {\n      for (const { event, handler } of this._boundEvents) {\n        ec.off(event, handler);\n      }\n    }\n    this._boundEvents = [];\n\n    const events = this._options.events;\n    if (!events || typeof ec.on !== 'function') return;\n\n    const mapping: Array<[ChartEventType, ChartEventHandler | undefined]> = [\n      ['click', events.onClick],\n      ['dblclick', events.onDoubleClick],\n      ['mouseover', events.onMouseOver],\n      ['mouseout', events.onMouseOut],\n    ];\n\n    for (const [event, fn] of mapping) {\n      if (typeof fn !== 'function') continue;\n      const wrapper = (params: unknown): void => {\n        try {\n          fn(buildChartEventContext(event, params));\n        } catch {\n          // A user event handler must never break ECharts' event dispatch.\n        }\n      };\n      ec.on(event, wrapper);\n      this._boundEvents.push({ event, handler: wrapper });\n    }\n  }\n\n  /** Run and clear the pending adapter teardown, swallowing its errors. */\n  private _runApplyCleanup(): void {\n    if (!this._applyCleanup) return;\n    const cleanup = this._applyCleanup;\n    this._applyCleanup = null;\n    try {\n      cleanup();\n    } catch {\n      // A misbehaving adapter teardown must never break the render /\n      // dispose path. Swallow — the engine has already dropped its\n      // reference, so a throwing cleanup can't wedge subsequent passes.\n    }\n  }\n\n  /**\n   * Wire `formatter.dismiss` (from {@link createAsyncTooltipFormatter}) to\n   * ECharts' `hideTip` event so the formatter's per-slice HTML cache is\n   * cleared whenever the tooltip closes. The cache then only deduplicates\n   * `customHtml` calls *within* a single tooltip session — next hover\n   * re-fetches fresh data.\n   *\n   * Idempotent across repeated `_apply()` calls: we detach the previous\n   * formatter's listener before attaching the new one, so re-renders\n   * (`update()`, `setTheme()`, `resize()`) never stack listeners.\n   */\n  private _rebindAsyncTooltipDismiss(option: unknown): void {\n    const next = extractAsyncTooltipDismiss(option);\n    if (next === this._asyncTooltipDismiss) return;\n    const ec = this.ecInstance as unknown as {\n      off?: (event: string, handler: (...args: unknown[]) => void) => void;\n      on?: (event: string, handler: (...args: unknown[]) => void) => void;\n    };\n    if (this._asyncTooltipDismiss && typeof ec.off === 'function') {\n      ec.off('hideTip', this._asyncTooltipDismiss);\n    }\n    this._asyncTooltipDismiss = next;\n    if (next && typeof ec.on === 'function') {\n      ec.on('hideTip', next);\n    }\n  }\n\n  /**\n   * Lift the high-water mark for `grid.right` from the resolved option so\n   * the next `update()` can feed it back via {@link RenderContext}. Race\n   * adapters use this to keep label headroom monotonic — see\n   * `resolveRaceLabelHeadroom`. Tolerant of options without a grid (e.g.\n   * pie, gauge) and of `grid` being either an object or an array.\n   */\n  private _observeGridRight(option: unknown): void {\n    const grid = (option as { grid?: unknown }).grid;\n    const first = Array.isArray(grid) ? grid[0] : grid;\n    const right = (first as { right?: unknown } | undefined)?.right;\n    if (typeof right === 'number' && right > this._maxGridRight) {\n      this._maxGridRight = right;\n    }\n  }\n}\n\n/**\n * Walk a resolved ECharts option for a `tooltip.formatter` produced by\n * {@link createAsyncTooltipFormatter} (identified by the `dismiss`\n * function property attached to the formatter callable). Tolerant of:\n *\n *   - `tooltip` being either an object (typical) or an array (when the\n *     user passes multiple tooltip configurations through\n *     `echarts.tooltip`),\n *   - `formatter` being a plain string, undefined, or a function without\n *     a `dismiss` property (e.g. a user-supplied formatter that bypasses\n *     the async pipeline).\n *\n * Returns the first matching `dismiss` callback, or `null` when nothing\n * async-tooltip-shaped is present.\n */\nfunction extractAsyncTooltipDismiss(option: unknown): (() => void) | null {\n  const tooltip = (option as { tooltip?: unknown }).tooltip;\n  if (!tooltip) return null;\n  const candidates = Array.isArray(tooltip) ? tooltip : [tooltip];\n  for (const t of candidates) {\n    const fmt = (t as { formatter?: unknown } | undefined)?.formatter;\n    if (typeof fmt !== 'function') continue;\n    const maybeDismiss = (fmt as { dismiss?: unknown }).dismiss;\n    if (typeof maybeDismiss === 'function') {\n      return maybeDismiss as () => void;\n    }\n  }\n  return null;\n}\n","import type {\n  TitleOptions,\n  TooltipOptions,\n  ChartEventHandlers,\n} from './shared.js';\n\n// ---------------------------------------------------------------------------\n// Chart type enum\n// ---------------------------------------------------------------------------\n\nexport enum ChartType {\n  Line = 'line',\n  Bar = 'bar',\n  Area = 'area',\n  Map = 'map',\n  Pie = 'pie',\n  Gauge = 'gauge',\n  LiquidProgress = 'liquidprogress',\n  Sankey = 'sankey',\n  Chord = 'chord',\n  Radar = 'radar',\n  Network = 'network',\n  Tree = 'tree',\n  Treemap = 'treemap',\n  WordCloud = 'wordcloud',\n}\n\n// ---------------------------------------------------------------------------\n// ChartOptions — base for every per-chart subtype\n// ---------------------------------------------------------------------------\n\n/**\n * Cross-cutting options shared by every chart type.\n *\n * Only fields actually consulted by every built-in adapter live here. Anything\n * chart-specific (axes, stacking, variants, slice/gauge/race namespaces,\n * legend/grid for charts that don't render them) belongs on the per-chart\n * `XxxChartOptions` subtype.\n *\n * See [AGENTS.md](../../AGENTS.md) for the rule and rationale.\n */\nexport interface ChartOptions {\n  theme?: string;\n  /** Chart title. Pass a plain string as shorthand or a TitleOptions object for full control. */\n  title?: string | TitleOptions;\n  /**\n   * Outer whitespace (px) between chart content and all canvas edges.\n   * Applies to title, legend, and the plot area. Default: 12.\n   */\n  padding?: number;\n  colors?: string[];\n  colorMap?: Record<string, string>;\n\n  /**\n   * Global font size (px) for data labels and edge labels across every\n   * chart type that renders them.\n   *\n   * **Applies to:**\n   * - line / bar / area `series.label` (when `showLabel: true`) and\n   *   line-race `endLabel`\n   * - pie slice labels\n   * - sankey / chord / tree node labels (parent + leaf for tree)\n   * - network node `series.label` and `series.edgeLabel`\n   *\n   * **Does NOT apply to:**\n   * - gauge `title` / `detail` inner text (container-auto-sized by the\n   *   gauge `percentage` variant)\n   * - radar `axisName` (indicator labels, not data labels)\n   * - `markPoint.label`\n   *\n   * Default: 12.\n   */\n  labelFontSize?: number;\n\n  tooltip?: TooltipOptions;\n\n  /**\n   * Typed mouse-interaction handlers (`onClick` / `onDoubleClick` /\n   * `onMouseOver` / `onMouseOut`). Each receives a normalized\n   * {@link ChartEventHandlers} `ChartEventContext` — the same item/edge shape\n   * the tooltip hooks get — instead of raw ECharts `params`. The engine binds\n   * them on the live instance and keeps them in sync across `update()`.\n   */\n  events?: ChartEventHandlers;\n\n  /** Raw ECharts options merged last — escape hatch for advanced users */\n  echarts?: Record<string, unknown>;\n}\n","import type { ChartOptions } from './base.js';\nimport type {\n  AxisOptions,\n  GridOptions,\n  LegendOptions,\n  SeriesOptions,\n} from './shared.js';\n// Type-only import — runtime is erased, no circular dependency at load time.\nimport type { ChartData } from './instance.js';\n\n// ---------------------------------------------------------------------------\n// XY data shape\n// ---------------------------------------------------------------------------\n\nexport interface XYDataSeries {\n  name: string;\n  data: number[];\n}\n\nexport interface XYData {\n  categories: (string | number)[];\n  series: XYDataSeries[];\n}\n\n/** Structural type guard for {@link XYData}. */\nexport function isXYData(data: ChartData): data is XYData {\n  return (\n    data !== null &&\n    typeof data === 'object' &&\n    'categories' in data &&\n    'series' in data &&\n    Array.isArray((data as XYData).series)\n  );\n}\n\n// ---------------------------------------------------------------------------\n// XYChartOptions — shared base for line / bar / area\n// ---------------------------------------------------------------------------\n\n/**\n * Shared options for XY-family charts (line, bar, area).\n *\n * Holds the fields every XY chart actually uses (axes, stacking, per-series\n * overrides, grid, legend) so the concrete per-chart subtypes only add their\n * own variant union and any chart-specific knobs.\n *\n * `grid` and `legend` live here — not on the base — because only XY charts\n * (and pie, separately) consult them. Gauge / sankey / chord ignore both.\n */\nexport interface XYChartOptions extends ChartOptions {\n  stacked?: boolean;\n  xAxis?: AxisOptions;\n  yAxis?: AxisOptions;\n  /** Per-series overrides keyed by series name (or `'*'` for all). */\n  series?: Record<string, SeriesOptions>;\n\n  legend?: LegendOptions;\n  grid?: GridOptions;\n}\n","import type { ChartOptions } from './base.js';\nimport type { ChartData } from './instance.js';\n\nexport interface MapDataItem {\n  /** Region name, matched against the registered map feature name. */\n  name: string;\n  /** Scalar value used by visualMap and tooltip display. */\n  value: number;\n  /**\n   * Per-region fixed color override.\n   * When provided, wins over palette / colorMap resolution.\n   */\n  color?: string;\n}\n\n/**\n * Map data set — one value per named region.\n */\nexport type MapData = MapDataItem[];\n\n/**\n * Structural type guard for map data.\n */\nexport function isMapData(data: ChartData): data is MapData {\n  return (\n    Array.isArray(data) &&\n    data.length > 0 &&\n    'name' in data[0] &&\n    'value' in data[0]\n  );\n}\n\nexport interface MapVisualMapOptions {\n  /** Show visualMap component. */\n  show?: boolean;\n  /** Explicit minimum for the visual domain. Default: data minimum. */\n  min?: number;\n  /** Explicit maximum for the visual domain. Default: data maximum. */\n  max?: number;\n  /** visualMap orientation. Default: `'vertical'`. */\n  orient?: 'horizontal' | 'vertical';\n  /** visualMap x-position. Default: `left: 'right'`. */\n  left?: string | number;\n  /** visualMap y-position. Default: `bottom: 12`. */\n  top?: string | number;\n  /** visualMap y-position (alternative to `top`). */\n  bottom?: string | number;\n  /** Number formatter for visualMap labels. */\n  formatter?: string | ((value: number) => string);\n  /** Piecewise visualMap bins. Default is continuous mode. */\n  pieces?: Array<{\n    min?: number;\n    max?: number;\n    label?: string;\n    color?: string;\n  }>;\n  /** Precision used by continuous visualMap labels. */\n  precision?: number;\n  /**\n   * Text labels shown at the two ends of the color bar (max end, min end).\n   * Default: auto-formatted min/max values are shown.\n   * Set to `[null, null]` or supply an explicit pair to override.\n   */\n  text?: [string | null, string | null];\n  /**\n   * Explicit color ramp for continuous visualMap.\n   *\n   * Default (when omitted):\n   * - two-stop ramp based on the library's normal map color resolution\n   *   (`resolveColors`):\n   *   - low stop: base color blended over theme `surface` at 20%\n   *   - high stop: base color (100%)\n   */\n  inRangeColors?: string[];\n}\n\nexport interface MapChartOptions extends ChartOptions {\n  /**\n   * Registered map resource name (must be pre-registered via `registerMap`).\n   */\n  mapName: string;\n  /**\n   * Name field in GeoJSON feature properties. Default: `'name'`.\n   */\n  nameProperty?: string;\n  /** Show region labels. Default: `false`. */\n  showLabel?: boolean;\n  /**\n   * Automatically hide region labels that cannot fit inside their region box.\n   *\n   * When enabled, the adapter wires a `labelLayout` callback that compares\n   * ECharts' computed region rect and label rect, then hides labels whose\n   * width/height exceed the region bounds. It also hides labels for regions\n   * without a usable numeric value (`NaN` / missing).\n   *\n   * Default: `false`.\n   */\n  autoHideOverflowLabel?: boolean;\n  /**\n   * Map interaction mode.\n   * - `false` (default): static map\n   * - `true`: pan + zoom\n   * - `'move'`: pan only\n   * - `'scale'`: zoom only\n   */\n  roam?: boolean | 'move' | 'scale';\n  /**\n   * Center point `[lng, lat]`.\n   * Requires map data with a geographic coordinate system.\n   */\n  center?: [number, number];\n  /**\n   * Initial zoom level. Default follows ECharts map series default.\n   */\n  zoom?: number;\n  /**\n   * visualMap config for choropleth coloring.\n   * When omitted, the adapter auto-enables visualMap if map data has numeric values.\n   * Set `visualMap: { show: false }` for a plain single-color map.\n   */\n  visualMap?: MapVisualMapOptions;\n}\n","import type { ChartOptions } from './base.js';\nimport type { LegendOptions, RichTextSpec } from './shared.js';\nimport type { ChartData } from './instance.js';\n\nexport type PieVariant = 'default' | 'doughnut' | 'half-doughnut' | 'nightingale';\n\nexport interface PieDataItem {\n  name: string;\n  value: number;\n}\n\nexport type PieData = PieDataItem[];\n\nexport type PieCenterLabel = string | RichTextSpec;\n\nexport function isPieData(data: ChartData): data is PieData {\n  return (\n    Array.isArray(data) &&\n    data.length > 0 &&\n    'name' in data[0] &&\n    'value' in data[0]\n  );\n}\n\nexport interface PieChartOptions extends ChartOptions {\n  variant?: PieVariant;\n  innerRadius?: string | number;\n  outerRadius?: string | number;\n  /** When false, slices keep their data order; otherwise sorted by value desc. Default: true. */\n  autoSort?: boolean;\n\n  /**\n   * Whether to render the outside slice labels (`{name}: {percent}%`\n   * leader-line text). Defaults to `!showLegend` — when the legend is\n   * shown it already names every slice and the outside labels would\n   * duplicate it (and steal radius headroom). Set to `true` to force\n   * them alongside a legend, or to `false` to hide them even when the\n   * legend is hidden.\n   */\n  showSliceLabel?: boolean;\n\n  // ---------------------------------------------------------------------------\n  // Slice styling — pie chart's own options, flat on the subtype. Field names\n  // are prefixed with `slice` so generic names like `borderRadius` / `gap` are\n  // unambiguous at the top level.\n  // ---------------------------------------------------------------------------\n\n  /** Border radius of every slice in px. Maps to ECharts `series.itemStyle.borderRadius`. */\n  sliceBorderRadius?: number;\n  /** Border color of every slice. Maps to ECharts `series.itemStyle.borderColor`. */\n  sliceBorderColor?: string;\n  /** Gap between adjacent slices in degrees. Maps to ECharts `series.padAngle`. */\n  sliceGap?: number;\n\n  /**\n   * Pie is the only non-XY chart that renders a legend, so the field lives\n   * here rather than on the base {@link ChartOptions}. Gauge / sankey / chord\n   * deliberately do not expose `legend`.\n   */\n  legend?: LegendOptions;\n\n  /** Center labels for doughnut / pie variants (multi-line). */\n  centerLabels?: PieCenterLabel[];\n  /**\n   * Pixel offset applied to center labels after layout: [x, y].\n   * Useful for fine-grained visual calibration.\n   */\n  centerLabelOffset?: [number, number];\n}\n","import type { ChartOptions } from './base.js';\nimport type { ChartData } from './instance.js';\n\nexport type GaugeVariant = 'default' | 'percentage';\n\nexport interface GaugeData {\n  value: number;\n  max?: number;\n  label?: string;\n}\n\nexport function isGaugeData(data: ChartData): data is GaugeData {\n  return (\n    data !== null &&\n    typeof data === 'object' &&\n    !Array.isArray(data) &&\n    'value' in data &&\n    !('categories' in data) &&\n    !('nodes' in data)\n  );\n}\n\n/**\n * Merge a partial gauge update into the previous frame.\n *\n * - `value` is always taken from `patch`.\n * - `max` / `label` are kept from `prev` unless the key is present on\n *   `patch` (including explicit empty values — `label: ''` clears the\n *   caption; `max: undefined` drops a prior custom max so the adapter\n *   falls back to its default).\n */\nexport function mergeGaugeData(prev: GaugeData, patch: GaugeData): GaugeData {\n  const merged: GaugeData = { value: patch.value };\n  if ('max' in patch) {\n    merged.max = patch.max;\n  } else if (prev.max !== undefined) {\n    merged.max = prev.max;\n  }\n  if ('label' in patch) {\n    merged.label = patch.label;\n  } else if (prev.label !== undefined) {\n    merged.label = prev.label;\n  }\n  return merged;\n}\n\nexport interface GaugeChartOptions extends ChartOptions {\n  variant?: GaugeVariant;\n  /** Arc thickness in px. Default: 18 (default variant) / 20 (percentage variant). */\n  gaugeWidth?: number;\n}\n","import type { ChartOptions } from './base.js';\nimport type { ChartData } from './instance.js';\nimport {\n  isGaugeData,\n  mergeGaugeData,\n  type GaugeData,\n} from './gauge.js';\n\nexport type LiquidProgressVariant = 'default';\n\nexport type LiquidProgressData = GaugeData;\n\n/**\n * Liquid progress data shape.\n *\n * Note: this is structurally identical to `GaugeData`.\n * The chart `type` string selects the adapter.\n */\nexport function isLiquidProgressData(data: ChartData): data is LiquidProgressData {\n  return isGaugeData(data);\n}\n\n/**\n * Merge a partial liquid-progress update into the previous frame.\n *\n * - `value` is always taken from `patch`.\n * - `max` / `label` are kept from `prev` unless the key is present on\n *   `patch` (including explicit empty values — `label: ''` clears the\n *   caption; `max: undefined` drops a prior custom max so the adapter\n *   falls back to its default).\n */\nexport function mergeLiquidProgressData(\n  prev: LiquidProgressData,\n  patch: LiquidProgressData,\n): LiquidProgressData {\n  return mergeGaugeData(prev, patch);\n}\n\nexport interface LiquidProgressChartOptions extends ChartOptions {\n  variant?: LiquidProgressVariant;\n  /**\n   * Radius of the liquid container.\n   * Accepts ECharts percent or px number. Default: `'70%'`.\n   */\n  radius?: string | number;\n  /**\n   * Wave count for the liquid fill.\n   * Default: `3`.\n   */\n  waveCount?: number;\n  /**\n   * Border thickness around the liquid container in px.\n   * Default: `2`.\n   */\n  borderWidth?: number;\n}\n","import type { ChartOptions } from './base.js';\nimport type { ChartData } from './instance.js';\n\nexport type SankeyVariant = 'default' | 'vertical';\n\nexport interface SankeyNode {\n  name: string;\n  /** Optional fixed color for this specific node */\n  color?: string;\n}\n\nexport interface SankeyLink {\n  source: string;\n  target: string;\n  value: number;\n}\n\nexport interface SankeyData {\n  nodes: SankeyNode[];\n  links: SankeyLink[];\n}\n\nexport function isSankeyData(data: ChartData): data is SankeyData {\n  return (\n    data !== null &&\n    typeof data === 'object' &&\n    !Array.isArray(data) &&\n    'nodes' in data &&\n    'links' in data &&\n    Array.isArray((data as SankeyData).nodes) &&\n    Array.isArray((data as SankeyData).links)\n  );\n}\n\nexport interface SankeyChartOptions extends ChartOptions {\n  variant?: SankeyVariant;\n}\n","import type { ChartOptions } from './base.js';\nimport type { ChartData } from './instance.js';\n\nexport interface ChordNode {\n  name: string;\n  /** Optional fixed color for this node's arc and outgoing ribbons */\n  color?: string;\n  /**\n   * Relative weight of the node arc.\n   * When omitted the arc size is derived from the sum of connected link values.\n   */\n  value?: number;\n}\n\nexport interface ChordLink {\n  source: string;\n  target: string;\n  value: number;\n}\n\nexport interface ChordData {\n  nodes: ChordNode[];\n  links: ChordLink[];\n}\n\n/**\n * ChordData and SankeyData share the same runtime shape ({ nodes, links }).\n * The chart type — not the data shape — determines which adapter is used.\n * This guard validates the structural contract for ChordData.\n */\nexport function isChordData(data: ChartData): data is ChordData {\n  return (\n    data !== null &&\n    typeof data === 'object' &&\n    !Array.isArray(data) &&\n    'nodes' in data &&\n    'links' in data &&\n    Array.isArray((data as ChordData).nodes) &&\n    Array.isArray((data as ChordData).links)\n  );\n}\n\n/**\n * Chord-chart-specific options.\n *\n * No chord-specific knobs today (chord has no variants and no extra fields\n * beyond {@link ChartOptions}); kept as a named subtype so consumers and\n * adapters can express intent and we have a stable home for future\n * chord-only knobs.\n */\nexport type ChordChartOptions = ChartOptions;\n","import type { ChartOptions } from './base.js';\nimport type { LegendOptions } from './shared.js';\nimport type { ChartData } from './instance.js';\n\nexport type RadarVariant = 'default' | 'circle';\n\n/**\n * One axis of the radar chart. ECharts calls this an \"indicator\".\n *\n * `max` / `min` are optional — when omitted ECharts auto-scales each axis to\n * the data range. Provide them when you want consistent scales across\n * indicators (e.g. when comparing different metrics on the same chart).\n */\nexport interface RadarIndicator {\n  name: string;\n  max?: number;\n  min?: number;\n}\n\n/**\n * One polygon drawn on the radar. `values[i]` is plotted on\n * `indicators[i]` — so the two arrays must line up by index and length.\n */\nexport interface RadarDataSeries {\n  name: string;\n  values: number[];\n}\n\nexport interface RadarData {\n  indicators: RadarIndicator[];\n  series: RadarDataSeries[];\n}\n\nexport function isRadarData(data: ChartData): data is RadarData {\n  if (data === null || typeof data !== 'object' || Array.isArray(data)) {\n    return false;\n  }\n  const d = data as Partial<RadarData>;\n  return (\n    Array.isArray(d.indicators) &&\n    d.indicators.length > 0 &&\n    typeof d.indicators[0]?.name === 'string' &&\n    Array.isArray(d.series) &&\n    d.series.length > 0 &&\n    typeof d.series[0]?.name === 'string' &&\n    Array.isArray(d.series[0]?.values)\n  );\n}\n\nexport interface RadarChartOptions extends ChartOptions {\n  variant?: RadarVariant;\n  /** Fill the polygon area for every series. Default: true. */\n  filled?: boolean;\n  /** Radar radius — same syntax as ECharts `radar.radius`. Default: '65%'. */\n  radius?: string | number;\n  /**\n   * Radar is a non-XY chart that benefits from a legend (one entry per\n   * polygon), so the field lives on this subtype rather than the base\n   * {@link ChartOptions}.\n   */\n  legend?: LegendOptions;\n}\n","import type { ChartOptions } from './base.js';\nimport type { LegendOptions } from './shared.js';\nimport type { ChartData } from './instance.js';\n\n/**\n * Layout strategies for the network chart.\n *\n * - `default`: physics-based force-directed layout. Nodes repel each other\n *   while edges pull them together; the simulator runs until it stabilises.\n *   Good for \"show me the structure\" of an unknown graph. Internally this\n *   maps to ECharts' `graph.layout: 'force'`. When nodes carry `x` / `y`\n *   they are used as initial positions; combine with `fixed: true` to lock\n *   specific nodes in place.\n * - `circular`: nodes are placed evenly around a circle in input order.\n *   Predictable layout for chord-style adjacency without needing per-node\n *   coordinates. Maps to ECharts' `graph.layout: 'circular'`.\n *\n * Need fully manual node positions (no algorithm at all)? Drop down to\n * the `echarts` escape hatch: `options.echarts = { series: [{ layout: 'none' }] }`\n * and provide `x` / `y` on every node.\n */\nexport type NetworkVariant = 'default' | 'circular';\n\nexport interface NetworkNode {\n  name: string;\n  /**\n   * Optional category name. Categories drive the legend and the default\n   * per-node color (every node in the same category gets the same palette\n   * slot). Unknown category names — names not present in `data.categories`\n   * (or, when omitted, not seen elsewhere in `nodes`) — are dropped.\n   */\n  category?: string;\n  /**\n   * Numeric value associated with the node. When `size` is omitted the\n   * adapter scales the rendered marker size from the value range.\n   */\n  value?: number;\n  /**\n   * Per-node fixed color override. Wins over the category palette and any\n   * `colorMap` / `colors` resolution.\n   */\n  color?: string;\n  /**\n   * Per-node marker size override (px). When omitted the adapter derives a\n   * size from `value` (scaled into {@link NetworkChartOptions.nodeSizeRange})\n   * and falls back to {@link NetworkChartOptions.nodeSize} for nodes\n   * without a value.\n   */\n  size?: number;\n  /**\n   * Optional initial layout coordinate (px on the chart canvas). Used as the\n   * starting position by the `default` (force) layout; ignored by `circular`\n   * which derives positions from input order.\n   */\n  x?: number;\n  y?: number;\n  /**\n   * When true, keep the node at `x` / `y` during the force simulation\n   * (i.e. it acts as an anchor while other nodes settle around it).\n   * Ignored by `circular`.\n   */\n  fixed?: boolean;\n}\n\nexport interface NetworkLink {\n  source: string;\n  target: string;\n  /** Optional weight. Surfaced in tooltips; force layout ignores it today. */\n  value?: number;\n  /**\n   * Per-link curveness override. Same scale as chart-wide\n   * {@link NetworkChartOptions.edgeCurveness} (`0` = straight, `0.3` ≈\n   * gently curved). Negative values bend the line the *other* way, which\n   * is the canonical fix for **bidirectional edges**: give `A → B` a\n   * positive curveness and `B → A` an equal negative one so the two\n   * arcs don't overlap.\n   *\n   * Wins over the chart-level default (and over any explicit\n   * `options.edgeCurveness`). Omit to inherit the chart-wide value.\n   */\n  curveness?: number;\n}\n\nexport interface NetworkData {\n  nodes: NetworkNode[];\n  links: NetworkLink[];\n  /**\n   * Explicit category list — drives legend ordering. When omitted, derived\n   * from unique `node.category` values in input order.\n   */\n  categories?: string[];\n}\n\n/**\n * NetworkData shares the `{ nodes, links }` runtime shape with SankeyData and\n * ChordData. The chart `type` string — not the data shape — selects the\n * adapter; this guard validates the structural contract for NetworkData.\n */\nexport function isNetworkData(data: ChartData): data is NetworkData {\n  return (\n    data !== null &&\n    typeof data === 'object' &&\n    !Array.isArray(data) &&\n    'nodes' in data &&\n    'links' in data &&\n    Array.isArray((data as NetworkData).nodes) &&\n    Array.isArray((data as NetworkData).links)\n  );\n}\n\nexport interface NetworkChartOptions extends ChartOptions {\n  variant?: NetworkVariant;\n  /** Enable wheel zoom. Default: `false`. */\n  enableZoom?: boolean;\n  /** Enable drag-to-pan. Default: `true`. */\n  enablePan?: boolean;\n  /** Allow dragging individual nodes. Default: true for `default` (force), false for `circular`. */\n  draggable?: boolean;\n  /** Show node name labels. Default: true. */\n  showNodeLabel?: boolean;\n  /** Show edge labels (rendered from `link.value`). Default: false. */\n  showLinkLabel?: boolean;\n  /**\n   * Force every node + edge label to render, bypassing **all** of the\n   * adapter's label-pruning strategies in one shot:\n   *   1. `labelLayout: { hideOverlap: true }` (the default overlap\n   *      culling that keeps dense force layouts readable).\n   *   2. The {@link labelMinNodeSize} size threshold that hides labels\n   *      on small markers.\n   *\n   * Default `false` keeps both strategies active — labels at the edges\n   * of a cluster show, the ones inside / on tiny nodes collapse first.\n   * This trades completeness for legibility and is usually the right\n   * answer.\n   *\n   * Set `true` when every node name matters (small graphs, screenshots,\n   * presentations) and you'd rather accept overlap than hide a name.\n   *\n   * Has no effect when {@link showNodeLabel} is `false` (no labels to show).\n   */\n  showAllLabels?: boolean;\n  /**\n   * Resolved marker size (px) strictly below this value hides that\n   * single node's label. Lets you scale nodes by `value` without the\n   * smallest dots drowning under their own captions — a common\n   * complaint on circular layouts where `labelLayout: { hideOverlap }`\n   * does nothing (radial labels rarely physically overlap).\n   *\n   * Default: `14`. Tuned for the default {@link nodeSizeRange} of\n   * `[10, 30]`: nodes whose `value` lands in the bottom ~20 % of the\n   * range scale into the `< 14 px` bucket and lose their label, while\n   * mid- and large-value nodes keep theirs. Set `0` to disable the\n   * threshold entirely (pre-v6.2 behavior). Raise (e.g. `18`) for more\n   * aggressive pruning.\n   *\n   * Compared against the **resolved** per-node size — whichever path\n   * produced it: explicit `node.size`, value-scaled into\n   * {@link nodeSizeRange}, or the container-aware no-value fallback.\n   *\n   * Interaction with the other label flags:\n   *   - {@link showNodeLabel} `false` wins → no labels render; threshold\n   *     becomes meaningless.\n   *   - {@link showAllLabels} `true` wins → threshold is skipped along\n   *     with overlap culling; every label renders.\n   */\n  labelMinNodeSize?: number;\n  /**\n   * Fallback marker size (px) for nodes that have no `value` and no\n   * per-node `size`. When omitted the adapter auto-sizes from the\n   * rendered container — `min(width, height) / sqrt(nodeCount) * 0.10`,\n   * clamped to `[8, 40]` — so sparse graphs in big cards get noticeable\n   * markers and dense graphs shrink markers automatically. SSR / hidden\n   * containers (no usable dims) fall back to 10 px. Pass an explicit\n   * number to disable auto-sizing.\n   */\n  nodeSize?: number;\n  /**\n   * Min / max marker size (px) used when scaling nodes by `value`.\n   * Default: `[10, 30]`.\n   */\n  nodeSizeRange?: [number, number];\n  /** Force-layout repulsion strength. Default: 100. */\n  repulsion?: number;\n  /**\n   * Force-layout edge length (px) — the spring's \"rest length\" between\n   * connected nodes. When omitted the adapter auto-sizes from the\n   * **body** (the area outside the title, legend, and padding reserves):\n   * `min(bodyWidth, bodyHeight) / sqrt(nodeCount) * 0.6`, clamped to\n   * `[30, 250]`. This means the cluster fills the available body\n   * automatically: a tall title or a side legend that shrinks the body\n   * also shrinks the springs, so the layout stays inside the reserved\n   * area instead of bleeding into the title bar. The 0.6 multiplier is\n   * calibrated so a 16-node graph with a body of ~400 px (the canonical\n   * forceData demo body, after subtracting title + 5-cat top legend +\n   * padding) lands exactly on 60 px — the pre-auto-sizing static\n   * default — so existing demos render unchanged. SSR / hidden\n   * containers (no usable dims) fall back to 60 px. Pass an explicit\n   * number to disable auto-sizing. Only consulted when\n   * `variant === 'default'`.\n   */\n  edgeLength?: number;\n  /** Force-layout gravity (pull toward center). Default: 0.1. */\n  gravity?: number;\n  /**\n   * Edge curveness (0 = straight, 0.3 = gently curved).\n   *\n   * Default depends on the variant:\n   *   - `default` (force) → `0` — physics already separates edges nicely.\n   *   - `circular` → `0.3` — straight edges through a circular layout\n   *     converge at the center and become unreadable; matches ECharts'\n   *     own circular-layout example.\n   *\n   * Pass an explicit value to override either default.\n   */\n  edgeCurveness?: number;\n  /**\n   * Network renders a category legend (one entry per category). Lives on\n   * this subtype — base {@link ChartOptions} stays legend-free.\n   */\n  legend?: LegendOptions;\n}\n","import type { ChartOptions } from './base.js';\nimport type { ChartData } from './instance.js';\nimport type { RichTextInput } from './shared.js';\n\n/**\n * Growth direction of the tree.\n *\n * - `'LR'` (default) — root on the left, leaves expand to the right.\n * - `'RL'` — root on the right, leaves expand to the left.\n * - `'TB'` — root on top, leaves expand downward.\n * - `'BT'` — root on bottom, leaves expand upward.\n *\n * The adapter flips the node-label position so labels always point away\n * from the tree body (parents toward the root edge, leaves toward the\n * opposite edge), and for vertical directions (`'TB'` / `'BT'`) rotates\n * labels 90° so the reading direction tracks the tree's growth.\n */\nexport type TreeDirection = 'LR' | 'RL' | 'TB' | 'BT';\n\n/**\n * A single node in the tree. Minimal by design — the only required field\n * is `name`. Internal nodes carry `children`; leaves omit it. `value` is\n * optional metadata surfaced in tooltips (the tree adapter does not size\n * nodes by value).\n */\nexport interface TreeNode {\n  /** Display name; also serves as the color-lookup key. */\n  name: string;\n  /** Optional numeric metadata. Shown in tooltips, not used for sizing. */\n  value?: number;\n  /** Child nodes. Omit (or pass an empty array) for a leaf. */\n  children?: TreeNode[];\n  /**\n   * Per-node fixed color override. Wins over `colorMap` / `colors` /\n   * theme palette resolution. Applied via `itemStyle.color` during the\n   * tree walk so the override survives any `options.echarts` deep-merge.\n   */\n  color?: string;\n  /**\n   * When `true`, the sub-tree below this node renders collapsed; the user\n   * can click to expand. Default: `false` (expanded). Combine with\n   * `options.initialTreeDepth` for depth-based collapsing across the\n   * whole tree.\n   */\n  collapsed?: boolean;\n}\n\n/**\n * The tree's root node. Tree data is just a single {@link TreeNode}.\n *\n * Example:\n * ```ts\n * const data: TreeData = {\n *   name: 'root',\n *   children: [\n *     { name: 'A', children: [{ name: 'A1' }, { name: 'A2' }] },\n *     { name: 'B', value: 42 },\n *   ],\n * };\n * ```\n */\nexport type TreeData = TreeNode;\n\n/**\n * Context passed to {@link TreeChartOptions.formatNodeLabel}.\n */\nexport interface TreeLabelFormatterContext {\n  /** Raw node object from the user-supplied tree data. */\n  node: TreeNode;\n  /** Convenience alias for `node.name`. */\n  name: string;\n  /** Depth from the root (`0` for root). */\n  depth: number;\n  /** `true` when the node has no children. */\n  isLeaf: boolean;\n}\n\n/**\n * Icon payload for {@link TreeChartOptions.formatNodeIcon}.\n */\nexport interface TreeNodeIconSpec {\n  /** Avatar / icon image URL (without `image://` prefix). */\n  image: string;\n  /** Node symbol width in px. */\n  width?: number;\n  /** Node symbol height in px. Defaults to `width`. */\n  height?: number;\n  /** Node symbol shape. Default: `'square'`. */\n  shape?: 'square' | 'circle';\n  /**\n   * Border thickness in px. **Opt-in** — when omitted (or set to `0`),\n   * the icon renders without any border on either shape. Set to a\n   * positive number to:\n   *\n   *   - **`shape: 'circle'`** → stroke a ring along the inside edge\n   *     of the circular clip in the avatar PNG.\n   *   - **`shape: 'square'`** → stroke a rectangular frame inside the\n   *     image's bounding box. Square + border switches the underlying\n   *     ECharts symbol from `image://...` (which can't render\n   *     `itemStyle.border*` natively) to a canvas-baked PNG so the\n   *     frame is part of the bitmap.\n   *\n   * Trade-off note: the canvas pipeline reserves `borderWidth * 2` px\n   * for the stroke before contain-fitting the avatar, so bumping this\n   * past `~width / 7` (e.g. 3 px on a 20 px icon, 5 px on a 36 px\n   * icon) starts visibly shrinking the image inside the frame.\n   * Adjust `width` proportionally if you want a thicker border.\n   */\n  borderWidth?: number;\n  /**\n   * Border color. Honored only when `borderWidth` is set to a\n   * positive value (color without width is silently ignored — there's\n   * no border to paint). Defaults to the node's resolved palette\n   * color (or the per-node `node.color` override when present), so a\n   * single `borderWidth: 2` opt-in produces the classic\n   * \"framed-in-node-color\" look without forcing the user to duplicate\n   * the palette. Specify a CSS color string (e.g. `'#10b981'`) to pin\n   * every node's frame to a brand accent.\n   */\n  borderColor?: string;\n}\n\n/**\n * Structural type guard for tree data.\n *\n * The check is intentionally conservative: a single object with a string\n * `name` field is enough, but we also exclude shapes that belong to\n * other built-in chart types (gauge's `value`-only payload, sankey /\n * chord / network's `{nodes, links}`, XY's `{categories, series}`,\n * radar's `{indicators, series}`) so that mistakenly handing the wrong\n * data to `createChart(el, 'tree', ...)` fails fast instead of silently\n * rendering nothing.\n */\nexport function isTreeData(data: ChartData): data is TreeData {\n  if (data === null || typeof data !== 'object' || Array.isArray(data)) {\n    return false;\n  }\n  // Cast through `unknown` because `ChartData` is a discriminated union of\n  // narrow shapes (none of which is an index-signature record) so the\n  // direct `Record<string, unknown>` cast trips the TS structural check.\n  const obj = data as unknown as Record<string, unknown>;\n  if (typeof obj.name !== 'string') return false;\n  // Reject other graph-shaped payloads that happen to carry a `name`.\n  if ('nodes' in obj || 'links' in obj) return false;\n  if ('categories' in obj || 'series' in obj) return false;\n  if ('indicators' in obj) return false;\n  return true;\n}\n\n/**\n * Tree-chart-specific options.\n *\n * Per the AGENTS.md convention, every chart-specific knob lives flat on\n * the subtype — no wrapping sub-object. Only `direction` is unique to\n * tree; the other fields are mild ECharts pass-throughs (`enableZoom`,\n * `nodeSize`, …) named consistently with sibling adapters.\n */\nexport interface TreeChartOptions extends ChartOptions {\n  /**\n   * Tree growth direction. See {@link TreeDirection}. Default: `'LR'`.\n   */\n  direction?: TreeDirection;\n  /**\n   * Initial expansion depth — the adapter starts with this many levels\n   * visible and collapses everything below. `-1` (the default) expands\n   * the whole tree. Use `2` for a typical \"show root + one level\"\n   * starting state on large trees.\n   */\n  initialTreeDepth?: number;\n  /**\n   * Enable wheel zoom. Default: `false`.\n   */\n  enableZoom?: boolean;\n  /**\n   * Enable drag-to-pan. Default: `true`.\n   */\n  enablePan?: boolean;\n  /** Show node-name labels. Default: `true`. */\n  showNodeLabel?: boolean;\n  /**\n   * Tree edge rendering style. Maps to ECharts `series.edgeShape`.\n   * Default: `'polyline'`. Use `'polyline'` for orthogonal elbow connectors,\n   * `'curve'` for smooth links.\n   */\n  lineStyle?: 'curve' | 'polyline';\n  /**\n   * Diameter (px) of every node marker. Default: `7` — matches the\n   * ECharts `tree-basic` example, which is calibrated so labels and\n   * markers don't collide at the default 12 px font.\n   */\n  nodeSize?: number;\n  /**\n   * Click an internal node to collapse / expand its sub-tree. Default:\n   * `true`. Set `false` to render a fully static tree (useful for\n   * snapshot exports).\n   */\n  expandAndCollapse?: boolean;\n  /**\n   * Disable automatic label rotation for vertical directions (`'TB'` / `'BT'`).\n   *\n   * - `false` (default): uses direction-aware rotation (`-90` for `'TB'`,\n   *   `+90` for `'BT'`).\n   * - `true`: forces both parent and leaf label `rotate` to `0`.\n   */\n  disableLabelRotate?: boolean;\n  /**\n   * Customize node labels.\n   *\n   * Receives the current node context and returns plain text or\n   * `RichTextSpec`. Rich text is compiled to ECharts formatter tokens and\n   * injected into both `series.label.rich` and `series.leaves.label.rich`.\n   * If this callback throws or returns an invalid value, the adapter falls\n   * back to the raw `node.name`.\n   */\n  formatNodeLabel?: (ctx: TreeLabelFormatterContext) => RichTextInput;\n  /**\n   * Customize the icon shown before each node label.\n   *\n   * Return:\n   * - `string` → treated as `image` URL.\n   * - `TreeNodeIconSpec` → full icon style control.\n   * - `null` / `undefined` → no icon for this node.\n   *\n   * When enabled, the adapter replaces that node's marker symbol with an\n   * image symbol (`symbol: 'image://...'`, `symbolSize` from `width/height`).\n   */\n  formatNodeIcon?: (\n    ctx: TreeLabelFormatterContext,\n  ) => string | TreeNodeIconSpec | null | undefined;\n}\n","import type { ChartOptions } from './base.js';\nimport type { ChartData } from './instance.js';\n\n/**\n * A single treemap node. Internal nodes carry `children`; leaves omit it.\n *\n * - `value` is required on leaves (drives rectangle area). Internal nodes\n *   may omit it — ECharts sums the children's values automatically.\n * - `color` is an optional per-node fix; wins over `colorMap` / `colors`\n *   palette resolution.\n */\nexport interface TreemapDataItem {\n  /** Display name; also serves as the color-lookup key. */\n  name: string;\n  /**\n   * Rectangle area. Required on leaves. Omit on internal nodes to let\n   * ECharts sum the descendant values automatically.\n   */\n  value?: number;\n  /** Child nodes. Omit (or pass an empty array) for a leaf. */\n  children?: TreemapDataItem[];\n  /**\n   * Per-node fixed color override. Wins over `colorMap` / `colors` /\n   * theme palette resolution. Applied via `itemStyle.color` so the\n   * override survives any `options.echarts` deep-merge.\n   */\n  color?: string;\n}\n\n/**\n * Treemap data — an array of one or more hierarchical roots.\n *\n * Matches ECharts' native `series.data` shape so the library remains a\n * thin wrapper over the underlying treemap series.\n *\n * Example:\n * ```ts\n * const data: TreemapData = [\n *   {\n *     name: 'flare',\n *     children: [\n *       { name: 'analytics', value: 120, children: [...] },\n *       { name: 'data',      value: 80 },\n *     ],\n *   },\n * ];\n * ```\n */\nexport type TreemapData = TreemapDataItem[];\n\n/**\n * Structural type guard for treemap data.\n *\n * Treemap data shares the `[{ name, value }]` skeleton with `PieData` and\n * `WordCloudData`; the chart `type` string selects the right adapter at\n * runtime, so the guard's job is just to verify the array-of-named-items\n * shape (matching the pie/word-cloud guards).\n */\nexport function isTreemapData(data: ChartData): data is TreemapData {\n  return (\n    Array.isArray(data) &&\n    data.length > 0 &&\n    'name' in data[0]\n  );\n}\n\n/**\n * Treemap-chart-specific options.\n *\n * Deliberately minimal — the field set is the smallest one that maps a\n * pleasant default treemap onto the user's intent while leaving every\n * advanced ECharts knob reachable through `options.echarts` for\n * power users.\n */\nexport interface TreemapChartOptions extends ChartOptions {\n  /**\n   * Show the drill-down breadcrumb (the \"you are here\" trail rendered\n   * at the bottom of the chart when the user zooms into a sub-tree).\n   * Default: `true`.\n   */\n  showBreadcrumb?: boolean;\n  /**\n   * Show node labels (the text drawn inside each rectangle). Default:\n   * `true`. When `false`, the chart renders as a pure heat-grid of\n   * unlabelled rectangles.\n   */\n  showNodeLabel?: boolean;\n  /**\n   * Maximum visible depth at first paint. Deeper nodes start collapsed\n   * and reveal when the user zooms / drills in. `undefined` (the default)\n   * renders every level at once. Useful for very deep hierarchies — pass\n   * `2` to start with \"root + one level\".\n   */\n  leafDepth?: number;\n  /**\n   * Enable click-to-drill-down (and zoom-to-node) navigation. Default:\n   * `true`. Set `false` for a fully static treemap (useful for snapshot\n   * exports or read-only dashboards).\n   */\n  drilldown?: boolean;\n  /**\n   * Enable wheel zoom + drag pan inside the active node. Default: `false`.\n   * Note: drill-down (clicking a node) is governed by `drilldown`, not\n   * this flag.\n   */\n  enableRoam?: boolean;\n}\n","import type { ChartOptions } from './base.js';\nimport type { ChartData } from './instance.js';\n\nexport type WordCloudVariant =\n  | 'default'\n  | 'diamond'\n  | 'poster'\n  | 'compact-diamond';\n\nexport interface WordCloudDataItem {\n  name: string;\n  value: number;\n  /**\n   * Per-word fixed color override.\n   * When provided, wins over palette / colorMap resolution.\n   */\n  color?: string;\n}\n\n/**\n * Word cloud data set.\n *\n * Note: this is structurally similar to `PieData` (`{name, value}[]`).\n * The chart `type` string selects the adapter.\n */\nexport type WordCloudData = WordCloudDataItem[];\n\nexport function isWordCloudData(data: ChartData): data is WordCloudData {\n  return (\n    Array.isArray(data) &&\n    data.length > 0 &&\n    'name' in data[0] &&\n    'value' in data[0]\n  );\n}\n\nexport interface WordCloudChartOptions extends ChartOptions {\n  /**\n   * Built-in layout presets.\n   * - `default`: balanced general-purpose cloud\n   * - `diamond`: denser diamond layout with horizontal labels\n   * - `poster`: high-contrast, bold visual style for hero cards\n   * - `compact-diamond`: deprecated alias of `diamond`\n   */\n  variant?: WordCloudVariant;\n  /** Text size range in px. Default: `[12, 60]`. */\n  sizeRange?: [number, number];\n  /**\n   * Word cloud silhouette. Built-in presets are from the word-cloud extension.\n   * Default: `'circle'`.\n   */\n  shape?:\n    | 'circle'\n    | 'cardioid'\n    | 'diamond'\n    | 'triangle-forward'\n    | 'triangle'\n    | 'pentagon'\n    | 'star';\n  /** Rotation range in degrees. Default: `[-90, 90]`. */\n  rotationRange?: [number, number];\n  /** Rotation step in degrees. Default: `45`. */\n  rotationStep?: number;\n  /** Grid size in px. Larger values create more gap between words. Default: `8`. */\n  gridSize?: number;\n  /** Keep `maskImage` aspect ratio. Default: `false`. */\n  keepAspect?: boolean;\n  /** Allow drawing outside the layout body. Default: `false`. */\n  drawOutOfBound?: boolean;\n  /** Shrink words to fit when layout is dense. Default: `false`. */\n  shrinkToFit?: boolean;\n  /** Enable placement animation. Default: `true`. */\n  layoutAnimation?: boolean;\n  /** Sort data by value descending before layout. Default: `true`. */\n  autoSort?: boolean;\n  /** Optional mask image for custom cloud shapes. */\n  maskImage?: HTMLImageElement | HTMLCanvasElement;\n}\n","import {\n  ColorHub,\n  lighten,\n  darken,\n  alpha,\n  type StateColors,\n} from '@bndynet/color-hub';\nimport * as echarts from 'echarts';\nimport { buildEChartsTheme } from './echarts-theme.js';\nimport { darkTheme, lightTheme, chartThemes } from './presets.js';\nimport type { ChartTheme, ChartThemeColors, ChartThemeConfig } from './types.js';\nimport { chartRegistry, pruneDetachedCharts } from '../registry.js';\nimport { PaletteRegistry } from './palette-registry.js';\n\n// ---------------------------------------------------------------------------\n// ColorHub — now a READ-ONLY theme / palette / token repository.\n// ---------------------------------------------------------------------------\n//\n// ColorHub used to do four things here: (1) store themes, (2) hold palette\n// arrays, (3) hold `ChartThemeColors` tokens, and (4) act as a *stateful*\n// name → color accumulator (its `getColors(name)` advanced a palette index\n// and wrote into a shared `colorMap` as a side effect of every chart render).\n//\n// Responsibility (4) has moved out to `paletteRegistry` below — an explicit,\n// introspectable object with separate auto/pin maps that the resolver calls\n// directly. We no longer call `colorHub.getColors`, so this instance never\n// mutates and never needs rebuilding. It is kept purely for (1)–(3): theme\n// storage + switching, palette arrays, and UI tokens — and as the deriver of\n// hover/active/disabled state colors via the color-math helpers below.\nconst colorHub = new ColorHub<ChartThemeColors>(chartThemes);\n\n// ---------------------------------------------------------------------------\n// PaletteRegistry — the single owner of consistentColors name→color state.\n// ---------------------------------------------------------------------------\n//\n// Holds auto-assigned and pinned maps separately, per theme, so resetting the\n// auto slots never touches user pins. This is what made the old\n// `pinnedColorMaps` shadow-map hack unnecessary.\nconst paletteRegistry = new PaletteRegistry();\n\nconst knownThemeNames = new Set<string>(chartThemes.map((t) => t.name));\n\nlet registered = false;\n\n/**\n * Register all built-in chart themes with ECharts.\n * Called lazily on first chart render.\n */\nexport function ensureThemesRegistered(): void {\n  if (registered) return;\n  registered = true;\n\n  for (const theme of chartThemes) {\n    if (theme.colors && theme.palette) {\n      echarts.registerTheme(theme.name, buildEChartsTheme(theme.colors, theme.palette));\n    }\n  }\n}\n\n/**\n * Switch the active theme, clear that theme's *auto-assigned* color slots\n * (the palette restarts at index 0 for the next chart), and re-apply the\n * theme to every live chart.\n *\n * Pinned entries from {@link setColorMap} are preserved — they live in a\n * dedicated `pins` map inside {@link PaletteRegistry}, untouched by the auto\n * reset, so a `setColorMap` pin survives every `switchTheme` cycle.\n *\n * This is the canonical way for SPA pages to get a clean palette without\n * leaking name → color assignments from a previously visited page.\n * Consumers no longer need to call {@link resetColorMap} manually before\n * each page mount; `switchTheme` does the right thing automatically.\n */\nexport function switchTheme(name: string): void {\n  colorHub.switchTheme(name);\n  paletteRegistry.resetTheme(name);\n  // Drop charts whose container is no longer attached BEFORE re-themeing —\n  // otherwise a leaked chart from a previously visited SPA page would run\n  // its adapter, re-declare its series names into the target theme's auto\n  // assignments, and starve the current page of palette slots. With the\n  // registry-backed pipeline this prune is a belt-and-suspenders fallback;\n  // see registry.ts for the full rationale.\n  pruneDetachedCharts();\n  for (const chart of chartRegistry) {\n    chart.setTheme(name);\n  }\n}\n\n/**\n * State colors ({@link StateColors}) for `name` in the active theme.\n *\n * The base (`default`) color is resolved through {@link PaletteRegistry} — the\n * same source the chart resolver uses — so `getSeriesColor(name).default`\n * always equals the consistentColors color assigned to that name. The\n * hover / active / disabled variants are derived from the base with the\n * color-math helpers (matching ColorHub's default state recipe:\n * lighten 0.05 / darken 0.1 / alpha 0.4).\n */\nexport function getSeriesColor(name: string): StateColors {\n  const theme = colorHub.getCurrentTheme();\n  const base = paletteRegistry.resolve(theme.name, name, theme.palette ?? []);\n  return deriveStateColors(base);\n}\n\nfunction deriveStateColors(base: string): StateColors {\n  return {\n    default: base,\n    hover: lighten(base, 0.05),\n    active: darken(base, 0.1),\n    disabled: alpha(base, 0.4),\n  };\n}\n\nexport function getCurrentTheme(): ChartTheme {\n  return colorHub.getCurrentTheme();\n}\n\nexport function getThemeColors(): ChartThemeColors | undefined {\n  return colorHub.getCurrentTheme().colors;\n}\n\n/**\n * Register a custom chart theme with both ColorHub and ECharts.\n *\n * Missing `colors` tokens are automatically inherited from the built-in\n * `light` or `dark` base theme according to `colorMode` (defaults to `light`).\n * A missing `palette` is also inherited from the base.\n */\nexport function registerTheme(config: ChartThemeConfig): void {\n  const base = config.colorMode === 'dark' ? darkTheme : lightTheme;\n  const theme: ChartTheme = {\n    ...config,\n    colors: { ...base.colors!, ...config.colors },\n    palette: config.palette ?? base.palette!,\n  };\n  colorHub.appendTheme(theme);\n  knownThemeNames.add(theme.name);\n  echarts.registerTheme(theme.name, buildEChartsTheme(theme.colors!, theme.palette!));\n}\n\n/**\n * Resolve the effective ECharts theme name.\n * When no explicit name is provided, falls back to the currently active\n * ColorHub theme so charts created after a theme switch pick up the right theme.\n */\nexport function resolveThemeName(name?: string): string {\n  return name || colorHub.getCurrentTheme().name;\n}\n\n/**\n * Build the palette color array for a chart given series names, user colors/colorMap,\n * and the active theme.\n *\n * This is the `consistentColors: true` resolver — names map to colors through\n * {@link PaletteRegistry} so the same name keeps the same color across charts.\n */\nexport function resolveSeriesColors(\n  seriesNames: string[],\n  userColors?: string[],\n  userColorMap?: Record<string, string>,\n): string[] {\n  if (userColors && userColors.length >= seriesNames.length) {\n    return userColors.slice(0, seriesNames.length);\n  }\n\n  const theme = colorHub.getCurrentTheme();\n  const themeName = theme.name;\n  const palette = theme.palette ?? [];\n  return seriesNames.map((name) => {\n    if (userColorMap?.[name]) return userColorMap[name];\n    return paletteRegistry.resolve(themeName, name, palette);\n  });\n}\n\n/**\n * Pre-bind name → color mappings (\"pins\").\n * When `themeName` is provided, applies only to that theme.\n * When omitted, applies to every registered theme.\n *\n * Pins are sticky: they survive {@link switchTheme} and {@link resetColorMap}\n * because they live in {@link PaletteRegistry}'s dedicated `pins` map, which\n * the auto-reset paths never touch. Calling `setColorMap` again with the same\n * name overwrites the existing pin; pins are additive across calls (no public\n * API to remove a single pin — start a fresh session if you really need to).\n *\n * Only meaningful when `consistentColors` is enabled — without it, the\n * resolver path is positional ({@link resolveColorsByPosition}) and never\n * reads the registry's stored map.\n */\nexport function setColorMap(\n  map: Record<string, string>,\n  themeName?: string,\n): void {\n  const targets = themeName ? [themeName] : [...knownThemeNames];\n  for (const name of targets) {\n    // Guard against unregistered themes: pinning under a name that no real\n    // theme will ever resolve against would silently strand the entry.\n    // Skip with a no-op instead.\n    if (!knownThemeNames.has(name)) continue;\n    for (const key of Object.keys(map)) {\n      paletteRegistry.pin(name, key, map[key]);\n    }\n  }\n}\n\n/**\n * Clear auto-assigned name → color slots.\n *\n * - When `themeName` is omitted, clears every theme's auto assignments so the\n *   next chart starts cleanly from `palette[0]` in whichever theme it renders\n *   against.\n * - When `themeName` is provided, only that theme's auto slots are cleared.\n *\n * In both cases, entries previously written by {@link setColorMap} are\n * **preserved** — they live in {@link PaletteRegistry}'s `pins` map. Call\n * {@link setColorMap} again to add new pins; there is no public API to remove\n * a pin (use a fresh app load if you really need that — pins are\n * intentionally sticky).\n *\n * Since `switchTheme(name)` now automatically clears the target theme's\n * auto-assigned entries, most consumers don't need to call this directly.\n * It remains useful for:\n *   - Manually wiping state mid-page without changing theme.\n *   - Wiping ALL themes' auto-assignments at once (the no-arg form).\n */\nexport function resetColorMap(themeName?: string): void {\n  if (themeName) {\n    paletteRegistry.resetTheme(themeName);\n    return;\n  }\n  paletteRegistry.resetAll();\n}\n\n/**\n * Resolve colors by palette position (index 0, 1, 2, …) independent of series names.\n * Each chart starts from palette[0], cycling if more names than palette entries.\n */\nexport function resolveColorsByPosition(\n  seriesNames: string[],\n  userColors?: string[],\n  userColorMap?: Record<string, string>,\n): string[] {\n  if (userColors && userColors.length >= seriesNames.length) {\n    return userColors.slice(0, seriesNames.length);\n  }\n\n  const palette = colorHub.getCurrentTheme().palette ?? [];\n  return seriesNames.map((name, i) => {\n    if (userColorMap?.[name]) return userColorMap[name];\n    return palette[i % palette.length] ?? '#888888';\n  });\n}\n\n/**\n * Sync the active theme before resolving colors.\n *\n * Internal-only — does NOT trigger the auto-reset behavior of the public\n * {@link switchTheme}. This is used by `resolveColors` on every adapter\n * call to set the right theme context, and must NOT clear auto assignments\n * (doing so would defeat `consistentColors`).\n */\nexport function syncColorHubTheme(name: string): void {\n  colorHub.switchTheme(name);\n}\n\n// ---------------------------------------------------------------------------\n// Render-session refcounting (internal — not part of the public package API)\n// ---------------------------------------------------------------------------\n//\n// The chart engine (`src/core.ts`) brackets each render with\n// `beginColorRender` / `endColorRender` so the names a chart resolves become a\n// refcounted *lease*; `releaseColorOwner` (called from `dispose()`) frees that\n// chart's names and recycles any auto slot whose refcount hits zero. This is\n// what demotes `pruneDetachedCharts` / the disconnect sentinel from a\n// load-bearing wall to a pure fallback — dispose now releases palette slots\n// directly, with no dependency on a registry sweep.\n//\n// `owner` is an opaque token (the IChart instance). These are no-ops for the\n// positional (`consistentColors: false`) path because that resolver never\n// calls into the registry, so a render session simply records zero names.\n\nexport function beginColorRender(owner: object, themeName: string): void {\n  paletteRegistry.beginRender(owner, themeName);\n}\n\nexport function endColorRender(owner: object): void {\n  paletteRegistry.endRender(owner);\n}\n\nexport function releaseColorOwner(owner: object): void {\n  paletteRegistry.releaseOwner(owner);\n}\n\nexport type { ChartTheme, ChartThemeColors, ChartThemeConfig };\nexport { lightTheme as chartLightTheme, darkTheme as chartDarkTheme, chartThemes } from './presets.js';\n","/**\n * Shared canvas-based text measurement primitive.\n */\n\nexport const DEFAULT_LABEL_FONT_SIZE = 12;\nexport const DEFAULT_LABEL_FONT = `${DEFAULT_LABEL_FONT_SIZE}px sans-serif`;\n\nexport function buildLabelFont(fontSize: number): string {\n  return `${fontSize}px sans-serif`;\n}\n\nconst FALLBACK_CHAR_PX = 7;\n\nlet measureCtx: CanvasRenderingContext2D | null | undefined;\n\nfunction getMeasureCtx(): CanvasRenderingContext2D | null {\n  if (measureCtx !== undefined) return measureCtx;\n  if (typeof document === 'undefined') {\n    measureCtx = null;\n    return null;\n  }\n  try {\n    measureCtx = document.createElement('canvas').getContext('2d');\n  } catch {\n    measureCtx = null;\n  }\n  return measureCtx ?? null;\n}\n\nexport function measureTextWidth(text: string, font: string = DEFAULT_LABEL_FONT): number {\n  if (!text) return 0;\n  const ctx = getMeasureCtx();\n  if (ctx) {\n    ctx.font = font;\n    return Math.ceil(ctx.measureText(text).width);\n  }\n  return text.length * FALLBACK_CHAR_PX;\n}\n\nexport function measureMaxTextWidth(\n  texts: ReadonlyArray<string>,\n  font: string = DEFAULT_LABEL_FONT,\n): number {\n  let widest = 0;\n  for (const text of texts) {\n    const w = measureTextWidth(text, font);\n    if (w > widest) widest = w;\n  }\n  return widest;\n}\n","import type { ChartThemeColors } from './types.js';\nimport { DEFAULT_LABEL_FONT_SIZE } from '../adapters/common/text-measure.js';\n\n/**\n * \"Outlined label\" defaults for series labels that sit on top of palette\n * colors. A `surface`-colored halo around the glyph keeps text legible\n * on any underlying fill — without it, `textPrimary` (near-black on\n * light, near-white on dark) drops into mid-tone palette tints (amber,\n * cyan, etc.) and becomes hard to read.\n *\n * Use the helper in any series-type theme entry whose adapter paints\n * the label *inside* a palette-colored shape:\n *  - `treemap.label` / `treemap.upperLabel` — labels always sit inside\n *    palette-tinted rectangles.\n *  - `sankey.label` — labels sit inside the column node when\n *    `variant === 'vertical'` (and harmlessly on the card background\n *    when horizontal — the `surface`-colored halo simply blends into\n *    the card and has no visual effect).\n *\n * `colors.surface` is deliberately the OPPOSITE side of\n * `colors.textPrimary` in both built-in presets (white in light,\n * slate-800 in dark — see `src/themes/presets.ts`), which is exactly\n * what an outline needs to be to read on every palette color.\n * 2 px is just enough to lift the glyph off mid-tone fills without\n * looking stickered.\n *\n * If a future surface needs a different halo width or a wholly\n * different stroke color, branch HERE (a second helper) — do not\n * inline the literal at the call site, so the rationale and the\n * matching `textBorder*` regression tests stay co-located.\n */\nfunction paletteLabelHalo(colors: ChartThemeColors) {\n  return {\n    textBorderColor: colors.surface,\n    textBorderWidth: 2,\n  };\n}\n\n/**\n * Build a full ECharts theme object from `ChartThemeColors` and a series palette.\n * Registered via `echarts.registerTheme(name, buildEChartsTheme(colors, palette))`.\n *\n * Token mapping:\n *  background    → chart canvas background (transparent by default)\n *  surface       → tooltip bg, axis-pointer callout bg\n *  surfaceText   → tooltip text, axis-pointer callout text\n *  itemDivider   → pie-slice border + treemap rectangle gap (and future\n *                  sunburst sectors / sankey & network node borders);\n *                  falls back to `surface` when undefined so themes\n *                  registered before this token existed keep their\n *                  previous behaviour\n *  textPrimary   → chart title, legend, pie labels, gauge detail (value),\n *                  radar indicator names (axisName), markPoint labels,\n *                  bar/line value labels (incl. race value labels and\n *                  line-race endLabels), graph/sankey/chord/tree node\n *                  + link labels, and custom-series labels (used by\n *                  `wordcloud`'s custom renderer)\n *  textSecondary → axis tick labels, gauge title (label text e.g. \"CPU\")\n *  gridLine      → splitLine (grid rules), radar splitLine + alternating\n *                  splitArea bands\n *  axisLine      → axis spine, tick marks, cursor crosshair, radar axisLine\n *\n * Note on label colors: adapters intentionally do NOT set `series.label.color`\n * / `series.endLabel.color` / `series.edgeLabel.color`. ECharts deep-merges\n * the series-type defaults below (`bar.label`, `line.label`, `line.endLabel`,\n * `pie.label`, `map.label`, `radar.axisName`, `graph.label`, `graph.edgeLabel`,\n * `sankey.label`, `chord.label`, `tree.label`, `custom.label`, …) into each series so themes\n * drive the look.\n * This keeps adapters theme-agnostic (they never read the active palette\n * directly) and means a single theme switch repaints every data label on the\n * chart. AGENTS.md \"Layout rule #6\" documents this two-sided contract: any\n * new chart whose adapter renders canvas-rendered text MUST add the matching\n * `<seriesType>.<field>.color` entry here AND a regression test below in\n * `echarts-theme.test.ts` — leaving the theme side unwired silently breaks\n * dark-theme rendering for that chart.\n *\n * Note on label fontSize (different contract from color): every relevant\n * `<seriesType>.label.fontSize` / `<seriesType>.edgeLabel.fontSize` below\n * is wired to {@link DEFAULT_LABEL_FONT_SIZE} as a *fallback*. Unlike\n * color (which is owned entirely by the theme), fontSize is also emitted\n * by adapters via `getLabelFontSize(options)` so that\n * `ChartOptions.labelFontSize` actually takes effect at the series level.\n * ECharts series-level merge wins over series-type defaults, so:\n *   - user sets `labelFontSize: 18` → adapter emits 18 → theme's 12 is\n *     overridden, every chart renders at 18 px.\n *   - user sets nothing → adapter emits the same `DEFAULT_LABEL_FONT_SIZE`\n *     (12) → identical to the theme default; the theme entry is the\n *     belt-and-suspenders guarantee that even an adapter which forgets\n *     to emit `fontSize` still ends up at the canonical 12 px (rather\n *     than ECharts' built-in default for the series type).\n */\nexport function buildEChartsTheme(\n  colors: ChartThemeColors,\n  palette: string[],\n) {\n  return {\n    color: palette,\n    backgroundColor: colors.background,\n\n    title: {\n      textStyle: { color: colors.textPrimary },\n    },\n\n    legend: {\n      textStyle: { color: colors.textPrimary },\n    },\n\n    visualMap: {\n      // Map value legend text should follow the same primary text token as\n      // title/legend/labels; otherwise it falls back to ECharts defaults\n      // (near-black), which is unreadable on dark themes.\n      textStyle: { color: colors.textPrimary },\n    },\n\n    tooltip: {\n      backgroundColor: colors.tooltipBackground ?? colors.surface,\n      borderColor:     colors.tooltipBorderColor ?? colors.axisLine,\n      textStyle: {\n        color: colors.tooltipTextColor ?? colors.surfaceText,\n      },\n      axisPointer: {\n        lineStyle:  { color: colors.axisLine, width: 1 },\n        crossStyle: { color: colors.axisLine, width: 1 },\n        label: {\n          backgroundColor: colors.tooltipBackground ?? colors.surface,\n          color:           colors.tooltipTitleColor ?? colors.tooltipTextColor ?? colors.surfaceText,\n        },\n      },\n    },\n\n    categoryAxis: buildAxisStyle(colors),\n    valueAxis:    buildAxisStyle(colors),\n    logAxis:      buildAxisStyle(colors),\n    timeAxis:     buildAxisStyle(colors),\n\n    line: {\n      smooth: false,\n      symbol: 'circle',\n      symbolSize: 4,\n      // Data labels (`showLabel: true`) and race endLabels — both render\n      // against the chart canvas, so they need the on-background text\n      // color, not whatever ECharts' built-in default happens to be (which\n      // is unreadable on dark themes). `fontSize` is the\n      // `DEFAULT_LABEL_FONT_SIZE` fallback; adapter overrides with\n      // `options.labelFontSize` via series-level merge.\n      label:    { color: colors.textPrimary, fontSize: DEFAULT_LABEL_FONT_SIZE },\n      endLabel: { color: colors.textPrimary, fontSize: DEFAULT_LABEL_FONT_SIZE },\n    },\n\n    bar: {\n      itemStyle: { barBorderWidth: 0 },\n      // Data labels (`showLabel: true`) and race value labels\n      // (`position: 'right'` + `valueAnimation`). Same rationale as line —\n      // labels live on the canvas and must follow the theme.\n      label: { color: colors.textPrimary, fontSize: DEFAULT_LABEL_FONT_SIZE },\n    },\n\n    pie: {\n      label:     { color: colors.textPrimary, fontSize: DEFAULT_LABEL_FONT_SIZE },\n      // 1 px stroke that fakes a gap between adjacent slices. Pre-token,\n      // this read `colors.surface` directly, which silently broke on\n      // themes whose tooltip surface differs from the card background\n      // (e.g. `dash-scifi`'s `surface: 'transparent'` glassmorphism →\n      // slices fused into one continuous ring). `itemDivider` is the\n      // dedicated knob; `?? colors.surface` keeps every pre-existing\n      // user-registered theme behaviourally identical.\n      itemStyle: { borderWidth: 1, borderColor: colors.itemDivider ?? colors.surface },\n    },\n\n    map: {\n      // Region labels on choropleth maps.\n      label: {\n        color: colors.textPrimary,\n        fontSize: DEFAULT_LABEL_FONT_SIZE,\n        ...paletteLabelHalo(colors),\n      },\n      emphasis: {\n        label: {\n          color: colors.textPrimary,\n          ...paletteLabelHalo(colors),\n        },\n      },\n      // Base region fill + border for map series. visualMap overwrites fill\n      // for regions with values, while regions without values still use this\n      // tokenized fallback. Border stays tokenized in all cases.\n      itemStyle: {\n        areaColor: colors.surface,\n        borderColor: colors.axisLine,\n        borderWidth: 1,\n      },\n    },\n\n    gauge: {\n      // ECharts gauge title/detail use `color` directly, NOT `textStyle.color`\n      title:     { color: colors.textSecondary }, // label (\"CPU\", \"Score\") — descriptive\n      detail:    { color: colors.textPrimary },   // value (the number)    — primary\n      axisLabel: { color: colors.textSecondary },\n      // Track (ring background): ECharts requires [[fraction, color]] array format.\n      // Adapter sets only `width`; ECharts deep-merges lineStyle so color is preserved.\n      axisLine:  { lineStyle: { color: [[1, colors.axisLine]] } },\n      splitLine: { lineStyle: { color: colors.axisLine } },\n      axisTick:  { lineStyle: { color: colors.axisLine } },\n    },\n\n    markPoint: {\n      label: { color: colors.textPrimary },\n    },\n\n    radar: {\n      // Indicator names (\"Sales\", \"Marketing\", …) are the only readable\n      // labels on the chart — treat them like pie/legend text rather than\n      // axis ticks so they stay legible against both light and dark\n      // backgrounds. Without this entry they fall back to ECharts'\n      // built-in grey and become hard to read on dark themes.\n      axisName: { color: colors.textPrimary },\n      // Spokes (axisLine) and concentric rings (splitLine) reuse the\n      // same `axisLine` / `gridLine` tokens as XY axes so a radar\n      // sitting beside a bar chart agrees on grid color.\n      ...buildStructuralLineDefaults(colors),\n      // Subtle alternating bands — half-strength gridLine so they hint at\n      // the polygon's structure without competing with the data series.\n      splitArea: {\n        show: true,\n        areaStyle: { color: ['transparent', colors.gridLine], opacity: 0.3 },\n      },\n    },\n\n    // Graph-family series (network, sankey, chord). Each adapter emits\n    // `series.label` (and network additionally emits `series.edgeLabel`)\n    // without a `color` key, so ECharts' built-in default (a near-black\n    // shade) would be unreadable on dark themes. Mirror the pie/bar/line\n    // contract: theme owns the text color, adapters stay theme-agnostic.\n    graph: {\n      label:     { color: colors.textPrimary, fontSize: DEFAULT_LABEL_FONT_SIZE }, // network node labels\n      edgeLabel: { color: colors.textPrimary, fontSize: DEFAULT_LABEL_FONT_SIZE }, // network link labels (when showLinkLabel)\n    },\n    sankey: {\n      // Sankey node labels render on the canvas. The adapter\n      // (`src/adapters/sankey.ts`) positions them on the SIDE of\n      // each column node when `variant === 'default'` (horizontal —\n      // labels sit on the card background) and INSIDE the node\n      // when `variant === 'vertical'` (columns stack top-to-bottom,\n      // and sideways labels would overlap adjacent columns).\n      //\n      // The `vertical` variant therefore paints text directly on\n      // palette-colored rectangles, with the same readability\n      // problem as treemap. Apply the shared \"outlined label\"\n      // halo so vertical sankey labels stay legible on any\n      // palette tint. The same halo is HARMLESS on horizontal\n      // sankey labels — the `surface` stroke color matches the\n      // card background, so it blends in and has no visual\n      // effect when the label sits beside (not on) a node.\n      label: {\n        color:    colors.textPrimary,\n        fontSize: DEFAULT_LABEL_FONT_SIZE,\n        ...paletteLabelHalo(colors),\n      },\n    },\n    chord: {\n      label: { color: colors.textPrimary, fontSize: DEFAULT_LABEL_FONT_SIZE }, // chord node labels (outside the ring)\n    },\n    tree: {\n      // Tree node labels render on the canvas next to each node marker.\n      // Same two-sided contract as the other graph-family entries above:\n      // the adapter (`src/adapters/tree.ts`) intentionally emits\n      // `series.label` / `series.leaves.label` *without* a `color` key\n      // so this theme entry can repaint every label in lockstep when\n      // the user switches themes.\n      label: { color: colors.textPrimary, fontSize: DEFAULT_LABEL_FONT_SIZE },\n      // Connector lines (the curved branches between parent and child)\n      // reuse the structural `axisLine` token so the tree's frame\n      // agrees with axis spines on dark themes — without this they\n      // fall back to a near-black ECharts default and disappear.\n      lineStyle: { color: colors.axisLine },\n    },\n    treemap: {\n      // Labels rendered inside each rectangle. Adapter\n      // (`src/adapters/treemap.ts`) emits `series.label` without a\n      // `color` / `textBorderColor` / `textBorderWidth` key so this\n      // theme entry drives the repaint when the user switches themes\n      // — same two-sided contract as every other label-rendering\n      // chart family above.\n      //\n      // Treemap labels sit ON TOP of palette-colored rectangles\n      // (blue / green / red / yellow / …), so `textPrimary` alone\n      // is not enough — a dark text on a mid-tone yellow or a light\n      // text on a mid-tone cyan loses contrast and becomes hard to\n      // read. The fix is the classic \"outlined label\" pattern —\n      // see `paletteLabelHalo` above for the shared rationale.\n      //\n      // Same treatment for `upperLabel` (the bar painted across the\n      // top of a parent rectangle when drilled in) — it sits on the\n      // exact same palette colors, so it needs the same halo.\n      label: {\n        color:    colors.textPrimary,\n        fontSize: DEFAULT_LABEL_FONT_SIZE,\n        ...paletteLabelHalo(colors),\n      },\n      upperLabel: {\n        color:    colors.textPrimary,\n        fontSize: DEFAULT_LABEL_FONT_SIZE,\n        ...paletteLabelHalo(colors),\n      },\n      // 1 px gap stroke between adjacent rectangles. Uses the same\n      // `itemDivider` token as pie (with `surface` fallback) so a\n      // single theme knob drives the cell-divider look across every\n      // partition-style chart.\n      itemStyle: { borderWidth: 1, borderColor: colors.itemDivider ?? colors.surface },\n      // Drill-down path chips at the bottom of the canvas. ECharts'\n      // built-in defaults are hardcoded grays (`#fff` chip bg + `#aaa`\n      // border + `#333` text) AND a hardcoded orange emphasis fill\n      // (`#e6a23c`) — both fight every theme. Wire BOTH the resting\n      // and hover/emphasis states to tokens so a single `setTheme()`\n      // sweeps the breadcrumb along with everything else.\n      //\n      // Token choice rationale (matters: the wrong tokens silently\n      // disappear into the card):\n      //   resting fill   → `gridLine` (subtle elevation above the\n      //                    typical card background; using `surface`\n      //                    here matches the card exactly in both\n      //                    built-in presets — `surface === itemDivider\n      //                    === card-bg` — and the chips vanish)\n      //   resting border → `axisLine` (one tier more prominent than\n      //                    the fill in both presets, defines the\n      //                    chip edge)\n      //   resting text   → `textPrimary`\n      //   emphasis fill  → `axisLine` (chip \"presses in\" by one\n      //                    elevation tier on hover)\n      //   emphasis border→ `textSecondary` (matches the hover tier)\n      //   emphasis text  → `textPrimary` (stays readable)\n      //\n      // The adapter (`src/adapters/treemap.ts`) deliberately does\n      // NOT emit any color fields on `breadcrumb.*` so this entry\n      // is the single source of truth — same two-sided contract as\n      // every other themed surface in this file.\n      breadcrumb: {\n        itemStyle: {\n          color:       colors.gridLine,\n          borderColor: colors.axisLine,\n          borderWidth: 1,\n          textStyle:   { color: colors.textPrimary },\n        },\n        emphasis: {\n          itemStyle: {\n            color:       colors.axisLine,\n            borderColor: colors.textSecondary,\n            borderWidth: 1,\n            textStyle:   { color: colors.textPrimary },\n          },\n        },\n      },\n    },\n    custom: {\n      // Wordcloud and liquidprogress are implemented via ECharts custom\n      // series (`renderItem: 'wordCloud'` / `'liquidFill'`). Keep\n      // custom-series labels on the same theme token so any label-like\n      // text emitted by custom charts remains legible.\n      label: { color: colors.textPrimary, fontSize: DEFAULT_LABEL_FONT_SIZE },\n    },\n  };\n}\n\n/**\n * Themed defaults for \"structural lines\" — the axis spine plus the\n * split-line grid rules — shared between XY axes (categoryAxis,\n * valueAxis, …) and the radar component.\n *\n * Both visual roles map back to the same tokens:\n *   - {@link ChartThemeColors.axisLine}  → XY axis spine / radar spokes\n *     (the \"frame\" rule, intentionally more prominent than gridLine).\n *   - {@link ChartThemeColors.gridLine}  → XY splitLine / radar's\n *     concentric polygon rings (the \"subtle reading aid\" rules).\n *\n * Built once so a token change repaints every chart type in lockstep.\n * Adapters and `buildAxisStyle` consume this via spread; never\n * redeclare the inner `{ lineStyle: { color: ... } }` shape elsewhere\n * in the theme.\n */\nfunction buildStructuralLineDefaults(colors: ChartThemeColors) {\n  return {\n    axisLine: { show: true, lineStyle: { color: colors.axisLine } },\n    splitLine: { show: true, lineStyle: { color: colors.gridLine } },\n  };\n}\n\nfunction buildAxisStyle(colors: ChartThemeColors) {\n  return {\n    ...buildStructuralLineDefaults(colors),\n    axisTick: {\n      show: true,\n      lineStyle: { color: colors.axisLine },\n    },\n    axisLabel: {\n      show: true,\n      color: colors.textSecondary,\n    },\n    splitArea: { show: false },\n  };\n}\n","import type { ChartTheme, ChartThemeColors } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Series palettes\n// ---------------------------------------------------------------------------\n// Palettes are the *only* colors managed by ColorHub (series assignment).\n// Light and dark variants use the same hue family but adjust lightness/saturation\n// so each palette looks natural against its respective background.\n\nconst LIGHT_PALETTE = [\n  '#3b82f6', // blue\n  '#10b981', // emerald\n  '#f59e0b', // amber\n  '#ef4444', // red\n  '#8b5cf6', // violet\n  '#06b6d4', // cyan\n  '#f97316', // orange\n  '#ec4899', // pink\n  '#84cc16', // lime\n  '#6366f1', // indigo\n];\n\nconst DARK_PALETTE = [\n  '#60a5fa', // blue-400\n  '#34d399', // emerald-400\n  '#fbbf24', // amber-400\n  '#f87171', // red-400\n  '#a78bfa', // violet-400\n  '#22d3ee', // cyan-400\n  '#fb923c', // orange-400\n  '#f472b6', // pink-400\n  '#a3e635', // lime-400\n  '#818cf8', // indigo-400\n];\n\n// ---------------------------------------------------------------------------\n// UI color tokens\n// ---------------------------------------------------------------------------\n\nconst LIGHT_COLORS: ChartThemeColors = {\n  // Surfaces\n  background:   'transparent',\n  surface:      '#ffffff', // axis-pointer callout — same light surface\n  surfaceText:  '#111827',\n\n  // Text\n  textPrimary:   '#111827',\n  textSecondary: '#6b7280',\n\n  // Structure\n  gridLine: '#f3f4f6', // barely visible rules\n  axisLine: '#d1d5db', // slightly more prominent frame\n  // White card background is the dominant business-app default (Element\n  // Plus / Tailwind / Ant Design ship `#ffffff` panels), so a white 1 px\n  // pie-slice border reads as a true gap. Numerically equals `surface`\n  // here, but the two tokens are semantically independent — themes whose\n  // tooltip surface differs from their card background (see `dash-scifi`)\n  // override one without touching the other.\n  itemDivider: '#ffffff',\n\n  // Tooltip — light popup consistent with the light background\n  tooltipBackground: '#ffffff',\n  tooltipBorderColor: '#e5e7eb',\n  tooltipTextColor:   '#111827',\n  tooltipTitleColor:  '#6b7280', // slightly muted vs body text\n\n  // Semantic\n  success: '#22c55e',\n  warning: '#f59e0b',\n  danger:  '#ef4444',\n  info:    '#3b82f6',\n};\n\nconst DARK_COLORS: ChartThemeColors = {\n  // Surfaces\n  background:   'transparent',\n  surface:      '#1e293b', // elevated panel, tooltip\n  surfaceText:  '#e2e8f0',\n\n  // Text\n  textPrimary:   '#f1f5f9',\n  textSecondary: '#94a3b8',\n\n  // Structure — same visual hierarchy as the light theme, walked one\n  // step up the slate scale per token so each rule stays visible\n  // against a slate-800 surface:\n  //   surface  (#1e293b, slate-800)\n  //   gridLine (#334155, slate-700) — subtle but legible rules\n  //   axisLine (#475569, slate-600) — clearly more prominent frame\n  // Earlier versions used `gridLine: '#1e293b'` (= surface), which made\n  // every XY splitLine and radar ring disappear on the default dark\n  // dashboard background.\n  gridLine: '#334155',\n  axisLine: '#475569',\n  // Matches the slate-800 panel color most dark dashboards put behind\n  // their cards, so a 1 px pie-slice border reads as a true gap. Same\n  // value as `surface` here purely by coincidence (both happen to map\n  // to slate-800 in the canonical dark theme) — the two tokens are\n  // semantically independent (see ChartThemeColors.itemDivider).\n  itemDivider: '#1e293b',\n\n  // Tooltip — slightly elevated surface to pop above the chart canvas\n  tooltipBackground: '#1e293b',\n  tooltipBorderColor: '#334155',\n  tooltipTextColor:   '#e2e8f0',\n  tooltipTitleColor:  '#94a3b8', // muted slate for title vs bright body text\n\n  // Semantic — slightly lighter variants for dark backgrounds\n  success: '#4ade80',\n  warning: '#fbbf24',\n  danger:  '#f87171',\n  info:    '#60a5fa',\n};\n\n// ---------------------------------------------------------------------------\n// Exported themes\n// ---------------------------------------------------------------------------\n\nexport const lightTheme: ChartTheme = {\n  name:      'light',\n  colorMode: 'light',\n  palette:   LIGHT_PALETTE,\n  colors:    LIGHT_COLORS,\n};\n\nexport const darkTheme: ChartTheme = {\n  name:      'dark',\n  colorMode: 'dark',\n  palette:   DARK_PALETTE,\n  colors:    DARK_COLORS,\n};\n\n/** All built-in chart themes, in registration order. */\nexport const chartThemes: ChartTheme[] = [lightTheme, darkTheme];\n","import type { IChartInstance } from './types.js';\n\n/**\n * Global registry of all live IChart instances.\n * Used by {@link switchTheme} to propagate theme changes to every chart.\n */\nexport const chartRegistry = new Set<IChartInstance>();\n\n/**\n * Drop and dispose any chart whose ECharts container is no longer in the\n * document.\n *\n * Most consumers never reach this code path — `IChart`'s constructor\n * installs a sentinel custom element (see `disconnect-sentinel.ts`) that\n * auto-disposes the chart the moment its container leaves the live DOM,\n * and `<i-chart>` additionally cleans up in its Lit `disconnectedCallback`.\n * This walk is the **last line of defense** for environments where the\n * sentinel can't fire:\n *\n * - SSR / Node test runners where `customElements` is undefined.\n * - Old browsers without the Custom Elements V1 registry.\n * - Cases where consumer code nukes the sentinel directly (e.g.\n *   `container.innerHTML = ''` — actually still fires disconnect; safe)\n *   or detaches the container before any task can run.\n *\n * Why it matters: registry walks (`switchTheme`,\n * `configure({ consistentColors })`) propagate changes to every entry,\n * and a detached chart still runs its adapter — which writes into the\n * active theme's `colorMap` (when `consistentColors: true`). Without\n * pruning, a stale chart from a previously visited page would re-populate\n * `colorMap` with its series names and starve the current page's palette,\n * producing the \"theme colors don't apply\" symptom users hit when\n * navigating between pages.\n *\n * `isConnected` is the DOM-standard check; works through shadow roots\n * (returns `true` only when the entire ancestor chain reaches `document`).\n * SSR / non-DOM environments expose `undefined` for `getDom()`, so we\n * leave those charts alone instead of misclassifying them as detached.\n */\nexport function pruneDetachedCharts(): void {\n  const toDispose: IChartInstance[] = [];\n  for (const chart of chartRegistry) {\n    const ec = chart.getEChartsInstance();\n    if (ec.isDisposed()) {\n      // Already disposed but still in registry (shouldn't happen since\n      // dispose() removes itself; belt-and-suspenders).\n      chartRegistry.delete(chart);\n      continue;\n    }\n    const dom = ec.getDom();\n    if (dom && !dom.isConnected) {\n      toDispose.push(chart);\n    }\n  }\n  // Snapshot first, then dispose, to avoid mutating chartRegistry mid-walk.\n  for (const chart of toDispose) {\n    chart.dispose();\n  }\n}\n","import { randomDistinctColor } from '@bndynet/color-hub';\n\n/**\n * Per-theme name → color state for the `consistentColors` pipeline.\n *\n * The maps are kept **explicitly separate** (unlike ColorHub's single mixed\n * `colorMap`) so that auto-assigned palette slots can be cleared or recycled\n * without ever touching user-supplied pins — the property that used to require\n * the `pinnedColorMaps` shadow map in `themes/index.ts`.\n *\n *  - `auto`  — names assigned a color from the palette on first encounter.\n *  - `pins`  — names pre-bound via `setColorMap`; permanent until overwritten.\n *  - `order` — first-seen order of `auto` names (stable allocation order).\n *  - `refs`  — refcount per auto name: how many live charts currently declare\n *              it. An auto entry whose refcount drops to 0 is recycled (its\n *              palette slot is freed for the next new name). Names assigned\n *              outside a render session (SSR one-shot render, `getSeriesColor`)\n *              never get a refcount and therefore linger — matching the old\n *              \"names are never released\" behavior for those paths.\n */\ninterface ThemeColorState {\n  auto: Map<string, string>;\n  pins: Map<string, string>;\n  order: string[];\n  refs: Map<string, number>;\n}\n\n/** What a single chart currently holds: a theme and the set of names leased from it. */\ninterface Lease {\n  theme: string;\n  names: Set<string>;\n}\n\n/**\n * Library-owned, SSR-safe (pure `Map`s — no browser globals) registry for\n * \"same name → same color across charts\" assignment, with lifecycle-owned\n * recycling.\n *\n * This replaces the stateful accumulator that used to live inside ColorHub's\n * `getColors(name)` call. Rendering a chart no longer mutates a shared\n * ColorHub singleton as a side effect; instead, the resolver explicitly asks\n * this registry for a color, and the state it keeps is introspectable and\n * owned by the chart lifecycle:\n *\n *   - Allocation is behavior-equivalent to the previous ColorHub\n *     implementation: pin wins; an already-seen auto name keeps its color; a\n *     new name gets the first palette color not already used by a pin or a\n *     prior auto assignment in the same theme; once the palette is exhausted a\n *     golden-ratio distinct color is generated.\n *   - Reference counting is driven by render *sessions*. The engine brackets\n *     each chart render with {@link beginRender} / {@link endRender}; every\n *     `resolve` made in between is recorded as that chart's *lease*. When the\n *     chart re-renders without a name, or is disposed via\n *     {@link releaseOwner}, the name's refcount drops; at zero the auto slot\n *     is recycled. This makes `dispose()` the primary cleanup mechanism and\n *     demotes the registry / sentinel sweeps to a pure fallback.\n *\n * State is partitioned per theme name, matching ColorHub's per-theme\n * `colorMap`, so auto assignments never bleed across themes.\n */\nexport class PaletteRegistry {\n  private readonly themes = new Map<string, ThemeColorState>();\n\n  /** Names currently leased by each live chart (keyed by an opaque owner token). */\n  private readonly leases = new Map<object, Lease>();\n\n  /** The render session in progress (one at a time — renders are synchronous). */\n  private current: { owner: object; theme: string; names: Set<string> } | null =\n    null;\n\n  private state(theme: string): ThemeColorState {\n    let s = this.themes.get(theme);\n    if (!s) {\n      s = { auto: new Map(), pins: new Map(), order: [], refs: new Map() };\n      this.themes.set(theme, s);\n    }\n    return s;\n  }\n\n  /**\n   * Resolve `name` to a color for `theme`, assigning a new palette slot on\n   * first encounter. Pins win over auto assignments. The `palette` is passed\n   * in (rather than stored) so the registry stays a pure name→color allocator\n   * and ColorHub remains the single owner of palette arrays.\n   *\n   * When called inside a {@link beginRender} session for the same theme, the\n   * name is recorded into the active chart's lease so it participates in\n   * refcounting; outside a session (SSR render, `getSeriesColor`) it is simply\n   * assigned without a refcount.\n   */\n  resolve(theme: string, name: string, palette: readonly string[]): string {\n    if (this.current && this.current.theme === theme) {\n      this.current.names.add(name);\n    }\n\n    const s = this.state(theme);\n    const pinned = s.pins.get(name);\n    if (pinned !== undefined) return pinned;\n    const existing = s.auto.get(name);\n    if (existing !== undefined) return existing;\n\n    const color = this.allocate(s, palette);\n    s.auto.set(name, color);\n    s.order.push(name);\n    return color;\n  }\n\n  /** First palette color not already used by a pin or auto assignment; golden fallback on exhaustion. */\n  private allocate(s: ThemeColorState, palette: readonly string[]): string {\n    const used = new Set<string>();\n    for (const c of s.pins.values()) used.add(c);\n    for (const c of s.auto.values()) used.add(c);\n\n    for (const c of palette) {\n      if (!used.has(c)) return c;\n    }\n\n    // Palette exhausted — mirror ColorHub's default `golden` exhaustion:\n    // pick a perceptually-spread color that doesn't collide with one in use.\n    let c: string;\n    do {\n      c = randomDistinctColor();\n    } while (used.has(c));\n    return c;\n  }\n\n  /** Pre-bind a name to a color for `theme`. Overwrites any existing pin. */\n  pin(theme: string, name: string, color: string): void {\n    this.state(theme).pins.set(name, color);\n  }\n\n  // ── Render-session refcounting ────────────────────────────────────────────\n\n  /**\n   * Open a render session for `owner` against `theme`. Every {@link resolve}\n   * for this theme until {@link endRender} is recorded as part of the owner's\n   * new lease. Idempotent-safe: a stray `beginRender` without a matching\n   * `endRender` is overwritten by the next `beginRender`.\n   */\n  beginRender(owner: object, theme: string): void {\n    this.current = { owner, theme, names: new Set() };\n  }\n\n  /**\n   * Close `owner`'s render session and reconcile its lease: acquire newly\n   * declared names, release names it no longer declares (recycling auto slots\n   * whose refcount hits 0). A no-op if no session is open for `owner`.\n   */\n  endRender(owner: object): void {\n    const session = this.current;\n    this.current = null;\n    if (!session || session.owner !== owner) return;\n    this.commitLease(owner, session.theme, session.names);\n  }\n\n  /**\n   * Release every name `owner` holds (called on `dispose()`), recycling auto\n   * slots whose refcount reaches 0. Pins are never recycled.\n   */\n  releaseOwner(owner: object): void {\n    const lease = this.leases.get(owner);\n    if (!lease) return;\n    this.leases.delete(owner);\n    const s = this.state(lease.theme);\n    for (const name of lease.names) this.releaseName(s, name);\n  }\n\n  private commitLease(owner: object, theme: string, names: Set<string>): void {\n    const prev = this.leases.get(owner);\n    const s = this.state(theme);\n\n    // Acquire names that are newly declared this pass.\n    for (const name of names) {\n      const heldBefore =\n        prev !== undefined && prev.theme === theme && prev.names.has(name);\n      if (!heldBefore) s.refs.set(name, (s.refs.get(name) ?? 0) + 1);\n    }\n\n    // Release names the owner previously held but no longer declares (a theme\n    // change releases the entire previous lease).\n    if (prev) {\n      const sameTheme = prev.theme === theme;\n      const prevState = sameTheme ? s : this.state(prev.theme);\n      for (const name of prev.names) {\n        if (sameTheme && names.has(name)) continue;\n        this.releaseName(prevState, name);\n      }\n    }\n\n    this.leases.set(owner, { theme, names });\n  }\n\n  /** Decrement a name's refcount; recycle the auto slot (not pins) at 0. */\n  private releaseName(s: ThemeColorState, name: string): void {\n    const count = s.refs.get(name);\n    if (count === undefined) return;\n    if (count > 1) {\n      s.refs.set(name, count - 1);\n      return;\n    }\n    s.refs.delete(name);\n    if (s.pins.has(name)) return; // pins are durable — never recycled\n    if (s.auto.delete(name)) {\n      const idx = s.order.indexOf(name);\n      if (idx >= 0) s.order.splice(idx, 1);\n    }\n  }\n\n  // ── Resets ────────────────────────────────────────────────────────────────\n\n  /** Clear a single theme's auto assignments + refcounts. Pins are preserved. */\n  resetTheme(theme: string): void {\n    const s = this.themes.get(theme);\n    if (s) {\n      s.auto.clear();\n      s.order.length = 0;\n      s.refs.clear();\n    }\n    // Drop the now-stale leased names for this theme so the next render of any\n    // live owner re-acquires clean refcounts instead of double-counting.\n    for (const lease of this.leases.values()) {\n      if (lease.theme === theme) lease.names.clear();\n    }\n  }\n\n  /** Clear every theme's auto assignments + refcounts. Pins are preserved. */\n  resetAll(): void {\n    for (const s of this.themes.values()) {\n      s.auto.clear();\n      s.order.length = 0;\n      s.refs.clear();\n    }\n    for (const lease of this.leases.values()) lease.names.clear();\n  }\n}\n","import { chartRegistry, pruneDetachedCharts } from './registry.js';\nimport {\n  resetColorMap,\n  registerTheme,\n  switchTheme,\n  type ChartThemeConfig,\n} from './themes/index.js';\n\nexport interface IChartsConfig {\n  consistentColors: boolean;\n  fontFamily?: string;\n  theme?: ChartThemeConfig;\n}\n\nconst DEFAULT_CONFIG: Readonly<IChartsConfig> = {\n  consistentColors: false,\n  fontFamily: undefined,\n  theme: undefined,\n};\n\nlet currentConfig: IChartsConfig = { ...DEFAULT_CONFIG };\n\nexport function configure(opts: Partial<IChartsConfig>): void {\n  const prev = { ...currentConfig };\n  currentConfig = { ...currentConfig, ...opts };\n\n  if (opts.theme) {\n    const shouldRegister =\n      !prev.theme ||\n      prev.theme.name !== opts.theme.name ||\n      prev.theme.colorMode !== opts.theme.colorMode ||\n      prev.theme.colors !== opts.theme.colors ||\n      prev.theme.palette !== opts.theme.palette;\n    if (shouldRegister) {\n      registerTheme(opts.theme);\n    }\n    switchTheme(opts.theme.name);\n  }\n\n  const shouldRerender =\n    prev.consistentColors !== currentConfig.consistentColors ||\n    prev.fontFamily !== currentConfig.fontFamily;\n\n  if (shouldRerender) {\n    if (currentConfig.consistentColors) {\n      resetColorMap();\n    }\n    // Same defensive prune as switchTheme — re-rendering a detached chart\n    // is wasted work and (with consistentColors: true) writes its series\n    // names into the freshly-cleared colorMap, recreating the cross-page\n    // palette drift this rebuild is meant to fix. See registry.ts.\n    pruneDetachedCharts();\n    for (const chart of chartRegistry) {\n      chart.update();\n    }\n  }\n}\n\n/** Reset configure() state back to library defaults. */\nexport function resetConfiguration(): void {\n  switchTheme('light');\n  configure({ ...DEFAULT_CONFIG });\n}\n\nexport function getConfig(): Readonly<IChartsConfig> {\n  return currentConfig;\n}\n","import type { ChartOptions } from './types.js';\nimport {\n  resolveSeriesColors,\n  resolveColorsByPosition,\n  syncColorHubTheme,\n  resolveThemeName,\n} from './themes/index.js';\nimport { getConfig } from './config.js';\n\n// ---------------------------------------------------------------------------\n// Object helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Type-aware deep merge. Later sources win. Arrays are replaced, not concatenated.\n * Handles plain objects recursively; non-objects overwrite.\n */\nexport function deepMerge<T extends Record<string, unknown>>(\n  ...sources: (Partial<T> | undefined)[]\n): T {\n  const result: Record<string, unknown> = {};\n\n  for (const source of sources) {\n    if (!source) continue;\n    for (const key of Object.keys(source)) {\n      const srcVal = (source as Record<string, unknown>)[key];\n      const dstVal = result[key];\n\n      if (isPlainObject(srcVal) && isPlainObject(dstVal)) {\n        result[key] = deepMerge(\n          dstVal as Record<string, unknown>,\n          srcVal as Record<string, unknown>,\n        );\n      } else if (srcVal !== undefined) {\n        result[key] = srcVal;\n      }\n    }\n  }\n\n  return result as T;\n}\n\nfunction isPlainObject(val: unknown): val is Record<string, unknown> {\n  return val !== null && typeof val === 'object' && !Array.isArray(val);\n}\n\n// ---------------------------------------------------------------------------\n// Number / string helpers\n// ---------------------------------------------------------------------------\n\nexport function formatNumber(\n  value?: number | string,\n  options?: FormatNumberOptions,\n): string {\n  return formatNumberWithOptions(value, options);\n}\n\nexport interface FormatNumberOptions extends Intl.NumberFormatOptions {\n  compact?: boolean;\n  locale?: string;\n}\n\nfunction formatNumberWithOptions(\n  value?: number | string,\n  options?: FormatNumberOptions,\n): string {\n  if (value === undefined || value === null) return '';\n  if (!options) {\n    return value.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n  }\n\n  const {\n    compact = false,\n    locale,\n    ...numberFormatOptions\n  } = options;\n\n  const numericValue = typeof value === 'number' ? value : Number(value);\n  if (!Number.isFinite(numericValue)) return '';\n\n  const formatter = new Intl.NumberFormat(locale, {\n    ...(compact ? { notation: 'compact', compactDisplay: 'short' as const } : {}),\n    useGrouping: true,\n    ...numberFormatOptions,\n  });\n  return formatter.format(numericValue);\n}\n\nexport function isTimestamp(value: unknown): boolean {\n  if (typeof value !== 'number') return false;\n  const len = value.toString().length;\n  return len === 10 || len === 13;\n}\n\n// ---------------------------------------------------------------------------\n// Color helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a CSS hex color (#rgb or #rrggbb) to an \"r, g, b\" string\n * suitable for use inside rgba(...).\n */\nexport function hexToRgb(hex: string): string {\n  const h = hex.replace('#', '');\n  if (h.length === 3) {\n    return [\n      parseInt(h[0] + h[0], 16),\n      parseInt(h[1] + h[1], 16),\n      parseInt(h[2] + h[2], 16),\n    ].join(', ');\n  }\n  return [\n    parseInt(h.substring(0, 2), 16),\n    parseInt(h.substring(2, 4), 16),\n    parseInt(h.substring(4, 6), 16),\n  ].join(', ');\n}\n\n/**\n * Build a gradient offset array from a list of colors.\n * Returns `[{ offset: 0, color }, ..., { offset: 1, color }]`.\n */\nexport function buildGradientStops(\n  colors: string[],\n): { offset: number; color: string }[] {\n  if (colors.length === 0) return [];\n  if (colors.length === 1) return [{ offset: 0, color: colors[0] }];\n  const step = 1 / (colors.length - 1);\n  return colors.map((color, i) => ({\n    offset: i === colors.length - 1 ? 1 : i * step,\n    color,\n  }));\n}\n\n/**\n * Build a vertical linear gradient for a spark area fill.\n * Top → series color at ~35% opacity; bottom → fully transparent.\n * Purely opacity-based, so it adapts automatically to any series color.\n */\nexport function buildSparkAreaGradient(hex: string): Record<string, unknown> {\n  const rgb = hexToRgb(hex);\n  return {\n    type: 'linear',\n    x: 0, y: 0, x2: 0, y2: 1,\n    colorStops: [\n      { offset: 0, color: `rgba(${rgb}, 0.35)` },\n      { offset: 1, color: `rgba(${rgb}, 0)` },\n    ],\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Palette resolution\n// ---------------------------------------------------------------------------\n//\n// Single, central entry point for \"given a list of names + chart options,\n// give me the colors to use\".  Adapters call this to obtain colors; they\n// are then free to attach the result to whichever ECharts option field\n// makes sense for their chart type.\n//\n// Resolution priority (highest first):\n//   1. options.colors[i]               -- positional override (must cover all names)\n//   2. options.colorMap[name]          -- per-name override\n//   3. configure({ consistentColors }) -- if true, ColorHub by name; else palette[i]\n//   4. fallback '#888888'              -- only inside resolveColorsForNodes\n//\n// `resolveColorsForNodes` adds one extra rule above (1): a node-level\n// `color` field always wins, so per-row data overrides can pin a single\n// node without affecting the rest.\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a color for each name using the active theme, `options.colors`,\n * `options.colorMap`, and `configure({ consistentColors })`.\n *\n * Returns an array of the same length as `names`. Returns an empty array\n * when `names` is empty (used by chart types without named series, e.g. gauge).\n */\nexport function resolveColors(\n  names: ReadonlyArray<string>,\n  options: ChartOptions,\n): string[] {\n  if (names.length === 0) return [];\n  syncColorHubTheme(resolveThemeName(options.theme));\n  const resolve = getConfig().consistentColors\n    ? resolveSeriesColors\n    : resolveColorsByPosition;\n  return resolve(names as string[], options.colors, options.colorMap);\n}\n\n/**\n * Resolve colors for graph nodes (sankey, chord, or any custom graph type).\n * Honors `node.color` first, then falls through to the same rules as\n * {@link resolveColors}. Always returns a non-empty hex string per node\n * (`'#888888'` as the final fallback when the palette is empty).\n */\nexport function resolveColorsForNodes(\n  nodes: ReadonlyArray<{ name: string; color?: string }>,\n  options: ChartOptions,\n): string[] {\n  const names = nodes.map((n) => n.name);\n  const palette = resolveColors(names, options);\n  return nodes.map(\n    (node, i) => node.color ?? palette[i] ?? palette[0] ?? '#888888',\n  );\n}\n","import type { ChartOptions } from '../../types.js';\nimport { DEFAULT_LABEL_FONT_SIZE } from './text-measure.js';\n\nconst FONT_FAMILY =\n  '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"PingFang SC\", ' +\n  '\"Microsoft YaHei\", \"Hiragino Sans GB\", \"Helvetica Neue\", Helvetica, Arial, sans-serif';\n\nexport { DEFAULT_LABEL_FONT_SIZE } from './text-measure.js';\n\nexport function getLabelFontSize(options: ChartOptions): number {\n  return options.labelFontSize ?? DEFAULT_LABEL_FONT_SIZE;\n}\n\nexport function getCommonDefaults(): Record<string, unknown> {\n  return {\n    textStyle: {\n      fontSize: 13,\n      fontFamily: FONT_FAMILY,\n    },\n    tooltip: {\n      padding: [6, 12],\n      textStyle: { fontWeight: 'normal' },\n      confine: true,\n    },\n    toolbox: { show: false },\n  };\n}\n","import type { ChartOptions, LegendOptions, TitleOptions } from '../../types.js';\n\n/**\n * Structural shape consumed by legend helpers.\n *\n * `legend` sits on chart-option subtypes that render a legend; this keeps\n * helper signatures concise without adding `legend` back to base ChartOptions.\n */\nexport type WithLegend = ChartOptions & { legend?: LegendOptions };\n\nexport interface EdgeReserves {\n  top: number;\n  bottom: number;\n  left: number;\n  right: number;\n}\n\nexport const EMPTY_EDGES: EdgeReserves = Object.freeze({\n  top: 0,\n  bottom: 0,\n  left: 0,\n  right: 0,\n});\n\nexport const CHART_DEFAULT_PADDING = 12;\nexport const LEGEND_ICON_WIDTH = 10;\nexport const LEGEND_ICON_HEIGHT = 10;\n\nexport const TITLE_DEFAULT_FONT_SIZE = 14;\nexport const TITLE_DEFAULT_PADDING = 8;\n/** Extra gap between the bottom of the title and the top of the plot area. */\nexport const TITLE_CHART_GAP = 8;\n\nexport function normalizeTitleOptions(title: string | TitleOptions): TitleOptions {\n  return typeof title === 'string' ? { text: title } : title;\n}\n\nexport function getChartPadding(options: ChartOptions): number {\n  return options.padding ?? CHART_DEFAULT_PADDING;\n}\n\nexport function getPositiveLegendSize(value: unknown): number | undefined {\n  return typeof value === 'number' && Number.isFinite(value) && value > 0\n    ? value\n    : undefined;\n}\n\n/**\n * Treat NaN/undefined as \"not set\" for axis min/max.\n */\nexport function isAxisBound(value: unknown): boolean {\n  if (value === undefined || value === null) return false;\n  if (typeof value === 'number') return Number.isFinite(value);\n  return typeof value === 'string' && value.length > 0;\n}\n","import type { ChartOptions } from '../../types.js';\nimport {\n  EMPTY_EDGES,\n  type EdgeReserves,\n  TITLE_CHART_GAP,\n  TITLE_DEFAULT_FONT_SIZE,\n  TITLE_DEFAULT_PADDING,\n  getChartPadding,\n  normalizeTitleOptions,\n} from './shared.js';\n\n/**\n * Vertical space (px) consumed by the title widget itself, or 0 if no title.\n */\nexport function getTitleHeight(options: ChartOptions): number {\n  if (!options.title) return 0;\n  const t = normalizeTitleOptions(options.title);\n  return (t.fontSize ?? TITLE_DEFAULT_FONT_SIZE) + (t.padding ?? TITLE_DEFAULT_PADDING) * 2 + TITLE_CHART_GAP;\n}\n\nexport function buildTitle(options: ChartOptions): Record<string, unknown> | undefined {\n  if (!options.title) return undefined;\n  const t = normalizeTitleOptions(options.title);\n  const fontSize = t.fontSize ?? TITLE_DEFAULT_FONT_SIZE;\n  const titlePadding = t.padding ?? TITLE_DEFAULT_PADDING;\n  const chartPadding = getChartPadding(options);\n\n  return {\n    text: t.text,\n    left: t.align ?? 'center',\n    top: chartPadding,\n    padding: [titlePadding, 0],\n    textStyle: { fontSize, fontWeight: 'normal' },\n  };\n}\n\nexport function getTitleReserve(options: ChartOptions): EdgeReserves {\n  const h = getTitleHeight(options);\n  if (h === 0) return { ...EMPTY_EDGES };\n  return { ...EMPTY_EDGES, top: h };\n}\n","import type {\n  RichTextInput,\n  RichTextSpec,\n  RichTextSegment,\n  RichTextStyle,\n} from '../../types.js';\nimport { DEFAULT_LABEL_FONT, measureMaxTextWidth } from './text-measure.js';\n\nexport interface CompiledRichText {\n  text: string;\n  plainText: string;\n  rich?: Record<string, RichTextStyle>;\n  measuredWidthPx?: number;\n}\n\nfunction isRichTextSpec(value: unknown): value is RichTextSpec {\n  if (typeof value !== 'object' || value === null) return false;\n  if (!('segments' in value)) return false;\n  return Array.isArray((value as { segments?: unknown }).segments);\n}\n\nfunction normalizeSegmentStyle(\n  segment: RichTextSegment,\n  styles?: Record<string, RichTextStyle>,\n): RichTextStyle | undefined {\n  const referenced =\n    typeof segment.style === 'string' ? styles?.[segment.style] : undefined;\n  const inline =\n    typeof segment.style === 'object' && segment.style !== null\n      ? segment.style\n      : undefined;\n\n  const out: RichTextStyle = {\n    ...(referenced ?? {}),\n    ...(inline ?? {}),\n  };\n  if (out.backgroundImage !== undefined) {\n    if (out.backgroundColor === undefined) {\n      out.backgroundColor = { image: out.backgroundImage } as Record<string, unknown>;\n    }\n    delete out.backgroundImage;\n  }\n  if (segment.width !== undefined) out.width = segment.width;\n  if (segment.align !== undefined) out.align = segment.align;\n  if (segment.verticalAlign !== undefined) out.verticalAlign = segment.verticalAlign;\n  if (Object.keys(out).length === 0) return undefined;\n\n  if (out.overflow === undefined) out.overflow = 'truncate';\n  if (out.ellipsis === undefined) out.ellipsis = '…';\n  return out;\n}\n\nfunction truncateLineToWidth(\n  line: string,\n  widthPx: number,\n  ellipsis: string,\n): string {\n  if (widthPx <= 0) return '';\n  if (measureMaxTextWidth([line], DEFAULT_LABEL_FONT) <= widthPx) return line;\n\n  let suffix = ellipsis;\n  if (suffix && measureMaxTextWidth([suffix], DEFAULT_LABEL_FONT) > widthPx) {\n    suffix = '';\n  }\n  const target = widthPx - measureMaxTextWidth([suffix], DEFAULT_LABEL_FONT);\n  if (target <= 0) return suffix;\n\n  let lo = 0;\n  let hi = line.length;\n  let best = '';\n  while (lo <= hi) {\n    const mid = Math.floor((lo + hi) / 2);\n    const candidate = line.slice(0, mid);\n    if (measureMaxTextWidth([candidate], DEFAULT_LABEL_FONT) <= target) {\n      best = candidate;\n      lo = mid + 1;\n    } else {\n      hi = mid - 1;\n    }\n  }\n  return `${best}${suffix}`;\n}\n\nfunction applySegmentOverflowDefaults(text: string, style?: RichTextStyle): string {\n  if (!style) return text;\n  if (style.overflow !== 'truncate') return text;\n  if (typeof style.width !== 'number' || !Number.isFinite(style.width)) return text;\n  const ellipsis = typeof style.ellipsis === 'string' ? style.ellipsis : '…';\n  return text\n    .split('\\n')\n    .map((line) => truncateLineToWidth(line, style.width as number, ellipsis))\n    .join('\\n');\n}\n\nfunction measureRichSpecWidth(spec: RichTextSpec): number {\n  const lineWidths = [0];\n  for (const segment of spec.segments) {\n    const style = normalizeSegmentStyle(segment, spec.styles);\n    const fixed =\n      typeof style?.width === 'number' && Number.isFinite(style.width)\n        ? style.width\n        : undefined;\n    const lines = segment.text.split('\\n');\n    lines.forEach((line, lineIndex) => {\n      const lineWidth =\n        fixed ?? measureMaxTextWidth([line], DEFAULT_LABEL_FONT);\n      if (lineIndex === 0) {\n        lineWidths[lineWidths.length - 1] += lineWidth;\n      } else {\n        lineWidths.push(lineWidth);\n      }\n    });\n  }\n  return Math.ceil(Math.max(...lineWidths, 0));\n}\n\nexport function compileRichText(\n  input: RichTextInput,\n  keyPrefix: string,\n): CompiledRichText {\n  if (typeof input === 'string') {\n    return {\n      text: input,\n      plainText: stripRichTextMarkup(input),\n    };\n  }\n\n  if (!isRichTextSpec(input) || input.segments.length === 0) {\n    return { text: '', plainText: '' };\n  }\n\n  const rich: Record<string, RichTextStyle> = {};\n  const tokens: string[] = [];\n  const plain: string[] = [];\n  input.segments.forEach((segment, segmentIndex) => {\n    const style = normalizeSegmentStyle(segment, input.styles);\n    const text = applySegmentOverflowDefaults(segment.text, style);\n    plain.push(text);\n    if (!style) {\n      tokens.push(text);\n      return;\n    }\n    const key = `__ich_${keyPrefix}_${segmentIndex}`;\n    rich[key] = style;\n    tokens.push(`{${key}|${text}}`);\n  });\n\n  return {\n    text: tokens.join(''),\n    plainText: plain.join(''),\n    rich: Object.keys(rich).length > 0 ? rich : undefined,\n    measuredWidthPx: measureRichSpecWidth(input),\n  };\n}\n\nexport function mergeCompiledRichStyles(\n  labels: ReadonlyArray<CompiledRichText>,\n): Record<string, RichTextStyle> {\n  const out: Record<string, RichTextStyle> = {};\n  for (const label of labels) {\n    if (!label.rich) continue;\n    Object.assign(out, label.rich);\n  }\n  return out;\n}\n\nexport function safeFormatLegendLabel(\n  formatLabel: (name: string, index: number) => RichTextInput,\n  name: string,\n  index: number,\n  keyPrefix: string,\n): CompiledRichText {\n  try {\n    const out = formatLabel(name, index);\n    if (typeof out === 'string' || isRichTextSpec(out)) {\n      return compileRichText(out, keyPrefix);\n    }\n    return compileRichText(name, keyPrefix);\n  } catch {\n    return compileRichText(name, keyPrefix);\n  }\n}\n\n/**\n * Defensive wrapper around `AxisOptions.formatLabel`.\n *\n * Mirrors {@link safeFormatLegendLabel} but accepts `string | number` values\n * (axis ticks). On throw or non-string / non-RichTextSpec return the entry\n * falls back to `String(value)` so a single bad lookup can't blank the whole\n * axis.\n */\nexport function safeFormatAxisLabel(\n  formatLabel: (value: string | number, index: number) => RichTextInput,\n  value: string | number,\n  index: number,\n  keyPrefix: string,\n): CompiledRichText {\n  try {\n    const out = formatLabel(value, index);\n    if (typeof out === 'string' || isRichTextSpec(out)) {\n      return compileRichText(out, keyPrefix);\n    }\n    return compileRichText(String(value), keyPrefix);\n  } catch {\n    return compileRichText(String(value), keyPrefix);\n  }\n}\n\nexport function stripRichTextMarkup(label: string): string {\n  if (!label.includes('{') || !label.includes('|')) return label;\n  return label.replace(/\\{[^|{}]+\\|/g, '').replace(/\\}/g, '');\n}\n\nexport function measureCompiledLabelWidth(label: CompiledRichText): number {\n  if (label.measuredWidthPx !== undefined) return label.measuredWidthPx;\n  return measureMaxTextWidth(label.plainText.split('\\n'), DEFAULT_LABEL_FONT);\n}\n","import type { LegendOptions } from '../../types.js';\nimport { DEFAULT_LABEL_FONT, measureMaxTextWidth } from './text-measure.js';\nimport { getTitleHeight } from './title.js';\nimport {\n  EMPTY_EDGES,\n  LEGEND_ICON_HEIGHT,\n  LEGEND_ICON_WIDTH,\n  type EdgeReserves,\n  type WithLegend,\n  getChartPadding,\n  getPositiveLegendSize,\n} from './shared.js';\nimport {\n  type CompiledRichText,\n  measureCompiledLabelWidth,\n  mergeCompiledRichStyles,\n  safeFormatLegendLabel,\n} from './rich-text.js';\n\nexport const LEGEND_RESERVE = 36;\n\nconst SIDE_LEGEND_NON_TEXT_PX = 26;\nconst SIDE_LEGEND_BODY_GAP = 8;\n\nexport function buildLegend(\n  names: string[],\n  options: WithLegend,\n): Record<string, unknown> {\n  const legend: LegendOptions = options.legend ?? {};\n  const show = legend.show ?? true;\n  const position = legend.position ?? 'bottom';\n  const p = getChartPadding(options);\n  const titleHeight = getTitleHeight(options);\n\n  const positionMap: Record<string, Record<string, unknown>> = {\n    top: { top: p + titleHeight, left: 'center', orient: 'horizontal' },\n    bottom: { bottom: p, left: 'center', orient: 'horizontal' },\n    left: { top: 'center', left: p, orient: 'vertical' },\n    right: { top: 'center', right: p, orient: 'vertical' },\n  };\n\n  const out: Record<string, unknown> = {\n    show,\n    type: legend.type ?? 'scroll',\n    data: names,\n    icon: 'roundRect',\n    itemWidth: LEGEND_ICON_WIDTH,\n    itemHeight: LEGEND_ICON_HEIGHT,\n    itemGap: 10,\n    pageButtonItemGap: 5,\n    pageButtonGap: 10,\n    pageIconSize: 12,\n    ...positionMap[position],\n  };\n  const legendHeight = getPositiveLegendSize(legend.height);\n  if (legendHeight !== undefined) out.height = legendHeight;\n  const legendWidth = getPositiveLegendSize(legend.width);\n  if (legendWidth !== undefined) out.width = legendWidth;\n\n  if (legend.formatLabel) {\n    const fn = legend.formatLabel;\n    const indexOf = new Map(names.map((n, i) => [n, i]));\n    const compiledByIndex = names.map((name, i) =>\n      safeFormatLegendLabel(fn, name, i, `legend_${i}`),\n    );\n    const rich = mergeCompiledRichStyles(compiledByIndex);\n    if (Object.keys(rich).length > 0) {\n      out.textStyle = { rich };\n    }\n    out.formatter = (name: string): string => {\n      const i = indexOf.get(name);\n      if (i === undefined) {\n        return safeFormatLegendLabel(fn, name, 0, 'legend_fallback').text;\n      }\n      return (compiledByIndex[i] as CompiledRichText).text;\n    };\n  }\n\n  return out;\n}\n\nexport function getLegendReserve(\n  options: WithLegend,\n  showLegend: boolean,\n  extraGap = 0,\n  names?: ReadonlyArray<string>,\n): EdgeReserves {\n  if (!showLegend) return { ...EMPTY_EDGES };\n  const position = options.legend?.position ?? 'bottom';\n  const isSide = position === 'left' || position === 'right';\n  const explicitHeight = getPositiveLegendSize(options.legend?.height);\n  const explicitWidth = getPositiveLegendSize(options.legend?.width);\n\n  let slot: number;\n  if (isSide && explicitWidth !== undefined) {\n    slot = explicitWidth + extraGap;\n  } else if (!isSide && explicitHeight !== undefined) {\n    slot = explicitHeight + extraGap;\n  } else if (isSide && names && names.length > 0) {\n    const fn = options.legend?.formatLabel;\n    const widest = fn\n      ? Math.max(\n        ...names.map((n, i) =>\n          measureCompiledLabelWidth(\n            safeFormatLegendLabel(fn, n, i, `legend_reserve_${i}`),\n          )),\n        0,\n      )\n      : measureMaxTextWidth(names, DEFAULT_LABEL_FONT);\n    slot =\n      Math.max(LEGEND_RESERVE, Math.ceil(widest) + SIDE_LEGEND_NON_TEXT_PX) + extraGap;\n  } else {\n    slot = LEGEND_RESERVE + extraGap;\n  }\n  if (isSide) slot += SIDE_LEGEND_BODY_GAP;\n\n  switch (position) {\n    case 'top':\n      return { ...EMPTY_EDGES, top: slot };\n    case 'bottom':\n      return { ...EMPTY_EDGES, bottom: slot };\n    case 'left':\n      return { ...EMPTY_EDGES, left: slot };\n    case 'right':\n      return { ...EMPTY_EDGES, right: slot };\n    default:\n      return { ...EMPTY_EDGES };\n  }\n}\n","import type { XYChartOptions, GridOptions } from '../../types.js';\nimport { deepMerge } from '../../utils.js';\nimport { getLegendReserve } from './legend.js';\nimport { getChartPadding } from './shared.js';\nimport { getTitleReserve } from './title.js';\n\nexport interface BuildGridOverrides {\n  legendShow?: boolean;\n  names?: ReadonlyArray<string>;\n}\n\nfunction getLegendGridAdjustment(\n  options: XYChartOptions,\n  legendShow?: boolean,\n  names?: ReadonlyArray<string>,\n): Record<string, unknown> {\n  const show = legendShow ?? options.legend?.show ?? true;\n  const reserves = getLegendReserve(options, show, 0, names);\n  const p = getChartPadding(options);\n  const titleTop = getTitleReserve(options).top;\n  const out: Record<string, unknown> = {};\n  const topReserve = titleTop + reserves.top;\n  if (topReserve > 0) out.top = p + topReserve;\n  if (reserves.bottom > 0) out.bottom = p + reserves.bottom;\n  if (reserves.left > 0) out.left = p + reserves.left;\n  if (reserves.right > 0) out.right = p + reserves.right;\n  return out;\n}\n\nexport function buildGrid(\n  options: XYChartOptions,\n  overrides?: BuildGridOverrides,\n): Record<string, unknown> {\n  const grid: GridOptions = options.grid ?? {};\n  const legendArea = getLegendGridAdjustment(\n    options,\n    overrides?.legendShow,\n    overrides?.names,\n  );\n  const p = getChartPadding(options);\n  return deepMerge(\n    {\n      show: true,\n      top: p,\n      left: p,\n      right: p,\n      bottom: p,\n      borderWidth: 0,\n      containLabel: true,\n    },\n    legendArea,\n    grid as Record<string, unknown>,\n  );\n}\n","export const STACKED_TEXT_DEFAULT_VISIBLE_GAP_PX = 12;\nexport const STACKED_TEXT_DEFAULT_GLYPH_PADDING_EM = 0.15;\n\nexport interface StackedTextOffsetsOptions {\n  primaryFontSize: number;\n  secondaryFontSize: number;\n  visibleGapPx?: number;\n  glyphPaddingEm?: number;\n  showSecondary?: boolean;\n}\n\nexport interface StackedTextOffsets {\n  primaryOffsetY: number;\n  secondaryOffsetY: number;\n}\n\nfunction roundHalfAwayFromZero1(n: number): number {\n  const sign = n < 0 ? -1 : 1;\n  return (sign * Math.round(Math.abs(n) * 10)) / 10;\n}\n\nexport function computeStackedTextOffsets(\n  opts: StackedTextOffsetsOptions,\n): StackedTextOffsets {\n  const {\n    primaryFontSize,\n    secondaryFontSize,\n    visibleGapPx = STACKED_TEXT_DEFAULT_VISIBLE_GAP_PX,\n    glyphPaddingEm = STACKED_TEXT_DEFAULT_GLYPH_PADDING_EM,\n    showSecondary = true,\n  } = opts;\n\n  const padding = glyphPaddingEm * (primaryFontSize + secondaryFontSize);\n  const emBoxGap = Math.max(0, visibleGapPx - padding);\n\n  const primaryOffsetY = showSecondary\n    ? roundHalfAwayFromZero1(-(emBoxGap + secondaryFontSize) / 2)\n    : 0;\n  const secondaryOffsetY = roundHalfAwayFromZero1(\n    (primaryFontSize + emBoxGap) / 2,\n  );\n\n  return { primaryOffsetY, secondaryOffsetY };\n}\n","/**\n * Format a Date using dayjs/Moment.js-compatible tokens:\n * YYYY, MM, DD, HH, mm, ss\n */\nexport function formatDateByPattern(date: Date, pattern: string): string {\n  const pad = (n: number) => String(n).padStart(2, '0');\n  return pattern\n    .replace('YYYY', String(date.getFullYear()))\n    .replace('YY', String(date.getFullYear()).slice(-2))\n    .replace('MM', pad(date.getMonth() + 1))\n    .replace('DD', pad(date.getDate()))\n    .replace('HH', pad(date.getHours()))\n    .replace('mm', pad(date.getMinutes()))\n    .replace('ss', pad(date.getSeconds()));\n}\n\nexport const DATE_STRING_RE =\n  /^\\d{4}[-/]\\d{1,2}([-/]\\d{1,2})?([T ]\\d{1,2}(:\\d{2}(:\\d{2})?)?)?Z?$/;\n","import type { AxisOptions, XYChartOptions, XYData } from '../../types.js';\nimport { formatDateByPattern, DATE_STRING_RE } from './date-utils.js';\nimport {\n  type CompiledRichText,\n  mergeCompiledRichStyles,\n  safeFormatAxisLabel,\n} from './rich-text.js';\nimport { isAxisBound } from './shared.js';\n\nexport function buildXAxis(\n  data: XYData,\n  options: XYChartOptions,\n  isTimeAxis: boolean,\n): Record<string, unknown>[] {\n  const userAxis: AxisOptions = options.xAxis ?? {};\n\n  const axis: Record<string, unknown> = {\n    type: isTimeAxis ? 'time' : 'category',\n    boundaryGap: !isTimeAxis,\n    splitLine: { show: false },\n    splitArea: { show: false },\n  };\n  if (userAxis.show !== undefined) {\n    axis.show = userAxis.show;\n  }\n\n  if (!isTimeAxis) {\n    axis.data = data.categories;\n  }\n\n  if (isAxisBound(userAxis.min)) axis.min = userAxis.min;\n  if (isAxisBound(userAxis.max)) axis.max = userAxis.max;\n\n  if (userAxis.name) {\n    axis.name = userAxis.name;\n    axis.nameLocation = 'center';\n    axis.nameGap = 30;\n  }\n\n  applyAxisLabel(\n    axis,\n    userAxis,\n    isTimeAxis,\n    isTimeAxis ? undefined : data.categories,\n    'xaxis',\n  );\n\n  if (isTimeAxis) {\n    const cursorFmt = userAxis.cursorFormat ?? userAxis.dateFormat;\n    if (cursorFmt) {\n      const fmt = cursorFmt;\n      axis.axisPointer = {\n        label: {\n          formatter: (params: { value: number }) =>\n            formatDateByPattern(new Date(params.value), fmt),\n        },\n      };\n    }\n  }\n\n  return [axis];\n}\n\n/**\n * Build the y-axis (or axes when `count > 1` for dual-axis charts).\n *\n * When `categoryValues` is supplied the **first** axis becomes a category\n * axis with `data: categoryValues` — used by horizontal-bar / bar-race for\n * the racer / category labels on the left edge. Without it the axes default\n * to `type: 'value'`. Per-axis `min` / `max` / `name` / `formatLabel` /\n * `show` are sourced from `options.yAxis` and applied to the first axis only\n * (axes 1+ get `alignTicks: true` and inherit the rest from ECharts).\n */\nexport function buildYAxis(\n  options: XYChartOptions,\n  count = 1,\n  categoryValues?: ReadonlyArray<string | number>,\n): Record<string, unknown>[] {\n  const userAxis: AxisOptions = options.yAxis ?? {};\n  const axes: Record<string, unknown>[] = [];\n  const isCategory = categoryValues !== undefined;\n\n  for (let i = 0; i < count; i++) {\n    const axis: Record<string, unknown> = {\n      type: isCategory && i === 0 ? 'category' : 'value',\n      splitArea: { show: false },\n      nameLocation: 'center',\n      nameGap: 60,\n    };\n    if (i === 0 && isCategory) {\n      axis.data = categoryValues;\n    }\n    if (i === 0 && userAxis.show !== undefined) {\n      axis.show = userAxis.show;\n    }\n\n    if (i === 0 && !isCategory && isAxisBound(userAxis.min)) axis.min = userAxis.min;\n    if (i === 0 && !isCategory && isAxisBound(userAxis.max)) axis.max = userAxis.max;\n\n    if (i === 0 && userAxis.name) {\n      axis.name = userAxis.name;\n    }\n\n    if (i === 0) {\n      applyAxisLabel(\n        axis,\n        userAxis,\n        false,\n        isCategory ? categoryValues : undefined,\n        'yaxis',\n      );\n    }\n\n    if (i > 0) {\n      axis.alignTicks = true;\n    }\n\n    axes.push(axis);\n  }\n\n  return axes;\n}\n\n/**\n * Wires `userAxis.formatLabel` (and time-axis `dateFormat`) into the given\n * ECharts axis literal.\n *\n * **RichTextSpec support is gated on knowing the tick set upfront.**\n * - `categoryValues` provided → pre-compile each value's `formatLabel` output\n *   so the per-segment styles can be merged into `axisLabel.rich`. ECharts\n *   only renders `{key|text}` markup when the matching key is registered,\n *   which is impossible at runtime (no setOption hook from the formatter).\n *   Pre-computing is the only reliable path.\n * - `categoryValues` omitted (value / time axis) → the user's function is\n *   still called per tick, but RichTextSpec returns are flattened to plain\n *   text (`compileRichText(...).plainText`). Plain string returns work\n *   everywhere. This is documented on `AxisOptions.formatLabel`.\n *\n * Falls back to a raw `dateFormat` formatter when no `formatLabel` is set\n * AND the axis is a time axis. Mutates `axis` in place; no return.\n *\n * Exposed so adapters that hand-author category-axis literals (bar race\n * y-axis, bar horizontal y-axis) can wire RichText support without\n * duplicating the compilation pipeline.\n */\nexport function applyAxisLabel(\n  axis: Record<string, unknown>,\n  userAxis: AxisOptions,\n  isTimeAxis: boolean,\n  categoryValues: ReadonlyArray<string | number> | undefined,\n  keyPrefix: string,\n): void {\n  const existing = (axis.axisLabel as Record<string, unknown> | undefined) ?? {};\n\n  if (userAxis.formatLabel) {\n    const fn = userAxis.formatLabel;\n    if (categoryValues !== undefined) {\n      const compiled: CompiledRichText[] = categoryValues.map((v, i) =>\n        safeFormatAxisLabel(fn, v, i, `${keyPrefix}_${i}`),\n      );\n      const rich = mergeCompiledRichStyles(compiled);\n      // Index by value (string-keyed since ECharts forwards the raw category\n      // value as `value`). Duplicate categories: keep the first index, like\n      // legend's safeFormatLegendLabel — same defensive contract.\n      const valueIndex = new Map<string, number>();\n      categoryValues.forEach((v, i) => {\n        const key = String(v);\n        if (!valueIndex.has(key)) valueIndex.set(key, i);\n      });\n      const richBlock =\n        Object.keys(rich).length > 0 ? { rich } : undefined;\n      axis.axisLabel = {\n        ...existing,\n        formatter: (value: string | number, idx: number): string => {\n          const i = valueIndex.get(String(value));\n          if (i !== undefined) return compiled[i].text;\n          return safeFormatAxisLabel(fn, value, idx, `${keyPrefix}_fallback`).text;\n        },\n        ...(richBlock ?? {}),\n      };\n      return;\n    }\n    axis.axisLabel = {\n      ...existing,\n      formatter: (value: string | number, idx: number): string =>\n        safeFormatAxisLabel(fn, value, idx, `${keyPrefix}_v`).plainText,\n    };\n    return;\n  }\n\n  if (isTimeAxis && userAxis.dateFormat) {\n    const fmt = userAxis.dateFormat;\n    axis.axisLabel = {\n      ...existing,\n      formatter: (value: number): string =>\n        formatDateByPattern(new Date(value), fmt),\n    };\n  }\n}\n\nexport function isTimeCategories(categories: (string | number)[]): boolean {\n  if (categories.length === 0) return false;\n  let hasRealTimestamp = false;\n  const everyValid = categories.every((v) => {\n    if (typeof v === 'number') {\n      if (v === 0) return true;\n      const abs = Math.abs(v);\n      if (abs < 1e8) return false;\n      if (abs >= 1e9) hasRealTimestamp = true;\n      return true;\n    }\n    if (typeof v === 'string') {\n      const ok = DATE_STRING_RE.test(v.trim());\n      if (ok) hasRealTimestamp = true;\n      return ok;\n    }\n    return false;\n  });\n  return everyValid && hasRealTimestamp;\n}\n","import type { CreateAsyncTooltipFormatterOptions } from './types.js';\n\n/**\n * Escape minimal HTML entities for safe inline text (errors, placeholders).\n */\nexport function escapeTooltipHtml(s: string): string {\n  return s\n    .replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;');\n}\n\n/**\n * Stable identity for an ECharts tooltip `params` payload. Used as the\n * default cache / dedupe key inside {@link createAsyncTooltipFormatter}.\n *\n * Two payload shapes ECharts emits:\n *\n *   - **Axis tooltips** (line / bar / area `trigger: 'axis'`): an array of\n *     series entries hovered at the same x-axis column. Keyed by the\n *     shared `axisValue`; falls back to `(seriesIndex, dataIndex)` pairs\n *     when `axisValue` is missing.\n *   - **Item / edge / node tooltips** (pie slice, sankey/chord node or\n *     link, network node, tree node — anything with `trigger: 'item'`):\n *     a single object. Keyed by `(dataType, seriesIndex, dataIndex, name)`.\n *\n * `dataType` is what lets sankey/chord/network distinguish a node hover\n * (`'node'`) from an edge hover (`'edge'`) — both share the same series\n * but resolve to different `customHtml` payloads, so the key has to\n * include it or the first one served would poison the cache.\n */\nfunction defaultTooltipCacheKey(params: unknown): string {\n  if (Array.isArray(params)) {\n    const first = params[0] as Record<string, unknown> | undefined;\n    if (first && first.axisValue !== undefined) {\n      return `axis:${String(first.axisValue)}`;\n    }\n    return (\n      'axis:' +\n      params\n        .map((p) => {\n          const r = p as Record<string, unknown> | undefined;\n          return `${String(r?.seriesIndex ?? '')}/${String(r?.dataIndex ?? '')}`;\n        })\n        .join(',')\n    );\n  }\n  const r = (params ?? {}) as Record<string, unknown>;\n  return [\n    'item',\n    String(r.dataType ?? ''),\n    String(r.seriesIndex ?? 0),\n    String(r.dataIndex ?? 0),\n    String(r.name ?? ''),\n  ].join('|');\n}\n\n/**\n * ECharts tooltip formatter callable + a `dismiss()` hook the engine wires\n * to ECharts' `hideTip` event. See {@link createAsyncTooltipFormatter} for\n * the full lifecycle rationale.\n */\nexport interface AsyncTooltipFormatter {\n  (\n    params: unknown,\n    asyncTicket: string,\n    callback?: (ticket: string, html: string | HTMLElement | HTMLElement[]) => void,\n  ): string;\n  /**\n   * Drop every cached and in-flight tooltip HTML this formatter holds. The\n   * engine wires this to ECharts' `hideTip` event so the cache only lives\n   * for a single tooltip session — the next hover always re-fetches fresh\n   * data, while rapid cursor motion within a single session still dedupes\n   * down to one `customHtml` call.\n   *\n   * Idempotent; safe to invoke when nothing is cached.\n   */\n  dismiss(): void;\n}\n\n/**\n * Build an ECharts tooltip `formatter` that shows synchronous HTML first, then\n * appends content from an async `customHtml` call. Works for **any** chart type:\n * pass your own `formatSync` (e.g. pie item, sankey link, or\n * {@link formatAxisTooltipSyncHtml} for axis charts) and use the same `params`\n * shape ECharts provides.\n *\n * Use with `ChartOptions.echarts.tooltip.formatter` when not using the built-in\n * `tooltip.customHtml` shortcut (axis line/bar/area only).\n *\n * **Cache lifecycle.** ECharts re-invokes the formatter on every mouse move\n * (not just when the hovered data point changes). To prevent `customHtml`\n * from firing — and the placeholder from flickering — on every pixel of\n * cursor motion, the formatter caches resolved HTML by a stable identity\n * derived from `params` (see {@link defaultTooltipCacheKey}). Concurrent\n * invocations for the same key share a single in-flight promise.\n *\n * The cache is cleared on:\n *   - **`hideTip`** — `IChart._apply()` registers a listener that calls\n *     `formatter.dismiss()`, so each new tooltip session re-fetches fresh\n *     data (cache only deduplicates *within* a session).\n *   - **Adapter re-resolve** — every `chart.update()` / `setTheme()` /\n *     `resize()` rebuilds the formatter closure with a fresh empty cache.\n *\n * Pass `cacheKey: false` in {@link CreateAsyncTooltipFormatterOptions} to\n * disable caching entirely when the async result genuinely varies across\n * mouse moves for the same data point.\n *\n * @example\n * ```ts\n * echarts: {\n *   tooltip: {\n *     trigger: 'item',\n *     formatter: createAsyncTooltipFormatter({\n *       formatSync: (p) => {\n *         const x = p as { name: string; value: number };\n *         return `${x.name}: <b>${x.value}</b>`;\n *       },\n *       customHtml: async (p) => {\n *         const x = p as { dataIndex: number };\n *         const r = await fetch(`/meta/${x.dataIndex}`);\n *         return (await r.json()).note;\n *       },\n *     }),\n *   },\n * }\n * ```\n */\nexport function createAsyncTooltipFormatter(\n  options: CreateAsyncTooltipFormatterOptions,\n): AsyncTooltipFormatter {\n  const placeholder = options.placeholder ?? 'Loading…';\n  const keyFn =\n    options.cacheKey === false ? null : options.cacheKey ?? defaultTooltipCacheKey;\n\n  // Per-formatter-instance state. Lives as long as the adapter-built option\n  // is held by ECharts — i.e. until the next `setOption` resolve in the\n  // adapter pipeline, which constructs a fresh formatter closure with a\n  // fresh cache. That self-clears stale data on chart updates.\n  const resolved = new Map<string, string>();\n  const inflight = new Map<string, Promise<string>>();\n  // Bumped on every `dismiss()`. Each in-flight `customHtml` task closes\n  // over the generation it started in and only commits its result to\n  // `resolved` if the generation hasn't advanced. Without this guard, a\n  // slow load that resolves AFTER the user leaves the chart would write\n  // its result back into the cache (post-`clear()`), and the next\n  // hover would serve that stale HTML instead of re-fetching.\n  let generation = 0;\n\n  const wrap = (syncHtml: string, extra: string): string => {\n    const extraTrim = extra.trim();\n    const syncTrim = syncHtml.trim();\n    if (!extraTrim) {\n      return syncTrim ? `<div style=\"line-height:1.55\">${syncTrim}</div>` : '';\n    }\n    if (!syncTrim) {\n      return `<div style=\"line-height:1.55\">${extraTrim}</div>`;\n    }\n    const fragment = `<div class=\"icharts-tooltip-extra\" style=\"margin-top:8px;padding-top:8px;border-top:1px solid rgba(128,128,128,.35);font-size:12px\">${extraTrim}</div>`;\n    return `<div style=\"line-height:1.55\">${syncTrim}${fragment}</div>`;\n  };\n\n  const wrapError = (syncHtml: string, e: unknown): string => {\n    const msg = e instanceof Error ? e.message : String(e);\n    return `<div style=\"line-height:1.55\">${syncHtml}<div style=\"color:#dc2626;font-size:12px;margin-top:6px\">${escapeTooltipHtml(msg)}</div></div>`;\n  };\n\n  const formatter = ((params, asyncTicket, callback) => {\n    const syncHtml = options.formatSync(params);\n    const key = keyFn ? keyFn(params) : null;\n\n    // Already resolved (success or error) for this slice/node/axis column —\n    // serve synchronously so ECharts doesn't repaint the placeholder.\n    if (key !== null) {\n      const cached = resolved.get(key);\n      if (cached !== undefined) {\n        return cached;\n      }\n    }\n\n    if (!callback) {\n      // No callback => ECharts won't accept an async result. Return the\n      // synchronous body and skip the load entirely. (This branch is also\n      // exercised by tests that invoke the formatter without ECharts.)\n      return syncHtml;\n    }\n\n    // Dedupe concurrent loads for the same key. The first hover starts the\n    // fetch; subsequent hovers (different mouse positions, same slice)\n    // attach their `callback` to the existing promise instead of firing\n    // a second request. Each invocation gets its own asyncTicket from\n    // ECharts, so we capture it in the local `then` closure.\n    let task = key !== null ? inflight.get(key) : undefined;\n    if (!task) {\n      // Invoke customHtml synchronously so dedupe is robust no matter how\n      // tightly the caller fires repeat invocations — `Promise.resolve(v)`\n      // evaluates v on the current tick.\n      const myGen = generation;\n      task = Promise.resolve(options.customHtml(params))\n        .then(\n          (extra) => wrap(syncHtml, extra),\n          (e: unknown) => wrapError(syncHtml, e),\n        )\n        .then((html) => {\n          // Discard the result if `dismiss()` fired while we were in\n          // flight — the user left the chart, the tooltip session ended,\n          // and the next hover should re-fetch fresh data rather than\n          // pick up this stale resolve.\n          if (key !== null && myGen === generation) {\n            resolved.set(key, html);\n            inflight.delete(key);\n          }\n          return html;\n        });\n      if (key !== null) {\n        inflight.set(key, task);\n      }\n    }\n\n    void task.then((html) => {\n      callback(asyncTicket, html);\n    });\n\n    return `<span style=\"opacity:.75\">${escapeTooltipHtml(placeholder)}</span>`;\n  }) as AsyncTooltipFormatter;\n\n  formatter.dismiss = (): void => {\n    generation += 1;\n    resolved.clear();\n    inflight.clear();\n  };\n\n  return formatter;\n}\n","import type {\n  ChartOptions,\n  TooltipContext,\n  TooltipContextAxis,\n  TooltipOptions,\n} from '../../types.js';\nimport { createAsyncTooltipFormatter } from '../../async-tooltip.js';\nimport type { AsyncTooltipFormatter } from '../../async-tooltip.js';\nimport type { RenderContext } from '../index.js';\nimport { formatDateByPattern } from './date-utils.js';\n\nexport function formatAxisTooltipSyncHtml(\n  params: unknown,\n  tooltip: TooltipOptions,\n  isTimeAxis: boolean,\n): string {\n  const items = Array.isArray(params) ? params : [params];\n  if (!items.length) return '';\n  const firstItem = items[0] as {\n    axisValue?: number | string;\n    value?: unknown;\n    seriesName?: string;\n    marker?: string;\n  };\n  const rawTs =\n    firstItem.axisValue ??\n    (Array.isArray(firstItem.value) ? (firstItem.value as [unknown, unknown])[0] : undefined);\n\n  let header: string;\n  if (isTimeAxis && tooltip.dateFormat && rawTs !== undefined) {\n    const ts = typeof rawTs === 'number' ? rawTs : Date.parse(String(rawTs));\n    header = !isNaN(ts) ? formatDateByPattern(new Date(ts), tooltip.dateFormat) : String(rawTs ?? '');\n  } else {\n    header = String(firstItem.axisValue ?? '');\n  }\n\n  const rows = items\n    .map((p: unknown) => {\n      const item = p as { marker?: string; seriesName?: string; value?: unknown };\n      const val = Array.isArray(item.value) ? (item.value as [unknown, unknown])[1] : item.value;\n      const displayVal = tooltip.formatValue\n        ? tooltip.formatValue(val as number, item.seriesName ?? '')\n        : val;\n      return `${item.marker ?? ''}${item.seriesName ?? ''}: ${displayVal}`;\n    })\n    .join('<br/>');\n  return `${header}<br/>${rows}`;\n}\n\nexport function buildAxisTooltipContext(\n  params: unknown,\n  tooltip: TooltipOptions,\n  isTimeAxis: boolean,\n): TooltipContextAxis {\n  const items = Array.isArray(params) ? params : [params];\n  const first = items[0] as {\n    axisValue?: number | string;\n    value?: unknown;\n    dataIndex?: number;\n  };\n  const rawTs =\n    first.axisValue ??\n    (Array.isArray(first.value) ? (first.value as [unknown, unknown])[0] : undefined);\n\n  let axisValueLabel: string;\n  if (isTimeAxis && tooltip.dateFormat && rawTs !== undefined) {\n    const ts = typeof rawTs === 'number' ? rawTs : Date.parse(String(rawTs));\n    axisValueLabel = !isNaN(ts)\n      ? formatDateByPattern(new Date(ts), tooltip.dateFormat)\n      : String(rawTs ?? '');\n  } else {\n    axisValueLabel = String(first.axisValue ?? '');\n  }\n\n  const series = items.map((p: unknown) => {\n    const item = p as {\n      marker?: string;\n      seriesName?: string;\n      value?: unknown;\n      color?: string;\n    };\n    const val = Array.isArray(item.value) ? (item.value as [unknown, unknown])[1] : item.value;\n    return {\n      name: item.seriesName ?? '',\n      value: val as number | string,\n      marker: item.marker,\n      color: typeof item.color === 'string' ? item.color : undefined,\n    };\n  });\n\n  return {\n    kind: 'axis',\n    axisValueLabel,\n    dataIndex: first.dataIndex ?? 0,\n    rawAxisValue: first.axisValue,\n    series,\n  };\n}\n\ninterface TooltipPositionSize {\n  contentSize: [number, number];\n  viewSize: [number, number];\n}\n\ntype TooltipPositionFn = (\n  point: [number, number],\n  params: unknown,\n  dom: unknown,\n  rect: unknown,\n  size: TooltipPositionSize,\n) => [number, number];\n\nexport function resolveTooltipPosition(\n  options: ChartOptions,\n): TooltipPositionFn | undefined {\n  const gap = options.tooltip?.cursorGap;\n  if (gap === undefined) return undefined;\n  return (point, _params, _dom, _rect, size) => {\n    const [px, py] = point;\n    const [w, h] = size.contentSize;\n    const [vw, vh] = size.viewSize;\n    let x = px + gap;\n    let y = py + gap;\n    if (x + w + 2 > vw) x = px - w - gap;\n    if (y + h > vh) y = py - h - gap;\n    return [x, y];\n  };\n}\n\nexport function resolveAppendToBody(\n  options: ChartOptions,\n  ctx?: RenderContext,\n): boolean {\n  const explicit = options.tooltip?.appendToBody;\n  if (explicit !== undefined) return explicit;\n  return !ctx?.inShadowDom;\n}\n\nconst SPARK_DEFAULT_CURSOR_GAP_PX = 6;\n\nexport function buildSparkTooltip(\n  options: ChartOptions = {},\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const sparkOptions: ChartOptions = {\n    ...options,\n    tooltip: {\n      cursorGap: SPARK_DEFAULT_CURSOR_GAP_PX,\n      ...options.tooltip,\n    },\n  };\n  return {\n    show: true,\n    trigger: 'axis',\n    axisPointer: { type: 'none' },\n    appendToBody: resolveAppendToBody(options, ctx),\n    position: resolveTooltipPosition(sparkOptions),\n  };\n}\n\nexport function buildTooltip(\n  options: ChartOptions,\n  trigger: 'axis' | 'item' = 'axis',\n  pointerType?: 'cross' | 'shadow' | 'line' | 'none',\n  isTimeAxis = false,\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const tooltip = options.tooltip ?? {};\n  const result: Record<string, unknown> = {\n    trigger,\n    padding: [6, 12],\n    textStyle: { fontWeight: 'normal' },\n    confine: true,\n    appendToBody: resolveAppendToBody(options, ctx),\n    position: resolveTooltipPosition(options),\n  };\n\n  if (pointerType) {\n    result.axisPointer = { type: pointerType };\n  }\n\n  if (tooltip.enabled === false) {\n    result.show = false;\n  }\n\n  if ((tooltip.customHtml || tooltip.appendHtml) && trigger === 'axis') {\n    const formatter = buildAsyncTooltipFormatter({\n      options,\n      defaultSync: (params) => formatAxisTooltipSyncHtml(params, tooltip, isTimeAxis),\n      toContext: (params) => buildAxisTooltipContext(params, tooltip, isTimeAxis),\n    });\n    if (formatter) {\n      result.formatter = formatter;\n      return result;\n    }\n  }\n\n  if (tooltip.formatValue) {\n    const fn = tooltip.formatValue;\n    result.valueFormatter = (value: number | string) =>\n      fn(value as number, '');\n  }\n\n  if (isTimeAxis && tooltip.dateFormat) {\n    result.formatter = (params: unknown) => formatAxisTooltipSyncHtml(params, tooltip, true);\n  }\n\n  return result;\n}\n\n/**\n * Compose `tooltip.customHtml` + `tooltip.appendHtml` into a single ECharts\n * tooltip formatter. Returns `undefined` when neither hook is set, so the\n * caller can fall back to its existing default-sync path (or let ECharts'\n * built-in tooltip render).\n *\n * Semantics (matches the doc on {@link TooltipOptions.customHtml} /\n * {@link TooltipOptions.appendHtml}):\n *\n *   - `customHtml` only — replaces the synchronous body. The default sync\n *     row is **not** rendered.\n *   - `appendHtml` only — keeps the default synchronous body and appends\n *     the user HTML below it (separator already supplied by\n *     {@link createAsyncTooltipFormatter}'s `wrap`).\n *   - both — `customHtml` provides the sync body (the built-in default is\n *     skipped), and `appendHtml`'s output is rendered below it inside the\n *     wrapper's `extra` slot, separated by a thin dashed rule.\n */\nexport function buildAsyncTooltipFormatter(opts: {\n  options: ChartOptions;\n  defaultSync: (params: unknown) => string;\n  toContext: (params: unknown) => TooltipContext;\n}): AsyncTooltipFormatter | undefined {\n  const tooltip = opts.options.tooltip ?? {};\n  const replaceFn = tooltip.customHtml;\n  const appendFn = tooltip.appendHtml;\n  if (!replaceFn && !appendFn) return undefined;\n\n  const APPEND_SEPARATOR =\n    '<div class=\"icharts-tooltip-append\" style=\"margin-top:6px;padding-top:6px;border-top:1px dashed rgba(128,128,128,.3)\">';\n\n  return createAsyncTooltipFormatter({\n    formatSync: replaceFn ? () => '' : opts.defaultSync,\n    customHtml: async (params) => {\n      const context = opts.toContext(params);\n      const replaceHtml = replaceFn ? await replaceFn(context) : '';\n      const appendHtml = appendFn ? await appendFn(context) : '';\n      const a = (replaceHtml ?? '').toString();\n      const b = (appendHtml ?? '').toString();\n      if (a && b) return `${a}${APPEND_SEPARATOR}${b}</div>`;\n      return a || b;\n    },\n    placeholder: tooltip.placeholder,\n  });\n}\n","/**\n * Apply a global font family to text-like ECharts option nodes.\n *\n * This is used by:\n * - `core.ts` before the main `setOption` call\n * - adapters that perform additional runtime `setOption(payload)` updates\n *   (e.g. pie's adaptive layout onInit path)\n */\nexport function applyConfiguredFontFamilyToOption(\n  option: unknown,\n  fontFamily?: string,\n): void {\n  const resolved = fontFamily?.trim();\n  if (!resolved || !option || typeof option !== 'object') return;\n\n  const root = option as Record<string, unknown>;\n  const rootTextStyle =\n    root.textStyle && typeof root.textStyle === 'object'\n      ? (root.textStyle as Record<string, unknown>)\n      : {};\n  root.textStyle = { ...rootTextStyle, fontFamily: resolved };\n\n  applyFontToTitleOrLegend(root, 'title', resolved);\n  applyFontToTitleOrLegend(root, 'legend', resolved);\n  applyFontToTextLikeNodes(root, resolved);\n}\n\nfunction applyFontToTitleOrLegend(\n  root: Record<string, unknown>,\n  key: 'title' | 'legend',\n  fontFamily: string,\n): void {\n  const target = root[key];\n  if (Array.isArray(target)) {\n    root[key] = target.map((item) => {\n      if (!item || typeof item !== 'object') return item;\n      const record = item as Record<string, unknown>;\n      const textStyle =\n        record.textStyle && typeof record.textStyle === 'object'\n          ? (record.textStyle as Record<string, unknown>)\n          : {};\n      return {\n        ...record,\n        textStyle: { ...textStyle, fontFamily },\n      };\n    });\n    return;\n  }\n\n  if (!target || typeof target !== 'object') return;\n  const record = target as Record<string, unknown>;\n  const textStyle =\n    record.textStyle && typeof record.textStyle === 'object'\n      ? (record.textStyle as Record<string, unknown>)\n      : {};\n  root[key] = {\n    ...record,\n    textStyle: { ...textStyle, fontFamily },\n  };\n}\n\nconst FONT_TARGET_KEYS = new Set([\n  'textStyle',\n  'style',\n  'label',\n  'endLabel',\n  'edgeLabel',\n  'axisLabel',\n  'axisName',\n  'nameTextStyle',\n  'upperLabel',\n  'detail',\n  'title',\n  'subtextStyle',\n]);\n\nfunction applyFontToTextLikeNodes(node: unknown, fontFamily: string): void {\n  if (!node || typeof node !== 'object') return;\n  if (Array.isArray(node)) {\n    for (const item of node) applyFontToTextLikeNodes(item, fontFamily);\n    return;\n  }\n\n  const record = node as Record<string, unknown>;\n  for (const [key, value] of Object.entries(record)) {\n    if (!value || typeof value !== 'object') continue;\n\n    if (FONT_TARGET_KEYS.has(key)) {\n      const target = value as Record<string, unknown>;\n      if (target.rich && typeof target.rich === 'object') {\n        const rich = target.rich as Record<string, unknown>;\n        for (const richKey of Object.keys(rich)) {\n          const richStyle = rich[richKey];\n          if (!richStyle || typeof richStyle !== 'object') continue;\n          rich[richKey] = {\n            ...(richStyle as Record<string, unknown>),\n            fontFamily,\n          };\n        }\n      }\n      const existingFontFamily = target.fontFamily;\n      if (\n        typeof existingFontFamily !== 'string' ||\n        existingFontFamily.trim().length === 0\n      ) {\n        target.fontFamily = fontFamily;\n      }\n    }\n\n    applyFontToTextLikeNodes(value, fontFamily);\n  }\n}\n","/**\n * Avatar / icon symbol helpers.\n *\n * The only consumer today is the tree adapter's `formatNodeIcon` path.\n * The helper pre-composites an avatar (contain-fit image inside a\n * shape clip + optional stroked border) onto an off-screen canvas,\n * then returns a `data:image/png;base64,…` URL.\n *\n * Why a data URL and not a canvas?\n *   ECharts only accepts a URL string after the `image://` prefix for\n *   its image symbol type. Handing back an `HTMLCanvasElement` invites\n *   callers to stuff it into `itemStyle.color: { image: canvas }`\n *   (pattern fill), which is the wrong tool for \"show this avatar\n *   inside a circle\": pattern fill is positioned in world coordinates\n *   (not shape-local) and doesn't do contain-style fitting, so the\n *   avatar appears cropped and mis-aligned. Returning the URL forces\n *   the only correct usage: `symbol: 'image://<dataUrl>'`.\n *\n * Why not just use ECharts' native `image://` symbol with\n * `itemStyle.borderColor` / `borderWidth`?\n *   ECharts image symbols don't paint `itemStyle.border*` — the image\n *   IS the symbol; there's no underlying shape geometry to stroke.\n *   For both shapes (circle clip + rect frame), the only reliable way\n *   to add a border around an image is to bake it into the bitmap\n *   ourselves. This helper does exactly that.\n */\n\nexport interface IconRenderOptions {\n  /** Avatar / icon image URL. Must be CORS-accessible (see notes below). */\n  src: string;\n  /**\n   * Output shape. `'circle'` clips the image to an inscribed circle and\n   * (when `borderWidth > 0`) strokes a ring along the inner edge.\n   * `'rect'` keeps the canvas's natural rectangular bounds and\n   * (when `borderWidth > 0`) strokes a rectangular frame.\n   */\n  shape: 'circle' | 'rect';\n  /** Output canvas width (px). The image is contain-fitted inside this. */\n  width: number;\n  /** Output canvas height (px). The image is contain-fitted inside this. */\n  height: number;\n  /**\n   * Stroke color for the surrounding ring/frame. Ignored when\n   * `borderWidth <= 0`.\n   */\n  borderColor: string;\n  /** Stroke width (px). Set to `0` to skip the border entirely. */\n  borderWidth: number;\n}\n\nconst dataUrlCache = new Map<string, Promise<string | undefined>>();\n\n/**\n * Resolve the device-pixel ratio we should bake into the bitmap. The\n * canvas is sized at `width * dpr × height * dpr` device pixels so\n * the encoded PNG carries enough detail for ECharts to sample 1:1\n * into its own HiDPI backing canvas — without this oversample, a\n * 36 px-wide avatar PNG gets *upsampled* by 2× / 3× on Retina / 4K\n * displays and reads as visibly blurry.\n *\n * Capped at 3× to bound memory: a 36 px avatar baked at DPR=4 would\n * be a 144×144 PNG (≈3 KB each, but ×N nodes adds up on dense trees),\n * and real-world DPR > 3 typically means the user is at heavy browser\n * zoom — at which point the source-image quality is the bottleneck,\n * not the avatar oversampling. DPR ≤ 1 returns 1 (no oversample).\n */\nfunction resolveDevicePixelRatio(): number {\n  if (typeof window === 'undefined') return 1;\n  const dpr = window.devicePixelRatio;\n  if (!Number.isFinite(dpr) || dpr <= 1) return 1;\n  return Math.min(dpr, 3);\n}\n\nfunction getCacheKey(opts: IconRenderOptions, dpr: number): string {\n  return [\n    opts.shape,\n    opts.src,\n    opts.width,\n    opts.height,\n    opts.borderColor,\n    opts.borderWidth,\n    // DPR is part of the key so a window dragged from a 2× Retina to\n    // a 1× external monitor (or vice versa) regenerates the bitmap at\n    // the new ratio instead of reusing a now-blurry / now-wasteful one.\n    dpr,\n  ].join('|');\n}\n\n/**\n * Pre-render an avatar bitmap and return it as a base64-encoded PNG\n * data URL. The bitmap has up to three baked-in features:\n *\n *   1. **Shape clip** — for `shape: 'circle'`, pixels outside the\n *      inscribed circle are transparent so the symbol reads as a\n *      round avatar. For `shape: 'rect'`, no clipping is applied\n *      (the canvas itself is rectangular).\n *   2. **Contain-style fit** — the source image is uniformly scaled\n *      down (never up) so the entire image fits inside the available\n *      area (canvas inset by `borderWidth` on every side) with\n *      letterboxing-equivalent transparency at the edges. The image\n *      is centered.\n *   3. **Stroked border** — when `borderWidth > 0`, a ring (circle)\n *      or frame (rect) of that thickness is stroked along the inner\n *      edge of the canvas in `borderColor`.\n *\n * Callers stitch the URL into ECharts via `symbol: 'image://<dataUrl>'`\n * so the avatar is drawn as a flat image symbol — no pattern-fill\n * quirks (which crop and mis-align under a circular shape), no\n * `itemStyle.borderRadius` (which has no effect on the built-in\n * `circle`/`rect` shape symbols anyway), and no double-render of\n * border or fill.\n *\n * **Returns `undefined`** when DOM/canvas are unavailable (SSR, vitest's\n * node environment, jsdom without 2D context), when the image fails to\n * load, or when the resulting canvas is CORS-tainted (the server didn't\n * send `Access-Control-Allow-Origin`, so `toDataURL` throws). Callers\n * fall back to their synchronous placeholder.\n *\n * **CORS note**: the image is fetched with `crossOrigin = 'anonymous'`\n * so the canvas stays untainted and `toDataURL` succeeds. Origins that\n * don't ship CORS headers will fail the load entirely — there is no\n * \"load image but skip toDataURL\" middle ground in the browser security\n * model. This is the correct trade-off: a load failure preserves the\n * synchronous placeholder, whereas a tainted canvas would throw\n * `SecurityError` on every render attempt.\n *\n * **Caching**: identical `(shape, src, width, height, borderColor,\n * borderWidth)` tuples share a single in-flight promise + cached data\n * URL, so re-renders / theme switches / chart re-creates don't re-fetch.\n */\nexport function renderIconDataUrl(\n  opts: IconRenderOptions,\n): Promise<string | undefined> {\n  const dpr = resolveDevicePixelRatio();\n  const key = getCacheKey(opts, dpr);\n  const cached = dataUrlCache.get(key);\n  if (cached) return cached;\n\n  const task = (async (): Promise<string | undefined> => {\n    if (typeof document === 'undefined' || typeof Image === 'undefined') {\n      return undefined;\n    }\n    const canvas = document.createElement('canvas');\n    if (!canvas) return undefined;\n    // Logical (CSS-pixel) dimensions — what the *content* is sized as.\n    // All geometry below (border, contain-fit math, circle radius,\n    // rect frame) operates in this coordinate space.\n    const W = Math.max(1, Math.round(opts.width));\n    const H = Math.max(1, Math.round(opts.height));\n    // Backing-store (device-pixel) dimensions — what the bitmap is\n    // *sampled at*. Oversampling by `dpr` is what makes the encoded\n    // PNG sharp on Retina / 4K: ECharts' own backing canvas runs at\n    // device pixels too, so a 2× / 3× source bitmap maps 1:1 instead\n    // of being upsampled at draw time.\n    canvas.width = Math.max(1, Math.round(W * dpr));\n    canvas.height = Math.max(1, Math.round(H * dpr));\n    const ctx = canvas.getContext('2d');\n    if (!ctx) return undefined;\n    // After this scale, every (x, y, w, h) we pass to the context is\n    // interpreted as logical pixels; the underlying transform takes\n    // care of mapping to device pixels. `lineWidth: border` strokes\n    // `border` *logical* pixels regardless of `dpr`, which is exactly\n    // what we want — a 2 px ring on a 1× monitor and a 2 px ring on\n    // Retina look identical to the user.\n    ctx.scale(dpr, dpr);\n    // Quality matters here: the typical case is a 256 px source image\n    // contain-fitted into a 36 px box, i.e. a ~7× downsample. The\n    // browser default ('low' on some engines) produces visibly aliased\n    // output for that ratio; `'high'` triggers a multi-tap filter that\n    // keeps facial features readable at avatar sizes.\n    ctx.imageSmoothingEnabled = true;\n    ctx.imageSmoothingQuality = 'high';\n\n    const img = new Image();\n    // Anonymous CORS so the canvas stays untainted; see CORS note above.\n    img.crossOrigin = 'anonymous';\n    const loaded = new Promise<boolean>((resolve) => {\n      img.onload = () => resolve(true);\n      img.onerror = () => resolve(false);\n    });\n    img.src = opts.src;\n    const ok = await loaded;\n    if (!ok || !img.naturalWidth || !img.naturalHeight) return undefined;\n\n    const border = Math.max(0, opts.borderWidth);\n    // Reserve `border` logical px on every edge for the stroke (so the\n    // border doesn't overlap the image content). For `border = 0` this\n    // is a no-op and the image fills the full canvas.\n    const innerW = Math.max(1, W - border * 2);\n    const innerH = Math.max(1, H - border * 2);\n    // Contain fit: uniform scale so the whole image fits, centered.\n    const scale = Math.min(innerW / img.naturalWidth, innerH / img.naturalHeight);\n    const drawW = Math.max(1, img.naturalWidth * scale);\n    const drawH = Math.max(1, img.naturalHeight * scale);\n    const drawX = (W - drawW) / 2;\n    const drawY = (H - drawH) / 2;\n\n    // Clear in logical coords — covers the full canvas because the\n    // CTM scale maps (0..W, 0..H) onto (0..W*dpr, 0..H*dpr) device px.\n    ctx.clearRect(0, 0, W, H);\n\n    if (opts.shape === 'circle') {\n      // Circular clip → contain-fit image inside the clip. The clip\n      // radius is `r - border` so the image never bleeds under the\n      // border ring (which would create a hairline of image pixels\n      // outside the stroked circle on sub-pixel rendering).\n      const r = Math.min(W, H) / 2;\n      const cx = W / 2;\n      const cy = H / 2;\n      ctx.save();\n      ctx.beginPath();\n      ctx.arc(cx, cy, Math.max(0, r - border), 0, Math.PI * 2);\n      ctx.closePath();\n      ctx.clip();\n      ctx.drawImage(img, drawX, drawY, drawW, drawH);\n      ctx.restore();\n\n      if (border > 0) {\n        // Stroke along the *inner* half of the border width — keeps\n        // the ring fully inside the canvas bounds. (Default canvas\n        // stroke straddles the path 50/50, so stroking at radius\n        // `r - border / 2` with thickness `border` leaves exactly\n        // half the stroke inside the canvas and half outside; we\n        // shift inward to avoid clipping.)\n        ctx.beginPath();\n        ctx.arc(cx, cy, Math.max(0.5, r - border / 2), 0, Math.PI * 2);\n        ctx.closePath();\n        ctx.strokeStyle = opts.borderColor;\n        ctx.lineWidth = border;\n        ctx.stroke();\n      }\n    } else {\n      // Rect: no clip needed (canvas IS rect). Draw the contain-fit\n      // image, then optionally stroke a rectangular frame inset by\n      // `border / 2` on every side so the stroke sits fully inside\n      // the canvas (same inner-half convention as the circle path).\n      ctx.drawImage(img, drawX, drawY, drawW, drawH);\n\n      if (border > 0) {\n        ctx.strokeStyle = opts.borderColor;\n        ctx.lineWidth = border;\n        ctx.strokeRect(\n          border / 2,\n          border / 2,\n          Math.max(1, W - border),\n          Math.max(1, H - border),\n        );\n      }\n    }\n\n    try {\n      return canvas.toDataURL('image/png');\n    } catch {\n      // Cross-origin image without CORS headers taints the canvas;\n      // `toDataURL` throws SecurityError. Surface as fallback so the\n      // synchronous placeholder stays visible.\n      return undefined;\n    }\n  })();\n\n  dataUrlCache.set(key, task);\n  return task;\n}\n","import type { RenderContext } from '../index.js';\nimport { DEFAULT_LABEL_FONT, measureMaxTextWidth } from './text-measure.js';\n\nconst RACE_FRAME_FALLBACK_MS = 500;\nconst RACE_FRAME_MIN_MS = 80;\nconst RACE_FRAME_MAX_MS = 3000;\n\nexport function resolveRaceFrameDuration(\n  explicit: number | undefined,\n  ctx: RenderContext | undefined,\n): number {\n  if (explicit !== undefined) return explicit;\n  const observed = ctx?.observedFrameMs;\n  if (observed !== undefined && Number.isFinite(observed)) {\n    return Math.max(RACE_FRAME_MIN_MS, Math.min(RACE_FRAME_MAX_MS, observed));\n  }\n  return RACE_FRAME_FALLBACK_MS;\n}\n\nconst RACE_LABEL_FONT = DEFAULT_LABEL_FONT;\nconst RACE_LABEL_GAP_PX = 8;\nconst RACE_LABEL_PAD_PX = 8;\nconst RACE_LABEL_MIN_PX = 32;\n\nexport function resolveRaceLabelHeadroom(\n  labels: ReadonlyArray<string>,\n  ctx: RenderContext | undefined,\n): number {\n  const widest = measureMaxTextWidth(labels, RACE_LABEL_FONT);\n  const suggested = Math.max(\n    RACE_LABEL_MIN_PX,\n    widest + RACE_LABEL_GAP_PX + RACE_LABEL_PAD_PX,\n  );\n  return Math.max(suggested, ctx?.maxRaceGridRight ?? 0);\n}\n","import type { XYData, XYChartOptions, SeriesOptions } from '../../types.js';\n\nexport function getSeriesOpts(name: string, options: XYChartOptions): SeriesOptions {\n  const wildcard = options.series?.['*'] ?? {};\n  const named = options.series?.[name] ?? {};\n  return { ...wildcard, ...named };\n}\n\nexport function getYAxisCount(data: XYData, options: XYChartOptions): number {\n  let count = 1;\n  if (options.series) {\n    for (const s of data.series) {\n      const so = getSeriesOpts(s.name, options);\n      if (so.yAxisIndex !== undefined && so.yAxisIndex + 1 > count) {\n        count = so.yAxisIndex + 1;\n      }\n    }\n  }\n  return count;\n}\n\nexport function applyMarkLines(series: Record<string, unknown>, so: SeriesOptions): void {\n  if (!so.markLines || so.markLines.length === 0) return;\n  series.markLine = {\n    symbol: ['none', 'none'],\n    data: so.markLines.map((type) => ({\n      type,\n      name: type.charAt(0).toUpperCase() + type.slice(1),\n      label: {\n        position: 'start',\n        align: 'right',\n        verticalAlign: 'middle',\n        distance: 8,\n      },\n    })),\n  };\n}\n\nexport function applyMarkPoints(series: Record<string, unknown>, so: SeriesOptions): void {\n  if (!so.markPoints || so.markPoints.length === 0) return;\n  series.markPoint = {\n    data: so.markPoints.map((type) => ({\n      type,\n      name: type.charAt(0).toUpperCase() + type.slice(1),\n    })),\n  };\n}\n","import type { LineData, AreaData, LineChartOptions, AreaChartOptions } from '../types.js';\nimport type { ChartSetupResult, RenderContext } from './index.js';\nimport { buildSparkAreaGradient, deepMerge, resolveColors } from '../utils.js';\nimport {\n  buildTitle,\n  buildLegend,\n  buildGrid,\n  buildXAxis,\n  buildYAxis,\n  buildTooltip,\n  buildSparkTooltip,\n  getLabelFontSize,\n  isTimeCategories,\n} from './common/index.js';\nimport { resolveRaceFrameDuration, resolveRaceLabelHeadroom } from './common/race-utils.js';\nimport { getSeriesOpts, getYAxisCount, applyMarkLines, applyMarkPoints } from './common/series-utils.js';\n\nexport function resolveLineOptions(\n  data: LineData,\n  options: LineChartOptions,\n  ctx?: RenderContext,\n): ChartSetupResult {\n  const variant = options.variant ?? 'default';\n\n  if (variant === 'race') {\n    return resolveLineRaceOptions(data, options, ctx);\n  }\n\n  // `dateFormat` is a strong opt-in: if the user is asking for date\n  // formatting, they want a time axis even when the heuristic would miss\n  // (e.g. category arrays that include the epoch `0`).\n  const isTime =\n    options.xAxis?.dateFormat !== undefined ||\n    isTimeCategories(data.categories);\n  const seriesNames = data.series.map((s) => s.name);\n  const isSpark = variant === 'spark';\n\n  const yAxisCount = getYAxisCount(data, options);\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    legend: isSpark\n      ? { show: false }\n      : buildLegend(seriesNames, options),\n    grid: isSpark\n      ? { top: 0, right: 0, bottom: 0, left: 0, containLabel: false }\n      : buildGrid(options, { names: seriesNames }),\n    xAxis: isSpark\n      ? [{ show: false, type: isTime ? 'time' : 'category', data: isTime ? undefined : data.categories, boundaryGap: false }]\n      : buildXAxis(data, options, isTime),\n    yAxis: isSpark\n      ? [{ show: false, type: 'value' }]\n      : buildYAxis(options, yAxisCount),\n    tooltip: isSpark\n      ? buildSparkTooltip(options, ctx)\n      : buildTooltip(options, 'axis', 'cross', isTime, ctx),\n    series: buildLineSeries(data, options, isTime, false),\n  };\n\n  const merged = deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n  merged.color = resolveColors(seriesNames, options);\n  return { option: merged };\n}\n\n// ---------------------------------------------------------------------------\n// Race variant\n// ---------------------------------------------------------------------------\n\n/**\n * The text painted by a line-race endLabel. Centralized so the adaptive\n * headroom calculation (which runs before ECharts paints anything) uses\n * the exact same string ECharts will eventually render — no risk of the\n * estimate diverging from the actual label width.\n *\n * Null/undefined values produce a trailing-space-free string so they\n * contribute their minimum width — matches what ECharts shows when a\n * series has no current value.\n */\nfunction formatRaceLineLabel(\n  seriesName: string,\n  value: number | string | null | undefined,\n): string {\n  if (value === null || value === undefined) return seriesName;\n  return `${seriesName} ${value}`;\n}\n\n/**\n * Builds an ECharts line-race option from a single frame of {@link LineData}.\n *\n * Per frame the caller provides:\n *   - `data.categories` — the x-axis points visible at the current frame\n *     (typically a growing list of time / step labels)\n *   - `data.series[i].name` — racer identity (must stay stable across frames;\n *     ECharts diffs series by name to animate the transition)\n *   - `data.series[i].data` — the trail of each racer up to the current frame\n *\n * Unlike bar race, lines aren't sorted — the visual race is the leading edge\n * of each line growing rightward. An animated end-label tracks each line's\n * latest value via `series.endLabel` + `valueAnimation`.\n *\n * The animation between frames is driven by the consumer calling\n * `chart.update(nextFrame)` on their own interval; we emit `notMerge: false`\n * so ECharts merges the new option into the previous one and animates the\n * value/position transitions.\n */\nfunction resolveLineRaceOptions(\n  data: LineData,\n  options: LineChartOptions,\n  ctx?: RenderContext,\n): ChartSetupResult {\n  const race = options.race ?? {};\n  // Auto-measured by default: matches the consumer's `chart.update()`\n  // cadence. Explicit `race.frameDuration` still wins.\n  const frameDuration = resolveRaceFrameDuration(race.frameDuration, ctx);\n  const showValueLabel = race.showValueLabel ?? true;\n\n  // Match the heuristic from the default path, with the same `dateFormat`\n  // opt-in. Race streams are the primary place users want to force a time\n  // axis (so existing points stay pinned across frames); honoring the\n  // explicit signal prevents the axis from flipping mid-stream when the\n  // category array briefly fails the digit-length heuristic (e.g. crosses\n  // the epoch `0`).\n  const isTime =\n    options.xAxis?.dateFormat !== undefined ||\n    isTimeCategories(data.categories);\n  const seriesNames = data.series.map((s) => s.name);\n  const yAxisCount = getYAxisCount(data, options);\n\n  // End labels are drawn just outside the right edge of each line and need\n  // grid headroom; otherwise they get clipped (same constraint as bar race\n  // value labels). Reserve space adaptively from the widest \"<name> <value>\"\n  // string in the current frame (canvas-measured when the DOM is available,\n  // char-count estimate otherwise). The engine's high-water mark\n  // (`ctx.maxRaceGridRight`) keeps the reserve monotonic across frames so\n  // value-digit flips don't jitter the plot area.\n  // Skip entirely when end labels are hidden — there's nothing to make\n  // room for.\n  const grid = buildGrid(options, { names: seriesNames });\n  if (options.grid?.right === undefined && showValueLabel) {\n    const labels = data.series.map((s) =>\n      formatRaceLineLabel(s.name, s.data[s.data.length - 1] as number | null | undefined),\n    );\n    grid.right = resolveRaceLabelHeadroom(labels, ctx);\n  }\n\n  const xAxis = buildXAxis(data, options, isTime);\n  // Streaming smoothness fix: on a time axis, pin the left edge of the\n  // domain to the first category. Without this, ECharts auto-fits min/max\n  // every frame, so existing points slide left as new ones arrive — the\n  // line looks like it's being compressed rather than extended. Pinning\n  // min keeps existing pixels stable. We only touch the leading edge;\n  // users wanting full-domain pinning (no right-edge drift either) should\n  // set `xAxis.max` explicitly — see README \"Line Race\".\n  //\n  // We check the BUILT axis (not raw user options) so this also kicks in\n  // when the user passed a bogus value (e.g. NaN) that buildXAxis stripped.\n  if (isTime && data.categories.length > 0) {\n    const first = xAxis[0] as Record<string, unknown>;\n    if (first.min === undefined) {\n      first.min = data.categories[0];\n    }\n  }\n\n  const labelFontSize = getLabelFontSize(options);\n  const series = buildLineSeries(data, options, isTime, false);\n  for (const s of series) {\n    s.showSymbol = false;\n    if (showValueLabel) {\n      s.endLabel = {\n        show: true,\n        valueAnimation: true,\n        // `ChartOptions.labelFontSize` — line-race tracking labels are\n        // canvas-rendered text, same contract as the non-race `showLabel`\n        // path inside `buildLineSeries` below.\n        fontSize: labelFontSize,\n        formatter: (params: { seriesName?: string; value?: unknown }) => {\n          const raw = params.value;\n          const v = Array.isArray(raw) ? raw[raw.length - 1] : raw;\n          return formatRaceLineLabel(\n            params.seriesName ?? '',\n            v as number | string | null | undefined,\n          );\n        },\n      };\n    }\n  }\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    legend: buildLegend(seriesNames, options),\n    grid,\n    xAxis,\n    yAxis: buildYAxis(options, yAxisCount),\n    tooltip: buildTooltip(options, 'axis', 'cross', isTime, ctx),\n    series,\n    animationDuration: 0,\n    animationDurationUpdate: frameDuration,\n    animationEasing: 'linear',\n    animationEasingUpdate: 'linear',\n  };\n\n  const merged = deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n  merged.color = resolveColors(seriesNames, options);\n  return { option: merged, notMerge: false };\n}\n\nexport function resolveAreaOptions(\n  data: AreaData,\n  options: AreaChartOptions,\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const isTime =\n    options.xAxis?.dateFormat !== undefined ||\n    isTimeCategories(data.categories);\n  const seriesNames = data.series.map((s) => s.name);\n  const variant = options.variant ?? 'default';\n  const isSpark = variant === 'spark';\n\n  const yAxisCount = getYAxisCount(data, options);\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    legend: isSpark\n      ? { show: false }\n      : buildLegend(seriesNames, options),\n    grid: isSpark\n      ? { top: 0, right: 0, bottom: 0, left: 0, containLabel: false }\n      : buildGrid(options, { names: seriesNames }),\n    xAxis: isSpark\n      ? [{ show: false, type: isTime ? 'time' : 'category', data: isTime ? undefined : data.categories, boundaryGap: false }]\n      : buildXAxis(data, options, isTime),\n    yAxis: isSpark\n      ? [{ show: false, type: 'value' }]\n      : buildYAxis(options, yAxisCount),\n    tooltip: isSpark\n      ? buildSparkTooltip(options, ctx)\n      : buildTooltip(options, 'axis', 'cross', isTime, ctx),\n    series: buildLineSeries(data, options, isTime, true),\n  };\n\n  const merged = deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n  const colors = resolveColors(seriesNames, options);\n  merged.color = colors;\n\n  // Spark area fill is a per-series gradient derived from each series color;\n  // the gradient lives on the series, so we apply it after merge to ensure\n  // user-provided `echarts.series` (if any) still receives the fill.\n  if (isSpark) {\n    applySparkAreaGradient(merged, colors);\n  }\n\n  return merged;\n}\n\nfunction applySparkAreaGradient(\n  option: Record<string, unknown>,\n  colors: ReadonlyArray<string>,\n): void {\n  const series = option.series as Record<string, unknown>[] | undefined;\n  if (!Array.isArray(series)) return;\n  series.forEach((s, i) => {\n    const hex = colors[i] ?? colors[0];\n    if (hex) s.areaStyle = { color: buildSparkAreaGradient(hex) };\n  });\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\nfunction buildLineSeries(\n  data: LineData,\n  options: LineChartOptions | AreaChartOptions,\n  isTime: boolean,\n  isArea: boolean,\n): Record<string, unknown>[] {\n  const isSpark = options.variant === 'spark';\n\n  return data.series.map((s) => {\n    const so = getSeriesOpts(s.name, options);\n\n    const seriesType = so.type ?? 'line';\n\n    const series: Record<string, unknown> = {\n      name: s.name,\n      type: seriesType,\n      data: isTime\n        ? s.data.map((v, i) => [data.categories[i], v])\n        : s.data,\n    };\n\n    if (seriesType === 'line') {\n      if (isTime) {\n        series.symbol = 'none';\n      }\n      if (isSpark) {\n        series.symbolSize = 0;\n      }\n\n      if (isArea) {\n        series.areaStyle = isSpark ? {} : { opacity: 0.8 };\n      }\n    }\n\n    if (options.stacked) {\n      series.stack = 'Total';\n    }\n\n    if (so.yAxisIndex !== undefined) series.yAxisIndex = so.yAxisIndex;\n\n    if (seriesType === 'line') {\n      if (so.smooth !== undefined) series.smooth = so.smooth;\n      if (so.showPoints !== undefined) series.showSymbol = so.showPoints;\n\n      if (so.lineWidth !== undefined) {\n        series.lineStyle = { width: so.lineWidth };\n      }\n      if (so.lineStyle) {\n        series.lineStyle = {\n          ...(series.lineStyle as Record<string, unknown> ?? {}),\n          type: so.lineStyle,\n        };\n      }\n    }\n\n    if (so.showLabel) {\n      series.label = {\n        show: true,\n        position: so.labelPosition ?? 'top',\n        fontSize: getLabelFontSize(options),\n      };\n    }\n\n    applyMarkLines(series, so);\n    applyMarkPoints(series, so);\n\n    return series;\n  });\n}\n","import type { BarData, BarChartOptions } from '../types.js';\nimport type { ChartSetupResult, RenderContext } from './index.js';\nimport { deepMerge, resolveColors } from '../utils.js';\nimport { resolveRaceFrameDuration, resolveRaceLabelHeadroom } from './common/race-utils.js';\nimport {\n  applyAxisLabel,\n  buildTitle,\n  buildLegend,\n  buildGrid,\n  buildXAxis,\n  buildTooltip,\n  buildSparkTooltip,\n  getLabelFontSize,\n  isTimeCategories,\n} from './common/index.js';\nimport { getSeriesOpts, applyMarkLines, applyMarkPoints } from './common/series-utils.js';\n\nexport function resolveBarOptions(\n  data: BarData,\n  options: BarChartOptions,\n  ctx?: RenderContext,\n): ChartSetupResult {\n  const variant = options.variant ?? 'default';\n\n  if (variant === 'race') {\n    return resolveBarRaceOptions(data, options, ctx);\n  }\n\n  const isTime = isTimeCategories(data.categories);\n  const seriesNames = data.series.map((s) => s.name);\n  const isSpark = variant === 'spark';\n  const isHorizontal = variant === 'horizontal';\n\n  // colorByCategory paints every bar with its own palette color (resolved\n  // from the category name via the same colorMap → theme pipeline used\n  // elsewhere). It only makes visual sense for a single-series, non-stacked\n  // chart — silently ignore otherwise.\n  const enableColorByCategory =\n    options.colorByCategory === true &&\n    !options.stacked &&\n    data.series.length === 1;\n\n  const baseLegend = isSpark ? { show: false } : buildLegend(seriesNames, options);\n  const legendVisible =\n    !isSpark && !enableColorByCategory && (options.legend?.show ?? true);\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    legend: enableColorByCategory ? { show: false } : baseLegend,\n    grid: isSpark\n      ? { top: 0, right: 0, bottom: 0, left: 0, containLabel: false }\n      : buildGrid(options, { legendShow: legendVisible, names: seriesNames }),\n    tooltip: isSpark\n      ? buildSparkTooltip(options, ctx)\n      : buildTooltip(options, 'axis', 'shadow', isTime, ctx),\n  };\n\n  // Categories laid out left→right normally, top→bottom when horizontal.\n  // Reversing for horizontal flips ECharts' default ascending y-axis so the\n  // first category sits at the top — matches the visual order users expect.\n  const horizontalCategories = isHorizontal\n    ? [...data.categories].reverse()\n    : data.categories;\n\n  const categoryAxis: Record<string, unknown> = {\n    type: 'category',\n    data: horizontalCategories,\n    boundaryGap: true,\n    splitLine: { show: false },\n    splitArea: { show: false },\n  };\n\n  const valueAxis: Record<string, unknown> = {\n    type: 'value',\n    splitArea: { show: false },\n  };\n\n  if (isSpark) {\n    eOption.xAxis = [{ show: false, ...categoryAxis }];\n    eOption.yAxis = [{ show: false, ...valueAxis }];\n  } else if (isHorizontal) {\n    // Horizontal: y-axis is the category axis. Wire `options.yAxis.formatLabel`\n    // (with rich-text support pre-compiled from the reversed category list).\n    applyAxisLabel(\n      categoryAxis,\n      options.yAxis ?? {},\n      false,\n      horizontalCategories,\n      'yaxis_horizontal',\n    );\n    eOption.yAxis = [categoryAxis];\n    eOption.xAxis = [valueAxis];\n  } else {\n    if (isTime) {\n      eOption.xAxis = buildXAxis(data, options, true);\n    } else {\n      // Vertical category x-axis: same RichText-aware wiring as buildXAxis,\n      // applied directly to the literal so the rest of the literal's defaults\n      // (boundaryGap, splitLine, splitArea) don't drift from sibling charts.\n      applyAxisLabel(\n        categoryAxis,\n        options.xAxis ?? {},\n        false,\n        data.categories,\n        'xaxis_bar',\n      );\n      eOption.xAxis = [categoryAxis];\n    }\n    eOption.yAxis = [valueAxis];\n  }\n\n  const series = buildBarSeries(data, options, isTime, isHorizontal, enableColorByCategory);\n  eOption.series = series;\n\n  const merged = deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n  // Palette source switches based on colorByCategory: when enabled, derive\n  // colors from category names (so ECharts colorBy:'data' picks per-bar\n  // colors); otherwise use series names (one color per series).\n  // Horizontal bars reverse category data — palette order must match.\n  const categoryNames = data.categories.map(String);\n  const namesForPalette =\n    enableColorByCategory && isHorizontal\n      ? [...categoryNames].reverse()\n      : categoryNames;\n  merged.color = enableColorByCategory\n    ? resolveColors(namesForPalette, options)\n    : resolveColors(seriesNames, options);\n  return { option: merged };\n}\n\n// ---------------------------------------------------------------------------\n// Race variant\n// ---------------------------------------------------------------------------\n\n/**\n * Builds an ECharts bar-race option from a single frame of {@link XYData}.\n *\n * Per frame the caller provides:\n *   - `data.categories` — racer names (stable across frames; defines bar identity)\n *   - `data.series[0].data` — values for those racers at the current frame\n *\n * Additional series are ignored — bar race shows a single ranked metric.\n * The animation between frames is driven by the consumer calling\n * `chart.update(nextFrame)` on their own interval; we emit `notMerge: false`\n * so ECharts merges the new option into the previous one and animates the\n * value/position transitions.\n */\nfunction resolveBarRaceOptions(\n  data: BarData,\n  options: BarChartOptions,\n  ctx?: RenderContext,\n): ChartSetupResult {\n  const race = options.race ?? {};\n  // Auto-measured by default: matches the consumer's `chart.update()`\n  // cadence. Explicit `race.frameDuration` still wins.\n  const frameDuration = resolveRaceFrameDuration(race.frameDuration, ctx);\n  const showValueLabel = race.showValueLabel ?? true;\n  const xAxisShow = options.xAxis?.show;\n  const yAxisShow = options.yAxis?.show;\n  const firstSeries = data.series[0] ?? { name: '', data: [] };\n  const seriesName = firstSeries.name;\n\n  // Race is always single-series, so no extra guards needed beyond reading\n  // the flag — the stacked / multi-series checks from the non-race path\n  // don't apply here.\n  const enableColorByCategory = options.colorByCategory === true;\n  const legendVisible = !enableColorByCategory && (options.legend?.show ?? true);\n\n  // Race labels sit *outside* the right end of each bar (position: 'right' +\n  // valueAnimation). The default grid only reserves `padding` (≈12px) on the\n  // right which clips the digits. Reserve label headroom adaptively from\n  // the current frame's widest value string (canvas-measured when the DOM is\n  // available, char-count estimate otherwise), and let the engine's\n  // high-water mark (`ctx.maxRaceGridRight`) keep the reserve monotonic\n  // across frames so digit flips don't jitter the plot area.\n  // Skip entirely when labels are hidden — there's nothing to make room for.\n  //\n  // Race shows a single series; the legend (if shown) renders that one\n  // entry. Forward the name so a side-edge legend gets a width-based slot.\n  const grid = buildGrid(options, {\n    legendShow: legendVisible,\n    names: seriesName ? [seriesName] : undefined,\n  });\n  if (options.grid?.show === undefined) {\n    grid.show = false;\n  }\n  if (options.grid?.right === undefined && showValueLabel) {\n    grid.right = resolveRaceLabelHeadroom(\n      firstSeries.data.map(formatRaceBarLabel),\n      ctx,\n    );\n  }\n\n  const raceSeries: Record<string, unknown> = {\n    name: seriesName,\n    type: 'bar',\n    // Raw numbers only — per-bar `{ value, itemStyle }` objects break the\n    // smooth value transition between consecutive `setOption` calls.\n    data: firstSeries.data,\n    realtimeSort: true,\n    label: {\n      show: showValueLabel,\n      position: 'right',\n      valueAnimation: true,\n      // `ChartOptions.labelFontSize` — race value label is canvas-\n      // rendered text, so it must follow the same global knob as the\n      // non-race `showLabel` path below.\n      fontSize: getLabelFontSize(options),\n    },\n    itemStyle: { borderRadius: [0, 4, 4, 0] },\n  };\n\n  applyBarOptionsSizing(raceSeries, options);\n\n  if (enableColorByCategory) {\n    raceSeries.colorBy = 'data';\n  }\n\n  const yAxisLiteral: Record<string, unknown> = {\n    type: 'category',\n    data: data.categories,\n    inverse: true,\n    // Keep racer labels visible while removing the axis chrome.\n    axisLine: { show: false },\n    axisTick: { show: false },\n    splitLine: { show: false },\n    splitArea: { show: false },\n    animationDuration: 300,\n    animationDurationUpdate: 300,\n    ...(yAxisShow !== undefined ? { show: yAxisShow } : {}),\n    // `max` controls how many bars fit in the viewport. ECharts wants the\n    // last *visible* index, so topN=10 → max=9. Omit when unset to show all.\n    ...(race.topN !== undefined ? { max: race.topN - 1 } : {}),\n  };\n  // Wire `options.yAxis.formatLabel` with full rich-text support (categories\n  // are stable across frames so the per-segment style map can be pre-\n  // compiled and registered on `axisLabel.rich`). Common use case: prefix\n  // each racer label with a flag / avatar / status icon.\n  applyAxisLabel(\n    yAxisLiteral,\n    options.yAxis ?? {},\n    false,\n    data.categories,\n    'yaxis_race',\n  );\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    legend: enableColorByCategory ? { show: false } : buildLegend([seriesName], options),\n    grid,\n    tooltip: buildTooltip(options, 'axis', 'shadow', false, ctx),\n    xAxis: {\n      type: 'value',\n      max: 'dataMax',\n      splitLine: { show: false },\n      splitArea: { show: false },\n      ...(xAxisShow !== undefined ? { show: xAxisShow } : {}),\n    },\n    yAxis: yAxisLiteral,\n    series: [raceSeries],\n    animationDuration: 0,\n    animationDurationUpdate: frameDuration,\n    animationEasing: 'linear',\n    animationEasingUpdate: 'linear',\n  };\n\n  const merged = deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n  merged.color = enableColorByCategory\n    ? resolveColors(data.categories.map(String), options)\n    : resolveColors([seriesName], options);\n  return { option: merged, notMerge: false };\n}\n\n/**\n * Mirrors the default text ECharts paints for a bar-race value label\n * (`label.valueAnimation: true` without a custom formatter). We use it\n * to drive the adaptive headroom calculation without having to wait for\n * ECharts to render and measure.\n *\n * Null/undefined values produce an empty string so they contribute zero\n * width — matching ECharts' own behavior of skipping the label.\n */\nfunction formatRaceBarLabel(v: number | null | undefined): string {\n  return v === null || v === undefined ? '' : String(v);\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\nfunction buildBarSeries(\n  data: BarData,\n  options: BarChartOptions,\n  isTime: boolean,\n  isHorizontal: boolean,\n  enableColorByCategory: boolean,\n): Record<string, unknown>[] {\n  const variant = options.variant ?? 'default';\n  const isSpark = variant === 'spark';\n\n  const rawSeries = data.series.map((s) => {\n    const so = getSeriesOpts(s.name, options);\n\n    const seriesData = isHorizontal ? [...s.data].reverse() : s.data;\n\n    const series: Record<string, unknown> = {\n      name: s.name,\n      type: 'bar',\n      data: isTime\n        ? s.data.map((v, i) => [data.categories[i], v])\n        : seriesData,\n    };\n\n    if (isSpark) {\n      series.symbolSize = 0;\n    }\n\n    if (options.stacked) {\n      series.stack = 'Total';\n    }\n\n    if (so.yAxisIndex !== undefined) series.yAxisIndex = so.yAxisIndex;\n\n    if (so.showLabel) {\n      series.label = {\n        show: true,\n        position: so.labelPosition ?? 'outside',\n        fontSize: getLabelFontSize(options),\n      };\n    }\n\n    applyMarkLines(series, so);\n    applyMarkPoints(series, so);\n\n    applyBarOptionsSizing(series, options);\n\n    if (enableColorByCategory) {\n      series.colorBy = 'data';\n    }\n\n    return series;\n  });\n\n  if (options.stacked) {\n    applyStackedRadius(rawSeries, isHorizontal);\n  } else {\n    applyNonStackedRadius(rawSeries, isHorizontal);\n  }\n\n  return rawSeries;\n}\n\n/**\n * Propagates the bar-sizing fields from {@link BarChartOptions} into a single\n * ECharts series object. Shared by every bar variant (default, horizontal,\n * spark, race) so authors get a consistent API.\n */\nfunction applyBarOptionsSizing(\n  series: Record<string, unknown>,\n  options: BarChartOptions,\n): void {\n  if (options.barWidth !== undefined) series.barWidth = options.barWidth;\n  if (options.barMaxWidth !== undefined) series.barMaxWidth = options.barMaxWidth;\n  if (options.barMinWidth !== undefined) series.barMinWidth = options.barMinWidth;\n  if (options.barGap !== undefined) series.barGap = options.barGap;\n  if (options.barCategoryGap !== undefined) series.barCategoryGap = options.barCategoryGap;\n}\n\nfunction applyNonStackedRadius(\n  series: Record<string, unknown>[],\n  isHorizontal: boolean,\n): void {\n  const radius = isHorizontal ? [0, 4, 4, 0] : [4, 4, 0, 0];\n  for (const s of series) {\n    const data = s.data as unknown[];\n    s.data = data.map((v) => ({\n      value: v,\n      itemStyle: { borderRadius: radius },\n    }));\n  }\n}\n\nfunction applyStackedRadius(\n  series: Record<string, unknown>[],\n  isHorizontal: boolean,\n): void {\n  if (series.length === 0) return;\n  const dataLength = (series[0].data as unknown[]).length;\n\n  const stackEnd: number[] = new Array(dataLength).fill(-1);\n\n  for (let dataIdx = 0; dataIdx < dataLength; dataIdx++) {\n    for (let seriesIdx = series.length - 1; seriesIdx >= 0; seriesIdx--) {\n      const val = (series[seriesIdx].data as unknown[])[dataIdx];\n      if (val !== undefined && val !== null && val !== '-') {\n        stackEnd[dataIdx] = seriesIdx;\n        break;\n      }\n    }\n  }\n\n  for (let seriesIdx = 0; seriesIdx < series.length; seriesIdx++) {\n    const data = series[seriesIdx].data as unknown[];\n    series[seriesIdx].data = data.map((v, dataIdx) => {\n      const isTop = stackEnd[dataIdx] === seriesIdx;\n      const topR = isTop ? 4 : 0;\n      return {\n        value: v,\n        itemStyle: {\n          borderRadius: isHorizontal\n            ? [0, topR, topR, 0]\n            : [topR, topR, 0, 0],\n        },\n      };\n    });\n  }\n}\n","import type {\n  MapChartOptions,\n  MapData,\n  TooltipContextItem,\n} from '../types.js';\nimport type { RenderContext } from './index.js';\nimport { deepMerge, resolveColors, hexToRgb } from '../utils.js';\nimport { getThemeColors } from '../themes/index.js';\nimport {\n  buildTitle,\n  buildAsyncTooltipFormatter,\n  getLabelFontSize,\n  resolveAppendToBody,\n  resolveTooltipPosition,\n} from './common/index.js';\n\nfunction normalizeMapValue(\n  value: unknown,\n): number | string | '' {\n  if (typeof value === 'number') {\n    return Number.isFinite(value) ? value : '';\n  }\n  if (typeof value === 'string') {\n    return value;\n  }\n  return '';\n}\n\nfunction parseRgbTuple(color: string): [number, number, number] | undefined {\n  if (color.startsWith('#')) {\n    const rgb = hexToRgb(color).split(',').map((x) => Number(x.trim()));\n    if (rgb.length === 3 && rgb.every((n) => Number.isFinite(n))) {\n      return [rgb[0], rgb[1], rgb[2]];\n    }\n    return undefined;\n  }\n  const m = color.match(/rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i);\n  if (!m) return undefined;\n  return [Number(m[1]), Number(m[2]), Number(m[3])];\n}\n\nfunction blendRgb(\n  foreground: [number, number, number],\n  background: [number, number, number],\n  foregroundRatio: number,\n): [number, number, number] {\n  const r = Math.round(foreground[0] * foregroundRatio + background[0] * (1 - foregroundRatio));\n  const g = Math.round(foreground[1] * foregroundRatio + background[1] * (1 - foregroundRatio));\n  const b = Math.round(foreground[2] * foregroundRatio + background[2] * (1 - foregroundRatio));\n  return [r, g, b];\n}\n\nfunction mapParamsToTooltipContext(params: unknown): TooltipContextItem {\n  const pr = params as Record<string, unknown>;\n  const value = normalizeMapValue(pr.value);\n  return {\n    kind: 'item',\n    dataIndex: typeof pr.dataIndex === 'number' ? pr.dataIndex : 0,\n    name: String(pr.name ?? ''),\n    value,\n    marker: typeof pr.marker === 'string' ? pr.marker : undefined,\n    color: typeof pr.color === 'string' ? pr.color : undefined,\n  };\n}\n\nfunction mapTooltipSyncHtml(\n  params: unknown,\n  options: MapChartOptions,\n): string {\n  const pr = params as Record<string, unknown>;\n  const marker = (pr.marker as string) ?? '';\n  const name = String(pr.name ?? '');\n  const value = normalizeMapValue(pr.value);\n  if (value === '') {\n    return `${marker}${name}`;\n  }\n  const fmt = options.tooltip?.formatValue;\n  const display = fmt ? fmt(value, name) : String(value);\n  return `${marker}${name}: ${display}`;\n}\n\nfunction resolveVisualMap(\n  data: MapData,\n  options: MapChartOptions,\n): Record<string, unknown> | undefined {\n  const cfg = options.visualMap;\n  if (cfg?.show === false) return undefined;\n\n  const numericValues = data\n    .map((d) => d.value)\n    .filter((v): v is number => Number.isFinite(v));\n  // Auto-enable visualMap when the dataset has numeric values, even if the\n  // caller only provides required map options (`mapName`).\n  if (!cfg && numericValues.length === 0) return undefined;\n\n  const minValue = numericValues.length > 0 ? Math.min(...numericValues) : 0;\n  const maxValue = numericValues.length > 0 ? Math.max(...numericValues) : 0;\n  const defaultBaseColor = resolveColors(['__map_visual__'], options)[0];\n  const surface = getThemeColors()?.surface ?? '#ffffff';\n  const baseRgb = parseRgbTuple(defaultBaseColor);\n  const surfaceRgb = parseRgbTuple(surface);\n  const lowColor = baseRgb && surfaceRgb\n    ? (() => {\n        const [r, g, b] = blendRgb(baseRgb, surfaceRgb, 0.2);\n        return `rgb(${r}, ${g}, ${b})`;\n      })()\n    : `rgba(${hexToRgb(defaultBaseColor)}, 0.2)`;\n  const highColor = baseRgb\n    ? `rgb(${baseRgb[0]}, ${baseRgb[1]}, ${baseRgb[2]})`\n    : defaultBaseColor;\n  const inRangeColors = options.visualMap?.inRangeColors ?? [\n    lowColor,\n    highColor,\n  ];\n\n  const resolvedMin = cfg?.min ?? minValue;\n  const resolvedMax = cfg?.max ?? maxValue;\n  const out: Record<string, unknown> = {\n    show: cfg?.show ?? true,\n    min: resolvedMin,\n    max: resolvedMax,\n    orient: cfg?.orient ?? 'vertical',\n    left: cfg?.left ?? 'right',\n    bottom: cfg?.bottom ?? 12,\n    // Keep the value legend compact so the map body gets more visual space.\n    itemWidth: 10,\n    itemHeight: 90,\n    textStyle: { fontSize: 10 },\n  };\n  if (!cfg?.pieces) {\n    out.inRange = { color: inRangeColors };\n  }\n\n  if (cfg?.top !== undefined) {\n    out.top = cfg.top;\n    delete out.bottom;\n  }\n  if (cfg?.formatter !== undefined) out.formatter = cfg.formatter;\n  if (cfg?.precision !== undefined) out.precision = cfg.precision;\n  if (cfg?.pieces !== undefined) out.pieces = cfg.pieces;\n\n  // Explicitly show scale labels at both ends of the gradient bar (max at top,\n  // min at bottom for vertical orientation). ECharts does not always surface\n  // these reliably without an explicit `text` value, so we set them here as the\n  // default. User-supplied `cfg.text` wins; `pieces` mode uses its own labels.\n  if (!cfg?.pieces) {\n    if (cfg?.text !== undefined) {\n      out.text = cfg.text;\n    } else {\n      const precision = cfg?.precision;\n      const formatEnd = (n: number): string => {\n        if (precision !== undefined) return n.toFixed(precision);\n        return Number.isInteger(n) ? String(n) : n.toFixed(1);\n      };\n      out.text = [formatEnd(resolvedMax), formatEnd(resolvedMin)];\n    }\n  }\n\n  return out;\n}\n\nfunction buildAutoHideOverflowLabelLayout(\n  options: MapChartOptions,\n): ((params: unknown) => Record<string, unknown>) | undefined {\n  if (!options.autoHideOverflowLabel) return undefined;\n  return (params: unknown): Record<string, unknown> => {\n    const pr = params as {\n      rect?: { width: number; height: number };\n      labelRect?: { width: number; height: number };\n    };\n    const regionRect = pr.rect;\n    const labelRect = pr.labelRect;\n    if (!regionRect || !labelRect) return {};\n    return {\n      hide:\n        labelRect.width > regionRect.width ||\n        labelRect.height > regionRect.height,\n    };\n  };\n}\n\nfunction buildAutoHideOverflowLabelFormatter(\n  options: MapChartOptions,\n): ((params: unknown) => string) | undefined {\n  if (!options.autoHideOverflowLabel) return undefined;\n  return (params: unknown): string => {\n    const pr = params as Record<string, unknown>;\n    const value = normalizeMapValue(pr.value);\n    // Hide labels for regions without usable values when auto-hide is enabled.\n    if (value === '') return '';\n    return String(pr.name ?? '');\n  };\n}\n\nexport function resolveMapOptions(\n  data: MapData,\n  options: MapChartOptions,\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const defaultAreaColor = resolveColors(['__map_default__'], options)[0];\n  const seriesData = data.map((item) => ({\n    name: item.name,\n    value: item.value,\n    itemStyle: (item.color ?? options.colorMap?.[item.name])\n      ? {\n          areaColor: item.color ?? options.colorMap?.[item.name],\n          color: item.color ?? options.colorMap?.[item.name],\n        }\n      : undefined,\n  }));\n\n  const tooltip: Record<string, unknown> = {\n    trigger: 'item',\n    confine: true,\n    show: options.tooltip?.enabled !== false,\n    appendToBody: resolveAppendToBody(options, ctx),\n    position: resolveTooltipPosition(options),\n  };\n  const mapFormatter = buildAsyncTooltipFormatter({\n    options,\n    defaultSync: (params) => mapTooltipSyncHtml(params, options),\n    toContext: mapParamsToTooltipContext,\n  });\n  tooltip.formatter =\n    mapFormatter ?? ((params: unknown) => mapTooltipSyncHtml(params, options));\n\n  const visualMap = resolveVisualMap(data, options);\n  const autoHideLabelLayout = buildAutoHideOverflowLabelLayout(options);\n  const autoHideLabelFormatter = buildAutoHideOverflowLabelFormatter(options);\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    tooltip,\n    visualMap,\n    series: [\n      {\n        type: 'map',\n        map: options.mapName,\n        nameProperty: options.nameProperty ?? 'name',\n        roam: options.roam ?? false,\n        center: options.center,\n        // Slightly larger default viewport so regional shapes are easier to read.\n        zoom: options.zoom ?? 1.08,\n        data: seriesData,\n        ...(visualMap === undefined\n          ? { itemStyle: { areaColor: defaultAreaColor } }\n          : {}),\n        label: {\n          show: options.showLabel ?? false,\n          fontSize: getLabelFontSize(options),\n          ...(autoHideLabelFormatter\n            ? { formatter: autoHideLabelFormatter }\n            : {}),\n        },\n        ...(autoHideLabelLayout\n          ? { labelLayout: autoHideLabelLayout }\n          : {}),\n      },\n    ],\n  };\n\n  const merged = deepMerge(\n    eOption,\n    (options.echarts ?? {}) as Record<string, unknown>,\n  );\n  merged.color = [defaultAreaColor];\n  return merged;\n}\n","import type {\n  ChartOptions,\n  TooltipContext,\n  TooltipContextItem,\n  TooltipContextEdge,\n  ChartEventContext,\n  ChartEventType,\n} from './types.js';\n\n/**\n * Map ECharts pie `item` tooltip params to {@link TooltipContextItem}.\n *\n * Reads `params.color` for the resolved slice color — ECharts populates\n * this with the same hex/rgb value it used to paint the slice, so it\n * already reflects `options.colors` / `options.colorMap` / theme palette\n * after our color pipeline has run.\n */\nexport function pieParamsToTooltipContext(params: unknown): TooltipContextItem {\n  const x = params as {\n    name: string;\n    value: number;\n    percent?: number;\n    dataIndex?: number;\n    marker?: string;\n    color?: string;\n  };\n  return {\n    kind: 'item',\n    dataIndex: x.dataIndex ?? 0,\n    name: x.name,\n    value: x.value,\n    percent: x.percent,\n    marker: x.marker,\n    color: typeof x.color === 'string' ? x.color : undefined,\n  };\n}\n\n/**\n * Default synchronous pie tooltip HTML (before `customHtml` append).\n */\nexport function formatPieTooltipSyncHtml(params: unknown, options: ChartOptions): string {\n  const x = params as {\n    marker?: string;\n    name: string;\n    value: number;\n    percent?: number;\n    seriesName?: string;\n  };\n  const fmt = options.tooltip?.formatValue;\n  const valDisplay = fmt ? fmt(x.value, x.name) : String(x.value);\n  const name = x.seriesName ?? x.name;\n  if (x.percent != null && !Number.isNaN(x.percent)) {\n    return `${x.marker ?? ''}${name}<br/>${valDisplay} (${x.percent.toFixed(1)}%)`;\n  }\n  return `${x.marker ?? ''}${name}<br/>${valDisplay}`;\n}\n\n/**\n * Map Sankey / Chord / Network / Tree tooltip params to {@link TooltipContext}.\n *\n * `nameToColor` is optional but **required for color fields to populate**:\n *\n *   - node hover (`kind: 'item'`) → `color = nameToColor.get(name)`\n *     (falls back to `params.color` when the map doesn't have an entry —\n *     ECharts' own `params.color` is a real hex on the node side, never\n *     `\"gradient\"`).\n *   - edge hover (`kind: 'edge'`) → `sourceColor = nameToColor.get(source)`,\n *     `targetColor = nameToColor.get(target)`. There is no `params.color`\n *     fallback here because ECharts reports the literal string\n *     `\"gradient\"` for sankey/chord links by default.\n *\n * Without the map both color fields are `undefined` and the rest of the\n * context still works — this keeps the function callable from custom\n * adapters that don't have a name→color lookup handy.\n */\nexport function sankeyChordParamsToTooltipContext(\n  params: unknown,\n  nameToColor?: ReadonlyMap<string, string>,\n): TooltipContext {\n  const pr = params as Record<string, unknown>;\n  if (pr.dataType === 'edge') {\n    const d = pr.data as Record<string, unknown>;\n    const source = String(d.source);\n    const target = String(d.target);\n    return {\n      kind: 'edge',\n      dataIndex: (pr.dataIndex as number) ?? 0,\n      source,\n      target,\n      value: d.value as number | string,\n      sourceColor: nameToColor?.get(source),\n      targetColor: nameToColor?.get(target),\n    };\n  }\n  const name = String(pr.name ?? '');\n  const fallbackColor = typeof pr.color === 'string' ? pr.color : undefined;\n  return {\n    kind: 'item',\n    dataIndex: (pr.dataIndex as number) ?? 0,\n    name,\n    value: (pr.value as number | string) ?? '',\n    marker: pr.marker as string | undefined,\n    color: nameToColor?.get(name) ?? fallbackColor,\n  };\n}\n\n/**\n * Coerce an ECharts `params.value` into the scalar a `TooltipContext*` exposes.\n * Most series report a number / string; scatter & word-cloud report a tuple\n * (`[x, y]` / `[word, count]`), in which case the trailing element is the\n * meaningful magnitude.\n */\nfunction scalarValue(value: unknown): number | string {\n  if (Array.isArray(value)) {\n    const last = value[value.length - 1];\n    return typeof last === 'number' || typeof last === 'string' ? last : '';\n  }\n  return typeof value === 'number' || typeof value === 'string' ? value : '';\n}\n\n/**\n * Normalize a raw ECharts mouse-event `params` into a {@link ChartEventContext}\n * for `ChartOptions.events` handlers. Reuses the tooltip item/edge shapes:\n *\n *   - `params.dataType === 'edge'` (sankey / chord / network link) → `data`\n *     is a {@link TooltipContextEdge}.\n *   - a hit carrying `name` / `value` / `data` (any series data item) → `data`\n *     is a {@link TooltipContextItem}.\n *   - anything else (empty canvas, legend, title, axis label) → `data` is\n *     `undefined`; the caller still gets `componentType` / `seriesType` / `raw`.\n *\n * ECharts' literal `\"gradient\"` link color is dropped (it's not a usable hex);\n * node/item `params.color` is a real resolved color and passes through.\n */\nexport function buildChartEventContext(\n  type: ChartEventType,\n  params: unknown,\n): ChartEventContext {\n  const pr = (params ?? {}) as Record<string, unknown>;\n\n  let data: TooltipContextItem | TooltipContextEdge | undefined;\n  if (\n    pr.dataType === 'edge' &&\n    pr.data !== null &&\n    typeof pr.data === 'object'\n  ) {\n    const d = pr.data as Record<string, unknown>;\n    data = {\n      kind: 'edge',\n      dataIndex: (pr.dataIndex as number) ?? 0,\n      source: String(d.source ?? ''),\n      target: String(d.target ?? ''),\n      value: scalarValue(d.value),\n    };\n  } else if (\n    pr.componentType === 'series' &&\n    (pr.name !== undefined || pr.value !== undefined || pr.data !== undefined)\n  ) {\n    const color =\n      typeof pr.color === 'string' && pr.color !== 'gradient'\n        ? pr.color\n        : undefined;\n    data = {\n      kind: 'item',\n      dataIndex: (pr.dataIndex as number) ?? 0,\n      name: String(pr.name ?? ''),\n      value: scalarValue(pr.value),\n      percent: typeof pr.percent === 'number' ? pr.percent : undefined,\n      marker: typeof pr.marker === 'string' ? pr.marker : undefined,\n      color,\n    };\n  }\n\n  return {\n    type,\n    data,\n    componentType:\n      typeof pr.componentType === 'string' ? pr.componentType : undefined,\n    seriesType: typeof pr.seriesType === 'string' ? pr.seriesType : undefined,\n    seriesIndex:\n      typeof pr.seriesIndex === 'number' ? pr.seriesIndex : undefined,\n    raw: params,\n  };\n}\n","import type {\n  PieData,\n  PieChartOptions,\n  PieVariant,\n  PieCenterLabel,\n} from '../types.js';\nimport type * as echarts from 'echarts';\nimport type { ChartSetupResult, RenderContext } from './index.js';\nimport { getConfig } from '../config.js';\nimport {\n  formatPieTooltipSyncHtml,\n  pieParamsToTooltipContext,\n} from '../tooltip-context.js';\nimport { deepMerge, resolveColors } from '../utils.js';\nimport {\n  type EdgeReserves,\n  buildTitle,\n  buildLegend,\n  buildAsyncTooltipFormatter,\n  compileRichText,\n  getLabelFontSize,\n  getLegendReserve,\n  getTitleReserve,\n  resolveAppendToBody,\n  resolveTooltipPosition,\n  applyConfiguredFontFamilyToOption,\n} from './common/index.js';\nimport { measureTextWidth } from './common/text-measure.js';\nimport { getThemeColors, resolveThemeName, syncColorHubTheme } from '../themes/index.js';\n\n// ---------------------------------------------------------------------------\n// Layout architecture\n// ---------------------------------------------------------------------------\n//\n// Pie is a body-centered chart, but unlike radar its slice / label / legend\n// geometry leaves very little tolerance for \"close enough\" sizing — the older\n// percent-of-reference-canvas math (PIE_REFERENCE_WIDTH = 480) under-shifted\n// the center on narrow cards because a fixed pixel legend reserve takes a\n// much larger fraction of a 280 px card than of the 480 px reference. The\n// result was a doughnut whose right edge landed on top of a `position:\n// 'right'` legend in dashboards (the regression that motivated this rewrite).\n//\n// The fix runs in two passes:\n//\n//   1. The static option (returned from `resolvePieOptions`) holds a generic\n//      centered fallback so the very first paint is reasonable even before\n//      the post-init hook fires.\n//   2. The `onInit` hook reads `chart.getWidth()` / `getHeight()` — the only\n//      authoritative source of canvas dimensions — and applies the\n//      pixel-accurate `center` + `radius` via `setOption` merge.\n//\n// A `ResizeObserver` on the chart's container DOM re-runs the recompute\n// whenever the container changes size (e.g. window resize, responsive\n// breakpoints). `onInit` returns the observer's teardown (a `ChartTeardown`),\n// so the engine disconnects it before the next render and on `dispose()` —\n// no per-instance state stashed on the chart, no `isDisposed()` polling.\n\n/** Fraction of the smaller available-area dimension the pie body fills.\n *  85% leaves a small visual cushion between the doughnut's outer arc and\n *  the legend / title / canvas edge. */\nconst PIE_FILL_FACTOR = 0.85;\n\n/** Half-doughnut version of {@link PIE_FILL_FACTOR}. The arc only occupies\n *  the upper half so it can absorb a larger fraction of the canvas without\n *  bumping into the bottom edge. */\nconst HALF_DOUGHNUT_FILL_FACTOR = 0.92;\n\n/** Pixel floor so the pie never collapses to a postage stamp in tiny cards. */\nconst PIE_MIN_RADIUS_PX = 24;\n\n/** Outside slice labels (`{b}: {d}%`) extend ~30 px past the outer arc.\n *  Reserved on every edge when slice labels are on so they don't get clipped. */\nconst PIE_LABEL_OVERFLOW_PX = 30;\n\n/**\n * Extra slot ECharts allocates around its legend group beyond what\n * {@link getLegendReserve} captures:\n *\n *   - ECharts' own internal padding around the legend group (~10 px total)\n *   - Visual breathing room between the chart body and the legend column\n *\n * Added to the side-legend reserve so the doughnut's outer arc doesn't\n * sit touching the swatch column. Tuned by eye on 280-720 px wide cards.\n */\nconst LEGEND_VISUAL_SAFETY_PX = 16;\n\n/** Row height ECharts uses for a single legend line (12 px text + ~6 px padding). */\nconst LEGEND_ITEM_HEIGHT_PX = 18;\n\n/** Vertical gap ECharts inserts between wrapped legend rows. */\nconst LEGEND_ROW_GAP_PX = 10;\n\n/**\n * Per-item horizontal slot inside a horizontal legend (icon + icon-text\n * gap + the inter-item gap ECharts inserts between adjacent items). Added\n * to each label's measured pixel width when estimating how many rows the\n * legend will wrap into.\n *\n * ECharts' default `itemWidth: 25` (not the 14 px the visible swatch hints\n * at — there's extra rendering padding around the icon) plus its default\n * 5 px gap to the label plus a 10 px inter-item gap. Over-estimating\n * triggers a slightly larger bottom reserve, which only shows up as a\n * cosmetic extra gap; under-estimating misses the wrap and re-introduces\n * the original overlap bug. We err on the conservative side.\n */\nconst LEGEND_ITEM_NON_TEXT_PX = 25 /* itemWidth */ + 5 /* icon-text gap */ + 10 /* item-to-item gap */;\n\nconst CENTER_LABEL_DEFAULT_GAP_PX = 4;\nconst CENTER_LABEL_PRIMARY_RATIO = 0.135;\nconst CENTER_LABEL_PRIMARY_MIN = 18;\nconst CENTER_LABEL_PRIMARY_MAX = 72;\nconst CENTER_LABEL_LINE_MIN = 10;\nconst CENTER_LABEL_LINE_MAX = 96;\nconst CENTER_LABEL_SECONDARY_SCALE = 0.4;\nconst CENTER_LABEL_FALLBACK_REF = 320;\nconst CENTER_LABEL_GRAPHIC_ID = '__ich_pie_center_labels';\n// Keep doughnut ring auto-sizing aligned with gauge `percentage`.\nconst PIE_AUTO_RING_RATIO = 0.075;\nconst PIE_AUTO_RING_MIN = 8;\nconst PIE_AUTO_RING_MAX = 36;\nconst PIE_AUTO_RING_FALLBACK = 20;\nconst NIGHTINGALE_INNER_CORNER_RADIUS = 4;\n\nexport function resolvePieOptions(\n  data: PieData,\n  options: PieChartOptions,\n  ctx?: RenderContext,\n): ChartSetupResult {\n  const themeName = resolveThemeName(options.theme);\n  syncColorHubTheme(themeName);\n  const defaultCenterLabelPrimaryColor = getThemeColors()?.textPrimary;\n  const defaultCenterLabelSecondaryColor = getThemeColors()?.textSecondary;\n\n  const variant = (options.variant ?? 'default') as PieVariant;\n  const names = data.map((d) => d.name);\n  const showLegend = options.legend?.show ?? false;\n  const showSliceLabel = options.showSliceLabel ?? !showLegend;\n\n  const sorted = options.autoSort !== false\n    ? [...data].sort((a, b) => b.value - a.value)\n    : data;\n\n  // ECharts pie matches `option.color[i]` to `series.data[i]` by index, so\n  // the palette has to follow the SORTED slice order — not the original\n  // input order. Otherwise a `colorMap` pin on a name that the sort moves\n  // (e.g. Premium at value 420 trailing higher tiers) paints the wrong\n  // slice and its matching legend swatch. The legend's display order still\n  // follows `names` (the user-supplied order) so callers retain control of\n  // the legend layout independent of the painted slice order.\n  const sliceNames = sorted.map((d) => d.name);\n\n  const tooltip: Record<string, unknown> = {\n    trigger: 'item',\n    confine: true,\n    appendToBody: resolveAppendToBody(options, ctx),\n    position: resolveTooltipPosition(options),\n  };\n  const pieFormatter = buildAsyncTooltipFormatter({\n    options,\n    defaultSync: (params) => formatPieTooltipSyncHtml(params, options),\n    toContext: pieParamsToTooltipContext,\n  });\n  if (pieFormatter) {\n    tooltip.formatter = pieFormatter;\n  }\n\n  const centerLabels = normalizeCenterLabels(\n    options.centerLabels,\n    defaultCenterLabelPrimaryColor,\n    defaultCenterLabelSecondaryColor,\n  );\n  const centerLabelOffset = options.centerLabelOffset ?? [0, 0];\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    legend: buildLegend(names, {\n      ...options,\n      legend: { ...options.legend, show: showLegend },\n    }),\n    tooltip,\n    series: buildPieSeries(sorted, options, variant, showSliceLabel),\n    ...(centerLabels\n      ? {\n          graphic: [\n            buildCenterLabelGraphic(\n              centerLabels,\n              variant,\n              0,\n              0,\n              centerLabelOffset[0],\n              centerLabelOffset[1],\n              false,\n              ctx?.containerWidth,\n              ctx?.containerHeight,\n            ),\n          ],\n        }\n      : {}),\n  };\n\n  const merged = deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n  merged.color = resolveColors(sliceNames, options);\n\n  return {\n    option: merged,\n    onInit: (chart) =>\n      applyAdaptiveLayout(\n        chart,\n        options,\n        variant,\n        showLegend,\n        showSliceLabel,\n        names,\n        centerLabels,\n        centerLabelOffset,\n      ),\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Pixel-accurate layout (runtime, knows actual canvas dimensions)\n// ---------------------------------------------------------------------------\n\ninterface PieLayout {\n  center: [number, number];\n  radius: [number | string, number | string];\n}\n\n/**\n * Compute the pie's pixel-perfect center + radius from actual canvas\n * dimensions and per-edge reserves. Applied via `setOption` merge so the\n * static option's percent fallback is replaced before the user notices.\n */\nfunction computePieLayout(\n  W: number,\n  H: number,\n  reserves: EdgeReserves,\n  variant: PieVariant,\n  options: PieChartOptions,\n): PieLayout {\n  const availW = Math.max(0, W - reserves.left - reserves.right);\n  const availH = Math.max(0, H - reserves.top - reserves.bottom);\n\n  if (variant === 'half-doughnut') {\n    return computeHalfDoughnutLayout(reserves, availW, availH, options);\n  }\n\n  // Center sits at the centroid of the available rectangle — the side with\n  // the larger reserve \"donates\" pixels to the opposite edge.\n  const cx = reserves.left + availW / 2;\n  const cy = reserves.top + availH / 2;\n\n  const outerRadius =\n    options.outerRadius !== undefined\n      ? options.outerRadius\n      : Math.max(PIE_MIN_RADIUS_PX, (Math.min(availW, availH) / 2) * PIE_FILL_FACTOR);\n\n  const innerRadius = resolveInnerRadius(variant, options, outerRadius, availW, availH);\n\n  return {\n    center: [Math.round(cx), Math.round(cy)],\n    radius: [innerRadius, outerRadius],\n  };\n}\n\nfunction computeHalfDoughnutLayout(\n  reserves: EdgeReserves,\n  availW: number,\n  availH: number,\n  options: PieChartOptions,\n): PieLayout {\n  // The arc spans startAngle=180 → endAngle=360 (upper half), so its visible\n  // bounding rectangle is `2r` wide and `r` tall, sitting directly above\n  // the center point. Two radius constraints:\n  //\n  //   - horizontal: 2r <= availW   → r <= availW / 2\n  //   - vertical:   r  <= availH   (the arc rect is r tall)\n  //\n  // Take the smaller — the arc fits both ways.\n  const limitingRadius = Math.min(availW / 2, availH);\n  const outerRadius =\n    options.outerRadius !== undefined\n      ? options.outerRadius\n      : Math.max(PIE_MIN_RADIUS_PX, limitingRadius * HALF_DOUGHNUT_FILL_FACTOR);\n\n  // Center the arc's bounding rectangle vertically inside the available\n  // area (between the title's bottom edge and the legend's top edge). The\n  // arc rect is `r` tall, so its midpoint sits at `reserves.top + availH/2`\n  // and the arc's diameter line (center.y) is half a radius below that.\n  //\n  // This replaces the old \"anchor to the bottom\" placement, which glued the\n  // diameter to `H - reserves.bottom` and left all the vertical slack on\n  // top — fine for short cards, ugly in tall ones where the grid stretches\n  // the card to match a taller sibling.\n  const cx = reserves.left + availW / 2;\n  const radiusForCenter = typeof outerRadius === 'number' ? outerRadius : limitingRadius;\n  const cy = reserves.top + availH / 2 + radiusForCenter / 2;\n\n  // Ring thickness scales with the outer radius so a tiny chart doesn't\n  // collapse to a hairline ring and a giant chart doesn't get an oversize\n  // gap. Capped at 60 px so the ring stays visually thin on large cards.\n  const ring =\n    resolveAutoRingWidth(availW, availH);\n  const innerRadius =\n    options.innerRadius !== undefined\n      ? options.innerRadius\n      : typeof outerRadius === 'number'\n        ? Math.max(0, outerRadius - ring)\n        : '60%';\n\n  return {\n    center: [Math.round(cx), Math.round(cy)],\n    radius: [innerRadius, outerRadius],\n  };\n}\n\nfunction resolveInnerRadius(\n  variant: PieVariant,\n  options: PieChartOptions,\n  outerRadius: number | string,\n  availW?: number,\n  availH?: number,\n): number | string {\n  if (options.innerRadius !== undefined) return options.innerRadius;\n  if (variant === 'doughnut') {\n    if (typeof outerRadius === 'number') {\n      const ring = resolveAutoRingWidth(availW, availH);\n      return Math.max(0, outerRadius - ring);\n    }\n    return '50%';\n  }\n  if (variant === 'nightingale') return typeof outerRadius === 'number' ? 16 : 20;\n  return 0;\n}\n\nfunction resolveAutoRingWidth(w?: number, h?: number): number {\n  if (!w || !h) return PIE_AUTO_RING_FALLBACK;\n  const ref = Math.min(w, h);\n  return clampRound(\n    ref * PIE_AUTO_RING_RATIO,\n    PIE_AUTO_RING_MIN,\n    PIE_AUTO_RING_MAX,\n  );\n}\n\n/**\n * Pixel-accurate edge reserves derived from actual canvas dimensions plus\n * title / legend / outside-label budgets.\n *\n * The horizontal-legend row count depends on the canvas width — five\n * tier names like `Premium`/`Pro`/`Standard`/`Basic`/`Churned` pack into\n * one row at 720 px but wrap to two at 380 px. Estimating that here lets\n * the half-doughnut's bottom edge clear a multi-row legend instead of\n * relying on the single-row assumption baked into `LEGEND_RESERVE`.\n *\n * `W` is optional so the function still works in the static-option path\n * (where canvas dimensions aren't known yet). When omitted, falls back to\n * the row-agnostic reserve `getLegendReserve` returns.\n */\nfunction computeEdgeReserves(\n  options: PieChartOptions,\n  showLegend: boolean,\n  showSliceLabel: boolean,\n  names: ReadonlyArray<string>,\n  W?: number,\n): EdgeReserves {\n  const p = options.padding ?? 12;\n  const title = getTitleReserve(options);\n  const legend = getLegendReserve(options, showLegend, 0, names);\n  const labelGap = showSliceLabel ? PIE_LABEL_OVERFLOW_PX : 0;\n\n  // Side legends sit at `right: p` (chart padding), so the chart body needs\n  // to leave room for the legend group AND the padding AND a visual gap.\n  const sidePad = (edge: number): number =>\n    edge > 0 ? edge + p + LEGEND_VISUAL_SAFETY_PX : 0;\n\n  // For horizontal (top / bottom) legends, when we know the canvas width\n  // we can estimate the rendered row count and replace the single-row\n  // assumption baked into `LEGEND_RESERVE` with a row-aware reserve.\n  // Skips the work when the legend isn't shown or names are empty.\n  const horizontalReserve = (edge: number): number => {\n    if (edge <= 0) return 0;\n    if (W === undefined || names.length === 0) return edge;\n    const rows = estimateHorizontalLegendRows(names, W - 2 * p);\n    if (rows <= 1) return edge;\n    const dynamicHeight =\n      rows * LEGEND_ITEM_HEIGHT_PX + (rows - 1) * LEGEND_ROW_GAP_PX + p;\n    return Math.max(edge, dynamicHeight);\n  };\n\n  return {\n    top: (title.top > 0 ? p + title.top : 0) + horizontalReserve(legend.top) + labelGap,\n    bottom: horizontalReserve(legend.bottom) + labelGap,\n    left: sidePad(legend.left) + labelGap,\n    right: sidePad(legend.right) + labelGap,\n  };\n}\n\n/**\n * Greedily pack legend item widths into rows to estimate how many rows\n * ECharts will wrap the legend into at the given canvas width. Mirrors\n * ECharts' own placement loop closely enough for our reserve math —\n * we're not trying to reproduce pixel-perfect layout, just predict\n * whether the legend will be one row or multiple.\n */\nfunction estimateHorizontalLegendRows(\n  names: ReadonlyArray<string>,\n  availWidth: number,\n): number {\n  if (availWidth <= 0) return 1;\n  let rows = 1;\n  let rowWidth = 0;\n  for (const name of names) {\n    const itemW = measureTextWidth(name) + LEGEND_ITEM_NON_TEXT_PX;\n    if (rowWidth + itemW > availWidth && rowWidth > 0) {\n      rows += 1;\n      rowWidth = itemW;\n    } else {\n      rowWidth += itemW;\n    }\n  }\n  return rows;\n}\n\n/**\n * Replace the static option's center/radius with pixel-accurate values\n * computed from the chart's real container dimensions, then attach a\n * `ResizeObserver` so the layout re-flows on container resize. Returns the\n * observer teardown (a `ChartTeardown`) for the engine to call before the\n * next render and on dispose — or `undefined` when there's nothing to clean\n * up (SSR / no `ResizeObserver` / detached DOM).\n */\nfunction applyAdaptiveLayout(\n  chart: echarts.ECharts,\n  options: PieChartOptions,\n  variant: PieVariant,\n  showLegend: boolean,\n  showSliceLabel: boolean,\n  names: ReadonlyArray<string>,\n  centerLabels?: NormalizedCenterLabels,\n  centerLabelOffset: [number, number] = [0, 0],\n): (() => void) | void {\n  const recompute = (): void => {\n    if (chart.isDisposed()) return;\n    const W = chart.getWidth();\n    const H = chart.getHeight();\n    if (!Number.isFinite(W) || !Number.isFinite(H) || W <= 0 || H <= 0) {\n      // Container hasn't been laid out yet — the ResizeObserver will fire\n      // when it does. Leave the static option's percent fallback in place\n      // for the moment.\n      return;\n    }\n    const reserves = computeEdgeReserves(options, showLegend, showSliceLabel, names, W);\n    const layout = computePieLayout(W, H, reserves, variant, options);\n    const payload: Record<string, unknown> = {\n      series: [{ center: layout.center, radius: layout.radius }],\n    };\n    if (centerLabels) {\n      payload.graphic = [\n        buildCenterLabelGraphic(\n          centerLabels,\n          variant,\n          layout.center[0],\n          layout.center[1],\n          centerLabelOffset[0],\n          centerLabelOffset[1],\n          true,\n          W,\n          H,\n        ),\n      ];\n    }\n    applyConfiguredFontFamilyToOption(payload, getConfig().fontFamily);\n    chart.setOption(\n      payload,\n      // Merge, not replace — we only want to overwrite center/radius and\n      // leave the data / colors / labels / etc. that the static option\n      // already set up.\n      false,\n    );\n  };\n\n  recompute();\n  return attachResizeObserver(chart, recompute);\n}\n\n/**\n * Attach a ResizeObserver to the chart's container DOM that re-runs the\n * pixel-layout recompute whenever the container changes size. Returns a\n * teardown that disconnects the observer; the engine calls it before the\n * next render (so each `_apply()` gets a fresh observer bound to the latest\n * closure) and on `dispose()`. Returns `undefined` when there's no observer\n * to manage (SSR / older browsers / detached DOM).\n */\nfunction attachResizeObserver(\n  chart: echarts.ECharts,\n  recompute: () => void,\n): (() => void) | void {\n  if (typeof ResizeObserver === 'undefined') return; // SSR / older browsers\n  const dom = chart.getDom() as HTMLElement | undefined;\n  if (!dom) return;\n\n  const observer = new ResizeObserver(() => {\n    // Belt-and-suspenders: the engine disconnects on dispose, but a queued\n    // resize entry could still fire in the same tick — bail if disposed.\n    if (chart.isDisposed()) {\n      observer.disconnect();\n      return;\n    }\n    recompute();\n  });\n  observer.observe(dom);\n  return () => observer.disconnect();\n}\n\n// ---------------------------------------------------------------------------\n// Static option construction (fallback for the very first paint)\n// ---------------------------------------------------------------------------\n\nfunction buildPieSeries(\n  data: PieData,\n  options: PieChartOptions,\n  variant: PieVariant,\n  showSliceLabel: boolean,\n): Record<string, unknown>[] {\n  // Reasonable centered defaults — these are only used until `onInit` fires\n  // immediately after the first `setOption`. By then the user sees the\n  // pixel-accurate layout. Tests that don't run onInit still get these\n  // values, which keeps the static option assertable without mocks.\n  const series: Record<string, unknown> = {\n    type: 'pie',\n    center: ['50%', '50%'],\n    radius: defaultStaticRadius(variant, options),\n    avoidLabelOverlap: true,\n    data: data.map((d) => ({ name: d.name, value: d.value })),\n    label: {\n      show: showSliceLabel,\n      position: 'outside',\n      formatter: '{b}: {d}%',\n      fontSize: getLabelFontSize(options),\n    },\n  };\n\n  if (variant === 'half-doughnut') {\n    series.startAngle = 180;\n    series.endAngle = 360;\n    series.center = ['50%', '75%'];\n  }\n  if (variant === 'nightingale') {\n    series.roseType = 'radius';\n  }\n\n  applySliceStyle(series, options, variant);\n  return [series];\n}\n\nfunction defaultStaticRadius(\n  variant: PieVariant,\n  options: PieChartOptions,\n): [number | string, number | string] {\n  const inner =\n    options.innerRadius !== undefined\n      ? options.innerRadius\n      : variant === 'doughnut'\n        ? '50%'\n        : variant === 'nightingale'\n          ? 20\n          : variant === 'half-doughnut'\n            ? '60%'\n            : 0;\n  const outer =\n    options.outerRadius !== undefined\n      ? options.outerRadius\n      : variant === 'half-doughnut'\n        ? '90%'\n        : '70%';\n  return [inner, outer];\n}\n\nfunction applySliceStyle(\n  series: Record<string, unknown>,\n  options: PieChartOptions,\n  variant: PieVariant,\n): void {\n  if (options.sliceGap !== undefined) {\n    series.padAngle = options.sliceGap;\n  }\n\n  const itemStyle: Record<string, unknown> = {};\n  if (options.sliceBorderRadius !== undefined) {\n    itemStyle.borderRadius = variant === 'nightingale'\n      ? [\n          NIGHTINGALE_INNER_CORNER_RADIUS,\n          NIGHTINGALE_INNER_CORNER_RADIUS,\n          options.sliceBorderRadius,\n          options.sliceBorderRadius,\n        ]\n      : options.sliceBorderRadius;\n  }\n  if (options.sliceBorderColor !== undefined) itemStyle.borderColor = options.sliceBorderColor;\n  if (Object.keys(itemStyle).length > 0) {\n    series.itemStyle = itemStyle;\n  }\n}\n\ninterface NormalizedCenterLabelLine {\n  plainText: string;\n  richText?: string;\n  rich?: Record<string, Record<string, unknown>>;\n  isRich: boolean;\n}\n\ninterface NormalizedCenterLabels {\n  lines: NormalizedCenterLabelLine[];\n  gap: number;\n  defaultPrimaryColor?: string;\n  defaultSecondaryColor?: string;\n}\n\nfunction normalizeCenterLabelLine(line: PieCenterLabel, index: number): NormalizedCenterLabelLine {\n  if (typeof line === 'string') {\n    return {\n      plainText: line,\n      isRich: false,\n    };\n  }\n  const compiled = compileRichText(line, `pie_center_${index}`);\n  return {\n    plainText: compiled.plainText,\n    richText: compiled.text,\n    rich: compiled.rich as Record<string, Record<string, unknown>> | undefined,\n    isRich: true,\n  };\n}\n\nfunction normalizeCenterLabels(\n  centerLabels: PieCenterLabel[] | undefined,\n  defaultPrimaryColor?: string,\n  defaultSecondaryColor?: string,\n): NormalizedCenterLabels | undefined {\n  if (!centerLabels) return undefined;\n  const lines = centerLabels\n    .map((line, index) => normalizeCenterLabelLine(line, index))\n    .filter((line) => line.plainText.trim().length > 0);\n  if (lines.length === 0) return undefined;\n  return {\n    lines,\n    gap: CENTER_LABEL_DEFAULT_GAP_PX,\n    defaultPrimaryColor,\n    defaultSecondaryColor,\n  };\n}\n\nfunction clampRound(value: number, min: number, max: number): number {\n  return Math.min(max, Math.max(min, Math.round(value)));\n}\n\nfunction resolveCenterLabelBaseFont(w?: number, h?: number): number {\n  const ref = w && h ? Math.min(w, h) : CENTER_LABEL_FALLBACK_REF;\n  return clampRound(\n    ref * CENTER_LABEL_PRIMARY_RATIO,\n    CENTER_LABEL_PRIMARY_MIN,\n    CENTER_LABEL_PRIMARY_MAX,\n  );\n}\n\nfunction centerLabelToken(index: number): string {\n  return `cl${index}`;\n}\n\nfunction extractRichTokenKeys(text: string): string[] {\n  const keys: string[] = [];\n  const re = /\\{([^|{}]+)\\|/g;\n  let match: RegExpExecArray | null;\n  while ((match = re.exec(text)) !== null) {\n    keys.push(match[1]);\n  }\n  return keys;\n}\n\nfunction buildCenterLabelRich(\n  centerLabels: NormalizedCenterLabels,\n  variant: PieVariant,\n  w?: number,\n  h?: number,\n): { formatter: string; rich: Record<string, Record<string, unknown>> } {\n  // Half-doughnut dedicates less vertical room to the inner label block, so\n  // nudge base size down slightly to keep two+ lines readable without overlap.\n  const variantScale = variant === 'half-doughnut' ? 0.9 : 1;\n  const base = resolveCenterLabelBaseFont(w, h) * variantScale;\n  const rich: Record<string, Record<string, unknown>> = {};\n  const formatterLines: string[] = [];\n  centerLabels.lines.forEach((line, index) => {\n    const isPrimary = index === 0;\n    const token = centerLabelToken(index);\n    const scale = isPrimary ? 1 : CENTER_LABEL_SECONDARY_SCALE;\n    const fontSize = clampRound(\n      base * scale,\n      CENTER_LABEL_LINE_MIN,\n      CENTER_LABEL_LINE_MAX,\n    );\n    const fontWeight = isPrimary ? 700 : 400;\n    const lineDefaultColor = isPrimary\n      ? centerLabels.defaultPrimaryColor\n      : centerLabels.defaultSecondaryColor ?? centerLabels.defaultPrimaryColor;\n\n    if (!line.isRich || !line.richText || !line.rich) {\n      rich[token] = {\n        fontSize,\n        fontWeight,\n        color: lineDefaultColor,\n        fill: lineDefaultColor,\n        lineHeight: fontSize + centerLabels.gap,\n        align: 'center',\n        verticalAlign: 'middle',\n      };\n      formatterLines.push(`{${token}|${line.plainText}}`);\n      return;\n    }\n    const tokenKeys = extractRichTokenKeys(line.richText);\n    for (const [styleKey, styleValue] of Object.entries(line.rich)) {\n      const shouldApplyLineDefaults = tokenKeys.includes(styleKey);\n      rich[styleKey] = {\n        ...styleValue,\n        fontSize:\n          styleValue.fontSize ?? (shouldApplyLineDefaults ? fontSize : undefined),\n        fontWeight:\n          styleValue.fontWeight ?? (shouldApplyLineDefaults ? fontWeight : undefined),\n        color: styleValue.color ?? lineDefaultColor,\n        fill: (styleValue as Record<string, unknown>).fill ?? styleValue.color ?? lineDefaultColor,\n        lineHeight:\n          styleValue.lineHeight ??\n          (shouldApplyLineDefaults ? fontSize + centerLabels.gap : undefined),\n      };\n    }\n    formatterLines.push(line.richText);\n  });\n  return {\n    formatter: formatterLines.join('\\n'),\n    rich,\n  };\n}\n\nfunction buildCenterLabelGraphic(\n  centerLabels: NormalizedCenterLabels,\n  variant: PieVariant,\n  centerX: number,\n  centerY: number,\n  offsetX: number,\n  offsetY: number,\n  visible: boolean,\n  w?: number,\n  h?: number,\n): Record<string, unknown> {\n  const label = buildCenterLabelRich(centerLabels, variant, w, h);\n  return {\n    id: CENTER_LABEL_GRAPHIC_ID,\n    type: 'text',\n    x: centerX + offsetX,\n    y: centerY + offsetY,\n    invisible: !visible,\n    silent: true,\n    z: 20,\n    style: {\n      x: 0,\n      y: 0,\n      text: label.formatter,\n      rich: label.rich,\n      fill: centerLabels.defaultPrimaryColor,\n      textAlign: 'center',\n      textVerticalAlign: 'middle',\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Internal test helpers — exported under a `__test` namespace so the unit\n// tests can pin the pixel-layout math without an actual ECharts instance.\n// ---------------------------------------------------------------------------\n\nexport const __test = {\n  computeEdgeReserves,\n  computePieLayout,\n};\n","import type { GaugeData, GaugeChartOptions, GaugeVariant } from '../types.js';\nimport { deepMerge } from '../utils.js';\nimport {\n  buildTitle,\n  computeStackedTextOffsets,\n  getTitleReserve,\n} from './common/index.js';\nimport type { RenderContext } from './index.js';\n\n/**\n * Reference chart height (px) used to convert the title area into a\n * percentage offset for `center`.  Matches the `.chart-box` height used in\n * the demo and is a common real-world card height.\n */\nconst GAUGE_REFERENCE_HEIGHT = 320;\n\n// ---------------------------------------------------------------------------\n// Percentage variant auto-sizing\n// ---------------------------------------------------------------------------\n//\n// ECharts gauge accepts pixel numbers — not percentages — for\n// `axisLine.lineStyle.width`, `progress.width`, and `detail.fontSize`. To\n// produce something that looks balanced across small KPI tiles and large\n// hero cards without forcing the consumer to specify `gaugeWidth`, we\n// derive the sizes from the rendered container.\n//\n// `ref = min(containerWidth, containerHeight)` is the right reference\n// because ECharts' default `radius: '75%'` is computed against the shorter\n// side, so the visible ring tracks `ref`. Ratios are picked to:\n//\n//   - put the ring at ~10% of the visible diameter (Apple-Activity /\n//     Material circular-progress feel), i.e. ~7.5% of `ref` since\n//     diameter ≈ 0.75·ref.\n//   - put the big % number at ~18% of the visible diameter (≈ 50% of the\n//     inner diameter), so it never collides with the ring.\n//   - keep the label below the number at 40% of the number's height,\n//     matching the previous hard-coded 36→14 ratio.\n//\n// Clamps protect tiny embedded charts (legibility floor) and oversized\n// canvases (a ring thicker than 36 px starts to look cartoonish).\nconst PERCENTAGE_RING_RATIO = 0.075;\nconst PERCENTAGE_DETAIL_RATIO = 0.135;\nconst PERCENTAGE_TITLE_RATIO = 0.4;\n\nconst PERCENTAGE_RING_MIN = 8;\nconst PERCENTAGE_RING_MAX = 36;\nconst PERCENTAGE_DETAIL_MIN = 18;\nconst PERCENTAGE_DETAIL_MAX = 72;\nconst PERCENTAGE_TITLE_MIN = 10;\nconst PERCENTAGE_TITLE_MAX = 28;\n\n// Centering math for the (big number + label) two-line block lives in\n// the shared `computeStackedTextOffsets` helper in `common.ts` so the\n// donut hole / pie center label / future KPI custom adapters can reuse\n// the same typographic compensation. Defaults (visible gap 12 px,\n// glyph padding 0.15 em) cover the gauge `percentage` aesthetic; pass\n// overrides at the call site below if a variant ever needs to tune\n// them.\n\n// Static fallback used when container dims are unavailable (SSR, jsdom\n// without layout, `display:none` ancestor). Matches the values shipped\n// before auto-sizing existed so snapshots stay stable in those\n// environments.\nconst PERCENTAGE_FALLBACK_RING = 20;\nconst PERCENTAGE_FALLBACK_DETAIL = 36;\nconst PERCENTAGE_FALLBACK_TITLE = 14;\n\ninterface PercentageSizing {\n  width: number;\n  detailFontSize: number;\n  titleFontSize: number;\n}\n\nfunction clampRound(value: number, min: number, max: number): number {\n  return Math.min(max, Math.max(min, Math.round(value)));\n}\n\n/**\n * Derive ring thickness + inner font sizes from the rendered container\n * dimensions. When the engine can't supply usable dims (SSR, hidden\n * card), return the legacy static defaults so resolved options remain\n * deterministic and existing snapshots don't drift.\n */\nfunction autoSizePercentage(ctx?: RenderContext): PercentageSizing {\n  const w = ctx?.containerWidth;\n  const h = ctx?.containerHeight;\n  if (!w || !h) {\n    return {\n      width: PERCENTAGE_FALLBACK_RING,\n      detailFontSize: PERCENTAGE_FALLBACK_DETAIL,\n      titleFontSize: PERCENTAGE_FALLBACK_TITLE,\n    };\n  }\n  const ref = Math.min(w, h);\n  const width = clampRound(\n    ref * PERCENTAGE_RING_RATIO,\n    PERCENTAGE_RING_MIN,\n    PERCENTAGE_RING_MAX,\n  );\n  const detailFontSize = clampRound(\n    ref * PERCENTAGE_DETAIL_RATIO,\n    PERCENTAGE_DETAIL_MIN,\n    PERCENTAGE_DETAIL_MAX,\n  );\n  const titleFontSize = clampRound(\n    detailFontSize * PERCENTAGE_TITLE_RATIO,\n    PERCENTAGE_TITLE_MIN,\n    PERCENTAGE_TITLE_MAX,\n  );\n  return { width, detailFontSize, titleFontSize };\n}\n\n/**\n * Returns the gauge `center` array.  When a title is present the y position\n * is shifted downward so the arc is visually centred in the space below the\n * title rather than in the full canvas.\n */\nfunction buildGaugeCenter(options: GaugeChartOptions): (string | number)[] {\n  const p = options.padding ?? 12;\n  const titleOffset = getTitleReserve(options).top;\n  if (titleOffset === 0) return ['50%', '50%'];\n\n  // Compute how much of the chart height the title area occupies and shift\n  // the center y by half that amount so the gauge sits in the middle of the\n  // remaining space.\n  const titleTop = p + titleOffset;\n  const centerY = Math.round(50 + (titleTop / GAUGE_REFERENCE_HEIGHT) * 50);\n  return ['50%', `${centerY}%`];\n}\n\nexport function resolveGaugeOptions(\n  data: GaugeData,\n  options: GaugeChartOptions,\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const variant = (options.variant ?? 'default') as GaugeVariant;\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    tooltip: { show: false },\n    series: variant === 'percentage'\n      ? buildPercentageSeries(data, options, ctx)\n      : buildDefaultSeries(data, options),\n  };\n\n  return deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n}\n\n// ---------------------------------------------------------------------------\n// Default gauge\n// ---------------------------------------------------------------------------\n\nfunction buildDefaultSeries(\n  data: GaugeData,\n  options: GaugeChartOptions,\n): Record<string, unknown>[] {\n  const max = data.max ?? 100;\n  const width = options.gaugeWidth ?? 18;\n\n  return [\n    {\n      type: 'gauge',\n      center: buildGaugeCenter(options),\n      min: 0,\n      max,\n      progress: { show: true, width },\n      axisLine: { lineStyle: { width } },\n      axisTick: { show: false },\n      splitLine: { length: 12, lineStyle: { width: 2 } },\n      // Labels sit comfortably beyond the 12 px tick marks\n      axisLabel: {\n        distance: 22,\n        fontSize: 11,\n      },\n      pointer: { show: true },\n      anchor: { show: true, size: 20, itemStyle: { borderWidth: 2 } },\n      title: {\n        show: !!data.label,\n        // Raised from 70% → 60% to avoid crowding the 0/100 endpoint labels\n        offsetCenter: [0, '60%'],\n        fontSize: 16,\n      },\n      detail: {\n        valueAnimation: true,\n        fontSize: 28,\n        // Raised from 40% → 32% to match the tighter title position\n        offsetCenter: [0, '32%'],\n        formatter: '{value}',\n      },\n      data: [{ value: data.value, name: data.label ?? '' }],\n    },\n  ];\n}\n\n// ---------------------------------------------------------------------------\n// Percentage variant (simpler ring)\n// ---------------------------------------------------------------------------\n\nfunction buildPercentageSeries(\n  data: GaugeData,\n  options: GaugeChartOptions,\n  ctx?: RenderContext,\n): Record<string, unknown>[] {\n  const max = data.max ?? 100;\n  const percent = Math.round((data.value / max) * 100);\n  const sizing = autoSizePercentage(ctx);\n  // Explicit `gaugeWidth` always wins; inner font sizes are sourced from\n  // the auto-sizer and can still be overridden through\n  // `options.echarts.series[0].detail.fontSize` etc. via the top-level\n  // `deepMerge` in `resolveGaugeOptions`.\n  const width = options.gaugeWidth ?? sizing.width;\n\n  // Stack the (big number + label) as a single px-anchored block\n  // around the ring center. Offsets are emitted as pixel numbers\n  // (ECharts `offsetCenter` accepts both numbers and percent strings\n  // — numbers = px, fixed regardless of radius). See\n  // `computeStackedTextOffsets` for the centering + typographic-\n  // padding math.\n  const hasLabel = !!data.label;\n  const { primaryOffsetY: detailOffsetY, secondaryOffsetY: titleOffsetY } =\n    computeStackedTextOffsets({\n      primaryFontSize: sizing.detailFontSize,\n      secondaryFontSize: sizing.titleFontSize,\n      showSecondary: hasLabel,\n    });\n\n  return [\n    {\n      type: 'gauge',\n      center: buildGaugeCenter(options),\n      startAngle: 90,\n      endAngle: -270,\n      min: 0,\n      max,\n      pointer: { show: false },\n      progress: {\n        show: true,\n        overlap: false,\n        roundCap: true,\n        clip: false,\n        width,\n      },\n      axisLine: {\n        lineStyle: { width },\n      },\n      splitLine: { show: false },\n      axisTick: { show: false },\n      axisLabel: { show: false },\n      title: {\n        show: hasLabel,\n        offsetCenter: [0, titleOffsetY],\n        fontSize: sizing.titleFontSize,\n      },\n      detail: {\n        fontSize: sizing.detailFontSize,\n        fontWeight: 'bold',\n        offsetCenter: [0, detailOffsetY],\n        valueAnimation: true,\n        formatter: `${percent}%`,\n      },\n      data: [{ value: data.value, name: data.label ?? '' }],\n    },\n  ];\n}\n","import type {\n  LiquidProgressData,\n  LiquidProgressChartOptions,\n} from '../types.js';\nimport { getCurrentTheme } from '../themes/index.js';\nimport { deepMerge, hexToRgb, resolveColors } from '../utils.js';\nimport {\n  buildTitle,\n  getLabelFontSize,\n  getTitleReserve,\n} from './common/index.js';\nimport type { RenderContext } from './index.js';\n\n/**\n * Reference chart height (px) used to convert the title area into a\n * percentage offset for `center`.\n */\nconst LIQUID_REFERENCE_HEIGHT = 320;\nconst LIQUID_LABEL_RATIO = 0.11;\nconst LIQUID_LABEL_MIN = 14;\nconst LIQUID_LABEL_MAX = 56;\nconst LIQUID_LABEL_FALLBACK = 24;\nconst LIQUID_BG_ALPHA_LIGHT = 0.14;\nconst LIQUID_BG_ALPHA_DARK = 0.24;\nconst MIN_SECONDARY_LABEL_CONTRAST = 2.6;\n\nfunction buildLiquidCenter(\n  options: LiquidProgressChartOptions,\n): (string | number)[] {\n  const p = options.padding ?? 12;\n  const titleOffset = getTitleReserve(options).top;\n  if (titleOffset === 0) return ['50%', '50%'];\n\n  const titleTop = p + titleOffset;\n  const centerY = Math.round(50 + (titleTop / LIQUID_REFERENCE_HEIGHT) * 50);\n  return ['50%', `${centerY}%`];\n}\n\nfunction clampRatio(value: number): number {\n  if (!Number.isFinite(value)) return 0;\n  return Math.max(0, Math.min(1, value));\n}\n\nfunction buildWaveData(ratio: number, waveCount: number): number[][] {\n  return Array.from({ length: waveCount }, (_unused, idx) =>\n    [Math.round(clampRatio(ratio - idx * 0.03) * 10000) / 10000],\n  );\n}\n\nfunction clampRound(value: number, min: number, max: number): number {\n  return Math.min(max, Math.max(min, Math.round(value)));\n}\n\nfunction resolveLiquidLabelFontSize(\n  options: LiquidProgressChartOptions,\n  ctx?: RenderContext,\n): number {\n  // Explicit `labelFontSize` always wins (shared cross-chart contract).\n  if (options.labelFontSize !== undefined) {\n    return getLabelFontSize(options);\n  }\n  const w = ctx?.containerWidth;\n  const h = ctx?.containerHeight;\n  if (!w || !h) return LIQUID_LABEL_FALLBACK;\n  const ref = Math.min(w, h);\n  return clampRound(ref * LIQUID_LABEL_RATIO, LIQUID_LABEL_MIN, LIQUID_LABEL_MAX);\n}\n\nfunction resolveLiquidBackgroundColor(seriesColor: string): string {\n  if (!seriesColor.startsWith('#')) return seriesColor;\n  const alpha =\n    getCurrentTheme().colorMode === 'dark'\n      ? LIQUID_BG_ALPHA_DARK\n      : LIQUID_BG_ALPHA_LIGHT;\n  return `rgba(${hexToRgb(seriesColor)}, ${alpha})`;\n}\n\nfunction hexToRgbTuple(hex: string): [number, number, number] | null {\n  if (!hex.startsWith('#')) return null;\n  const raw = hex.slice(1);\n  if (raw.length === 3) {\n    return [\n      parseInt(raw[0] + raw[0], 16),\n      parseInt(raw[1] + raw[1], 16),\n      parseInt(raw[2] + raw[2], 16),\n    ];\n  }\n  if (raw.length === 6) {\n    return [\n      parseInt(raw.slice(0, 2), 16),\n      parseInt(raw.slice(2, 4), 16),\n      parseInt(raw.slice(4, 6), 16),\n    ];\n  }\n  return null;\n}\n\nfunction relativeLuminance(rgb: [number, number, number]): number {\n  const [r, g, b] = rgb.map((v) => {\n    const c = v / 255;\n    return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n  });\n  return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\nfunction contrastRatio(a: [number, number, number], b: [number, number, number]): number {\n  const l1 = relativeLuminance(a);\n  const l2 = relativeLuminance(b);\n  const [hi, lo] = l1 >= l2 ? [l1, l2] : [l2, l1];\n  return (hi + 0.05) / (lo + 0.05);\n}\n\nfunction resolveSecondaryLabelColor(\n  textSecondary: string | undefined,\n  textPrimary: string | undefined,\n  seriesColor: string,\n): string | undefined {\n  if (!textSecondary) return textPrimary;\n  if (!textPrimary) return textSecondary;\n\n  const secondaryRgb = hexToRgbTuple(textSecondary);\n  const primaryRgb = hexToRgbTuple(textPrimary);\n  const seriesRgb = hexToRgbTuple(seriesColor);\n  if (!secondaryRgb || !primaryRgb || !seriesRgb) return textSecondary;\n\n  const secondaryContrast = contrastRatio(secondaryRgb, seriesRgb);\n  if (secondaryContrast >= MIN_SECONDARY_LABEL_CONTRAST) return textSecondary;\n  return textPrimary;\n}\n\nexport function resolveLiquidProgressOptions(\n  data: LiquidProgressData,\n  options: LiquidProgressChartOptions,\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const max = data.max ?? 100;\n  const ratio = max > 0 ? clampRatio(data.value / max) : 0;\n  const percent = Math.round(ratio * 100);\n  const waveCount = Math.max(1, options.waveCount ?? 3);\n  const primaryLabelFontSize = resolveLiquidLabelFontSize(options, ctx);\n  const secondaryLabelFontSize = getLabelFontSize(options);\n  const names = [data.label ?? 'Progress'];\n  const colors = resolveColors(names, options);\n  const themeColors = getCurrentTheme().colors;\n  const seriesColor = colors[0];\n  const secondaryLabelColor = resolveSecondaryLabelColor(\n    themeColors?.textSecondary,\n    themeColors?.textPrimary,\n    seriesColor,\n  );\n  const backgroundColor = resolveLiquidBackgroundColor(seriesColor);\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    tooltip: { show: false },\n    series: [\n      {\n        type: 'custom',\n        renderItem: 'liquidFill',\n        coordinateSystem: 'none',\n        data: buildWaveData(ratio, waveCount),\n        itemStyle: {\n          color: seriesColor,\n          opacity: 0.95,\n        },\n        itemPayload: {\n          center: buildLiquidCenter(options),\n          radius: options.radius ?? '70%',\n          waveAnimation: true,\n          amplitude: 6,\n          outline: {\n            show: true,\n            borderDistance: 3,\n            itemStyle: {\n              borderWidth: options.borderWidth ?? 2,\n            },\n          },\n          backgroundStyle: { color: backgroundColor },\n        },\n        label: {\n          show: true,\n          formatter: data.label\n            ? `{primary|${percent}%}\\n{secondary|${data.label}}`\n            : `{primary|${percent}%}`,\n          fontSize: primaryLabelFontSize,\n          rich: {\n            primary: {\n              fontSize: primaryLabelFontSize,\n              fontWeight: 'bold',\n            },\n            secondary: {\n              fontSize: secondaryLabelFontSize,\n              fontWeight: 'normal',\n              color: secondaryLabelColor,\n            },\n          },\n        },\n      },\n    ],\n  };\n\n  const merged = deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n  merged.color = colors;\n  return merged;\n}\n","export interface GraphInputNode {\n  name: string;\n  color?: string;\n  value?: number;\n}\n\nexport function mapGraphNodesForECharts<T extends GraphInputNode>(\n  nodes: ReadonlyArray<T>,\n  extra?: (node: T, index: number) => Record<string, unknown>,\n): Record<string, unknown>[] {\n  return nodes.map((node, index) => {\n    const entry: Record<string, unknown> = { name: node.name };\n    if (node.value !== undefined) entry.value = node.value;\n    if (extra) Object.assign(entry, extra(node, index));\n    return entry;\n  });\n}\n\nexport function paintGraphNodes(\n  option: Record<string, unknown>,\n  seriesType: string,\n  nameToColor: ReadonlyMap<string, string>,\n): void {\n  const series = option.series as Record<string, unknown>[] | undefined;\n  if (!Array.isArray(series)) return;\n\n  for (const s of series) {\n    if (s.type !== seriesType) continue;\n    const nodes = s.data as Record<string, unknown>[] | undefined;\n    if (!Array.isArray(nodes)) continue;\n\n    for (const node of nodes) {\n      const name = node.name;\n      if (typeof name !== 'string') continue;\n\n      const existing = (node.itemStyle as Record<string, unknown> | undefined)\n        ?.color;\n      if (existing) continue;\n\n      const color = nameToColor.get(name);\n      if (color) {\n        node.itemStyle = {\n          ...(node.itemStyle as Record<string, unknown> | undefined),\n          color,\n        };\n      }\n    }\n  }\n}\n","import type { SankeyData, SankeyChartOptions, SankeyVariant } from '../types.js';\nimport type { RenderContext } from './index.js';\nimport { sankeyChordParamsToTooltipContext } from '../tooltip-context.js';\nimport { deepMerge, resolveColorsForNodes } from '../utils.js';\nimport {\n  buildTitle,\n  buildAsyncTooltipFormatter,\n  getLabelFontSize,\n  getTitleReserve,\n  resolveAppendToBody,\n  resolveTooltipPosition,\n} from './common/index.js';\nimport { mapGraphNodesForECharts, paintGraphNodes } from './common/graph-colors.js';\n\nfunction sankeyTooltipSyncHtml(params: unknown, options: SankeyChartOptions): string {\n  const fmt = options.tooltip?.formatValue;\n  const pr = params as Record<string, unknown>;\n  if (pr.dataType === 'edge') {\n    const data = pr.data as Record<string, unknown>;\n    const label = `${data.source} → ${data.target}`;\n    const v = fmt ? fmt(data.value as number, label) : data.value;\n    return `${label}: ${v}`;\n  }\n  return `${params && typeof params === 'object' && 'name' in params ? (params as { name: string }).name : ''}`;\n}\n\n/** Nodes with no outgoing links (terminal / sink): labels go left so they stay inside the grid. */\nfunction namesWithoutOutgoingLinks(links: SankeyData['links']): Set<string> {\n  const withOutgoing = new Set<string>();\n  for (const link of links) {\n    withOutgoing.add(link.source);\n  }\n  return withOutgoing;\n}\n\nexport function resolveSankeyOptions(\n  data: SankeyData,\n  options: SankeyChartOptions,\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const variant = (options.variant ?? 'default') as SankeyVariant;\n  const orient = variant === 'vertical' ? 'vertical' : 'horizontal';\n  const withOutgoing =\n    orient === 'horizontal' ? namesWithoutOutgoingLinks(data.links) : null;\n\n  const nodes = mapGraphNodesForECharts(data.nodes, (node) =>\n    withOutgoing && !withOutgoing.has(node.name) ? { label: { position: 'left' } } : {},\n  );\n\n  // Resolve the palette up front — `nameToColor` is consumed by both the\n  // tooltip context (so `customHtml`/`appendHtml` can surface node colors)\n  // and `paintGraphNodes` at the end of the function. Computing it once\n  // here keeps the two consumers in lockstep.\n  const colors = resolveColorsForNodes(data.nodes, options);\n  const nameToColor = new Map(data.nodes.map((n, i) => [n.name, colors[i]]));\n\n  const p = options.padding ?? 12;\n  const titleOffset = getTitleReserve(options).top;\n  const top = p + titleOffset;\n\n  const series: Record<string, unknown> = {\n    type: 'sankey',\n    orient,\n    layout: 'none',\n    emphasis: { focus: 'adjacency' },\n    data: nodes,\n    links: data.links,\n    top,\n    bottom: p,\n    left: p,\n    right: p,\n    label: {\n      position: orient === 'vertical' ? 'inside' : 'right',\n      fontSize: getLabelFontSize(options),\n    },\n    lineStyle: {\n      color: 'gradient',\n      curveness: 0.5,\n    },\n    nodeAlign: 'justify',\n    nodeGap: 12,\n    nodeWidth: 20,\n  };\n\n  const tooltip: Record<string, unknown> = {\n    trigger: 'item',\n    confine: true,\n    appendToBody: resolveAppendToBody(options, ctx),\n    position: resolveTooltipPosition(options),\n  };\n  const sankeyFormatter = buildAsyncTooltipFormatter({\n    options,\n    defaultSync: (params) => sankeyTooltipSyncHtml(params, options),\n    toContext: (params) => sankeyChordParamsToTooltipContext(params, nameToColor),\n  });\n  tooltip.formatter =\n    sankeyFormatter ?? ((params: unknown) => sankeyTooltipSyncHtml(params, options));\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    tooltip,\n    series: [series],\n  };\n\n  const merged = deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n\n  merged.color = colors;\n  paintGraphNodes(merged, 'sankey', nameToColor);\n\n  return merged;\n}\n","import type { ChordData, ChordChartOptions } from '../types.js';\nimport type { ChartSetupResult, RenderContext } from './index.js';\nimport { sankeyChordParamsToTooltipContext } from '../tooltip-context.js';\nimport { deepMerge, resolveColorsForNodes } from '../utils.js';\nimport {\n  buildTitle,\n  buildAsyncTooltipFormatter,\n  getLabelFontSize,\n  resolveAppendToBody,\n  resolveTooltipPosition,\n} from './common/index.js';\nimport { mapGraphNodesForECharts, paintGraphNodes } from './common/graph-colors.js';\n\nfunction chordTooltipSyncHtml(params: unknown, options: ChordChartOptions): string {\n  const fmt = options.tooltip?.formatValue;\n  const pr = params as Record<string, unknown>;\n  if (pr.dataType === 'edge') {\n    const d = pr.data as Record<string, unknown>;\n    const label = `${d.source} → ${d.target}`;\n    const v = fmt ? fmt(d.value as number, label) : d.value;\n    return `${label}: ${v}`;\n  }\n  return `${pr.name}`;\n}\n\n/**\n * Build an ECharts option using the native chord series introduced in v6.\n * Replaces the previous custom renderItem implementation (~400 lines) with\n * a thin mapping layer that delegates all layout and interactivity to ECharts.\n */\nexport function resolveChordOptions(\n  data: ChordData,\n  options: ChordChartOptions,\n  ctx?: RenderContext,\n): ChartSetupResult {\n  const p = options.padding ?? 12;\n\n  const nodes = mapGraphNodesForECharts(data.nodes);\n\n  // Resolve the palette up front — `nameToColor` is consumed by both the\n  // tooltip context (so `customHtml`/`appendHtml` can surface node and\n  // edge endpoint colors) and `paintGraphNodes` at the end of the\n  // function. Computing it once here keeps the two consumers in lockstep.\n  const colors = resolveColorsForNodes(data.nodes, options);\n  const nameToColor = new Map(data.nodes.map((n, i) => [n.name, colors[i]]));\n\n  const series: Record<string, unknown> = {\n    type: 'chord',\n    // Use left/right/bottom padding only; omitting `top` keeps the chord\n    // centred in the full container (center_y ≈ 50% of height).  The title\n    // naturally sits above without pushing the diagram down, giving a ~35 px\n    // gap regardless of container height — no magic formula required.\n    left: p,\n    right: p,\n    bottom: p,\n    radius: ['62%', '72%'],\n    startAngle: 90,\n    padAngle: 2,\n    data: nodes,\n    edges: data.links.map((l) => ({\n      source: l.source,\n      target: l.target,\n      value: l.value,\n    })),\n    lineStyle: {\n      color: 'gradient', // or 'source' (default), 'target',\n      opacity: 0.45,\n    },\n    label: {\n      show: true,\n      position: 'outside',\n      distance: 8,\n      fontSize: getLabelFontSize(options),\n    },\n    emphasis: {\n      focus: 'adjacency',\n      lineStyle: { opacity: 0.7 },\n    },\n  };\n\n  const tooltip: Record<string, unknown> = {\n    trigger: 'item',\n    confine: true,\n    show: options.tooltip?.enabled !== false,\n    appendToBody: resolveAppendToBody(options, ctx),\n    position: resolveTooltipPosition(options),\n  };\n  const chordFormatter = buildAsyncTooltipFormatter({\n    options,\n    defaultSync: (params) => chordTooltipSyncHtml(params, options),\n    toContext: (params) => sankeyChordParamsToTooltipContext(params, nameToColor),\n  });\n  tooltip.formatter =\n    chordFormatter ?? ((params: unknown) => chordTooltipSyncHtml(params, options));\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    tooltip,\n    series: [series],\n  };\n\n  const merged = deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n\n  merged.color = colors;\n  paintGraphNodes(merged, 'chord', nameToColor);\n\n  return { option: merged };\n}\n","import type { RadarData, RadarChartOptions, RadarVariant } from '../types.js';\nimport type { RenderContext } from './index.js';\nimport { deepMerge, resolveColors } from '../utils.js';\nimport {\n  type EdgeReserves,\n  buildTitle,\n  buildLegend,\n  getLegendReserve,\n  getTitleReserve,\n  resolveAppendToBody,\n  resolveTooltipPosition,\n} from './common/index.js';\n\n// ---------------------------------------------------------------------------\n// Layout constants\n// ---------------------------------------------------------------------------\n//\n// Radar is anchored by a percentage `center` (relative to the full canvas)\n// and a percentage `radius` (relative to half of `min(width, height)`). The\n// adapter doesn't know the runtime canvas size, so we convert pixel reserves\n// (title height, legend slot) to percent offsets against a reference card\n// size — the same chart-box dimensions used by every site demo. Charts\n// shorter/wider than the reference still render correctly; the radar just\n// occupies slightly more or less of the available space, which is fine for\n// a typical 320–480 px card. Users who need exact pixel control can set\n// `options.radius` and/or `options.echarts.radar.center` directly.\n\nconst RADAR_REFERENCE_HEIGHT = 320;\nconst RADAR_REFERENCE_WIDTH = 480;\n\n/** Baseline radius when nothing else is competing for canvas space. */\nconst RADAR_BASE_RADIUS_PCT = 65;\n\n/** Floor so the polygon never collapses to a postage stamp on cramped layouts. */\nconst RADAR_MIN_RADIUS_PCT = 45;\n\n/**\n * Extra pixel gap reserved between the radar's axisName labels and the\n * legend (or title) on the same edge. `LEGEND_RESERVE` covers only the\n * legend's own height — without this padding the polygon's outer\n * indicator labels visually touch the legend row because they extend\n * ~15 px past the polygon radius. Tuned by eye on the default 320 px\n * chart-box height; adjust if you change `axisName.padding` defaults.\n */\nconst RADAR_EDGE_GAP = 24;\n\n/**\n * Aggressiveness of the radius shrink as edge reserves grow. The product\n * `loss * RADAR_RADIUS_SHRINK_FACTOR` is the percentage points removed from\n * the baseline radius — picked so a single bottom legend (≈11% loss on a\n * 320 px card) shrinks from 65% → ≈61%, and a legend + title combined\n * (≈23% loss) shrinks to ≈57%. Lower values keep the polygon roomy at the\n * cost of pushing labels closer to the legend / title edges.\n */\nconst RADAR_RADIUS_SHRINK_FACTOR = 35;\n\nexport function resolveRadarOptions(\n  data: RadarData,\n  options: RadarChartOptions,\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const variant = (options.variant ?? 'default') as RadarVariant;\n  const names = data.series.map((s) => s.name);\n  const showLegend = options.legend?.show ?? names.length > 1;\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    legend: buildLegend(names, {\n      ...options,\n      legend: { ...options.legend, show: showLegend },\n    }),\n    tooltip: buildRadarTooltip(options, ctx),\n    radar: buildRadarComponent(data, options, variant, showLegend, names),\n    series: buildRadarSeries(data, options),\n  };\n\n  const merged = deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n  merged.color = resolveColors(names, options);\n  return merged;\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\n/**\n * Pixel reserves at each canvas edge driven by title + legend position.\n *\n * Delegates legend-slot math to the shared {@link getLegendReserve}\n * helper so a radar placed beside an XY chart agrees on how much space\n * the legend row needs (the XY grid path consumes the same helper via\n * {@link buildGrid}). Adds {@link RADAR_EDGE_GAP} as the `extraGap`\n * argument to account for radar.axisName labels overflowing the\n * polygon, and forwards `names` so side legends (left/right) get a\n * width-based slot rather than the 36 px row-height default.\n */\nfunction getEdgeReserves(\n  options: RadarChartOptions,\n  showLegend: boolean,\n  names: ReadonlyArray<string>,\n): EdgeReserves {\n  const p = options.padding ?? 12;\n  // Compose two EdgeReserves in the same edge math. Title contributes\n  // `p + h` (title-only paths add chart padding above the widget); we\n  // don't pre-add p inside getTitleReserve because percent-center math\n  // expects padding-free reserves — see EdgeReserves docblock.\n  const title = getTitleReserve(options);\n  const legend = getLegendReserve(options, showLegend, RADAR_EDGE_GAP, names);\n  return {\n    top: (title.top > 0 ? p + title.top : 0) + legend.top,\n    bottom: legend.bottom,\n    left: legend.left,\n    right: legend.right,\n  };\n}\n\nfunction buildRadarLayout(\n  options: RadarChartOptions,\n  showLegend: boolean,\n  names: ReadonlyArray<string>,\n): { center: (string | number)[]; radius: string | number } {\n  const reserves = getEdgeReserves(options, showLegend, names);\n\n  // Center: shift toward the side with more remaining space.\n  // shift_pct = (opposite_reserve - this_reserve) / (2 * REF) * 100\n  //           = (top - bottom) / REF * 50\n  const yShiftPct = ((reserves.top - reserves.bottom) / RADAR_REFERENCE_HEIGHT) * 50;\n  const xShiftPct = ((reserves.left - reserves.right) / RADAR_REFERENCE_WIDTH) * 50;\n\n  const centerX = Math.round(50 + xShiftPct);\n  const centerY = Math.round(50 + yShiftPct);\n\n  let radius: string | number;\n  if (options.radius !== undefined) {\n    radius = options.radius;\n  } else {\n    const verticalLoss = (reserves.top + reserves.bottom) / RADAR_REFERENCE_HEIGHT;\n    const horizontalLoss = (reserves.left + reserves.right) / RADAR_REFERENCE_WIDTH;\n    const loss = Math.max(verticalLoss, horizontalLoss);\n    const radiusPct = Math.max(\n      RADAR_MIN_RADIUS_PCT,\n      Math.round(RADAR_BASE_RADIUS_PCT - loss * RADAR_RADIUS_SHRINK_FACTOR),\n    );\n    radius = `${radiusPct}%`;\n  }\n\n  return {\n    center: [`${centerX}%`, `${centerY}%`],\n    radius,\n  };\n}\n\nfunction buildRadarComponent(\n  data: RadarData,\n  options: RadarChartOptions,\n  variant: RadarVariant,\n  showLegend: boolean,\n  names: ReadonlyArray<string>,\n): Record<string, unknown> {\n  const { center, radius } = buildRadarLayout(options, showLegend, names);\n  return {\n    indicator: data.indicators.map((ind) => ({\n      name: ind.name,\n      ...(ind.max !== undefined ? { max: ind.max } : {}),\n      ...(ind.min !== undefined ? { min: ind.min } : {}),\n    })),\n    shape: variant === 'circle' ? 'circle' : 'polygon',\n    center,\n    radius,\n    splitNumber: 4,\n  };\n}\n\nfunction buildRadarSeries(\n  data: RadarData,\n  options: RadarChartOptions,\n): Record<string, unknown>[] {\n  const filled = options.filled ?? true;\n  return [\n    {\n      type: 'radar',\n      symbol: 'circle',\n      symbolSize: 4,\n      lineStyle: { width: 2 },\n      ...(filled ? { areaStyle: { opacity: 0.2 } } : {}),\n      data: data.series.map((s) => ({ name: s.name, value: s.values })),\n    },\n  ];\n}\n\nfunction buildRadarTooltip(\n  options: RadarChartOptions,\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const tooltip: Record<string, unknown> = {\n    trigger: 'item',\n    confine: true,\n    padding: [6, 12],\n    textStyle: { fontWeight: 'normal' },\n    appendToBody: resolveAppendToBody(options, ctx),\n    position: resolveTooltipPosition(options),\n  };\n\n  if (options.tooltip?.enabled === false) {\n    tooltip.show = false;\n  }\n  return tooltip;\n}\n","import type {\n  NetworkData,\n  NetworkChartOptions,\n  NetworkLink,\n  NetworkNode,\n  NetworkVariant,\n} from '../types.js';\nimport type { RenderContext } from './index.js';\nimport { sankeyChordParamsToTooltipContext } from '../tooltip-context.js';\nimport { deepMerge, resolveColors, resolveColorsForNodes } from '../utils.js';\nimport {\n  buildLegend,\n  buildTitle,\n  buildAsyncTooltipFormatter,\n  getLabelFontSize,\n  getLegendReserve,\n  getTitleReserve,\n  resolveAppendToBody,\n  resolveTooltipPosition,\n} from './common/index.js';\nimport { paintGraphNodes } from './common/graph-colors.js';\nimport { DEFAULT_LABEL_FONT, measureMaxTextWidth } from './common/text-measure.js';\n\nconst DEFAULT_NODE_SIZE = 10;\nconst DEFAULT_NODE_SIZE_RANGE: readonly [number, number] = [10, 30];\nconst DEFAULT_REPULSION = 100;\nconst DEFAULT_EDGE_LENGTH = 60;\nconst DEFAULT_GRAVITY = 0.1;\n\n/**\n * Resolved node sizes strictly below this value get their label hidden\n * by default. Tuned to the `[10, 30]` `nodeSizeRange`: nodes whose\n * `value` lands in the bottom ~20 % of the data range scale into the\n * `< 14 px` bucket, which is the band where a label visually dominates\n * the marker and circular layouts read as label-soup. Users opt out\n * with `labelMinNodeSize: 0`, raise the threshold for more aggressive\n * pruning, or bypass entirely with `showAllLabels: true`. Has no effect\n * when `showNodeLabel: false` — that switch wipes labels globally.\n */\nconst DEFAULT_LABEL_MIN_NODE_SIZE = 14;\n\n/**\n * Distance (px) between a circular-layout label's outer end and the body\n * box edge. Small breathing room so labels don't kiss title / legend /\n * canvas edges even after we've reserved their full text width.\n */\nconst NETWORK_CIRCULAR_LABEL_GAP_PX = 8;\n\n/**\n * Hard cap (px) on circular-layout label overflow per body edge. Without\n * this, a single 50-char node name would shrink the ring to a dot. 200 px\n * ≈ 28 chars at the default 12 px sans-serif, which covers every\n * reasonable identifier; truly enormous names get clipped at the edge,\n * which is far less destructive than swallowing the chart body.\n */\nconst NETWORK_CIRCULAR_LABEL_MAX_RESERVE_PX = 200;\n\n/**\n * Resolve the per-edge body inset (px) needed for circular-layout label\n * overflow. `circular` arranges nodes on a ring with `rotateLabel: true`,\n * so ECharts renders each label tangent to the ring and the text extends\n * *outward* radially past the ring radius. The worst-case overflow on\n * any edge is the widest label's pixel width — a node at 12 o'clock\n * pushes its label up by that much, a node at 3 o'clock pushes right,\n * etc. Reserve `widestLabel + gap` on every side and the ring shrinks\n * just enough that no label bleeds into title / legend / canvas edges,\n * regardless of which angle each node ends up at.\n *\n * Same body-overflow pattern as `radar.axisName` (which uses a fixed\n * `RADAR_EDGE_GAP = 24` because indicator names are usually 1–2 words);\n * network node names vary wildly in length so we measure the actual\n * data instead of picking a fixed reserve. Falls back to a char-count\n * estimate via {@link measureMaxTextWidth} when canvas isn't available\n * (jsdom without layout, SSR), so tests get deterministic values.\n *\n * Returns 0 when `showNodeLabel: false` (no labels render → no\n * overflow needed) or when there are no nodes. Force layout doesn't\n * call this — gravity keeps nodes well inside the body, so labels at\n * `position: 'right'` rarely reach the edge.\n */\nfunction resolveCircularLabelOverflow(\n  data: NetworkData,\n  options: NetworkChartOptions,\n): number {\n  if (options.showNodeLabel === false) return 0;\n  if (data.nodes.length === 0) return 0;\n  const widest = measureMaxTextWidth(\n    data.nodes.map((n) => n.name),\n    DEFAULT_LABEL_FONT,\n  );\n  return Math.min(\n    widest + NETWORK_CIRCULAR_LABEL_GAP_PX,\n    NETWORK_CIRCULAR_LABEL_MAX_RESERVE_PX,\n  );\n}\n\n/**\n * Build the layout / variant-specific block of the graph series.\n *\n * Public variant names live on the user-facing API; this helper translates\n * them to ECharts' own `layout` field:\n *   - `default` → `'force'`  (physics-based simulation, library convention\n *                              calls the baseline \"default\" rather than\n *                              parroting ECharts' implementation name)\n *   - `circular` → `'circular'` (1:1 with ECharts)\n *\n * Users who need ECharts' `layout: 'none'` (manual x/y on every node) can\n * still reach it through the `options.echarts.series[0].layout` escape\n * hatch — that path bypasses this helper entirely.\n */\nfunction buildLayoutBlock(\n  variant: NetworkVariant,\n  options: NetworkChartOptions,\n  autoEdgeLength: number | undefined,\n): Record<string, unknown> {\n  if (variant === 'circular') {\n    return {\n      layout: 'circular',\n      circular: { rotateLabel: true },\n    };\n  }\n  // 'default' → force layout. Priority for `edgeLength`:\n  //   1. Explicit `options.edgeLength`            (user pin)\n  //   2. Container-aware `autoEdgeLength`         (when ctx available)\n  //   3. Static `DEFAULT_EDGE_LENGTH`             (SSR / jsdom fallback)\n  return {\n    layout: 'force',\n    force: {\n      repulsion: options.repulsion ?? DEFAULT_REPULSION,\n      edgeLength: options.edgeLength ?? autoEdgeLength ?? DEFAULT_EDGE_LENGTH,\n      gravity: options.gravity ?? DEFAULT_GRAVITY,\n      // Friction defaults are fine; expose later if needed.\n    },\n  };\n}\n\nfunction resolveRoamMode(\n  enablePan: boolean | undefined,\n  enableZoom: boolean | undefined,\n): boolean | 'move' | 'scale' {\n  const pan = enablePan ?? true;\n  const zoom = enableZoom ?? false;\n  if (pan && zoom) return true;\n  if (pan) return 'move';\n  if (zoom) return 'scale';\n  return false;\n}\n\n/**\n * Linearly map `value` from [vmin, vmax] into [smin, smax]. When all values\n * are equal we return the midpoint of the symbol-size range so every node\n * stays visible without flattening into a tiny dot.\n */\nfunction scaleSymbolSize(\n  value: number,\n  vmin: number,\n  vmax: number,\n  range: readonly [number, number],\n): number {\n  if (vmax === vmin) return (range[0] + range[1]) / 2;\n  const t = (value - vmin) / (vmax - vmin);\n  return range[0] + t * (range[1] - range[0]);\n}\n\n/** Derive an ordered category list from `data.categories` or the unique node categories. */\nfunction deriveCategories(data: NetworkData): string[] {\n  if (data.categories && data.categories.length > 0) return [...data.categories];\n  const seen = new Set<string>();\n  const out: string[] = [];\n  for (const node of data.nodes) {\n    if (node.category !== undefined && !seen.has(node.category)) {\n      seen.add(node.category);\n      out.push(node.category);\n    }\n  }\n  return out;\n}\n\n/**\n * Clamp bounds for the auto-sized fallback marker. 8 px keeps a node\n * recognisable on small cards / dense graphs; 40 px stops a sparse graph\n * in a huge container from drawing a few floating beach balls.\n */\nconst AUTO_NODE_SIZE_MIN_PX = 8;\nconst AUTO_NODE_SIZE_MAX_PX = 40;\n\n/**\n * Resolve the fallback marker size (px) for nodes that have no explicit\n * `value` and no per-node `size`. Mirrors the gauge `percentage`\n * variant's container-aware sizing pattern (see `gauge.ts` `autoSize…`):\n *\n *   1. Explicit `options.nodeSize` always wins.\n *   2. With a usable container (px reported via `RenderContext`), derive\n *      `ref / sqrt(n) * 0.10` clamped to `[MIN, MAX]`. The √n factor\n *      models \"linear pixels available per node along one axis\", so\n *      sparser graphs render bigger markers and dense ones shrink to\n *      keep labels readable. The 0.10 multiplier was tuned against the\n *      built-in demos:\n *        - 5 nodes in a ≈460 px card → ~21 px (deliberate, sparse)\n *        - 28 nodes in a ≈560 px card → ~11 px (matches the legacy\n *          static default so dense graphs look unchanged)\n *   3. SSR / jsdom / hidden-card paths have no usable dims → fall back\n *      to the static `DEFAULT_NODE_SIZE` so snapshots stay stable.\n *\n * Only consulted in the no-value branch — graphs whose nodes carry\n * `value` continue to map through `nodeSizeRange` exactly as before.\n * `core.ts` re-applies on `resize()`, so a window resize re-flows the\n * node markers in lockstep with the chart body.\n */\nfunction resolveDefaultNodeSize(\n  data: NetworkData,\n  options: NetworkChartOptions,\n  ctx: RenderContext | undefined,\n): number {\n  if (options.nodeSize !== undefined) return options.nodeSize;\n\n  const w = ctx?.containerWidth;\n  const h = ctx?.containerHeight;\n  if (\n    w === undefined ||\n    h === undefined ||\n    !Number.isFinite(w) ||\n    !Number.isFinite(h) ||\n    w <= 0 ||\n    h <= 0\n  ) {\n    return DEFAULT_NODE_SIZE;\n  }\n\n  const ref = Math.min(w, h);\n  const n = Math.max(1, data.nodes.length);\n  const computed = (ref / Math.sqrt(n)) * 0.10;\n  return Math.max(\n    AUTO_NODE_SIZE_MIN_PX,\n    Math.min(AUTO_NODE_SIZE_MAX_PX, Math.round(computed)),\n  );\n}\n\n/**\n * Clamp bounds for the auto-sized force-layout `edgeLength` (px).\n *   - 30 px: ECharts' own native default for `force.edgeLength`. Anything\n *     smaller would let the spring constraint overwhelm node markers and\n *     make labels collide regardless of `labelLayout`.\n *   - 250 px: prevents 2-node demos in a giant container from settling\n *     so far apart they fall off-screen — gravity does pull nodes back,\n *     but at very long springs the equilibrium drifts beyond the body.\n */\nconst AUTO_EDGE_LENGTH_MIN_PX = 30;\nconst AUTO_EDGE_LENGTH_MAX_PX = 250;\n\n/**\n * Body-aware default for the force layout's `edgeLength` so the cluster\n * fills the area *outside* the title + legend reserves without the user\n * having to set anything. The previous version used raw container dims,\n * which over-counted on cards with a tall title or a side legend — the\n * cluster would happily extend into the reserved area.\n *\n * The body box passed in here is the same `containerW/H − reserves` math\n * the resolver uses for `series.top/bottom/left/right`, so the spring\n * calibration tracks whatever space ECharts has actually reserved for\n * the graph series. Title taller? Smaller `bodyHeight` → tighter springs.\n * Side legend? Smaller `bodyWidth` → tighter springs along that axis.\n *\n * Formula: `ref / sqrt(nodeCount) * 0.6`, where `ref = min(bodyW, bodyH)`.\n * Same \"linear pixels available per node along one axis\" heuristic as\n * `resolveDefaultNodeSize` (so markers and edge lengths scale in lockstep\n * when the body changes). The 0.6 multiplier is calibrated so the\n * canonical 16-node × ~480-px-tall demo with title + legend (body height\n * ≈ 394 px after subtracting ~80 px of reserves) lands exactly on the\n * legacy 60-px default — existing demos look pixel-identical, while\n * sparse graphs and chrome-less cards expand to fill the available body.\n *\n * Returns `undefined` when body dims aren't usable (SSR, jsdom, hidden\n * card, or `body ≤ 0` after huge reserves) so the caller can fall back\n * to the static `DEFAULT_EDGE_LENGTH` and keep snapshots stable. Explicit\n * `options.edgeLength` always wins. `core.ts` re-applies on `resize()`,\n * so a window resize re-flows the force simulation in lockstep with the\n * marker auto-sizing.\n */\nfunction resolveAutoEdgeLength(\n  nodeCount: number,\n  bodyWidth: number | undefined,\n  bodyHeight: number | undefined,\n): number | undefined {\n  if (\n    bodyWidth === undefined ||\n    bodyHeight === undefined ||\n    !Number.isFinite(bodyWidth) ||\n    !Number.isFinite(bodyHeight) ||\n    bodyWidth <= 0 ||\n    bodyHeight <= 0\n  ) {\n    return undefined;\n  }\n\n  const ref = Math.min(bodyWidth, bodyHeight);\n  const n = Math.max(1, nodeCount);\n  const computed = (ref / Math.sqrt(n)) * 0.6;\n  return Math.max(\n    AUTO_EDGE_LENGTH_MIN_PX,\n    Math.min(AUTO_EDGE_LENGTH_MAX_PX, Math.round(computed)),\n  );\n}\n\nfunction buildNodeData(\n  data: NetworkData,\n  options: NetworkChartOptions,\n  catToIdx: ReadonlyMap<string, number>,\n  defaultSize: number,\n): Record<string, unknown>[] {\n  const range = options.nodeSizeRange ?? DEFAULT_NODE_SIZE_RANGE;\n\n  // Compute value range once for proportional node sizing.\n  let vmin = Infinity;\n  let vmax = -Infinity;\n  for (const node of data.nodes) {\n    if (typeof node.value === 'number' && Number.isFinite(node.value)) {\n      if (node.value < vmin) vmin = node.value;\n      if (node.value > vmax) vmax = node.value;\n    }\n  }\n  const hasValueRange = vmin !== Infinity && vmax !== -Infinity;\n\n  // Per-node label gating by resolved size. Three flags participate:\n  //   - `showNodeLabel: false` → no labels at all; nothing to gate here.\n  //   - `showAllLabels: true`  → user explicitly opted into \"show every\n  //                              label, accept overlap\"; size threshold\n  //                              must also stand down or the flag is a\n  //                              no-op for circular (the exact reason\n  //                              this helper exists).\n  //   - `labelMinNodeSize: 0`  → user opted out of size-based hiding.\n  // Otherwise nodes whose resolved size is strictly below the threshold\n  // get a per-node `label: { show: false }`, which ECharts deep-merges\n  // over the series-level `label.show: true` we set in the adapter —\n  // single-node opt-out, no overlap math involved. The size we compare\n  // against is the value we write into ECharts' `symbolSize` data field\n  // (renamed `size` on the user-facing `NetworkNode`, but ECharts'\n  // protocol still expects `symbolSize` on the series data entry).\n  const minNodeSize = options.labelMinNodeSize ?? DEFAULT_LABEL_MIN_NODE_SIZE;\n  const gateLabelBySize =\n    options.showNodeLabel !== false &&\n    !options.showAllLabels &&\n    minNodeSize > 0;\n\n  return data.nodes.map((node) => {\n    const entry: Record<string, unknown> = { name: node.name };\n\n    if (node.value !== undefined) entry.value = node.value;\n\n    if (node.category !== undefined) {\n      const idx = catToIdx.get(node.category);\n      if (idx !== undefined) entry.category = idx;\n    }\n\n    // `entry.symbolSize` is the ECharts series-data field name (graph\n    // protocol); the user-facing equivalent on `NetworkNode` is `size`.\n    if (node.size !== undefined) {\n      entry.symbolSize = node.size;\n    } else if (typeof node.value === 'number' && hasValueRange) {\n      entry.symbolSize = scaleSymbolSize(node.value, vmin, vmax, range);\n    } else {\n      entry.symbolSize = defaultSize;\n    }\n\n    if (node.x !== undefined) entry.x = node.x;\n    if (node.y !== undefined) entry.y = node.y;\n    if (node.fixed) entry.fixed = true;\n\n    if (node.color) {\n      entry.itemStyle = { color: node.color };\n    }\n\n    if (gateLabelBySize && (entry.symbolSize as number) < minNodeSize) {\n      entry.label = { show: false };\n    }\n\n    return entry;\n  });\n}\n\nfunction buildLinkData(links: NetworkLink[]): Record<string, unknown>[] {\n  return links.map((l) => {\n    const entry: Record<string, unknown> = { source: l.source, target: l.target };\n    if (l.value !== undefined) entry.value = l.value;\n    // Per-link curveness writes through `lineStyle.curveness` so it deep-merges\n    // over the series-level `lineStyle.curveness` we set below from\n    // `options.edgeCurveness`. Negative values bend the line the other way,\n    // which is the canonical bidirectional-edge trick (A→B positive, B→A\n    // negative ⇒ two arcs that don't overlap).\n    if (l.curveness !== undefined) {\n      entry.lineStyle = { curveness: l.curveness };\n    }\n    return entry;\n  });\n}\n\nfunction networkTooltipSyncHtml(params: unknown, options: NetworkChartOptions): string {\n  const fmt = options.tooltip?.formatValue;\n  const pr = params as Record<string, unknown>;\n  if (pr.dataType === 'edge') {\n    const d = pr.data as Record<string, unknown>;\n    const label = `${d.source} → ${d.target}`;\n    const v = d.value;\n    if (v === undefined) return label;\n    const display = fmt ? fmt(v as number, label) : v;\n    return `${label}: ${display}`;\n  }\n  // Node hover. ECharts injects a colored marker bullet via `params.marker`.\n  const marker = (pr.marker as string) ?? '';\n  const name = String(pr.name ?? '');\n  const value = pr.value;\n  if (value === undefined) return `${marker}${name}`;\n  const display = fmt ? fmt(value as number, name) : value;\n  return `${marker}${name}: ${display}`;\n}\n\nexport function resolveNetworkOptions(\n  data: NetworkData,\n  options: NetworkChartOptions,\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const variant = (options.variant ?? 'default') as NetworkVariant;\n  const categories = deriveCategories(data);\n  const catToIdx = new Map(categories.map((c, i) => [c, i]));\n  const hasCategories = categories.length > 0;\n\n  // Network has its own legend default: show iff we have categories the user\n  // can actually toggle. Single-category graphs (or none) hide the legend\n  // because there's nothing meaningful to click.\n  const showLegend = options.legend?.show ?? hasCategories;\n\n  // Layout reserves — body-centered chart, mirrors radar / pie / gauge.\n  const p = options.padding ?? 12;\n  const titleR = getTitleReserve(options).top;\n  // Pass `categories` so a side legend (left/right) sizes its slot to the\n  // widest category label, just like radar does for series names.\n  const legendR = getLegendReserve(options, showLegend, 0, categories);\n\n  // Force layout (`default`) is dragged to refine node placement; the\n  // circular layout is fixed by construction so dragging it is meaningless\n  // by default. Users can still opt in via `options.draggable: true`.\n  const draggable = options.draggable ?? variant === 'default';\n  const roam = resolveRoamMode(options.enablePan, options.enableZoom);\n\n  // `circular` arranges every node around the same ring, so straight edges\n  // would all converge through the center and pile up into an unreadable\n  // mess. ECharts' own circular-layout example uses curveness 0.3, which\n  // separates the bands and reads cleanly. Force layout doesn't have that\n  // problem (edges follow physics) so it stays at 0. Explicit\n  // `edgeCurveness` always wins.\n  const defaultCurveness = variant === 'circular' ? 0.3 : 0;\n  const curveness = options.edgeCurveness ?? defaultCurveness;\n\n  // Body-overflow allowance for circular-layout labels — see\n  // `resolveCircularLabelOverflow` for the radial-extent rationale.\n  // Composed *on top of* the title + legend reserves so the ring shrinks\n  // regardless of whether title/legend are present.\n  const labelOverflow =\n    variant === 'circular' ? resolveCircularLabelOverflow(data, options) : 0;\n\n  // Container-aware fallback for nodes without a `value` — see the helper.\n  // Computed once at the resolver level so every node sees the same number.\n  const defaultNodeSize = resolveDefaultNodeSize(data, options, ctx);\n\n  // Body-box insets — single source of truth for both `series.top/…` (sets\n  // the visible chart area) and `resolveAutoEdgeLength` (sizes the springs\n  // to that same area). Keeping them in sync is what makes the \"fill the\n  // area outside title + legend\" guarantee actually hold.\n  const topInset = p + titleR + legendR.top + labelOverflow;\n  const bottomInset = p + legendR.bottom + labelOverflow;\n  const leftInset = p + legendR.left + labelOverflow;\n  const rightInset = p + legendR.right + labelOverflow;\n\n  // Body dims = container − insets. Undefined when ECharts hasn't given\n  // us usable dims yet (SSR / hidden card) so the helper can fall back.\n  const bodyWidth =\n    ctx?.containerWidth !== undefined && Number.isFinite(ctx.containerWidth)\n      ? ctx.containerWidth - leftInset - rightInset\n      : undefined;\n  const bodyHeight =\n    ctx?.containerHeight !== undefined && Number.isFinite(ctx.containerHeight)\n      ? ctx.containerHeight - topInset - bottomInset\n      : undefined;\n\n  // Body-aware fallback for the force layout's `edgeLength` so sparse\n  // graphs fan out to fill the body, and dense graphs / chrome-heavy\n  // cards (tall title, side legend) shrink the springs to fit. Returns\n  // `undefined` for SSR / jsdom / `body ≤ 0` paths so the static default\n  // kicks in. Only consulted by the force branch; circular ignores it.\n  const autoEdgeLength = resolveAutoEdgeLength(data.nodes.length, bodyWidth, bodyHeight);\n\n  // Global label fontSize — node labels and edge labels share the same\n  // size (the previous 12/11 split was a token visual hint that didn't\n  // survive `ChartOptions.labelFontSize` overrides cleanly; keeping them\n  // identical makes user intent — \"make all labels bigger\" — predictable).\n  const labelFontSize = getLabelFontSize(options);\n\n  const series: Record<string, unknown> = {\n    type: 'graph',\n    ...buildLayoutBlock(variant, options, autoEdgeLength),\n    top: topInset,\n    bottom: bottomInset,\n    left: leftInset,\n    right: rightInset,\n    roam,\n    draggable,\n    data: buildNodeData(data, options, catToIdx, defaultNodeSize),\n    links: buildLinkData(data.links),\n    categories: hasCategories ? categories.map((name) => ({ name })) : undefined,\n    label: {\n      show: options.showNodeLabel ?? true,\n      position: 'right',\n      fontSize: labelFontSize,\n    },\n    edgeLabel: options.showLinkLabel\n      ? {\n          show: true,\n          fontSize: labelFontSize,\n          formatter: (p2: { value?: unknown }) =>\n            p2.value === undefined ? '' : String(p2.value),\n        }\n      : { show: false },\n    lineStyle: {\n      color: 'source',\n      curveness,\n      opacity: 0.6,\n      width: 1,\n    },\n    emphasis: {\n      focus: 'adjacency',\n      lineStyle: { width: 2, opacity: 0.9 },\n    },\n  };\n\n  // Default mode: let ECharts auto-hide overlapping node + edge labels so\n  // dense graphs stay readable. ECharts walks every label's bounding box\n  // and drops the ones that collide, keeping the most-spread-out subset\n  // visible. Users opt into \"show every label\" by setting\n  // `showAllLabels: true` — useful for small graphs or presentations\n  // where every name matters and overlap is acceptable.\n  if (!options.showAllLabels) {\n    series.labelLayout = { hideOverlap: true };\n  }\n\n  // Resolve the palette up front — `nameToColor` is consumed by both the\n  // tooltip context (so `customHtml`/`appendHtml` can surface node and\n  // edge endpoint colors) and the final `merged.color` / `paintGraphNodes`\n  // assignment below. Computing it once here keeps the two consumers in\n  // lockstep.\n  //\n  // Color assembly: categories own the palette (so the legend swatch and\n  // every member node share the same color). Per-node `color` overrides\n  // (already projected onto `itemStyle.color` from `buildNodeData`) win\n  // over the category color in the `nameToColor` map too, so a tooltip\n  // never reports a different color than ECharts paints. Networks without\n  // categories fall back to one color per node so the graph doesn't\n  // render as a single-color blob.\n  let paletteColors: string[];\n  const nameToColor = new Map<string, string>();\n  if (hasCategories) {\n    paletteColors = resolveColors(categories, options);\n    for (const node of data.nodes) {\n      if (node.color) {\n        nameToColor.set(node.name, node.color);\n        continue;\n      }\n      const idx =\n        node.category !== undefined ? catToIdx.get(node.category) : undefined;\n      if (idx !== undefined) {\n        nameToColor.set(node.name, paletteColors[idx]);\n      }\n    }\n  } else {\n    paletteColors = resolveColorsForNodes(data.nodes, options);\n    data.nodes.forEach((n: NetworkNode, i) => {\n      nameToColor.set(n.name, n.color ?? paletteColors[i]);\n    });\n  }\n\n  const tooltip: Record<string, unknown> = {\n    trigger: 'item',\n    confine: true,\n    show: options.tooltip?.enabled !== false,\n    appendToBody: resolveAppendToBody(options, ctx),\n    position: resolveTooltipPosition(options),\n  };\n  const networkFormatter = buildAsyncTooltipFormatter({\n    options,\n    defaultSync: (params) => networkTooltipSyncHtml(params, options),\n    toContext: (params) => sankeyChordParamsToTooltipContext(params, nameToColor),\n  });\n  tooltip.formatter =\n    networkFormatter ?? ((params: unknown) => networkTooltipSyncHtml(params, options));\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    legend: buildLegend(categories, {\n      ...options,\n      legend: { ...options.legend, show: showLegend },\n    }),\n    tooltip,\n    series: [series],\n  };\n\n  const merged = deepMerge(eOption, (options.echarts ?? {}) as Record<string, unknown>);\n\n  merged.color = paletteColors;\n  if (!hasCategories) {\n    paintGraphNodes(merged, 'graph', nameToColor);\n  }\n\n  return merged;\n}\n","import type {\n  TreeData,\n  TreeNode,\n  TreeChartOptions,\n  TreeDirection,\n  TreeNodeIconSpec,\n} from '../types.js';\nimport type { ChartSetupResult, RenderContext } from './index.js';\nimport { sankeyChordParamsToTooltipContext } from '../tooltip-context.js';\nimport { getConfig } from '../config.js';\nimport { deepMerge, resolveColors } from '../utils.js';\nimport {\n  applyConfiguredFontFamilyToOption,\n  buildTitle,\n  buildAsyncTooltipFormatter,\n  compileRichText,\n  getLabelFontSize,\n  getTitleReserve,\n  measureCompiledLabelWidth,\n  mergeCompiledRichStyles,\n  renderIconDataUrl,\n  resolveAppendToBody,\n  resolveTooltipPosition,\n} from './common/index.js';\n\n/**\n * Default node marker diameter (px). Matches the ECharts `tree-basic`\n * example, which is calibrated so a 12 px label sits cleanly next to the\n * symbol without crowding.\n */\nconst DEFAULT_NODE_SIZE = 7;\n\n/**\n * Breathing room (px) between the rendered label glyph and the canvas\n * edge — keeps the text from kissing the chart's outer border even\n * after we've reserved its full pixel width.\n */\nconst TREE_LABEL_GAP_PX = 10;\n\n/**\n * Hard cap (px) on label-overflow reserve per edge. Without this, a\n * single 60-char node name could shrink the tree body to nothing —\n * mirroring the `NETWORK_CIRCULAR_LABEL_MAX_RESERVE_PX` policy used by\n * the network adapter's circular variant. 200 px ≈ 28 chars at the\n * default 12 px sans-serif, which covers every reasonable identifier;\n * truly enormous names get clipped at the edge (a far less destructive\n * failure than swallowing the whole chart body).\n */\nconst TREE_LABEL_MAX_RESERVE_PX = 200;\n\n/**\n * Floor (px) on label-overflow reserve per edge — applied to whichever\n * edges actually receive a label-driven reserve (i.e. *not* the\n * perpendicular axes in horizontal layouts). Guarantees enough room for\n * a short label like \"A\" even when measurement is unavailable (SSR /\n * jsdom without canvas layout). Tuned to the default 12 px font:\n * `'Frontend'` measures ~55 px, `'CEO'` ~25 px; 40 px is the threshold\n * where a one-word label looks padded rather than crammed.\n */\nconst TREE_LABEL_MIN_RESERVE_PX = 40;\n\n/**\n * Approximate line-height ratio for the default sans-serif label font.\n * Used to derive the *perpendicular-axis* reserve in vertical layouts\n * (TB/BT): rotated -90° labels are a thin vertical strip whose\n * horizontal extent equals one line-height, anchored on the node's\n * x-position — so `fontSize * ratio / 2 + gap` per side is plenty.\n *\n * Multiplying by the effective `labelFontSize` (rather than baking in a\n * fixed 18 px) keeps the perp slot proportional when the user overrides\n * `ChartOptions.labelFontSize` — e.g. raising the global label size to\n * 18 px would otherwise leave vertical-layout side reserves too tight,\n * letting the leftmost / rightmost rotated labels kiss the canvas edge.\n */\nconst TREE_LABEL_LINE_HEIGHT_RATIO = 1.5;\n\n/**\n * Per-direction layout metadata. Two label-rendering regimes:\n *\n * `'horizontal'` layouts (`'LR'`, `'RL'`) — labels render horizontally,\n * extending OUTSIDE each node along the X axis. Parent labels grow\n * toward the root edge, leaf labels grow toward the opposite edge.\n * Both side edges therefore need a label-width reserve; vertical\n * clipping is just half line-height (negligible next to padding).\n *\n * `'vertical'` layouts (`'TB'`, `'BT'`) — labels are rotated 90° so they\n * read in the same direction the tree grows: `'TB'` rotates labels\n * **clockwise** (`-90`) so text reads top-to-bottom alongside a\n * downward-growing tree; `'BT'` rotates labels **counter-clockwise**\n * (`+90`) so text reads bottom-to-top alongside an upward-growing tree.\n *\n * Practical wins of rotated labels in vertical layouts:\n *   - tall narrow node names (\"AgglomerativeCluster\") fit naturally in\n *     a deep vertical tree without overlapping horizontal neighbours;\n *   - the perpendicular (horizontal) axis only needs ~half font-height\n *     of reserve, freeing up canvas width for the actual tree spread.\n *\n * After rotation, the label's unrotated text-width becomes vertical\n * extent, so the active axis (top/bottom) needs a full label-width\n * reserve — same formula as horizontal layouts. The reserve math is\n * rotation-sign-agnostic: ±90° both produce the same bounding box.\n */\ninterface DirectionLayout {\n  orient: 'LR' | 'RL' | 'TB' | 'BT';\n  axis: 'horizontal' | 'vertical';\n  parentPosition: 'left' | 'right' | 'top' | 'bottom';\n  parentAlign: 'left' | 'right' | 'center';\n  leafPosition: 'left' | 'right' | 'top' | 'bottom';\n  leafAlign: 'left' | 'right' | 'center';\n  /**\n   * Rotation (degrees) applied to BOTH parent and leaf labels — ECharts\n   * convention: positive = counter-clockwise.\n   *   - `0` keeps labels horizontal (LR/RL).\n   *   - `-90` rotates clockwise so text reads top-to-bottom (TB).\n   *   - `+90` rotates counter-clockwise so text reads bottom-to-top (BT).\n   * The sign tracks the tree growth direction, so the reading direction\n   * always matches the tree's flow.\n   */\n  labelRotate: number;\n  /** Canvas edge the root (and parent labels) grow toward. */\n  rootEdge: 'top' | 'bottom' | 'left' | 'right';\n  /** Canvas edge the leaves (and leaf labels) grow toward. */\n  leafEdge: 'top' | 'bottom' | 'left' | 'right';\n}\n\nconst DIRECTION_LAYOUT: Record<TreeDirection, DirectionLayout> = {\n  LR: {\n    orient: 'LR',\n    axis: 'horizontal',\n    parentPosition: 'left',\n    parentAlign: 'right',\n    leafPosition: 'right',\n    leafAlign: 'left',\n    labelRotate: 0,\n    rootEdge: 'left',\n    leafEdge: 'right',\n  },\n  RL: {\n    orient: 'RL',\n    axis: 'horizontal',\n    parentPosition: 'right',\n    parentAlign: 'left',\n    leafPosition: 'left',\n    leafAlign: 'right',\n    labelRotate: 0,\n    rootEdge: 'right',\n    leafEdge: 'left',\n  },\n  // 'TB': clockwise rotation (`-90`). Text reads top-to-bottom alongside\n  // the tree. With `rotate: -90`, the unrotated text's RIGHT end lands\n  // at the BOTTOM of the rendered glyph — so to anchor parent labels\n  // above the node (and grow them UPWARD into the top reserve) we use\n  // `align: 'right'`. Leaf labels mirror with `align: 'left'`.\n  TB: {\n    orient: 'TB',\n    axis: 'vertical',\n    parentPosition: 'top',\n    parentAlign: 'right',\n    leafPosition: 'bottom',\n    leafAlign: 'left',\n    labelRotate: -90,\n    rootEdge: 'top',\n    leafEdge: 'bottom',\n  },\n  // 'BT': counter-clockwise rotation (`+90`) so text reads bottom-to-top,\n  // matching the tree's upward growth direction. With `rotate: +90`\n  // the unrotated text's RIGHT end lands at the TOP of the rendered\n  // glyph — flipped vs. 'TB'. To anchor parent labels BELOW the node\n  // (and grow them DOWNWARD into the bottom reserve), we still need\n  // the rotated bottom to sit on the anchor: that's `align: 'right'`\n  // (whose unrotated right-end is now the rotated top), so the\n  // unrotated left-end (rotated bottom) sits at the anchor and text\n  // grows away from the node. Leaf labels mirror with `align: 'left'`.\n  BT: {\n    orient: 'BT',\n    axis: 'vertical',\n    parentPosition: 'bottom',\n    parentAlign: 'right',\n    leafPosition: 'top',\n    leafAlign: 'left',\n    labelRotate: 90,\n    rootEdge: 'bottom',\n    leafEdge: 'top',\n  },\n};\n\n/**\n * Walk the tree and collect every node name in pre-order. The resulting\n * array drives the palette lookup via {@link resolveColors} — one color\n * per node, in traversal order.\n */\nfunction collectNodeNames(root: TreeNode): string[] {\n  const out: string[] = [];\n  const visit = (node: TreeNode): void => {\n    out.push(node.name);\n    if (node.children) for (const child of node.children) visit(child);\n  };\n  visit(root);\n  return out;\n}\n\n/**\n * Names split by ECharts' \"leaf vs parent\" distinction — leaves are\n * nodes with no `children`, everything else is a parent (including\n * the root and any intermediate node). The two groups receive\n * different label `position` defaults from this adapter (parents on\n * the root-side, leaves on the opposite side), so we measure them\n * separately for the body-reserve math.\n */\ninterface SplitNodeNames {\n  leafLabels: Array<{ name: string; compiled: ReturnType<typeof compileRichText> }>;\n  parentLabels: Array<{ name: string; compiled: ReturnType<typeof compileRichText> }>;\n}\n\nconst TREE_LABEL_TOKEN_KEY = '__ichLabelText';\nconst TREE_ICON_META_KEY = '__ichIconMeta';\n\n/**\n * Fallback border / fill color when the resolver doesn't surface a\n * palette color for a node (e.g. the node's name isn't in the resolved\n * `names` array, which shouldn't happen for tree adapters but is\n * defensive). Slate-400-equivalent — visible against both light and\n * dark themes without screaming for attention. Adapters elsewhere use\n * the same neutral as a last-resort defensive color.\n */\nconst TREE_ICON_FALLBACK_COLOR = '#94a3b8';\n\n/**\n * Icon→label gap calibration for nodes that carry a custom icon\n * (`formatNodeIcon` returned an `image` / `circle` spec). ECharts'\n * default `label.distance` is 5 px — fine for a 7 px dot, but reads\n * as cramped as soon as the symbol carries any real visual mass\n * (avatars, logos, app icons). We scale the gap proportionally to the\n * icon's larger dimension and clamp at a comfortable floor:\n *\n *   distance = max(round(maxIconDim * RATIO), FLOOR)\n *\n * Calibration:\n *   - 36 px avatar → 12 px gap (comfortable list-item spacing)\n *   - 24 px icon  → 8 px (clamped to floor; tight icons don't need\n *                          loose labels)\n *   - 12 px badge → 8 px (floor)\n *\n * Why 1/3 + an 8 px floor (vs. a fixed bump or a single magic number)?\n *   - The 1/3 ratio echoes typographic spacing rules of thumb (caption\n *     gap ≈ 1/3 of the visual element it labels) so it scales with\n *     custom sizes without surprising users.\n *   - The 8 px floor matches the smallest gap that consistently reads\n *     as \"intentional space\" rather than \"rendering glitch\" at typical\n *     label font sizes (12–14 px) — anything smaller and the label\n *     looks glued to the icon.\n *\n * Only applied when the node carries a custom icon. Default 7 px dot\n * nodes keep ECharts' built-in 5 px gap so existing layouts that\n * don't opt into `formatNodeIcon` see no reflow.\n */\nconst TREE_ICON_LABEL_DISTANCE_RATIO = 1 / 3;\nconst TREE_ICON_LABEL_DISTANCE_FLOOR_PX = 8;\n\n/**\n * Metadata stashed on each node whose icon needs the canvas baking\n * pipeline. Two flavors of node end up with this:\n *\n *   - `shape: 'circle'` — *always* needs the canvas (for the circular\n *     clip + contain-fit), regardless of border. Sync placeholder is\n *     a `circle` ECharts symbol with palette fill (and palette ring\n *     when `borderWidth > 0`).\n *   - `shape: 'rect'`  — only when `borderWidth > 0`. Without a\n *     border, square icons skip canvas baking entirely and use a\n *     plain `image://<URL>` symbol that ECharts loads natively. With\n *     a border, the only way to draw a frame around an image symbol\n *     is to bake it into the bitmap (ECharts ignores\n *     `itemStyle.border*` on image symbols), so the rect goes through\n *     the same async-swap pipeline as circles. Sync placeholder is\n *     a `rect` ECharts symbol (which DOES respect `itemStyle.border*`\n *     because it's a shape symbol, not an image symbol).\n *\n * The metadata lives in a private symbol-keyed property so\n * {@link createTreeIconOnInit} can walk the tree post-render and\n * asynchronously swap each placeholder for a pre-composited\n * `image://<dataUrl>` symbol — see {@link renderIconDataUrl} for the\n * bitmap pipeline.\n */\ninterface IconMeta {\n  shape: 'circle' | 'rect';\n  src: string;\n  width: number;\n  height: number;\n  borderColor: string;\n  /** `0` means no border (canvas helper skips the stroke). */\n  borderWidth: number;\n}\n\nfunction isRichTextSpecLike(\n  value: unknown,\n): value is Extract<Parameters<typeof compileRichText>[0], object> {\n  if (typeof value !== 'object' || value === null) return false;\n  if (!('segments' in value)) return false;\n  return Array.isArray((value as { segments?: unknown }).segments);\n}\n\nfunction splitNodeNames(root: TreeNode, options: TreeChartOptions): SplitNodeNames {\n  const leafLabels: Array<{ name: string; compiled: ReturnType<typeof compileRichText> }> = [];\n  const parentLabels: Array<{ name: string; compiled: ReturnType<typeof compileRichText> }> =\n    [];\n  let labelIndex = 0;\n  const visit = (node: TreeNode, depth: number): void => {\n    if (node.children && node.children.length > 0) {\n      parentLabels.push({\n        name: node.name,\n        compiled: compileNodeLabel(\n          node,\n          depth,\n          false,\n          options,\n          `treeLabel_${labelIndex++}`,\n        ),\n      });\n      for (const child of node.children) visit(child, depth + 1);\n    } else {\n      leafLabels.push({\n        name: node.name,\n        compiled: compileNodeLabel(node, depth, true, options, `treeLabel_${labelIndex++}`),\n      });\n    }\n  };\n  visit(root, 0);\n  return { leafLabels, parentLabels };\n}\n\nfunction compileNodeLabel(\n  node: TreeNode,\n  depth: number,\n  isLeaf: boolean,\n  options: TreeChartOptions,\n  keyPrefix: string,\n): ReturnType<typeof compileRichText> {\n  const ctx = { node, name: node.name, depth, isLeaf };\n  const formatter = options.formatNodeLabel;\n  let base = compileRichText(node.name, keyPrefix);\n  try {\n    if (formatter) {\n      const out = formatter(ctx);\n      if (typeof out === 'string' || isRichTextSpecLike(out)) {\n        base = compileRichText(out, keyPrefix);\n      }\n    }\n  } catch {\n    // Fallback to raw node name when formatter fails.\n  }\n  return base;\n}\n\nfunction resolveTreeIconSpec(\n  formatter: NonNullable<TreeChartOptions['formatNodeIcon']>,\n  ctx: { node: TreeNode; name: string; depth: number; isLeaf: boolean },\n): TreeNodeIconSpec | undefined {\n  try {\n    const out = formatter(ctx);\n    if (!out) return undefined;\n    if (typeof out === 'string') return { image: out };\n    if (typeof out === 'object' && typeof out.image === 'string') return out;\n    return undefined;\n  } catch {\n    return undefined;\n  }\n}\n\nfunction measureWidestCompiledLabel(\n  labels: ReadonlyArray<{ name: string; compiled: ReturnType<typeof compileRichText> }>,\n): number {\n  let widest = 0;\n  for (const label of labels) {\n    widest = Math.max(widest, measureCompiledLabelWidth(label.compiled));\n  }\n  return widest;\n}\n\n/** Clamp a label-driven reserve into `[MIN, MAX]`, then add the gap. */\nfunction clampLabelReserve(widestPx: number): number {\n  if (widestPx <= 0) return 0;\n  const withGap = widestPx + TREE_LABEL_GAP_PX;\n  return Math.max(\n    TREE_LABEL_MIN_RESERVE_PX,\n    Math.min(TREE_LABEL_MAX_RESERVE_PX, withGap),\n  );\n}\n\n/**\n * Walk the tree, producing a deep copy of the ECharts-shaped node tree.\n *\n * Adapter responsibilities at each level:\n *   - copy `name` and (when present) `value` straight through;\n *   - honor `collapsed` from input;\n *   - assemble `itemStyle.color` from the resolved palette OR the\n *     per-node `node.color` override (override wins).\n *\n * Returns a plain object that ECharts can consume directly. Mutation of\n * the returned tree is safe — none of the original `TreeNode` instances\n * are reused.\n */\nfunction annotateTree(\n  root: TreeNode,\n  nameToColor: ReadonlyMap<string, string>,\n  options: TreeChartOptions,\n): Record<string, unknown> {\n  let labelIndex = 0;\n  const hasCustomLabel = typeof options.formatNodeLabel === 'function';\n  const formatIcon = options.formatNodeIcon;\n  const visit = (node: TreeNode, depth: number): Record<string, unknown> => {\n    const out: Record<string, unknown> = { name: node.name };\n    if (node.value !== undefined) out.value = node.value;\n    if (node.collapsed) out.collapsed = true;\n    const isLeaf = !node.children || node.children.length === 0;\n    if (hasCustomLabel) {\n      const compiled = compileNodeLabel(\n        node,\n        depth,\n        isLeaf,\n        options,\n        `treeLabel_${labelIndex++}`,\n      );\n      out[TREE_LABEL_TOKEN_KEY] = compiled.text;\n    }\n    const paletteColor = node.color ?? nameToColor.get(node.name);\n    // Tracks whether the icon branch already emitted a custom `itemStyle`\n    // (placeholder fill / border for nodes routed through the canvas\n    // pipeline OR plain image-symbol nodes — note that image-symbol\n    // nodes never set `itemStyle`, so this gate is really \"did the icon\n    // branch claim ownership of the node's appearance\"). When false, we\n    // fall through to the default `itemStyle: { color: paletteColor }`\n    // assignment below; when true, we leave the icon's setup intact.\n    let usesAsyncIcon = false;\n    if (formatIcon) {\n      const icon = resolveTreeIconSpec(formatIcon, {\n        node,\n        name: node.name,\n        depth,\n        isLeaf,\n      });\n      if (icon) {\n        const width = icon.width ?? 20;\n        const height = icon.height ?? width;\n        // Border is opt-in: a missing `borderWidth` means no border,\n        // even on circles. Users who want the old default 2 px palette\n        // ring must say so explicitly. Setting `borderWidth: 0` is\n        // equivalent to omitting it — both produce a no-border render.\n        const hasBorder =\n          icon.borderWidth !== undefined && icon.borderWidth > 0;\n        const placeholderFill =\n          paletteColor ?? TREE_ICON_FALLBACK_COLOR;\n        // `borderColor` falls back to the palette fill so a node with\n        // a per-node `color` (or palette token) still gets a tinted\n        // ring even if the user only specified `borderWidth`.\n        const borderColor = icon.borderColor ?? placeholderFill;\n        const borderWidth = hasBorder ? (icon.borderWidth as number) : 0;\n\n        if (icon.shape === 'circle') {\n          // Circles ALWAYS go through the canvas pipeline — that's the\n          // only way to get a circular clip + contain-fit on top of an\n          // arbitrary source image. The border is optional (canvas\n          // helper skips the stroke when `borderWidth === 0`).\n          //\n          // Synchronous placeholder: an ECharts `circle` shape symbol\n          // tinted with the node's palette color. NO pattern fill with\n          // `itemStyle.color: { image }` — that's the buggy path we\n          // replaced: ECharts pattern fill is positioned in world\n          // coords (not shape-local), so the avatar appears off-center\n          // and cropped under a circle shape; `itemStyle.borderRadius`\n          // has no effect on the built-in `circle` symbol either. The\n          // placeholder exists ONLY to render a visible marker until\n          // the async swap and stash metadata that the swap consumes.\n          out.symbol = 'circle';\n          usesAsyncIcon = true;\n          out[TREE_ICON_META_KEY] = {\n            shape: 'circle',\n            src: icon.image,\n            width,\n            height,\n            borderColor,\n            borderWidth,\n          } satisfies IconMeta;\n          out.itemStyle = hasBorder\n            ? { color: placeholderFill, borderColor, borderWidth }\n            : { color: placeholderFill };\n        } else {\n          // Square: only run the canvas pipeline when the user wants a\n          // border around the image. ECharts' image symbol cannot draw\n          // `itemStyle.border*` (the image is the symbol; no underlying\n          // shape geometry to stroke), so a bordered square avatar\n          // *requires* baking the frame into the PNG. Without a border\n          // we keep the simpler path — `image://<URL>` — which lets\n          // ECharts load the image natively (no CORS friction).\n          if (hasBorder) {\n            // Sync placeholder: ECharts `rect` shape symbol — unlike\n            // image symbols, shape symbols DO respect `itemStyle.border*`,\n            // so we get a clean colored frame around a palette-fill\n            // square until the baked PNG swaps in.\n            out.symbol = 'rect';\n            usesAsyncIcon = true;\n            out[TREE_ICON_META_KEY] = {\n              shape: 'rect',\n              src: icon.image,\n              width,\n              height,\n              borderColor,\n              borderWidth,\n            } satisfies IconMeta;\n            out.itemStyle = {\n              color: placeholderFill,\n              borderColor,\n              borderWidth,\n            };\n          } else {\n            // No border requested → no canvas needed → ECharts loads\n            // the image natively.\n            const image = icon.image;\n            out.symbol = image.startsWith('image://') ? image : `image://${image}`;\n            out.symbolKeepAspect = true;\n          }\n        }\n        out.symbolSize = width === height ? width : [width, height];\n        // Per-node `label.distance` override — see\n        // `TREE_ICON_LABEL_DISTANCE_*` for calibration. Deep-merges into\n        // `series.label` / `series.leaves.label` so it applies whether\n        // the node is a parent or leaf and survives any other label\n        // overrides. Only set on icon-bearing nodes; default-dot nodes\n        // keep ECharts' built-in 5 px gap.\n        const maxIconDim = Math.max(width, height);\n        const labelDistance = Math.max(\n          Math.round(maxIconDim * TREE_ICON_LABEL_DISTANCE_RATIO),\n          TREE_ICON_LABEL_DISTANCE_FLOOR_PX,\n        );\n        out.label = { distance: labelDistance };\n      }\n    }\n    // Per-node `color` wins over the palette lookup so per-row overrides\n    // can pin a single node without affecting the rest of the tree.\n    if (paletteColor && !usesAsyncIcon) out.itemStyle = { color: paletteColor };\n    if (node.children && node.children.length > 0) {\n      out.children = node.children.map((child) => visit(child, depth + 1));\n    }\n    return out;\n  };\n  return visit(root, 0);\n}\n\nfunction collectNodesWithIconMeta(\n  root: Record<string, unknown>,\n): Array<{ node: Record<string, unknown>; meta: IconMeta }> {\n  const out: Array<{ node: Record<string, unknown>; meta: IconMeta }> = [];\n  const stack: Record<string, unknown>[] = [root];\n  while (stack.length > 0) {\n    const node = stack.pop()!;\n    const rawMeta = node[TREE_ICON_META_KEY];\n    if (typeof rawMeta === 'object' && rawMeta !== null) {\n      const meta = rawMeta as IconMeta;\n      if (\n        (meta.shape === 'circle' || meta.shape === 'rect') &&\n        typeof meta.src === 'string' &&\n        typeof meta.width === 'number' &&\n        typeof meta.height === 'number' &&\n        typeof meta.borderColor === 'string' &&\n        typeof meta.borderWidth === 'number'\n      ) {\n        out.push({ node, meta });\n      }\n    }\n    const kids = node.children;\n    if (Array.isArray(kids)) {\n      for (const child of kids) {\n        if (typeof child === 'object' && child !== null) {\n          stack.push(child as Record<string, unknown>);\n        }\n      }\n    }\n  }\n  return out;\n}\n\n/**\n * After the synchronous placeholder is rendered, asynchronously\n * upgrade each canvas-pipeline avatar (circles always, rects only\n * when the user requested a border) to a real image symbol. Two\n * upgrade paths, picked per-node based on what the browser allows:\n *\n *   1. **Canvas path (preferred)** — {@link renderIconDataUrl}\n *      pre-composites the image into a PNG with a baked-in shape clip\n *      (circle or rect), contain-fit, and optional border stroke,\n *      then we set `symbol: 'image://<dataUrl>'` and drop the\n *      placeholder `itemStyle`. Only works when the image host ships\n *      `Access-Control-Allow-Origin` — otherwise the canvas is\n *      CORS-tainted and `toDataURL` throws `SecurityError`.\n *\n *   2. **Native image fallback** — when the canvas path returns\n *      `undefined` (CORS-blocked or load failed), use ECharts'\n *      built-in `image://<original-url>` symbol instead. ECharts\n *      loads the image as a regular `<img>` (no CORS needed for\n *      display, only for pixel extraction), so the avatar shows up\n *      as a *square* image. When the user asked for a border, we\n *      paint a rectangular frame around the image via\n *      `itemStyle.borderColor` / `borderWidth`. Circles lose the\n *      circular clip in this fallback (the avatar reads as square)\n *      but stay visible — strictly better than the colored-shape\n *      placeholder users see when both paths fail.\n *\n *   3. **Placeholder retained** — when both async paths fail (image\n *      404, network error, etc.), the synchronous colored-shape\n *      placeholder stays as the last-resort visible marker.\n *\n * The two-tier strategy means *most* avatar hosts work out of the\n * box. Hosts like DiceBear, Gravatar, S3-with-CORS get the full\n * baked-in treatment; hosts like pravatar.cc (no CORS) gracefully\n * degrade to a square framed avatar; total failures stay readable.\n *\n * Why a flat image symbol (not a canvas pattern fill on a shape)?\n *   ECharts pattern fill is positioned in world coordinates, not\n *   shape-local, so the avatar would appear mis-aligned under a\n *   centered shape and gets clipped to whatever slice of the canvas\n *   overlaps the shape. The image-symbol path treats the\n *   pre-composited PNG as a flat sprite — exactly what we want.\n *\n * Returns `undefined` when no node has a canvas-pipeline icon (no\n * circles, no bordered rects), so the adapter can skip wiring an\n * `onInit` callback entirely (saves a `Promise.all` + `setOption`\n * round-trip on every render of every tree without avatars). The\n * async work is wrapped in an IIFE-style void promise so the\n * engine's `onInit?.(this.ecInstance)` call returns immediately; the\n * swap happens on the next frame after the canvas paints (or images\n * load).\n */\nfunction createTreeIconOnInit(\n  root: Record<string, unknown>,\n): ((instance: { setOption: (option: Record<string, unknown>, notMerge?: boolean) => void }) => void) | undefined {\n  const targets = collectNodesWithIconMeta(root);\n  if (targets.length === 0) return undefined;\n\n  return (instance) => {\n    void (async () => {\n      let changed = false;\n      await Promise.all(\n        targets.map(async ({ node, meta }) => {\n          const dataUrl = await renderIconDataUrl({\n            shape: meta.shape,\n            src: meta.src,\n            width: meta.width,\n            height: meta.height,\n            borderColor: meta.borderColor,\n            borderWidth: meta.borderWidth,\n          });\n          if (dataUrl) {\n            // Canvas path — full avatar with shape clip + contain-fit\n            // (+ optional border) baked into the PNG. Drop the\n            // placeholder `itemStyle` so ECharts doesn't double-paint\n            // the colored fill / border underneath or on top of the\n            // image symbol. `symbolKeepAspect` is defensive — the\n            // canvas is square when `width === height`, but the flag\n            // prevents subtle distortion when they diverge.\n            node.symbol = `image://${dataUrl}`;\n            node.symbolKeepAspect = true;\n            delete (node as Record<string, unknown>).itemStyle;\n            changed = true;\n            return;\n          }\n          // Native image fallback — host doesn't ship CORS headers (or\n          // image load failed but we'll let ECharts retry the load with\n          // its own loader). ECharts draws the image as a rectangular\n          // image symbol — for circles this means losing the circular\n          // clip (a known degradation; users see a square avatar\n          // instead of a colored dot, which is strictly better).\n          //\n          // When the user asked for a border (`borderWidth > 0`) we\n          // paint a rectangular frame around the symbol via\n          // `itemStyle`. ECharts honors `border*` on image symbols\n          // here as a stroke around the bounding box. `color:\n          // 'transparent'` ensures the placeholder fill doesn't tint\n          // the loaded image. When no border was requested, we omit\n          // the `itemStyle` entirely so ECharts renders just the raw\n          // image — matching the \"no border\" intent end-to-end.\n          node.symbol = meta.src.startsWith('image://')\n            ? meta.src\n            : `image://${meta.src}`;\n          node.symbolKeepAspect = true;\n          if (meta.borderWidth > 0) {\n            node.itemStyle = {\n              color: 'transparent',\n              borderColor: meta.borderColor,\n              borderWidth: meta.borderWidth,\n            };\n          } else {\n            delete (node as Record<string, unknown>).itemStyle;\n          }\n          changed = true;\n        }),\n      );\n      if (!changed) return;\n      // Runtime payload — must go through `applyConfiguredFontFamilyToOption`\n      // per AGENTS.md architecture rule #9 even though we touch no text\n      // fields here. Future contributors swapping in label tweaks via\n      // this same payload pipeline get the font-family guard for free.\n      const payload: Record<string, unknown> = {\n        series: [{ data: [root] }],\n      };\n      applyConfiguredFontFamilyToOption(payload, getConfig().fontFamily);\n      try {\n        instance.setOption(payload, false);\n      } catch {\n        // Chart may already be disposed (e.g. component unmounted\n        // mid-fetch). Swallow rather than rethrow — there's no way\n        // for the swap to retroactively succeed.\n      }\n    })();\n  };\n}\n\nfunction createTreeLabelFormatter(\n  fallbackByName: ReadonlyMap<string, string>,\n): (params: unknown) => string {\n  return (params: unknown): string => formatTreeLabel(params, fallbackByName);\n}\n\nfunction formatTreeLabel(\n  params: unknown,\n  fallbackByName: ReadonlyMap<string, string>,\n): string {\n  const pr = params as Record<string, unknown>;\n  const data =\n    (pr.data as Record<string, unknown> | undefined) ??\n    (pr.value as Record<string, unknown> | undefined);\n  const custom = data?.[TREE_LABEL_TOKEN_KEY];\n  if (typeof custom === 'string') return custom;\n  if (typeof pr.name === 'string') {\n    return fallbackByName.get(pr.name) ?? pr.name;\n  }\n  return '';\n}\n\n/**\n * Default sync tooltip for tree nodes. Mirrors the pattern used by other\n * \"single item\" tooltips in the library (network, pie, …): show the\n * colored marker, the node name, and (when present) the formatted value.\n */\nfunction treeTooltipSyncHtml(\n  params: unknown,\n  options: TreeChartOptions,\n): string {\n  const pr = params as Record<string, unknown>;\n  const marker = (pr.marker as string) ?? '';\n  const name = String(pr.name ?? '');\n  const value = pr.value;\n  if (value === undefined) return `${marker}${name}`;\n  const fmt = options.tooltip?.formatValue;\n  const display = fmt ? fmt(value as number, name) : value;\n  return `${marker}${name}: ${display}`;\n}\n\nfunction resolveRoamMode(\n  enablePan: boolean | undefined,\n  enableZoom: boolean | undefined,\n): boolean | 'move' | 'scale' {\n  const pan = enablePan ?? true;\n  const zoom = enableZoom ?? false;\n  if (pan && zoom) return true;\n  if (pan) return 'move';\n  if (zoom) return 'scale';\n  return false;\n}\n\n/**\n * Resolve a `TreeData` + `TreeChartOptions` pair into an ECharts option\n * object. Single-series chart — emits one `{ type: 'tree' }` series.\n *\n * Layout: body-centered chart (no XY grid). Reserves the title height\n * on `top` via {@link getTitleReserve} (same pattern as pie / gauge /\n * radar). Both the root-side and leaf-side edges receive a measured\n * label reserve (parents grow toward the root, leaves grow toward the\n * opposite edge — so both directions can clip). Vertical layouts\n * (`'TB'` / `'BT'`) rotate labels 90° so they read along the tree's\n * growth direction; the rotation swaps the geometry, putting full\n * label-width onto the active vertical axis and a thin font-height\n * strip onto the perpendicular horizontal axis.\n *\n * Colors: every node name flows through {@link resolveColors}, then\n * the per-node `itemStyle.color` is injected during the tree walk in\n * {@link annotateTree}. Tree data is hierarchical, not a flat array,\n * so `paintGraphNodes` (which only walks `series.data[]`) doesn't fit\n * — the tree walk handles color injection in one pass instead.\n */\nexport function resolveTreeOptions(\n  data: TreeData,\n  options: TreeChartOptions,\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const direction: TreeDirection = options.direction ?? 'LR';\n  const layout = DIRECTION_LAYOUT[direction];\n  const labelRotate = options.disableLabelRotate ? 0 : layout.labelRotate;\n\n  const names = collectNodeNames(data);\n  const colors = resolveColors(names, options);\n  const nameToColor = new Map<string, string>(names.map((n, i) => [n, colors[i]]));\n\n  // Layout reserves — body-centered, mirrors radar / pie / gauge.\n  const p = options.padding ?? 12;\n  const titleR = getTitleReserve(options).top;\n\n  const showLabel = options.showNodeLabel ?? true;\n  const hasCustomLabel = typeof options.formatNodeLabel === 'function';\n  const parentAlign = hasCustomLabel ? 'center' : layout.parentAlign;\n  const leafAlign = hasCustomLabel ? 'center' : layout.leafAlign;\n\n  // Effective label fontSize for this chart instance — drives both the\n  // canvas measureText calls below AND the `series.label.fontSize` /\n  // `series.leaves.label.fontSize` emitted further down. Keeping them\n  // in lockstep is the measure-vs-render contract: if `measure` uses\n  // 12 px but ECharts renders at 18 px, the reserved label slot under-\n  // estimates and the rightmost / leafmost names clip.\n  const labelFontSize = getLabelFontSize(options);\n  // Per-axis edge reserves so labels at the root edge AND the leaf edge\n  // both stay inside the canvas. Two failure modes the previous (leaf-only)\n  // version hit:\n  //   1. LR/RL: the root's own label grows TOWARD the root edge (`position:\n  //      'left'` for LR) and slips past the left inset whenever it's wider\n  //      than `padding`.\n  //   2. TB/BT: even with rotated -90° labels (which read vertically),\n  //      the unrotated text-width becomes the vertical extent past the\n  //      node — the root's parent label grows full-width upward into\n  //      the top reserve, and leaf labels grow full-width downward\n  //      into the bottom reserve.\n  // Measure both groups separately because they receive different label\n  // positions (parents on the root side, leaves on the opposite side) and\n  // a tree often has very different name lengths between them.\n  const { leafLabels, parentLabels } = splitNodeNames(data, options);\n  const widestLeafPx = showLabel\n    ? measureWidestCompiledLabel(leafLabels)\n    : 0;\n  const widestParentPx = showLabel\n    ? measureWidestCompiledLabel(parentLabels)\n    : 0;\n\n  // Slot per edge, in the active layout's terms:\n  //   `rootSlot` = label-driven reserve on whichever edge the ROOT grows\n  //                toward (LR→left, RL→right, TB→top, BT→bottom).\n  //   `leafSlot` = same, on the opposite edge.\n  //   `perpSlot` = reserve on the OTHER axis. Horizontal layouts get\n  //                zero (labels are vertically centered, ~half line-height\n  //                ≈ negligible next to chart padding). Vertical layouts\n  //                with rotated -90° labels still get a small reserve\n  //                because the rotated text strip is one font-height\n  //                wide; half a line-height + gap keeps the leftmost /\n  //                rightmost nodes' labels from kissing the canvas edge.\n  let rootSlot: number;\n  let leafSlot: number;\n  let perpSlot: number;\n  if (layout.axis === 'horizontal') {\n    // Labels extend the full label-width past each node along the X\n    // axis; vertical extent is just half line-height (negligible).\n    rootSlot = clampLabelReserve(widestParentPx);\n    leafSlot = clampLabelReserve(widestLeafPx);\n    perpSlot = 0;\n  } else {\n    // Vertical layout with rotated (`-90°`) labels — the rotation\n    // swaps the geometry: the unrotated text-width becomes vertical\n    // extent past the node, and the unrotated text-height becomes\n    // horizontal extent. So:\n    //   - Active axis (top/bottom) needs the SAME widest-name reserve\n    //     as horizontal layouts use on their active axis.\n    //   - Perpendicular axis (left/right) only needs ~half line-height\n    //     since the rotated text is a thin vertical strip anchored at\n    //     the node's x-position.\n    rootSlot = clampLabelReserve(widestParentPx);\n    leafSlot = clampLabelReserve(widestLeafPx);\n    perpSlot = showLabel\n      ? Math.ceil((labelFontSize * TREE_LABEL_LINE_HEIGHT_RATIO) / 2) +\n        TREE_LABEL_GAP_PX\n      : 0;\n  }\n\n  // Map slots onto absolute canvas edges. `top` additionally folds in the\n  // title widget reserve when present — same pattern as pie / gauge / radar.\n  const reserveFor = (edge: 'top' | 'bottom' | 'left' | 'right'): number => {\n    if (edge === layout.rootEdge) return rootSlot;\n    if (edge === layout.leafEdge) return leafSlot;\n    return perpSlot;\n  };\n\n  const top = p + Math.max(reserveFor('top'), titleR);\n  const bottom = p + reserveFor('bottom');\n  const left = p + reserveFor('left');\n  const right = p + reserveFor('right');\n\n  const expandAndCollapse = options.expandAndCollapse ?? true;\n  const mergedRich = mergeCompiledRichStyles([\n    ...parentLabels.map((entry) => entry.compiled),\n    ...leafLabels.map((entry) => entry.compiled),\n  ]);\n  const rich =\n    hasCustomLabel && Object.keys(mergedRich).length > 0 ? mergedRich : undefined;\n  const parentLabelTextByName = new Map(parentLabels.map((entry) => [entry.name, entry.compiled.text]));\n  const leafLabelTextByName = new Map(leafLabels.map((entry) => [entry.name, entry.compiled.text]));\n  const parentFormatter = createTreeLabelFormatter(parentLabelTextByName);\n  const leafFormatter = createTreeLabelFormatter(leafLabelTextByName);\n\n  const series: Record<string, unknown> = {\n    type: 'tree',\n    // ECharts expects an array of root nodes; we only ever ship one.\n    data: [annotateTree(data, nameToColor, options)],\n    orient: layout.orient,\n    top,\n    bottom,\n    left,\n    right,\n    symbolSize: options.nodeSize ?? DEFAULT_NODE_SIZE,\n    roam: resolveRoamMode(options.enablePan, options.enableZoom),\n    expandAndCollapse,\n    edgeShape: options.lineStyle ?? 'polyline',\n    initialTreeDepth: options.initialTreeDepth ?? -1, // -1 = fully expanded\n    label: {\n      show: showLabel,\n      position: layout.parentPosition,\n      align: parentAlign,\n      verticalAlign: 'middle',\n      // `rotate` is `-90` for TB/BT (labels read top-to-bottom) and `0`\n      // for LR/RL (horizontal text). Mirrors ECharts' own tree-vertical\n      // / tree-orient-bottom-top reference examples.\n      rotate: labelRotate,\n      // Single source of truth for the rendered font size — resolved once\n      // via `getLabelFontSize(options)`, then used for both parent/leaf\n      // label styles while reserve math is driven by compiled label widths.\n      // Diverging these values would re-introduce label clipping.\n      fontSize: labelFontSize,\n      // No `color` here on purpose — theme owns canvas text color.\n      // See AGENTS.md \"Layout rule #6\" + `tree.label.color` entry in\n      // `src/themes/echarts-theme.ts`.\n      ...(hasCustomLabel ? { formatter: parentFormatter } : {}),\n      ...(rich ? { rich } : {}),\n    },\n    leaves: {\n      label: {\n        position: layout.leafPosition,\n        align: leafAlign,\n        verticalAlign: 'middle',\n        rotate: labelRotate,\n        // Mirror parent label fontSize to keep label metrics consistent.\n        fontSize: labelFontSize,\n        ...(hasCustomLabel ? { formatter: leafFormatter } : {}),\n        ...(rich ? { rich } : {}),\n      },\n    },\n    emphasis: { focus: 'descendant' },\n    animationDuration: 550,\n    animationDurationUpdate: 750,\n  };\n\n  // Tree tooltips fire on hover (not click) so users can scan the tree\n  // without committing to a click target — matches ECharts' own\n  // `tree-basic` example and the network adapter's UX.\n  const tooltip: Record<string, unknown> = {\n    trigger: 'item',\n    triggerOn: 'mousemove',\n    confine: true,\n    show: options.tooltip?.enabled !== false,\n    appendToBody: resolveAppendToBody(options, ctx),\n    position: resolveTooltipPosition(options),\n  };\n  // Tree tooltip semantics:\n  //   - `customHtml` owns the full tooltip body (name, avatar, …) — the\n  //     built-in name row is skipped. Same convention as every other\n  //     chart type post the unified `customHtml = replace` semantics.\n  //   - `appendHtml` keeps the default name row and adds extras below it.\n  //   - Both can compose: customHtml's body + appendHtml's extras below.\n  // The shared helper wires this exactly.\n  const treeFormatter = buildAsyncTooltipFormatter({\n    options,\n    defaultSync: (params) => treeTooltipSyncHtml(params, options),\n    toContext: (params) => sankeyChordParamsToTooltipContext(params, nameToColor),\n  });\n  tooltip.formatter =\n    treeFormatter ?? ((params: unknown) => treeTooltipSyncHtml(params, options));\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    tooltip,\n    series: [series],\n  };\n\n  const merged = deepMerge(\n    eOption,\n    (options.echarts ?? {}) as Record<string, unknown>,\n  );\n\n  // Final color assembly — palette resolution wins over any user\n  // `echarts.color` override, matching the convention every other\n  // adapter follows (see AGENTS.md architecture rule #3).\n  merged.color = colors;\n\n  return merged;\n}\n\nexport function resolveTreeSetup(\n  data: TreeData,\n  options: TreeChartOptions,\n  ctx?: RenderContext,\n): ChartSetupResult {\n  const option = resolveTreeOptions(data, options, ctx);\n  const root = ((option.series as Record<string, unknown>[] | undefined)?.[0]?.data as\n    | Record<string, unknown>[]\n    | undefined)?.[0];\n  if (!root || typeof root !== 'object') return { option };\n  const onInit = createTreeIconOnInit(root);\n  return { option, onInit };\n}\n","import type {\n  TreemapData,\n  TreemapDataItem,\n  TreemapChartOptions,\n  TooltipContextItem,\n} from '../types.js';\nimport type { RenderContext } from './index.js';\nimport { deepMerge, resolveColors } from '../utils.js';\nimport {\n  buildTitle,\n  buildAsyncTooltipFormatter,\n  getLabelFontSize,\n  getTitleReserve,\n  resolveAppendToBody,\n  resolveTooltipPosition,\n} from './common/index.js';\n\n/**\n * ECharts treemap breadcrumb default height (px). The breadcrumb sits\n * flush at canvas bottom by default (`breadcrumb.bottom: 0`), so we\n * need to subtract this PLUS a small visual gap from the series'\n * bottom inset — otherwise the rectangle area extends behind the\n * breadcrumb and the two visually overlap.\n */\nconst BREADCRUMB_HEIGHT_PX = 22;\n\n/**\n * Visual breathing gap (px) between the chart body and the breadcrumb\n * path. Matches the title-to-body gap so all three layout zones\n * (title / body / breadcrumb) feel evenly spaced.\n */\nconst BREADCRUMB_GAP_PX = 6;\n\n/**\n * Map ECharts treemap tooltip params → unified `TooltipContextItem`. The\n * treemap fires `item`-trigger tooltips per node hover; ECharts populates\n * `params.color` with the painted rectangle fill so consumers receive a\n * real hex (the closure does NOT need a `nameToColor` map — every node\n * carries its own resolved `itemStyle.color`, which ECharts surfaces\n * back as `params.color`).\n */\nfunction treemapParamsToTooltipContext(params: unknown): TooltipContextItem {\n  const pr = params as Record<string, unknown>;\n  return {\n    kind: 'item',\n    dataIndex: typeof pr.dataIndex === 'number' ? pr.dataIndex : 0,\n    name: String(pr.name ?? ''),\n    value: (pr.value as number | string) ?? '',\n    marker: typeof pr.marker === 'string' ? pr.marker : undefined,\n    color: typeof pr.color === 'string' ? pr.color : undefined,\n  };\n}\n\n/**\n * Default synchronous tooltip body. Mirrors the per-item pattern used by\n * pie / word-cloud: marker chip + node name + formatted value.\n */\nfunction treemapTooltipSyncHtml(\n  params: unknown,\n  options: TreemapChartOptions,\n): string {\n  const pr = params as Record<string, unknown>;\n  const marker = (pr.marker as string) ?? '';\n  const name = String(pr.name ?? '');\n  const value = pr.value;\n  if (value === undefined || value === null || value === '') {\n    return `${marker}${name}`;\n  }\n  const fmt = options.tooltip?.formatValue;\n  const display = fmt ? fmt(value as number, name) : String(value);\n  return `${marker}${name}: ${display}`;\n}\n\n/**\n * Walk the tree and deep-copy it into the ECharts-shaped node tree.\n *\n * Per-node responsibilities:\n *   - copy `name`, `value`, `children` straight through;\n *   - inject `itemStyle.color` from the resolved palette (root-level\n *     `nameToColor` lookup) OR from `node.color` (per-node override\n *     wins over palette).\n *\n * Returns a plain object ECharts can consume directly. The original\n * `TreemapDataItem` instances are NOT reused, so downstream mutation\n * of the returned tree never leaks back to the caller's input.\n */\nfunction annotateTree(\n  node: TreemapDataItem,\n  nameToColor: ReadonlyMap<string, string>,\n): Record<string, unknown> {\n  const out: Record<string, unknown> = { name: node.name };\n  if (node.value !== undefined) out.value = node.value;\n\n  // Per-node color override > palette lookup keyed on the root-level\n  // name. Children inherit from ECharts' built-in tinting (each level\n  // gets a lighter shade derived from its ancestor's color) unless the\n  // user pins them explicitly via `node.color`.\n  const color = node.color ?? nameToColor.get(node.name);\n  if (color) out.itemStyle = { color };\n\n  if (node.children && node.children.length > 0) {\n    out.children = node.children.map((child) => annotateTree(child, nameToColor));\n  }\n  return out;\n}\n\n/**\n * Resolve a `TreemapData` + `TreemapChartOptions` pair into an ECharts\n * option object. Single-series chart — emits one `{ type: 'treemap' }`\n * series.\n *\n * Layout: body-centered chart (no XY grid). Reserves the title height\n * on `top` via {@link getTitleReserve} (same pattern as pie / gauge /\n * radar / tree). When `showBreadcrumb` is on, ECharts paints the\n * breadcrumb trail inside the chart canvas — its default 25 px height\n * is allocated automatically by ECharts; the adapter doesn't add an\n * extra bottom reserve beyond `padding`.\n *\n * Colors: every ROOT-level node's name flows through {@link resolveColors};\n * the resulting palette is assigned per-node via `itemStyle.color` so\n * `options.colorMap` / `options.colors` / `node.color` overrides reach\n * the rendered rectangles. Child nodes inherit ECharts' built-in\n * descendant-tinting unless individually pinned.\n */\nexport function resolveTreemapOptions(\n  data: TreemapData,\n  options: TreemapChartOptions,\n  _ctx?: RenderContext,\n): Record<string, unknown> {\n  const rootNames = data.map((d) => d.name);\n  const palette = resolveColors(rootNames, options);\n  const nameToColor = new Map<string, string>(\n    rootNames.map((n, i) => [n, palette[i]] as const),\n  );\n  const annotated = data.map((root) => annotateTree(root, nameToColor));\n\n  const p = options.padding ?? 12;\n  const topReserve = p + getTitleReserve(options).top;\n  // Bottom reserve grows when the breadcrumb is shown — push the\n  // chart body UP by the breadcrumb's height + visual gap so the\n  // rectangle area never overlaps the path chips below it.\n  const showBreadcrumb = options.showBreadcrumb ?? true;\n  const bottomReserve = showBreadcrumb\n    ? p + BREADCRUMB_HEIGHT_PX + BREADCRUMB_GAP_PX\n    : p;\n\n  const tooltip: Record<string, unknown> = {\n    trigger: 'item',\n    confine: true,\n    show: options.tooltip?.enabled !== false,\n    appendToBody: resolveAppendToBody(options, _ctx),\n    position: resolveTooltipPosition(options),\n  };\n  const asyncFormatter = buildAsyncTooltipFormatter({\n    options,\n    defaultSync: (params) => treemapTooltipSyncHtml(params, options),\n    toContext: treemapParamsToTooltipContext,\n  });\n  tooltip.formatter =\n    asyncFormatter ?? ((params: unknown) => treemapTooltipSyncHtml(params, options));\n\n  const showNodeLabel = options.showNodeLabel ?? true;\n  const drilldown = options.drilldown ?? true;\n  const enableRoam = options.enableRoam ?? false;\n\n  // ECharts treemap wraps multi-root data in an implicit root and\n  // labels that root from `series.name` in the breadcrumb's first\n  // cell. With no name set, the first cell renders empty — which\n  // looks broken next to the rest of the drill path. Derive the\n  // root label from the title text so the breadcrumb agrees with\n  // what the user sees above the chart (e.g. title \"Disk Usage\" →\n  // breadcrumb starts with \"Disk Usage › Library › Caches\").\n  // Users who want a different root label can either override\n  // `options.echarts.series[0].name` or pass a TitleOptions object\n  // with a different `text`.\n  const titleText =\n    typeof options.title === 'string' ? options.title : options.title?.text;\n\n  const series: Record<string, unknown> = {\n    type: 'treemap',\n    // Name surfaces as the root cell in the breadcrumb path. Omit\n    // entirely (rather than emitting `name: undefined`) so the\n    // resolved option stays clean and `options.echarts.series[0].name`\n    // overrides keep working.\n    ...(titleText ? { name: titleText } : {}),\n    // ECharts treemap honors only numeric pixel positions (no\n    // percentages) for top/bottom/left/right. Mirror the title /\n    // padding reserves the other body-centered adapters use. The\n    // bottom inset folds in the breadcrumb height when the path\n    // is visible (see `bottomReserve` above) so the chart body\n    // never bleeds into the breadcrumb chips.\n    top: topReserve,\n    bottom: bottomReserve,\n    left: p,\n    right: p,\n    // Click behavior: 'zoomToNode' drills down into the clicked\n    // sub-tree (and back via the breadcrumb). `false` disables the\n    // entire drill interaction — useful for snapshots / read-only.\n    nodeClick: drilldown ? 'zoomToNode' : false,\n    roam: enableRoam,\n    // Breadcrumb is positioned `p` px above the canvas bottom (matches\n    // chart padding); height pinned to BREADCRUMB_HEIGHT_PX so the\n    // reserve math above stays accurate even if a future ECharts\n    // release changes its default. NO color/border fields here —\n    // those live in the theme so a `setTheme()` repaint sweeps the\n    // breadcrumb chips along with everything else (see\n    // `src/themes/echarts-theme.ts` → `treemap.breadcrumb.*`).\n    breadcrumb: showBreadcrumb\n      ? { show: true, bottom: p, height: BREADCRUMB_HEIGHT_PX }\n      : { show: false },\n    label: {\n      show: showNodeLabel,\n      fontSize: getLabelFontSize(options),\n    },\n    // Hide the \"parent name\" upper-label bar by default — it doubles\n    // the breadcrumb when on and clutters small charts. Users who\n    // want it can flip it via `options.echarts.series[0].upperLabel`.\n    upperLabel: { show: false },\n    data: annotated,\n  };\n\n  if (options.leafDepth !== undefined) {\n    series.leafDepth = options.leafDepth;\n  }\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    tooltip,\n    series: [series],\n  };\n\n  const merged = deepMerge(\n    eOption,\n    (options.echarts ?? {}) as Record<string, unknown>,\n  );\n  // Palette also published on the top-level option so ECharts can use\n  // it for any palette-driven feature we haven't pinned per-node\n  // (e.g. user-supplied `colorMappingBy: 'index'`).\n  merged.color = palette;\n  return merged;\n}\n","import type { TooltipContextItem, WordCloudChartOptions, WordCloudData } from '../types.js';\nimport type { RenderContext } from './index.js';\nimport { deepMerge, resolveColors } from '../utils.js';\nimport {\n  buildTitle,\n  buildAsyncTooltipFormatter,\n  getTitleReserve,\n  resolveAppendToBody,\n  resolveTooltipPosition,\n} from './common/index.js';\n\ninterface ResolvedWordCloudDefaults {\n  sizeRange: [number, number];\n  shape:\n    | 'circle'\n    | 'cardioid'\n    | 'diamond'\n    | 'triangle-forward'\n    | 'triangle'\n    | 'pentagon'\n    | 'star';\n  rotationRange: [number, number];\n  rotationStep: number;\n  gridSize: number;\n}\n\nfunction resolveWordCloudDefaults(\n  options: WordCloudChartOptions,\n): ResolvedWordCloudDefaults {\n  const variant = options.variant ?? 'default';\n  if (variant === 'diamond' || variant === 'compact-diamond') {\n    return {\n      sizeRange: options.sizeRange ?? [14, 48],\n      shape: options.shape ?? 'diamond',\n      rotationRange: options.rotationRange ?? [0, 0],\n      rotationStep: options.rotationStep ?? 45,\n      gridSize: options.gridSize ?? 10,\n    };\n  }\n  if (variant === 'poster') {\n    return {\n      sizeRange: options.sizeRange ?? [16, 72],\n      shape: options.shape ?? 'star',\n      rotationRange: options.rotationRange ?? [-45, 45],\n      rotationStep: options.rotationStep ?? 15,\n      gridSize: options.gridSize ?? 12,\n    };\n  }\n  return {\n    sizeRange: options.sizeRange ?? [12, 60],\n    shape: options.shape ?? 'circle',\n    rotationRange: options.rotationRange ?? [-90, 90],\n    rotationStep: options.rotationStep ?? 45,\n    gridSize: options.gridSize ?? 8,\n  };\n}\n\nfunction wordCloudParamsToTooltipContext(params: unknown): TooltipContextItem {\n  const pr = params as Record<string, unknown>;\n  const raw = pr.value;\n  let name = String(pr.name ?? '');\n  let value: number | string = '';\n  if (Array.isArray(raw)) {\n    name = String(raw[0] ?? name);\n    value = (raw[1] ?? '') as number | string;\n  } else if (typeof raw === 'number' || typeof raw === 'string') {\n    value = raw;\n  }\n  return {\n    kind: 'item',\n    dataIndex: typeof pr.dataIndex === 'number' ? pr.dataIndex : -1,\n    name,\n    value,\n    marker: typeof pr.marker === 'string' ? pr.marker : undefined,\n    color: typeof pr.color === 'string' ? pr.color : undefined,\n  };\n}\n\nfunction wordCloudTooltipSyncHtml(\n  params: unknown,\n  options: WordCloudChartOptions,\n): string {\n  const ctx = wordCloudParamsToTooltipContext(params);\n  const marker = ctx.marker ?? '';\n  const fmt = options.tooltip?.formatValue;\n  const display = fmt ? fmt(ctx.value, ctx.name) : ctx.value;\n  return `${marker}${ctx.name}: ${display}`;\n}\n\nexport function resolveWordCloudOptions(\n  data: WordCloudData,\n  options: WordCloudChartOptions,\n  ctx?: RenderContext,\n): Record<string, unknown> {\n  const defaults = resolveWordCloudDefaults(options);\n  const sorted = options.autoSort !== false\n    ? [...data].sort((a, b) => b.value - a.value)\n    : data;\n  const names = sorted.map((d) => d.name);\n  const colors = resolveColors(names, options);\n  const padding = options.padding ?? 12;\n  const topReserve = getTitleReserve(options).top;\n  const wordData = sorted.map((item, idx) => ({\n    name: item.name,\n    value: [item.name, item.value],\n    itemStyle: { color: item.color ?? colors[idx] },\n  }));\n\n  const tooltip: Record<string, unknown> = {\n    trigger: 'item',\n    confine: true,\n    show: options.tooltip?.enabled !== false,\n    appendToBody: resolveAppendToBody(options, ctx),\n    position: resolveTooltipPosition(options),\n  };\n  const wordCloudFormatter = buildAsyncTooltipFormatter({\n    options,\n    defaultSync: (params) => wordCloudTooltipSyncHtml(params, options),\n    toContext: wordCloudParamsToTooltipContext,\n  });\n  tooltip.formatter =\n    wordCloudFormatter ?? ((params: unknown) => wordCloudTooltipSyncHtml(params, options));\n\n  const eOption: Record<string, unknown> = {\n    title: buildTitle(options),\n    tooltip,\n    series: [\n      {\n        type: 'custom',\n        renderItem: 'wordCloud',\n        // Wordcloud custom renderer draws in canvas space directly and does\n        // not use cartesian/polar coordinates.\n        coordinateSystem: 'none',\n        data: wordData,\n        itemPayload: {\n          left: padding,\n          right: padding,\n          bottom: padding,\n          top: padding + topReserve,\n          sizeRange: defaults.sizeRange,\n          shape: defaults.shape,\n          rotationRange: defaults.rotationRange,\n          rotationStep: defaults.rotationStep,\n          gridSize: defaults.gridSize,\n          keepAspect: options.keepAspect ?? false,\n          drawOutOfBound: options.drawOutOfBound ?? false,\n          shrinkToFit: options.shrinkToFit ?? false,\n          layoutAnimation: options.layoutAnimation ?? true,\n          maskImage: options.maskImage,\n        },\n      },\n    ],\n  };\n\n  const merged = deepMerge(\n    eOption,\n    (options.echarts ?? {}) as Record<string, unknown>,\n  );\n  merged.color = colors;\n  return merged;\n}\n","import type * as echarts from 'echarts';\nimport type { ChartData, ChartOptions } from '../types.js';\n\n/**\n * Cleanup callback an adapter's `onInit` may return. The engine runs it on\n * the next re-render (before the next `onInit`) and on `dispose()`, so an\n * adapter that wires `ResizeObserver` / event listeners / timers in `onInit`\n * has a deterministic teardown point — no need to stash state on the chart\n * instance or poll `isDisposed()`.\n */\nexport type ChartTeardown = () => void;\n\n/**\n * Result returned by an adapter's resolve method.\n *\n * `option`    -- full ECharts option ready for setOption().\n * `onInit`    -- optional hook called after the instance is initialised and\n *                setOption() has been called (e.g. for event listeners). It\n *                fires on every render pass (initial + every update / theme /\n *                resize). May return a {@link ChartTeardown} cleanup; the\n *                engine invokes the previous pass's cleanup before the next\n *                `onInit`, and the final cleanup on `dispose()`.\n * `notMerge`  -- forwarded to ECharts `setOption(option, notMerge)`. Defaults\n *                to `true` (full replace). Adapters that depend on cross-call\n *                state transitions (e.g. bar `race` needs ECharts to animate\n *                value/position changes between successive `chart.update()`\n *                calls) set this to `false` so ECharts merges with the\n *                previous option instead of replacing it.\n */\nexport interface ChartSetupResult {\n  option: Record<string, unknown>;\n  onInit?: (instance: echarts.ECharts) => void | ChartTeardown;\n  notMerge?: boolean;\n}\n\n/**\n * Per-render context the engine passes to adapters alongside data/options.\n *\n * Carries lightweight signals derived from prior render passes — or from\n * the chart container itself — so adapters can make better decisions\n * without holding their own state or doing their own DOM lookups:\n *\n *   - `observedFrameMs` — wall-clock gap between the last two `chart.update()`\n *     calls. Race / streaming adapters use this to auto-size\n *     `animationDurationUpdate` so callers don't have to mirror their own\n *     `setInterval` value as `race.frameDuration`. `undefined` on the very\n *     first `update()` (no prior call to measure against).\n *   - `maxRaceGridRight` — high-water mark of the largest `grid.right` any\n *     prior frame asked for. Race adapters mix this into their adaptive\n *     label-headroom calculation (see `resolveRaceLabelHeadroom`) so the\n *     reserved space grows monotonically as labels widen and never shrinks\n *     back, avoiding plot-area jitter when label digits flip frame to frame.\n *   - `inShadowDom` — `true` when the chart container's root is a\n *     `ShadowRoot` (e.g. the `<i-chart>` web component). Tooltip helpers\n *     (`buildTooltip` / `buildSparkTooltip`) use this to decide the default\n *     value of ECharts' `appendToBody`: `false` inside shadow DOM (so the\n *     tooltip stays inside the shadow root for style encapsulation) and\n *     `true` in light DOM (so it can escape ancestors with `overflow:\n *     hidden` like card / KPI containers). Users can still override via\n *     `options.tooltip.appendToBody`. The engine sets this flag once at\n *     construction time — moving the host between shadow / light DOM\n *     after `init` isn't a supported scenario.\n *   - `containerWidth` / `containerHeight` — px reported by\n *     `ecInstance.getWidth()` / `getHeight()` at render time. Threaded\n *     through every `_apply()` (including resize-triggered re-renders)\n *     so adapters that need pixel-derived sizing can react to the\n *     actual rendered viewport. Today the gauge `percentage` variant is\n *     the canonical consumer: ECharts' `axisLine.lineStyle.width`,\n *     `progress.width`, and `detail.fontSize` are pixel-only (no native\n *     `%` support), so the adapter computes them from\n *     `min(containerWidth, containerHeight)` when the consumer hasn't\n *     set them. Both fields are `undefined` when the instance reports a\n *     zero / non-finite size (SSR, display:none ancestors, jsdom\n *     environments without layout) so adapters can fall back to static\n *     defaults and keep snapshots stable.\n *\n * Frame-derived fields (`observedFrameMs`, `maxRaceGridRight`) are\n * `undefined` during the initial render from the constructor;\n * container-derived fields (`inShadowDom`, `containerWidth`,\n * `containerHeight`) are populated from the very first render.\n */\nexport interface RenderContext {\n  observedFrameMs?: number;\n  maxRaceGridRight?: number;\n  inShadowDom?: boolean;\n  containerWidth?: number;\n  containerHeight?: number;\n}\n\n/**\n * Contract every chart adapter must satisfy.\n *\n * `validate` -- returns true when `data` has the shape this adapter expects.\n * `resolve`  -- builds the ECharts option (and optional onInit hook).\n *               `ctx` is optional; adapters that don't need it ignore the arg.\n *\n * `mergeData` -- optional. When provided, the engine calls it on `update()`\n *               to fold the next data into the previous frame instead of\n *               replacing it wholesale. This lets live-updating charts\n *               (e.g. gauge, liquid-progress) animate value transitions\n *               across successive `chart.update({ value })` calls — the\n *               caller can send a partial patch and the adapter decides how\n *               to carry forward fields it isn't given. The engine only\n *               invokes it when BOTH the previous and next data pass\n *               `validate`, so an adapter's `mergeData` can safely narrow to\n *               its own data shape. When omitted, the engine replaces data\n *               (the default).\n *\n * `clearOnThemeChange` -- optional. When `true`, the engine calls\n *               `instance.clear()` before re-applying on a `setTheme()`\n *               switch. Needed by custom-series renderers (e.g. wordcloud)\n *               whose diff/merge can leave stale display elements behind on\n *               a theme repaint. Defaults to `false`.\n */\nexport interface ChartAdapter {\n  validate(data: ChartData): boolean;\n  resolve(\n    data: ChartData,\n    options: ChartOptions,\n    ctx?: RenderContext,\n  ): ChartSetupResult;\n  mergeData?(prev: ChartData, next: ChartData): ChartData;\n  clearOnThemeChange?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Adapter registry\n// ---------------------------------------------------------------------------\n\nconst adapterRegistry = new Map<string, ChartAdapter>();\n\n/**\n * Snapshot of the type strings owned by built-in adapters. Populated once at\n * the bottom of this module after all built-ins are registered (stays `null`\n * during built-in registration so those calls never warn). Used solely to\n * flag the uncommon case of a consumer silently shadowing a built-in type.\n */\nlet builtinTypes: ReadonlySet<string> | null = null;\n\n/**\n * Register a chart adapter for a given type string.\n * Built-in adapters are registered at module load time.\n * Users can call this to add custom chart types.\n *\n * Overriding a **built-in** type emits a `console.warn` (the override still\n * takes effect). This is almost always an accidental type-string collision;\n * prefer a distinct string for custom charts. Re-registering a custom type is\n * silent.\n */\nexport function registerAdapter(type: string, adapter: ChartAdapter): void {\n  if (builtinTypes?.has(type) && adapterRegistry.get(type) !== adapter) {\n    console.warn(\n      `[icharts] registerAdapter(\"${type}\") overrides a built-in chart type. ` +\n        `If this is intentional you can ignore this; otherwise use a distinct ` +\n        `type string for your custom chart to avoid shadowing the built-in.`,\n    );\n  }\n  adapterRegistry.set(type, adapter);\n}\n\n/**\n * Look up the adapter registered for a given chart type, or `undefined` when\n * none is registered. Used by the engine to consult optional adapter\n * capabilities (`mergeData`, `clearOnThemeChange`) without hardcoding\n * per-type behavior.\n */\nexport function getAdapter(type: string): ChartAdapter | undefined {\n  return adapterRegistry.get(type);\n}\n\n/**\n * Whether an adapter is registered for `type` (built-in or custom). Cheap\n * pre-flight check before `createChart` so callers can branch without a\n * try/catch around the engine's \"Unsupported chart type\" throw.\n */\nexport function hasAdapter(type: string): boolean {\n  return adapterRegistry.has(type);\n}\n\n/**\n * The type strings of every registered adapter (built-in + custom), in\n * registration order. Useful for diagnostics, building a type picker, or\n * asserting a custom adapter registered as expected.\n */\nexport function listAdapters(): string[] {\n  return [...adapterRegistry.keys()];\n}\n\n/**\n * Remove a previously registered adapter. Returns `true` if one was removed,\n * `false` if no adapter was registered for `type`. Primarily for tests and\n * hot-reload scenarios; removing a built-in is allowed but leaves that type\n * unusable until re-registered.\n */\nexport function unregisterAdapter(type: string): boolean {\n  return adapterRegistry.delete(type);\n}\n\n/**\n * Human-readable, value-free description of a data payload's shape. Used to\n * build actionable validation errors without echoing the user's (potentially\n * sensitive / large) data values back into the message.\n */\nfunction describeDataShape(data: unknown): string {\n  if (data === null) return 'null';\n  if (data === undefined) return 'undefined';\n  if (Array.isArray(data)) return `an array of length ${data.length}`;\n  if (typeof data === 'object') {\n    const keys = Object.keys(data as object);\n    return keys.length\n      ? `an object with keys [${keys.join(', ')}]`\n      : 'an empty object';\n  }\n  return `a ${typeof data}`;\n}\n\n/**\n * Resolve chart data + options into a ChartSetupResult.\n */\nexport function resolveEChartsOption(\n  type: string,\n  data: ChartData,\n  options: ChartOptions,\n  ctx?: RenderContext,\n): ChartSetupResult {\n  const adapter = adapterRegistry.get(type);\n  if (!adapter) {\n    const known = listAdapters();\n    throw new Error(\n      `Unsupported chart type: \"${type}\". ` +\n        (known.length\n          ? `Registered types: ${known.join(', ')}. `\n          : '') +\n        `Register a custom adapter with registerAdapter(\"${type}\", ...) first.`,\n    );\n  }\n  if (!adapter.validate(data)) {\n    throw new Error(\n      `Invalid data for chart type \"${type}\": received ${describeDataShape(data)}. ` +\n        `See the expected data format in docs/chart-*.md (or the chart's data type).`,\n    );\n  }\n  return adapter.resolve(data, options, ctx);\n}\n\n// ---------------------------------------------------------------------------\n// Register built-in adapters\n// ---------------------------------------------------------------------------\n\nimport {\n  ChartType,\n  isXYData,\n  isMapData,\n  isPieData,\n  isGaugeData,\n  mergeGaugeData,\n  isLiquidProgressData,\n  mergeLiquidProgressData,\n  isSankeyData,\n  isChordData,\n  isRadarData,\n  isNetworkData,\n  isTreeData,\n  isTreemapData,\n  isWordCloudData,\n} from '../types.js';\nimport type {\n  LineData,\n  BarData,\n  AreaData,\n  MapData,\n  PieData,\n  GaugeData,\n  LiquidProgressData,\n  SankeyData,\n  ChordData,\n  RadarData,\n  NetworkData,\n  TreeData,\n  TreemapData,\n  WordCloudData,\n  LineChartOptions,\n  BarChartOptions,\n  AreaChartOptions,\n  MapChartOptions,\n  PieChartOptions,\n  GaugeChartOptions,\n  LiquidProgressChartOptions,\n  SankeyChartOptions,\n  ChordChartOptions,\n  RadarChartOptions,\n  NetworkChartOptions,\n  TreeChartOptions,\n  TreemapChartOptions,\n  WordCloudChartOptions,\n} from '../types.js';\nimport { resolveLineOptions, resolveAreaOptions } from './line.js';\nimport { resolveBarOptions } from './bar.js';\nimport { resolveMapOptions } from './map.js';\nimport { resolvePieOptions } from './pie.js';\nimport { resolveGaugeOptions } from './gauge.js';\nimport { resolveLiquidProgressOptions } from './liquid-progress.js';\nimport { resolveSankeyOptions } from './sankey.js';\nimport { resolveChordOptions } from './chord.js';\nimport { resolveRadarOptions } from './radar.js';\nimport { resolveNetworkOptions } from './network.js';\nimport { resolveTreeSetup } from './tree.js';\nimport { resolveTreemapOptions } from './treemap.js';\nimport { resolveWordCloudOptions } from './word-cloud.js';\n\n// Each built-in adapter narrows the generic `ChartData` / `ChartOptions` it\n// receives from the registry to its declared per-chart Data + Options pair.\n// `validate` has already verified the data shape at this point.\n\nregisterAdapter(ChartType.Line, {\n  validate: isXYData,\n  resolve: (data, options, ctx) =>\n    resolveLineOptions(data as LineData, options as LineChartOptions, ctx),\n});\n\nregisterAdapter(ChartType.Area, {\n  validate: isXYData,\n  resolve: (data, options, ctx) => ({\n    option: resolveAreaOptions(data as AreaData, options as AreaChartOptions, ctx),\n  }),\n});\n\nregisterAdapter(ChartType.Bar, {\n  validate: isXYData,\n  resolve: (data, options, ctx) =>\n    resolveBarOptions(data as BarData, options as BarChartOptions, ctx),\n});\n\nregisterAdapter(ChartType.Map, {\n  validate: isMapData,\n  resolve: (data, options, ctx) => ({\n    option: resolveMapOptions(data as MapData, options as MapChartOptions, ctx),\n  }),\n});\n\nregisterAdapter(ChartType.Pie, {\n  validate: isPieData,\n  resolve: (data, options, ctx) =>\n    resolvePieOptions(data as PieData, options as PieChartOptions, ctx),\n});\n\nregisterAdapter(ChartType.Gauge, {\n  validate: isGaugeData,\n  // Carry max / label forward when the consumer sends a partial `{ value }`\n  // patch on each `chart.update()` tick (see mergeGaugeData).\n  mergeData: (prev, next) => mergeGaugeData(prev as GaugeData, next as GaugeData),\n  resolve: (data, options, ctx) => ({\n    option: resolveGaugeOptions(data as GaugeData, options as GaugeChartOptions, ctx),\n    // Merge successive frames so ECharts can animate pointer / progress /\n    // detail.valueAnimation when consumers drive live metrics via\n    // `chart.update({ value })` on an interval.\n    notMerge: false,\n  }),\n});\n\nregisterAdapter(ChartType.LiquidProgress, {\n  validate: isLiquidProgressData,\n  mergeData: (prev, next) =>\n    mergeLiquidProgressData(\n      prev as LiquidProgressData,\n      next as LiquidProgressData,\n    ),\n  resolve: (data, options, ctx) => ({\n    option: resolveLiquidProgressOptions(\n      data as LiquidProgressData,\n      options as LiquidProgressChartOptions,\n      ctx,\n    ),\n    notMerge: false,\n  }),\n});\n\nregisterAdapter(ChartType.Sankey, {\n  validate: isSankeyData,\n  resolve: (data, options, ctx) => ({\n    option: resolveSankeyOptions(data as SankeyData, options as SankeyChartOptions, ctx),\n  }),\n});\n\nregisterAdapter(ChartType.Chord, {\n  validate: isChordData,\n  resolve: (data, options, ctx) =>\n    resolveChordOptions(data as ChordData, options as ChordChartOptions, ctx),\n});\n\nregisterAdapter(ChartType.Radar, {\n  validate: isRadarData,\n  resolve: (data, options, ctx) => ({\n    option: resolveRadarOptions(data as RadarData, options as RadarChartOptions, ctx),\n  }),\n});\n\nregisterAdapter(ChartType.Network, {\n  validate: isNetworkData,\n  resolve: (data, options, ctx) => ({\n    option: resolveNetworkOptions(data as NetworkData, options as NetworkChartOptions, ctx),\n  }),\n});\n\nregisterAdapter(ChartType.Tree, {\n  validate: isTreeData,\n  resolve: (data, options, ctx) =>\n    resolveTreeSetup(data as TreeData, options as TreeChartOptions, ctx),\n});\n\nregisterAdapter(ChartType.Treemap, {\n  validate: isTreemapData,\n  resolve: (data, options, ctx) => ({\n    option: resolveTreemapOptions(\n      data as TreemapData,\n      options as TreemapChartOptions,\n      ctx,\n    ),\n  }),\n});\n\nregisterAdapter(ChartType.WordCloud, {\n  validate: isWordCloudData,\n  // The wordcloud custom-series renderer can leave stale display elements\n  // behind during ECharts' diff/merge on a theme repaint — clear first.\n  clearOnThemeChange: true,\n  resolve: (data, options, ctx) => ({\n    option: resolveWordCloudOptions(\n      data as WordCloudData,\n      options as WordCloudChartOptions,\n      ctx,\n    ),\n  }),\n});\n\n// Freeze the set of built-in type strings now that every built-in is\n// registered. From here on, `registerAdapter` warns when a consumer overrides\n// one of these (see registerAdapter above).\nbuiltinTypes = new Set(adapterRegistry.keys());\n","/**\n * Auto-dispose mechanism for charts created via the imperative\n * `createChart()` API.\n *\n * `IChart`'s constructor appends a hidden custom element — the \"sentinel\"\n * — to the chart container. When the container leaves the document (the\n * host component unmounts, a parent calls `removeChild`, the user clears\n * `innerHTML`, …), the browser synchronously fires the sentinel's\n * `disconnectedCallback`, which we use to call `chart.dispose()` for the\n * caller. No `onUnmounted` hook required.\n *\n * # Why a custom element instead of …\n *\n * - `MutationObserver`: each chart would need its own observer (or one\n *   global observer with bookkeeping). `disconnectedCallback` is a\n *   zero-cost browser-native lifecycle hook with no observer wiring.\n * - `ResizeObserver` / `IntersectionObserver`: neither fires on detach.\n * - Polling (`requestAnimationFrame` / `setInterval`): runs forever and\n *   wastes the main thread.\n *\n * # Edge cases handled\n *\n * - **SSR / non-DOM environments** — `installSentinel` returns `null` when\n *   `document` or `customElements` is unavailable; `IChart` continues to\n *   function (the `pruneDetachedCharts()` fallback in `registry.ts`\n *   covers test environments that walk the registry on theme switch).\n * - **HMR / duplicate module copies** — if the tag name is already\n *   registered we skip `customElements.define` and reuse the existing\n *   class. The disconnection contract is identical across copies.\n * - **Transient detach-then-reattach (Vue Teleport / React Portal)** — we\n *   defer the disposer one microtask. If the sentinel is re-attached\n *   synchronously (same task), `isConnected` is `true` by the time the\n *   microtask runs and we skip disposal entirely. The microtask runs\n *   before any paint, so the user never sees a half-disposed chart.\n * - **Explicit `chart.dispose()`** — the returned handle's `remove()`\n *   clears the callback *before* removing the sentinel, so the\n *   disconnect we're about to cause can't re-enter the dispose path.\n *   `IChart.dispose()` is also idempotent (guarded by a `_disposed`\n *   flag) so double-disposal from both paths is safe regardless of\n *   ordering — important for `<i-chart>` whose Lit `disconnectedCallback`\n *   already calls `engine.dispose()` independently.\n */\n\nconst TAG_NAME = 'icharts-sentinel';\n\n// Per-instance state stored as a symbol-keyed property so direct\n// `document.createElement('icharts-sentinel')` (without going through\n// `installSentinel`) can't accidentally trigger a stranger's disposer.\nconst CALLBACK_KEY: unique symbol = Symbol('icharts.sentinel.callback');\n\ninterface SentinelElement extends HTMLElement {\n  [CALLBACK_KEY]?: (() => void) | null;\n}\n\nlet registered = false;\n\n/**\n * Register the sentinel custom element with the global registry.\n *\n * The `class … extends HTMLElement` declaration is **deliberately\n * function-local**: in pure-Node environments (Vitest's default\n * `environment: node`, SSR bundles) `HTMLElement` is undefined at\n * module-load time, so a top-level class would throw `ReferenceError`\n * the moment `core.ts` imports this file — long before any sentinel is\n * actually installed. Deferring the declaration into a function body\n * means the `HTMLElement` reference is only resolved on the first\n * `installSentinel()` call in a DOM-capable environment.\n */\nfunction ensureRegistered(): boolean {\n  if (registered) return true;\n  // `customElements` may be missing in tests / SSR / very old browsers.\n  // Caller falls back to the registry's `pruneDetachedCharts` walk.\n  if (typeof customElements === 'undefined') return false;\n  if (typeof HTMLElement === 'undefined') return false;\n  if (customElements.get(TAG_NAME)) {\n    // Already defined by another copy of this module (HMR or\n    // multi-instance bundle). Skip the re-definition — `customElements`\n    // would throw `NotSupportedError` — and trust the existing class to\n    // implement the same contract.\n    registered = true;\n    return true;\n  }\n  class IChartsSentinel extends HTMLElement {\n    disconnectedCallback(): void {\n      const cb = (this as SentinelElement)[CALLBACK_KEY];\n      if (!cb) return;\n      // Defer one microtask so a synchronous detach→reattach (Vue\n      // Teleport, React Portal, manual `parent.appendChild(node)` while\n      // keeping the tree alive) self-heals: by the time the microtask\n      // runs, the browser has finished the reattach and\n      // `this.isConnected` reports the final state. We clear the\n      // callback before invoking it to make the disposer\n      // re-entrant-safe in case `cb()` itself triggers another detach\n      // (e.g. removing the sentinel inside dispose()).\n      queueMicrotask(() => {\n        if (this.isConnected) return;\n        (this as SentinelElement)[CALLBACK_KEY] = null;\n        cb();\n      });\n    }\n  }\n  customElements.define(TAG_NAME, IChartsSentinel);\n  registered = true;\n  return true;\n}\n\nexport interface SentinelHandle {\n  /**\n   * Remove the sentinel without firing its disposer. Called by\n   * `IChart.dispose()` to avoid re-entering its own dispose path through\n   * the sentinel's `disconnectedCallback`.\n   */\n  remove(): void;\n}\n\n/**\n * Append a hidden sentinel to `container` and invoke `onDisconnect`\n * exactly once when the sentinel leaves the live DOM. Returns `null` in\n * environments without a DOM / custom-elements registry — in which case\n * the chart relies on the registry's `pruneDetachedCharts` defense.\n */\nexport function installSentinel(\n  container: HTMLElement,\n  onDisconnect: () => void,\n): SentinelHandle | null {\n  if (typeof document === 'undefined') return null;\n  if (!ensureRegistered()) return null;\n\n  const sentinel = document.createElement(TAG_NAME) as SentinelElement;\n  // Layout-free + pointer-transparent so we don't shift ECharts' canvas\n  // measurement or block hover/click on the chart. `contain: strict`\n  // isolates this element from the parent's layout/paint pipeline.\n  sentinel.style.cssText =\n    'position:absolute;width:0;height:0;visibility:hidden;pointer-events:none;contain:strict';\n  sentinel.setAttribute('aria-hidden', 'true');\n  sentinel[CALLBACK_KEY] = onDisconnect;\n  container.appendChild(sentinel);\n\n  return {\n    remove(): void {\n      // Order matters: clear the callback *before* removing the element.\n      // `sentinel.remove()` synchronously triggers\n      // `disconnectedCallback`, which would otherwise queue a microtask\n      // that re-enters `IChart.dispose()`. The `_disposed` guard in\n      // `IChart` makes the re-entry harmless, but skipping the work\n      // entirely is cheaper and easier to reason about.\n      sentinel[CALLBACK_KEY] = null;\n      sentinel.remove();\n    },\n  };\n}\n","import type {\n  ChartData,\n  AnyChartOptions,\n  IChartInstance,\n  ChartTypeRegistry,\n  ChartDataFor,\n  ChartOptionsFor,\n} from './types.js';\nimport { IChart } from './core.js';\n\n/**\n * Create a chart imperatively.\n *\n * The `type` argument drives full type inference: passing a registered type\n * literal (e.g. `'pie'`) narrows `data` to its data shape (`PieData`) and\n * `options` to its options shape (`PieChartOptions`, including the narrowed\n * `variant`), so mismatches are caught at compile time and editors offer\n * accurate completions. Passing an arbitrary `string` (dynamic type, or a\n * custom type not folded into {@link ChartTypeRegistry}) falls back to the\n * broad {@link ChartData} / {@link AnyChartOptions} unions.\n *\n * Custom chart types registered via `registerAdapter` become first-class by\n * augmenting {@link ChartTypeRegistry} via declaration merging — see its\n * docs for the pattern.\n *\n * @example\n * ```ts\n * const chart = createChart(document.getElementById('app')!, 'line', {\n *   categories: ['Jan', 'Feb', 'Mar'],\n *   series: [{ name: 'Sales', data: [10, 20, 30] }],\n * });\n * chart.resize();\n * chart.dispose();\n * ```\n */\nexport function createChart<T extends keyof ChartTypeRegistry | (string & {})>(\n  el: HTMLElement,\n  type: T,\n  data: ChartDataFor<T>,\n  options: ChartOptionsFor<T> = {} as ChartOptionsFor<T>,\n): IChartInstance<T> {\n  return new IChart(\n    el,\n    type,\n    data as ChartData,\n    options as AnyChartOptions,\n  ) as unknown as IChartInstance<T>;\n}\n","import * as echarts from 'echarts';\n\nexport interface MapGeoJsonSource {\n  type: string;\n  features: unknown[];\n  [key: string]: unknown;\n}\n\nexport interface MapSvgSource {\n  svg: string;\n}\n\nexport interface MapSourceObject {\n  geoJSON?: MapGeoJsonSource;\n  geoJson?: MapGeoJsonSource;\n  svg?: string;\n  [key: string]: unknown;\n}\n\n/**\n * Register a map resource for the built-in `map` chart type.\n *\n * Accepts either:\n * - raw GeoJSON (`FeatureCollection`) object,\n * - `{ geoJSON | geoJson, specialAreas? }`,\n * - `{ svg }` (ECharts SVG map mode).\n */\nexport function registerMap(\n  name: string,\n  source: MapGeoJsonSource | MapSvgSource | MapSourceObject,\n  specialAreas?: Record<string, { left: number; top: number; width: number; height: number }>,\n): void {\n  const register = echarts.registerMap as unknown as (\n    mapName: string,\n    mapSource: unknown,\n    mapSpecialAreas?: unknown,\n  ) => void;\n  if ('type' in source && 'features' in source) {\n    register(name, source, specialAreas);\n    return;\n  }\n  register(name, source, specialAreas);\n}\n","// Server-side chart rendering — produces a complete `<svg>...</svg>`\n// document in pure Node without ever touching `window`, `document`,\n// `customElements`, or a `<canvas>` element. Safe to call from\n// Next.js / Nuxt / Astro / SvelteKit / Vite SSR / serverless / CLI\n// scripts that import from `@bndynet/icharts/core`.\n//\n// This is the SSR counterpart of `IChart`: where `IChart` wraps an\n// ECharts instance bound to a real `HTMLElement` (browser only),\n// `renderChartToSVGString` wraps a headless ECharts instance using\n// ECharts 6's built-in `ssr: true` mode + SVG renderer. The two paths\n// share the same adapter pipeline (`resolveEChartsOption`), the same\n// theme registration (`ensureThemesRegistered` / `resolveThemeName`),\n// and the same global font-family guard\n// (`applyConfiguredFontFamilyToOption`), so any chart that renders in\n// the browser also renders here — modulo the canvas-based feature\n// fallbacks documented below.\n//\n// Why a standalone helper instead of an `IChart` overload:\n//\n//   - `IChart`'s contract (`update`, `setTheme`, `resize`, `dispose`,\n//     auto-dispose sentinel, theme propagation via `chartRegistry`) is\n//     all built around a long-lived, container-bound chart. Server\n//     rendering is the opposite shape: one-shot, no container, no\n//     lifetime — get a string, dispose, return.\n//   - Threading `null`-container handling through `IChart`'s\n//     constructor would either widen its public type (breaking) or\n//     introduce a parallel \"headless mode\" branch that consumers must\n//     reason about. A separate function keeps each path simple.\n//   - Running the engine in pure Node has different invariants\n//     (`ResizeObserver` doesn't exist, `customElements` doesn't exist,\n//     canvas-based text measurement falls back to char-count\n//     estimates). Centralizing those expectations here means the\n//     browser path of `IChart` can keep assuming a real DOM.\n//\n// The chart instance is fully `dispose()`d before the function returns\n// (via `try`/`finally`), so no engine resources leak across\n// invocations — the call site stays one-liner-safe even in a hot\n// request loop.\n//\n// Plugin-backed chart types (`wordcloud`, `liquidprogress`) require\n// their `@echarts-x/*` installer to be registered against the shared\n// `echarts` global. The main entry (`@bndynet/icharts`) does this as a\n// side-effect, but the SSR-safe entry (`@bndynet/icharts/core`) does\n// not. SSR consumers who need those types must register the installer\n// explicitly — see the function JSDoc for the exact incantation.\n\nimport * as echarts from 'echarts';\nimport type { ChartData, AnyChartOptions } from './types.js';\nimport { resolveEChartsOption } from './adapters/index.js';\nimport { applyConfiguredFontFamilyToOption } from './adapters/common/font-family.js';\nimport { getConfig } from './config.js';\nimport { ensureThemesRegistered, resolveThemeName } from './themes/index.js';\n\n/**\n * Options forwarded to ECharts' SSR-mode `init` and `renderToSVGString`\n * for {@link renderChartToSVGString}.\n *\n * `width` and `height` are required because, unlike a browser chart\n * that can read its own container dimensions, a headless instance has\n * no DOM to size against — the caller must declare the SVG viewport\n * up front.\n */\nexport interface RenderChartToSVGStringOptions {\n  /** Width of the rendered SVG viewport in pixels. */\n  width: number;\n  /** Height of the rendered SVG viewport in pixels. */\n  height: number;\n  /**\n   * Locale forwarded to ECharts for date / time / number formatters.\n   * Defaults to ECharts' built-in locale (`'EN'`).\n   */\n  locale?: string;\n  /**\n   * Controls whether the root `<svg>` element carries a `viewBox`\n   * attribute. Both modes always emit `width` + `height` attrs.\n   *\n   * - `true` (default, matches ECharts) — root SVG has\n   *   `width=\"W\" height=\"H\" viewBox=\"0 0 W H\"`. The intrinsic\n   *   dimensions are still `W × H`, but the `viewBox` lets a host\n   *   stylesheet override `width` / `height` (or wrap the SVG in a\n   *   responsive container) without distorting the chart geometry.\n   *   This is the right default for HTML / web embeds.\n   * - `false` — root SVG has only `width=\"W\" height=\"H\"` (no\n   *   `viewBox`). The output renders at exactly the input dimensions\n   *   and ignores any CSS resizing of the host element. Use this for\n   *   strictly fixed-size output: print, PDF rasterizers that resolve\n   *   intrinsic dims, screenshot diffs.\n   *\n   * Either way, the chart's internal coordinate system is laid out\n   * against `ssr.width × ssr.height`, so font sizes / strokes / symbol\n   * radii stay constant regardless of how the SVG is later scaled.\n   *\n   * Forwarded directly to ECharts' `renderToSVGString({ useViewBox })`.\n   */\n  useViewBox?: boolean;\n}\n\n/**\n * Render a chart to a full `<svg>...</svg>` string in a server / Node\n * runtime.\n *\n * Uses ECharts' built-in SSR mode (`ssr: true` + `renderer: 'svg'`) so\n * the whole call path is DOM-free and canvas-free — safe to invoke\n * from Next.js / Nuxt / Astro / SvelteKit / Vite SSR / serverless /\n * CLI scripts. The returned string is suitable for:\n *\n *   - Embedding inline in server-rendered HTML pages, emails, PDFs.\n *   - Saving to disk: `fs.writeFileSync('chart.svg', svg)`.\n *   - Converting to PNG via a standalone library, e.g.\n *     [`sharp`](https://sharp.pixelplumbing.com/) or\n *     [`@resvg/resvg-js`](https://github.com/yisibl/resvg-js).\n *     icharts deliberately stays SVG-only so SSR consumers don't pay\n *     for a native canvas dependency they may not need.\n *\n * The underlying ECharts instance is created and `dispose()`d entirely\n * inside this function (`try`/`finally`), so calling this in a hot\n * request loop doesn't leak engine resources.\n *\n * **Plugin-backed chart types.** `liquidprogress` requires the\n * `@echarts-x/custom-liquid-fill` plugin to be registered with the\n * shared ECharts global. The main entry (`@bndynet/icharts`)\n * registers it via side-effect on import, but the SSR-safe entry\n * (`@bndynet/icharts/core`) does NOT — server consumers opt in via\n * the {@link installLiquidProgress} helper, which keeps the\n * `echarts` and `@echarts-x/*` packages internal to this library:\n *\n * ```ts\n * import { installLiquidProgress, renderChartToSVGString } from '@bndynet/icharts/core';\n * installLiquidProgress(); // once at boot; idempotent\n * const svg = renderChartToSVGString(\n *   'liquidprogress',\n *   { value: 0.65 },\n *   { width: 400, height: 400 },\n * );\n * ```\n *\n * `wordcloud` is **not** SSR-renderable, no matter how you register\n * it. The `@echarts-x/custom-word-cloud` package touches `window` at\n * module-load and `canvas.addEventListener` at render-time — both\n * fundamental browser dependencies. Render wordcloud on the client\n * only, via `createChart('wordcloud', ...)` from the main\n * `@bndynet/icharts` entry. See `src/ssr-plugins.ts` for the full\n * rationale.\n *\n * **SSR fallbacks** (vs. browser rendering):\n *\n *   - `canvas.measureText` is unavailable, so adapters that measure\n *     label widths fall back to a `chars × 7px` estimate. Race\n *     `grid.right` headroom and tree label widths can drift by 1–2 px.\n *   - `ResizeObserver` is unavailable, so the pie adapter's resize-\n *     driven center/radius recompute is replaced by the static\n *     percent fallback (still legible, slightly less centered).\n *   - SVG renderer text width is approximated, not measured against a\n *     real canvas, so very long labels can wrap differently than in\n *     the browser. Pad your widths slightly if you depend on exact\n *     parity.\n *\n * @example\n * ```ts\n * import { renderChartToSVGString } from '@bndynet/icharts/core';\n * import { writeFileSync } from 'node:fs';\n *\n * const svg = renderChartToSVGString(\n *   'line',\n *   {\n *     categories: ['Jan', 'Feb', 'Mar'],\n *     series: [{ name: 'Sales', data: [10, 20, 30] }],\n *   },\n *   { width: 800, height: 400 },\n *   { title: 'Q1 Sales' },\n * );\n * writeFileSync('chart.svg', svg);\n * ```\n *\n * @param type    Chart type string (e.g. `'line'`, `'bar'`, `'pie'`).\n *                Must match a registered adapter.\n * @param data    Chart data — same shape consumed by `createChart`.\n * @param ssr     Required SSR-render options (`width`, `height`,\n *                `locale?`, `useViewBox?`). Replaces the DOM\n *                container that the browser API would take.\n * @param options Optional `XxxChartOptions` (theme, title, legend,\n *                tooltip, …). Same shape as the fourth argument to\n *                `createChart`.\n * @returns Full `<svg>...</svg>` markup as a single string.\n * @throws Error when `ssr.width` / `ssr.height` are missing or\n *         non-finite, when `type` has no registered adapter, or when\n *         `data` fails the adapter's `validate` check (same errors\n *         the browser path would surface).\n */\nexport function renderChartToSVGString(\n  type: string,\n  data: ChartData,\n  ssr: RenderChartToSVGStringOptions,\n  options: AnyChartOptions = {},\n): string {\n  // Defensive: width/height are the one input we can't reasonably\n  // default. Surface a clear error rather than letting ECharts emit\n  // an opaque \"size not specified\" warning into stderr.\n  if (\n    !ssr ||\n    typeof ssr.width !== 'number' ||\n    !Number.isFinite(ssr.width) ||\n    ssr.width <= 0 ||\n    typeof ssr.height !== 'number' ||\n    !Number.isFinite(ssr.height) ||\n    ssr.height <= 0\n  ) {\n    throw new Error(\n      'renderChartToSVGString: `ssr.width` and `ssr.height` are required and must be positive finite numbers (in px).',\n    );\n  }\n\n  ensureThemesRegistered();\n  const themeName = resolveThemeName(options.theme);\n\n  // SSR-mode init: pass `null` for the DOM (ECharts 6 explicitly\n  // supports this when `ssr: true`), forward locale + dimensions, pin\n  // the SVG renderer.\n  const ec = echarts.init(null, themeName, {\n    renderer: 'svg',\n    ssr: true,\n    width: ssr.width,\n    height: ssr.height,\n    locale: ssr.locale,\n  });\n\n  try {\n    const { option, onInit, notMerge } = resolveEChartsOption(\n      type,\n      data,\n      options,\n      {\n        // Headless: never in shadow DOM, no observed-frame interval.\n        // Container dims are surfaced from the SSR options so adapters\n        // that compute pixel-derived sizing (e.g. gauge `percentage`)\n        // get the same input they would in the browser.\n        inShadowDom: false,\n        containerWidth: ssr.width,\n        containerHeight: ssr.height,\n      },\n    );\n    applyConfiguredFontFamilyToOption(option, getConfig().fontFamily);\n    ec.setOption(option, notMerge ?? true);\n    // Run the adapter's post-init hook (e.g. pie's pixel-perfect\n    // center/radius recompute). The hook is required to short-circuit\n    // when DOM-only APIs are missing (`ResizeObserver`, `getDom()` on\n    // a headless instance) — every built-in adapter already does, and\n    // the SSR fallbacks listed in the JSDoc above are the trade-offs.\n    onInit?.(ec);\n    return ec.renderToSVGString({ useViewBox: ssr.useViewBox });\n  } finally {\n    // Always dispose, even on a thrown adapter / setOption — leaving\n    // a headless ECharts instance alive in a request handler would\n    // accumulate across calls and silently drift memory.\n    ec.dispose();\n  }\n}\n","// SSR-safe plugin installers — named functions that hide the\n// `echarts` and `@echarts-x/*` package boundaries from server-side\n// consumers of `@bndynet/icharts/core`.\n//\n// Why this file exists, and how it differs from `src/installers/index.ts`:\n//\n//   `src/installers/index.ts` is a *side-effect* module: importing it\n//   immediately calls `echarts.use(...)` for every browser-friendly\n//   `@echarts-x/*` plugin. It's the single entry the browser-first\n//   main entry (`src/index.ts`) pulls in, which is why\n//   `import '@bndynet/icharts'` \"just works\" for wordcloud and\n//   liquid-progress on the client. But that file STATICALLY imports\n//   `@echarts-x/custom-word-cloud`, whose module body references\n//   `window` — so it cannot be imported on the server.\n//\n//   This file, by contrast:\n//\n//     1. Exposes **named functions**, not side effects. Consumers\n//        call them explicitly, so registration costs nothing for\n//        request handlers that don't need the plugin.\n//     2. Only re-exports plugins that are actually SSR-renderable.\n//        Currently that's `installLiquidProgress` only — see the\n//        large comment at the bottom for why `wordcloud` is\n//        deliberately not exposed.\n//     3. Keeps the `echarts` and `@echarts-x/*` packages internal.\n//        Consumers of `@bndynet/icharts/core` never have to\n//        `import * as echarts from 'echarts'` or\n//        `import x from '@echarts-x/...'` — the package boundary\n//        stays clean.\n//\n// `echarts.use(...)` is idempotent (it dedupes by class identity),\n// so calling these installers on every request, in every concurrent\n// handler, or from multiple modules is harmless. The fast path after\n// the first call is a `Map.has` lookup inside ECharts.\n\nimport * as echarts from 'echarts';\nimport liquidFillInstaller from '@echarts-x/custom-liquid-fill';\n\n/**\n * Register the `@echarts-x/custom-liquid-fill` plugin so\n * {@link renderChartToSVGString} can render `'liquidprogress'` charts\n * on the server.\n *\n * Call this **once, before the first `renderChartToSVGString` call**\n * that targets `'liquidprogress'`. Subsequent calls are idempotent\n * (ECharts dedupes plugin registrations by class identity), so\n * sprinkling it at the top of every handler is safe but unnecessary.\n *\n * The wrapper exists so SSR consumers never have to import `echarts`\n * or `@echarts-x/*` directly — the public surface stays\n * `@bndynet/icharts/core`. The implementation is intentionally tiny\n * (a single `echarts.use(...)` call); the value is the API boundary,\n * not the code.\n *\n * @example\n * ```ts\n * import { installLiquidProgress, renderChartToSVGString } from '@bndynet/icharts/core';\n *\n * installLiquidProgress();\n *\n * const svg = renderChartToSVGString(\n *   'liquidprogress',\n *   { value: 0.65 },\n *   { width: 400, height: 400 },\n *   { title: 'CPU' },\n * );\n * ```\n *\n * @example Express handler with per-request rendering\n * ```ts\n * import express from 'express';\n * import { installLiquidProgress, renderChartToSVGString } from '@bndynet/icharts/core';\n *\n * // Register once at boot time — idempotent, but no reason to repeat.\n * installLiquidProgress();\n *\n * app.get('/chart.svg', (req, res) => {\n *   const svg = renderChartToSVGString('liquidprogress', { value: Number(req.query.v) }, { width: 400, height: 400 });\n *   res.type('image/svg+xml').send(svg);\n * });\n * ```\n */\nexport function installLiquidProgress(): void {\n  echarts.use(liquidFillInstaller);\n}\n\n/*\n * Note on `wordcloud`: there is intentionally NO `installWordCloud`\n * in this module. The `@echarts-x/custom-word-cloud` package is not\n * SSR-renderable, for two independent reasons:\n *\n *   1. Module-load: the plugin's top-level code runs\n *      `if (!window.setImmediate) { ... }` followed by\n *      `document.createElement('canvas')`. Both throw\n *      `ReferenceError` the moment the module is imported in Node —\n *      even a dynamic `await import('@echarts-x/custom-word-cloud')`\n *      crashes. So any wrapper here would either need to install a\n *      global `window` / `document` polyfill into the consumer's\n *      process (a silent side effect we won't bake in) or fail.\n *\n *   2. Runtime: even with a `window` / `document` polyfill the\n *      plugin's word-placement algorithm crashes with\n *      `canvas.addEventListener is not a function`. The layout step\n *      needs a *real* canvas (text metrics, event listeners on the\n *      canvas element). Supporting that requires jsdom + node-canvas,\n *      which fundamentally moves the runtime out of \"pure SSR\" — at\n *      that point you might as well render the chart with Playwright\n *      / Puppeteer.\n *\n * Wordcloud therefore stays a browser-only chart type. Use it via\n * `createChart('wordcloud', ...)` from `@bndynet/icharts` on the\n * client. The SSR-mode fallbacks list in README (\"Option 4 — SSR\")\n * and the JSDoc on `renderChartToSVGString` document this.\n *\n * If the upstream plugin ever publishes an SSR-friendly build (no\n * top-level browser globals, headless layout fallback), add a\n * matching `installWordCloud()` here and wire it into the regression\n * test in `src/ssr-plugins.test.ts`.\n */\n"],"mappings":"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","names":["registerMap","registerTheme","echarts","ChartType","import_color_hub","c","registerTheme","registerTheme","r","record","textStyle","clampRound","clampRound","alpha","display","DEFAULT_NODE_SIZE","resolveRoamMode","annotateTree","registered","echarts","registerMap","echarts","echarts","liquidFillInstaller"]}