{"version":3,"sources":["../src/index.ts","../src/installers/index.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","../src/components/i-chart.ts"],"sourcesContent":["// Browser-first entry: re-exports the full public API from\n// `./index-core.js`, registers the `@echarts-x` chart-type installers\n// (wordcloud + liquid-fill), and loads the `<i-chart>` web component\n// as a side-effect (custom-element registration happens at module\n// load when `customElements` is available; see\n// `./components/i-chart.js` for the Node-safe guard).\n//\n// SSR / server runtimes that need to avoid the web-component load and\n// the `window` / `document` dependencies of the @echarts-x installers\n// should import from `@bndynet/icharts/core` instead (resolves to\n// `./index-core.js`).\n\n// Side-effect: register `@echarts-x` chart-type plugins with the\n// shared ECharts global. Kept out of `./core.js` so the SSR-safe\n// `./index-core.js` doesn't pull `window` / `document` references\n// into the module graph.\nimport './installers/index.js';\n\nexport * from './index-core.js';\n\n// Web component (registers <i-chart> custom element as side effect in\n// environments with a `customElements` registry; a no-op in Node).\nexport { IChartElement } from './components/i-chart.js';\n","/**\n * Browser-first side-effect module that registers the `@echarts-x`\n * custom chart types (wordcloud + liquid-fill) with the shared\n * ECharts instance.\n *\n * Why this is split out of `core.ts`:\n *\n * `@echarts-x/custom-word-cloud` reads `window` and calls\n * `document.createElement('canvas')` at module-load time (a\n * `setImmediate` polyfill plus a feature probe). Importing the\n * package in pure Node throws `ReferenceError: window is not defined`\n * before any user code runs.\n *\n * Keeping the imports inside `core.ts` therefore poisoned every\n * downstream consumer — including the SSR-safe\n * `@bndynet/icharts/core` subpath — because `core.ts` is on the\n * shared engine path used by `createChart()` / `new IChart()`.\n *\n * By isolating the installs in this file and importing it as a\n * side-effect *only* from `src/index.ts` (the browser-first main\n * entry), we get:\n *\n *   - `@bndynet/icharts`        → main entry, registers wordcloud +\n *     liquid-fill on import (browser/CSR behavior is unchanged).\n *   - `@bndynet/icharts/core`   → SSR-safe entry, never pulls\n *     `@echarts-x/*` into the module graph. Safe to import in\n *     Next.js / Nuxt / Astro / SvelteKit / Vite SSR.\n *\n * `echarts.use(...)` is idempotent (it dedupes registrations by\n * class identity) so loading this module multiple times is harmless.\n *\n * SSR consumers who use `/core` but still need wordcloud or\n * liquid-progress on the client should either:\n *\n *   - Import `@bndynet/icharts` from a client-only code path\n *     (`onMounted`, `useEffect`, `'use client'`), OR\n *   - Import this module explicitly:\n *       `await import('@bndynet/icharts/dist/installers/index.js')`\n *     before constructing the chart on the client.\n */\nimport * as echarts from 'echarts';\nimport wordCloudInstaller from '@echarts-x/custom-word-cloud';\nimport liquidFillInstaller from '@echarts-x/custom-liquid-fill';\n\necharts.use(wordCloudInstaller);\necharts.use(liquidFillInstaller);\n\nexport {};\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","import { LitElement, html, css, type PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport type { ChartData, AnyChartOptions, IChartInstance } from '../types.js';\nimport { IChart } from '../core.js';\n\n/**\n * `<i-chart>` web component backed by ECharts.\n *\n * @example\n * ```html\n * <i-chart\n *   type=\"line\"\n *   .data=${{ categories: ['A','B','C'], series: [{ name: 'S1', data: [1,2,3] }] }}\n *   .options=${{ title: 'My Chart' }}\n * ></i-chart>\n * ```\n */\nexport class IChartElement extends LitElement {\n  static override styles = css`\n    :host {\n      display: block;\n      width: 100%;\n      height: 100%;\n    }\n    .ichart-container {\n      width: 100%;\n      height: 100%;\n    }\n  `;\n\n  @property({ type: String })\n  type: string = 'line';\n\n  @property({ type: Object })\n  data: ChartData | null = null;\n\n  @property({ type: Object })\n  options: AnyChartOptions = {};\n\n  private engine: IChart | null = null;\n  private resizeObserver: ResizeObserver | null = null;\n\n  override render() {\n    return html`<div class=\"ichart-container\"></div>`;\n  }\n\n  override firstUpdated(): void {\n    this.resizeObserver = new ResizeObserver(() => {\n      this.engine?.resize();\n    });\n    this.resizeObserver.observe(this);\n    this.renderChart();\n  }\n\n  override updated(changed: PropertyValues): void {\n    if (\n      changed.has('type') ||\n      changed.has('data') ||\n      changed.has('options')\n    ) {\n      // Skip the very first update — handled by firstUpdated\n      if (changed.has('type') && !changed.get('type') && this.engine === null) return;\n      this.renderChart();\n    }\n  }\n\n  override disconnectedCallback(): void {\n    super.disconnectedCallback();\n    this.resizeObserver?.disconnect();\n    this.resizeObserver = null;\n    this.engine?.dispose();\n    this.engine = null;\n  }\n\n  /** Expose the underlying chart instance for advanced usage. */\n  getChartInstance(): IChartInstance | null {\n    return this.engine;\n  }\n\n  private renderChart(): void {\n    if (!this.data) return;\n\n    const container = this.shadowRoot?.querySelector(\n      '.ichart-container',\n    ) as HTMLElement | null;\n    if (!container) return;\n\n    if (!this.engine) {\n      this.engine = new IChart(container, this.type, this.data, this.options);\n    } else {\n      this.engine.setType(this.type);\n      this.engine.update(this.data, this.options);\n    }\n  }\n}\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'i-chart': IChartElement;\n  }\n}\n\n// Register the custom element only when a `customElements` registry is\n// available (browsers, jsdom, Lit's `@lit-labs/ssr-dom-shim`). In pure\n// Node SSR runtimes without the shim, this is a deliberate no-op so\n// `import '@bndynet/icharts'` doesn't throw — the chart is created\n// client-side via `createChart()` / mounting `<i-chart>` regardless.\n// The `customElements.get('i-chart')` check also handles HMR /\n// multi-bundle scenarios where the tag may already be registered.\nif (\n  typeof customElements !== 'undefined' &&\n  !customElements.get('i-chart')\n) {\n  customElements.define('i-chart', IChartElement);\n}\n"],"mappings":"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","names":["registerMap","registerTheme","wordCloudInstaller","liquidFillInstaller","echarts","ChartType","import_color_hub","echarts","c","registerTheme","registerTheme","r","html","record","textStyle","clampRound","clampRound","alpha","display","DEFAULT_NODE_SIZE","resolveRoamMode","annotateTree","registered","echarts","registerMap","echarts","echarts","import_custom_liquid_fill","liquidFillInstaller"]}